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