intel x86 保護模式的內存和任務管理

2021-01-07 閒聊代碼

在開啟保護模式之後(步驟見Linux使用bochs模擬啟動保護模式),CPU的運行分為3個方面:內存管理、任務管理、中斷管理。

1,內存管理,

一般是分頁管理。

單純的分段管理比較死板,在多進程系統裡處理起進程的動態創建和退出時不夠靈活,而且任務切換的代價太高:需要切換任務寄存器TR,以及由此導致一系列任務上下文的切換。

單純的分段內存+多任務方式,趙炯老師的書裡有個簡單的例子,固定寫好的2個任務,根據系統時鐘進行切換。從0換到1,從1換到0,與我在Linux的fork()系統調用這篇文章裡演示的例子差不多。

趙老師的代碼是內核態彙編代碼,需要一定的「計算機組成原理與彙編語言」基礎,有興趣的可以看一下。

Linux裡使用的是分頁管理,一個內存頁的大小是4096位元組(4k),而且進程的task_struct或者thread_info與內核棧是在一組連續的頁上的(且以4k * N對齊,N為這組頁的個數),見之前介紹內核current宏的文章:Linux內核獲取當前進程結構的current宏。

經典的32位分頁模式,是由頁目錄和頁表組成的二級數據結構管理,頁目錄的物理地址放在cr3寄存器裡,所以cr3也叫頁目錄基地址寄存器。

一個虛擬地址vaddr轉換到物理地址paddr時,它的最高10位用來在頁目錄中查詢頁表,中間10位用來在頁表中查詢具體的頁,最低12位是頁內的偏移量。

unsigned long vaddr;

unsigned long* pgtable = (unsigned long*)pgdir[ vaddr >> 22 ];

unsigned long page = pgtable[ (vaddr >> 12) & 0x3ff ];

unsigned long paddr = (page &~0xfff) + (vaddr & 0xfff);

無符號整數的右移>>是邏輯右移,高位添0,所以vaddr >> 22取最高10位時省略了& 0x3ff。當然,為了避免編譯器出漏子,也可以添上。

因為CPU使用頁表項的低12位記錄各種權限標誌,所以在計算物理地址時低12位要清零。在寫時複製copy-on-write時,要在對應的頁表項裡添加低12的權限標誌。

在打開分頁之後,頁目錄、頁表裡填寫的是物理地址,代碼裡使用的是虛擬地址,CPU的內存管理單元MMU依據cr3寄存器負責地址轉換。

如果是外部設備,它很大可能沒有MMU,所以DMA傳輸時還是需要物理地址。

Linux把內核空間放在3G-4G,所以物理地址在內核態時與虛擬地址有個3G的偏移量。在用戶態時,則要根據進程的頁表進行映射,這個是寫時複製,如果不寫則與父進程共享。

x64的內存管理,等我研究明白了英特爾那4卷天書再補充(捂臉

這個圖來自英特爾的4卷天書,可以看出線性地址到物理地址的轉換過程。

2,段描述符,

段描述符的結構如下,它可以是全局描述符表GDT或者局部描述符表LDT裡的一項,可以有多個,每項8個字節。

段描述符

GDT:global descriptor table.

LDT:local descriptor table.

一般情況下,LDT表裡的段描述符要有代碼段、數據段、堆棧段。

GDT表裡除了代碼段、數據段、堆棧段之外,還要有LDT描述符、任務狀態段描述符,等等。

段描述符的結構都是大同小異的,分為3部分:基地址base、段限長limit、各種屬性欄位。

base是32位,limit是20位,都是分在了兩個4位元組整數裡,並不連續。

權限標誌都在第2個4位元組:

1)第23位,G,表示內存粒度的大小,置1表示4k,置0表示1位元組,所以20位的limit欄位可以表示2^20 * 4k = 2^20 * 2^12 = 2^32 = 4G內存空間。

段限長,表示段內的可以允許的最大索引號,是2^20 - 1,反正把第1個4位元組的低16位設置為0xff,第2個4位元組的16-19位設置為0xf,就行了。

2)13-14位,DPL,表示描述符的權限優先級,即所謂的ring0-ring3,內核段的這兩位都是0,用戶段的這兩位都是1(0b11 = 3),Linux不使用中間的ring1和ring2。

3)22位,D/B,默認操作數大小,在保護模式是32位,置1。

就算是64位代碼,默認操作數的大小也是32位。除了特別的指令之外,一般指令都是添加0x48前綴表示64位,添加0x66前綴表示16位。

4)15位,P,存在位,表示這個欄位正在內存裡,它是1時圖中的大多數項才有意義。

5)12位,S,表示是系統描述符(S = 0,任務、中斷等),還是代碼或者數據段描述符(S = 1)。

趙老師書裡的例子(第145頁),

代碼段的描述符是.quard 0x00 c0,9a 00,00 00,07 ff;

數據段的描述符是.quard 0x00 c0,92 00,00 00,07 ff。

前8位全是0,對應base的最高8位。

然後是c,即12,0b1100,對應23-20位,可以看出G為1(4k分頁),D/B為1(32位),L為0(不開啟64位模式),AVL 用戶可用欄位為0(OS暫時不使用它)。

然後是limit的高4位,也是0,即第2個8位是0xc0。

接下來的4位是9,0b1001,P為1(在內存裡),DPL為0(ring0),S為1(最後一位為1,表示是代碼或者數據段)。

最後8位是0x7ff,表示段的大小是2k個4k,即8M內存。0x7ff + 1=0x800=2048=2k。

6)8-11位,type欄位,在代碼段或者數據段裡,涉及到擴展方向、讀寫執行權限,見下圖。

數據段需要讀寫,所以第9位是1,8-11位組合一起是0x2。

代碼段需要執行,8-11位對應數字10,即0xa。

所以代碼段和數據段的8-16位,分別為0x9a和0x92。

3,任務管理,

任務相關的段描述符,屬於系統描述符,主要是任務狀態段TSS,它包含了任務的上下文信息,見下圖。

一堆寄存器,其中堆棧相關的SS和ESP分了3組,分別對應ring0 - ring2,在用戶態ring3不使用這個數據結構。

Linux的任務切換是軟切換,TSS結構只需要開始加載一次,之後整個系統內核和用戶進程都是當作一個任務來運行的(在CPU看來)。所以前段時間,Linus把英特爾懟了,說他們設計的機制太複雜,軟體開發人員不願意用:(

32位TSS的結構

趙老師書裡的例子,兩個任務的描述符分別是:

.word 0x68,tss0,0xe900,0x00;

.word 0x68,tss1,0xe900,0x00。

其中的tss0和tss1分別是兩個任務的TSS的地址,這幾個字節描述的就是上圖的TSS。

因為使用了.word而不是.quard,所以與前面的代碼段和數據段的排列是反著的。

0x68 = 104,即任務狀態段TSS的段限長limit,tss0是第一個任務的TSS地址,這個數據結構是寫在head.s裡的,偏移量不會超過16位,因為head.s的代碼很短。

0xe9,0xe = 0b1110對應P DPL S欄位,S=0表示是系統段,P=1表示在內存裡,DPL=3表示是ring3權限,即運行的代碼是用戶態的。

0x9,對應下圖的32-bit TSS,即這個描述符的類型。

最高的16位元組全0,說明tss0的地址最高位是0,內存粒度是按1位元組表示的,即0x68的長度限制是104位元組。

開啟分頁之後,系統要模擬從中斷中返回,把權限從ring0降到ring3,進入0號進程idle。

只要把中斷返回的地址設置為C語言寫的main()函數,之後就不需要用彙編了。

相關焦點

  • x86架構&linux內核系列(三)——我眼中的intel x86架構(一)
    我眼中的intel x86架構(一)——      上一篇有哥們說寫短啦,所以這一篇就寫長了些,結果長的都有點像裹腳布了。另一點,是為了裝逼,顯示筆者在圈子裡德高望重,字裡行間暗示自己是個老不死,呃,老衲是你爸爸的戰友……    可是摸著良心說,我真的不能算和x86伺服器很相熟。畢竟從前我是搞小機和存儲的。就借著之前的高度和相通的一些經驗來看待x86 intel架構吧。
  • 搞不清楚PowerPC、x86和ARM,別說你懂嵌入式!
    但是,對工程師而言,兼容8086的X86指令集一直是必須完成的任務。畢竟,兼容前代產品是使英特爾成長壯大起來的關鍵因素,而且還可以保護用戶原先的投資和使用數以百萬計應用軟體。 既然如此,為什麼又要放棄整個X86指令集重新開始呢?X86的不足在什麼地方?
  • ARM架構和X86架構二者之間的區別是什麼
    x86架構 X86架構(The X86 architecture)是微處理器執行的計算機語言指令集,指一個intel通用計算機系列的標準編號縮寫,也標識一套通用的計算機指令集合。 arm架構和x86架構的區別 一、性能 X86結構的電腦相比ARM架構的系統在性能方面要快得多、強得多。
  • Intel X86伺服器架構(十)封神路之MCE診斷
    上篇我畫了一幅圖: 昨天有位大哥問,學樸,你都是從哪裡總結的公眾號裡這些x86架構技術文檔?以後,我會儘量公開能公開的參考文檔。司內曾有同事問我要相關的intel的文檔。當我拿出相關文檔給他們時,居然有人質疑問什麼沒有中文的,我只能呵呵了。我只能說,像intel這樣的公司,除了為了照顧最終用戶,會將售前PPT資料或客戶報告翻譯成了中文以外,專業技術人員看的或者說真正有乾貨的技術文檔,一水兒的英文。若技術人員真的想接觸技術鮮貨,必須看英文原版。
  • 一文看懂arm架構和x86架構有什麼區別
    本文主要介紹的是arm架構和x86架構的區別,首先介紹了ARM架構圖,其次介紹了x86架構圖,最後從性能、擴展能力、作業系統的兼容性、軟體開發的方便性及可使用工具的多樣性及功耗這五個方面詳細的對比了arm架構和x86架構的區別,具體的跟隨小編一起來了解一下。
  • 回顧:Intel最令人難忘16款X86處理器
    它是第一款具備內存管理單元(MMU)的x86,可以管理虛擬內存。就像8086,它擁有一個浮點單元(FPU),但可以搭配x87協同處理器(80287)。    不過其他兩個版本也值得一提:SL是提供快取(外部)管理功能的第一款x86,以及用於太空計劃(哈伯望遠鏡使用這顆處理器)的386EX。
  • Intel換了CEO能做蘋果M1那樣的晶片嗎?PC處理器大小核反擊戰
    Venkata (Murthy)的離職就能夠從公司管理層面,顯現Intel對現狀的反思。本文篇幅較長,這裡給出導讀,讀者可根據自己的興趣,做選擇性閱讀。在Intel的定義中,Sunny Cove針對需要快速響應,以及與用戶體驗切身相關的線程;而Tremont則針對要求多線程性能的相關任務,以及需要在較高效模式下跑的非用戶相關後臺任務。比如視頻編碼工作,通常考慮用四個Tremont核心來跑,Windows後臺任務也交由Tremont完成;類似用戶點擊開始菜單、滾動網頁這種操作,要求快速響應,則交給Sunny Cove。
  • 驗證intel 8086K性能,高頻率、雙通道內存錦上添花
    入手intel 8086K處理器已經有很長時間了,裝機貼也和大家分享過。作為家裡的主力機一直用得很順手,無論是簡單的辦公,還是複雜的圖形處理以及3D遊戲都能勝任。當初入手這顆CPU主要就是看中了它具有特殊的意義,而且具備不俗的超頻潛力。我的這顆8086K可以在默認參數下超頻到全核4.8GHz,如果悉心調校相信還有不少的提升空間。
  • Intel警告:基於ARM的Win10設備x86模擬器是侵權
    6月10日消息,通過x86模擬器,微軟和高通讓基於ARM處理器的 PC有了運行x86軟體的可能性,但現在Intel警告到,這種行為是侵權的。IT之家Win10Intel法律總顧問日前表態稱,有些公司在沒有獲得X86授權的情況下試圖模擬Intel的X86指令集,顯然這是在暗指微軟和高通。高通近日宣布將跟合作夥伴推出基於驍龍處理器的Win10筆記本電腦,高通的ARM平臺可以同時運行桌面x86 Win32應用程式以及通用Windows應用程式。
  • FPGA+x86構建高性能國產網絡測試儀競技之道
    3、存儲系統靈活性x86+DPDK+網卡:x86系統面向通用計算,目前主流的內存系統是DDR4內存,帶寬大但是訪問延遲也大,根據讀寫訪問模式的不同,可能會帶有延遲抖動;FPGA+x86:FPGA的內存,可以根據需要組合片上RAM(可以實現cache功能)+DDR+QDR+RLDRAM等各種內存技術,優化帶寬需求型和延遲需求型訪問。
  • ARM vs x86 vs RISC-V,未來屬於誰?
    專家認為,儘管Intel的x86處理器在伺服器領域依然無敵,但64位的ARM構架應該可以找到自己的一席之地,ARM在內存和網絡接口同計算核心間的距離會被儘可能的拉近,並藉此承載起密度極高的大量計算進程,這種特性與Web伺服器及其應用十分契合。
  • 性能更強的SPARC和Power為啥鬥不過x86
    但時至今日,已經接近40歲的x86架構佔據了超過90%的伺服器市場。根源來看,是由於封閉系統和企業屬性不符,盲目的追求生態會讓推第三方到競爭對手的懷抱。這也是更開放的x86架構如今枝繁葉茂的原因。而x86則是採用了NUMA結構,CPU和內存分區,這就意味著在訪問自己部分的內存速度飛快,而其他部分內存速度要慢不少。也正是因此,4路以上的x86伺服器相對較少。硬體方面,Power系統在可靠性、可用性和可維護性的方面的出色表現使得 IBM從晶片到系統所設計的整機方案有著獨有的優勢。Power架構的處理器在超算、大型企業的UNIX伺服器等多個方面應用也十分成功。
  • 研究Intel IOMMU記錄
    這幾個patch做的工作就是解析bios通過acpi表(dmar標記的acpi表)提供給作業系統的iommu特性(一堆寄存器基地址,用來使能IOMMU功能,設置頁表基地址等)和針對pci設備,填入下面這張映射表,當設備進行dma時,對訪問的IOVA進行重定位。
  • 海盜船Lynnfield雙通道內存通過Intel XMP認證
    海盜船專為Core i7-870/860設計的雙通道4GB、8GB DDR3內存 通過Intel XMP認證全球高效能計算機與快閃記憶體產品領導廠商Corsair,今天宣布,包括4GB和8GB Dominator GT內存已通過英特爾Core i7-860和870平臺XMP技術的CPU Ready認證。
  • 如何快速讀取Mac進程的內存映射
    /usr/lib/ruby/1.9.1/x86_64-linux/enc/trans/transdb.so7f1d4484b000-7f1d4484c000 rw-p 00003000 00:14 14411  /usr/lib/ruby/1.9.1/x86_64-linux/enc/trans/transdb.so而在所有版本的Mac上,雖然內存映射的結構基本上是相同的
  • IO埠映射和IO內存映射(詳解S3C24XX_GPIO驅動)
    因為物理地址和總線地址相同,所以憑眼睛看是不能確定這個地址是用在哪兒的,它或者在內存中,或者是某個卡上的存儲單元,甚至可能這個地址上沒有對應的存儲器。3)虛擬地址:現代作業系統普遍採用虛擬內存管理(Virtual Memory Management)機制,這需要MMU(Memory Management Unit)的支持。
  • 安芯網盾:基於內存保護技術的主動防禦體系建設
    儘管企業和機構都部署了大量的安全防護產品,攻擊者仍然能夠輕而易舉的突破層層防線,複雜的網絡攻擊在不斷增加,現有的檢測防禦方案失效,成為企業在安全能力建設中的痛點。基於內存的攻擊難以防禦的四大原因:原因一:通過籤名技術無法識別基於內存的攻擊。基於籤名技術的大多數方法基於特徵匹配模式,無法識別基於內存的攻擊。
  • 谷歌發布x86 64位Android L模擬器
    谷歌已經發布了一款x86 64位Android模擬器,來幫助Android開發者創建64位應用程式。
  • 嵌入式Linux內存管理的一些知識點總結
    這個內存管理的知識點還真的需要我們專門的去理解一下,今天大家一起來學習學習嵌入式Linux內存管理的知識。1.不涉及linux內核的彙編知識,僅C語言層面解析1.回答:彙編主要處理的是寄存器地址(包括內容)的計算,進行一部分的地址轉換工作(當然,它是重要的);C語言處理了極大部分的系統內存管理工作。