问题描述
我一直在开发Bootloader,当我尝试用LGDT指令加载GDT时,它会引发一般保护错误,我不确定如何处理。
bootloader / gdt.asm
gdt_start: ; don't remove the labels,they're needed to compute sizes and jumps
gdt_null:
dq 0
; GDT for code segment. base = 0x00000000,length = 0xfffff
gdt_code:
dw 0xffff ; segment length,bits 0-15
dw 0x0 ; segment base,bits 0-15
db 0x0 ; segment base,bits 16-23
db 10011010b ; flags (8 bits)
db 11001111b ; flags (4 bits) + segment length,bits 16-19
db 0x0 ; segment base,bits 24-31
; GDT for data segment. base and length identical to code segment
gdt_data:
dw 0xffff
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
; GDT descriptor
gdt_descriptor:
dw gdt_end - gdt_start - 1 ; size (16 bit),always one less of its true size
dd gdt_start ; address (32 bit)
; define some constants for later use
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
[bits 16]
switch_to_pm:
cli
lgdt [gdt_descriptor] ; THIS is where the general protection fault occours
mov eax,0xff
mov [0xa006],eax
mov eax,cr0
or eax,0x1 ; 3. set 32-bit mode bit in cr0
mov cr0,eax
jmp CODE_SEG:init_pm ; 4. far jump by using a different segment
; somehow forgot to copy this in
[bits 32]
init_pm: ; we are now using 32-bit instructions
mov ax,DATA_SEG ; 5. update the segment registers
mov ds,ax
mov ss,ax
mov es,ax
mov fs,ax
mov gs,ax
mov eax,0xee
mov [0xa000],eax
mov ebp,0x90000 ; 6. update the stack right at the top of the free space
mov esp,ebp
call ready ; 7. Call a well-known label with useful code
bootloader.asm
[BITS 16]
[ORG 0x7c00]
jmp 0:start
%include "bootloader/gdt.asm"
[BITS 16]
start:
; setup video mode
mov ah,00h
mov al,13h
int 10h
mov dx,0
call print_dbg_x
; LOAD the system
mov ah,02h
mov al,20
mov ch,0
mov cl,02h
mov dh,0
mov dl,0
mov ebx,PROGRAM
int 13h
call print_dbg_x
; next setup the gdt
call print_dbg_x
cli
mov ax,0x2401
int 0x15 ; enable A20 bit
call switch_to_pm
load_kern_err:
mov ah,0Ch
mov al,0xC
xor bh,bh
inc cx
int 10h
hlt
print_dbg_x:
mov ah,0xF
xor bh,bh
inc cx
int 10h
ret
[BITS 32]
ready:
mov eax,0xff
mov [0xa000],eax
mov esp,090000h
mov ax,DATA_SEG
mov ds,ax
mov ebp,0x90000
mov esp,ebp
call PROGRAM
jmp $
PROGRAM equ 0x1000
times 510 - ($ - $$) db 0
dw 0AA55h
switch_to_pm
在需要加载GDT并切换到pmode时由引导加载程序跳转到。在此之前,它从FDD加载内核并将其放入地址0x1000
中。我还没有加载IDT,因为pmode的内核可以。
我使用nasm,它被编译成二进制文件(它包含在主引导程序中)。
Bochs在重启之前将其报告为异常,可能是#GPF的来源
(0).[14992474] [0x000000007c40] 0000:0000000000007c40 (unk. ctxt): jmpf 0x0008:7c45 ; ea457c0800
显然,CPU进入了保护模式,因此jumpf出了点问题。
00014992474i[CPU0 ] CPU is in protected mode (active)
00014992474i[CPU0 ] CS.mode = 16 bit
00014992474i[CPU0 ] SS.mode = 16 bit
00014992474i[CPU0 ] EFER = 0x00000000
00014992474i[CPU0 ] | EAX=60000011 EBX=00000000 ECX=00090004 EDX=00000000
00014992474i[CPU0 ] | ESP=0000ffd4 EBP=00000000 ESI=000e0000 EDI=0000ffac
00014992474i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00014992474i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00014992474i[CPU0 ] | CS:0000( 0004| 0| 0) 00000000 0000ffff 0 0
00014992474i[CPU0 ] | DS:0010( 0005| 0| 0) 00000100 0000ffff 0 0
00014992474i[CPU0 ] | SS:0010( 0005| 0| 0) 00000100 0000ffff 0 0
00014992474i[CPU0 ] | ES:0010( 0005| 0| 0) 00000100 0000ffff 0 0
00014992474i[CPU0 ] | FS:0010( 0005| 0| 0) 00000100 0000ffff 0 0
00014992474i[CPU0 ] | GS:0010( 0005| 0| 0) 00000100 0000ffff 0 0
00014992474i[CPU0 ] | EIP=00007c40 (00007c40)
00014992474i[CPU0 ] | CR0=0x60000011 CR2=0x00000000
00014992474i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
这是引导程序将从第二个扇区加载的代码,内核是在编译时与此代码链接的C外部代码。
kentry.asm
[BITS 32]
global _start
_start:
mov ebp,ebp
extern kernel
call kernel
ret
global idt_load
extern idtp
idt_load:
lidt [idtp]
ret
我先编译引导程序,然后编译内核,然后将代码放在一起,然后再用cat将引导程序放在内核中的二进制文件中。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)