日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 综合教程 >内容正文

综合教程

操作系统:GDT简介&实模式到保护模式的跳转

發(fā)布時(shí)間:2024/6/21 综合教程 39 生活家
生活随笔 收集整理的這篇文章主要介紹了 操作系统:GDT简介&实模式到保护模式的跳转 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言(瞎逼逼)

自從AFO之后就想著開(kāi)一個(gè)什么新坑,但是包括但不限于大學(xué)申請(qǐng)之類(lèi)的破事兒讓我的確忙活了一陣子。。。閑下來(lái)的時(shí)候突然想起來(lái)以前曾經(jīng)開(kāi)過(guò)一個(gè)小頭(當(dāng)然很快就因?yàn)樽藙?shì)水平不夠就放棄了)的編寫(xiě)操作系統(tǒng),于是自己就想著把兒時(shí)的夢(mèng)想繼續(xù)堅(jiān)持下去吧

這篇博客主要是依靠于淵的《Orange's 一個(gè)操作系統(tǒng)的實(shí)現(xiàn)》里面的代碼來(lái)給出的解釋?zhuān)钥赡軙?huì)有很多的匯編。

實(shí)模式

CPU自啟動(dòng)的時(shí)候一開(kāi)始會(huì)首先進(jìn)入實(shí)模式,此時(shí)我們只能訪問(wèn)1MB的內(nèi)存,并且任何程序都可以訪問(wèn)內(nèi)存段內(nèi)的任意位置,這樣顯然是不安全的。但是現(xiàn)在的32位CPU可以訪問(wèn)4GB的內(nèi)存,我們主要是通過(guò)進(jìn)入保護(hù)模式來(lái)達(dá)到這個(gè)目的的(保護(hù)模式帶來(lái)的好處并不限于訪問(wèn)內(nèi)存的擴(kuò)大)

GDT

我們先來(lái)想一下,實(shí)模式下CPU的尋址方式是:

[段地址:段內(nèi)偏移
]

這種方式在以前固然好,但是新的32位CPU提供了32位地址線。老的16位寄存器已經(jīng)不夠用了,我們現(xiàn)在需要一種新的內(nèi)存尋址方式,GDT就此誕生了

GDT本質(zhì)上一個(gè)表,表內(nèi)包含了一段內(nèi)存的段基址,段界限,段屬性。實(shí)模式下我們使用段地址:偏移地址通過(guò)地址處理器來(lái)直接訪問(wèn)內(nèi)存,但是實(shí)模式下段地址的意義發(fā)生了根本的變化。段地址不再表示實(shí)際內(nèi)存中的某一段,而是表示的我們要訪問(wèn)的段在GDT表里面的偏移。通過(guò)訪問(wèn)GDT表的特定表項(xiàng)來(lái)得出段基址,緊接著通過(guò)段內(nèi)偏移來(lái)訪問(wèn)內(nèi)存。此時(shí)的段地址我們有另外一個(gè)名字——段選擇子。我們通過(guò)定義不同的選擇子來(lái)對(duì)應(yīng)到不同的表項(xiàng)里面去,接著就可以訪問(wèn)特定內(nèi)存了。

總結(jié)起來(lái)就是這個(gè)樣子的:

當(dāng)然,要使用GDT我們必須先有一個(gè)GDT,下面是GDT的定義部分:

[SECTION .gdt]
LABEL_GDT:              Descriptor      0,          0,           0 ;空描述符
LABEL_DESC_CODE32:      Descriptor      0,SegCode32Len-1,  DA_C+DA_32 ;32位代碼段
LABEL_DESC_VIDEO:       Descriptor 0B8000h,0ffffh    ,DA_DRW ;顯存映射到內(nèi)存中的地址

然后加上GDT的長(zhǎng)度和界限

GdtLen equ $-LABEL_GDT ;GDT長(zhǎng)度
GdtPtr dw GdtLen-1 ;GDT界限
dd 0

在這里面的 LABEL_DESC_CODE32 和 GdtPtr 都要-1,因?yàn)樵L問(wèn)指定表項(xiàng)所對(duì)應(yīng)的段基址的時(shí)候都是包含基址的,長(zhǎng)度自然要-1

再往后面就是定義段選擇子了,其實(shí)很簡(jiǎn)單,就是表項(xiàng)相對(duì)于GDT表的偏移

SelectorCode32 equ LABEL_DESC_CODE32-LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO-LABEL_GDT

然后我們就要開(kāi)始準(zhǔn)備載入GDT了。這里 LABEL_DESC_CODE32 的基地址并不急著給出,因?yàn)槟阋膊恢?2位代碼段的起始位置。

接著就是在16位下初始化GDT了:

[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
    mov ax,cs
    mov ds,ax
    mov es,ax
    mov ss,ax
    mov sp,0100h

    mov ax,0003h
    int 10h

這里除了一些基本的指令以外就是我調(diào)用了10號(hào)中斷來(lái)清了屏,因?yàn)閎ochs一開(kāi)始屏幕上會(huì)有一堆BIOS提示。

且聲明了棧段和sp。

    xor eax,eax
    mov ax,cs
    shl eax,4
    add eax,LABEL_SEG_CODE32
    mov word [LABEL_DESC_CODE32+2],ax
    shr eax,16
    mov byte [LABEL_DESC_CODE32+4],al
    mov byte [LABEL_DESC_CODE32+7],ah

這里我們就要開(kāi)始處理之前留下來(lái)的32位代碼段基地址的問(wèn)題了。要注意的是,由于此時(shí)我們?nèi)匀惶幱?6位下,并且GDT并沒(méi)有被載入到i內(nèi)存中去,所以 LABEL_DESC_CODE32+2 指向的仍然是標(biāo)號(hào)指向的位置,也就是表項(xiàng)內(nèi)部(和之前在實(shí)模式下尋址方式一樣,不要搞混了)

    xor eax,eax
    mov ax,ds
    shl eax,4
    add eax,LABEL_GDT
    mov dword [GdtPtr+2],eax

CPU是通過(guò)寄存器GDTR來(lái)得知GDT的基地址和界限的,GDTR的示意圖在這里:

我們要做到的就是在GdtPtr里面填充符合標(biāo)準(zhǔn)的數(shù)據(jù)然后使用后lgdt指令來(lái)加載GDTR寄存器,也就是上面的這段代碼所做的事情。

然后就可以快樂(lè)地加載GDTR了

    lgdt [GdtPtr]

接著我們需要屏蔽掉所有16位中斷。因?yàn)楸Wo(hù)模式下中斷處理的方式都是不同的(比如說(shuō)尋址),如果計(jì)算機(jī)在保護(hù)模式之后又跑去處理實(shí)模式下的中斷代碼的化會(huì)發(fā)生錯(cuò)誤

    cli ;關(guān)中斷

再就是打開(kāi)A20地址線了。關(guān)于A20地址線的歷史性問(wèn)題這里就不再贅述,感興趣的化可以去《x86匯編語(yǔ)言 從實(shí)模式到保護(hù)模式》的11.5章節(jié)里面找到細(xì)節(jié)的描述。

具體來(lái)講,打開(kāi)A20地址線的方法就是操作92號(hào)端口來(lái)實(shí)現(xiàn)的:

    in al,92h
    or al,00000010b
    out 92h,al

接下來(lái)就是置控制寄存器cr0的PE(Protected Enable)位到1來(lái)開(kāi)啟保護(hù)模式

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

然后就是跳轉(zhuǎn)到32位保護(hù)模式下的代碼段了:

    jmp dword SelectorCode32:0

這里有一些細(xì)節(jié)要注意。因?yàn)榇藭r(shí)GDTR已經(jīng)獲得了GDT的位置,所以這里就已經(jīng)是通過(guò)GDT來(lái)尋址了。并且此時(shí)偏移地址仍然是在16位下進(jìn)行編譯的,所以如果偏移地址不是0而是一個(gè)很大的值,普通的 jmp SelectorCode32:0x12345678 可能會(huì)讓偏移位上的地址發(fā)生截?cái)唷K晕覀兺ㄟ^(guò)聲明dword類(lèi)型的地址避免編譯器把偏移地址給自動(dòng)截?cái)?/p>

接下來(lái)就是32位代碼段的代碼了,有一些之前使用過(guò)的標(biāo)號(hào)是在這里聲明的,可以和之前的代碼結(jié)合起來(lái)看:

[SECTION .s32]
[BITS 32]

LABEL_SEG_CODE32:
    mov ax,SelectorVideo 
    mov gs,ax
    mov edi,(80*11+39)*2
    mov ah,0ch
    mov al,'p'
    mov [gs:edi],ax
    jmp $

SegCode32Len equ $-LABEL_SEG_CODE32

就是在屏幕中央打印一個(gè)紅色的 'p'

所有代碼:

%include "pm.inc"

org 07c00h
jmp LABEL_BEGIN

[SECTION .gdt]
LABEL_GDT:              Descriptor      0,          0,           0
LABEL_DESC_CODE32:      Descriptor      0,SegCode32Len-1,  DA_C+DA_32
LABEL_DESC_VIDEO:       Descriptor 0B8000h,0ffffh    ,DA_DRW

GdtLen equ $-LABEL_GDT
GdtPtr dw GdtLen-1
dd 0

SelectorCode32 equ LABEL_DESC_CODE32-LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO-LABEL_GDT

[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
    mov ax,cs
    mov ds,ax
    mov es,ax
    mov ss,ax
    mov sp,0100h

    mov ax,0003h
    int 10h

    xor eax,eax
    mov ax,cs
    shl eax,4
    add eax,LABEL_SEG_CODE32
    mov word [LABEL_DESC_CODE32+2],ax
    shr eax,16
    mov byte [LABEL_DESC_CODE32+4],al
    mov byte [LABEL_DESC_CODE32+7],ah

    xor eax,eax
    mov ax,ds
    shl eax,4
    add eax,LABEL_GDT
    mov dword [GdtPtr+2],eax

    lgdt [GdtPtr]

    cli

    in al,92h
    or al,00000010b
    out 92h,al

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

    jmp dword SelectorCode32:0

[SECTION .s32]
[BITS 32]

LABEL_SEG_CODE32:
    mov ax,SelectorVideo 
    mov gs,ax
    mov edi,(80*11+39)*2
    mov ah,0ch
    mov al,'p'
    mov [gs:edi],ax
    jmp $

SegCode32Len equ $-LABEL_SEG_CODE32

運(yùn)行截圖:

后續(xù)

很憋屈的是,這段代碼依然是放在引導(dǎo)扇區(qū)里面的。所以如果你用bximage新創(chuàng)建了一個(gè)1.44mb大小的img的化,需要在尾部寫(xiě)入0xaa55以讓cpu識(shí)別到引導(dǎo)扇區(qū),否則就會(huì)報(bào) no bootable device的錯(cuò)

第一次寫(xiě)OS相關(guān)的博客,可能會(huì)有一些地方出錯(cuò)。。。

總結(jié)

以上是生活随笔為你收集整理的操作系统:GDT简介&实模式到保护模式的跳转的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。