简体   繁体   English

我无法将CPU从实模式切换到保护模式

[英]I failed in switching the cpu from real-mode to protected-mode

I do this according a book by Nick Blundell. 我是根据Nick Blundell的书来做的。 I write a MBR program, which runs in real-mode firstly, and some instructions in the program will switch the cpu to protected-mode. 我编写了一个MBR程序,该程序首先在实模式下运行,该程序中的某些指令会将CPU切换到保护模式。 First I set the GDT like this: 首先,我将GDT设置如下:

gdt_start:

gdt_null:
    dd 0x0
    dd 0x0

gdt_code:
    dw 0xffff
    dw 0x0
    db 10011010b
    db 11001111b
    db 0x0

gdt_data:
    dw 0xffff
    dw 0x0
    db 0x0
    db 10010010b
    db 11001111b
    db 0x0

gdt_end:

gdt_descriptor :
    dw gdt_end - gdt_start - 1
    dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start

Then the cpu runs the following instructions: 然后,CPU运行以下指令:

   cli

    lgdt [gdt_descriptor]
    mov eax,cr0
    or eax,0x1
    mov cr0,eax ;this will set the cpu to protected-mode        

;jmp $  ;I use this instrction to find where is wrong
    jmp CODE_SEG:init_pm

jmp $
[bits 32]
init_pm:
jmp $
    mov ax,10
jmp $
    mov ds,eax
    mov ss,eax
jmp $
    mov es,ax
    mov fs,ax
    mov gs,ax
    mov ebp,0x90000
    mov esp,ebp
    call BEGIN_PM

The instruction jmp CODE_SEG:init_pm will cause the cpu to crash and restart. 指令jmp CODE_SEG:init_pm将导致CPU崩溃并重新启动。 If I change this to jmp init_pm , the following instruction mov ax,10 will cause the cpu to crash and restart. 如果将其更改为jmp init_pm ,则以下指令mov ax,10将导致CPU崩溃并重新启动。 And the book said the switching operation needs a long jump. 书中说开关操作需要跳远。

Could you please help me do the switching operation? 您能帮我进行切换操作吗?

In your gdt_descriptor , you've got the limit and the address. 在您的gdt_descriptor ,您有限制和地址。 Unlike most other addresses, this is NOT a segment:offset address. 与大多数其他地址不同,这不是segment:offset地址。 It needs to be a linear address. 它必须是一个线性地址。 As an MBR, you've probably moved it from where it was originally loaded at 0x7C00. 作为MBR,您可能已将其从最初加载0x7C00的位置移走了。 The address in your gdt_descriptor (often called gdtr ) needs to be the linear address of where you are now. gdt_descriptor的地址(通常称为gdtr )必须是您现在所在位置的线性地址。 You don't show quite enough code to be sure, but I suspect your problem is right in there. 您不确定要显示的代码不够多,但是我怀疑您的问题就在那里。

There are several problems in your code: 您的代码中存在几个问题:

  1. You're missing lower byte of base´s high word in your gdt_code descriptor. 您在gdt_code描述符中缺少基数高位字的低字节。 Simply add db 0x0 after dw 0x0 . 只需在dw 0x0之后添加db 0x0 dw 0x0
  2. Frank Kotler wrote that gdt_descriptor must contain linear address. 弗兰克·科特勒(Frank Kotler)写道gdt_descriptor必须包含线性地址。 Yes, that's true, but it's not the only place where linear address is required. 是的,的确如此,但这并不是唯一需要线性地址的地方。 You can use ORG directive before any code, or manually add origin to this field. 您可以在任何代码之前使用ORG指令,也可以手动将原点添加到此字段。
  3. Instruction lgdt still uses ds register for seg:off address calculation. 指令lgdt仍使用ds寄存器进行seg:off地址计算。 You should have it set to zero when writing code under org . org下编写代码时,应将其设置为零。
  4. Far jump to the protected mode also needs linear address used as offset. 远跳到保护模式还需要将线性地址用作偏移量。 Remember that this jump is executed in compatibility mode (as it's the first instruction executed after protected mode switch). 请记住,此跳转是在兼容模式下执行的(因为它是在保护模式切换后执行的第一条指令)。 It uses two bytes for segment selector (before colon) and only two bytes for offset (after colon). 它使用两个字节作为段选择器(在冒号之前), 仅使用两个字节作为偏移量(在冒号之后)。 That means you shouldn't try to jump to address higher than 0xFFFF . 这意味着您不应该尝试跳转到高于0xFFFF地址。 Again, check origin of your code. 再次,检查代码的来源。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM