【我所認知的BIOS】—>實模式&保護模式LightSeed 2009-6-17 回顧一下blog里的第一篇文章【我所認知的BIOS】—>ADU.EXE,http://blog.csdn.net/lightseed/archive/2009/05/26/4216113.aspx在這篇文章我有提到關於Memory的訪問,在ADU中有關於“real mode”和“Flat mode”兩種形式去訪問內存。那麼這張起我就來談談我對實模式(real mode)和保護模式(protect mode)的理解。(筆者:主要把訪問內存的方式作為切入點。)不過爲什麽要說說這兩個模式,我在這裡就先提一下。BIOS code大部分都是在real mode下寫的,但當有需求存取1MB以上的memory時(其實經常會遇到),big real mode(下一節介紹)是個不錯的選擇。雖然我們熟悉的protected mode也可以達成存取4GB內存的目的,但如果程式本身執行的環境是DOS或BIOS的話,打開protected mode反而會造成麻煩。例如無法呼叫原來在real mode下呼叫的一些routines,或是必須頻頻在兩個mode下切換!要談清楚地把BigRealMode說明的話,我想protect mode是必修課。(筆者:如果不深究爲什麽會出來BigRealMode,不瞭解protect mode也是可以做到的。)1、物理地址CPU要訪問內存必須要通過時,要給出內存單元的地址。所有的內存單元組成在一起是一個呈線性的空間。每個空間裏面存儲著我們的數據,而且這每一個空間都有一個唯一的地址,我們將這個唯一的地址就稱為物理地址。(筆者:這段話主要是參考《匯編語言》王爽老師著)2、實模式(real mode)下訪問內存2.1訪問實例在實模式下,我們訪問內存是通過segment:offset找到內存的。舉個例子:如果我們訪問的內存是D000H:0FC0H處的內存,那麼我們實際訪問到的物理地址是(D000H*16+0FC0H)處內存。為了說明清楚問題,見圖1: 圖1實模式下訪問內存截圖正如圖1所示,紅線為segment:offset,黃線為內存中的值。我們來總結一下再real mode下。segment*16+offset =物理地址2.2需要說明的一個問題:段的概念在我們說的過程中,有提到一個“段”的概念,也許大家會這麼認為,在內存中是存在一個接一個的“段”而構成整個內存空間的。我當初也范了這樣的主觀上的錯誤,在這裡也強調一下。這種想法是錯誤的。“段”的形式不是因為內存本來有“段”,只是CPU為了方便自己管理內存,從而存在的一種管理方式而已。一個很明瞭的例子見圖2舉給大家。(筆者:“段”有大有小,不過最大不能超過一個界限。如果有興趣的朋友,你可以推算一下。不過我在下一篇里會詳細演算一遍。) 圖2分段我们可以看到在real mode下,CPU能够访问到的内存空间范围是00000H~FFFFFH一共是1M的大小。3.保護模式(protect mode)保護模式下的存儲管理機制比較複雜,我也不可能說的很詳細哈。只是從大方向闡述一下我個人的理解。如果有人有興趣詳細鑽研,我想《80X86匯編語言程序設計教程》楊季文著,這本書是不錯的選擇。至於其他的詳細資料,如果有人需要的話,我可以通過mail發給你。在下麵的文章中,我會引用一些剛剛提到的這本書里的內容。(筆者:專家寫的總是比我要寫的好,不過由於話比較多,我就儘量揀重點說。引號內均為原話)3.1地址空間和地址轉換保護模式其實應該是從80386時代開始的,“80386分两步实现虚拟地址空间到物理地址空间到物理地址空间的映射,也就是分两步实现虚拟地址到物理地址的转换,但第二步是可选的。”图3是地址映射转换的示意图。 圖3地址映射转换示意 “通过描述符表和描述符,分段管理机制实现虚拟地址空间到线性地址空间的映射,实现把二维的虚拟地址转换为一维的线性地址。这一步总是存在的。分页管理机制把线性地址空间和物理地址空间分别划分为大小相同的块,这样的块称为页。通过在线性地址空间的页与物理地址空间的页建立之间建立的映射表,分页管理机制实现线性地址空间到物理地址空间的映射,实现线性地址到物理地址的转换。分页管理机制是可选的,在不采用分页管理机制时,线性地址空间就等同于物理地址空间,线性地址就等于物理地址。分段管理机制所使用的可变大小的块,使分段管理机制比较适宜处理复杂系统的逻辑分段。存储块的大小可以根据适当的逻辑含义进行定义,而不用考虑固定大小的页所强加的人为限制。每个段可作为独立的单位处理,以简化段的保护及共享。分页机制使用的固定大小的块最适合于管理物理存储器,无论是管理内存还是外存都同样有效。分页管理机制能够有效地支持实现虚拟存储器。”不過上面兩種機制中,我著重談談分段管理機制。(筆者:起碼我到現在為止,全部用的是這個東東。并且通过Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3A: System Programming Guide, Part 1 3.1第一段最末就明確說明了,分段管理機制是必定存在的,而分页管理机制是可選的。)3.2虛擬地址到線性地址轉換我們要明確,“段”是實現虛擬地址到線性地址轉換的基礎。在保護模式下,段有三個參數定義:段基地址(Base Address)、段界限(Limit)、段屬性(Attributes)。Base address,在這裡比real mode下的segment靈活很多,可以從線性地址空間的任何一個字節開始。不再需要必須被16整除。由上面三個參數我們可以確定,一個段的基地址(起始地址),以及這個段的映射範圍(段界限決定)。而在圖3出現的偏移量,其實我們要訪問的內存相對于基地址而言的長度。段內偏移為X的虛擬地址,對應的線性地址就為Base + X =線性地址 然而我的偏移量是>0且<段界限(Limit)的。我們來看看圖4的示意圖。 圖4虛擬地址到線性地址轉換示意圖3.3段基地址(Base Address)、段界限(Limit)、段屬性(Attributes)正如小标题,这三个参数是用来定义“段”的。我们把他们统称为描述符。在保护模式下,每一個段都有一個對應的描述符來描述。按照描述的對象來劃分,描述符又被分為:存儲段描述符、系統段描述符、控制描述符。不過我著重講一下我經常用到的存儲段描述符。3.3.1存儲段描述符(相當重要!)假如描述符8個字節的最低字節地址為X。存儲段描述符的格式見圖5 圖5 存儲的描述符格式對於格式中的東西,我只解釋幾個重要點的。(1)P位称为存在(Present)位。P=1表示描述符对地址转换是有效的,或者说该描述符所描述的段存在,即在内存中;P=0表示描述符对地址转换无效,即该段不存在。使用该描述符进行内存访问时会引起异常。(2)DPL表示描述符特权级(Descriptor Privilege level),共2位。它规定了所描述段的特权级,用于特权检查,以决定对该段能否访问。(3)DT位说明描述符的类型。对于存储段描述符而言,DT=1,以区别与系统段描述符和门描述符(DT=0)。(4)TYPE说明存储段描述符所描述的存储段的具体属性。(我就不列了,到處都有資料)(5)G为就是段界限粒度(Granularity)位。G=0表示界限粒度为字节;G=1表示界限粒度为4K字节。注意,界限粒度只对段界限有效,对段基地址无效,段基地址总是以字节为单位。由於在後面的過程中我會陸續用到這個描述符,就我個人喜好,我喜歡把這個描述符做成一個結構體的形式,這樣每次調用的時候我只要填相應的值到結構體中即可。見下: ;存储段描述符结构类型的定义 DESCRIPTOR struc Limitl DW 0 ;段界限(0~15) Basel DW 0 ;段基地址(0~15) Basem DB 0 ;段基地址(16~23) Attributes DW 0 ;段属性 Baseh DB 0 ;段基地址(24~31)DESCRIPTOR ENDS比如說我調用結構體,Code DESCRIPTOR <0FFFFH,0,10H,0F2H,0> Code描述一个可读写的有效(存在的)数据段,基地址是100000H,以字节为单位的界限是0FFFFH,描述符特权级DPL=3。 在我們實際的code中,必定會有一個全域描述符表(GDT)的存在。他們就是由這些結構體一個一個挨在一起的一段數據(只是我們自己把它們看成一個表而已)。3.3.2段選擇子(也很重要!)我們來回顧一下,在real mode中,CPU訪問內存空間是通過segment*16+offset =物理地址來做到的可以寫作。Segment:offset =物理地址而在保護模式中CPU訪問內存空間可以寫作Selector:offset =物理地址這個時候我們可以和保護模式的訪問方式做對比,看成是segment確定了基地址(base address),offset是偏移量。這麼一看原來實模式和保護模式基本上是一樣的。(筆者:只是從這個方式上去理解。)只是CPU在保護模式下,確定這個基地址(base addres)不是直接把地址寫成[base addres]:limit的形式的,而是寫成[段選擇子]:offset的形式。如果我們固執地認為這個【段選擇子】就是一個segment,那麼我想給你說,yes!you are right!只是真正CPU在處理的過程中會做一些動作,把段選擇子換成是保護模式中的基地址。我們不追究段選擇子的每個bit代表什麽的話,那麼你可以這樣認為。段選擇子是描述符索引。具體是什麽意思呢?其實就是3.3.1最後提到的那個全域描述符表中的序號。選擇子確定描述符-->描述符確定段基地址-->段基地址+偏移=線性地址-->線性地址與物理地址映射。從而CPU計算得到了內存的物理地址。也許我這樣說,你可能還是感覺有點抽象。見下表Index全域描述符表(GDT)label0Null DESCRIPTOR ??>1Code DESCRIPTOR <0FFFFH,0,10H,0F2H,0>2Datasi DESCRIPTOR <0FFFFH,0,22H,0F2H,0>3Datadi DESCRIPTOR <0FFFFH,0,22H,0F2H,0>……從表中,CPU一看就知道(筆者:我們人看了可不知道哈,呵呵。。^.^)在保護模式下,如果遇到這樣的codeMov ax,1Mov cs,axMov cs:[893h],dx ;在這裡,CPU就會解析到cs中的值是“1”,那麼;就是說在GDT中index為“1”的那個描述符中;的base address就是我CPU大哥要用的base;address了。於是就可以得到,此時的base;address就為100000H。不知道大家在對於這個段選擇子的認識搞清楚了沒有?By the way,CPU在解析這個段基地址的時候不是我說的這麼簡單,中間還做了很多加快速度呀,這樣那樣的操作,讓整個計算機的性能更好。但是原理是一樣的。我個人認為段選擇子的引入是保護模式輝煌的一筆,弄清楚它的含義那麼后兩篇文章我要講的內容就輕而易舉了。後面我會舉一個實例來一步一步分析怎麼進入保護模式的。再後面和大家探討關於big real mode的相關知識。 總的來說,這一章如果不是很懂也應該沒有關係,不會影響我們的debug過程,但是我個人認為把這個弄懂了的話,心裡會踏實很多。僅僅是個人拙見而已。 虛擬地址 線性地址 物理地址???>