2012-02-04 31 views
10

我目前正在使用x86 Assember來提高我的低級編程技能。目前,我在32位保護模式下尋址方案遇到了一些問題。彙編程序跳轉到GDT保護模式

的情況如下:

我在0x7e0加載的程序將CPU切換到保護模式,並跳轉到在代碼中根據標籤:

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

jmp ProtectedMode 


[...] 

bits 32 

ProtectedMode: 
    .halt: 
     hlt 
     jmp .halt 

這工作絕對沒這麼遠。 「jmp ProtectedMode」在沒有明確的遠程跳轉的情況下工作,以清除預取隊列 - 因爲此程序的偏移量爲0(開始時爲org 0) - 導致代碼段指向正確的位置。

我現在目前的問題是,在「ProtectedMode」標籤內,我想跳轉到其他程序,它是在0x8000加載的(我使用內存轉儲進行了檢查,加載函數確實工作正常,程序加載正確到0x8000)。

由於CPU現在處於ProtectedMode而不是RealMode,因此尋址模式不同。 ProtectedMode使用描述符選擇器在描述符表中查找基地址和限制,以添加給定的偏移量並檢索物理地址(據我所知)。因此,在進入ProtectedMode之前,有必要安裝GDT。

礦正在尋找類似如下:

%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__ 

,並加載到GDT註冊通過

lgdt [gdtr] 

我不明白到目前爲止,我怎麼現在跳到物理在ProtectedMode中使用GDT地址0x8000?我的第一個想法是選擇應該指向0x7e00(當前程序被加載)的代碼描述符(CODE_DESC),並使用必要的偏移量來達到0x8000(512字節),從而產生跳轉指令:

jmp CODE_DESC:0x200 

但這不起作用。

jmp 0x7e0:0x200 

也不管用...

你有任何想法,我在這裏失蹤?也許我不明白32位ProtectedMode尋址方案和GDT的用法。

[編輯]完整代碼:

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 

回答

11

裏有代碼的多個問題。

首先,你GDTR.Base包含因爲你的代碼被編譯開始在地址0(因爲org 0)的偏移GDT從代碼的開始。基地址必須是物理地址,而不是相對地址。 IOW,如果您保留此org 0,則必須將CS * 16(= 0x7e00)添加到Base

其次,因爲同樣的org 0,在你的代碼中的32位偏移量(bits 32ProtectedMode:後)不等於它們對應的物理地址,它們比物理地址0x7e00少。 OTOH中,GDT中定義的段開始於物理地址0(因爲GDT條目的基本部分爲0),而不是0x7e00。這意味着,當您嘗試將這些段與您的代碼/數據一起使用時,您將錯過地址0x7e00。如果您想保留org 0,則GDT中的基址必須設置爲0x7e00。

或者您可以將org 0更改爲org 0x7e00然後GDT中的鹼基應該爲0.您不需要將GDTR.Base調整爲0x7e00,0就可以了。

這應該工作:

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 

注意,一個段限制等於段大小減1

數點......加載所有的段寄存器與有效的選擇或0。此外,設置堆棧。如果你有垃圾(或來自實模式的舊值),當你開始玩中斷/異常時,你會有更多的崩潰。

最後,我不知道elf64是什麼,但你必須照顧其他模塊的org事情,並確保所有生成的地址對應於加載地址。如果你打算啓用64位模式,那麼需要做很多工作。我建議不要急於進入64位模式,因爲你正在絆倒相對簡單的東西。

+0

感謝您的解釋......這正是我爲什麼這麼做的原因 - 當您從頭開始閱讀x86引用時,這並不是那麼簡單:)!順便說一句:有什麼偉大的書,你可以建議,處理完全這些類型的話題? – 2012-02-05 04:29:23

+1

我不認識好書。英特爾和AMD的官方文檔包含了所有的信息,它不是一種您可以輕鬆閱讀並且立即理解所有內容的典型書籍或教科書(順便提一句,英特爾文檔中存在很多錯別字和偶爾的錯誤)。網上有很多文章和教程。你可以隨時做實驗。或者查看某人的代碼並提出問題。查看以下羣組:[alt.os.development](http://groups.google.com/group/alt.os.development/topics),[comp.lang.asm.x86](http://groups.google的.com /組/ comp.lang.asm.x86 /主題)。 – 2012-02-05 05:02:03

+0

感謝您的諮詢!我會看看那個! – 2012-02-05 07:08:42

3

一對夫婦的事情。首先,您當前的代碼在技術上不會進入保護模式。通過使用GDT的描述符加載cs來進入保護模式。由於您無法直接設置cs寄存器,因此執行此操作的最簡單方法是使用遠程跳轉。替換您當前的跳轉:

jmp (CODE_DESC-NULL_DESC):ProtectedMode 

其次,代碼段的基數爲0,而不是0x7e00。如果您查看標有單詞「base」的四個字節,它們全部爲0.您有兩個選項。要麼改變你的GDT擁有的0x7e00基地,或添加指令來改變所有保護模式下的代碼加載地址爲0

基地一旦你完成了這兩個東西,你可以使用跳轉到您的程序一個正常的跳轉指令。如果你選擇離開你的GDT,因爲它是,你可以使用完整的地址:如果您選擇更改代碼段的基

jmp 0x8000 

,你將需要使用相對於該地址。

jmp 0x200 

More information about the GDT
More information about entering protected mode

+0

感謝您的回答..好的 - 當使用跳轉指令「jmp CODE_DESC:ProtectedMode」時,CPU發生三重故障並復位(因爲此跳轉方向似乎跳到了某處)。 「jmp ProtectedMode」跳轉到正確的標籤並暫停系統。由於這可能與GDT基本問題相關,我將更改GDT並重試。感謝您的快速響應! – 2012-02-04 02:56:44

+0

@ughoavgfhw你的意思是'jmp(CODE_DESC-NULL_DESC):ProtectedMode'? – Nayuki 2012-02-04 05:37:57

+0

@NayukiMinase謝謝你的接觸,我認爲他們已經偏移了。 – ughoavgfhw 2012-02-04 05:40:47