繁体   English   中英

程序集Bootloader没有跳转到内核

[英]Assembly Bootloader Not Jumping to Kernel

我正在尝试在汇编中编写引导加载程序和内核以用于学习目的。 当我组装代码并使用它启动虚拟机时,引导加载程序似乎正常工作,但内核永远不会启动。 我想我正在跳错了指令,但不知道我需要做些什么更正才能解决我的问题。 还有可能我试图使软盘不正确,但我认为这不是问题。 当我在十六进制编辑器中查看图像文件时,似乎它们被正确附加。 另一个原因可能是从软盘读取错误的扇区。 我正试图让内核在引导加载程序之后立即进入扇区。

要构建和运行此代码,我在Windows Vista x64中执行以下操作:

nasm bootloader_2.asm -f bin -o bootloader_2.bin 
nasm kernel_2.asm -f bin -o kernel.bin 
partcopy bootloader_2.bin bootloader_2.img 0d 511d 
partcopy kernel_2.bin kernel_2.img 0d 511d 
copy bootloader.img /b + kernel.img POS_2.img

然后我使用Oracle VM Virtual Box将POS_2.img挂载为软盘驱动器,并在来宾系统上运行它。

结果是

帕特里克的Bootloader开始了。 软盘已重置。 读取内核扇区内核扇区

内核永远不会启动。

这是我的代码

bootloader_2.asm

bits 16
org 0x7C00
boot: jmp loader

; OEM Parameter block / BIOS Parameter block (wtf is this for?)
times 0Bh-$+boot DB 0
bpbBytesPerSector:        DW 512
bpbSectorsPerCluster:    DB 1
bpbReservedSectors:        DW 1
bpbNumberOfFATs:        DB 2
bpbRootEntries:            DW 224
bpbTotalSectors:        DW 2880
bpbMedia:                DB 0xF0
bpbSectorsPerFAT:        DW 9
bpbSectorsPerTrack:        DW 18
bpbHeadsPerCylinder:    DW 2
bpbHiddenSectors:        DD 0
bpbTotalSectorsBig:        DD 0
bsDriveNumber:            DB 0
bsUnused:                DB 0
bsExtBootSignature:        DB 0x29
bsSerialNumber:            DD 0xa0a1a2a3
bsVolumeLabel:            DB "MOS FLOPPY"
bsFileSystem:            DB "FAT12"
; END PARAMETER BLOCK

; ----- Variables -----

started db "Patrick's Bootloader Started...", 0x0D, 0x0A, 0
floppy_reset_done db "Floppy has been reset.", 0x0D, 0x0A, 0
loading_msg db "Reading Kernel Sector", 0x0D, 0x0A, 0
loading_sucess db "Kernel Sector Loaded", 0x0D, 0x0A, 0
done db "Bootloader Done.", 0x0D, 0x0A, 0

; ----- End Variables -----

; ----- Calls -----

reset_floppy:
    mov ah, 0
    mov dl, 0
    int 0x13
    jc reset_floppy
    mov si, floppy_reset_done
    call print_string
    ret

read_kernel:
    mov si, loading_msg
    call print_string
    mov si, 0x0

    mov ax, 0x1000    ; setting up the address to read into
    mov es, ax        ; moving the value in to es
    xor bx, bx        ; clearing bx
    mov ah, 0x02    ; floppy function
    mov al, 1        ; read 1 sector
    mov ch, 1        ; track
    mov cl, 2        ; sector to read
    mov dh, 0        ; head number
    mov dl, 0        ; drive number

    int 0x13        ; BIOS Interrupt Call

    jc read_kernel

    mov si, loading_sucess
    call print_string

    ret

print_string:
    lodsb
    or al, al
    jz .done
    mov ah, 0x0E
    int 0x10
    jmp print_string
.done:
    ret

; input is ax, cx is destroyed    
print_hex:
    mov cx, 4
    .next_digit:
        push cx
        mov cl, 4
        rol ax, cl
        push ax
        and al, 0x0F
        add al, '0'
        cmp al, '9'
        jle .not_a_leter
        add al, 'A'-'9'-1
    .not_a_leter:
        mov ah, 0x0E
        int 0x10
        pop ax
        pop cx
        loop .next_digit
    ret

; ----- End of Calls -----

; ===== Bootloader Main =====

loader:
    mov si, started
    call print_string
    call reset_floppy
    call read_kernel

    jmp 0x1000:0x0

    mov si, done        ; never reached. Intentional for debugging
    call print_string    ; these lines failure to produce a result tell us that the jmp was attempted

; ===== End of Bootloader Main =====

times 510-($-$$) db 0
dw 0xAA55

kernel_2.asm

kernel:
    jmp k_main

welcome_msg db "Welcome to Patrick's Operating System!", 0x0D, 0x0A, 0

print_string:
    lodsb
    or al, al
    jz .done
    mov ah, 0x0E
    int 0x10
    jmp print_string
.done:
    ret

k_main:

    mov si, welcome_msg
    call print_string

    .k_main_loop:

    jmp .k_main_loop

cli
hlt

times 512-($-$$) db 0

冒着指出明显的风险,您的脚本不会复制正确的文件。 在某些地方你指的是kernel.bin和其他的kernel_2.bin 试试这个:

nasm bootloader_2.asm -f bin -o bootloader_2.bin 
nasm kernel_2.asm -f bin -o kernel_2.bin 
partcopy bootloader_2.bin bootloader_2.img 0d 511d 
partcopy kernel_2.bin kernel_2.img 0d 511d 
copy bootloader.img /b + kernel_2.img POS_2.img

您可能还会发现使用dd更容易使用dd 它可以作为Cygwin的一部分使用,并且具有可以写入文件或物理设备(如真正的软盘)的优点。

此外,您应该考虑使用Makefile而不是脚本。 当您进一步扩展项目时,它将有所帮助。

也就是说,代码有三个基本问题。 首先,要加载的下一个扇区是在柱面0上,而不是柱面1.其次,代码不能简单地安全地ret内核 - 你必须明确地跳转到那里。 那部分代码将如下所示:

read_kernel:
    mov si, loading_msg
    call print_string
    mov si, 0x0

    mov ax, 0x1000   ; setting up the address to read into
    mov es, ax       ; moving the value in to es
    xor bx, bx       ; clearing bx
    mov ah, 0x02     ; floppy function
    mov al, 1        ; read 1 sector
    mov ch, 0        ; cylinder
    mov cl, 2        ; sector to read
    mov dh, 0        ; head number
    mov dl, 0        ; drive number

    int 0x13         ; BIOS Interrupt Call

    jc read_kernel
    push es          ; either push the address and retf or use far jmp
    push bx          ;

    mov si, loading_sucess
    call print_string

    ; jmp  0x1000:0  ; alternative to push/retf is simple long jump

    retf

第三个问题是内核。 您还没有将DS寄存器更改为指向新的偏移量,因此即使您获得该代码,它也不会打印您想要的字符串。 将代码更改为以下内容:

k_main:
    push cs          ; save the cs reg
    pop  ds          ; use as ds also

    mov si, welcome_msg
    call print_string

    .k_main_loop:

    jmp .k_main_loop

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM