Win98 Boot Sector
The following is a copy of the Win98 boot strap (or MBR). INT 19 will read that information and jump to 0x0000:0x7C00. It is expected to read other sectors and start running some operating system.
# Note: it is assumed that CS is 0x0000 by this time
7C00: EB 3C jmps start go to 7C3E
7C02: 90 nop
BIOS Parameter Block and Extended Block
(not 100% sure, but it could be that the BIOS [or LILO/GRUB] will
poke some values in here before jumping to 7C00)
7C03: 4D 53 57 49 4E 34 2E 31 MSWIN4.1
7C0B: 00 02 0x0200 (512) bytes per sector
7C0D: 40 0x40 (64) sectors per cylinder
7C0E: 01 00 0x0001 (1) reserved sector (this MBR)
7C10: 02 0x02 (2) number of FATs (File Allocation Tables)
7C11: 00 02 0x0200 (512) number of files in the root directory
7C13: 00 00 0x0000 (0) number of sectors (if 0, check large count below)
7C15: F8 media type
7C16: FA 00 0x00FA (250) sectors per FAT
7C18: 3F 00 0x003F (63) sectors per track
7C1A: FF 00 0x00FF (255) heads
7C1C: 3F 00 00 00 0x003F (63) hidden sectors
7C20: B5 CF 3B 00 0x003BCFB5 (3919797) sectors (too large for 7C13)
7C24: 80 physical disk number (always 0x80 for hard drives)
7C25: 00 unused (current head)
7C26: 29 signature (must be 0x28 or 0x29)
7C27: F8 11 08 42 Some Unique ID
7C2B: 20 20 20 20 20 20 20 20 20 20 20 Unused disk label
7C36: 46 41 54 31 36 20 20 20 FAT16, the system ID (FAT12 or FAT16)
start:
7C3E: 33 C9 xor cx,cx clear CX
7C40: 8E D1 mov ss,cx clear SS
7C42: BC FC 7B mov sp,0x7BFC set SP to7BFC (just before this block)
7C45: 16 push ss copy SS to ES (i.e. clear ES)
7C46: 07 pop es
7C47: BD 78 00 mov bp,0x0078 address of INT 1E
7C4A: C5 76 00 lds si,[bp+0x00] loading DS:SI (source)
7C4D: 1E push ds save DS:SI (original INT 1E content)
7C4E: 56 push si (need to restore that later!)
7C4F: 16 push ss save SS:BP (address to INT 1E)
7C50: 55 push bp
7C51: BF 22 05 mov di,0x0522 address = 0x0522 (dest.)
7C54: 89 7E 00 mov [bp+0x00],di save ES:DI (dest.) in INT 1E
7C57: 89 4E 02 mov [bp+0x02],cx clear (segment = 0)
7C5A: B1 0B mov cl,0x0B
7C5C: FC cld
7C5D: F3 A4 rep movsb copy 11 bytes (floppy parameters)
7C5F: 06 push es clear ds (segment = 0)
7C60: 1F pop ds
7C61: BD 00 7C mov bp,0x7C00
7C64: C6 45 FE 0F mov [di-0x02],0x0F set settle time to 15 ms
7C68: 38 4E 24 cmp [bp+0x24],cl is [bp+24] negative? (i.e. hard drive)
7C6B: 7D 20 jnl boot_floppy go to 7C8D
harddrive:
7C6D: 8B C1 mov ax,cx clear ax (read sector 0, partition?)
7C6F: 99 cwd clear dx
7C70: E8 7E 01 calln read go to 7DF1
7C73: 83 EB 3A sub bx,0x3A go to the 1st partition table
7C76: 66 A1 1C 7C mov eax,[0x7C1C] # of hidden sectors
next_partition:
7C7A: 66 3B 07 cmp eax,[bx]
7C7D: 8A 57 FC mov dl,[bx-0x04]
7C80: 75 06 jne keep_old_read go to 7C88
7C82: 80 CA 02 or dl,0x02
7C85: 88 56 02 mov [bp+0x02],dl if 0x0E, use extended read
keep_old_read:
7C88: 80 C3 10 add bl,0x10 next partition
7C8B: 73 ED jnc next_partition go to 7C7A
The follow reads the root directory in which it expects to find the file
JO.SYS (unlikely) or IO.SYS (more likely!)
7C8D: 33 C9 xor cx,cx
7C8F: FE 06 D8 7D inc [0x7DD8] character I -> J
retry:
7C93: 8A 46 10 mov al,[bp+0x10] number of FATs
7C96: 98 cbw clear ah
7C97: F7 66 16 mul [bp+0x16] sectors per FAT
7C9A: 03 46 1C add ax,[bp+0x1C] hidden sectors (low)
7C9D: 13 56 1E adc dx,[bp+0x1E] hidden sectors (high)
7CA0: 03 46 0E add ax,[bp+0x0E] reserved sectors (low)
7CA3: 13 D1 adc dx,cx add carry if any (high)
7CA5: 8B 76 11 mov si,[bp+0x11] number of files in root dir.
7CA8: 60 pushaw
7CA9: 89 46 FC mov [bp-0x04],ax save sector #
7CAC: 89 56 FE mov [bp-0x02],dx
7CAF: B8 20 00 mov ax,0020
7CB2: F7 E6 mul si ax,dx = si x 32 (i.e. 0x00004000)
7CB4: 8B 5E 0B mov bx,[bp+0x0B] size of 1 sector
7CB7: 03 C3 add ax,bx
7CB9: 48 dec ax
7CBA: F7 F3 div bx (ax,dx + bx - 1) / bx (i.e. 0x41FF / 0x200 = 0x20)
7CBC: 01 46 FC add [bp-0x04],ax
7CBF: 11 4E FE adc [bp-0x02],cx
7CC2: 61 popaw
7CC3: BF 00 07 mov di,0x0700
7CC6: E8 28 01 calln read go to 7DF1
7CC9: 72 3E jc io_error go to 7D09
compare_next:
7CCB: 38 2D cmp [di],ch is [di] null?
7CCD: 74 17 je try_again go to 7CE6
7CCF: 60 pushaw
7CD0: B1 0B mov cl,0x0B 11 chars
7CD2: BE D8 7D mov si,0x7DD8 "JO SYS" or "IO SYS"
7CD5: F3 A6 rep cmpsb assumes that the D flag is still 0
7CD7: 61 popaw
7CD8: 74 3D je load_system go to 7D17
7CDA: 4E dec si
7CDB: 74 09 je try_again go to 7CE6
7CDD: 83 C7 20 addw di,0x0020
7CE0: 3B FB cmp di,bx
7CE2: 72 E7 jc compare_next go to 7CCB
7CE4: EB DD jmps go to 7CC3
try_again:
7CE6: FE 0E D8 7D dec [0x7DD8] restore the 'I' and try again (when we get an 'H' we don't branch)
7CEA: 7B A7 jnp retry go to 7C93
not_a_system_disk:
7CEC: BE 7F 7D mov si,0x7D7F
print: // print 2 strings (input si and then "Press Any Key")
7CEF: AC lodsb load 1 byte from si (implies "inc si")
7CF0: 98 cbw clear ah
7CF1: 03 F0 add si,ax add to si
next_char:
7CF3: AC lodsb load 1 character from string
7CF4: 98 cbw
7CF5: 40 inc ax is it 0xFF? (end of string followed by press a key)
7CF6: 74 0C je msg_press_key go to 7D04
7CF8: 48 dec ax is it 0x00? (end of string)
7CF9: 74 13 je msg_beep go to 7D0E
7CFB: B4 0E mov ah,0x0E put char in al on screen
7CFD: BB 07 00 mov bx,0x0007
7D00: CD 10 int 0x10
7D02: EB EF jmps next_char
msg_press_key:
7D04: BE 82 7D mov si,0x7D82
7D07: EB E6 jmps print go to 7CEF
io_error:
7D09: BE 80 7D mov si,0x7D80
7D0C: EB E1 jmps print go to 7CEF
msg_beep:
7D0E: CD 16 int 16 getchar() (keyboard read)
7D10: 5E pop si
7D11: 1F pop ds
7D12: 66 8F 04 popd [si]
7D15: CD 19 int 19 bootstrap loader (does not return)
The following found the file named JO.SYS or IO.SYS in the root directory
and it starts loading its first 4 sectors and execute them
On my system this file is 218Kb, so that's quite big. It certainly is
the handling of all of MSDOS.
load_system:
7D17: BE 81 7D mov si,0x7D81 <- this is weird...
7D1A: 8B 7D 1A mov di,[di+0x1A]
7D1D: 8D 45 FE lea ax,[di-0x02]
7D20: 8a 3E 0D mov cl,[bp+0x0D]
7D23: F7 E1 mulw cx
7D25: 03 46 FC add ax,[bp-0x04]
7D28: 13 56 FE adc dx,[bp-0x02]
7D2B: B1 04 mov cl,0x04 read 4 sectors
7D2D: E8 C2 00 calln read_nsectors go to 7DF2
7D30: 72 D7 jc io_error go to 7D09
7D32: EA 00 02 70 00 jmpf 0x0070:0x0200 start the system!
read_sector:
//
// all these push generate a Disk Address Packet structure
// note that the input is dx,ax with the LBA sector number
// and bx with the address where the sector is to be read (0x0700)
//
// the dx,ax notation is "advanced" and here they compute
// the old fashion read in al,ch,cl,dh,dl and es:bx even
// if we are to read with the new extended read... This
// is the opposite of that computation:
// (Cylinder x Heads + Selected Head) x Sectors per Track + Selected Sector - 1
//
7D37: 52 push dx block # (high)
7D38: 50 push ax block # (low)
7D39: 06 push es buffer segment
7D3A: 53 push bx buffer address
7D3B: 6A 01 push 0x0001 # of blocks to transfer
7D3D: 6A 10 push 0x0010 packet size (16 bytes) + reserved
7D3F: 91 xchg ax,cx mov ax in cx in 1 byte
7D40: 8B 46 18 mov ax,[bp+18] get our sectors per track
7D43: A2 26 05 mov [0x0526],al copy our sectors per track info
7D46: 96 xchg ax,si mov si,ax (sectors per track)
7D47: 92 xchg ax,dx mov ax,dx
7D48: 33 D2 xor dx,dx clear dx
7D4A: F7 F6 div si dx,ax / si => ax (remainder in dx)
7D4C: 91 xchg ax,cx restore ax
7D4D: F7 F6 div si dx,ax / si => ax (remainder in dx)
7D4F: 42 inc dx
7D50: 87 CA xchg cx,dx
7D52: F7 76 1A div [bp+0x1A] dx,ax / [bp+1A] (# of heads)
7D55: 8A F2 mov dh,dl duplicate remainder
7D57: 8A E8 mov ch,al ch = low eight bits of cylinder #
7D59: C0 CC 02 ror ah,2 put bits 0..1 in bits 6..7
7D5C: 0A CC or cl,ah cl = sector number + high cylinder bits
7D5E: B8 01 02 mov ax,0x0201 read disk command (non-extended!), 1 sector
7D61: 80 7E 02 0E cmp [bp+0x02],0x0E extended detected?
7D65: 75 04 jne not_extended go to 7D16B
7D67: B4 42 mov ah,42 extended read disk command
7D69: 8B F4 mov si,sp pointer to the disk address packet
not_extended:
7D6B: 8A 56 24 mov dl,[bp+0x24] drive number
7D6E: CD 13 int 13 floppy/hard disk service
7D70: 61 popaw get rid of the disk address packet
7D71: 61 popaw restore all the registers
7D72: 72 0A jc read_err go to 7D7E
7D74: 40 inc ax next sector (dx:ax + 1)
7D75: 75 01 jne no_carry go to 7D78
7D77: 42 inc dx manage overflow (32 bits number!)
no_carry:
7D78: 03 5E 0b add bx,[bp+0x0B] add size of 1 sector to address
7D7B: 49 dec cx read more sectors?
7D7C: 75 77 jne read_more go to 7DF5
read_err:
7D7E: C3 retn
7D7F: 03 0x7D83 -- message "\r\nDisque non systeme \377"
7D80: 18 0x7D99 -- message "\r\nErreur d'E/S \377"
7D81: 01 0x7D83 -- message "\r\nDisque non systeme \377"
7D82: 27 0x7DAA -- message "\r\nRemplacez-le et appuyez sur une touche \r\n\0"
7D83: 0D 0A 44 69 73 71 75 65 20 6E 6F 6E 20 73 79 73 74 65 6D 65 20 FF
7D99: 0D 0A 45 72 65 75 72 20 64 27 45 2F 53 20 20 FF
7DAA: 0D 0A 52 65 6D 70 6C 61 63 65 7A 2D 6C 65 20 65 74 20 61 70 70 75
7DC0: 79 65 7A 20 73 75 72 20 75 6E 65 20 74 6F 75 63 68 65 20 20 0D 0A 00
7DD7: 00 .byte 0x00 unused
7DD8: 49 4F 20 20 20 20 20 20 53 59 53 "IO SYS"
7DE3: 4D 53 54 4F 53 20 20 20 53 59 53 "MSDOS SYS"
7DEE: 7F 01 00 .byte 0x7F, 0x01, 0x00 seems unused
read:
7DF1: 41 inc cx it is assumed that cx = 0 on entry, so read 1 sector
read_nsectors:
7DF2: BB 00 07 mov bx,0x0700 address where sector is to be read
load_next:
7DF5: 60 pushaw save all registers
7DF6: 66 6A 00 push 0x00000000 start a read structure on the stack
7DF9: E9 3B FF jmpn load_sector go to 7D37
7DFC: 00 00 .byte 0x00, 0x00 unused
7DFE: 55 AA .byte 0x55, 0xAA valid MBR magic word