@@ MichaelPetch已经重写了整个问题,以将其简化为一个易于重现的特定问题。最初的问题集中在以64位长模式进行OS开发时遇到的问题。该代码正试图使用8042 PS / 2控制器重新引导计算机,但是尽管它在BOCHS中确实起作用,但它无法在QEMU上工作。原始代码可以在此Github project中找到。
[Michael认为该问题不是特定于长模式的,因此对其进行了实质性的减少,以证明潜在的问题。
为此演示,我是:
此演示的代码如下:
bootloader.asm:
[BITS 32]
section .mboot
mboot_header_start:
dd 0xe85250d6
dd 0
dd mboot_header_end - mboot_header_start
dd 0x100000000 - (0xe85250d6 + 0 +(mboot_header_end - mboot_header_start))
align 8
mboot_inforeq_start:
dw 1
dw 0
dd mboot_inforeq_end - mboot_inforeq_start
dd 2
dd 6
dd 8
mboot_inforeq_end:
align 8
mboot_end_start:
dw 0
dw 0
dd mboot_end_end - mboot_end_start
mboot_end_end:
mboot_header_end:
section .text
global _start
_start:
mov word [0xb8000], (0x5f << 8) | 'B'
mov word [0xb8002], (0x5f << 8) | 'O'
mov word [0xb8004], (0x5f << 8) | 'O'
mov word [0xb8006], (0x5f << 8) | 'T'
; Delay after writing to the screen so it appears for a bit of time before reboot
mov ecx, 0xfffff
delay:
loop delay
; Wait until the 8042 PS/2 Controller is ready to be sent a command
wait_cmd_ready:
in al, 0x64
test al, 00000010b
jne wait_cmd_ready
; Use 8042 PS/2 Controller to reboot the machine
mov al, 0xfe
out 0x64, al
; If this is displayed the reboot wasn't successful. Shouldn't get this far
mov word [0xb8000+160], (0x5f << 8) | 'N'
mov word [0xb8002+160], (0x5f << 8) | 'O'
mov word [0xb8004+160], (0x5f << 8) | 'R'
mov word [0xb8006+160], (0x5f << 8) | 'E'
mov word [0xb8006+160], (0x5f << 8) | 'B'
; Infinite loop to end
hltloop:
hlt
jmp hltloop
link.ld:
ENTRY(_start);
kern_vma = 0x100000;
SECTIONS
{
. = 0x500;
.boot :
{
*(*.mboot*)
}
. = kern_vma;
.text ALIGN(4K) :
{
*(*.text*)
}
.bss ALIGN(4K) :
{
*(.bss)
}
}
我的Linux构建脚本是:
#!/bin/sh
ISO_DIR="isodir"
ISO_NAME="myos"
GRUB_CFG="grub.cfg"
KERNEL_NAME="bootloader"
nasm -f elf32 bootloader.asm -o bootloader.o
ld -m elf_i386 -T link.ld bootloader.o -o $KERNEL_NAME.elf
mkdir -p $ISO_DIR/boot/grub
cp $KERNEL_NAME.elf $ISO_DIR/boot/
echo 'set timeout=2' > $ISO_DIR/boot/grub/$GRUB_CFG
echo 'set default=0' >> $ISO_DIR/boot/grub/$GRUB_CFG
echo 'menuentry "My Kernel" {' >> $ISO_DIR/boot/grub/$GRUB_CFG
echo ' multiboot2 /boot/'$KERNEL_NAME'.elf' >> $ISO_DIR/boot/grub/$GRUB_CFG
echo '}' >> $ISO_DIR/boot/grub/$GRUB_CFG
# build iso image
grub-mkrescue -o $ISO_NAME.iso $ISO_DIR/
问题
当我运行构建脚本并使用命令运行它时:
qemu-system-i386 -cdrom myos.iso
运行GRUB引导内核时,BOOT
在窗口左上角的洋红色属性上正确显示为白色。它应该短暂地等待,然后重新启动机器负载GRUB并重复该循环。
它没有完成预期的操作。它按原样显示BOOT
,但QEMU似乎坐着,什么也不做,这不是我期望的。
如果我使用附加选项-d int
运行QEMU,我发现计算机似乎处于永久循环,其中包括断点异常(v = 03)或无效的操作码异常(v = 06),这是一般性保护错误( v = 0d),并以双重故障(v = 08)结束。输出通常看起来像:
0: v=06 e=0000 i=0 cpl=0 IP=0008:000f0000 pc=000f0000 SP=0010:00000fc0 env->regs[R_EAX]=00000000 EAX=00000000 EBX=00000000 ECX=00000010 EDX=000f171d ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000fc0 EIP=000f0000 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0 ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA] CS =0008 00000000 ffffffff 00cf9b00 DPL=0 CS32 [-RA] SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA] DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA] FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA] GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA] LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy GDT= 000f6080 00000037 IDT= 000f60be 00000000 CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000 DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 DR6=ffff0ff0 DR7=00000400 CCS=00000000 CCD=0000007f CCO=ADDB EFER=0000000000000000 check_exception old: 0xffffffff new 0xd 1: v=0d e=0032 i=0 cpl=0 IP=0008:000f0000 pc=000f0000 SP=0010:00000fc0 env->regs[R_EAX]=0000 0000 EAX=00000000 EBX=00000000 ECX=00000010 EDX=000f171d ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000fc0 EIP=000f0000 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0 ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA] CS =0008 00000000 ffffffff 00cf9b00 DPL=0 CS32 [-RA] SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA] DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA] FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA] GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA] LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy GDT= 000f6080 00000037 IDT= 000f60be 00000000 CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000 DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 DR6=ffff0ff0 DR7=00000400 CCS=00000000 CCD=0000007f CCO=ADDB EFER=0000000000000000 check_exception old: 0xd new 0xd 2: v=08 e=0000 i=0 cpl=0 IP=0008:000f0000 pc=000f0000 SP=0010:00000fc0 env->regs[R_EAX]=0000 0000 EAX=00000000 EBX=00000000 ECX=00000010 EDX=000f171d ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000fc0 EIP=000f0000 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0 ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA] CS =0008 00000000 ffffffff 00cf9b00 DPL=0 CS32 [-RA] SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA] DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA] FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA] GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA] LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy GDT= 000f6080 00000037 IDT= 000f60be 00000000 CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000 DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 DR6=ffff0ff0 DR7=00000400 CCS=00000000 CCD=0000007f CCO=ADDB EFER=0000000000000000 check_exception old: 0x8 new 0xd check_exception old: 0xffffffff new 0x6
它会不断重复类似的模式。不寻常的是它似乎陷入了这种例外循环:
0: v=06 e=0000 i=0 cpl=0 IP=0008:000f0000 pc=000f0000 SP=0010:00000fc0 env->regs[R_EAX]=00000000 1: v=0d e=0032 i=0 cpl=0 IP=0008:000f0000 pc=000f0000 SP=0010:00000fc0 env->regs[R_EAX]=0000 2: v=08 e=0000 i=0 cpl=0 IP=0008:000f0000 pc=000f0000 SP=0010:00000fc0 env->regs[R_EAX]=0000
导致此问题的原因以及如何解决此问题,以便QEMU可以正确地重新启动并再次启动GRUB?
原始OS代码需要付出努力才能确定此问题的根本原因。该示例使人们更容易发现罪魁祸首。在原始代码中找到此问题需要花费一些精力。