0

所以今天我正在创建另一个引导加载程序,并认为如果我能够使用 64 位处理器的功能会很好。一切似乎都运行良好,直到我的 bochs 由于页面错误而开始重新启动。

注意:部分代码是从 osdev 和其他一些 osdev 教程中复制的,因为我希望首先能够拥有工作代码,然后分析它是如何工作的,然后自己重​​写它。

正如维基百科所说:

页面错误发生在正在运行的程序访问映射到虚拟地址空间但未实际加载到主内存中的内存页面时。

不幸的是,我无法理解这是什么意思。

这是代码:

org 0x7C00
bits 16

xor ax,ax
mov ds,ax
mov es,ax

mov bx,0x8000
cli
mov ss,bx
mov sp,ax
sti

cld
clc

;bootloader
;plan for bootloader
;change graphics to 0x0118
;enable A20
;goto 32 bit protected mode
;goto 64 bit long mode

;set 118h VESA graphics mode
mov ax,0x4f02
mov bx,118h
int 0x10

;load 64 bit code

mov ah,0x2
mov al,0x1
mov ch,0x0
mov cl,0x2
mov dh,0x0
mov bx,0x0000
mov es,bx
mov bx,0x7E00
int 0x13

;enable A20
call check_a20
jc code
mov ax,0x2401
int 0x15
call check_a20
jc code
in al,0x92
or al,0x2
out 0x92, al
call check_a20
jnc error

code: ;label for compiler

;at this point A20 should be enabled

;going into 32 bit mode
cli
pusha
lgdt [toc]
popa

mov eax, cr0
or eax, 1
mov cr0, eax

jmp 0x8:code32

jmp error

bits 32

code32:

mov ax,0x010
mov ds,ax
mov ss,ax
mov es,ax

;detect is long mode supported
;to detect long mode support you need to detect CPUID support



;check extended functions
mov eax, 0x80000000    ; Set the A-register to 0x80000000.
cpuid                  ; CPU identification.
cmp eax, 0x80000001    ; Compare the A-register with 0x80000001.
jb error32               ; It is less, there is no long mode.

;to go to long mode you need
;disable paging
;set PAE enable in CR4
;load CR3 with physical address of the PML4
;enable long mode by settings EFER.LME flag in MSR 0xC0000080
;enable paging

;setup paging

mov eax, cr0                                   ; Set the A-register to control register 0.
and eax, 01111111111111111111111111111111b     ; Clear the PG-bit, which is bit 31.
mov cr0, eax                                   ; Set control register 0 to the A-register.

;clear tables
mov edi, 0x1000    ; Set the destination index to 0x1000.
mov cr3, edi       ; Set control register 3 to the destination index.
xor eax, eax       ; Nullify the A-register.
mov ecx, 4096      ; Set the C-register to 4096.
rep stosd          ; Clear the memory.
mov edi, cr3       ; Set the destination index to control register 3.

;setup tables
mov DWORD [edi], 0x2003      ; Set the uint32_t at the destination index to 0x2003.
add edi, 0x1000              ; Add 0x1000 to the destination index.
mov DWORD [edi], 0x3003      ; Set the uint32_t at the destination index to 0x3003.
add edi, 0x1000              ; Add 0x1000 to the destination index.
mov DWORD [edi], 0x4003      ; Set the uint32_t at the destination index to 0x4003.
add edi, 0x1000              ; Add 0x1000 to the destination index.

mov ebx, 0x00000003          ; Set the B-register to 0x00000003.
mov ecx, 512                 ; Set the C-register to 512.

SetEntry:
    mov DWORD [edi], ebx         ; Set the uint32_t at the destination index to the B-register.
    add ebx, 0x1000              ; Add 0x1000 to the B-register.
    add edi, 8                   ; Add eight to the destination index.
    loop SetEntry               ; Set the next entry.


;enable PAE
mov eax, cr4                 ; Set the A-register to control register 4.
or eax, 1 << 5               ; Set the PAE-bit, which is the 6th bit (bit 5).
mov cr4, eax                 ; Set control register 4 to the A-register.

;switch to Long Mode

mov ecx, 0xC0000080          ; Set the C-register to 0xC0000080, which is the EFER MSR.
rdmsr                        ; Read from the model-specific register.
or eax, 1 << 8               ; Set the LM-bit which is the 9th bit (bit 8).
wrmsr                        ; Write to the model-specific register.


;enable paging

mov eax, cr0                 ; Set the A-register to control register 0.
or eax, 1 << 31              ; Set the PG-bit, which is the 32nd bit (bit 31).
mov cr0, eax                 ; Set control register 0 to the A-register.


;setup GDT again
lgdt [GDT64.Pointer]
jmp 0x08:0x7E00

error32:
    cli
    hlt

bits 16

error:
    cli
    hlt

check_a20:
    cli
    push ds
    xor ax,ax
    mov es,ax
    not ax
    mov ds,ax
    mov di,0x0500
    mov si,0x0510
    ;mov al, byte [es:di]  ;read beyond limit
    push ax
    mov al, byte [ds:si]
    push ax
    mov byte [es:di], 0x00
    mov byte [ds:si], 0xFF
    cmp byte [es:di], 0xFF
    pop ax
    mov byte[ds:si],al
    pop ax
    mov byte [es:di],al
    pop ds
    sti
    clc ;disabled   carry flag = 0
    je .exit
    stc ;enabled    carry flag = 1
    .exit:
        ret


;data

;Global Descriptor Table
gdt_data: 
    dd 0                ; null descriptor
    dd 0 

; gdt code:             ; code descriptor
    dw 0FFFFh           ; limit low
    dw 0                ; base low
    db 0                ; base middle
    db 10011010b            ; access
    db 11001111b            ; granularity
    db 0                ; base high

; gdt data:             ; data descriptor
    dw 0FFFFh           ; limit low (Same as code)
    dw 0                ; base low
    db 0                ; base middle
    db 10010010b            ; access
    db 11001111b            ; granularity
    db 0                ; base high

end_of_gdt:
toc: 
    dw end_of_gdt - gdt_data - 1    ; limit (Size of GDT)
    dd gdt_data             ; base of GDT

GDT64:                           ; Global Descriptor Table (64-bit).
    .Null: equ $ - GDT64         ; The null descriptor.
    dw 0                         ; Limit (low).
    dw 0                         ; Base (low).
    db 0                         ; Base (middle)
    db 0                         ; Access.
    db 0                         ; Granularity.
    db 0                         ; Base (high).
    .Code: equ $ - GDT64         ; The code descriptor.
    dw 0                         ; Limit (low).
    dw 0                         ; Base (low).
    db 0                         ; Base (middle)
    db 10011010b                 ; Access (exec/read).
    db 00100000b                 ; Granularity.
    db 0                         ; Base (high).
    .Data: equ $ - GDT64         ; The data descriptor.
    dw 0                         ; Limit (low).
    dw 0                         ; Base (low).
    db 0                         ; Base (middle)
    db 10010010b                 ; Access (read/write).
    db 00000000b                 ; Granularity.
    db 0                         ; Base (high).
    .Pointer:                    ; The GDT-pointer.
    dw $ - GDT64 - 1             ; Limit.
    dq GDT64                     ; Base.

times 0x1FE - ($ - $$) db 0x00
db 0x55
db 0xAA

;already 64 bit data

bits 64

mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax

;new colour 0x72, 0xDC, 0xEF
;0x0118 mode starts at 0xA0000
mov EAX, 0x72DCEF00
mov DI, 0xA0000
mov ECX, 0x100000
fill:
    stosd
    dec DI
    loop fill

cli
hlt

times 0x400 - ($ - $$) db 0x00

当我尝试用颜色 rgb(114, 220, 239) 填充我的屏幕时发生页面错误,这里是:

;new colour 0x72, 0xDC, 0xEF
;0x0118 mode starts at 0xA0000
mov EAX, 0x72DCEF00
mov DI, 0xA0000
mov ECX, 0x100000
fill:
    stosd
    dec DI
    loop fill

我知道这听起来可能很愚蠢,但我能做些什么来解决这个问题?

另请注意,我以前从未使用过长模式

4

0 回答 0