这是我的MBR代码:
config/boot.asm:
%ifndef BOOT_H
%define BOOT_H
; Kernel loader address.
LOADER_BASE_ADDR: equ 0x900
; The logical sector address of the kernel loader on the disk.
LOADER_START_SECTOR: equ 0x2
; The number of sectors occupied by the kernel loader.
LOADER_SECTORS: equ 4
%endif
mbr.asm:
section MBR vstart=0x7C00
jmp main
%include "config/boot.asm"
[bits 16]
main:
mov ax, 0
mov ss, ax
mov ds, ax
mov fs, ax
mov es, ax
mov sp, $$
push bp
mov bp, sp
call init
; Read starting sector from disk.
call read_disk
; Started supporting OS loader.
jmp LOADER_BASE_ADDR
init:
push bp
mov bp, sp
; Clean up BIOS output.
mov ax, 0xB800
mov es, ax
mov cx, 2000
mov di, 0
clean_screen:
mov word [es: di], 0
add di, 2
loop clean_screen
leave
ret
; Read OS loader from disk.
read_disk:
push bp
mov bp, sp
; Set the number of sectors to read.
mov dx, 0x1F2
mov ax, LOADER_SECTORS
out dx, al
; Set the logical sector address.
mov ax, LOADER_START_SECTOR
mov dx, 0x1F3
out dx, al
mov cl, 8
mov dx, 0x1F4
shr ax, cl
out dx, al
shr ax, cl
mov dx, 0x1F5
out dx, al
shr ax, cl
and al, 0x0F
or al, 0xE0
mov dx, 0x1F6
out dx, al
; Send a read command.
mov dx, 0x1F7
mov al, 0x20
out dx, al
; Wait for the hard drive to prepare the data.
mov dx, 0x1F7
.read_disk_wait:
nop
in al, dx
and al, 0x88
cmp al, 0x08
jnz .read_disk_wait
; The hard disk is ready to start reading data.
mov di, LOADER_BASE_ADDR
mov ax, LOADER_SECTORS
mov dx, 256
mul dx
mov cx, ax
mov dx, 0x1F0
.read_disk_read:
in ax, dx
mov [di], ax
add di, 2
loop .read_disk_read
leave
ret
times 510-($-$$) db 0
db 0x55, 0xAA
这是我的内核加载程序的代码:
section CORE_LOADER vstart=LOADER_BASE_ADDR
jmp main
%include "config/boot.asm"
%include "config/gdt.asm"
%include "print.asm"
MESSAGE: db "Hello World", 0
STRLEN: equ $ - MESSAGE
[bits 16]
main:
mov sp, $$
push bp
mov bp, sp
; Load GDT, turn on protected mode.
in al, 0x92
or al, 2
out 0x92, al
lgdt [GDT_PTR]
mov eax,cr0
or eax, 1
mov cr0, eax
jmp dword SELECTOR_CODE:p_mode_start
[bits 32]
p_mode_start:
mov esp, $$
mov ax, SELECTOR_DATA
mov ds, ax
mov ss, ax
mov gs, ax
mov es, ax
; clean screen
call clean_screen
; Output "Hello World".
push MESSAGE
call print
add esp, 8
jmp $
我没有给出";打印";以及";GDT";,但我可以保证他们没有问题。
这是我的Makefile:
SOURCE=src
BUILD_DIR=build
ASSEMBLER=@nasm -I $(SOURCE)
DD=@dd
OS_IMG=$(BUILD_DIR)/aszswaz.img
MBR=$(BUILD_DIR)/mbr.bin
OS_LOADER=$(BUILD_DIR)/os-loader.bin
IMG_SECTOR=60
all: $(BUILD_DIR)
$(OS_IMG)
$(BUILD_DIR):
@mkdir -p $@
.PHONY: clean
clean:
@rm -rf $(BUILD_DIR)
# Build an OS image.
$(OS_IMG): $(MBR) $(OS_LOADER)
$(DD) if=/dev/zero of=$@ bs=1M count=$(IMG_SECTOR) >> /dev/null 2>&1
$(DD) if=$(MBR) of=$@ bs=512 count=1 conv=notrunc >> /dev/null 2>&1
$(DD) if=$(OS_LOADER) of=$@ bs=512 seek=2 conv=notrunc >> /dev/null 2>&1
$(MBR): $(SOURCE)/mbr.asm $(SOURCE)/print.asm $(SOURCE)/config/boot.asm
$(ASSEMBLER) $< -o $@
$(OS_LOADER): $(SOURCE)/os-loader.asm $(SOURCE)/print.asm $(SOURCE)/config/boot.asm $(SOURCE)/config/gdt.asm
$(ASSEMBLER) $< -o $@
这是我的bochs配置:
megs: 32
# Set BIOS and vga.
romimage: file=/usr/share/bochs/BIOS-bochs-latest
vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest
boot: disk
log: bochs.log
mouse: enabled=0
keyboard: keymap=/usr/share/bochs/keymaps/x11-pc-us.map
# Set up the hard disk.
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=disk, path=build/aszswaz.img, mode=flat, cylinders=121, heads=16, spt=63
这是我的qemu配置:
$ qemu-system-i386
-name 'guest=aszswaz'
-m 1M
-boot 'menu=on,strict=on'
-drive 'file=build/aszswaz.img,format=raw'
以下是我的bochs和qemu版本:
$ bochs --help
========================================================================
Bochs x86 Emulator 2.7
Built from SVN snapshot on August 1, 2021
Timestamp: Sun Aug 1 10:07:00 CEST 2021
========================================================================
...
$ qemu-system-i386 -version
QEMU emulator version 7.1.0
Copyright (c) 2003-2022 Fabrice Bellard and the QEMU Project developers
我通过GDB检查了0x900的内存,在qemu中运行的MBR似乎没有正常读取操作系统加载程序,但IO端口没有给出任何异常。但这在地滚球中效果很好。
根据Brendan的建议,我尝试使用BIOS读取操作系统加载程序,修改后的MBR代码如下:
section MBR vstart=0x7C00
jmp main
%include "config/boot.asm"
%include "print16.asm"
%include "config/memory-management.asm"
DISK_READ_ERROR: db "OS loader read failed, the error code is: 0x", 0
[bits 16]
main:
mov ax, 0
mov ss, ax
mov ds, ax
mov fs, ax
mov es, ax
mov sp, $$
call clean_screen
; Read OS loader via BIOS interrupt.
; Set the function number, 2 means read sector.
mov ah, 2
; Set the number of sectors to read.
mov al, LOADER_SECTORS
; Set the cylinder.
mov ch, 0
; Set the head.
mov dh, 0
; Set sector.
mov cl, LOADER_START_SECTOR
; Set the drive letter, 0 ~ 0x7F is floppy disk, 0x80 ~ 0xFF is hard disk.
mov dl, 0x80
; Set the destination address.
mov bx, LOADER_BASE_ADDR
int 0x13
; If the disk read error, the BIOS will set the CF of the flags register to 1, and AH is the error code.
jc disk_error
jmp LOADER_BASE_ADDR
disk_error:
mov [REGISTER_AX], ax
mov ax, DISK_READ_ERROR
call print
mov ax, [REGISTER_AX]
call print_hex
jmp $
times 510-($-$$) db 0
db 0x55, 0xAA
另一件需要注意的事情是,在进入保护之前,需要使用cli
命令禁用中断,否则在qemu中,这将导致计算机无限重启。