;------------------------------
; boot sector disassembly by Michael Dehlwes
; From MS-DOS 6.2, german version.

; This source will assemble exactly to my boot record
; This code will be loaded by BIOS to 0:7C00h
;  offset of error message:
;    7D9E        (used in code)
;    -19E        (physically)
;    ----
;    7C00
; Then this code loads IO.SYS to 0:700h
; ss=es=ds=0 for most parts of code
; First 11 bytes of code (Offset 3Eh) will be overwritten with
; Disk Parameter Table (DPT)
;NAME:             BOOT.BIN
;FILELENGTH:       00200h - 512d
;START (CS:IP):    00000h
;CODE ENDE:        00200h  end
;CODE ANFANG:      00000h  begin
;DATUM:            Sat Jul 30 11:22:51 1994
CODE    SEGMENT BYTE PUBLIC 'CODE'
        ASSUME  CS:CODE,DS:CODE,ES:NOTHING,SS:NOTHING
        ORG     0
H00000: JMP     Short H0003E                        ;00000 EB3C
;---------------------------------------------------
        NOP                                         ;00002 90
;---------------------------------------------------
        DB      "MSDOS5.0"
        ; But it's a DOS 6.2 harddisk. Formats are the same, I think.
;---------------------------------------------------
        ; Media description follows here.
        DB      0                                   ;0000B
        DB      02h                                 ;0000C
        ; Bytes per sector
        DB      10h                                 ;0000D
        ; sectors per cluster
        DB      01h                                 ;0000E
        DB      00h                                 ;0000F
        ; Boot sectors at beginning
        DB      02h                                 ;00010
        ; FAT copies
        DB      00h                                 ;00011
        DB      02h                                 ;00012
        ; Boot directory entries
        DB      00h                                 ;00013
        DB      00h                                 ;00014
        ; (UNUSED): total sectors on disk
        DB      0F8h                                ;00015
        ; media descriptor byte
        DB      0CBh                                ;00016
        DB      00h                                 ;00017
        ; sectors per FAT
        DB      38h                                 ;00018
        DB      00h                                 ;00019
        ; sectors per track
        DB      0Fh                                 ;0001A
        DB      00h                                 ;0001B
        ; sides
        DB      38h                                 ;0001C
        DB      00h                                 ;0001D
        DB      00h                                 ;0001E
        DB      00h                                 ;0001F
        ; Special hidden sectors
        DB      0A8h                                ;00020
        DB      0A9h
        DB      0Ch
        DB      00h
        ; DWORD: big total number of sectors
        DB      80h                                 ;00024
        DB      00h                                 ;00025
        ; Physical Drive number 80h = Harddisk 0
        DB      29h                                 ;00026
        ; Extended boot record signature
        DB      0D8h,1Dh,";'"                       ;00027
        ; DWORD: Volume serial number
        DB      "HD-MICHI   "                       ;0002B
        ; volume label
        DB      "FAT16   "
        ; file system ID
;---------------------------------------------------
; Following code will be overwritten with DPT
; 3Eh-48h
; DD 49h = (sect/FAT)*FATs + HiddenSectors + BootSectors@Begin + BootDirSectors
;          this data is required when giving control to IO.SYS
; DD 50h = (sect/FAT)*FATs + HiddenSectors + BootSectors
;          = location of root directory
H0003E: CLI
        XOR     AX,AX
        MOV     SS,AX           ;SS=0
        MOV     SP,7C00h        ;SP=7C00h
        PUSH    SS
        POP     ES              ;ES=0
        MOV     BX,0078h
        LDS     SI,SS:[BX]      ;DS:SI = [0:78h] int 1Eh vector =
                                ;        pointer to disk parameter table
        PUSH    DS              ; 4 registers PUSHed, will only be POPed
        PUSH    SI              ; when error occurred and INT 19h is called
        PUSH    SS
        PUSH    BX
        MOV     DI,7C3Eh        ; start of code
        MOV     CX,0Bh          ; 11 bytes
        CLD                     ; overwrite first code with disk parameter
        REPZ    MOVSB           ; table (DPT)
        PUSH    ES
        POP     DS              ;DS=0
        ; after REP MOVSB di points to 7C49h, end of DPT
        ; [DI-2] = DPT[9] = head settle time in milliseconds
        MOV     Byte Ptr [DI-02h],0Fh
        MOV     CX,DS:[7C18h]   ; get sectors per track
        ; [DI-7] = DPT[4]
        MOV     [DI-07h],CL     ; store into DPT
        MOV     [BX+02h],AX     ; redirect DPT pointer to our data
        MOV     Word Ptr [BX],7C3Eh
        STI
        ; AX=0, DL=0, INT 13h - reset disk system
        INT     13h             ;B-Reset_FD
        JB      H000ED          ;Error ? Yes -> error prompt
        XOR     AX,AX
        CMP     DS:[7C13h],AX   ; check SMALL FIELD total sectors on disk
        JZ      H00084          ; this field is unused with big drives
                                ; so if 0 (unused), skip
        MOV     CX,DS:[7C13h]
        MOV     DS:[7C20h],CX   ; else store value to BIG FIELD
H00084: MOV     AL,DS:[7C10h]   ; sectors per FAT * FAT copies (2 in my case)
        MUL     Word Ptr DS:[7C16h] ; -> DX:AX
        ADD     AX,DS:[7C1Ch]   ; add hidden sectors
        ADC     DX,DS:[7C1Eh]
        ADD     AX,DS:[7C0Eh]   ; add boot sectors at beginning
        ADC     DX,+00h
        MOV     DS:[7C50h],AX   ; store to [50h]
        MOV     DS:[7C52h],DX
        MOV     DS:[7C49h],AX   ; and to [49h]
        MOV     DS:[7C4Bh],DX
        MOV     AX,20h
        MUL     Word Ptr DS:[7C11h] ; Calculate boot directory size in bytes
        MOV     BX,DS:[7C0Bh]
        ADD     AX,BX
        DEC     AX
        DIV     BX                      ; adjust to sectors
        ADD     DS:[7C49h],AX           ; add to DD [49h]
        ADC     Word Ptr DS:[7C4Bh],0
        MOV     BX,500h         ; Load root directory to ES:500h
        MOV     DX,DS:[7C52h]   ; location of root dir
        MOV     AX,DS:[7C50h]
        CALL    H00160          ;Calc sector
        JB      H000ED          ;Error? -> prompt for valid system disk
        MOV     AL,1            ;Read 1 sector
        CALL    H00181          ;Read HD sector
        JB      H000ED          ;Error? -> prompt for valid system disk
        MOV     DI,BX           ;Check if first entry is IO.SYS
        MOV     CX,0Bh          ;Length "IO      SYS"
        MOV     SI,7DDFh        ;Offset "IO      SYS"
        REPZ    CMPSB
        JNZ     H000ED          ;Not identical? -> error prompt
        ; after previos REP CMPS  si points at "MSDOS   SYS"
        LEA     DI,[BX+20h]     ;Load offset "MSDOS   SYS" in root dir
        MOV     CX,0Bh          ;Length "MSDOS   SYS"
        REPZ    CMPSB
        JZ      H00105          ;Identical? Yes-> continue with file load
                                ;No-> error prompt
;---------------------------------
; Invalid system disk, prompt for new one.
H000ED: MOV     SI,7D9Eh        ;Offset "No system disk or drive error"
        CALL    H00152          ;Print ASCIZ string
        XOR     AX,AX
        INT     16h             ;B-Next_Kbd_Char
        POP     SI
        POP     DS
        POP     [SI]
        POP     [SI+2]
        INT     19h             ;BIOS Reboot
H00100: POP     AX              ;Adjust stack
        POP     AX
        POP     AX
        JMP     Short H000ED    ;Reboot
;---------------------------------------------------
; Read file from disk (IO.SYS)
H00105: MOV     AX,[BX+1Ah]     ; Get location of IO.SYS (in dir entry)
        DEC     AX
        DEC     AX
        MOV     BL,DS:[7C0Dh]
        XOR     BH,BH
        MUL     BX              ; Convert to cluster
        ; DX:AX = [B 7C0Dh] * ( [W BX+1Ah] - 2 )
        ADD     AX,DS:[7C49h]
        ADC     DX,DS:[7C4Bh]
        ; DX:AX+= [DD 7C49h]
        MOV     BX,0700h        ; Load IO.SYS to es:700h
        MOV     CX,3            ; Load three sectors
; Read next sector
H00120: PUSH    AX
        PUSH    DX
        PUSH    CX
        CALL    H00160          ;Calc sector
        JC      H00100          ;Error? -> prompt for valid system disk
        MOV     AL,01h          ;Read 1 sector
        CALL    H00181          ;Read HD sector
        POP     CX
        POP     DX
        POP     AX
        JB      H000ED          ;Error? -> prompt for valid system disk
        ; Advance to next sector
        ADD     AX,1
        ADC     DX,0
        ADD     BX,DS:[7C0Bh]
        LOOP    H00120
; Give control to IO.SYS
        MOV     CH,DS:[7C15h]
        MOV     DL,DS:[7C24h]
        MOV     BX,DS:[7C49h]
        MOV     AX,DS:[7C4Bh]
        DB      0EAh
        DW      0,70h
        ; =JMP   0070h:0000h                         ;0014D EA00007000
;---------------------------------------------------
; Write a 0-terminated string to TTY (bios)
; Offset in SI
H00152: LODSB                                       ;00152
        OR      AL,AL                               ;00153
        JZ      H00180          ;jmp to RET instr.  ;00155
        MOV     AH,0Eh                              ;00157
        MOV     BX,0007h                            ;00159
        INT     10h             ;B-Wr_TTY_Char      ;0015C
        JMP     Short H00152                        ;0015E
;---------------------------------------------------
; Calculates logical sector
; On entry: DX:AX  (physical sector/cluster?)
; carry flag set on error
;   IF DX >= [7C18h] GOTO errorexit
; DX:AX div [W 7C18h] -> AX
;         remainder+1 -> [B 7C4Fh]=sector number
; 0:AX div [W 7C1Ah]  -> [W 7C4Dh]=cylinder number
;        remainder    -> [B 7C25h]=head number
H00160: CMP     DX,DS:[7C18h]                       ;00160
        JNB     H0017F          ; error exit        ;00164
        DIV     Word Ptr DS:[7C18h]                 ;00166
        INC     DL                                  ;0016A
        MOV     DS:[7C4Fh],DL                       ;0016C
        XOR     DX,DX                               ;00170
        DIV     Word Ptr DS:[7C1Ah]                 ;00172
        MOV     DS:[7C25h],DL                       ;00176
        MOV     DS:[7C4Dh],AX                       ;0017A
        CLC                                         ;0017D
        RET                     ;RET_Near           ;0017E
H0017F: STC                                         ;0017F
H00180: RET                     ;RET_Near           ;00180
;---------------------------------------------------
; Read disk sector
; AL (must be set on entry): number of sectors to read
; ES:BX: offset data buffer
; BYTE [7C24h] = drive number
; BYTE [7C25h] = head number
; WORD [7C4Dh] = cylinder number
; BYTE [7C4Fh] = sector number
H00181: MOV     AH,02h  ; BIOS function read sector
        MOV     DX,DS:[7C4Dh]                       ;00183
        MOV     CL,06h                              ;00187
        SHL     DH,CL                               ;00189
        OR      DH,DS:[7C4Fh]                       ;0018B
        MOV     CX,DX                               ;0018F
        XCHG    CH,CL                               ;00191
        ; convert to BIOS call requirements
        ; CX=ccccccccCCssssss
        ; CH=low eight bits of cylinder number           "c"
        ; CL=sector number (bits 0-5)                    "s"
        ;    high two bits of cylinder (bit 6-7 HD only) "C"
        MOV     DL,DS:[7C24h]                       ;00193
        ; DL=drive number (bit 7 set: hard disk)
        MOV     DH,DS:[7C25h]                       ;00197
        ; DH=head number
        INT     13h             ;BIOS-Read Disk Sect;0019B
        RET                     ;RET_Near           ;0019D
;---------------------------------------------------
        ; Ralf Brown says:
        ; 1BEh  (16 bytes)  partition record for partition 1
        ; 1CEh  (16 bytes)  partition record for partition 2
        ; 1DEh  (16 bytes)  partition record for partition 3
        ; 1EEh  (16 bytes)  partition record for partition 4
        ; But that's not valid in this case. Funny.
        DB      13,10,"Kein System oder Laufwerksfehler"    ;0019E
                        ; No system or drive error
        DB      13,10,"Wechseln und Taste drcken",13,10,0
                        ; Change [disk] and press key
        DB      "IO      SYS"                       ;001DF
        DB      "MSDOS   SYS"                       ;001EA
        DB      9 DUP (0)         ; Fill            ;001F5
        DB      055h,0AAh                           ;001FE
        ; Signature, indicates valid boot block.
CODE    ENDS
        END     H00000
