мой загрузчик состоит из двух этапов по 512 байт. этап 1 загружается b ios в область MBR. Затем stage1 переходит к загрузке stage2 с диска и переходит к нему.
Я подтвердил с помощью шестнадцатеричного редактора, что размер конечного двоичного файла "program.bin" составляет точно 1024 байта и содержит обе "подписи" (последний два байта каждого этапа, 0xAA55 для stage1 (подпись MBR) и 0xCC77 для stage2).
ожидаемые результаты:
1 // stage1 started
0000 or 0080 // drive# in hex
CC77 // stage2 "signature" in hex
2 // stage2 started
это отлично работает в QEMU, но не работает в виртуальном боксе и на оборудовании . мне кажется, что загрузка stage2 молча терпит неудачу (ветвь ошибки не вызывается), и я безуспешно пытаюсь решить эту проблему в течение двух недель.
Вывод QEMU ![QEMU output](https://i.stack.imgur.com/YFT2o.png)
Hardware & Virtual Box output
Вывод VBox
stage1.asm:
global _start
extern _stage2
extern _stage2data
BITS 16
_start:
; init registers
xor ax, ax
mov es, ax
mov gs, ax
mov ss, ax
mov sp, 0x7C00 ; right before MBR, counting upwards
mov ax, 0x7C0 ; set DS to 0x7c0 so pointing at 0x0 resolves to 0x7C0:x0000 = 0x7C00
mov ds, ax
cld ; set direction flag to make string operations count forward
; mark start of stage 1 by printing "1"
mov al, '1'
call real_mode_print_char
call real_mode_new_line
print_drive_number:
; drive# is put into DL by BIOS
mov dh, 0x0
mov bx, dx
call real_mode_print_hex
load_sector2:
mov al, 0x01 ; load 1 sector
mov bx, 0x7E00 ; destination, right after your bootloader
mov cx, 0x0002 ; cylinder 0, sector 2
; mov dl, [BootDrv] ; boot drive
xor dh, dh ; head 0
call read_sectors_16
jnc execute_stage2 ; if carry flag is set, disk read failed
jmp error
execute_stage2:
mov bx, [_stage2data] ; print data at _stage2data to confirm stage 2 was loaded
call real_mode_print_hex
jmp _stage2 ; start execude instructions of _stage2
error:
; print "E" if an error occurs
mov al, 'E'
call real_mode_print_char
; infinite loop
loop:
jmp loop
; read_sectors_16
;
; Reads sectors from disk into memory using BIOS services
;
; input: dl = drive
; ch = cylinder[7:0]
; cl[7:6] = cylinder[9:8]
; dh = head
; cl[5:0] = sector (1-63)
; es:bx -> destination
; al = number of sectors
;
; output: cf (0 = success, 1 = failure)
read_sectors_16:
push ax
mov si, 0x02 ; maximum attempts - 1
.top:
mov ah, 0x02 ; read sectors into memory (int 0x13, ah = 0x02)
int 0x13
jnc .end ; exit if read succeeded
dec si ; decrement remaining attempts
jc .end ; exit if maximum attempts exceeded
xor ah, ah ; reset disk system (int 0x13, ah = 0x00)
int 0x13
jnc .top ; retry if reset succeeded, otherwise exit
.end:
pop ax
retn
# print a number in hex
# IN
# bx: the number
# CLOBBER
# al, cx
real_mode_print_hex:
mov cx, 4
.lp:
mov al, bh
shr al, 4
cmp al, 0xA
jb .below_0xA
add al, 'A' - 0xA - '0'
.below_0xA:
add al, '0'
call real_mode_print_char
shl bx, 4
loop .lp
call real_mode_new_line
ret
real_mode_new_line:
mov al, 0x0D
call real_mode_print_char
mov al, 0x0A
call real_mode_print_char
ret
real_mode_print_char:
push bx
xor bx, bx ; Attribute=0/Current Video Page=0
mov ah, 0x0e
int 0x10 ; Display character
pop bx
ret
; boot signature
TIMES 510-($-$$) db 0
mbr_id:
dw 0xAA55
stage2.asm:
global _stage2
global _stage2data
BITS 16
_stage2:
mov al, '2'
call bios_print_char
loop:
jmp loop
bios_print_char:
push bx
xor bx, bx ; Attribute=0/Current Video Page=0
mov ah, 0x0e
int 0x10 ; Display character
pop bx
ret
; boot signature
TIMES 510-($-$$) db 0
_stage2data:
dw 0xCC77
скрипт компоновщика "linker.ld":
ENTRY(_start)
OUTPUT_FORMAT(binary)
SECTIONS
{
output :
{
stage1.elf(.text)
stage2.elf(.text)
}
}
Я использую следующие команды для компиляции и компоновки всего вместе:
nasm -f elf64 stage1.asm -o stage1.elf
nasm -f elf64 stage2.asm -o stage2.elf
ld -m elf_x86_64 -o program.bin stage2.elf stage1.elf -nostdlib -T linker.ld
Я запускаю двоичный файл на QEMU с помощью:
qemu-system-x86_64 -drive format=raw,file=program.bin
, чтобы запустить его на оборудовании, я записываю двоичный файл в USB с:
dd if=program.bin of=/dev/sdb1 && sync