gpt4 book ai didi

x86 - 为实模式设置分页到 64 位长模式切换

转载 作者:行者123 更新时间:2023-12-04 03:15:50 24 4
gpt4 key购买 nike

我正在尝试使用 NASM 编写引导加载程序,结果我发现 OSDEV 非常有用。然而,在设置分页、加载我的 GDT 或转换(我直接来自实模式)过程中的某处,出现导致机器重新启动的错误。我的代码基于 Long mode OSDEV article .这就是我所拥有的对问题很重要的内容:

广东话

gdt_start:

.gdt_null: equ $-gdt_start ; mandatory null descriptor
dw 0
dw 0
db 0 ; define double word
db 0
db 0
db 0

.gdt_code: equ $-gdt_start ; code segment
; base = 0x0, limif = 0xffff
; 1st flags: (present)1 (privilege)00 (descriptor type)1 -> 1001
; type flags: (code)1 (conforming)0 (readable)1 (accessed)0 -> 1010
; 2nd flags: (granularity)1 (32 bit default)1 (64 bit seg)0 (AVL)0 -> 1100
dw 0 ; limit (0-15)
dw 0 ; base (0-15)
db 0 ; base (16-23)
db 10011010b ; 1st/type flags
db 00100000b ; 2nd flags, limit (16-19)
db 0 ; base (bits 24-31)

.gdt_data: equ $-gdt_start ; data segment descriptor
; type flags (code)0 (expand down)0 (writable)1 (accessed)0 -> 0010
dw 0 ; limit
dw 0 ; base
db 0 ; base
db 10010010b ; 1st/type flags
db 00000000b ; 2nd flags, limit
db 0 ; base

gdt_end:

gdt_descriptor:
dw gdt_end - gdt_start - 1 ; size of GDT

dq gdt_start

CODE_SEG equ gdt_start.gdt_code
DATA_SEG equ gdt_start.gdt_data

分页和切换:

%include "gdt.ns"

;test/enable A20 line
call test_a20
fin:

cmp ax, 1
je enabled

call enable_A20

enabled:

;switch
call switch_to_lm
jmp $

switch_to_lm:
;
; SET UP PAGING!!!!!
;

;no previous paging defined so the below code is unnecessary
;mov eax, cr0
;and eax, 01111111111111111111111111111111b
;mov cr0, eax

;clear tables
mov edi, 0x1000
mov cr3, edi
xor eax, eax
mov ecx, 4096
rep stosd
mov edi, cr3

;set up new tables
mov DWORD [edi], 0x2003
add edi, 0x1000
mov DWORD [edi], 0x3003
add edi, 0x1000
mov DWORD [edi], 0x4003
add edi, 0x1000

mov ebx, 0x00000003
mov ecx, 512

.setEntry:
mov DWORD [edi], ebx
add ebx, 0x1000
add edi, 8
loop .setEntry

;enable PAE bit in CR4
mov eax, cr4
or eax, 1<<5
mov cr4, eax

;switch from REAL MODE
;set long mode bit
mov ecx, 0xc0000080
rdmsr
or eax, 1<<8
wrmsr

;enable paging
mov eax, cr0
or eax, 1<<31
mov cr0, eax

lgdt [gdt_descriptor]
jmp CODE_SEG:init_lm

[bits 64]

init_lm:

cli
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax

mov ebp, 0x90000
mov esp, ebp

call BEGIN_LM

我的 A20 测试代码:

test_a20:
pushf
push ds
push es
push di
push si

cli

xor ax, ax
mov es, ax

not ax
mov ds, ax

mov di, 0x0500
mov si, 0x0510

mov al, byte [es:di]
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

mov ax, 0
je test_exit

mov ax, 1

test_exit:
pop si
pop di
pop es
pop ds
popf

jmp fin

最佳答案

在您的代码中,test_a20 函数有问题。特别是你有这段代码:

mov al, byte [es:di]
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

您似乎将 AX 的一个值压入堆栈,然后弹出 2 个值。这会弄乱堆栈,寄存器将被错误地恢复,包括 DS 和标志。看来您可能一直在尝试通过不使用 ret 返回来规避此错误。相反,您使用 jmp fin 跳转到 call test_a20 指令之后的某个点。

看来您正在尝试使用 A20 test code from OSDEV Wiki .您会注意到您缺少这些行:

mov al, byte [ds:si]
push ax

如果您修改 test_a20 函数以添加缺失的行并使用 ret,它应该如下所示:

test_a20:
pushf
push ds
push es
push di
push si

cli

xor ax, ax
mov es, ax

not ax
mov ds, ax

mov di, 0x0500
mov si, 0x0510

mov al, byte [es:di]
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

mov ax, 0
je test_exit

mov ax, 1

test_exit:
pop si
pop di
pop es
pop ds
popf
ret

此更改应解决 DS 寄存器被破坏以及页面写入代码中的后续内存访问无法正常工作的问题。您还必须修改页面启用代码以启用保护模式。这段代码:

;enable paging
mov eax, cr0
or eax, 1<<31
mov cr0, eax

应该是:

;enable paging
mov eax, cr0
or eax, (1<<31) | (1<<0)
mov cr0, eax

通过这些更改,您应该能够进入 64 位长模式。

关于x86 - 为实模式设置分页到 64 位长模式切换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41085245/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com