日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國(guó)內(nèi)最全I(xiàn)T社區(qū)平臺(tái) 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁(yè) > 服務(wù)器 > 一個(gè)操作系統(tǒng)的實(shí)現(xiàn)(8)-進(jìn)一步體會(huì)分頁(yè)機(jī)制

一個(gè)操作系統(tǒng)的實(shí)現(xiàn)(8)-進(jìn)一步體會(huì)分頁(yè)機(jī)制

來(lái)源:程序員人生   發(fā)布時(shí)間:2016-06-22 15:28:56 閱讀次數(shù):3348次

上面的兩篇文章中,我們對(duì)可用內(nèi)存進(jìn)行了統(tǒng)計(jì),并且公道的分配了頁(yè)表的大小。這節(jié)中,我們來(lái)看看分頁(yè)的好處

在此之前不知道你有無(wú)注意過(guò)1個(gè)細(xì)節(jié),如果你寫1個(gè)程序(在Linux或Windows下都可),并改個(gè)名復(fù)制1份,然后同時(shí)調(diào)試,你會(huì)發(fā)現(xiàn),從變量地址到寄存器的值,幾近全部都是1樣的!而這些“1樣的”地址之間完全不會(huì)混淆起來(lái),而是各自完成著自己的職責(zé)。這就是分頁(yè)機(jī)制的功勞,下面我們就來(lái)摹擬1下這個(gè)效果。

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

先履行某個(gè)線性地址處的模塊,然后通過(guò)改變cr3來(lái)轉(zhuǎn)換地址映照關(guān)系,再履行同1個(gè)線性地址處的模塊,由于地址映照已改變,所以兩次得到的應(yīng)當(dāng)是不同的輸出。

映照關(guān)系轉(zhuǎn)換前的情形以下圖所示:

開(kāi)始,我們讓ProcPagingDemo中的代碼實(shí)現(xiàn)向LinearAddrDemo這個(gè)線性地址的轉(zhuǎn)移,而LinearAddrDemo映照到物理地址空間中
的ProcFoo處。我們讓ProcFoo打印出紅色的字符串Foo,所以履行時(shí)我們應(yīng)當(dāng)可以看到紅色的Foo。隨后我們改變地址映照關(guān)系,變
化成下圖所示的情形。

頁(yè)目錄表和頁(yè)表的切換讓LinearAddrDemo映照到ProcBar(物理地址空間)處,所以當(dāng)我們?cè)?次調(diào)用進(jìn)程ProcPagingDemo時(shí),程序?qū)⑥D(zhuǎn)移到ProcBar處履行,我們將看到紅色的字符串Bar。

接下來(lái)看看新增的代碼:

改變映照關(guān)系的代碼實(shí)現(xiàn)

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

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

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

之所以用了兩個(gè)描寫符來(lái)描寫這個(gè)段,是由于我們不單單要讀寫這段內(nèi)存,而且要履行其中的代碼,而這對(duì)描寫符的屬性要求是不1樣的。這兩個(gè)段的段基址都是0,長(zhǎng)度都是4GB。

下面我們就將啟動(dòng)分頁(yè)的代碼做相應(yīng)的修改,以下所示:

257 ; 啟動(dòng)分頁(yè)機(jī)制 -------------------------------------------------------------- 258 SetupPaging: 259 ; 根據(jù)內(nèi)存大小計(jì)算應(yīng)初始化多少PDE和多少頁(yè)表 260 xor edx, edx 261 mov eax, [dwMemSize] 262 mov ebx, 400000h ; 400000h = 4M = 4096 * 1024, 1個(gè)頁(yè)表對(duì)應(yīng)的內(nèi)存大小 263 div ebx 264 mov ecx, eax ; 此時(shí) ecx 為頁(yè)表的個(gè)數(shù),也即 PDE 應(yīng)當(dāng)?shù)膫€(gè)數(shù) 265 test edx, edx 266 jz .no_remainder 267 inc ecx ; 如果余數(shù)不為 0 就需增加1個(gè)頁(yè)表 268 .no_remainder: 269 mov [PageTableNumber], ecx ; 暫存頁(yè)表個(gè)數(shù) 270 271 ; 為簡(jiǎn)化處理, 所有線性地址對(duì)應(yīng)相等的物理地址. 并且不斟酌內(nèi)存空洞. 272 273 ; 首先初始化頁(yè)目錄 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 ; 為了簡(jiǎn)化, 所有頁(yè)表在內(nèi)存中是連續(xù)的. 282 loop .1 283 284 ; 再初始化所有頁(yè)表 285 mov eax, [PageTableNumber] ; 頁(yè)表個(gè)數(shù) 286 mov ebx, 1024 ; 每一個(gè)頁(yè)表 1024 個(gè) PTE 287 mul ebx 288 mov ecx, eax ; PTE個(gè)數(shù) = 頁(yè)表個(gè)數(shù) * 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 ; 每頁(yè)指向 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 ; 分頁(yè)機(jī)制啟動(dòng)終了 ----------------------------------------------------------

我們?cè)瓉?lái)并沒(méi)有把頁(yè)表個(gè)數(shù)保存起來(lái),而現(xiàn)在情況產(chǎn)生了變化,我們不只有1個(gè)頁(yè)目錄和頁(yè)表,為了初始化另外的頁(yè)表時(shí)方便起見(jiàn),在這里增加了1個(gè)變量PageTableNumber,頁(yè)表的個(gè)數(shù)就存在里面。

在全部初始化頁(yè)目錄和頁(yè)表的進(jìn)程中,es始終為SelectorFlatRW。這樣,想存取物理地址的時(shí)候,只需將地址賦值給edi,那末es:edi指向的就是相應(yīng)物理地址。比如頁(yè)目錄物理地址為PageDirBase0,第276即將edi賦值為PageDirBase0,es:edi因而指向地址PageDirBase0處,賦值通過(guò)指令stosd來(lái)實(shí)現(xiàn)。初始化頁(yè)表也是一樣的道理。

這樣,頁(yè)目錄和頁(yè)表的準(zhǔn)備工作就完成了。不過(guò)我們不再在原來(lái)的位置調(diào)用它,而是新建1個(gè)函數(shù)PagingDemo,把所有與分頁(yè)有關(guān)的內(nèi)容全都放進(jìn)里面,這樣,程序看起來(lái)結(jié)構(gòu)清晰1些。

根據(jù)上面兩幅圖,我們可以認(rèn)為在這個(gè)程序的實(shí)現(xiàn)中有4個(gè)要關(guān)注的要素,分別是ProcPagingDemo、LinearAddrDemo、ProcFoo和ProcBar,我們把它們稱為F4。由于程序開(kāi)始時(shí)LinearAddrDemo指向ProcFoo并且線性地址和物理地址是對(duì)等的,所以LinearAddrDemo應(yīng)當(dāng)?shù)扔赑rocFoo。而ProcFoo和ProcBar應(yīng)當(dāng)是指定的物理地址,所以LinearAddrDemo也應(yīng)當(dāng)是指定的物理地址。也正由于如此,我們使用它們時(shí)應(yīng)當(dāng)確保使用的是FLAT段,即段選擇子應(yīng)當(dāng)是SelectorFlatC或SelectorFlatRW。

為了將我們的代碼放置在ProcFoo和ProcBar這兩處地方,我們先寫兩個(gè)函數(shù),在程序運(yùn)行時(shí)將這兩個(gè)函數(shù)的履行碼復(fù)制過(guò)去就能夠了。

ProcPagingDemo要調(diào)用FLAT段中的LinearAddrDemo,所以如果不想使用段間轉(zhuǎn)移,我們需要把ProcPagingDemo也放進(jìn)FLAT段中。我們需要寫1個(gè)函數(shù),然后把代碼復(fù)制到ProcPagingDemo處。

這樣看來(lái),F4雖然都是當(dāng)作函數(shù)來(lái)使用,但實(shí)際上卻都是內(nèi)存中指定的地址。我們把它們定義為常量。以下:

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

將代碼填充進(jìn)這些內(nèi)存地址的代碼就在上文我們提到的PagingDemo中,以下:

310 ; 測(cè)試分頁(yè)機(jī)制 -------------------------------------------------------------- 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 ; 數(shù)據(jù)段選擇子 337 mov es, ax 338 339 call SetupPaging ; 啟動(dòng)分頁(yè) 340 341 call SelectorFlatC:ProcPagingDemo 342 call PSwitch ; 切換頁(yè)目錄,改變地址映照關(guān)系 343 call SelectorFlatC:ProcPagingDemo 344 345 ret 346 ; ---------------------------------------------------------------------------

其中用到了名為MemCpy的函數(shù),它復(fù)制3個(gè)進(jìn)程到指定的內(nèi)存地址,類似于C語(yǔ)言中的memcpy。但有1點(diǎn)不同,它假定源數(shù)據(jù)放在ds段中,而目的在es段中。所以在函數(shù)的開(kāi)頭,你可以找到分別為ds和es賦值的語(yǔ)句。MemCpy代碼以下:

131 ; ------------------------------------------------------------------------ 132 ; 內(nèi)存拷貝,仿 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 ; 判斷計(jì)數(shù)器 149 jz .2 ; 計(jì)數(shù)器為零時(shí)跳出 150 151 mov al, [ds:esi] ; ┓ 152 inc esi ; ┃ 153 ; ┣ 逐字節(jié)移動(dòng) 154 mov byte [es:edi], al ; ┃ 155 inc edi ; ┛ 156 157 dec ecx ; 計(jì)數(shù)器減1 158 jmp .1 ; 循環(huán) 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 ; 函數(shù)結(jié)束,返回 169 ; MemCpy 結(jié)束-------------------------------------------------------------

被復(fù)制的3個(gè)進(jìn)程以下:

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

接下來(lái)繼續(xù)看PagingDemo中的代碼,這部份代碼最重要的部份是4個(gè)call語(yǔ)句,以下:

339 call SetupPaging ; 啟動(dòng)分頁(yè) 340 341 call SelectorFlatC:ProcPagingDemo 342 call PSwitch ; 切換頁(yè)目錄,改變地址映照關(guān)系 343 call SelectorFlatC:ProcPagingDemo

首先啟動(dòng)分頁(yè)機(jī)制,然后調(diào)用ProcPagingDemo,再切換頁(yè)目錄,最后又調(diào)用1遍ProcPagingDemo。

現(xiàn)在ProcPagingDemo、ProcFoo和ProcBar的內(nèi)容我們都已知道了,由于LinearAddrDemo和ProcFoo相等,并且函數(shù)SetupPaging建立起來(lái)的是對(duì)等的映照關(guān)系,所以第1次對(duì)ProcPagingDemo的調(diào)用反應(yīng)的就是開(kāi)始時(shí)的內(nèi)存映照關(guān)系圖。

接下來(lái)看看調(diào)用的PSwitch:

349 ; 切換頁(yè)表 ------------------------------------------------------------------ 350 PSwitch: 351 ; 初始化頁(yè)目錄 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 ; 為了簡(jiǎn)化, 所有頁(yè)表在內(nèi)存中是連續(xù)的. 361 loop .1 362 363 ; 再初始化所有頁(yè)表 364 mov eax, [PageTableNumber] ; 頁(yè)表個(gè)數(shù) 365 mov ebx, 1024 ; 每一個(gè)頁(yè)表 1024 個(gè) PTE 366 mul ebx 367 mov ecx, eax ; PTE個(gè)數(shù) = 頁(yè)表個(gè)數(shù) * 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 ; 每頁(yè)指向 4K 的空間 374 loop .2 375 376 ; 在此假定內(nèi)存是大于 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 ; ---------------------------------------------------------------------------

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

所以,此函數(shù)調(diào)用完成以后,對(duì)ProcPagingDemo的調(diào)用就變成了后來(lái)的映照關(guān)系圖。

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

程序的運(yùn)行情況以下:

我們看到紅色的Foo和Bar,這說(shuō)明我們的頁(yè)表切換起作用了。其實(shí),我們先條件到的不同進(jìn)程有相同的地址,原理跟本例是類似的,也是在任務(wù)切換時(shí)通過(guò)改變cr3的值來(lái)切換頁(yè)目錄,從而改變地址映照關(guān)系。

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

源代碼

; ========================================== ; pmtest8.asm ; 編譯方法:nasm pmtest8.asm -o pmtest8.com ; ========================================== %include "pm.inc" ; 常量, 宏, 和1些說(shuō)明 PageDirBase0 equ 200000h ; 頁(yè)目錄開(kāi)始地址: 2M PageTblBase0 equ 201000h ; 頁(yè)表開(kāi)始地址: 2M + 4K PageDirBase1 equ 210000h ; 頁(yè)目錄開(kāi)始地址: 2M + 64K PageTblBase1 equ 211000h ; 頁(yè)表開(kāi)始地址: 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 結(jié)束 GdtLen equ $ - LABEL_GDT ; GDT長(zhǎng)度 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] ; 數(shù)據(jù)段 ALIGN 32 [BITS 32] LABEL_DATA: ; 實(shí)模式下使用這些符號(hào) ; 字符串 _szPMMessage: db "In Protect Mode now. ^-^", 0Ah, 0Ah, 0 ; 進(jìn)入保護(hù)模式后顯示此字符串 _szMemChkTitle: db "BaseAddrL BaseAddrH LengthLow LengthHigh Type", 0Ah, 0 ; 進(jìn)入保護(hù)模式后顯示此字符串 _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 ; 保護(hù)模式下使用這些符號(hào) 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 ; 得到內(nèi)存數(shù) 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 ; 初始化數(shù)據(jù)段描寫符 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 作準(zhǔn)備 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] ; 關(guān)中斷 cli ; 打開(kāi)地址線A20 in al, 92h or al, 00000010b out 92h, al ; 準(zhǔn)備切換到保護(hù)模式 mov eax, cr0 or eax, 1 mov cr0, eax ; 真正進(jìn)入保護(hù)模式 jmp dword SelectorCode32:0 ; 履行這1句會(huì)把 SelectorCode32 裝入 cs, 并跳轉(zhuǎn)到 Code32Selector:0 處 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; LABEL_REAL_ENTRY: ; 從保護(hù)模式跳回到實(shí)模式就到了這里 mov ax, cs mov ds, ax mov es, ax mov ss, ax mov sp, [_wSPValueInRealMode] in al, 92h ; ┓ and al, 11111101b ; ┣ 關(guān)閉 A20 地址線 out 92h, al ; ┛ sti ; 開(kāi)中斷 mov ax, 4c00h ; ┓ int 21h ; ┛回到 DOS ; END of [SECTION .s16] [SECTION .s32]; 32 位代碼段. 由實(shí)模式跳入. [BITS 32] LABEL_SEG_CODE32: mov ax, SelectorData mov ds, ax ; 數(shù)據(jù)段選擇子 mov es, ax mov ax, SelectorVideo mov gs, ax ; 視頻段選擇子 mov ax, SelectorStack mov ss, ax ; 堆棧段選擇子 mov esp, TopOfStack ; 下面顯示1個(gè)字符串 push szPMMessage call DispStr add esp, 4 push szMemChkTitle call DispStr add esp, 4 call DispMemSize ; 顯示內(nèi)存信息 call PagingDemo ; 演示改變頁(yè)目錄的效果 ; 到此停止 jmp SelectorCode16:0 ; 啟動(dòng)分頁(yè)機(jī)制 -------------------------------------------------------------- SetupPaging: ; 根據(jù)內(nèi)存大小計(jì)算應(yīng)初始化多少PDE和多少頁(yè)表 xor edx, edx mov eax, [dwMemSize] mov ebx, 400000h ; 400000h = 4M = 4096 * 1024, 1個(gè)頁(yè)表對(duì)應(yīng)的內(nèi)存大小 div ebx mov ecx, eax ; 此時(shí) ecx 為頁(yè)表的個(gè)數(shù),也即 PDE 應(yīng)當(dāng)?shù)膫€(gè)數(shù) test edx, edx jz .no_remainder inc ecx ; 如果余數(shù)不為 0 就需增加1個(gè)頁(yè)表 .no_remainder: mov [PageTableNumber], ecx ; 暫存頁(yè)表個(gè)數(shù) ; 為簡(jiǎn)化處理, 所有線性地址對(duì)應(yīng)相等的物理地址. 并且不斟酌內(nèi)存空洞. ; 首先初始化頁(yè)目錄 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 ; 為了簡(jiǎn)化, 所有頁(yè)表在內(nèi)存中是連續(xù)的. loop .1 ; 再初始化所有頁(yè)表 mov eax, [PageTableNumber] ; 頁(yè)表個(gè)數(shù) mov ebx, 1024 ; 每一個(gè)頁(yè)表 1024 個(gè) PTE mul ebx mov ecx, eax ; PTE個(gè)數(shù) = 頁(yè)表個(gè)數(shù) * 1024 mov edi, PageTblBase0 ; 此段首地址為 PageTblBase0 xor eax, eax mov eax, PG_P | PG_USU | PG_RWW .2: stosd add eax, 4096 ; 每頁(yè)指向 4K 的空間 loop .2 mov eax, PageDirBase0 mov cr3, eax mov eax, cr0 or eax, 80000000h mov cr0, eax jmp short .3 .3: nop ret ; 分頁(yè)機(jī)制啟動(dòng)終了 ---------------------------------------------------------- ; 測(cè)試分頁(yè)機(jī)制 -------------------------------------------------------------- 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 ; 數(shù)據(jù)段選擇子 mov es, ax call SetupPaging ; 啟動(dòng)分頁(yè) call SelectorFlatC:ProcPagingDemo call PSwitch ; 切換頁(yè)目錄,改變地址映照關(guān)系 call SelectorFlatC:ProcPagingDemo ret ; --------------------------------------------------------------------------- ; 切換頁(yè)表 ------------------------------------------------------------------ PSwitch: ; 初始化頁(yè)目錄 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 ; 為了簡(jiǎn)化, 所有頁(yè)表在內(nèi)存中是連續(xù)的. loop .1 ; 再初始化所有頁(yè)表 mov eax, [PageTableNumber] ; 頁(yè)表個(gè)數(shù) mov ebx, 1024 ; 每一個(gè)頁(yè)表 1024 個(gè) PTE mul ebx mov ecx, eax ; PTE個(gè)數(shù) = 頁(yè)表個(gè)數(shù) * 1024 mov edi, PageTblBase1 ; 此段首地址為 PageTblBase1 xor eax, eax mov eax, PG_P | PG_USU | PG_RWW .2: stosd add eax, 4096 ; 每頁(yè)指向 4K 的空間 loop .2 ; 在此假定內(nèi)存是大于 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 ; 顯示內(nèi)存信息 -------------------------------------------------------------- DispMemSize: push esi push edi push ecx mov esi, MemChkBuf mov ecx, [dwMCRNumber] ;for(int i=0;i<[MCRNumber];i++) // 每次得到1個(gè)ARDS(Address Range Descriptor Structure)結(jié)構(gòu) .loop: ;{ mov edx, 5 ; for(int j=0;j<5;j++) // 每次得到1個(gè)ARDS中的成員,共5個(gè)成員 mov edi, ARDStruct ; { // 順次顯示:BaseAddrLow,BaseAddrHigh,LengthLow,LengthHigh,Type .1: ; push dword [esi] ; call DispInt ; DispInt(MemChkBuf[j*4]); // 顯示1個(gè)成員 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" ; 庫(kù)函數(shù) SegCode32Len equ $ - LABEL_SEG_CODE32 ; END of [SECTION .s32] ; 16 位代碼段. 由 32 位代碼段跳入, 跳出后到實(shí)模式 [SECTION .s16code] ALIGN 32 [BITS 16] LABEL_SEG_CODE16: ; 跳回實(shí)模式: 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 ; 段地址會(huì)在程序開(kāi)始處被設(shè)置成正確的值 Code16Len equ $ - LABEL_SEG_CODE16 ; END of [SECTION .s16code]
生活不易,碼農(nóng)辛苦
如果您覺(jué)得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 最新日韩电影 | 午夜精品一区二区三区在线视 | av在线一区二区三区四区 | 九九热在线免费视频 | 午夜美女福利 | 日韩精品一区二区三区中文字幕 | 国产一区二区视频在线 | 久久久免费精品 | 国产日产精品一区二区三区四区 | 日韩二区三区 | 国产一区二区三区四区三区四 | 国产精品每日更新 | 91国内精品久久 | 亚洲美女视频一区 | 最新国产精品精品视频 | 韩国爱爱视频 | 国产精品美女久久久网av | 国产欧美综合一区二区三区 | 久久久久久久 | 黄色小视频在线 | 亚洲在看 | 国产成人免费视频网站视频社区 | 国产精选视频在线观看 | 99精品国产一区二区 | 国产精品久久久久久久久久新婚 | 又爽又大又黄a级毛片在线视频 | 欧美国产日韩一区二区三区 | www.国产91 | 99久久精品免费看国产四区 | xxxx性欧美 | 黄色毛片在线 | 久久国产精品一区 | 久久精品 | 亚洲欧美日韩精品久久亚洲区 | 免费视频一区 | 国产一级片av| wwwav在线 | 欧美在线性爱视频 | 亚洲成人精品久久 | 亚洲视频在线观看免费 | 国产99在线观看 |