【轉貼】PAE 在檔案中發現了這文章,可看性頗佳,就貼出了,原文是在2004年在TANET的程設語言板所取出的,作者是 CIH,應該大家都知道的人OK --------->開始 [code] 03 Jun 2004 , CIH 我只是單純以技術來探討這些問題. 若有錯誤的地方, 麻煩大家糾正. 感恩啦~~~ 1. 關於DOS/4GW. 時間: 我大二(約民國84年) 機器: 386 工具: 用softice去trace 能力背景: 那時寫過DOS extender 那年我有實務寫DOS extender的經驗, 靠自己的程式, 去動IDTR, GDTR, CR3等等system registers, 同時最後動CR0的PE, PG, 讓386從DOS下的real mode, 切到protected mode, 此刻可以定址4GB, 並支援MMU(因為我有enable PG), 一個page是4KB大小. 其定址方式, 是selector:offset. 這樣的DOS extender, 可以些許"相容", DOS/BIOS call, 也就是int 21h, int 13h等依然可以正常執行, 其原因, 我是把x86從protected mode切到V86 mode(此mode,依然在protected mode), 程式的寫法是利用iret從PM->V86, 切到V86 mode後, CPU是segment:offset定址方式(跟real mode一樣), 就可以正常呼叫這些DOS/BIOS call, 為了避免V86 mode下的程式讀取I/O產生GP, 所以那時我把IOPL(在cflag裡面)設成3, 以便讓ring 3權限的DOS/BIOS擁有完全I/O控制權(包括可以正常執行cli/sti等指令). 當然呼叫BIOS/DOS程式前, 我會去查IVT(位於phys addr最前面, 所謂中斷向量表), 然後取出16-bit segment, 以及16-bit offset, 並且把stack裡面CS/IP的值, 給一個我指定的address, 以便執行我給的非法指令, 產生非法指令exception, 才能再回到protected mode下. 那時也利用MMU, 把64KB限制的VGA, 拉成1MB. 同道理, DOS/4GW也是這樣, 我也trace過它. 之前是用watcom c++編譯的, 裡面有附所謂DOS/4GW這樣的dos extender. 它可以讓你在DOS下, 可以擁有4GB定址的能力, 同時DOS/BIOS call依然正常可以執行!! 原理也如我的做法一樣!! 倒是那時trace它, 若它發現沒有DPMI存在, 就會自己動CR0, 若存在的話, 會靠DPMI協助, 切到protected mode. 不過此刻是16-bit segment定址方式, 無法access到4GB, 最後它會配置32-bit Segment Descriptor, 最後才可以存取到4GB. 2. 關於386定址, CPU定址最大是4GB. 因為segment, page記憶體管理描述表, 只能存取最大到4GB. 或許很多人有看過一些資料, 會看過64TB, 這樣的數據, 這是因為GDT/LDT這些表最大共有2^14=16384個(16-bit的selector減去2-bit的RPL), 也就是最大可以指16384個segment, 而每個segment最大是4GB, 故16384x4GB=65536GB=64TB. 286已經有protected mode, 不過是16-bit protected mode. 從386以後, 就有32-bit protected mode. 3. 在x86 CPU上, 以Windows/Linux Kernel而言, 目前對memory的保護方式, 是不透過segment那一層(ring0-ring3), 而是透過page來保護(只有兩種權限user/kernel). 4. 至於現在"聽說"有些x86版子可以插到大於4GB的RAM, 同時OS依然可以存取到所有RAM, 為何呢!?? 我已經脫離這領域很久了, 也不知道為何現在可以access超過4GB的physically address. 也非常好奇, 剛剛查詢一下網路... ========================= 以下內容,我沒有實際寫過這樣的東西, 單純從網路文件得知, 看完後的心得. ========================= 果真, 從Pentium以後, 就有36位元的定址能力. 當CR4的PAE啟動後, 其page的轉換方式, 就跟之前386不同. 簡單而言, 那些分頁目錄(PDE), 分頁表(PTE), 原本在386下, 只能定址到2^32=4GB, 現在全部可以定址到2^36=64GB. 那我們真的擁有64GB的定址空間嗎!??? 對, 我們可以定址到64GB, 不過呢, 從邏輯位址(selector:offset, 例如CS:EIP或是DS:ESI), 其EIP以及ESI等等暫存器, 全是32-bit, 最大只能到4GB. 再透過segment這一層, 轉換成32-bit linear address, 最後透過這個所謂"36-bit" page轉換後, 就可以定址64GB內, 任意的最大4GB空間. 也就是, 簡單形容一下, 雖然整個空間是64GB, 不過, 我們依然最大最大只能擁有4GB大小的window, 只能利用這個4GB window在64GB中移動. 舉個例子, 31GB到35GB 32GB到36GB 對程式而言, 依然只能看到最大4GB, 不過這個最大4GB, 可能坐落在整個64GB任何一塊. 大致上是這樣, 有興趣的人, 可以上網找資料, 研究一下~~~ Bless you~~ -------------------------------------------------------------------------------- 根據之前我寫的文章, 我再補充一下, 在x86 Pentium系列後(根據網路文章描述,我沒徹底考證過), 啟動PAE後, 那到底程式(可能kernel/driver/AP), 擁有是4GB的最大空間, 還是64GB的最大空間!?? "假設"板子上插了64GB的RAM. 因為所有程式(無論user mode/kernel mode), 都要透過第一層的segment把邏輯位址selector:offset(32-bit), 轉換成32-bit linear address, 再透過第二層所謂36-bit page轉換後, 最大可以定址64GB裡面的4GB大小. 是故, 無論如何, 最大只能定址4GB. 不過, 假設OS(有ring 0權限), 有個function可以去設定page相關tables, 隨意讓其它程式呼叫(包括ring 3), 並重新remap linear address與physically address的對應關係. 若此function叫做"4GB_Linear_To_Phys". 若, 4GB_Linear_To_Phys(0) ==> 0-4GB(linear)就是 0-4GB(physically address). 4GB_Linear_To_Phys(1) ==> 0-4GB(linear)就是 4-8GB(physically address). .. 4GB_Linear_To_Phys(15) ==> 0-4GB(linear)就是60-64GB(physically address). 因此, 我們可以讓ring 3程式, 可以access到整個64GB的RAM. 簡易程式如下: unsigned char *p = NULL; for ( i = 0 ; i < 16 ; i++ ) { 4GB_Linear_To_Phys(i); p = 0; do { c = *p; p++; } while ( p != 0 ); } 當然, 以上程式, 基本上, 我認為, 不可能~~~~ 對OS很困擾, 是個不可能的做法!!!!!! 當然硬要幹的話, 一定也可以!!! 其原因是, 一但整個4GB被重新map, 把linear address的4GB, 對應到不同的4GB大小physically address. 此刻程式, 包括OS本身, 整個系統立刻死掉!! 假設, 我們的, 0-4GB(linear)就是 0-4GB(physically address). 若AP在linear address的1M, OS在linear address的3GB. 所以當然AP在phys addr的1M, OS在phys addr的3GB. P.S 此刻我是指所謂4GB flat mode. 若此時, ring 3的AP, 呼叫 4GB_Linear_To_Phys(1); 沒做特別處理前, 若直接切page, 這時, 0-4GB(linear)就是 4-8GB(physically address). 而4-8GB(physically address)根本沒有任何程式碼, 資料, 完全空的!! 當然0-4GB(linear)也是空的, 因此立刻整個系統, 徹底死掉!!!!! 所以我們的4GB_Linear_To_Phys這個function, 一開始就得把相關AP, OS, 以及所有使用的記憶體, 全部相對應copy到RAM(phys addr)的4GB-8GB. 最後才去更改page對應. 因此這樣function, 根本不可能真正運用在OS, 不可能這樣做!!! 若是某個白爛OS, 硬這樣的話, 我認了!!!! 不過倒是kernel可以提供這樣的function, 例如: 256MB_Linear_To_Phys, virt=256MB_Linear_To_Phys(0) ==> virt到virt+256M(linear)就是 0-256MB(physically address). virt=256MB_Linear_To_Phys(1) ==> virt到virt+256M(linear)就是 256MB-512MB(physically address). virt=256MB_Linear_To_Phys(2) ==> virt到virt+256M(linear)就是 512MB-768MB(physically address). 依此類推... 這樣的做法, 絕對性沒問題!!! 只要kernel(ring 0), 有提供如此function, AP就可以透過上面那樣程式, 一個迴圈的程式, 可以讀取到整個64GB的RAM. 大致上是這樣, 希望能提供大家清晰的觀念與幫助~~~ 感恩啦~~~~ -------------------------------------------------------------------------------- 最後再補充一下我小小的想法, x86 Pentium以後系列, 啟動PAE後, 事實上, 還是定址最大4GB, 只是這個4GB是位於64GB以內任何一段. 當然, 如我之前文章所提, 若OS有提供修改page tables之類的function, 依然AP可以 "間接" 讀取到整個64GB!! 所以, 那到底一個AP最大定址空間是4GB, 還是64GB!???? 我也不知道, 這些文字的"定義"是如何~~~~~ 倒是我還是偏向於, 程式最大是定址4GB大小, 只是若OS有提供特殊system call, 則可以透過這樣function, 利用這個window, "間接" 存取到64GB. 結論: 我實在不知道這個"最大定址空間大小"中文正確意義是什麼, 或許其他人會比較清楚. 那, 若要改變x86 Pentium CPU, 徹底一次定址到64GB的話, 也就是只要ds:esi這樣一行組合語言指令, 就可以access到0-64GB. 我們該怎麼作!? 個人想法: 1. registers要變成36-bit(如: eip, esi, esp等) 2. Segment Descriptor 此table, 原本其中兩個欄位, base address以及segment limit各是32-bit, 必須都改成36-bit, 才能把selector(16-bit):offset(36-bit)這個邏輯位址, 轉成36-bit linear address. P.S base address這一欄, 事實上, 在我們這個舉例中, 可以不用變. 重要的是, segment limit一定要36-bit. 3. Page轉換這一層, 要重新定義, 重改. 原本x86 Pentium系列, 啟動PAE後, 是有能力把32-bit linear address, 透過我叫做"所謂"36-bit page的轉換. 不過, 轉換成32-bit phys addr, 依然最大只能定址4GB, 只不過此4GB(2^32)是位於64GB(2^36)裡面的一個window. 是故, 此架構, 要全改. 變成有能力, 把36-bit linear address, 轉換成36-bit phys addr. 大概這樣, 奔忙中, 沒空看這個板, 以後有空, 再聊我實際寫這類程式的經驗~~~~ 再次感恩啦~~~ [/code] |
所有時間均為 +8。現在的時間是 09:50 PM。 |
XML | RSS 2.0 | RSS |
本論壇所有文章僅代表留言者個人意見,並不代表本站之立場,討論區以「即時留言」方式運作,故無法完全監察所有即時留言,若您發現文章可能有異議,請 email :[email protected] 處理。