Loaded at 7C00h, setup stack and copy block from 7C00 to 7E00h. Push 7E20h on the stack and return near which will begin execution at 7E20h. This is the initial code loaded at 07C0:0000 and the disassembled code relocated at 07E0:0000 continues below.
After relocation the entry is at 7E20, I left out the 7E00 to 7E1F code which is not used. I am really only interested in the basic follow and the loaded and follow-on module, so some of the commenting could be better. In general, a Boot Manager partition is looked for and a simple consistency check is done on the MBR.
If you see below a check is made to verify INT 13 Extensions API support (see CheckINT13Ext). The result is stored at 3000:0000, if supported 58333149h is stored if not 0 is stored. This value is used later.
ReadDrive procedure is used to load the second drive without using the INT 13 Extensions API, but is used later to load the partition boot information using INT 13 Extensions API.
Things for my own note, there are 3 possible error messages while processing the LVM MBR: SYS01462, SYS01463, and SYS01464. Also, the drives look like they must support INT 13 Extensions API which should not be a problem now days.
The partition boot information is loaded at 7C00 and execution is continued.
(7C00h) _entry proc near ; disable interupts cli ; setup stack mov ax, 30h mov ss, ax mov sp, 100h ; decimal 256 ; enable interupts sti ; move 7C00 to 7E00 +512 cld xor ax, ax ; Zero out the Accumulator mov ds, ax ; Zero-out Data Segment mov es, ax ; Zero-out Extra Segment mov si, 7C00h ; Copy from here... mov di, 7E00h ; copy to here: 0000:7E00 mov cx, 200h ; 200h (512 words) count rep movsw ; push return addr 7E20 and execute return push 7E20h retn _entry endp
After the code is moved from 0000:7C00 to 0000:7E00 the entry point is 0000:7E20.
(7E20) _relocentry proc near mov si, 7EFAh ; si point to SYS01462 message start mov bx, 7FBEh ; bx set to first partition info location ; *** Check for Boot Manager ; read each MBR record and check if it is type Boot Manager (0x0A). bootman00: cmp byte ptr [bx+4], 0Ah ; cmp part type 11 (0Ah) BootManager jz short checktype ; jump if Boot Manager partition found add bx, 10h ; setup to read next partition entry cmp bx, 7FFEh ; check for sig - end of MBR if not get next jl short bootman00 xor ax, ax ; zero ax int 13h ; DISK - RESET DISK SYSTEM ; DISK - GET DRIVE PARAMETERS (PC,XT286,CONV,PS,ESDI,SCSI) ; AH = 08h ; DL = drive (bit 7 set for hard disk) ; Return:CF set on error ; AH = status (07h) (see #0211) ; CF clear if successful ; AH = 00h ; AL = 00h on at least some BIOSes ; BL = drive type (AT/PS2 floppies only) (see #0219) ; CH = low eight bits of maximum cylinder number ; CL = maximum sector number (bits 5-0) ; high two bits of maximum cylinder number (bits 7-6) ; DH = maximum head number ; DL = number of drives ; ES:DI -> drive parameter table (floppies only) ; check for drive #2 mov ah, 8 mov dl, 81h ; drive 2 int 13h jb short checktype ; jump no 2nd drive ; read 2nd drive MBR mov cx, 7FB4h mov dl, 81h call ReadDrive or ah, ah jnz short checktype ; jump if read error cmp word ptr ds:7DFEh, 0AA55h ; check signature jnz short checktype ; jump not valid MBR signature mov bx, 7DBEh ; set start 2nd drive MBR info ; Check for Boot Manager on 2nd drive bootman01: cmp byte ptr [bx+4], 0Ah jnz short bootman02 ; the following get executed if a 0Ah found on 2nd drive mov dl, 81h ; second drive 81h in dl mov cx, bx ; bx - location of 0Ah partition info jmp short extcheck2 bootman02: add bx, 10h cmp bx, 7DFEh jl short bootman01 ; *** Check for bootable partition ; get here if boot manager part found on 1st drive, no second drive, and falls through ; no boot manager found on second drive checktype: mov bx, 7FBEh ; load _bootind partition 1 xor cx, cx ; zero cx ; seems to just run through the MBR and ensure it is somewhat correct checktype1: cmp byte ptr [bx], 80h ; is it bootable? jnz short checktype2 ; jump if not bootable or cx, cx jnz short DispMsgEntry ; Not zero display SYS01462 error and hang mov cx, bx jmp short checktype3 checktype2: cmp byte ptr [bx], 0 ; is it 0 (not-bootable) - so if not 80h or 0 then unknown _bootind jnz short DispMsgEntry ; Not zero display SYS01462 error and hang checktype3: add bx, 10h ; increment to next partition record cmp bx, 7FFEh ; at the end of MBR - check signature jl short checktype1 or cx, cx jnz short extcheck1 int 18h ; None were bootable, so start ROM-BASIC many ; BIOS simply display "PRESS A KEY TO REBOOT" ; when an Interrupt 18h is executed. extcheck1: mov dl, 80h ; first drive ; at this point dl contains drive number 80h or 81h extcheck2: pusha ; PUSH AX, CX, DX, BX, SP, BP, SI and DI call CheckINT13Ext popa ; POP AX, CX, DX, BX, SP, BP, SI and DI push dx push cx call ReadDrive jz short vbr00 ; jump no error mov si, 7F0Fh ; SYS01463 Message jmp short DispMsgEntry ; Not zero display error and hang vbr00: mov si, 7F24h ; SYS01464 Message cmp ds:SigEnd, 0AA55h ; compare to end block signature jnz short DispMsgEntry ; Not zero display error and hang pop si ; seems to hold MBR pointer pop dx ; boot drive number jmp far ptr 0000:7C00h ; ** jump 0000:7C00 ** _relocentry endp ; IBM/MS INT 13 Extensions - INSTALLATION CHECK ; AH = 41h ; BX = 55AAh ; DL = drive (80h-FFh) ; Return:CF set on error (extensions not supported) ; AH = 01h (invalid function) ; CF clear if successful ; BX = AA55h if installed ; AH = major version of extensions ; 01h = 1.x ; 20h = 2.0 / EDD-1.0 ; 21h = 2.1 / EDD-1.1 ; 30h = EDD-3.0 ; AL = internal use ; CX = API subset support bitmap (see #0248) ; DH = extension version (v2.0+ ??? -- not present in 1.x) ; Note: The Phoenix Enhanced Disk Drive Specification v1.0 uses version 2.0 of the INT 13 Extensions API ; ; See Also: AH=42h"INT 13 Ext" - AH=48h"INT 13 Ext" ; ; Bitfields for IBM/MS INT 13 Extensions API support bitmap: ; ; Bit(s) Description (Table 0248) ; 0 extended disk access functions (AH=42h-44h,47h,48h) supported ; 1 removable drive controller functions (AH=45h,46h,48h,49h,INT 15/AH=52h) ; supported ; 2 enhanced disk drive (EDD) functions (AH=48h,AH=4Eh) supported. ; Extended drive parameter table is valid (see #0250,#0255) ; 3-15 reserved (0) ; ; NOTE: From : http://lrs.uni-passau.de/support/doc/interrupt-57/RB-0668.HTM ; checks for extended int 13 capability - ; Exit if supported 3000:0000 move 58333149h ; not supported mov 0 ; * dl contains drive number on entry (7EBA) CheckINT13Ext proc near mov ah, 41h mov bx, 55AAh int 13h jb short NoINT13Ext ; jump to NoINT13Ext is not supported cmp bx, 0AA55h ; AA55h if installed INT 13 Extensions API jnz short NoINT13Ext cmp ah, 21h ; major version of extensions 21h = 2.1 / EDD-1.1 jb short NoINT13Ext test cl, 1 ; Test if extended Disk Access functions supported jz short NoINT13Ext mov eax, 58333149h jmp short INT13Continue NoINT13Ext: xor ax, ax ; zero ax if ext 13 not supported INT13Continue: push 3000h ; store eax at 3000:0000 pop fs mov fs:0, eax retn CheckINT13Ext endp
There are 3 possible error messages while processing the LVM MBR: SYS01462, SYS01463, and SYS01464:
***** DISPLAY MESSAGE LOOP ***** (7EE8) DispMsgEntry: xor bx, bx ; zero bx jmp short DispMsg DispNext: int 10h DispMsg: mov ah, 0Eh lodsb ; get char of message or al, al ; check if end jnz short DispNext sti HangLoop: jmp short HangLoop ; The following boot message information is from Bob Eager, ; Tavi Systems page http://www.tavi.co.uk/os2pages/boot.html: ; SYS01462 ; The partition table on the startup drive is incorrect. Generally, this ; means either that more than one partition is marked active, or one of ; the partitions has a status byte with a value other than 00H or 80H, ; which are the only legal values. 7EF8 db 12h 7EF9 db 0 7EFA _SYS01462 db 'OS/2 !! SYS01462',0Dh,0Ah,0 ; SYS01463 ; The operating system cannot be loaded from the startup drive. This is ; caused by a disk read error, while reading the boot sector of the ; active partition 7F0D db 12h 7F0E db 0 7F0F _SYS01463 db 'OS/2 !! SYS01463',0Dh,0Ah,0 ; SYS01464 ; The operating system is missing from the startup drive. A valid boot ; sector for a partition should contain the values 055H and 0AAH in its ; last two bytes, in that order. This is a simple validation check, ; intended to prevent attempts to boot from a corrupt or unformatted ; partition. This message is generated if the validation check for ; these two bytes fails. 7F22 db 12h 7F23 db 0 7F24 _SYS01464 db 'OS/2 !! SYS01464',0Dh,0Ah,0
ReadDrive procedure loads MBR of the second drive and the boot record of the botable partition:
; On entry: ; DL == drive ; CX == location of Track + Sector to read ; location 3000:0000 == 49h ext read supported else old 0 - 1023 read ReadDrive proc near mov bx, cx mov di, 5 ; see INT13Ext storage 3000:0000 push 3000h pop fs cmp byte ptr fs:0, 49h jz short ExtRead ; equals 49h if ext supported ; CX contains both the cylinder number (10 bits, possible ; values are 0 to 1023) and the sector number (6 bits, possible values are 1 to 63): mov cx, [bx+2] ; Head mov dh, [bx+1] ; (ES):BX = Memory Buffer mov bx, 7C00h ReadOld01: xor ax, ax int 13h ; Reset DISK mov ax, 201h ; Function 2 AH == 00000010 / Sectors To Read Count AL == 00000001 int 13h ; INT 13, -- Read Sectors From Drive jnb short ReadOld02 ; error reading dec di ; number of retries - default 5 jg short ReadOld01 ; retry read ReadOld02: retn ; The following are the "INT 13 Extensions Installation Check" and ; the Extended READ sectors from Hard Drive (Function 42h) routines. ; **** Normal entry if Ext int13 supported after CheckINT13Ext call ExtRead: ; dl == drive number push ds mov eax, [bx+8] ; load number of sectors before partition from MBR ; set fs and ds 0x3000 push fs pop ds ; DS:SI segment:offset pointer to the DAP, see below ; DAP == 3000:0008 mov si, 8 ; DAP : Disk Address Packet (16 bytes) ; offset range size description ; 00h 1 byte size of DAP = 16 = 10h ; 01h 1 byte unused, should be zero ; 02h 1 byte number of sectors to be read, 0..127 (= 7Fh) ; 03h 1 byte unused, should be zero ; 04h..07h 4 bytes segment:offset pointer to the memory buffer to which sectors will be transferred ; 08h..0Fh 8 bytes absolute number of the start of the sectors to be read (1st sector of drive has number 0) mov ds:4, eax mov [si+8], eax xor eax, eax ; zero eax mov word ptr [si], 10h ; 00h BYTE 10h (size of packet) mov word ptr [si+2], 1 ; number of blocks to transfer mov word ptr [si+4], 7C00h ; -> transfer buffer mov [si+6], ax mov [si+0Ch], eax ; DAP" ; 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 ; 10 00 01 00 [00 7C 00 00] [00 3F 00 00 00 00 00 00] ReadJmp04: sub ax, ax int 13h ; Reset drive mov ah, 42h ; function number for extended read int 13h jnb short ReadJmp05 ; Error dec di ja short ReadJmp04 ; Retry read ReadJmp05: pop ds retn ReadDrive endp
; The following is an example using my current Virtual PC drive ; src/jfs/utils/libfs/mbr.h -- from openJFS source located on Netlabs.org ; ; struct part { ; UCHAR bootind; /* 0x80 means partition is bootable */ ; UCHAR starthead; /* head number of partition start */ ; UCHAR startsect; /* sector number */ ; UCHAR startcyl; /* cylinder number */ ; UCHAR systind; /* partition ID */ ; UCHAR endhead; /* head number of partition end */ ; UCHAR endsect; /* sector number */ ; UCHAR endcyl; /* cylinder number */ ; ULONG lsn; /* number of sectors before partition */ ; ULONG nsects; /* number of sectors in partition */ ; }; ; ; struct mbr { ; UCHAR code[0x1be]; /* boot record code and data */ ; struct part ptbl[4]; /* the partition table */ ; USHORT sig; /* special signature */ ; }; 7FB8 OptiDiskSig dd 0 7FBC dw 0CC33h 7FBE ; ***** Partition 1 ***** 7FBE _bootind db 80h ; bootable 7FBF _starthead db 1 7FC0 _startsect db 1 7FC1 _startcyl db 0 7FC2 _systind db 7 7FC3 _endhead db 3Fh 7FC4 _endsect db 0FFh 7FC5 _endcyl db 0F6h 7FC6 _lsn dd 3Fh 7FCA _nsects dd 3E7201h 7FCE ; ***** Partition 2 ***** 7FCE Part2 db 10h dup(0) 7FDE ; ***** Partition 3 ***** 7FDE Part3 db 10h dup(0) 7FEE ; ***** Partition 4 ***** 7FEE Part4 db 10h dup(0) 7FFE ; ***** Signature ***** 7FFE SigEnd dw 0AA55h