多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > 服務器 > 一個操作系統的實現(8)-進一步體會分頁機制

一個操作系統的實現(8)-進一步體會分頁機制

來源:程序員人生   發布時間:2016-06-22 15:28:56 閱讀次數:3342次

上面的兩篇文章中,我們對可用內存進行了統計,并且公道的分配了頁表的大小。這節中,我們來看看分頁的好處

在此之前不知道你有無注意過1個細節,如果你寫1個程序(在Linux或Windows下都可),并改個名復制1份,然后同時調試,你會發現,從變量地址到寄存器的值,幾近全部都是1樣的!而這些“1樣的”地址之間完全不會混淆起來,而是各自完成著自己的職責。這就是分頁機制的功勞,下面我們就來摹擬1下這個效果。

線性地址到物理地址的映照

先履行某個線性地址處的模塊,然后通過改變cr3來轉換地址映照關系,再履行同1個線性地址處的模塊,由于地址映照已改變,所以兩次得到的應當是不同的輸出。

映照關系轉換前的情形以下圖所示:

開始,我們讓ProcPagingDemo中的代碼實現向LinearAddrDemo這個線性地址的轉移,而LinearAddrDemo映照到物理地址空間中
的ProcFoo處。我們讓ProcFoo打印出紅色的字符串Foo,所以履行時我們應當可以看到紅色的Foo。隨后我們改變地址映照關系,變
化成下圖所示的情形。

頁目錄表和頁表的切換讓LinearAddrDemo映照到ProcBar(物理地址空間)處,所以當我們再1次調用進程ProcPagingDemo時,程序將轉移到ProcBar處履行,我們將看到紅色的字符串Bar。

接下來看看新增的代碼:

改變映照關系的代碼實現

首先,我們用到了另外1套頁目錄表和頁表,所以本來的頁目錄段和頁表段已不再夠用了。事實上,前面的程序中我們用兩個段分別寄存頁目錄表和頁表,是為了讓我們瀏覽時更加直觀和形象。在接下來的程序中,我們把它們放到同1個段中,同時把增加的1套頁目錄和頁表也放到這個段中。

為了操作方便,我們新增加1個段,其線性地址空間為0~4GB。由于分頁機制啟動之前線性地址同等于物理地址,所以通過這個段可以方便地存取特定的物理地址。此段的代碼定義以下:

26 LABEL_DESC_FLAT_C: Descriptor 0, 0fffffh, DA_CR|DA_32|DA_LIMIT_4K; 0~4G 27 LABEL_DESC_FLAT_RW: Descriptor 0, 0fffffh, DA_DRW|DA_LIMIT_4K ; 0~4G ... 41 SelectorFlatC equ LABEL_DESC_FLAT_C - LABEL_GDT 42 SelectorFlatRW equ LABEL_DESC_FLAT_RW - LABEL_GDT

之所以用了兩個描寫符來描寫這個段,是由于我們不單單要讀寫這段內存,而且要履行其中的代碼,而這對描寫符的屬性要求是不1樣的。這兩個段的段基址都是0,長度都是4GB。

下面我們就將啟動分頁的代碼做相應的修改,以下所示:

257 ; 啟動分頁機制 -------------------------------------------------------------- 258 SetupPaging: 259 ; 根據內存大小計算應初始化多少PDE和多少頁表 260 xor edx, edx 261 mov eax, [dwMemSize] 262 mov ebx, 400000h ; 400000h = 4M = 4096 * 1024, 1個頁表對應的內存大小 263 div ebx 264 mov ecx, eax ; 此時 ecx 為頁表的個數,也即 PDE 應當的個數 265 test edx, edx 266 jz .no_remainder 267 inc ecx ; 如果余數不為 0 就需增加1個頁表 268 .no_remainder: 269 mov [PageTableNumber], ecx ; 暫存頁表個數 270 271 ; 為簡化處理, 所有線性地址對應相等的物理地址. 并且不斟酌內存空洞. 272 273 ; 首先初始化頁目錄 274 mov ax, SelectorFlatRW 275 mov es, ax 276 mov edi, PageDirBase0 ; 此段首地址為 PageDirBase0 277 xor eax, eax 278 mov eax, PageTblBase0 | PG_P | PG_USU | PG_RWW 279 .1: 280 stosd 281 add eax, 4096 ; 為了簡化, 所有頁表在內存中是連續的. 282 loop .1 283 284 ; 再初始化所有頁表 285 mov eax, [PageTableNumber] ; 頁表個數 286 mov ebx, 1024 ; 每一個頁表 1024 個 PTE 287 mul ebx 288 mov ecx, eax ; PTE個數 = 頁表個數 * 1024 289 mov edi, PageTblBase0 ; 此段首地址為 PageTblBase0 290 xor eax, eax 291 mov eax, PG_P | PG_USU | PG_RWW 292 .2: 293 stosd 294 add eax, 4096 ; 每頁指向 4K 的空間 295 loop .2 296 297 mov eax, PageDirBase0 298 mov cr3, eax 299 mov eax, cr0 300 or eax, 80000000h 301 mov cr0, eax 302 jmp short .3 303 .3: 304 nop 305 306 ret 307 ; 分頁機制啟動終了 ----------------------------------------------------------

我們原來并沒有把頁表個數保存起來,而現在情況產生了變化,我們不只有1個頁目錄和頁表,為了初始化另外的頁表時方便起見,在這里增加了1個變量PageTableNumber,頁表的個數就存在里面。

在全部初始化頁目錄和頁表的進程中,es始終為SelectorFlatRW。這樣,想存取物理地址的時候,只需將地址賦值給edi,那末es:edi指向的就是相應物理地址。比如頁目錄物理地址為PageDirBase0,第276即將edi賦值為PageDirBase0,es:edi因而指向地址PageDirBase0處,賦值通過指令stosd來實現。初始化頁表也是一樣的道理。

這樣,頁目錄和頁表的準備工作就完成了。不過我們不再在原來的位置調用它,而是新建1個函數PagingDemo,把所有與分頁有關的內容全都放進里面,這樣,程序看起來結構清晰1些。

根據上面兩幅圖,我們可以認為在這個程序的實現中有4個要關注的要素,分別是ProcPagingDemo、LinearAddrDemo、ProcFoo和ProcBar,我們把它們稱為F4。由于程序開始時LinearAddrDemo指向ProcFoo并且線性地址和物理地址是對等的,所以LinearAddrDemo應當等于ProcFoo。而ProcFoo和ProcBar應當是指定的物理地址,所以LinearAddrDemo也應當是指定的物理地址。也正由于如此,我們使用它們時應當確保使用的是FLAT段,即段選擇子應當是SelectorFlatC或SelectorFlatRW。

為了將我們的代碼放置在ProcFoo和ProcBar這兩處地方,我們先寫兩個函數,在程序運行時將這兩個函數的履行碼復制過去就能夠了。

ProcPagingDemo要調用FLAT段中的LinearAddrDemo,所以如果不想使用段間轉移,我們需要把ProcPagingDemo也放進FLAT段中。我們需要寫1個函數,然后把代碼復制到ProcPagingDemo處。

這樣看來,F4雖然都是當作函數來使用,但實際上卻都是內存中指定的地址。我們把它們定義為常量。以下:

13 LinearAddrDemo equ 00401000h 14 ProcFoo equ 00401000h 15 ProcBar equ 00501000h 16 ProcPagingDemo equ 00301000h

將代碼填充進這些內存地址的代碼就在上文我們提到的PagingDemo中,以下:

310 ; 測試分頁機制 -------------------------------------------------------------- 311 PagingDemo: 312 mov ax, cs 313 mov ds, ax 314 mov ax, SelectorFlatRW 315 mov es, ax 316 317 push LenFoo 318 push OffsetFoo 319 push ProcFoo 320 call MemCpy 321 add esp, 12 322 323 push LenBar 324 push OffsetBar 325 push ProcBar 326 call MemCpy 327 add esp, 12 328 329 push LenPagingDemoAll 330 push OffsetPagingDemoProc 331 push ProcPagingDemo 332 call MemCpy 333 add esp, 12 334 335 mov ax, SelectorData 336 mov ds, ax ; 數據段選擇子 337 mov es, ax 338 339 call SetupPaging ; 啟動分頁 340 341 call SelectorFlatC:ProcPagingDemo 342 call PSwitch ; 切換頁目錄,改變地址映照關系 343 call SelectorFlatC:ProcPagingDemo 344 345 ret 346 ; ---------------------------------------------------------------------------

其中用到了名為MemCpy的函數,它復制3個進程到指定的內存地址,類似于C語言中的memcpy。但有1點不同,它假定源數據放在ds段中,而目的在es段中。所以在函數的開頭,你可以找到分別為ds和es賦值的語句。MemCpy代碼以下:

131 ; ------------------------------------------------------------------------ 132 ; 內存拷貝,仿 memcpy 133 ; ------------------------------------------------------------------------ 134 ; void* MemCpy(void* es:pDest, void* ds:pSrc, int iSize); 135 ; ------------------------------------------------------------------------ 136 MemCpy: 137 push ebp 138 mov ebp, esp 139 140 push esi 141 push edi 142 push ecx 143 144 mov edi, [ebp + 8] ; Destination 145 mov esi, [ebp + 12] ; Source 146 mov ecx, [ebp + 16] ; Counter 147 .1: 148 cmp ecx, 0 ; 判斷計數器 149 jz .2 ; 計數器為零時跳出 150 151 mov al, [ds:esi] ; ┓ 152 inc esi ; ┃ 153 ; ┣ 逐字節移動 154 mov byte [es:edi], al ; ┃ 155 inc edi ; ┛ 156 157 dec ecx ; 計數器減1 158 jmp .1 ; 循環 159 .2: 160 mov eax, [ebp + 8] ; 返回值 161 162 pop ecx 163 pop edi 164 pop esi 165 mov esp, ebp 166 pop ebp 167 168 ret ; 函數結束,返回 169 ; MemCpy 結束-------------------------------------------------------------

被復制的3個進程以下:

402 PagingDemoProc: 403 OffsetPagingDemoProc equ PagingDemoProc - $$ 404 mov eax, LinearAddrDemo 405 call eax 406 retf 407 LenPagingDemoAll equ $ - PagingDemoProc 408 409 foo: 410 OffsetFoo equ foo - $$ 411 mov ah, 0Ch ; 0000: 黑底 1100: 紅字 412 mov al, 'F' 413 mov [gs:((80 * 17 + 0) * 2)], ax ; 屏幕第 17 行, 第 0 列。 414 mov al, 'o' 415 mov [gs:((80 * 17 + 1) * 2)], ax ; 屏幕第 17 行, 第 1 列。 416 mov [gs:((80 * 17 + 2) * 2)], ax ; 屏幕第 17 行, 第 2 列。 417 ret 418 LenFoo equ $ - foo 419 420 bar: 421 OffsetBar equ bar - $$ 422 mov ah, 0Ch ; 0000: 黑底 1100: 紅字 423 mov al, 'B' 424 mov [gs:((80 * 18 + 0) * 2)], ax ; 屏幕第 18 行, 第 0 列。 425 mov al, 'a' 426 mov [gs:((80 * 18 + 1) * 2)], ax ; 屏幕第 18 行, 第 1 列。 427 mov al, 'r' 428 mov [gs:((80 * 18 + 2) * 2)], ax ; 屏幕第 18 行, 第 2 列。 429 ret 430 LenBar equ $ - bar

接下來繼續看PagingDemo中的代碼,這部份代碼最重要的部份是4個call語句,以下:

339 call SetupPaging ; 啟動分頁 340 341 call SelectorFlatC:ProcPagingDemo 342 call PSwitch ; 切換頁目錄,改變地址映照關系 343 call SelectorFlatC:ProcPagingDemo

首先啟動分頁機制,然后調用ProcPagingDemo,再切換頁目錄,最后又調用1遍ProcPagingDemo。

現在ProcPagingDemo、ProcFoo和ProcBar的內容我們都已知道了,由于LinearAddrDemo和ProcFoo相等,并且函數SetupPaging建立起來的是對等的映照關系,所以第1次對ProcPagingDemo的調用反應的就是開始時的內存映照關系圖。

接下來看看調用的PSwitch:

349 ; 切換頁表 ------------------------------------------------------------------ 350 PSwitch: 351 ; 初始化頁目錄 352 mov ax, SelectorFlatRW 353 mov es, ax 354 mov edi, PageDirBase1 ; 此段首地址為 PageDirBase1 355 xor eax, eax 356 mov eax, PageTblBase1 | PG_P | PG_USU | PG_RWW 357 mov ecx, [PageTableNumber] 358 .1: 359 stosd 360 add eax, 4096 ; 為了簡化, 所有頁表在內存中是連續的. 361 loop .1 362 363 ; 再初始化所有頁表 364 mov eax, [PageTableNumber] ; 頁表個數 365 mov ebx, 1024 ; 每一個頁表 1024 個 PTE 366 mul ebx 367 mov ecx, eax ; PTE個數 = 頁表個數 * 1024 368 mov edi, PageTblBase1 ; 此段首地址為 PageTblBase1 369 xor eax, eax 370 mov eax, PG_P | PG_USU | PG_RWW 371 .2: 372 stosd 373 add eax, 4096 ; 每頁指向 4K 的空間 374 loop .2 375 376 ; 在此假定內存是大于 8M 的 377 mov eax, LinearAddrDemo 378 shr eax, 22 379 mov ebx, 4096 380 mul ebx 381 mov ecx, eax 382 mov eax, LinearAddrDemo 383 shr eax, 12 384 and eax, 03FFh ; 1111111111b (10 bits) 385 mov ebx, 4 386 mul ebx 387 add eax, ecx 388 add eax, PageTblBase1 389 mov dword [es:eax], ProcBar | PG_P | PG_USU | PG_RWW 390 391 mov eax, PageDirBase1 392 mov cr3, eax 393 jmp short .3 394 .3: 395 nop 396 397 ret 398 ; ---------------------------------------------------------------------------

這個函數前面初始化頁目錄表和頁表的進程與SetupPaging是差不多的,只是緊接著程序增加了改變線性地址LinearAddrDemo對應的物理地址的語句。改變后,LinearAddrDemo將不再對應ProcFoo,而是對應ProcBar。<font color=”red>具體是如何改變的,不是很懂

所以,此函數調用完成以后,對ProcPagingDemo的調用就變成了后來的映照關系圖。

在代碼PSwitch的后半部份,我們把cr3的值改成了PageDirBase1,這個切換進程宣布完成。

程序的運行情況以下:

我們看到紅色的Foo和Bar,這說明我們的頁表切換起作用了。其實,我們先條件到的不同進程有相同的地址,原理跟本例是類似的,也是在任務切換時通過改變cr3的值來切換頁目錄,從而改變地址映照關系。

這就是分頁的妙處。其實,妙處還不單單如此。由于分頁機制的存在,程序使用的都是線性地址空間,而不再直接是物理地址。這好像操作系統為利用程序提供了1個不依賴于硬件(物理內存)的平臺,利用程序沒必要關心實際上有多少物理內存,也沒必要關心正在使用的是哪1段內存,乃至沒必要關心某1個地址是在物理內存里面還是在硬盤中。總之,操作系統全權負責了這其中的轉換工作。

源代碼

; ========================================== ; pmtest8.asm ; 編譯方法:nasm pmtest8.asm -o pmtest8.com ; ========================================== %include "pm.inc" ; 常量, 宏, 和1些說明 PageDirBase0 equ 200000h ; 頁目錄開始地址: 2M PageTblBase0 equ 201000h ; 頁表開始地址: 2M + 4K PageDirBase1 equ 210000h ; 頁目錄開始地址: 2M + 64K PageTblBase1 equ 211000h ; 頁表開始地址: 2M + 64K + 4K LinearAddrDemo equ 00401000h ProcFoo equ 00401000h ProcBar equ 00501000h ProcPagingDemo equ 00301000h org 0100h jmp LABEL_BEGIN [SECTION .gdt] ; GDT ; 段基址, 段界限, 屬性 LABEL_GDT: Descriptor 0, 0, 0 ; 空描寫符 LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW ; Normal 描寫符 LABEL_DESC_FLAT_C: Descriptor 0, 0fffffh, DA_CR|DA_32|DA_LIMIT_4K; 0~4G LABEL_DESC_FLAT_RW: Descriptor 0, 0fffffh, DA_DRW|DA_LIMIT_4K ; 0~4G LABEL_DESC_CODE32: Descriptor 0, SegCode32Len⑴, DA_CR|DA_32 ; 非1致代碼段, 32 LABEL_DESC_CODE16: Descriptor 0, 0ffffh, DA_C ; 非1致代碼段, 16 LABEL_DESC_DATA: Descriptor 0, DataLen⑴, DA_DRW ; Data LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA|DA_32 ; Stack, 32 位 LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 顯存首地址 ; GDT 結束 GdtLen equ $ - LABEL_GDT ; GDT長度 GdtPtr dw GdtLen - 1 ; GDT界限 dd 0 ; GDT基地址 ; GDT 選擇子 SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT SelectorFlatC equ LABEL_DESC_FLAT_C - LABEL_GDT SelectorFlatRW equ LABEL_DESC_FLAT_RW - LABEL_GDT SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT SelectorData equ LABEL_DESC_DATA - LABEL_GDT SelectorStack equ LABEL_DESC_STACK - LABEL_GDT SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT ; END of [SECTION .gdt] [SECTION .data1] ; 數據段 ALIGN 32 [BITS 32] LABEL_DATA: ; 實模式下使用這些符號 ; 字符串 _szPMMessage: db "In Protect Mode now. ^-^", 0Ah, 0Ah, 0 ; 進入保護模式后顯示此字符串 _szMemChkTitle: db "BaseAddrL BaseAddrH LengthLow LengthHigh Type", 0Ah, 0 ; 進入保護模式后顯示此字符串 _szRAMSize db "RAM size:", 0 _szReturn db 0Ah, 0 ; 變量 _wSPValueInRealMode dw 0 _dwMCRNumber: dd 0 ; Memory Check Result _dwDispPos: dd (80 * 6 + 0) * 2 ; 屏幕第 6 行, 第 0 列。 _dwMemSize: dd 0 _ARDStruct: ; Address Range Descriptor Structure _dwBaseAddrLow: dd 0 _dwBaseAddrHigh: dd 0 _dwLengthLow: dd 0 _dwLengthHigh: dd 0 _dwType: dd 0 _PageTableNumber dd 0 _MemChkBuf: times 256 db 0 ; 保護模式下使用這些符號 szPMMessage equ _szPMMessage - $$ szMemChkTitle equ _szMemChkTitle - $$ szRAMSize equ _szRAMSize - $$ szReturn equ _szReturn - $$ dwDispPos equ _dwDispPos - $$ dwMemSize equ _dwMemSize - $$ dwMCRNumber equ _dwMCRNumber - $$ ARDStruct equ _ARDStruct - $$ dwBaseAddrLow equ _dwBaseAddrLow - $$ dwBaseAddrHigh equ _dwBaseAddrHigh - $$ dwLengthLow equ _dwLengthLow - $$ dwLengthHigh equ _dwLengthHigh - $$ dwType equ _dwType - $$ MemChkBuf equ _MemChkBuf - $$ PageTableNumber equ _PageTableNumber- $$ DataLen equ $ - LABEL_DATA ; END of [SECTION .data1] ; 全局堆棧段 [SECTION .gs] ALIGN 32 [BITS 32] LABEL_STACK: times 512 db 0 TopOfStack equ $ - LABEL_STACK - 1 ; END of [SECTION .gs] [SECTION .s16] [BITS 16] LABEL_BEGIN: mov ax, cs mov ds, ax mov es, ax mov ss, ax mov sp, 0100h mov [LABEL_GO_BACK_TO_REAL+3], ax mov [_wSPValueInRealMode], sp ; 得到內存數 mov ebx, 0 mov di, _MemChkBuf .loop: mov eax, 0E820h mov ecx, 20 mov edx, 0534D4150h int 15h jc LABEL_MEM_CHK_FAIL add di, 20 inc dword [_dwMCRNumber] cmp ebx, 0 jne .loop jmp LABEL_MEM_CHK_OK LABEL_MEM_CHK_FAIL: mov dword [_dwMCRNumber], 0 LABEL_MEM_CHK_OK: ; 初始化 16 位代碼段描寫符 mov ax, cs movzx eax, ax shl eax, 4 add eax, LABEL_SEG_CODE16 mov word [LABEL_DESC_CODE16 + 2], ax shr eax, 16 mov byte [LABEL_DESC_CODE16 + 4], al mov byte [LABEL_DESC_CODE16 + 7], ah ; 初始化 32 位代碼段描寫符 xor eax, eax mov ax, cs shl eax, 4 add eax, LABEL_SEG_CODE32 mov word [LABEL_DESC_CODE32 + 2], ax shr eax, 16 mov byte [LABEL_DESC_CODE32 + 4], al mov byte [LABEL_DESC_CODE32 + 7], ah ; 初始化數據段描寫符 xor eax, eax mov ax, ds shl eax, 4 add eax, LABEL_DATA mov word [LABEL_DESC_DATA + 2], ax shr eax, 16 mov byte [LABEL_DESC_DATA + 4], al mov byte [LABEL_DESC_DATA + 7], ah ; 初始化堆棧段描寫符 xor eax, eax mov ax, ds shl eax, 4 add eax, LABEL_STACK mov word [LABEL_DESC_STACK + 2], ax shr eax, 16 mov byte [LABEL_DESC_STACK + 4], al mov byte [LABEL_DESC_STACK + 7], ah ; 為加載 GDTR 作準備 xor eax, eax mov ax, ds shl eax, 4 add eax, LABEL_GDT ; eax <- gdt 基地址 mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址 ; 加載 GDTR lgdt [GdtPtr] ; 關中斷 cli ; 打開地址線A20 in al, 92h or al, 00000010b out 92h, al ; 準備切換到保護模式 mov eax, cr0 or eax, 1 mov cr0, eax ; 真正進入保護模式 jmp dword SelectorCode32:0 ; 履行這1句會把 SelectorCode32 裝入 cs, 并跳轉到 Code32Selector:0 處 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; LABEL_REAL_ENTRY: ; 從保護模式跳回到實模式就到了這里 mov ax, cs mov ds, ax mov es, ax mov ss, ax mov sp, [_wSPValueInRealMode] in al, 92h ; ┓ and al, 11111101b ; ┣ 關閉 A20 地址線 out 92h, al ; ┛ sti ; 開中斷 mov ax, 4c00h ; ┓ int 21h ; ┛回到 DOS ; END of [SECTION .s16] [SECTION .s32]; 32 位代碼段. 由實模式跳入. [BITS 32] LABEL_SEG_CODE32: mov ax, SelectorData mov ds, ax ; 數據段選擇子 mov es, ax mov ax, SelectorVideo mov gs, ax ; 視頻段選擇子 mov ax, SelectorStack mov ss, ax ; 堆棧段選擇子 mov esp, TopOfStack ; 下面顯示1個字符串 push szPMMessage call DispStr add esp, 4 push szMemChkTitle call DispStr add esp, 4 call DispMemSize ; 顯示內存信息 call PagingDemo ; 演示改變頁目錄的效果 ; 到此停止 jmp SelectorCode16:0 ; 啟動分頁機制 -------------------------------------------------------------- SetupPaging: ; 根據內存大小計算應初始化多少PDE和多少頁表 xor edx, edx mov eax, [dwMemSize] mov ebx, 400000h ; 400000h = 4M = 4096 * 1024, 1個頁表對應的內存大小 div ebx mov ecx, eax ; 此時 ecx 為頁表的個數,也即 PDE 應當的個數 test edx, edx jz .no_remainder inc ecx ; 如果余數不為 0 就需增加1個頁表 .no_remainder: mov [PageTableNumber], ecx ; 暫存頁表個數 ; 為簡化處理, 所有線性地址對應相等的物理地址. 并且不斟酌內存空洞. ; 首先初始化頁目錄 mov ax, SelectorFlatRW mov es, ax mov edi, PageDirBase0 ; 此段首地址為 PageDirBase0 xor eax, eax mov eax, PageTblBase0 | PG_P | PG_USU | PG_RWW .1: stosd add eax, 4096 ; 為了簡化, 所有頁表在內存中是連續的. loop .1 ; 再初始化所有頁表 mov eax, [PageTableNumber] ; 頁表個數 mov ebx, 1024 ; 每一個頁表 1024 個 PTE mul ebx mov ecx, eax ; PTE個數 = 頁表個數 * 1024 mov edi, PageTblBase0 ; 此段首地址為 PageTblBase0 xor eax, eax mov eax, PG_P | PG_USU | PG_RWW .2: stosd add eax, 4096 ; 每頁指向 4K 的空間 loop .2 mov eax, PageDirBase0 mov cr3, eax mov eax, cr0 or eax, 80000000h mov cr0, eax jmp short .3 .3: nop ret ; 分頁機制啟動終了 ---------------------------------------------------------- ; 測試分頁機制 -------------------------------------------------------------- PagingDemo: mov ax, cs mov ds, ax mov ax, SelectorFlatRW mov es, ax push LenFoo push OffsetFoo push ProcFoo call MemCpy add esp, 12 push LenBar push OffsetBar push ProcBar call MemCpy add esp, 12 push LenPagingDemoAll push OffsetPagingDemoProc push ProcPagingDemo call MemCpy add esp, 12 mov ax, SelectorData mov ds, ax ; 數據段選擇子 mov es, ax call SetupPaging ; 啟動分頁 call SelectorFlatC:ProcPagingDemo call PSwitch ; 切換頁目錄,改變地址映照關系 call SelectorFlatC:ProcPagingDemo ret ; --------------------------------------------------------------------------- ; 切換頁表 ------------------------------------------------------------------ PSwitch: ; 初始化頁目錄 mov ax, SelectorFlatRW mov es, ax mov edi, PageDirBase1 ; 此段首地址為 PageDirBase1 xor eax, eax mov eax, PageTblBase1 | PG_P | PG_USU | PG_RWW mov ecx, [PageTableNumber] .1: stosd add eax, 4096 ; 為了簡化, 所有頁表在內存中是連續的. loop .1 ; 再初始化所有頁表 mov eax, [PageTableNumber] ; 頁表個數 mov ebx, 1024 ; 每一個頁表 1024 個 PTE mul ebx mov ecx, eax ; PTE個數 = 頁表個數 * 1024 mov edi, PageTblBase1 ; 此段首地址為 PageTblBase1 xor eax, eax mov eax, PG_P | PG_USU | PG_RWW .2: stosd add eax, 4096 ; 每頁指向 4K 的空間 loop .2 ; 在此假定內存是大于 8M 的 mov eax, LinearAddrDemo shr eax, 22 mov ebx, 4096 mul ebx mov ecx, eax mov eax, LinearAddrDemo shr eax, 12 and eax, 03FFh ; 1111111111b (10 bits) mov ebx, 4 mul ebx add eax, ecx add eax, PageTblBase1 mov dword [es:eax], ProcBar | PG_P | PG_USU | PG_RWW mov eax, PageDirBase1 mov cr3, eax jmp short .3 .3: nop ret ; --------------------------------------------------------------------------- PagingDemoProc: OffsetPagingDemoProc equ PagingDemoProc - $$ mov eax, LinearAddrDemo call eax retf LenPagingDemoAll equ $ - PagingDemoProc foo: OffsetFoo equ foo - $$ mov ah, 0Ch ; 0000: 黑底 1100: 紅字 mov al, 'F' mov [gs:((80 * 17 + 0) * 2)], ax ; 屏幕第 17 行, 第 0 列。 mov al, 'o' mov [gs:((80 * 17 + 1) * 2)], ax ; 屏幕第 17 行, 第 1 列。 mov [gs:((80 * 17 + 2) * 2)], ax ; 屏幕第 17 行, 第 2 列。 ret LenFoo equ $ - foo bar: OffsetBar equ bar - $$ mov ah, 0Ch ; 0000: 黑底 1100: 紅字 mov al, 'B' mov [gs:((80 * 18 + 0) * 2)], ax ; 屏幕第 18 行, 第 0 列。 mov al, 'a' mov [gs:((80 * 18 + 1) * 2)], ax ; 屏幕第 18 行, 第 1 列。 mov al, 'r' mov [gs:((80 * 18 + 2) * 2)], ax ; 屏幕第 18 行, 第 2 列。 ret LenBar equ $ - bar ; 顯示內存信息 -------------------------------------------------------------- DispMemSize: push esi push edi push ecx mov esi, MemChkBuf mov ecx, [dwMCRNumber] ;for(int i=0;i<[MCRNumber];i++) // 每次得到1個ARDS(Address Range Descriptor Structure)結構 .loop: ;{ mov edx, 5 ; for(int j=0;j<5;j++) // 每次得到1個ARDS中的成員,共5個成員 mov edi, ARDStruct ; { // 順次顯示:BaseAddrLow,BaseAddrHigh,LengthLow,LengthHigh,Type .1: ; push dword [esi] ; call DispInt ; DispInt(MemChkBuf[j*4]); // 顯示1個成員 pop eax ; stosd ; ARDStruct[j*4] = MemChkBuf[j*4]; add esi, 4 ; dec edx ; cmp edx, 0 ; jnz .1 ; } call DispReturn ; printf("\n"); cmp dword [dwType], 1 ; if(Type == AddressRangeMemory) // AddressRangeMemory : 1, AddressRangeReserved : 2 jne .2 ; { mov eax, [dwBaseAddrLow] ; add eax, [dwLengthLow] ; cmp eax, [dwMemSize] ; if(BaseAddrLow + LengthLow > MemSize) jb .2 ; mov [dwMemSize], eax ; MemSize = BaseAddrLow + LengthLow; .2: ; } loop .loop ;} ; call DispReturn ;printf("\n"); push szRAMSize ; call DispStr ;printf("RAM size:"); add esp, 4 ; ; push dword [dwMemSize] ; call DispInt ;DispInt(MemSize); add esp, 4 ; pop ecx pop edi pop esi ret ; --------------------------------------------------------------------------- %include "lib.inc" ; 庫函數 SegCode32Len equ $ - LABEL_SEG_CODE32 ; END of [SECTION .s32] ; 16 位代碼段. 由 32 位代碼段跳入, 跳出后到實模式 [SECTION .s16code] ALIGN 32 [BITS 16] LABEL_SEG_CODE16: ; 跳回實模式: mov ax, SelectorNormal mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax mov eax, cr0 and eax, 7FFFFFFEh ; PE=0, PG=0 mov cr0, eax LABEL_GO_BACK_TO_REAL: jmp 0:LABEL_REAL_ENTRY ; 段地址會在程序開始處被設置成正確的值 Code16Len equ $ - LABEL_SEG_CODE16 ; END of [SECTION .s16code]
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 欧美最猛性xxxxx(亚洲精品) | 日本欧美久久久久免费播放网 | 亚洲网址 | 欧美成人精品福利在线视频 | 午夜影院在线观看 | 欧美激情视频一区二区三区 | 欧美日一区二区三区 | 在线免费h视频 | 国产精品一区高清在线观看 | 非洲黑人女bbwxxxx | free性欧美hd另类精品 | 亚洲精品在线网址 | 亚洲一区二区三区久久精品 | 国产性色强伦免费看视频 | 夜夜未满十八勿进的爽爽影院 | 欧美性猛交xxxxx按摩国内 | 久操网在线 | www.色午夜 | 日韩中文字幕久久精品 | www.av视频在线 | 欧美视频一 | 玖玖色资源 | 福利区在线观看 | 欧美一级永久免费毛片在线 | 国产精品成人扳一级aa毛片 | 亚洲视频在线免费看 | 性欧美video另类hd尤物 | 亚洲线精品久久一区二区三区 | 亚洲欧美日韩精品久久 | 色吊丝在线观看 | 毛片免费在线播放 | 一区二区三区四区在线免费观看 | 亚洲v天堂 | 国产专区一va亚洲v天堂 | 精品国产理论在线观看不卡 | 欧美 亚洲 校园 第一页 | 欧美乱码| 日韩 欧美 中文 | 日韩欧美一区二区三区不卡在线 | 美女精品永久福利在线 | 欧美69xxxhd|