3

In order to boot from flash memory drive we load disks using the BIOS interrupt 13h in real mode with specifying the disk 0x80. Another disks should be accessed by 0x81, 0x82... as mentioned over this link

I am trying to make my simple GRUB.

My very first step is to boot from flash memory drive (Load MBR into 0x7C00 and print a message as a proof of correct boot) and read the my main HDD (which I assume it is numbered 0x81 and that the first 15 sectors are needed for booting) again into 0x7C00.

I suppose that this naive idea should drop me into my main HDD's bootloader, but it is not as expected. Would you please tell me what is wrong.

By the way, how should I get the numbers of HDDs?

Please note that my main HDD contains grub2 with several operating systems.

Edit: For me this is a theoretical question, but I added the code due to a request in comments.

bootloader.asm:

[bits 16]
[org 0x7C00]

; The bootloader is in charge of writing BPB into MBR in addition to installing this code.
; Then a second sector is written to the drive, this is where the FAT is allocated.
LOADER_OFFSET equ 0x1000

jmp short main
nop
%include "ASM/BPB.asm"

main:
    xor ax, ax
    mov ds, ax
    mov es, ax

    ; Save the boot drive. Basically it should be 0x80
    mov [BOOT_DRIVE], dl
    mov ax, 0x0000                  ; End of stack

    ; Lock and create stack
    cli
    mov ss, ax
    mov sp, 0x0000
    sti

    mov     ah, 0x0e
    mov al, 'X'
    int 0x10

    ; Load the second sector into memory at LOADER_OFFSET
    mov bx, LOADER_OFFSET
    mov al, 1
    mov cl , 0x02
    mov dl, [BOOT_DRIVE]
    call    disk_load

    ; Call the loader using segmentation
    jmp 0x0000:LOADER_OFFSET

; Global variables
BOOT_DRIVE  db 0

%include "ASM/disk_load.asm"

; Bootsector padding
times 510-($-$$) db 0
dw 0xAA55

Second Stage bootloader- loader.asm:

[bits 16]
[org 0x1000]

KERNEL_OFFSET equ 0x7C00

_start:

    xor ax, ax
    xor bx, bx

    mov     ah, 0x0e
    mov al, 'Y'
    int 0x10

    mov bx, KERNEL_OFFSET   
    mov al, 15
    mov dl , 0x81
    mov cl , 0x01
    call    disk_load

    jmp 0x7C0:0000

%include "ASM/disk_load.asm"

times 512-($-$$) db 0

BPB.asm:

BPB:
    iOEM        db  "mkfs.fat"              ; 0x03 ; OEM String
    iSectSize   dw  512                 ; 0x0B ; Bytes per sector
    iClustSize  db  0x40                    ; 0x0D ; Sectors per cluster
    iResSect    dw  0x1                 ; 0x0E ; # of reserved sectors. For now, it should be 1 
                                    ; 0x0E ; unless we need more space to write the bootstrap
                                    ; 0x0E ; sector
    iFatCnt     db  2                   ; 0x10 ; # of fat copies
    iRootSize   dw  1024                    ; 0x11 ; size of root directory
    iTotalSect  dw  0                   ; 0x13 ; total #of sectors if below 32 MB
    iMedia      db  0xF8                    ; 0x15 ; Media Descriptor
    iFatSize    dw  256                 ; 0x16 ; Size of each FAT
    iTrackSect  dw  62                  ; 0x18 ; Sectors per track
    iHeadCnt    dw  63                  ; 0x1A ; number of read-write heads
    iHiddenSect dd  0                   ; 0x1C ; number of hidden sectors
    iSect32     dd  0x003c3000              ; 0x20 ; # of sectors if over 32 MB



EBPB:
    iBootDrive  db  80                  ; 0x24 ; holds drive that the boot sector came from
    iReserved   db  0                   ; 0x25 ; reserved, empty
    iBootSign   db  0x29                    ; 0x26 ; extended boot sector signature
    iVolID      dd  0xA8B531B1              ; 0x27 ; disk serial
    acVolLabel  db  "BIOSver", 0x20, 0x20, 0x20, 0x20   ; 0x2B ; just placeholder. We don't yet use volume labels.
    acFSType    db  "FAT16", 0x20, 0x20, 0x20       ; 0x36 ; file system type

disk_load.asm:

disk_load:
    push dx
    mov ah , 0x02
    mov ch , 0x00
    mov dh , 0x00
    int 0x13
    jc disk_error
    pop dx
    ret

disk_error:
    pop si
    pop ax
    pop cx
    pop dx
    jmp $

; Variables
SECTORS     db 0

Makefile:

ASFLAGS=-g3

all: os.img

os.img: bootloader.bin loader.bin
    cat bin/bootloader.bin bin/loader.bin > bin/os.img


bootloader.bin: ASM/bootloader.asm
    nasm $(ASFLAGS) $^ -f bin -o bin/$@

loader.bin: ASM/loader.asm
    nasm $(ASFLAGS) $^ -f bin -o bin/$@

clean:
    rm -f bin/*.* bin/* os.img

This code should print XY to screen and then pass control to the HDD's bootsector. But what I am getting is just XY printed to the screen.

  • Are you sure you don't overwrite your running code with this method? – tofro Mar 14 '17 at 15:53
  • Is this something you've actually tried? It doesn't sound very "theoretical" to me; it sounds like you have a hunk of code that isn't working right. If you have code, please consider posting a minimal, complete, and verifiable example of the part that isn't actually working right. http://stackoverflow.com/help/mcve – Sean Werkema Mar 14 '17 at 16:00
  • you are right @tofro. Indeed, I am using two steps bootloader. It will overwrite the first one which I don't care about. –  Mar 14 '17 at 16:16
  • Sounds like you are intending to [chainload](https://en.wikipedia.org/wiki/Chain_loading#Chain_loading_in_boot_manager_programs) the bootloader. You can't read data on top of 0x7c00 and clobber the memory that is executing. To get around this a bootloader will relocate itself (copy the code) to somehwere else in memory (ieL 0x0000:0x0600) transfer control there (_JMP_), read data to location 0x0000:0x7c00 from disk then _JMP_ back to 0x0000:0x7c00. – Michael Petch Mar 14 '17 at 16:25
  • @MichaelPetch, thank you. I really follow your comments everywhere. What about the two steps bootloader (I already added the code now)? –  Mar 14 '17 at 16:32
  • @SeanWerkema, Ok. I added the code. –  Mar 14 '17 at 16:32
  • 2
    Eyeballing this code I see one serious issue. You load the disk sectors to 0x0000:0x1000. You then _JMP_ to it with `jmp 0x100:0000` . This is a far _JMP_ and will set _CS_ to 0x100 and _IP_ to 0x0000. The issue is that your second stage has `[org 0x1000]`. If you want to use `jmp 0x100:0000` then you need an ORG of 0x0000. If you want an `[org 0x1000]` you need to change the _JMP_ to `jmp 0x0000:0x1000` . There may be other issues but that one stands out. – Michael Petch Mar 14 '17 at 16:41
  • This isn't a minimal complete example because of course you don't show us BPB.asm and disk_load.asm. I don't know if disk_load.asm is actually correctly reading from disk (or whether there are some bugs in it causing issues) – Michael Petch Mar 14 '17 at 16:48
  • @MichaelPetch, I added BPB.asm and disk_load.asm. It is my fault. –  Mar 14 '17 at 16:53
  • When you run it what output do you get? – Michael Petch Mar 14 '17 at 16:58
  • @MichaelPetch, I get "XY" and then it hangs which means it is loading the second stage bootloader but not chainloading. By the way, I corrected your issue. –  Mar 14 '17 at 17:03
  • 1
    If I had to guess (after the fix I gave you) is that whatever environment you are running it is probably virtual (and not real) and that your disk image for the second hard drive image (drive 0x81) doesn't contain 15 sectors worth of extra data (after the first sector) and the disk read is failing (I'd expect this to be a potential issue in virtual environments but not real hardware). What happens if instead of reading 15 sectors you simply read 1 sector? – Michael Petch Mar 14 '17 at 17:28
  • 1
    You are right @MichaelPetch. It is in qemu emulator. I tested it now with real system with one operating system (Windows XP) reading just the first sector, I got "XYError loading operating system". I guess this means that the disk load is correct and the problem is somewhere else. Probably, it is due to the fact the the flash drive is formatted to FAT16 while HDD is of NTFS format. I will check it and be back later. –  Mar 14 '17 at 18:44
  • Coming back. No news. It seems there is something missing here with my code. Do you think it is feasible to simply chainload Windows by calling its MBR (The MBR of disk where it is installed)? –  Mar 15 '17 at 17:25

1 Answers1

2

Answering my own question inspired from the above comments from Micheal Petch: There are mainly two problems: 1. Using emulator does not necessarily means that all drives are loaded which was my case 2. Loading the disk sectors to 0x0000:0x1000 with jmp 0x100:0000.

In addition, chainloading requires overwriting interrupt 13 to re-arrange the numbers of boot devices as explained in rufus code (i.e. Flash memory to 0x81 and main HDD to 0x80).