我正在构建一个业余操作系统,但是在某些时候它无法正常工作(黑屏不显示任何内容),并且在试图知道为什么我试图使最小的内核可能无法正常工作的同时,这导致了到大师冥想错误,我怀疑这与int 13h有关]
这是产生大师冥想错误的代码:
VGA_MEMORY equ 0xB8000
org 0x7C00
bits 16
mov ax, VGA_MEMORY >> 4
mov es, ax
mov ax, 0x07E0
mov ss, ax
mov esp, 0xFFF0
mov ax, 0
mov ds, ax
; Disable the annoying cursor
mov ah, 0x01
mov ch, 001_11111b
int 0x10
reset_disk_hdd:
mov ah, 0x00 ; reset function
int 0x13 ; disk int
jc reset_disk_hdd
mov ax, 00h
mov ds, ax
mov si, disk_address_packet
read_disk_hdd:
mov ah, 42h ; read function
int 0x13 ; disk int
jc read_disk_hdd
jmp $
disk_address_packet:
db 10h ; size of DAP (set this to 10h)
db 00h ; unused, should be zero
dw 44h ; number of sectors to be read
dd 0x0000_7E00 ; segment:offset pointer to the memory buffer to which sectors will be transferred
dq 01h ; absolute number of the start of the sectors to be read
times 510-($-$$) db 0
dw 0xAA55
dw 'H'
我开始使用的原始代码读取了位于硬盘第二扇区的双字,它基本上是前景的颜色,背景的颜色和要在屏幕上打印的字符,然后将其移动字到0xB8000以在屏幕上打印出来。但是,当我看到这个黑屏却什么也没显示时,我开始尽可能地减少代码以保持出现此错误,但是却出现了Guru Meditation错误。注意,例如,我正在从磁盘读取44h个扇区。这是不断出现错误的最低数字。
这些是我使用以下代码打开虚拟机的命令:
mkdir vbox ; \
VBoxManage controlvm "X" poweroff ; \
sleep 1 ; \
VBoxManage unregistervm "e0b08add-d834-4af5-89e8-05abec11aa78" ; \
rm -r vbox/X ; \
rm kernel ; \
rm kernel.raw ; \
rm kernel.vdi ; \
VBoxManage createvm \
--name "X" \
--ostype "Other" \
--register \
--basefolder "$(pwd)/vbox" \
--uuid "e0b08add-d834-4af5-89e8-05abec11aa78" \
--default ; \
VBoxManage modifyvm "e0b08add-d834-4af5-89e8-05abec11aa78" \
--usbxhci on \
--memory 8 ; \
nasm -l kernel.lst kernel.asm ; \
dd if=/dev/zero of=kernel.raw bs=1024 count=2048 ; \
dd if=kernel of=kernel.raw conv=notrunc ; \
VBoxManage convertfromraw kernel.raw kernel.vdi --format VDI ; \
VBoxManage storageattach "X" \
--storagectl "IDE" \
--port 0 \
--device 0 \
--type hdd \
--medium "$(pwd)"/kernel.vdi ; \
VBoxManage startvm "X"; \
我正在使用Virtualbox 6.1.0
这些是我的操作系统规格,我添加它们是为了以防万一,因为我不知道您是否会觉得它有用:
我真正想知道的是我是否丢失了某些东西(如果有的话,是什么),或者这是虚拟机的实际错误。
[Michael Petch评论:
BIOS中有一个规则,由于DMA(直接内存地址),您绝不能越过64KiB边界。我不知道virtualbox是否强制执行它,但是我可以看到,如果您加载的地址为(0x7e00)+(扇区数*每个扇区的字节数)> 0x10000(0x10000 = 64KiB),可能会出现问题。从理论上讲,尽管那是问题所在,但我希望潜在问题出在> 0x41扇区(0x42 * 512 + 0x7e00)= 0x10200。如果加载从0x1000:0x0000而不是0x0000:0x7e00开始的0x44扇区,它会失败吗?
我更改了汇编代码以将缓冲区地址设置为0x10000,但是该程序仍然无法正常工作。但是,现在的问题有所不同:我没有得到上师的冥想,而是得到了黑屏,什么也没打印。当我加载低至3Fh的扇区时会发生这种情况,但是当我加载3Fh以下的任意数量的扇区时,程序将正确打印'H'字符:
VGA_MEMORY equ 0xB8000
GREEN equ 0x2
RED equ 0x4
org 0x7C00
bits 16
mov ax, VGA_MEMORY >> 4
mov es, ax
mov ax, 0x07E0
mov ss, ax
mov esp, 0xFFF0
mov ax, 0
mov ds, ax
; Disable the annoying cursor
mov ah, 0x01
mov ch, 001_11111b
int 0x10
reset_disk_hdd:
mov ah, 0x00 ; reset function
int 0x13 ; disk int
jc reset_disk_hdd
mov ax, 00h
mov ds, ax
mov si, disk_address_packet
read_disk_hdd:
mov ah, 42h ; read function
int 0x13 ; disk int
jc read_disk_hdd
mov ax, VGA_MEMORY >> 4
mov es, ax
mov ax, 0x1000
mov ds, ax
mov ax, [ds:0x0000]
mov [es:0x00], ax
jmp $
disk_address_packet:
db 10h ; size of DAP (set this to 10h)
db 00h ; unused, should be zero
dw 3Fh ; number of sectors to be read
dd 0x1000_0000 ; segment:offset pointer to the memory buffer to which sectors will be transferred
dq 01h ; absolute number of the start of the sectors to be read
times 510-($-$$) db 0
dw 0xAA55
dw (RED << 4 | GREEN) << 8 | 'H'
为了确保int 13h ah = 42h正常工作,应检查以下各项: