assembly 加载后未执行内核

3z6pesqy  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(180)

问题

内核似乎被引导加载程序加载,但没有进一步执行。似乎有一个问题,无论是我运行的方式与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

js5cn81o

js5cn81o1#

mov dl, 0x0       ; drive number to load (0 = boot disk)

字符串
你已经在@Jester和@MichaelPetch的帮助下解决了主要问题。
仍然存在一些问题:

  • 问题1
org 0x7C00
%define color_black   0
...
mov [drive_number], dl


也许你已经习惯了你的模拟器(qemu)用零段寄存器启动你的 Bootstrap 。在许多系统上,情况并非如此!如果你关心开发健壮的软件,那么至少在你的 Bootstrap 旁边添加:

org  0x7C00
%define color_black   0
...
xor  ax, ax
mov  ds, ax
mov  es, ax
mov  ss, ax             ; Keep these two together
mov  sp, 0x7C00         ;  and in this order
cld                     ; So LODSB functions allright
mov  [drive_number], dl ; Depends on DS=0
...

  • 问题2
mov ax, 0x1000
mov ds, ax      ; data segment
mov es, ax      ; extra segment
mov fs, ax       
mov gs, ax
mov ss, ax      ; stack segment
call disk_load  ; loads kernel into memory
jmp 0x1000:0x0


因为您甚至在通过 disk_load 过程加载内核之前就设置了这些段寄存器,所以 disk_load 过程无法显示其消息,无论是 disk_error 还是 disk_success
更糟糕的是,您更改了SS段寄存器,但没有分配合适的SP寄存器。目前,这不会造成问题,因为你只加载一个扇区。但是想象一下,一旦你的项目增长,你加载了100个扇区,会发生什么。然后,SP中的任何值都会(与新的SS相结合)在内核中造成严重破坏,很难检测到这个错误.
总之,在内核的第一行中更改这些段寄存器和SP(为了可读性,也可以在顶部使用org 0,即使该设置恰好是默认设置)。

  • 问题3
  • print_string_buffer* 过程依赖于DL和DH保存合适的列和行指示,但是当从 disk_load 中调用时(显示错误或成功消息),情况就不是这样了!没有告诉这些消息是否或在哪里出现。
  • 问题4
mov dx, 25 << 8 | 80           ; Clear window to 24, 80


80 x25屏幕的右下角是(79,24)。这个指令应该是:mov dx, 24 << 8 | 79

  • 问题5
start_up_message: db "Bootloader bootstrap", 0
drive_number: resb 8

  • drive_number* 的存储只需要1个字节。不要使用保留8个字节的resb 8,而只需写入:
start_up_message: db "Bootloader bootstrap", 0
drive_number:     db 0

相关问题