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.
NOTE: Getting a “Invalid code for JFS” error could be cleared up with a sysinstx.com on the boot drive or by using DFSee.
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
Boot_Serial
is the 32-bit binary volume serial number for the media. Boot_System_ID
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.
The extended BPB structure is a super-set of the conventional BPB structure, as follows:
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