Pat*_*ord 7 assembly operating-system kernel bootloader
我正在尝试在汇编中编写引导加载程序和内核以用于学习目的.当我组装代码并使用它启动虚拟机时,引导加载程序似乎正常工作,但内核永远不会启动.我想我正在跳错了指令,但不知道我需要做些什么更正才能解决我的问题.还有可能我试图使软盘不正确,但我认为这不是问题.当我在十六进制编辑器中查看图像文件时,似乎它们被正确附加.另一个原因可能是从软盘读取错误的扇区.我正试图让内核在引导加载程序之后立即进入扇区.
要构建和运行此代码,我在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
Run Code Online (Sandbox Code Playgroud)
然后我使用Oracle VM Virtual Box将POS_2.img挂载为软盘驱动器,并在来宾系统上运行它.
结果是
帕特里克的Bootloader开始了.软盘已重置.读取内核扇区内核扇区
.内核永远不会启动.
这是我的代码
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
冒着指出明显的风险,您的脚本不会复制正确的文件.在某些地方,你可以参考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
Run Code Online (Sandbox Code Playgroud)
您可能还会发现使用此类内容更容易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
Run Code Online (Sandbox Code Playgroud)
第三个问题是内核.您还没有将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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1584 次 |
| 最近记录: |