Page 1 of 1

Understanding why INT 13 ah=42 fails with CF

Posted: Fri Oct 02, 2015 8:56 am
by elazarl
I wrote (actually, adapted from OSv) a small boot loader, which simply loads from disk, using INT 13h, ah=42 the first few sectors from the disk, switches to 32bit mode, copy this sector to memory and switches back to 16 bit mode.

Here is a git repository with the code: https://gist.github.com/elazarl/9f7d61dabeb6d899b64e

For some reason, a seemingly legal int13h42 packet returns a CF error. In the attached gist it happens in boot16.S line 89.

Run `bash ./debug.sh` to build the image, and debug it. It would create a raw image, run it with `qemu -s`, run `gdb` and connect to QEMU's debug stub, set breakpoint after INT 13, and tell gdb to print things after hitting this breakpoint.

When in gdb, type "c", and it would print the eflags registers afterward the INT 13 call.

You can see that you get the CF flag, with `ah=1`, meaning "invalid function in AH or invalid parameter".

The exact same code work with a smaller sector number.

I'll be happy for any hints how to solve it, or even understand the problem better.

For debugging, I compiled QEMU run with [tt]DEBUG_IDE[/tt] symbol, and here is the output

Code: Select all

[Thread 0x7fffe4dab700 (LWP 29677) exited]
# OK to here
ide: write control addr=0x3f6 val=0a
ide: read addr=0x1f7 val=50
ide: read addr=0x1f6 val=60
IDE: write addr=0x1f6 val=0xe0
IDE: write addr=0x1f1 val=0x00
IDE: write addr=0x1f2 val=0x40
IDE: write addr=0x1f3 val=0x00
IDE: write addr=0x1f4 val=0x02
IDE: write addr=0x1f5 val=0x00
IDE: write addr=0x1f7 val=0x20
ide: CMD=20
sector=512
[New Thread 0x7fffe4dab700 (LWP 29679)]
ide: read addr=0x1f7 val=58
sector=513
ide: read status addr=0x3f6 val=58
ide: read addr=0x1f7 val=58
sector=514
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=515
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=516
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=517
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=518
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=519
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=520
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=521
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=522
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=523
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=524
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=525
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=526
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=527
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=528
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=529
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=530
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=531
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=532
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=533
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=534
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=535
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=536
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=537
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=538
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=539
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=540
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=541
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=542
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=543
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=544
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=545
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=546
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=547
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=548
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=549
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=550
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=551
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=58
sector=552
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=553
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=d0
ide: read addr=0x1f7 val=58
sector=554
ide: read status addr=0x3f6 val=d0
ide: read addr=0x1f7 val=41
ide: write control addr=0x3f6 val=08
# NOW [Thread 0x7fffe4dab700 (LWP 29679) exited]
# GOT CF

Re: Understanding why INT 13 ah=42 fails with CF

Posted: Fri Oct 02, 2015 10:06 am
by BrightLight
TBH, I don't know and so I can't read AT&T syntax assembly language.
I do know that some BIOSes (including Bochs BIOS, QEMU's SeaBIOS and Virtual PC's BIOS) have a 127 sectors count limit for INT 0x13 AH 0x42. Also, there are segmentation limits on some BIOSes. If you read too many sectors and cross a segment limit, the system will hang or the BIOS will return with CF set.

Re: Understanding why INT 13 ah=42 fails with CF

Posted: Fri Oct 02, 2015 1:22 pm
by Octocontrabass
elazarl wrote:For some reason, a seemingly legal int13h42 packet returns a CF error. In the attached gist it happens in boot16.S line 89.
Have you checked to make sure the one on line 83 doesn't do the same thing?
elazarl wrote:The exact same code work with a smaller sector number.
How big is your disk image?

Re: Understanding why INT 13 ah=42 fails with CF

Posted: Sat Oct 03, 2015 1:42 pm
by elazarl
Octocontrabass wrote:
elazarl wrote:For some reason, a seemingly legal int13h42 packet returns a CF error. In the attached gist it happens in boot16.S line 89.
Have you checked to make sure the one on line 83 doesn't do the same thing?
Not sure what you mean. Line 83 does it once, line 89 does it in loop.
Octocontrabass wrote:
elazarl wrote:The exact same code work with a smaller sector number.
How big is your disk image?
163840 bytes

Code: Select all

❯ ls -haltr out/loader.img
-rw-rw-r-- 1 elazar elazar 160K Oct  2 16:46 out/loader.img

Re: Understanding why INT 13 ah=42 fails with CF

Posted: Sat Oct 03, 2015 5:21 pm
by Octocontrabass
elazarl wrote:Not sure what you mean. Line 83 does it once, line 89 does it in loop.
I'm referring specifically to the fact that it returns an error. The one on line 83 doesn't have an error handler, so if it fails too, you won't notice unless you're using a debugger.
elazarl wrote:163840 bytes
Your disk image is 320 sectors, but your qemu log shows you reading sector 512? Something doesn't add up here.

Re: Understanding why INT 13 ah=42 fails with CF

Posted: Sat Oct 03, 2015 5:56 pm
by elazarl
Octocontrabass wrote:
elazarl wrote:Not sure what you mean. Line 83 does it once, line 89 does it in loop.
I'm referring specifically to the fact that it returns an error. The one on line 83 doesn't have an error handler, so if it fails too, you won't notice unless you're using a debugger.
I was indeed using the QEMU gdb-stub debugger.
Octocontrabass wrote:
elazarl wrote:163840 bytes
Your disk image is 320 sectors, but your qemu log shows you reading sector 512? Something doesn't add up here.
I played with image size, and it could be this specific run is from a different image. I'll re-run it with this exact image.