简体   繁体   English

程序集Bootloader没有跳转到内核

[英]Assembly Bootloader Not Jumping to Kernel

I'm trying to write a bootloader and kernel in assembly for learning purposes. 我正在尝试在汇编中编写引导加载程序和内核以用于学习目的。 When I assemble my code, and boot a virtual machine with it, the bootloader seems to work properly, but the kernel never starts. 当我组装代码并使用它启动虚拟机时,引导加载程序似乎正常工作,但内核永远不会启动。 I'm thinking that I'm jumping to the wrong instruction, but don't know what corrections I need to make to resolve my issue. 我想我正在跳错了指令,但不知道我需要做些什么更正才能解决我的问题。 There's also the possibility that I'm trying to make the floppy incorrectly, but I don't think this is the issue. 还有可能我试图使软盘不正确,但我认为这不是问题。 When I look at the image files in a hex editor it appears that they were appended correctly. 当我在十六进制编辑器中查看图像文件时,似乎它们被正确附加。 Another cause might be reading the wrong sector from the floppy disk. 另一个原因可能是从软盘读取错误的扇区。 I'm trying to get the kernel to be in, and be read from, the sector right after the bootloader. 我正试图让内核在引导加载程序之后立即进入扇区。

To build and run this code I'm doing the following in Windows Vista x64: 要构建和运行此代码,我在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

I'm then using Oracle VM Virtual Box to mount the POS_2.img as a floppy drive, and run it on a guest system. 然后我使用Oracle VM Virtual Box将POS_2.img挂载为软盘驱动器,并在来宾系统上运行它。

The results are 结果是

Patrick's Bootloader Started. 帕特里克的Bootloader开始了。 Floppy has been reset. 软盘已重置。 Reading Kernel Sector Kernel Sector Loaded 读取内核扇区内核扇区

. And the kernel never starts. 内核永远不会启动。

Here's my code 这是我的代码

bootloader_2.asm 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_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

At the risk of pointing out the obvious, your script doesn't copy the right file. 冒着指出明显的风险,您的脚本不会复制正确的文件。 In some places you refer to kernel.bin and in others kernel_2.bin . 在某些地方你指的是kernel.bin和其他的kernel_2.bin Try this instead: 试试这个:

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

You may also find it easier for such things to use dd instead. 您可能还会发现使用dd更容易使用dd It's available as part of Cygwin and has the advantage that it can write to either files or physical devices such as a real floppy disk. 它可以作为Cygwin的一部分使用,并且具有可以写入文件或物理设备(如真正的软盘)的优点。

Also, you should consider using a Makefile instead of script. 此外,您应该考虑使用Makefile而不是脚本。 It will help as you expand your project further. 当您进一步扩展项目时,它将有所帮助。

That said, there are three basic problems with the code. 也就是说,代码有三个基本问题。 First, the next sector to be loaded is on cylinder 0, not cylinder 1. Second, the code can't simply safely ret to the kernel - you must jump there explicitly. 首先,要加载的下一个扇区是在柱面0上,而不是柱面1.其次,代码不能简单地安全地ret内核 - 你必须明确地跳转到那里。 That portion of the code would then look like this: 那部分代码将如下所示:

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

The third problem is the kernel. 第三个问题是内核。 You haven't changed the DS register to point to the new offset so even if you get to that code, it won't print the string you intend. 您还没有将DS寄存器更改为指向新的偏移量,因此即使您获得该代码,它也不会打印您想要的字符串。 Change that code to look like this instead: 将代码更改为以下内容:

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