I have some bootcode that reads sectors off the hard disk. The problem that I am having is that reading a sector onto the stack doesnt work (int 31 returns AH as 0Ch), while reading the sector into a global varible seems ok.
Code:
;_____________________________________________________________________
;_____________________________________________________________________
; IN: FS:DI = PTR to S_DriveStat
; ES:BX = Data buffer
; ECX = Sector
; AL = Sectors to Read (AX for Extended Read)
; OUT: AH return code: 0 = Success
ReadSector PROC
LOCAL dwRet : DWORD
LOCAL sDAP : S_DISK_ADDRESS_PACK
LOCAL TempBuffer[512] : BYTE
PUSHAD
;Override the ES:BX passed in with the address of the local TempBuffer
LEA BX, TempBuffer
PUSH SS
POP ES
ReadSector_Ex:
MOV sDAP.bySize, 10h
MOV sDAP.byReserved, 0
MOV sDAP.wBufferOffset, BX
MOV sDAP.wBufferSegment, ES
MOV sDAP.wSectorCount, AX
MOV sDAP.dwSectorNumberLo, 0
MOV sDAP.dwSectorNumberHi, 0
LEA SI, sDAP.bySize ; DS:SI = ptr to S_DISK_ADDRESS_PACK
PUSH DS
PUSH SS
POP DS
MOV EDX , FS:[DI.S_DriveStats.dwDiskNum] ; Drive
MOV EAX, 4200h
INT 13h
MOV dwRet, EAX
POP DS
JNC ReadSector_Ret ;Jmp if Successfull
;todo remove
;print the error code in AH
PUSH EAX
CALL AM_Print_NewLine
CALL AM_Print_NewLine
POP EAX
CALL AM_Print_EAX_16
CALL AM_Print_NewLine
CALL AM_Print_NewLine
MOV AH,0 ; wait for key
INT 016h
ReadSector_Ret:
POPAD
MOV EAX, dwRet
XOR AL,AL ;EAX = 0 on success. Otherwise AH has error code.
RET
ReadSector ENDP
Remove the the lines blow from the code above and everything works fine, that is because the ReadSector is called with ES:BX set to the address of variable is in code segment.
LOCAL TempBuffer[512] : BYTE ;Override the ES:BX passed in with the address of the local TempBuffer
LEA BX, TempBuffer
PUSH SS
POP ES
I really want to write to the stack and not the global variable.
Any ideas why a write to the stack doesnt work?
I have tried setting ES:BX to the address of the stack before calling the proc, but its doesnt work either.
I have tried removing the lines descrbied above, and putting in a SUB SP,512 and ADD SP,512 before and after the int 13h call, but this returns the same error code.
Your help is much appreciated!
Hi,
the code looks ok (if it is called with AX==1).
A wild guess is that your BIOS doesn't like the segment part of the buffer address to be 0000? IIRC at boot time SS might be 0. To verify you could add:
mov cx, es
inc cx
mov es,cx
sub bx,10h
before ReadSector_Ex.
The code looks OK to me too. If you set up a workable stack, preferably with SS=DS, and set the initial value of SP so the stack will not overwrite anything important, AFAICT the code should work OK.
thanks for your comments, but I am still stuck.
I am using Bochs to debug, and before the int 13 the registers are set to the following:
(0) [0x000088a8] 07e0:0aa8 (unk. ctxt): int 0x13 ; cd13
<bochs:30> r
eax: 0x4200 16896
ecx: 0x0 0
edx: 0x80 128
ebx: 0xfd8f 64911
esp: 0xfd6d 64877
ebp: 0xffa3 65443
esi: 0xff8f 65423
edi: 0x512 1298
eip: 0xaa8
eflags 0x246
cs: 0x7e0
ss: 0x9000
ds: 0x9000
es: 0x9000
fs: 0x7e0
gs: 0x0
As you can see no segment register is set to 0. My code is at 07E0h and my stack is at 9000h.
and after the int 13:
00002020671i[BIOS ] int13_harddisk: function 42, error 01 !
eax: 0xa3ff0c00 -1543566336
ecx: 0x0 0
edx: 0x80 128
ebx: 0xfd8f 64911
esp: 0xfd6d 64877
ebp: 0xffa3 65443
esi: 0xff8f 65423
edi: 0x512 1298
eip: 0xaaa
eflags 0x247
cs: 0x7e0
ss: 0x9000
ds: 0x9000
es: 0x9000
fs: 0x7e0
gs: 0x0
Bochs says error 1. While the Result in AH is 0Ch
What do you guys think?
thanks again
Are you trying to read more than 1 sector? I noticed that your buffer address is 9000:FD8F, so reading more than one sector would go past 9000:FFFF
Nope just reading the one sector. (I am reading partition info for hard drives).
ebx: 0xfd8f 64911
esp: 0xfd6d 64877
ebp: 0xffa3 65443
esi: 0xff8f 65423
edi: 0x512 1298
eip: 0xaa8
eflags 0x246
cs: 0x7e0
ss: 0x9000
ds: 0x9000
es: 0x9000
fs: 0x7e0
ss:sp == 9000:fd6d! Did you set these high values for the stack? It is not aligned, which is bad, but possibly worse is that Bochs's BIOS might have allocated the XBDA (extended BIOS data area) at segment FDC0, and you are now writing in this region.
Thanks for the response japheth,
Yes I set the stack values. Why are these bad? Why cant it be this high? Stack grows down so I gave it as much space as possible.
When you say aligned, do you mean dword aligned? Why specifically does it need to be aligned? eg, the Int 13 needs it aligned?
How can I tell where Bochs XBDA is located?
Sorry..so many questions! :)
Interrupt 15h, AH=C1h should return the XBDA segment in ES, or return with the carry flag set in case of an error. On my test system it returns with ES=9FC0h.
> is that Bochs's BIOS might have allocated the XBDA (extended BIOS data area) at segment FDC0
this was a typo, I meant 9FC0 of course :red
> Why specifically does it need to be aligned?
No, it doesn't need to be, but it slows down the machine (possibly no problem on Bochs, since it is already very slow).
> Interrupt 15h, AH=C1h should return the XBDA segment in ES, or return with the carry flag set in case of an error.
Yes. Another method is to get the XBDA segment from 0040:000E
The XBDA was the culprit! I've modified my starting stack locations to 9000:CFFF and all is well!
thanks guys!! :bg