问题
内核似乎被引导加载程序加载,但没有进一步执行。似乎有一个问题,无论是我运行的方式与qemu
的图像或与内核的加载方式。
源码
- makefile*
bold=`tput bold`
black=`tput setaf 0`
red=`tput setaf 1`
green=`tput setaf 2`
yellow=`tput setaf 3`
blue=`tput setaf 4`
magenta=`tput setaf 5`
cyan=`tput setaf 6`
white=`tput setaf 7`
reset=`tput sgr0`
default: build run
build:
@echo "${bold}${green}[INFO]${reset} Compiling Bootloader"
@nasm -f bin src/bootloader.asm -o bin/boot.bin
@echo "${bold}${green}[INFO]${reset} Compiling Kernel"
@nasm -f bin src/kernel.asm -o bin/kernel.bin
@echo "${bold}${green}[INFO]${reset} Compiling the OS"
@cat bin/boot.bin bin/kernel.bin > bin/os.bin
@echo "${bold}${green}[INFO]${reset} Compiled."
run:
@echo "${bold}${green}[INFO]${reset} Launching the VM:"
@qemu-system-x86_64 -enable-kvm -drive format=raw,file=bin/os.bin -m 4G -cpu host -smp 2 -vga virtio -display sdl,gl=on
clean:
@echo "${bold}${green}[INFO]${reset} Cleaning..."
@rm -rfv bin/*.bin
@echo "${bold}${green}[INFO]${reset} Cleaned"
字符串
辅助函数: src/utils/print.asm
print_string_buffer:
; The function prints a string from the buffer
; stored in the SI register, it expects a
; null symbol to be found in the buffer.
; Parameters:
; si - memory offset to the buffer
push si
push ax
.loop:
lodsb
or al, al
jz .done
; display character
mov ah, 0x0A
mov bh, 0x00
mov cx, 1
int 0x10
; move cursor
mov ah, 0x02
inc dl
int 0x10
jmp .loop
.done:
pop ax
pop si
ret
型
- src/disk.asm*
disk_load:
; The function reads DH number of sectors
; into ES:BX memory location from drive DL
; Parameters:
; es:bx - buffer memory address
push dx ; store dx on stack for error handling later
mov ah, 0x02 ; INT 13H 02H, BIOS read disk sectors into memory
mov al, dh ; number of sectors
mov ch, 0x00 ; cylinder
mov dh, 0x00 ; head
mov cl, 0x02 ; start reading sector (2 is the sector after the bootloader)
int 0x13 ; BIOS interrupt for disk functions
jc disk_error ; checks if CF (carry flag) set to 1
pop dx ; restore dx value from stack
cmp dh, al ; checks dh (number of read sectors) vs al (number of desired read sectors)
jne disk_error ; if not the desired amount of sectors were read, then error
call disk_success
ret ; return to caller
disk_error:
mov si, DISK_ERROR_MESSAGE
call print_string_buffer
hlt
disk_success:
mov si, DISK_SUCCESS_MESSAGE
call print_string_buffer
; move cursor
mov ah, 0x02
inc dh
mov dl, 0
int 0x10
ret
DISK_ERROR_MESSAGE: db "could not read from disk", 0
DISK_SUCCESS_MESSAGE: db "successfully loaded the disk", 0
型
bootloader src/bootloader.asm
org 0x7C00
%define color_black 0
%define color_blue 1
%define color_green 2
%define color_cyan 3
%define color_red 4
%define color_magenta 5
%define color_orange 6
%define color_gray 7
%define color_yellow 14
%define color_white 15
;;;;;;;;
; INIT ;
;;;;;;;;
clear_screen:
; Int 0x10
; AH = 06h
; AL = number of lines by which to scroll up (00h = clear entire window)
; BH = attribute used to write blank lines at bottom of window
; CH, CL = row, column of window's upper left corner
; DH, DL = row, column of window's lower right corner
mov ax, 0x0600 ; AH = 6 = Scroll Window Up, AL = 0 = clear window
mov bh, color_black << 4 | color_magenta ; Attribute to clear screen with (White on Red)
xor cx, cx ; Clear window from 0, 0
mov dx, 25 << 8 | 80 ; Clear window to 24, 80
int 0x10 ; Clear the screen
mov ah, 0x02 ; Set cursor
mov bh, 0x00 ; Page 0
mov dx, 0x00 ; Row = 0, col = 0
int 0x10
set_custom_cursor:
; Int 0x10
; AH = 01h
; CH = start scan line of character matrix (0-1fH; 20H=no cursor)
; CL = end scan line of character matrix (0-1fH)
mov ax, 0x0100 ; AH = 1 = Set Cursor Shape & Size, AL = 0 = nothing
mov ch, 0x1 ; Sets the width of the cursor, the higher the thicker
mov cl, 0x10 ; Sets the height of the cursor, the less the higher
int 0x10
; bootloader start-up message
mov si, start_up_message
call print_string_buffer
; set up DX for disk loading
mov dh, 0x1 ; number of sectors that will be loaded into memory
mov dl, 0x0 ; drive number to load (0 = boot disk)
; set up ES:BX memory address to load sectors into
mov bx, 0x1000 ; load sector to memory address 0x1000
mov es, bx ; ES = 0x1000
mov bx, 0x0 ; ES:BX = 0x1000:0 (segment:offset)
; set up segment registers for RAM
mov ax, 0x1000
mov ds, ax ; data segment
mov es, ax ; extra segment
mov fs, ax
mov gs, ax
mov ss, ax ; stack segment
;;;;;;;;;;;;;;;;;;;;;;;;;;
; BOOTLOADER ENTRY POINT ;
;;;;;;;;;;;;;;;;;;;;;;;;;;
call disk_load ; loads kernel into memory
jmp 0x1000:0x0
;;;;;;;;;;;
; IMPORTS ;
;;;;;;;;;;;
%include "src/utils/print.asm"
%include "src/disk.asm"
;;;;;;;
; VAR ;
;;;;;;;
start_up_message: db "Bootloader bootstrap", 0
;;;;;;;;;;;;;;;;;
; MAGIC NUMBERS ;
;;;;;;;;;;;;;;;;;
times 510-($-$$) db 0
dw 0xAA55
型
*kernel * src/kernel.asm
;;;;;;;;;;;;;;;
; ENTRY POINT ;
;;;;;;;;;;;;;;;
start:
mov si, OS_VERSION
call print_string_buffer
hlt
;;;;;;;;;;;
; IMPORTS ;
;;;;;;;;;;;
%include "src/utils/print.asm"
OS_VERSION: db "OS v1.0", 0
; sector padding
times 512-($-$$) db 0
型
运行make
后,可以看到以下项目的结构:
.
├── bin
│ ├── boot.bin
│ ├── kernel.bin
│ └── os.bin
├── makefile
└── src
├── bootloader.asm
├── disk.asm
├── kernel.asm
└── utils
└── print.asm
型
我尝试通过将ES:BX
寄存器设置为0x0:0x1000
等值,从引导加载程序跳转到内核的不同位置。此外,我将虚拟机的内存增加到4GB RAM。以下方法都没有帮助。
任何理论或想法都会有帮助。谢谢。
新发现更新
制作一个floopy镜像并在VirtualBox中运行它似乎工作得很好。而同一个floopy镜像在执行引导加载程序后仍然冻结,无法到达内核。因此源代码应该是正确的,问题在于qemu
参数。
- makefile的更改 *:
...
build:
@echo "${bold}${green}[INFO]${reset} Compiling Bootloader"
@nasm -f bin src/bootloader.asm -o bin/boot.bin
@echo "${bold}${green}[INFO]${reset} Compiling Kernel"
@nasm -f bin src/kernel.asm -o bin/kernel.bin
@echo "${bold}${green}[INFO]${reset} Compiling the OS"
@cat bin/boot.bin bin/kernel.bin > bin/os.bin
@echo "${bold}${green}[INFO]${reset} Compiling the Floopy image"
@dd if=/dev/zero of=bin/floopy.img bs=1024 count=1440
@dd conv=notrunc if=bin/os.bin of=bin/floopy.img
@echo "${bold}${green}[INFO]${reset} Compiled."
run:
@echo "${bold}${green}[INFO]${reset} Launching the VM:"
@qemu-system-x86_64 -enable-kvm -drive format=raw,file=bin/floopy.img -m 4G -cpu host -smp 2 -vga virtio -display sdl,gl=on
...
型
溶液
在将控制权交给引导加载程序之前,保存BIOS设置的DL
寄存器的初始值,解决了这个问题。
- 修复 Bootstrap *
org 0x7C00
%define color_black 0
%define color_blue 1
%define color_green 2
%define color_cyan 3
%define color_red 4
%define color_magenta 5
%define color_orange 6
%define color_gray 7
%define color_yellow 14
%define color_white 15
;;;;;;;;
; INIT ;
;;;;;;;;
; save DL (drive number) value from the BIOS
mov [drive_number], dl
clear_screen:
; Int 0x10
; AH = 06h
; AL = number of lines by which to scroll up (00h = clear entire window)
; BH = attribute used to write blank lines at bottom of window
; CH, CL = row, column of window's upper left corner
; DH, DL = row, column of window's lower right corner
mov ax, 0x0600 ; AH = 6 = Scroll Window Up, AL = 0 = clear window
mov bh, color_black << 4 | color_magenta ; Attribute to clear screen with (White on Red)
xor cx, cx ; Clear window from 0, 0
mov dx, 25 << 8 | 80 ; Clear window to 24, 80
int 0x10 ; Clear the screen
mov ah, 0x02 ; Set cursor
mov bh, 0x00 ; Page 0
mov dx, 0x00 ; Row = 0, col = 0
int 0x10
set_custom_cursor:
; Int 0x10
; AH = 01h
; CH = start scan line of character matrix (0-1fH; 20H=no cursor)
; CL = end scan line of character matrix (0-1fH)
mov ax, 0x0100 ; AH = 1 = Set Cursor Shape & Size, AL = 0 = nothing
mov ch, 0x1 ; Sets the width of the cursor, the higher the thicker
mov cl, 0x10 ; Sets the height of the cursor, the less the higher
int 0x10
; bootloader start-up message
print_start_up_message:
mov si, start_up_message
call print_string_buffer
; move cursor
mov ah, 0x02
inc dh
mov dl, 0
int 0x10
; set up DX for disk loading
mov dh, 0x1 ; number of sectors that will be loaded into memory
mov dl, [drive_number] ; drive number to load (0 = boot disk)
; set up ES:BX memory address to load sectors into
mov bx, 0x1000 ; load sector to memory address 0x1000
mov es, bx ; ES = 0x1000
mov bx, 0x0 ; ES:BX = 0x1000:0 (segment:offset)
; set up segment registers for RAM
mov ax, 0x1000
mov ds, ax ; data segment
mov es, ax ; extra segment
mov fs, ax
mov gs, ax
mov ss, ax ; stack segment
;;;;;;;;;;;;;;;;;;;;;;;;;;
; BOOTLOADER ENTRY POINT ;
;;;;;;;;;;;;;;;;;;;;;;;;;;
call disk_load ; loads kernel into memory
jmp 0x1000:0x0
;;;;;;;;;;;
; IMPORTS ;
;;;;;;;;;;;
%include "src/utils/print.asm"
%include "src/disk.asm"
;;;;;;;
; VAR ;
;;;;;;;
start_up_message: db "Bootloader bootstrap", 0
drive_number: resb 8
;;;;;;;;;;;;;;;;;
; MAGIC NUMBERS ;
;;;;;;;;;;;;;;;;;
times 510-($-$$) db 0
dw 0xAA55
型
1条答案
按热度按时间js5cn81o1#
字符串
你已经在@Jester和@MichaelPetch的帮助下解决了主要问题。
仍然存在一些问题:
型
也许你已经习惯了你的模拟器(qemu)用零段寄存器启动你的 Bootstrap 。在许多系统上,情况并非如此!如果你关心开发健壮的软件,那么至少在你的 Bootstrap 旁边添加:
型
型
因为您甚至在通过 disk_load 过程加载内核之前就设置了这些段寄存器,所以 disk_load 过程无法显示其消息,无论是 disk_error 还是 disk_success。
更糟糕的是,您更改了SS段寄存器,但没有分配合适的SP寄存器。目前,这不会造成问题,因为你只加载一个扇区。但是想象一下,一旦你的项目增长,你加载了100个扇区,会发生什么。然后,SP中的任何值都会(与新的SS相结合)在内核中造成严重破坏,很难检测到这个错误.
总之,在内核的第一行中更改这些段寄存器和SP(为了可读性,也可以在顶部使用
org 0
,即使该设置恰好是默认设置)。型
80 x25屏幕的右下角是(79,24)。这个指令应该是:
mov dx, 24 << 8 | 79
。型
resb 8
,而只需写入:型