The micro-FSD

This module contains the micro-FSD which is located between the partition bootsector and the actual data on the hard drive. The load segment was calculated in Phase 2 and for the Bochs drive image is 0x8800. The entry point is 8800:199C or 0x8999C with the registers (Bochs image) loaded as follows:

 

	eax: 0x0000199C
	ecx: 0x00007FBE
	edx: 0x00000080
	ebx: 0x00000000
	esp: 0x00007C00
	ebp: 0x00000000
	esi: 0xFFFF0046
	edi: 0x00000000
	eflags 0x00000246
	IOPL=0 id vip vif ac vm rf nt of df IF tf sf ZF af PF cf

 

Segment registers:

 

cs:s=0x8800    ds:s=0x8800    ss:s=0x0000    es:s=0x07C0    fs:s=0x3000

 

This is somewhat irrelevant because es, ds, and ss will be set to cs (0x8800 in this example) and sp set to 0x5000.

Items from previous loads:

 

  • If INT13 Ext functions are supported then 3000:0000, segment contain in fs, has 58333149h, stored as 49 31 33 58. If not the location is zero.
  • The storage area contains the results of Phase 2 — (Bochs disk) 0x8803E 3F, 0, 0 0, 0, 0, 0, 0 or 0x000000000000003F.

The JFS superblock procedure loads the super block and stores values at the following locations:

 

superblock 8800:160C (0x8960C to 0x8980C)
offset 1858 to 185B (0x89858 to 0x89858)
offset 185C to 185F (0x8985C to 0x8985F)

; module locations
ft_cfiles dw 3
ft_ldrseg dw 0
ft_ldrlen dd 0
ft_museg dw 0
ft_mulen dd 0x5000
ft_mfsseg dw 0
ft_mfslen dd 0
ft_ripseg dw 0
ft_riplen dd 0x0

; microFSD vector table
ft_muOpen dd seg:1A9C
ft_muRead dd seg:1BD4
ft_muClose dd seg:1DAE
ft_muTerminate dd seg:1DD4

 

88000	jmp	short near ptr _entry  ;  Entry point from MBR code
88002	nop

;  BIOS parameter block (BPB) 
88003	db    'IBM 4.50'    ; Partition creator
8800B	db    0, 2    ; 0x0200 size of sector in bytes
8800D	db    0
8800E	db    0
8800F	db    0
88010	db    0
88011	db    0
88012	db    0
88013	db    0
88014	db    0
88015	db   F8    ; media type - hard disk
88016	db    0
88017	db    0
88018	db   3F, 0		; BPB formatted geo: Sectors - 63
8801A	db    20, 0		; BPB formatted geo: Heads - 32
8801C	db    3F, 0, 0 ,0	; 0x0000003F hidden sectors
88020	db    41, 12, 13, 0    ; 0x00131241 Big number of sectors
88024	db    80    		;  physical drive number
88025	db    80    		;  Boot drive letter
88026	db    29    		;  Ext-BPB signature
88027	db    BD , 55,  9C, 69    ;  Partition serial number 0x699c55bd
8802B	db    bochs, 0, 0, 0, 0, 0, 0    ; Partition label (11)
88036	db    "JFS     "    ; Filesystem type (8)

; Used as temp storage
8803E	db    0, 0, 0, 0    ; absolute number of the start of the sectors
88042	db    0, 0, 0, 0

; DAP : Disk Address Packet (16 bytes)
88046	db    10		; size of DAP = 16 = 10h
88047	db    0			; unused, should be zero
88048	db    20		; number of sectors to be read
88049	db    0			; unused, should be zero
8804A	db    0, 0, 0, 0	;segment:offset pointer to the memory buffer
8804E	db    0, 0, 0, 0, 0, 0, 0, 0

 

 

; eax: 0x00000001 ecx: 0x00007fbe edx: 0x00000080 ebx: 0x00000000
; esp: 0x00004ffe ebp: 0x00000000 esi: 0xffff160c edi: 0x00000040
; IOPL=0 id vip vif ac vm rf nt of df IF tf sf ZF af PF cf

 

; 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
	mov	bx, 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
;  Display address in hex

 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
	mov	bx, 7
	int	10h		
	retn			

dispchar	endp

 

eax: 0x0000199c 6556
ecx: 0x00007fbe 32702
edx: 0x00000080 128
ebx: 0x00000000 0
esp: 0x00007c00 31744
ebp: 0x00000000 0
esi: 0xffff0046 -65466
edi: 0x00000000 0
eip: 0x0000199c
eflags 0x00000246
IOPL=0 id vip vif ac vm rf nt of df IF tf sf ZF af PF cf

; cs:s=0x8800 ds:s=0x8800 ss:s=0x0000 es:s=0x07c0 fs:s=0x3000

0x0008924a <bogus+ 0>: 0x03 0x00 0x00 0x10 0x00 0xae 0x00 0x00
0x00089252 <bogus+ 8>: 0x00 0x88 0x00 0x50 0x00 0x00 0x7c 0x00
0x0008925a <bogus+ 16>: 0xe9 0xea 0x00 0x00 0x00 0x00 0x00 0x00
0x00089262 <bogus+ 24>: 0x00 0x00 0x9c 0x1a 0x00 0x88

 

8924A ft_cfiles       dw 0x0003
8924C ft_ldrseg       dw 0x1000
8924E ft_ldrlen       dd 0xAE ; will vary with version of os2ldr used
89252 ft_museg        dw 0x0000
89254 ft_mulen        dd 0
89258 ft_mfsseg       dw 0
8925A ft_mfslen       dd 0
8925E ft_ripseg       dw 0
89260 ft_riplen       dd 0

; microFSD vector table
89264 ft_muOpen_OFF   		dw 0
89266 ft_muOpen_SEG   		dw 0
89268 ft_muRead_OFF   		dw 0
8926A ft_muRead_SEG   		dw 0
8926C ft_muClose_OFF  		dw 0
8926E ft_muClose_SEG  		dw 0
89270 ft_muTerminate_OFF 	dw 0
89272 ft_muTerminate_SEG 	dw 0

 

This is the main entry point from Phase 2:

 

(SEG:199C)
_entry	proc far
	push	cs
	pop	ax
	mov	es, ax		; swap cs to es
	mov	ds, ax		; set ds to cs

	; setup	stack
	cli
	mov	ss, ax		; set ss to cs
	mov	sp, 5000h
	sti
	; es / ds / ss	set to entry cs

	call	readsuperblock

	mov	ax, 202h
	push	ds
	push	ax
	push	ds
	mov	si, 2B2Fh	; ALTF2ON.$$$ location
	push	si
	mov	ax, cs
	mov	word ptr cs:loc_899BC+3, ax

loc_899BC:				
	call	ft_muOpen
	add	sp, 8		; clean	up the stack - post C function?
	or	ax, ax
	jnz	short MAIN_JMP_1 ; ?? zero return is good result
	mov	al, 1
	mov	ds:byte_8AB2E, al
	mov	ax, cs
	mov	word ptr cs:loc_899D3+3, ax

loc_899D3:				
	call	ft_muClose

MAIN_JMP_1:				
	mov	si, 1D6h		; os2boot file name
	mov	di, 7Ch			; os2boot load address
	mov	ds:ft_mfsseg, di  ; miniFSD location
	call	LoadFile
	test	bx, 1		; test if good load
	jz	short good_os2boot

	mov	si, 1274h	; SYS1475: The file OS2BOOT cannot be found
	call	ErrorHangSys    ; does not return

good_os2boot:				
	mov	eax, ds:dword_88202
	mov	ds:ft_mfslen, eax    ; miniFSD length
	mov	si, 1CFh	; os2ldr file name
	mov	di, 1000h	; os2boot load address
	mov	ds:ft_ldrseg, di    ; os2ldr location
	call	LoadFile
	test	bx, 1		; test if good load
	jz	short good_os2ldr

	mov	si, 12ABh	; Missing OS2LDR
	call	ErrorHangSys    ; does not return

good_os2ldr:
	mov	eax, ds:dword_88202
	mov	ds:ft_ldrlen, eax    ; os2ldr length

	; loading 0Fh to DispCopyInd stops display
	; of copyright message

	mov	al, 0Fh
	mov	ds:DispCopyRInd, al

	; setup MicroFSD entry
	push	ds
	pop	ax
	mov	ds:ft_museg, ax    ; MicroFSD location
	mov	eax, 5000h
	mov	ds:ft_mulen, eax    ; MicroFSD length

	; number of entries
	mov	ds:ft_cfiles, 3

	; sets up a function list
	mov	ds:ft_muOpen_SEG, ds
	mov	ds:ft_muOpen_OFF, 1A9Ch	; ds:1A9C
	mov	ds:ft_muRead_SEG, ds
	mov	ds:ft_muRead_OFF, 1BD4h	; ds:1BD4
	mov	ds:ft_muClose_SEG, ds
	mov	ds:ft_muClose_OFF, 1DAEh ; ds:1DAE
	mov	ds:ft_muTerminate_SEG, ds
	mov	ds:ft_muTerminate_OFF, 1DAEh ; ds:1DD4
	mov	ds:ft_ripseg, 0
	mov	ds:ft_riplen, 0

	push	ds
	push	cs
	pop	ds
	mov	eax, dword ptr ds:aJfs+8
	mov	ds:dword_8801C,	eax
	pop	ds
	assume ds:nothing
	xor	di, di		; zero di
	mov	es:[di], eax
	mov	dl, ds:24h
	mov	dh, dl
	mov	ds:24h,	dx
	mov	dh, 14h
	mov	si, 0Bh
	push	ds
	pop	es
	mov	di, 124Ah
	mov	ax, ds:124Ch
	push	ax
	xor	ax, ax
	push	ax

	retf	; Should be a return which enters os2ldr

_entry	endp

 

 

readsuperblock  proc near

	mov	si, 160Ch    ; 8800:160C buffer
	mov	ax, 1		; read 1 sector

	mov	edi, 40h      ; offset from beginning of partition 
	mov	ebx, 0         ; for read

	; read 1 sector from offset of partition 0x40 (64) or 32,768
	; from the IBM docs this would be the superblock and it gets
	; read into memory at offset 160C buffer 
	; see openJFS -- jfs_superblock.h
	call	readdrive      ; load superblock to 0x8960C

	mov	eax, ds:161Ch
	bsf	ecx, eax
	mov	ds:1942h, cx     ; 0x89942
	mov	edx, ds:163Ch
	and	edx, 0FF000000h
	shr	edx, 18h
	mov	eax, ds:1640h
	shld	edx, eax, cl
	shl	eax, cl
	mov	ds:1858h, eax         ; 0x89858
	mov	ds:185Ch, edx         ; 0x8985C
	mov	dword ptr ds:23Eh, 2  ; 0x8823E
	push	bp
	mov	bp, sp
	xor	ecx, ecx
	mov	di, 3D45h
	call	sub_8AA59
	mov	cl, al
	mov	ch, 0
	push	cx
	mov	di, 1509h
	call	sub_8AA59
	mov	bx, 1
	pop	cx
	cmp	cl, al
	jg	short loc_8AA55
	mov	si, 3D45h
	mov	di, 1509h
	mov	bx, 1
	repe cmpsb
	or	cl, cl
	jnz	short loc_8AA55
	cmp	byte ptr es:[di], 5Ch ;	'\'
	jz	short loc_8AA3E
	cmp	byte ptr es:[di], 0
	jnz	short loc_8AA55

loc_8AA3E:				
	mov	al, [si-1]
	cmp	al, es:[di-1]
	jnz	short loc_8AA55
	mov	di, si
	mov	al, 5Ch	; '\'
	stosb
	mov	ds:14EFh, di
	xor	ax, ax
	stosb
	xor	bx, bx

loc_8AA55:				
	mov	ax, bx
	pop	bp
	retn

readsuperblock  endp