1. 程式人生 > >真實模式

真實模式

目錄

真實模式分段機制

1. 為什麼要分段

8086cpu有20根地址匯流排,可以訪問 1M (1<<20 )的記憶體空間,DS段暫存器定址能力,為64kb的記憶體空間。

地址匯流排定址能力:1M
段暫存器定址能力 : 64kb

因此段暫存器明顯是不夠用的。無法進行20位的定址。這時候就需要引入分段機制,使用DS段暫存器,配合一個偏移地址,來共同定址。從而達到20位的定址能力。

20位定址能力 :DS段暫存器(16位) << 4 +  偏移地址

這樣剛好達到20位定址能力,這樣根據一個段暫存器和一個偏移地址,就能確定指令或者資料在記憶體的位置了(歸根結底還是段暫存器不夠大,導致單獨一個段暫存器不夠用的)。

當程式執行時,可以設定一個段地址為開始地址,其他的段內地址為段開始地址+段內偏移地址。這樣來決定一條指令的位置。

在這種模式下,CPU提供了3個段暫存器,首先一個程式碼段暫存器CS,資料段暫存器DS,還有一個ES附加段暫存器。

在32位系統中,CPU有2種工作模式,分別為真實模式和保護模式。

真實模式的定址方式

由於最早的8086CPU只有20根匯流排,而定址能用到的只有16根。所以真實模式採用的是16位匯流排的定址方式。開始執行BIOS之後,計算機首先就是進入的真實模式。

關於匯流排寬度:http://www.cpu-world.com/CPUs/CPU.html

計算方式:實體地址 = DS段值 * 0x10 + BX偏移

真實模式是相容8086cpu的,採用的是16位的定址方式,段暫存器的大小侷限為16位。使用段暫存器 << 4 + 偏移地址這種方式的定址範圍只能使用1M左右的記憶體。相對於1G以上的記憶體,這個定址範圍肯定是不夠用的。

  • 真實模式定址為什麼需要偏移

cpu的匯流排為20位,定址範圍就為 1 << 20 = 1024KB。但是cpu的段暫存器只有16位,可使用定址範圍為1 << 16 =64kb,那麼明顯不夠用的。因此在計算地址時使用一個基址段暫存器 以及一個偏移地址,然後以DS段值+偏移地址進行計算,換算成20位匯流排地址。

2. 程式碼段和資料段

一個可執行程式一般包含程式碼段和資料段兩部分。比如顯示字串的功能,將字串文字資料和顯示函式放在2個位置。

  1. 程式碼段

    因為處理器是自動從一個開始地址中取出指令開始執行,如果沒有指令進行跳轉的話。則依次取出下一條指令繼續執行。而這些完成某個工作的指令集中在記憶體的連續一段區域,稱為程式碼段。

    記憶體中指令位置:

    [CS段暫存器 : IP指令指標暫存器]

  2. 資料段

    程式操作的資料也集中一起,放在記憶體的連續一段區域,稱為資料段。

    記憶體中資料位置:

    [DS段暫存器:偏移地址]

3. 分段後定址方式

8086的20位匯流排定址方式:

匯流排定址(訪問記憶體地址):CPU到記憶體提供20根匯流排,也就是20位的定址,定址能力為2^20,等於1M。

暫存器定址(通過暫存器訪問記憶體地址):段暫存器的大小為16位,也就是說CPU的段暫存器儲存的地址只有16位,單個段暫存器的定址能力為2<<16,大概等於64KB。

因此,只通過一個段暫存器是無法在真實模式下完全訪問1M記憶體的,這樣相當於浪費了匯流排到記憶體的訪問能力。

因此需要使用個段暫存器加上一個偏移地址,在記憶體地址以及暫存器地址之間做一個轉換的方式來指定地址。

記憶體地址(20位) = 段暫存器  << 4 + 偏移地址
  • ps:16位包含的地址數為:0x0000-0xhhhh,大小為2^16總共為64K,而20位包含的地址為 0x00000-0xhhhhh,總共為1M(也就是1024K);使用2個暫存器做對映,保證了可以訪問1M的記憶體地址
  • 偏移地址可以使用暫存器或者立即數,偏移地址使用暫存器時,只能為BX,SI,DI,BP中之一.

真實模式:資料訪問

1. 記憶體單元:

記憶體單元,一個記憶體單元的大小是一位元組:1B(1BYTE)。

記憶體單元的地址:

記憶體單元表示方式為:

[基本地址 : 偏移地址]

計算方式:

記憶體單元地址 = 基本地址 << 4+偏移地址

2. 記憶體單元的資料

記憶體單元的資料,大小為16B,記憶體單元的資料,是根據[記憶體單元地址]來獲取的。

CPU是根據DS段地址和偏移地址來定位記憶體單元的地址/

訪問記憶體單元的資料使用

[段暫存器值 : 偏移地址]

來表示根據

得到的記憶體地址處的記憶體單元 = 段暫存器值 << 4 + 偏移地址。

如果不指定段暫存器,CPU執行時預設會取DS段暫存器值進行計算。

預設使用DS段暫存器
記憶體單元的資料: [偏移地址] = [DS段暫存器:偏移地址]

3. 訪問記憶體資料(16位)

訪問記憶體,需要使用到段暫存器:DS段暫存器

記憶體單元讀寫

讀取記憶體單元的資料到暫存器中:
例如

mov ds,0x10000
mov ax,[0x10]       ;ax = [0x10000:0x10]

段暫存器不能使用常量立即數賦值,所以必須使用一箇中間的資料暫存器來操作

例如讀取[0x10000H:0x0016H]的資料到al暫存器中

mov bx,0x10000
mov ds,bx                   ;ds = 0x10000
mov al,[0x0016]         ;al = [0x10000:0x0016WW]

訪問範圍

真實模式下,偏移地址也是16位的,限制位 0x0000 ~ 0xffff。所以如果訪問超出這個範圍的記憶體地址,只使用偏移地址是不行的。

如下:
[偏移地址] 定址範圍: 0x0000 ~ 0xffff
[段暫存器值 :偏移地址] 定址範圍 : 0x0_0000 ~ 0xf_ffff

真實模式指令執行

段暫存器賦值

  1. 段暫存器賦值
    因為intel處理器不允許直接將段暫存器進行'立即數'賦值,因此如果使用段暫存器的話,必須先將'立即數'放到通用暫存器,然後複製通用暫存器的資料到段暫存器中。

    比如:
    ​ MOV 通用暫存器 , 0x7c00
    ​ MOV 段暫存器,通用暫存器
    或者:
    ​ MOV 段暫存器,記憶體地址

  2. 段暫存器範圍

    真實模式下,段的暫存器為16位,範圍為 0x0000 ~ 0xFFFF,當超出0xFFFF就會進位,繼續回到 0x0000的值。

  3. 段內地址賦值

    當我們使用一個段地址時,可以使用一下方式

    MOV [0x1000:0x000b], 0x100

    其中0x1000為段地址,0x000b為偏移地址,0x100為運算元的值。

    這個表示式意思為設定地址 DS * 0xf + 0x000b 的值為0x100。

    當然,不過也可以不指定 0x1000,那麼偏移會預設以DS中的值為基點,計算偏移後的地址

    比如

    MOV [0x000b], 0x100
* 關於[]表名這個是地址,而不是運算元。如果在右邊不加[]時為運算元,而加入[]則表示一個地址,當運算會以地址指向的資料來進行計算。

指令執行

執行指令,需要使用到段暫存器:CS段暫存器 和 IP指令指標暫存器

CPU每次執行記憶體中指令,都需要一個記憶體地址。這個地址為記憶體中的指令程式碼地址。

CPU是根據暫存器來獲取到這個地址並且執行這個地址的指令的。使用到2個暫存器來獲取指令地址:CS和IP

  1. 指令執行

1.首先CPU根據CS和IP獲取到記憶體地址,將記憶體中對應的指令放入指令緩衝器等待執行。
2.之後IP暫存器的值會自動增加,使得CS和IP的地址指向記憶體中的下一條指令。
3.使用JMP指令可以修改CS,IP的值

例如,執行CS:0x0003H,IP:0x0016H地址的指令

JMP 0x0003:0x0016    ;跳轉到記憶體 0x0003H<<4 + 0x0016H處
  1. 指令的記憶體地址
    指令的記憶體地址使用:CS段暫存器:IP指令指標暫存器 來表示。
    例如:

    0x0003:0x0016 ;代表記憶體 0x0003<< 4 + 0x0016處的指令。

真實模式下記憶體訪問範圍

在真實模式下:

記憶體單元的資料大小為1個位元組 (16B).

基本地址是使用一個16位的段暫存器的值,而偏移地址是一個16位的值。

如果沒有顯式說明段暫存器,預設基本地址使用DS段暫存器。

訪問範圍 0x0000 ~ 0x10FFEF (0xFFFF << 4 + 0xFFFF )

當程式訪問0x100000~0x10FFEF這一段地址時,因為其邏輯上是正常的,CPU並不會認為其訪問越界而產生異常,但這段地址確實沒有實際的實體地址與其對應,會擷取掉最高的一位,進行迴繞訪問。

真實模式記憶體分配

首先我們需要對程式在記憶體中分配的位置有個大概的定義。
首先是真實模式下的1M空間的記憶體,分配

這1M大小的記憶體區域位並不完全位於通常的記憶體條中,會被BIOS以及顯示卡等佔據一部分。

其中0x00000~0x9FFFF位置是屬於記憶體條的地址。
0xA0000~0xEFFFF提供給外圍裝置使用,例如顯示卡等。
而0xF0000~0xFFFFF是屬於BIOS的ROM地址。

記憶體地址 空間大小 用途
0x00000 ~ 0x003FF 1KB 中斷向量表
0x00400 ~ 0x004FF 256B BIOS資料區
0x00500 ~ 0x07BFF 大概30KB 可用區域
0x07C00 ~ 0x07DFF 512B MBR引導載入位置
0x07E00 ~ 0x9FBFF 大概608KB 可用區域
0x9FC00 ~ 0x9FFFF 1KB BIOS擴充套件資料區
--- --- ---
0xA0000 ~ 0xAFFFF 64KB 顯示介面卡-彩色模式
0xB0000 ~ 0xB7FFF 32KB 顯示介面卡-黑白模式
0xB8000 ~ 0xBFFFF 32KB 顯示介面卡-文字模式
0xC0000 ~ 0xC7FFF 32KB 顯示介面卡
0xC8000 ~ 0xEFFFF 160KB 硬體介面卡ROM
0xF0000 ~ 0xFFFFF 64KB BIOS程式。BOIS入口地址為: 0xF0000-0xFFFFF

boot :0x07C00 ~ 0x07DFF 1個扇區(512_位元組)
loader :0x90000 ~ 0x907FF 4個扇區(2048_位元組)
kernel :0x10000 ~ 24個扇區(12288_位元組)

執行後應該是進入黑屏無游標的頁面(區別是沒有游標的哦)。