与GDT保护模式汇编转移 [英] Assembler jump in Protected Mode with GDT

查看:265
本文介绍了与GDT保护模式汇编转移的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在玩弄的x86汇编程序,以增强我的低级编程技能。目前,我面临的一个小问题,在32位保护模式寻址方案。

情况如下:

我在0x7e0加载的程序该CPU切换到保护模式,并跳转到在code中的标签按:

  [...]
code切换CPU在保护模式
[...]JMP ProtectedMode
[...]32位ProtectedMode:
    。停:
        HLT
        JMP .halt

这工作绝对没那么远。在JMP ProtectedMode作品没有一个明确的远跳转到清除prefetch队列 - 因为这个程序被加载与偏移0(开头组织0) - 导致code段指向正确的位置

我现在的现在的问题是,认为ProtectedMode标签内我要跳到这是在为0x8000加载的其他程序(我查这跟内存转储,装载功能没有工作正常,程序正确地装入为0x8000)。

由于CPU现在处于ProtectedMode并且不再实模式,寻址模式是不同的。 ProtectedMode使用描述符中选择一个描述符表中添加指定的偏移量和检索的物理地址来查找基地址和限制(我的理解)。因此,有必要在进入ProtectedMode之前安装GDT。

煤矿正在寻找这样的:

 %IFNDEF __GDT_INC_INCLUDED__
%定义__GDT_INC_INCLUDED__; **********
*全局描述符表(GDT)*
; **********
NULL_DESC:
    DD 0;空描述符
    DD 0code_DESC:
    DW 0xFFFF的;低限
    DW 0;底座低
    DB 0;中间基地
    DB 10011010b;访问
    DB 11001111b;粒度
    DB 0;基地高DATA_DESC:
    DW 0xFFFF的;数据描述符
    DW 0;低限
    DB 0;底座低
    DB 10010010b;访问
    DB 11001111b;粒度
    DB 0;基地高GDTR:
    限制DW 24; GDT的长度
    基地DD​​ NULL_DESC; GDT的基地%ENDIF; __ GDT_INC_INCLUDED__

并通过

加载到GDT注册

  LGDT [GDTR]

我不明白到目前为止,我怎么现在跳转到物理地址为0x8000在使用GDT ProtectedMode?

我的第一个想法是选择code描述符(code_DESC),这应该指向0x7e00(被当前程序被加载),并使用偏移量是必要得到为0x8000(512字节)导致跳转指令:

  JMP code_DESC:为0x200

但是,这并不正常工作。

  JMP 0x7e0:为0x200

不工作要么...

你有任何想法,我在这里丢失?也许我不明白的东西32位ProtectedMode解决方案和GDT的使用中是必不可少的。

完成code:

  16位
组织0;装载偏移0000(物理地址:0x7e00)JMP启动开始:
    异斧,斧
    MOV AX,CS
    MOV DS,AX;更新数据段    CLI;清除中断    LGDT [GDTR]从GDTR(见gdt_32.inc)加载GDT    调用OpenA20Gate;打开A20门    调用EnablePMode;跳转到ProtectedMode; ******************
*打开A20门*
; ******************
OpenA20Gate:
    在人,0x93;通过快速A20端口92开关门A20    或人,2;设置A20门位1
    和人〜1;明确INIT_NOW位
    出0x92,人    RET; ************
; *启用保护模式*
; ************
EnablePMode:
    MOV EAX,CR0
    或EAX,1
    MOV CRO,EAX    JMP ProtectedMode;这个工程(将跳转到标号并中止)
    ; JMP(code_DESC-NULL_DESC):ProtectedMode; = GT;不工作
    ; JMP 08H:ProtectedMode,= GT;不工作; ***************
*数据字段*
*放大器;包括*
; ***************
%包括gdt_32.inc; ******************
*保护模式*
; ******************
32位ProtectedMode:
    ;在这里我要跳转到物理地址为0x8000(ELF64汇编程序)    。停:
        HLT
        JMP .halt


解决方案

有在code多个问题。

首先,你的 GDTR.Base 包含来自code开头的偏移量 GDT 的因为你的code编译开始在地址0(因为 0组织)。基地址必须是物理地址,而不是相对地址。 IOW,如果你把这个组织0 ,您必须添加 CS * 16(= 0x7e00)为基本

其次,由于同样的组织0 ,在code(32位偏移后位32 ProtectedMode:)不等于它们对应的物理地址,它们比物理地址0x7e00少。 OTOH,在GDT定义的段在物理地址0开始(因为在GDT条目的基部是0),而不是在0x7e00。这意味着,当您尝试使用这些领域与code /数据,你会出现在0x7e00缺少的地址。如果你想保持 0组织,在GDT基地址必须设置为0x7e00。

你也可以 0组织更改为组织0x7e00 然后在GDT的基地应该是0和你不会需要通过0x7e00调整GDTR.Base,0就行了。

这应该工作:

  16位
组织0x7e00;在加载物理地址0x7e00
                            ;控制必须用JMP 0传送:0x7e00    异斧,斧
    MOV DS,AX;更新数据段    CLI;清除中断    LGDT [GDTR]从GDTR(见gdt_32.inc)加载GDT    调用OpenA20Gate;打开A20门    调用EnablePMode;跳转到ProtectedMode; ******************
*打开A20门*
; ******************
OpenA20Gate:
    在人,0x93;通过快速A20端口92开关门A20    或人,2;设置A20门位1
    和人〜1;明确INIT_NOW位
    出0x92,人    RET; ************
; *启用保护模式*
; ************
EnablePMode:
    MOV EAX,CR0
    或EAX,1
    MOV CRO,EAX    JMP(code_DESC - NULL_DESC):ProtectedMode; ***************
*数据字段*
*放大器;包括*
; ***************
;%包括gdt_32.inc
; **********
*全局描述符表(GDT)*
; **********
NULL_DESC:
    DD 0;空描述符
    DD 0code_DESC:
    DW 0xFFFF的;低限
    DW 0;底座低
    DB 0;中间基地
    DB 10011010b;访问
    DB 11001111b;粒度
    DB 0;基地高DATA_DESC:
    DW 0xFFFF的;低限
    DW 0;底座低
    DB 0;中间基地
    DB 10010010b;访问
    DB 11001111b;粒度
    DB 0;基地高GDTR:
    限制DW GDTR - NULL_DESC - 1; GDT的长度
    基地DD​​ NULL_DESC; GDT的基地; ******************
*保护模式*
; ******************
32位ProtectedMode:
    MOV AX,DATA_DESC - NULL_DESC
    MOV DS,AX;更新数据段    。停:
        HLT
        JMP .halt

请注意,一个段限制等于段大小减1。

数点......加载所有的段寄存器与有效的选择或0。此外,设置堆栈。如果你有垃圾存在(或从实模式旧值),当你开始中断/异常打球,你就会有更多的崩溃。

最后,我不知道ELF64是什么,但你必须照顾的组织的事情其他模块,并确保所有生成的地址对应于加载地址。如果你打算启用64位模式,还有大量的工作要做。我建议不要急于进入64位模式还没有,因为你绊倒了相对简单的东西。

I am currently playing around with x86 Assember in order to sharpen my low-level programming skills. Currently, I am facing a little problem with the addressing scheme in 32-Bit Protected Mode.

The situation is the following:

I have a Program loaded at 0x7e0 which switches the CPU to Protected Mode and jumps to the according label in the code:

[...]
code to switch CPU in Protected Mode
[...]

jmp ProtectedMode


[...]

bits 32

ProtectedMode:
    .halt:
        hlt
        jmp .halt

This works absolutely fine so far. The "jmp ProtectedMode" works without a explicit far jump to clear the prefetch queue - since this program is loaded with offset 0 (org 0 at the beginning) - causing the code segment pointing to the right location.

My current problem now is, that within the "ProtectedMode" label I want to jump to an other program which is loaded at 0x8000 (I checked this with a memory dump, the loading function did work properly and the program is loaded correctly to 0x8000).

Since the CPU is now in ProtectedMode and not RealMode anymore, the addressing schema is different. ProtectedMode uses descriptor selectors to lookup a base address and a limit in a descriptor table to add the given offset and retrieve the physical address (as I understood). Therefore, it was necessary to install a GDT before entering ProtectedMode.

Mine is looking like the following:

%ifndef __GDT_INC_INCLUDED__
%define __GDT_INC_INCLUDED__

;*********************************
;* Global Descriptor Table (GDT) *
;*********************************
NULL_DESC:
    dd 0            ; null descriptor
    dd 0

CODE_DESC:
    dw 0xFFFF       ; limit low
    dw 0            ; base low
    db 0            ; base middle
    db 10011010b    ; access
    db 11001111b    ; granularity
    db 0            ; base high

DATA_DESC:
    dw 0xFFFF       ; data descriptor
    dw 0            ; limit low
    db 0            ; base low
    db 10010010b    ; access
    db 11001111b    ; granularity
    db 0            ; base high

gdtr:
    Limit dw 24         ; length of GDT
    Base dd NULL_DESC   ; base of GDT

%endif ;__GDT_INC_INCLUDED__

and is loaded to the GDT register via

lgdt [gdtr]

What I did not understand so far is, how do I now jump to the physical address 0x8000 in ProtectedMode using the GDT?

My first thoughts were to select the Code Descriptor (CODE_DESC) which should point to 0x7e00 (were the current program is loaded) and use the offset that is necessary to get to 0x8000 (512 bytes), resulting in the jump instruction:

jmp CODE_DESC:0x200

But this does not work.

jmp 0x7e0:0x200 

does not work either...

Do you have any idea what I am missing here? Maybe I did not understand something essential within the 32-Bit ProtectedMode addressing scheme and the usage of the GDT.

[EDIT] Complete code:

bits 16
org 0                       ; loaded with offset 0000 (phys addr: 0x7e00)

jmp Start

Start:
    xor ax, ax
    mov ax, cs
    mov ds, ax              ; update data segment

    cli                     ; clear interrupts

    lgdt [gdtr]             ; load GDT from GDTR (see gdt_32.inc)

    call OpenA20Gate        ; open the A20 gate 

    call EnablePMode        ; jumps to ProtectedMode

;******************
;* Opens A20 Gate *
;******************
OpenA20Gate:
    in al, 0x93         ; switch A20 gate via fast A20 port 92

    or al, 2            ; set A20 Gate bit 1
    and al, ~1          ; clear INIT_NOW bit
    out 0x92, al

    ret

;**************************
;* Enables Protected Mode *
;**************************
EnablePMode:
    mov eax, cr0
    or eax, 1
    mov cr0, eax

    jmp ProtectedMode ; this works (jumps to label and halts)
    ;jmp (CODE_DESC-NULL_DESC):ProtectedMode ; => does not work
    ;jmp 08h:ProtectedMode , => does not work

;***************
;* data fields *
;*  &includes  *
;***************
%include "gdt_32.inc"

;******************
;* Protected Mode *
;******************
bits 32

ProtectedMode:
    ;here I want to jump to physical addr 0x8000 (elf64 asm program)

    .halt:
        hlt
        jmp .halt

解决方案

There are multiple problems in the code.

First, your GDTR.Base contains the offset of the GDT from the beginning of the code since your code is compiled to begin at address 0 (because of org 0). The base address must be the physical address, not a relative address. IOW, if you keep this org 0, you must add CS*16 (=0x7e00) to Base.

Second, because of that same org 0, the 32-bit offsets in your code (after bits 32 and ProtectedMode:) aren't equal to physical addresses they correspond to, they're 0x7e00 less than the physical addresses. OTOH, the segments defined in your GDT start at physical address 0 (because the base portions of the GDT entries are 0's) and not at 0x7e00. This means that when you try to use these segments with your code/data, you'll be missing the addresses by 0x7e00. If you want to keep org 0, the base addresses in the GDT must be set to 0x7e00.

Or you can change org 0 to org 0x7e00 and then the bases in the GDT should be 0. And you won't need to adjust GDTR.Base by 0x7e00, 0 will do.

This should work:

bits 16
org 0x7e00                  ; loaded at phys addr 0x7e00
                            ; control must be transferred with jmp 0:0x7e00

    xor ax, ax
    mov ds, ax              ; update data segment

    cli                     ; clear interrupts

    lgdt [gdtr]             ; load GDT from GDTR (see gdt_32.inc)

    call OpenA20Gate        ; open the A20 gate 

    call EnablePMode        ; jumps to ProtectedMode

;******************
;* Opens A20 Gate *
;******************
OpenA20Gate:
    in al, 0x93         ; switch A20 gate via fast A20 port 92

    or al, 2            ; set A20 Gate bit 1
    and al, ~1          ; clear INIT_NOW bit
    out 0x92, al

    ret

;**************************
;* Enables Protected Mode *
;**************************
EnablePMode:
    mov eax, cr0
    or eax, 1
    mov cr0, eax

    jmp (CODE_DESC - NULL_DESC) : ProtectedMode

;***************
;* data fields *
;*  &includes  *
;***************
;%include "gdt_32.inc"
;*********************************
;* Global Descriptor Table (GDT) *
;*********************************
NULL_DESC:
    dd 0            ; null descriptor
    dd 0

CODE_DESC:
    dw 0xFFFF       ; limit low
    dw 0            ; base low
    db 0            ; base middle
    db 10011010b    ; access
    db 11001111b    ; granularity
    db 0            ; base high

DATA_DESC:
    dw 0xFFFF       ; limit low
    dw 0            ; base low
    db 0            ; base middle
    db 10010010b    ; access
    db 11001111b    ; granularity
    db 0            ; base high

gdtr:
    Limit dw gdtr - NULL_DESC - 1 ; length of GDT
    Base dd NULL_DESC   ; base of GDT

;******************
;* Protected Mode *
;******************
bits 32

ProtectedMode:
    mov     ax, DATA_DESC - NULL_DESC
    mov     ds, ax ; update data segment

    .halt:
        hlt
        jmp .halt

Note that a segment limit equals the segment size minus 1.

A few more points... Load all segment registers with valid selectors or 0. Also, set up the stack. If you have garbage there (or old values from real mode), when you start playing with interrupts/exceptions, you'll have more crashes.

Finally, I don't know what elf64 is, but you will have to take care of the org thing for other modules and make sure all generated addresses correspond to load addresses. And if you intend to enable 64-bit mode, there's a ton of work to do. I'd advise not to rush into 64-bit mode yet since you're tripping over relatively simple stuff.

这篇关于与GDT保护模式汇编转移的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆