真實模式
目錄
真實模式分段機制
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個位置。
程式碼段
因為處理器是自動從一個開始地址中取出指令開始執行,如果沒有指令進行跳轉的話。則依次取出下一條指令繼續執行。而這些完成某個工作的指令集中在記憶體的連續一段區域,稱為程式碼段。
記憶體中指令位置:
[CS段暫存器 : IP指令指標暫存器]
資料段
程式操作的資料也集中一起,放在記憶體的連續一段區域,稱為資料段。
記憶體中資料位置:
[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
真實模式指令執行
段暫存器賦值
段暫存器賦值
因為intel處理器不允許直接將段暫存器進行'立即數'賦值,因此如果使用段暫存器的話,必須先將'立即數'放到通用暫存器,然後複製通用暫存器的資料到段暫存器中。比如:
MOV 通用暫存器 , 0x7c00
MOV 段暫存器,通用暫存器
或者:
MOV 段暫存器,記憶體地址段暫存器範圍
真實模式下,段的暫存器為16位,範圍為 0x0000 ~ 0xFFFF,當超出0xFFFF就會進位,繼續回到 0x0000的值。
段內地址賦值
當我們使用一個段地址時,可以使用一下方式
MOV [0x1000:0x000b], 0x100
其中0x1000為段地址,0x000b為偏移地址,0x100為運算元的值。
這個表示式意思為設定地址 DS * 0xf + 0x000b 的值為0x100。
當然,不過也可以不指定 0x1000,那麼偏移會預設以DS中的值為基點,計算偏移後的地址
比如
MOV [0x000b], 0x100
* 關於[]表名這個是地址,而不是運算元。如果在右邊不加[]時為運算元,而加入[]則表示一個地址,當運算會以地址指向的資料來進行計算。
指令執行
執行指令,需要使用到段暫存器:CS段暫存器 和 IP指令指標暫存器
CPU每次執行記憶體中指令,都需要一個記憶體地址。這個地址為記憶體中的指令程式碼地址。
CPU是根據暫存器來獲取到這個地址並且執行這個地址的指令的。使用到2個暫存器來獲取指令地址:CS和IP
- 指令執行
1.首先CPU根據CS和IP獲取到記憶體地址,將記憶體中對應的指令放入指令緩衝器等待執行。
2.之後IP暫存器的值會自動增加,使得CS和IP的地址指向記憶體中的下一條指令。
3.使用JMP指令可以修改CS,IP的值
例如,執行CS:0x0003H,IP:0x0016H地址的指令
JMP 0x0003:0x0016 ;跳轉到記憶體 0x0003H<<4 + 0x0016H處
指令的記憶體地址
指令的記憶體地址使用: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_位元組)
執行後應該是進入黑屏無游標的頁面(區別是沒有游標的哦)。