1

I'm building my own bootloader and when I emulate it using qemu I get "Boot failed: could not read the boot disk". It works like this: The first stage loads the second stage and then the second stage bootloader loads the kernel. Everything looks fine, but I keep getting that message and nothing works like it should.

This is the code of my first stage bootloader: I'm building my own bootloader and when I simulate it using qemu I get "Boot failed: could not read the boot disk".

org 0x7C00
jmp 0x0000:start

string db 'Bootloader by JCLC - GMM4 - RGT!', 13, 10, 0

    start:
    ;Setup stack segments
    mov ax,cs              
    mov ds,ax  
    mov es,ax              
    mov ss,ax
    mov sp, 0x7c00

    xor ax, ax
    mov ds, ax

    xor ax, ax
    mov ds, ax
    mov si, string
    mov cl, 0

    printString:
    lodsb                                
    cmp cl, al                          
    je done

    mov ah, 0xe    
    mov bl, 2      
    int 10h            

    jmp printString

    done:

    mov ah, 0x02
    mov al, 1
    mov dl, 0x80
    mov ch, 0
    mov dh, 0   
    mov cl, 2
    mov bx, 0x7E00
    int 0x13

    jmp 0x7E00  

    times ((0x200 - 2) - ($ - $$)) db 0x00
    dw 0xAA55

This one is the code of my second stage bootloader:

org 0x7E00

    mov ax,cs              
    mov ds,ax  
    mov es,ax              
    mov ss,ax
    mov sp,0x7E00

    xor ax, ax
    mov ds, ax    

    mov ah, 0x500
    mov al, 1
    mov dl, 0x80
    mov ch, 0
    mov dh, 0   
    mov cl, 2
    mov bx, 0x500
    int 0x13

    jmp 0x500 

    times ((0x200 - 2) - ($ - $$)) db 0x00
    dw 0xAA55

This is what should be the kernel. It's just something I wrote to see if everythig was working as it should.

org 0x500

    ; Print 'a'.
    mov ax, 0x0E61
    int 0x10

    cli
    hlt

    ; Pad image to multiple of 512 bytes.

times ((0x200 - 2) - ($ - $$)) db 0x00
Michael Petch
  • 46,082
  • 8
  • 107
  • 198

1 Answers1

3

You have a number of issues with your code. You have this in your original boot1.asm:

    jmp 0x0000:start
string db 'Bootloader by JCLC - GMM4 - RGT!', 13, 10, 0
    ;Setup stack segments
    mov ax,cs              
    mov ds,ax  
    mov es,ax              
    mov ss,ax
    mov sp, 0x7c00
start:

You should place start right after the string definition so that all the segments get set up correctly.

When control is transferred to the bootloader by the BIOS DL contains the boot drive number that can be used for disk operations like Int 13h/AH=2 (disk reads). Hard coding the drive number with mov dl, 0x80 forces you to always be booting from hard disk 1 (0x00 = floppy A, 0x01 = floppy B, 0x80 = harddisk 1, 0x81 = harddisk2). You can simply remove mov dl, 0x80 from the first and second stage disk reads since you don't destroy DL at any point and it is still the value passed by the BIOS.

If you read Ralph Brown's Interrupt List for Int 0x13/AH=2 you'd find this:

DISK - READ SECTOR(S) INTO MEMORY

AH = 02h
AL = number of sectors to read (must be nonzero)
CH = low eight bits of cylinder number
CL = sector number 1-63 (bits 0-5)
     high two bits of cylinder (bits 6-7, hard disk only)
DH = head number
DL = drive number (bit 7 set for hard disk)
ES:BX -> data buffer

Return:

CF set on error
if AH = 11h (corrected ECC error), AL = burst length
CF clear if successful
AH = status (see #00234)
AL = number of sectors transferred (only valid if CF set for some BIOSes)

In your boot1.asm and boot2.asm you incorrectly set AH. AH should be the value 2 to do a disk read.

In boot2.asm you read the wrong sector number. You have:

    mov cl, 2

You want to read the 3rd sector from the disk. It should be:

    mov cl, 3

With all this in mind your files would look like:

boot1.asm:

org 0x7C00
jmp 0x0000:start

string db 'Bootloader by JCLC - GMM4 - RGT!', 13, 10, 0

    start:    
    ;Setup stack segments
    mov ax,cs
    mov ds,ax
    mov es,ax
    mov ss,ax
    mov sp, 0x7c00

    mov si, string
    mov cl, 0

    printString:
    lodsb
    cmp cl, al
    je done

    mov ah, 0xe
    mov bl, 2
    int 10h

    jmp printString

    done:

    mov ah, 2       ; Int 13h/AH=2 = disk read
    mov al, 1
    ;mov dl, 0x80   ; Comment out - use value passed by BIOS in DL
    mov ch, 0
    mov dh, 0
    mov cl, 2
    mov bx, 0x7E00
    int 0x13

    jmp 0x7E00

    times ((0x200 - 2) - ($ - $$)) db 0x00
    dw 0xAA55

boot2.asm:

org 0x7E00

    mov ax,cs
    mov ds,ax
    mov es,ax
    mov ss,ax
    mov sp,0x7E00

    xor ax, ax
    mov ds, ax

    mov ah, 2        ; Int 13h/AH=2 = disk read 
    mov al, 1
    ; mov dl, 0x80   ; Comment out - use value passed by BIOS in DL
    mov ch, 0
    mov dh, 0
    mov cl, 3        ; You want to read sector 3 (not 2)
    mov bx, 0x500
    int 0x13

    jmp 0x500

    times ((0x200 - 2) - ($ - $$)) db 0x00
    dw 0xAA55

kernel.asm:

org 0x500

    ; Print 'a'.
    mov ax, 0x0E61
    int 0x10

    cli
    hlt

    ; Pad image to multiple of 512 bytes.

times ((0x200 - 2) - ($ - $$)) db 0x00

When I run this via your Makefile I get this as output in QEMU:

enter image description here


Debugging Bootloaders

The best tool to debug bootloaders is BOCHS rather than QEMU. BOCHS has a built in debugger that has very good support for real mode code like bootloaders.


Bootloader Tips

I have a Stackoverflow answer with a number of Bootloader Development Tips.

Community
  • 1
  • 1
Michael Petch
  • 46,082
  • 8
  • 107
  • 198
  • Isn't it also ill-advised to rely on the value of `CS` when initializing the other segment registers? You'll probably get away with it on emulators that have relatively "clean", "correct" BIOS implementations, but I'd say it's dangerous on real hardware! – Cody Gray - on strike Apr 19 '17 at 12:20
  • @CodyGray : He doesn't rely on it. He sets _CS_ to 0x0000 with the FAR JMP `jmp 0x0000:start` so it is perfectly safe to rely on _CS_ after that point. Of course he can get away with the _FAR JMP_ as the first instruction since he isn't using a BPB. – Michael Petch Apr 19 '17 at 13:53
  • Right, of course. Should have paid more attention to the code. I didn't notice that was a far jump. You see what you are expecting. Thanks for the clarification. – Cody Gray - on strike Apr 19 '17 at 14:05
  • Thanks very much for helping me, Michael Petch – Jefferson Carlos Lima da Costa Apr 19 '17 at 16:18
  • I'm still getting "boot failed: could not read from boot disk" error and I can't figure out what it is – Jefferson Carlos Lima da Costa Apr 19 '17 at 16:19
  • @JeffersonCarlosLimadaCosta: You likely have missed something from my answer. Take the files I have given you in my answer exactly as is and test it out and let me know if it works. – Michael Petch Apr 19 '17 at 16:21