I am trying to implement my own MBR code in order to let users choose which system to load. After I write it, I substitute the first nearly 200 bytes of the disk with my own code. But I came across a problem that I cannot figure out, to load and execute the boot loader code of each system.
The code I wrote:
; Instruct NASM to generate code that is to be run on CPU that is running in 16 bit mode
bits 16
org 0x600
xor ax,ax
mov ss,ax
mov sp,0x7c00
sti
push ax
pop es
push ax
pop ds
cld
mov si,0x7c1b
mov di,0x61b
push ax
push di
mov cx,0x1e5
rep movsb
retf
mov bp,0x7be
; choose_background:
mov ah, 0x06 ; Clear / scroll screen up function
xor al, al ; Number of lines by which to scroll up (00h = clear entire window)
xor cx, cx ; Row,column of window's upper left corner
mov dx, 0x184f ; Row,column of window's lower right corner
mov bh, 0xf1 ; Background/foreground colour. In our case - red background / yellow foreground (https://en.wikipedia.org/wiki/BIOS_color_attributes)
int 0x10 ; Issue BIOS video services interrupt with function 0x06
; Move label's bootloaderBanner memory address to si
mov si, bootloaderBanner
; Put 0x0e to ah, which stands for "Write Character in TTY mode" when issuing a BIOS Video Services interrupt 0x10
mov ah, 0x0e
loop:
; Load byte at address si to al
lodsb
; Check if al==0 / a NULL byte, meaning end of a C string
test al, al
; If al==0, jump to end, where the bootloader will be halted
jz exit_print_loop
; Issue a BIOS interrupt 0x10 for video services
int 0x10
; Repeat
jmp loop
exit_print_loop:
; Clear the keyboard buffer
xor ah, ah
; Read a character from the keyboard
mov ah, 0
int 0x16
; Display the character on the screen
mov ah, 0x0e
int 0x10
; mov ah, 0
; int 0x16
cmp al, '1'
jne start_ubuntu
mov ax,0x201
mov bx,0x7c00
mov cx,[bp+0x2]
mov dx,[bp+0x0]
int 0x13
jnc 0x7c00
start_ubuntu:
xor ax,ax
mov ds,ax
mov si,0x7c05
mov byte [si],0x10
mov byte [si+0x1],0x00
mov byte [si+0x2],0x01
mov byte [si+0x3],0x00
mov byte [si+0x4],0x00
mov byte [si+0x5],0x80
mov byte [si+0x6],0x00
mov byte [si+0x7],0x00
mov byte [si+0x8],0x01
mov byte [si+0x9],0x00
mov byte [si+0xa],0x00
mov byte [si+0xb],0x00
mov byte [si+0xc],0x00
mov byte [si+0xd],0x00
mov byte [si+0xe],0x00
mov byte [si+0xf],0x00
mov ah,0x42
mov dl,0x80
int 0x13
jnc 0x8000
bootloaderBanner: db " 1 Windows",13,10," 2 Ubuntu",13,10, 0
; Fill remaining space of the 512 bytes minus our instructions, with 00 bytes
; $ - address of the current instruction
; $$ - address of the start of the image .text section we're executing this code in
times 510 - ($-$$) db 0
; Bootloader magic number
dw 0xaa55
And i copied the valid binary code into the first nearly 200 bytes of the disk and did not change the rest part like partition table
Part of the partition table of my disk is:
| B | SCHS | ID | ECHS | RSLBA | SecCnt |
|---|---|---|---|---|---|
| 80 | 20 21 00 | 07 | df 13 0c | 00 08 00 00 | 00 20 03 00 |
| 00 | df 14 0c | 07 | fe ff ff | 00 28 03 00 | 00 98 d1 01 |
| 00 | fe ff ff | 05 | fe ff ff | fe c7 d4 01 | 02 30 4b 01 |
| 00 | 00.... |
By the way, my computer system is MSWindows 11 and the virtual disk is created by qemu. And the systems I installed are MSWindows 7 and Ubuntu 22.04
Now I wonder where the stage 2 of ubuntu is located. I searched online and from this i know i need to find the (4-byte) Quad-Word, but i never know where it is. I have also searched the string "Loading stage2" in the whole disk but no results.
The result of fdisk -l in the ubuntu system installed on the disk:
| equipment | start | beginning | end | sector | size | id | type |
|---|---|---|---|---|---|---|---|
| /dev/sda1 | 2048 | 206847 | 204800 | 100M | 7 | HPFS/NTFS/exFAT | |
| /dev/sda2 | 206848 | 30719999 | 30513152 | 14.5G | 7 | HPFS/NTFS/exFAT | |
| /dev/sda3 | 30722046 | 52426751 | 21704706 | 10.3G | 5 | extend | |
| /dev/sda5 | * | 30722048 | 31111167 | 389120 | 190M | ef | EFI(FAT -12/16/32) |
| /dev/sda6 | 31113216 | 52426751 | 21313536 | 10.2G | 83 | Linux |