BIOS parameter block (BPB) is a variant record embedded within the boot block (block zero) of a disc volume. In the example below the BPB is located from 0x7C0B to 0x7C36. The references I used, bios-parameter-block and DFSee.
Entry is made at 0x7C00 followed by a jump to _entry. After the stack is set up INT 12 is called to find the top of low memory (640K). Next, 54h (84 dec) is subtracted, and AND with 0xFFF0 then shifted left (6) to get the segment for the next module load (micro-FSD). For the Bochs example image the result is 0x8800. A load of BPB+31 sectors is loaded at the calculated segment and offset 0x0000 and the temp storage area is moved to this area (7C3E – 7C45). This load contains the instructions to continue the system load and the micro-FSD.
During the drive read and error will result in DAP information being displayed and a SYS02027 message, the system will then hang. The error sequence is from the readdrive procedure which is also used executing the micro-FSD loading code.
A check of the calculated segment and offset 0x0200 is made for 0x1961 signature. If the signature is found and return from function is executed which will result in execution continuing at the calculated load segment and offset 0x199C (Bochs image 8800:199C or 0x8999C). If the signature is now found, a “Invalid code for JFS” error and some address information will be displayed and the system will hang.
On entry a register dump and these might not be set values (based on Bochs image):
eax: 0x00000000 ecx: 0x00007fbe — MBR info location edx: 0x00000080 — Drive number
ebx: 0x00007fbe — MBR info location esi: 0xffff7fbe — MBR info location
edi: 0x00080005 eip: 0x00007c00
eflags 0x00000246
cs:s=0x0000 ds:s=0x0000 ss:s=0x0030 es:s=0x0000
fs:s=0x3000 — location of INT 13 Ext result
The Extended Boot structure is as follows:
struct Extended_Boot { unsigned char Boot_jmp[3]; unsigned char Boot_OEM[8]; struct Extended_BPB Boot_BPB; unsigned char Boot_DriveNumber; unsigned char Boot_CurrentHead; unsigned char Boot_Sig = 41; /* Indicate Extended Boot */ unsigned char Boot_Serial[4]; unsigned char Boot_Vol_Label[11]; unsigned char Boot_System_ID[8]; };
Where
is an 8-byte name written when the media is formatted. It is used by FSDs to identify their media but need not be the same as the name the FSD exports via FS_NAME and is NOT the name users employ to refer to the FSD. (They may, however, be the same names). Boot_Vol_Label
is the 11-byte ASCII label of the disk/diskette volume. FAT file systems must ALWAYS use the volume label in the root directory for compatibility reasons. An FSD may use the one in the boot sector.
struct Extended_BPB { unsigned short BytePerSector; unsigned char SectorPerCluster; unsigned short ReservedSectors; unsigned char NumberOfFats; unsigned short RootEntries; unsigned short TotalSectors; unsigned char MediaDescriptor; unsigned short SectorsPerFat; unsigned short SectorsPerTrack; unsigned short Heads; unsigned long HiddenSectors; unsigned long Ext_TotalSectors; };
7C00 jmp short near ptr _entry ; Entry point from MBR code 7C02 nop ; BIOS parameter block (BPB) 7C03 db 'IBM 4.50' ; Partition creator 7C0B db 0, 2 ; 0x0200 size of sector in bytes 7C0D db 0 7C0E db 0 7C0F db 0 7C10 db 0 7C11 db 0 7C12 db 0 7C13 db 0 7C14 db 0 7C15 db F8 ; media type - hard disk 7C16 db 0 7C17 db 0 7C18 db 3F, 0 ; BPB formatted geo: Sectors - 63 7C1A db 20, 0 ; BPB formatted geo: Heads - 32 7C1C db 3F, 0, 0 ,0 ; 0x0000003F hidden sectors 7C20 db 41, 12, 13, 0 ; 0x00131241 Big number of sectors 7C24 db 80 ; physical drive number 7C25 db 80 ; Boot drive letter 7C26 db 29 ; Ext-BPB signature 7C27 db BD , 55, 9C, 69 ; Partition serial number 0x699c55bd 7C2B db bochs, 0, 0, 0, 0, 0, 0 ; Partition label (11) 7C36 db "JFS " ; Filesystem type (8) ; Used as temp storage 7C3E db 0, 0, 0, 0 ; absolute number of the start of the sectors 7C42 db 0, 0, 0, 0 ; DAP : Disk Address Packet (16 bytes) 7C46 db 10 ; size of DAP = 16 = 10h 7C47 db 0 ; unused, should be zero 7C48 db 20 ; number of sectors to be read 7C49 db 0 ; unused, should be zero 7C4A db 0, 0, 0, 0 ;segment:offset pointer to the memory buffer 7C4E db 0, 0, 0, 0, 0, 0, 0, 0
_entry proc far cli ; Clear Interrupt Flag xor ax, ax ; zero ax mov ss, ax ; set SS to 0000 mov sp, 7C00h ; set stack pointer sti ; Set Interrupt Flag mov bx, 7C0h mov es, bx ; 7C0 to es sti ; Set Interrupt Flag ; ax == 0 ss == 0 sp == 7C0 es == 7C0 ; Find the top of continuous low memory (640K) ; subtract 54h (84 dec) or 84K ; clear lower 4 bits ; shift left 6 bits and move to ds ; this will be the segment address for os2boot loading ; Returns 27Fh - 639 is returned from Bochs and final ds == 0x8800 int 12h ; MEMORY SIZE - LOW MEM Return: AX = number of contiguous 1K blocks of memory sub ax, 54h ; subtract 54h -- 84 dec and ax, 0FFF0h ; 1111111111110000b - results in 220h shl ax, 6 ; Shift Logical Left mov ds, ax xor edi, edi ; zero edi xor ebx, ebx ; zero edx mov eax, es:1Ch ; load eax 0x1C (Bochs drive 0x0000003F) hidden sectors ; add start of partition to readdrive storage add es:3Eh, eax adc es:42h, ebx push ds ; buffer segment mov ax, 20h ; number sectors to read xor si, si ; buffer offset ; Bochs drive: ; eax: 0x00000020 ecx: 0x00007fbe edx: 0x00000080 ebx: 0x00000000 esp: 0x00007bfe ; esi: 0xffff0000 edi: 0x00000000 ; cs:s=0x0000 ds:s=0x8800 ss:s=0x0000 es:s=0x07c0 fs:s=0x3000 call readdrive pop ds ; Bochs drive: ; if reados2boot returns from goodread, registers: ; eax: 0x00000000 ecx: 0x00007fbe edx: 0x00000080 ebx: 0x00000000 esp: 0x00007c00 ; ebp: 0x00000000 esi: 0xffff0046 ; cs:s=0x0000 ds:s=0x8800 ss:s=0x0000 es:s=0x07c0 fs:s=0x3000 ; stack is empty ; move from part. boot data to Phase 3 data area mov eax, es:3Eh mov ds:3Eh, eax ; Bochs image move 0x7C3E to 0x8803E mov eax, es:42h mov ds:42h, eax ; Bochs image move 0x7C42 to 0x88042 mov al, es:24h mov ds:24h, al ; Bochs image move 0x7C24 to 0x88024 ; check for 1961h at 8800:0200 (0x88200) cmp word ptr ds:200h, 1961h jz short _goodload mov ax, 7C0h mov ds, ax mov ax, ds:200h ; move 7E00 to ax == 0xb8fa mov si, 0C8h ; *** display - "Invalid code for JFS" *** call displayerr _goodload: push ds ; segment entry -- calc from previous mov ax, 199Ch ; Offset push ax ; 8800:199C (0x8999C) for Bochs drive retf ; Return Far from Procedure _entry endp
(0x7CC8) InvalidCode db 'Invalid code for JFS ',0 (0x7CDE) Sys02027 db '- SYS02027 - ',0
;On entry the Bochs registers are: ; eax: 0x00000020 ecx: 0x00007fbe edx: 0x00000080 ebx: 0x00000000 esp: 0x00007bfe ; esi: 0xffff0000 edi: 0x00000000 ; cs:s=0x0000 ds:s=0x8800 ss:s=0x0000 es:s=0x07c0 fs:s=0x3000 ; readdrive ; ; entry: ; ax contains number of sectors to read ; es segment for DAP structure ; ds segment for transfer buffer ; si offset for transfer buffer ; es:003E + 4 and es:0042 + 4 absolute number start sectors to read ; es:0024 drive index ; di (L) and bx (H) contain offset to absolute start for begin read readdrive proc near push ds ; save ds and dx push dx mov dx, ds push es pop ds ; set ds to entry es value ; 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 ; This routine DAP structure: ; ds:0046 size of DAP - 16 bytes always ; ds:0047 always zero ; ds:0048 number of sectors to read ; ds:0049 always zero ; ds:004A to 004D segment:offset pointer transfer buffer ; ds:004E to 0055 absolute number of the start of the sectors to be ; read (1st sector of drive has number 0) ; Load DAP mov ds:48h, ax ; number of sectors to read, ax contains on entry mov ds:4Ch, dx ; Buffer segment mov ds:4Ah, si ; Buffer offset mov si, 46h ; DAP offset mov eax, ds:3Eh ; move sector read start from storage area mov ds:4Eh, eax ; ds:003E to ds:0055 to DAP mov eax, ds:42h mov ds:52h, eax add ds:4Eh, edi adc ds:52h, ebx ; DAP located at ds:0046 mov ah, 42h ; 42h = function number for extended read mov dl, ds:24h ; drive index mov al, 0 int 13h ; cf Set On Error, Clear If No Error ; ah Return Code jnb short goodread or ah, ah jnz short readerror goodread: pop dx ; restore entry dx and ds before returning pop ds retn readerror: ; display some DAP info push ax mov eax, ds:52h shr eax, 10h call dispaddress mov eax, ds:52h call dispaddress mov eax, ds:4Eh shr eax, 10h call dispaddress mov eax, ds:4Eh call dispaddress mov ax, ds:48h shl eax, 10h pop ax mov al, dl mov si, 0DEh ; SYS02027 message call $+3 ; really a jump to displayerr - never returns readdrive endp ; displayerr ; Display error message pointed to by ds:(e)si and address ; then hang the system displayerr proc near cld push eax _dispnextchar: lodsb ; Load byte at address DS:(E)SI into AL test al, 0FFh jz short _endmessage mov ah, 0Eh ; int10 teletype output mov bx, 7 ; page 0 - color 7 int 10h jmp short _dispnextchar _endmessage: sti pop eax push eax and eax, 0FFFF0000h shr eax, 10h call dispaddress mov al, 3Ah mov ah, 0Eh mov bx, 7 int 10h pop eax call dispaddress _hangsystem: jmp short _hangsystem displayerr endp ; dispaddress ; Entry - address (16 bit) in ax ; Display address in hex on page 0 dispaddress proc near push ax mov al, ah and al, 0F0h mov cl, 4 shr al, cl call dispchar pop ax push ax mov al, ah and al, 0Fh call dispchar pop ax push ax and al, 0F0h mov cl, 4 shr al, cl call dispchar pop ax push ax and al, 0Fh call dispchar pop ax retn dispaddress endp ; dispchar ; Output char from dispaddress dispchar proc near add al, 30h cmp al, 39h jle short _dispchar1 add al, 7 _dispchar1: mov ah, 0Eh ; int10 teletype output mov bx, 7 ; page 0 - color 7 int 10h retn dispchar endp
Os2ldr db 'OS2LDR',0 Os2boot db 'OS2BOOT',0 shtemenko db '(c) P.Shtemenko 2002,2004',0 db 0 db 0 db 0 db 0 db 0 db 0 dw 0AA55h