Page 1 of 2

Int13h AH=42h Boot From Hard Drive just fails [Solved]

Posted: Sun Jun 07, 2009 5:35 am
by CmpXchg
Hi!

I'm working an a project of an OS, but gotten stuck with the bootsector code.

Problem: Bootsector fails to load 2nd stage loader.

It's designed for NTFS partitions, it's supposed to load some number of sectors immediately following it on the partition. But Int13h AH=42h returns AH=1 with CF set. Couldn't figure out why so far.

Here's the code that fails:

Code: Select all

;/*
;* bootldr.asm *
;* NTFS-specific *
;* Bootsector is supposed to start with EB 52 *
;*/
        org 7C54h

;NTFS Bootsector Structures
        [section .bpb]
absolute        7C1Ch
BPB_HiddSec                     resd    1

absolute        7C28h
ExtBPB_TotalSectors             resq    1
ExtBPB_$MFTCluster              resq    1
ExtBPB_$MFTMirrCluster          resq    1
ExtBPB_FileRecordSize           resd    1
ExtBPB_IndexBlockSize           resd    1
ExtBPB_SerialNumber             resq    1
ExtBPP_Checksum                 resd    1


;My bootsector code
        [section .code align=2]
start:
        xor     ax,ax
        mov     ds,ax
        mov     es,ax
        cli
        mov     ss,ax
        mov     sp,7C00h
        sti

        push    first_message
        call    print_string
        
        push    word (bootldr_end - sector1)/512 + 1            ;evaluates to 1
        push    word sector1                                    ;offset
        push    ds                                              ;segment
        push    dword [BPB_HiddSec]                             ;LBA
        call    load_sectors

        jmp     sector1

;/* 
;* Realmode Int13h AH=42h sector loading routine *
;*/
load_sectors:
        push    bp
        mov     bp,sp

%define lba     (bp+4)
%define seg     (bp+8)
%define ofs     (bp+10)
%define nsect   (bp+12)
        
        push    dword 0
        push    dword [lba]             ;LBA
        push    word [seg]              ;segment
        push    word [ofs]              ;offset
        push    word [nsect]            ;number of sectors
        push    word 10h                ;10h, 0h.

        mov     ah,42h
        mov     si,sp
        mov     dl,80h
        int     13h

        jc      os_failure
        test    ah,ah
        jnz     os_failure

        leave
        retn    10

os_failure:
        push    fail_message
        call    print_string
        mov     al,ah
        call    print_al

        xor     ax,ax
        int     16h
        int     19h

;Text messages
first_message   db      "Hi! I'm a boot sector! Let's start up...",13,10,0

fail_message    db      "Didn't even make it past the bootsector. Goodbye ;(",13,10
                db      'INT13 Failed with AH=',0

;<here are some printing routines for debug>
;/* 
;* Realmode printing routine *
;*/
print_string:
        mov     bp,sp
        mov     si,word [bp+2]
        pusha
        mov     ah,0Eh
        cld
.print_loop:
        lodsb
        test    al,al
        jz      .end_print
        int     10h
        jmp     short .print_loop
.end_print:
        popa
        retn    2

times   510-54h-($-$$) db 0

db      55h,0AAh
;======================================== The End of Sector 0

; The Start of Sector 1 ======================================
sector1:
        push    message2
        call    print_string
        xor     ax,ax
        int     16h
        int     19h

;/* TODO:
;* -) Parse the NTFS root dir for Kernel.exe
;* -) Load it up above 1 Mb using INT13h AH=42h
;* -) Set up basic PM
;* -) Jump to KernelEntry()
;*/

message2        db      "Ok, let's load the Kernel.exe and set up PM",0                 

bootldr_end:
How to reproduce: Compile with NASM -f bin and run in QEMU or even on real hardware, same thing. The output binary file is supposed to be pasted into an NTFS bootsector at offset 0x54.

Please give your perspective. Slap me if this has been answered somewhere before :oops:

Re: Int13h AH=42h Boot From Hard Drive just fails

Posted: Sun Jun 07, 2009 2:24 pm
by Masterkiller
Last 15 times I redesign my loader I used this:
http://www.ctyme.com/intr/rb-0706.htm
to check if the specified device support extended functions.
It's all depends on your hardware if it has LBA access in BIOS. LBA Access (Extended function) in BIOS for a bootable device is not the save as LBA access through the I/O ports. So even you hard disk is 500GB, that does not mean BIOS will support LBA access.

Re: Int13h AH=42h Boot From Hard Drive just fails

Posted: Sun Jun 07, 2009 2:29 pm
by alethiophile
Try running it in Bochs. It tends to emit more helpful errors than Qemu.

Re: Int13h AH=42h Boot From Hard Drive just fails

Posted: Sun Jun 07, 2009 3:54 pm
by mathematician
The fact that addresses are always written seg:offset means it is an easy mistake to make, but you are pushing the seg and offset in the wrong order. Seg should be the most significant word of a double word address. For example, 1234:5678h would appear in memory as:

dw 5678h.........................offset - least sig word (sp= 98 say)
dw 1234h.........................seg - most sig word (sp= 100 say)

Re: Int13h AH=42h Boot From Hard Drive just fails

Posted: Sun Jun 07, 2009 10:58 pm
by kop99
but you are pushing the seg and offset in the wrong order.
mathematician, you are wrong.
CmpXchg's pushing order is right.

Re: Int13h AH=42h Boot From Hard Drive just fails

Posted: Sun Jun 07, 2009 11:04 pm
by kop99
CmpXchg, make sure there is right value...

Code: Select all

push    word (bootldr_end - sector1)/512 + 1            ;evaluates to 1

Re: Int13h AH=42h Boot From Hard Drive just fails

Posted: Sun Jun 07, 2009 11:11 pm
by Masterkiller
kop99 wrote:
but you are pushing the seg and offset in the wrong order.
mathematician, you are wrong.
CmpXchg's pushing order is right.
Actually all that he pushes is wrong. Structure must be as follows:

Code: Select all

+0: word 0x10
+2: word NumberOfSectors
+4: word Offset
+6: word Segment
+8: Qword LBA
You do not specify the size of structure.
You do not push the high double-word of the 64-bit value of LBA.
You start pushing from +0 part. You stack DEcrements on every pushing, not INcrement, so the structure you got is in reverse order.

P.S. oops, I looked in the wrong place e.g. pushing before call, not before int. Anyway no guarantees that extended read is supported for the current device. Also try to use an DL returned by BIOS, not 0x80 :)

Re: Int13h AH=42h Boot From Hard Drive just fails

Posted: Sun Jun 07, 2009 11:16 pm
by kop99
Masterkiller, your structure is right.

Code: Select all

+0: word 0x10
+2: word NumberOfSectors
+4: word Offset
+6: word Segment
+8: Qword LBA
so, push order is following.

Code: Select all

+8: Qword LBA
+6: word Segment
+4: word Offset
+2: word NumberOfSectors
+0: word 0x10
and CmpXchg's code is following.

Code: Select all

        push    dword 0
        push    dword [lba]             ;LBA
        push    word [seg]              ;segment
        push    word [ofs]              ;offset
        push    word [nsect]            ;number of sectors
        push    word 10h                ;10h, 0h.
So, isn't he all right?
I think you have a little mistake.

Re: Int13h AH=42h Boot From Hard Drive just fails

Posted: Mon Jun 08, 2009 3:03 am
by pcmattman
@OP: Will this have the correct value when popped as a QWord? Make sure your endianness is correct.

Code: Select all

        push    dword 0
        push    dword [lba]             ;LBA
Also,
Try running it in Bochs. It tends to emit more helpful errors than Qemu.
You can also enable debug logging on the device you're reading from, which will let you see exactly what's happening.

Re: Int13h AH=42h Boot From Hard Drive just fails

Posted: Mon Jun 08, 2009 7:47 am
by Firestryke31
Is the packet address DWORD aligned? I've had problems when it wasn't. Aligning the stack is rather simple, try something along the lines of this (Intel syntax):

Code: Select all

 push bp
 mov bp, sp
 mov ax, sp
 and ax, 3
 jz .noAlign
 sub sp, ax
.noAlign:
 ;; Pushing packet here!

 ;; When done with packet, do this
 mov sp, bp
 pop bp

Re: Int13h AH=42h Boot From Hard Drive just fails

Posted: Mon Jun 08, 2009 10:19 am
by mathematician
kop99 wrote:
but you are pushing the seg and offset in the wrong order.
mathematician, you are wrong.
CmpXchg's pushing order is right.
After a far call, the stack looks like this:

arg1
arg2
cs
ip

After a real mode interrupt, it looks like this:

flags
cs
ip

stored in memory a far pointer looks like this:

dw offset, seg

The seg is always the most significant word. The thing which confuses the issue is so called "back words storage"
ip

Re: Int13h AH=42h Boot From Hard Drive just fails

Posted: Mon Jun 08, 2009 6:55 pm
by kop99
mathematician, if you point that code, i think there is no mistake.

Code: Select all

        push    word [seg]              ;segment
        push    word [ofs]              ;offset
dw offset, seg

The seg is always the most significant word. The thing which confuses the issue is so called "back words storage"
ip
in IA, memory order for Disk Address Packet is, first offset, and then segment.

Re: Int13h AH=42h Boot From Hard Drive just fails

Posted: Mon Jun 08, 2009 8:28 pm
by geppyfx
Right, voting that original(1st) post has correct code for offset,segment.
Segment is at highest addr in the ram and pushed first, SP decreased; offset at the lowest and pushed second.
mathematician wrote: dw 5678h.........................offset - least sig word (sp= 98 say)
dw 1234h.........................seg - most sig word (sp= 100 say)
mathematician probably looked at 1st 4 pushes outside the load_sectors function and decided that CmpXchg pushes them in same order for int13

There is one big flaw in the CmpXchg code however. But its not the problem why code is not working. PUSH uses SS and int13h uses DS. Consciously or not but CmpXchg zeroed them both, this is why code still working.

Re: Int13h AH=42h Boot From Hard Drive just fails

Posted: Tue Jun 09, 2009 11:19 am
by CmpXchg
Okay...
Wow, I'm impressed, so many people willing to help. Thanks!

Now... to make sure everyone feels heard, let me see what we've got here.
Masterkiller wrote:It's all depends on your hardware if it has LBA access in BIOS. LBA Access (Extended function) in BIOS for a bootable device is not the save as LBA access through the I/O ports. So even you hard disk is 500GB, that does not mean BIOS will support LBA access.
I'm damn sure BIOS supports LBA access, it just returns an error, but the functions are there. Windows XP loader code uses them every time I turn this thing on. And they must be supported in virtual machines.
pcmattman wrote:Also,
alethiophile wrote:Try running it in Bochs. It tends to emit more helpful errors than Qemu.
You can also enable debug logging on the device you're reading from, which will let you see exactly what's happening.
Well, yeah, but right now with Qemu, I can just go: qemu -hdb d: -L <whatever>
and it boots my D: partiton. The problem is: how to do the same with Bochs?

Next, that fascinating debate around pushing order... I believe I'm pushing it right. In memory, offset gets pushed at lower address (98, say) and the seg gets pushed to a higher address (100, say). So, reversely, the seg has to be pushed first. Period.
mathematician wrote:After a far call, the stack looks like this:
...
After a real mode interrupt, it looks like this:
...
stored in memory a far pointer looks like this:
...
dw offset, seg
Nah, these are all near relative calls. And yeah, dw offset, seg - that's how exactly it gets stored in memory. No question.

@pcmattman: the endianness does seem to be correct.

Now, if the structure content is right, what is the actual problem, then?
Firestryke31 wrote:Is the packet address DWORD aligned? I've had problems when it wasn't.
Hmm, that looks like a cause for trouble. Frankly, alignment was the last thing on my mind when I wrote this... I'll play with this.
geppyfx wrote:There is one big flaw in the CmpXchg code however. But its not the problem why code is not working. PUSH uses SS and int13h uses DS. Consciously or not but CmpXchg zeroed them both, this is why code still working.
I did it consciously :D Still not the issue, then! One thing I am thinking about is that INT13 might modify BP... which would mess up the stack completely, of course.

Keep brainstorming, please...

Re: Int13h AH=42h Boot From Hard Drive just fails

Posted: Tue Jun 09, 2009 11:39 am
by Love4Boobies
Your origin is 0754h (as opposed to 7C00h) and thus all offsets are wrong (jumps, variables, etc).