LVM MBR Disassembled
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