我一直在研究引导加载程序,目前正试图让它切换到长模式。到目前为止我已经切换到保护模式,我确信它有效,但似乎当我启用分页进入长模式时会导致故障。我想这可能是因为我的页面表。这是代码:
[BITS 16]
org 0x2000
Start:
jmp main
;Constants
%DEFINE TEAL 0x03
%DEFINE RED 0x04
%DEFINE PURPLE 0x05
%DEFINE VIDEO_MEM 0xB8000
%DEFINE COLS 80 ; width and height of screen
%DEFINE LINES 25
%DEFINE LONG_SELECTOR 3 << 3
X_POS: db 0
Y_POS: db 0
;Enabling the A20 line
EnableA20:
IN AL, 0x92 ; A20, using fast A20 gate
MOV CL, AL
AND CL, 2
JNZ .skip ; if a20 bit seems set, don't touch it
OR AL, 2
OUT 0x92, AL
.skip:
ret
main:
;first stage of bootloader is loaded at the address 0x07c0:0
;second stage of bootloader is loaded at address 0x200:0x0
cli
xor ax, ax ; All segments set to 0, flat memory model
mov ds, ax
mov es, ax
mov gs, ax
mov fs, ax
mov ss, ax
; Set stack top SS:0xffff
mov sp, 0x0FFFF
mov [CDDriveNumber], dl
SwitchToProtectedMode:
lgdt [GDT_32];load the gdt
call EnableA20
mov eax, cr0
or eax, 1
mov cr0, eax
; Flush CS and set code selector
jmp 0x8:Protected_Mode
[BITS 32];Declare 32 bits
Protected_Mode:
mov eax,0x10 ; load 4 GB data descriptor
mov ds,ax ; to all data segment registers
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
mov eax,cr4
or eax,1 << 5
mov cr4,eax ; enable physical-address extensions
mov edi,70000h
mov ecx,4000h >> 2
xor eax,eax
rep stosd ; clear the page tables
mov dword [70000h],71000h + 111b ; first PDP table
mov dword [71000h],72000h + 111b ; first page directory
mov dword [72000h],73000h + 111b ; first page table
mov edi,73000h ; address of first page table
mov eax,0 + 111b
mov ecx,256 ; number of pages to map (1 MB)
make_page_entries:
stosd
add edi,4
add eax,1000h
loop make_page_entries
mov eax,70000h
mov cr3,eax ; load page-map level-4 base
mov ecx,0C0000080h ; EFER MSR
rdmsr
or eax,1 << 8 ; enable long mode
wrmsr
lgdt[GDT_64]
mov eax,cr0 ; << problem here
or eax,1 << 31
mov cr0,eax ; enable paging
jmp 0x08:Long_Mode
[BITS 64]
Long_Mode:
call clear
xor bx, bx
mov bx, Entered_LMODE
call sPrint
cli
hlt
[BITS 32]
clear:
pusha
mov edi, VIDEO_MEM
mov BYTE[edi], ' '
mov BYTE[edi+1], TEAL
rep stosw
MOV BYTE[X_POS], 0x0
MOV BYTE [Y_POS], 0x0
popa
ret
sPrint:
pusha
jmp .start
.Row:
call NewLine
MOV BYTE[EDI], ' '
jmp .Next
.start:
MOV EDI, VIDEO_MEM
xor ecx, ecx
xor eax, eax
mov ecx, COLS*2 ; Mode 7 has 2 bytes per char, so its COLS*2 bytes per line
mov al, BYTE [Y_POS] ; get y pos
mul ecx ; multiply y*COLS
push eax ; save eax--the multiplication
mov al, byte [X_POS] ; multiply _CurX by 2 because it is 2 bytes per char
mov cl, 2
mul cl
pop ecx ; pop y*COLS result
add eax, ecx
add edi, eax
mov al,BYTE[bx]
cmp al, 0x0;check if end
je .Done
cmp al, 0xA;check if new line
je .Row
mov BYTE[edi],al
.Next:
mov BYTE[edi+1], PURPLE
INC BX
inc BYTE[X_POS] ; go to next character
cmp BYTE[X_POS], COLS ; are we at the end of the line?
je .Row ; yep-go to next row
jmp .start
.Done:
popa
ret
NewLine:
inc BYTE[Y_POS]
MOV BYTE[X_POS], -1
ret
Entered_PMODE: db "You have succcessfully entered Protected Mode Very Happy",0xA, 0
LOAD_SUCCESS: db "Stage 2 Loaded Successfully",0xA, 0
CDDriveNumber: db 0
Entered_LMODE: db "You have successfully entered Long Mode Very Happy !!!!!!!!!!!",0xA,0
GDT_START:
;null descriptor
dd 0
dd 0
;data descriptor
dw 0xFFFF
dw 0
db 0
db 10011010b
db 11001111b
db 0
;code descriptor
dw 0xFFFF
dw 0
db 0
db 10010010b
db 11001111b
db 0
GDT_END:
align 4
GDT_32:
dw GDT_END - GDT_START - 1
dd GDT_START
GDT_64:
.Null:
dq 0x0000000000000000 ; Null Descriptor - should be present.
.Code_64:
dq 0x0020980000000000 ; 64-bit code descriptor.
dq 0x0000900000000000 ; 64-bit data descriptor.
.Pointer:
dw $ - GDT_64 - 1 ; 16-bit Size (Limit) of GDT.
dd GDT_64 ; 32-bit Base Address of GDT. (CPU will zero extend to 64-bit)
ALIGN 4
IDT:
.Length dw 0
.Base dd 0
PML4_POINTER:;blank table
dd 0
PML4_POINTER_END:
table_768: dd 0
答案 0 :(得分:2)
您需要使用lgdt [GDT_64.Pointer]
。此外,您无法使用64位代码中的clear
和sPrint
。