Tag Archives: micro fsd

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