操作系統(tǒng)中分頁(yè)管理內(nèi)核的模擬與實(shí)現(xiàn)
??
?現(xiàn)代操作系統(tǒng)大部分都采用了分頁(yè)的方式對(duì)物理內(nèi)存進(jìn)行管理,Intel 從80386之后也在硬件上支持的分頁(yè)管理,為操作系統(tǒng)的設(shè)計(jì)和實(shí)現(xiàn)帶來(lái)了很多便利之處。
?由于實(shí)際去實(shí)現(xiàn)一個(gè)操作系統(tǒng)的內(nèi)存管理內(nèi)核是一件相對(duì)比較困難的事情,因此我們今天將用模擬的方式來(lái)設(shè)計(jì)和實(shí)現(xiàn)一個(gè)操作系統(tǒng)的分頁(yè)管理內(nèi)核。由于我自己也是一個(gè)學(xué)生,因此有說(shuō)的不妥甚至錯(cuò)誤的地方,請(qǐng)各位看官不要吝嗇您的意見(jiàn)建議甚至批評(píng)。如無(wú)特別說(shuō)明,下文的物理內(nèi)存地址一詞均指模擬物理內(nèi)存中的物理地址。
一切開(kāi)始以前先來(lái)確定一些基準(zhǔn)數(shù)據(jù):
1.?物理頁(yè)的大小:物理頁(yè)的大小通常和硬件系統(tǒng)有關(guān),
2.?比如Intel80386及以后的處理器都是按4KB大小來(lái)分頁(yè)。這里我們也選擇用4KB來(lái)作為分頁(yè)的尺寸。
3.?邏輯頁(yè)的大小:邏輯頁(yè)的大小個(gè)人認(rèn)為和物理頁(yè)取同4.?樣大小最好,5.?因?yàn)檫@樣可以不6.?用擔(dān)心頁(yè)邊界問(wèn)題,7.?并且在設(shè)計(jì)分頁(yè)變換機(jī)構(gòu)時(shí)比較容易實(shí)現(xiàn)。因此也取為4KB。
8.?系統(tǒng)能有效管理的最大內(nèi)存:作為一個(gè)模擬系統(tǒng),9.?這里我取32MB作為最大內(nèi)存管理上限,10.?太大了沒(méi)什么實(shí)際意義,11.?再說(shuō)模擬系統(tǒng)跑起來(lái)也會(huì)很占資源。
12.?頁(yè)號(hào)地址范圍:依照邏輯頁(yè)尺寸和支持的最大內(nèi)存,13.?系統(tǒng)中最多可有8192個(gè)邏輯頁(yè)面,14.?則頁(yè)面地址為0x0-0x1FFF
15.?頁(yè)內(nèi)偏移量范圍:頁(yè)尺寸取為4KB 則頁(yè)內(nèi)偏移地址為0x0-0x0fff.。
在分頁(yè)管理系統(tǒng)中,地址的通常不止一種。在我們現(xiàn)在要做的系統(tǒng)中,地址分為3類,既分頁(yè)地址,線性地址,虛擬地址。
線性地址:線性地址既存儲(chǔ)器的物理地址,在系統(tǒng)內(nèi)核未初始化和初始化時(shí),都將使用線性地址操作內(nèi)存。
虛擬地址:虛擬地址是在分頁(yè)后產(chǎn)生的。其含義和線形地址相同,在系統(tǒng)中存在的各個(gè)進(jìn)程,都使用虛擬地址訪問(wèn)內(nèi)存,虛擬地址傳入內(nèi)核后,內(nèi)核利用該進(jìn)程的頁(yè)表和自身的頁(yè)地址變換機(jī)構(gòu)將虛擬地址映射為某一個(gè)線性地址。
分頁(yè)地址:分頁(yè)地址由2部分組成,按照上文的基準(zhǔn)數(shù)據(jù)設(shè)定,其結(jié)構(gòu)如下:
????BBBBBBBBBBBBB:BBBBBBBBBBBB
?前一部分共13bit用來(lái)記錄頁(yè)號(hào)地址,后一部分共12bit用來(lái)記錄頁(yè)內(nèi)偏移量。由于我們將物理頁(yè)和邏輯頁(yè)的尺寸統(tǒng)一了,因此分頁(yè)地址所表示的整體意義和線性地址是一樣的。
例如:分頁(yè)地址0000000000001000000000001 是0x1001。作為分頁(yè)地址,它表示物理內(nèi)存中第二個(gè)物理頁(yè)(注意,不是第一個(gè)物理頁(yè),因?yàn)?x0000也是有效地址,表示的是第一個(gè)物理頁(yè)),頁(yè)內(nèi)偏移量為01。這個(gè)分頁(yè)地址所表示的線性地址為:頁(yè)號(hào)×頁(yè)尺寸+頁(yè)內(nèi)偏移量,即:1×4096+1=4097 (0x1001)。可以看到,從整體上來(lái)看,分頁(yè)地址和線性地址在意義上一樣的,但是分頁(yè)地址和線性地址所表示的自身含義則是完全不同的,這一點(diǎn)在邏輯頁(yè)和物理頁(yè)尺寸不統(tǒng)一的情況下尤為明顯,并且在這種情況下,分頁(yè)地址和線性地址的整體含義也就完全不同了。由此看出,邏輯頁(yè)和物理頁(yè)尺寸的統(tǒng)一給我們?cè)O(shè)計(jì)和實(shí)現(xiàn)內(nèi)核的地址變換部分提供了很大的便利。
?在正式開(kāi)始設(shè)計(jì)內(nèi)核前,先來(lái)看看現(xiàn)代操作系統(tǒng)的一個(gè)重要特征:硬件無(wú)關(guān)性。這個(gè)特征通常是提供給用戶的。但是個(gè)人認(rèn)為,在操作系統(tǒng)的底層設(shè)計(jì)中,也應(yīng)該有一個(gè)接口部分是直接操作硬件,而其他部分在這個(gè)部分之上,通過(guò)這個(gè)接口去訪問(wèn)和控制硬件。這樣做可以使得操作系統(tǒng)的實(shí)現(xiàn)可以在某種程度上脫離具體硬件規(guī)格,并且可以給移植帶來(lái)方便。這種設(shè)計(jì)思路在Microsoft Windows NT家族的中得到了具體的體現(xiàn),NT中使用了“硬件抽象層”(HAL)的概念來(lái)分離操作系統(tǒng)的相對(duì)高層部分和底層硬件。各個(gè)高層部分通過(guò)HAL層來(lái)訪問(wèn)和控制硬件,而不是將各種對(duì)硬件的訪問(wèn)和控制操作分散在系統(tǒng)的各個(gè)角落。這種設(shè)計(jì)思路將在我們今天即將開(kāi)始設(shè)計(jì)的模擬內(nèi)核中再一次得到體現(xiàn)。這就是“模擬硬件抽象層”(EmuHAL)。
?EmuHAL的設(shè)計(jì)思路完全取自Windows NT的HAL。作為給這個(gè)模擬內(nèi)核搭配的HAL層,EmuHAL將提供一個(gè)基本上完全真實(shí)的物理內(nèi)存環(huán)境供我們來(lái)操作,你可以認(rèn)為通過(guò)EmuHAL層進(jìn)行操作和訪問(wèn)的是完全的一個(gè)物理硬件,而不必要將其想象成別的什么。在這里,EmuHAL層通過(guò)利用一個(gè)數(shù)組,來(lái)提供真實(shí)的物理內(nèi)存操作環(huán)境。下面是其提供的接口函數(shù):
DWORD? APIENTRY?Fn_HAL_Init(LPDWORD??lpMemoary,????
UDWORD ??NewMemoaryLength);
BYTE?APIENTRY?Fn_ReadByte(UDWORD Address);
VOID?APIENTRY?Fn_WriteByte(UDWORD Address,DWORD Value);
WORD?APIENTRY?Fn_ReadWord(UDWORD Address);
VOID?APIENTRY?Fn_WriteWord(UDWORD Address,DWORD Value);
DWORD?APIENTRY?Fn_ReadDword(UDWORD Address);
VOID?APIENTRY?Fn_WriteDword(UDWORD Address,DWORD Value);
這些函數(shù)都是對(duì)內(nèi)存的原子操作的模擬。除去第一初始化函數(shù)外,從上到下一共3組,每組對(duì)應(yīng)一個(gè)讀寫(xiě)服務(wù)集,分別為:字節(jié)讀/寫(xiě)集,字讀/寫(xiě)集, 雙字讀/寫(xiě)集。EmuHAL層的實(shí)現(xiàn)源代碼如下:
宏定義頭文件::Base.h
//=================================================================================
//Name:??Base.h
//Funcation:?Base Type Define,CPU support,MyUnicode Support.
//Author:?kakashi.R
//Last Update:?6.1.2005
//=================================================================================?
#ifndef _BASE_H
#define?_BASE_H
#define??TRUE??1
#define??FALSE??0
#define??SUCCESS??1
#define??FAILURE??0
#define??ENABLE??1
#define??DISABLE??0
#define??HIGH??1
#define??LOW??0
#define??USED??1
#define??UNUSE??0
#define??NULL??0
#pragma message("")
#pragma message("This is A Header File Created by kakashir. :)")
#pragma message("")
#if (defined _IOSTREAM)?? //Incude iostream.h for I/O.
#pragma message("")
#pragma?message("Macro _IOSTREAM actived Now.")
#pragma message("Now iostream.h included for I/O.")
#pragma?message("")
#include <iostream.h>
#endif? //#if (defined _IOSTREAM)
#if ( !(defined APIENTRY) && (defined _STDAPI) ) //__stdcall style support.
#pragma message("")
#pragma message("Macro _STDAPI actived Now.")
#pragma message("Funcations call style KeyWord APIENTRY Defined as __stdcall.")
#pragma message("")
#define??APIENTRY???__stdcall???
#define??CENTRY????__cdecl????
#define??API????APIENTRY???
#define??PASCAL????API????
#define??CALLBACK???PASCAL????
#endif? //#if ( !(defined APIENTRY) && (defined _STDAPI) )
#ifdef?_I386?? //Intel 80386 and later CPU support and typedefs.
#pragma message("")
#pragma message("Macro _I386 actived NOW.")
#pragma message("Data define Keywords defined for Intel 80386 and later Processer Family.")
#pragma message("")
#if !(defined _UNICODE)
typedef??char????CHAR;
#endif? //#if !(defined _UNICODE )
typedef??__int8????BYTE;
typedef??__int16????WORD;
typedef??__int32????DWORD;
typedef??__int64????QWORD;
typedef??float????FLOAT;
typedef??double????DOUBLE;
typedef??unsigned?__int8??UBYTE;
typedef??unsigned?__int16??UWORD;
typedef??unsigned?__int32??UDWORD;
typedef??unsigned?__int64??UQWORD;
typedef??void*????LPVOID;
typedef??WORD*????LPWORD;
typedef??BYTE*????LPBYTE;
typedef??DWORD*????LPDWORD;
typedef??QWORD*????LPQWORD;
typedef??FLOAT*????LPFLOAT;
typedef??DOUBLE*????LPDOUBLE;
typedef??UBYTE*????LPUBYTE;
typedef??UWORD*????LPUWORD;
typedef??UDWORD*????LPUDWORD;
typedef??UQWORD*????LPUQWORD;
????
typedef??bool????BOOL;
typedef??void????VOID;
typedef?union?___uint128???? //128bit unsigned data support.
{
?unsigned __int64??__128[2];
?unsigned __int32??__32[4];
?unsigned __int16??__16[8];
?unsigned __int8???__8[16];
}uint128;
typedef?union?___sint128??? //128bit signed data support.
{
?signed __int64??__128[2];
?signed __int32??__32[4];
?signed __int16??__16[8];
?signed __int8??__8[16];
}sint128;
typedef??UBYTE????U8;
typedef??short?unsigned??U16;
typedef??long?unsigned??U32;
typedef??UQWORD????U64;
typedef??uint128????U128;
typedef??BYTE????S8;
typedef??short?signed???S16;
typedef??long?signed???S32;
typedef??QWORD????S64;
typedef??sint128????S128;
#endif ?//#ifdef? _I386
#if (defined _UNICODE && defined _I386)? // MyUNICODE support!! :)
#pragma message("")
#pragma message("Macro _UNICODE actived NOW.")
#pragma message("The Keyword CHAR(upcase) defined 16bit for support UNICODE now.")
#pragma message("Pleas use cout() to display UNICODE char or String.")
#pragma?message("use __char to define Old ANSCII-Style Character :)")
#pragma message("")
typedef?char?__char;
typedef union?___wchar?? //Define MyUNICODE struct.
{?
?U16?Unicode16;
?U8?Unicode8[2];
}__wchar;
typedef?? __wchar CHAR;
#include <UnicodeTable.h>? //include MyUNICODE Table :)
#define?__IOSTREAM
#include <iostream.h>
#if (defined _IOSTREAM)
void APIENTRY?_cout(CHAR Word)? //MyUnicode I/O Funcation for character Display
{
?if(Word.Unicode8[1] == 0)
??{
???cout<<(__char)Word.Unicode8[0]<<flush;
??}
?else
??{
???if(Word.Unicode8[1] >=0 && Word.Unicode8[1] <= HIGH_WORD_MAX &&
????? Word.Unicode8[0] >=0 && Word.Unicode8[0] <= LOW_WORD_MAX)
????{
?????_Buffer[0] = *(UnicodeTable[(Word.Unicode8[1]-1)] +?? (2*Word.Unicode8[0])?? );
?????_Buffer[1] = *(UnicodeTable[(Word.Unicode8[1]-1)] +?? (2*Word.Unicode8[0])+1 );
?????_Buffer[2] = '\0';
?????cout<<_Buffer<<flush;
????}
??}
?
}
void APIENTRY?_cout(CHAR* Word)? //MyUnicode I/O Funcation for String display
{
?U32?Length = sizeof(Word)/2;
?U32?Tmp_a=0;
?for(Tmp_a=0;Tmp_a<Length;Tmp_a++)
??{
???if((Word+Tmp_a)->Unicode8[1] == 0)
????{
?????cout<<(__char)( (Word+Tmp_a)->Unicode8[0])<<flush;
????}
???else if ( ((Word+Tmp_a)->Unicode8[1]) >=0 && ((Word+Tmp_a)->Unicode8[1]) <= HIGH_WORD_MAX &&
???????????? ((Word+Tmp_a)->Unicode8[0]) >=0 && ((Word+Tmp_a)->Unicode8[0]) <= LOW_WORD_MAX )
?????{
??????_Buffer[0] = *(UnicodeTable[ ( (Word+Tmp_a)->Unicode8[1] )-1 ] + 2*( (Word+Tmp_a)->Unicode8[0] )? );
??????_Buffer[1] = *(UnicodeTable[ ( (Word+Tmp_a)->Unicode8[1] )-1 ] + 2*( (Word+Tmp_a)->Unicode8[0] )+1);
??????_Buffer[2] = '\0';
??????cout<<_Buffer<<flush;?????
?????}
??}
}
#define??lpUnicode(var,value)??((var)->Unicode16) = value
#define??Unicode(var,value)??((var).Unicode16)? = value
#define??cout(UnicodeString)??_cout(UnicodeString)?
#endif? //#if (defined _IOSTREAM)?
#endif //#if (define __UNICODE)
#endif?? //#ifndef _BASE_H
//===================================================================//
EmuHAL層源代碼頭文件 Hal_Define.h
#ifndef?_HAL_DEFINE_H
#define?_HAL_DEFINE_H
#define??_STDAPI
#define??_I386
#include?<base.h>
#define??MAX_MEMOARY_SUPPORT?0x02000000
DWORD?APIENTRY?Fn_HAL_Init(LPDWORD lpMemoary,UDWORD NewMemoaryLength);
BYTE?APIENTRY?Fn_ReadByte(UDWORD Address);
VOID?APIENTRY?Fn_WriteByte(UDWORD Address,DWORD Value);
WORD?APIENTRY?Fn_ReadWord(UDWORD Address);
VOID?APIENTRY?Fn_WriteWord(UDWORD Address,DWORD Value);
DWORD?APIENTRY?Fn_ReadDword(UDWORD Address);
VOID?APIENTRY?Fn_WriteDword(UDWORD Address,DWORD Value);
#endif?//#ifndef?_HAL_DEFINE_H
//===================================================================//
EmuHAL 層源代碼實(shí)現(xiàn)文件:Hal.cpp
#ifndef _HAL_H
#define?_HAL_H
#include "../include/HAL_Define.h"
static?LPDWORD?lpMemoary=NULL;
static?UDWORD?MemoarySize=NULL;
DWORD?APIENTRY?Fn_HAL_Init(LPDWORD Init_lpMemoary,UDWORD NewMemoaryLength)
{
?DWORD?Resault=SUCCESS;
?_asm
??{
???mov?EAX,[Init_lpMemoary]
???cmp?EAX,NULL
???je?ERROR
???mov?[lpMemoary],EAX
???jmp?EXIT?
??ERROR:
???mov?[Resault],FAILURE
??EXIT:?
???
??}
?MemoarySize = NewMemoaryLength;
?_asm
??{
???cmp?[MemoarySize],MAX_MEMOARY_SUPPORT
???ja?OverFlow
???jmp?OK
??OverFlow:
???mov?[MemoarySize],MAX_MEMOARY_SUPPORT
??OK:
??}
?return?Resault;
}
BYTE?APIENTRY?Fn_ReadByte(UDWORD Address)
{
?BYTE?Resault=NULL;
?_asm
??{
????push?EBX
????
????mov?EBX,[Address]
????mov?EAX,[MemoarySize]
????cmp?EBX,EAX
????jae?EXIT
????
????mov?EBX,[lpMemoary]
????add?EBX,[Address]
????mov?BL ,BYTE ptr[EBX]
????mov?[Resault],BL
???EXIT:
????pop?EBX
??}
?
?return?Resault;
}
VOID?APIENTRY?Fn_WriteByte(UDWORD Address,DWORD Value)
{
?_asm
??{
????push?EBX
????mov?EBX,[Address]
????mov?EAX,[MemoarySize]
????cmp?EBX,EAX
????jae?EXIT
????
????mov?EBX,[lpMemoary]
????mov?EAX,[Value]
????add?EBX,[Address]
????mov?BYTE ptr[EBX],AL
???EXIT:
????pop?EBX
??}
}
WORD?APIENTRY?Fn_ReadWord(UDWORD Address)
{
?WORD?Resault=NULL;
?_asm
??{
????push?EBX
????
????mov?EBX,[Address]
????mov?EAX,[MemoarySize]
????sub?EAX,0x02
????cmp?EBX,EAX
????ja?EXIT
????
????mov?EBX,[lpMemoary]
????add?EBX,[Address]
????mov?BX ,WORD ptr[EBX]
????mov?[Resault],BX
???EXIT:
????pop?EBX
??}
?
?return?Resault;
}
VOID?APIENTRY?Fn_WriteWord(UDWORD Address,DWORD Value)
{
?_asm
??{
????push?EBX
????
????
????mov?EBX,[Address]
????mov?EAX,[MemoarySize]
????sub?EAX,0x02
????cmp?EBX,EAX
????ja?EXIT
????
????mov?EBX,[lpMemoary]
????mov?EAX,[Value]
????add?EBX,[Address]
????mov?WORD ptr[EBX],AX
??
???EXIT:
????
????pop?EBX
??}
}
DWORD?APIENTRY?Fn_ReadDword(UDWORD Address)
{
?DWORD?Resault=NULL;
?_asm
??{
????push?EBX
????
????mov?EBX,[Address]
????mov?EAX,[MemoarySize]
????sub?EAX,0x04
????cmp?EBX,EAX
????ja?EXIT
????
????mov?EBX,[lpMemoary]
????add?EBX,[Address]
????mov?EBX ,DWORD ptr[EBX]
????mov?[Resault],EBX
???EXIT:
????pop?EBX
??}
?
?return?Resault;
}
VOID?APIENTRY?Fn_WriteDword(UDWORD Address,DWORD Value)
{
?_asm
??{
????push?EBX
????
????
????mov?EBX,[Address]
????mov?EAX,[MemoarySize]
????sub?EAX,0x04
????cmp?EBX,EAX
????ja?EXIT
????
????mov?EBX,[lpMemoary]
????mov?EAX,[Value]
????add?EBX,[Address]
????mov?DWORD ptr[EBX],EAX
??
???EXIT:
????
????pop?EBX
??}
??
?
}
#endif?//#ifndef _HAL_H???
以上3個(gè)文件中,Base.h 是我個(gè)人給自己寫(xiě)的類型定義和宏定義文件。在后面設(shè)計(jì)實(shí)現(xiàn)內(nèi)核時(shí)也會(huì)用到。從現(xiàn)在開(kāi)始,我們正式進(jìn)入內(nèi)核的設(shè)計(jì)。
?首先,我們要實(shí)現(xiàn)的模擬內(nèi)核是內(nèi)存分頁(yè)管理內(nèi)核,但是由于分頁(yè)管理時(shí)有可能出現(xiàn)頁(yè)表過(guò)長(zhǎng)的情況(這在頁(yè)尺寸較小但需要管理的內(nèi)存總量很大時(shí)尤其明顯),這時(shí)我們采用的方法是將頁(yè)表分組,即多級(jí)頁(yè)表的方式。那么我們現(xiàn)在正在設(shè)計(jì)的模擬內(nèi)核也需要實(shí)現(xiàn)這樣的功能嗎?我個(gè)人給出的答案是否。并不是因?yàn)槲覀児芾淼淖畲髢?nèi)存只有32MB所以不需要這樣的功能,而是由我們所設(shè)計(jì)的模擬內(nèi)核在一個(gè)真實(shí)的操作系統(tǒng)所處的位置導(dǎo)致的。個(gè)人認(rèn)為,在真實(shí)的操作系統(tǒng)中,內(nèi)存管理內(nèi)核應(yīng)該并不是一個(gè)單獨(dú)整體,而是由一個(gè)層次結(jié)構(gòu)組成。大致上如下:
???????系統(tǒng)調(diào)用接口層
???????頁(yè)表管理層(高級(jí))
???????頁(yè)表管理層(低級(jí))
???????HAL層
其中“頁(yè)表管理層(高級(jí))”部分實(shí)現(xiàn)對(duì)二級(jí)或者多級(jí)頁(yè)表的管理,而頁(yè)表管理層(低級(jí))部分則實(shí)現(xiàn)對(duì)于一級(jí)頁(yè)表中的地址映射,變換操作,同時(shí)由于該部分是緊挨HAL層的,因此對(duì)物理內(nèi)存的訪問(wèn)也將通過(guò)該層傳遞到HAL層。可能很多人要問(wèn),為什么不把對(duì)一級(jí)頁(yè)表的操作獨(dú)立出來(lái)呢?我是這樣考慮的,由于無(wú)論頁(yè)表是多級(jí)還是一級(jí),最終存放待映射地址的總是一級(jí)頁(yè)表,在訪問(wèn)到一級(jí)頁(yè)表后,緊接著馬上就要進(jìn)行對(duì)硬件的操作和訪問(wèn),因此為了高效,我將從一級(jí)頁(yè)表到傳遞給HAL操作的實(shí)現(xiàn)部分包含在了“頁(yè)表管理層(低級(jí))”中。現(xiàn)在我們就依照這樣的層次結(jié)構(gòu),來(lái)設(shè)計(jì)這個(gè)模擬內(nèi)核。以下是這個(gè)工程的名字和這個(gè)模擬內(nèi)核的代號(hào),在后文中,我可能將頻繁使用到這些代號(hào)。
?工程名:??操作系統(tǒng)中分頁(yè)管理內(nèi)核的模擬
?工程代號(hào):??EmuSolaris
?內(nèi)核代號(hào):??Venus
我將采用C++來(lái)設(shè)計(jì)和實(shí)現(xiàn)這個(gè)模擬內(nèi)核,并且為了快速和方便,會(huì)使用一些asm指令,但是不會(huì)太復(fù)雜。
?作為操作系統(tǒng)中內(nèi)存管理內(nèi)核的最底層部分(僅高于HAL層),Venus必須明確知道其將要管理的硬件對(duì)象的具體參數(shù),在這里,就是物理內(nèi)存的尺寸,并且利用這個(gè)數(shù)據(jù),可以計(jì)算出系統(tǒng)中合法物理和邏輯頁(yè)面號(hào)的范圍。另外,在整個(gè)EmuSolaris中,Venus應(yīng)該是做為在HAL層被加載后首先被加載的內(nèi)核。在加載后,整個(gè)物理內(nèi)存的操作和訪問(wèn)都將由Venus去控制。并且在加載完后,分頁(yè)地址就應(yīng)該可以開(kāi)始使用,物理內(nèi)存也已經(jīng)被劃分為邏輯頁(yè)和物理頁(yè),并且可以開(kāi)始對(duì)物理內(nèi)存按頁(yè)為單位進(jìn)行分配和回收,提供給高層部分的內(nèi)存訪問(wèn)接口也已經(jīng)初始化完畢,可以利用指定的頁(yè)表對(duì)內(nèi)存進(jìn)行訪問(wèn)了。以上就是我認(rèn)為應(yīng)該最先設(shè)計(jì)并實(shí)現(xiàn)的基礎(chǔ)功能。相對(duì)的,Venus應(yīng)該有如下的數(shù)據(jù)結(jié)構(gòu)以用于支持分頁(yè)變換和地址映射功能。注意,這里所有的數(shù)據(jù)類型定義符都請(qǐng)參看前文的Base.h。
BOOL?IsPage;???? //是否分頁(yè)管理 正常初始化時(shí)為1,即使用分頁(yè)管理
??UDWORD??PageAddressIndex;? //虛擬地址中的頁(yè)號(hào)地址?
??UDWORD??InPageOffset;??? //虛擬地址中的頁(yè)內(nèi)偏移地址
??UDWORD??NowLineAddress;??? //當(dāng)前等待變換或者使用的虛擬地址
??UDWORD??ErrorCode;????? //錯(cuò)誤代碼變量
??UDWORD??MemoarySize;??? //當(dāng)前總共內(nèi)存容量
??UDWORD??MaxPageIndex;?//最大頁(yè)面號(hào),有初始化時(shí)的總計(jì)內(nèi)存容量決定.
為了實(shí)現(xiàn)上面所說(shuō)的基礎(chǔ)功能,Venus應(yīng)該具有如下的操作函數(shù):
??
VOID?APIENTRY?Fn_TranslateLineAddress();
?VOID?APIENTRY?Fn_Service_LoadVirtualAddress(UDWORD VirtualAddress);
VOID?APIENTRY?Fn_Service_Init(UDWORD?NewMemoarySize);
Fn_Service_LoadVirtualAddress(UDWORD VirtualAddress)函數(shù)實(shí)現(xiàn)加載虛擬地址到Venus的操作。在上文中的數(shù)據(jù)結(jié)構(gòu)中,PageAddressIndex和InPageOffset分別用來(lái)保存當(dāng)前加載的虛擬地址中的頁(yè)號(hào)地址和頁(yè)內(nèi)偏移量地址。Fn_Service_LoadVirtualAddress函數(shù)就是對(duì)這個(gè)2個(gè)數(shù)據(jù)對(duì)象進(jìn)行操作。而Fn_TranslateLineAddress();則是執(zhí)行具體變換動(dòng)作的函數(shù),在IsPage為真的情況下,這個(gè)函數(shù)將會(huì)按照由Fn_Service_LoadVirtualAddress的參數(shù)傳遞過(guò)來(lái)的地址進(jìn)行變換,并將結(jié)果分別放在PageAddressIndex和InPageOffset中。而Fn_Service_LoadVirtualAddress中所帶的參數(shù)則會(huì)保存在NowLineAddress中。這個(gè)設(shè)計(jì)可以供以后在擴(kuò)展系統(tǒng)時(shí)使用。到這里,虛擬地址和線性地址轉(zhuǎn)換為分頁(yè)地址的操作就完成了。
由于分頁(yè)管理的緣故,EmuSolaris中運(yùn)行的其他進(jìn)程都將使用虛擬地址來(lái)訪問(wèn)內(nèi)存,并且必須提供頁(yè)表以供Venus進(jìn)行從虛擬地址到物理地址的映射和變換。由此可以得到Venus的運(yùn)行圖:
加載待讀取的虛擬地址à利用指定的頁(yè)表進(jìn)行地址變換,得到物理地址à將待訪問(wèn)的地址傳遞給EmuHAL層àEmuHAL層完成硬件操作
按照這個(gè)運(yùn)行圖,可以看出,第一部分已經(jīng)設(shè)計(jì)完畢,那么我們首先來(lái)實(shí)現(xiàn)這個(gè)部分。代碼如下:
首先是Venus啟動(dòng)和初始化函數(shù):
VOID? APIENTRY?MemoaryKernel::Fn_Service_Init(UDWORD?NewMemoarySize)
{
?MemoarySize = NewMemoarySize;
?InPageOffset = NULL;
?PageAddressIndex = NULL;
?NowLineAddress = NULL;
ErrorCode = NORMAL;
?
?_asm//這段匯編完成計(jì)算出NewMemoarySize對(duì)應(yīng)的最大頁(yè)號(hào)地址
??{
???push?EDX
???push?ECX
???
???mov?EAX,[NewMemoarySize]
???mov?EDX,EAX
???and?EAX,0x0000FFFF
???
???shr?EDX,0x010
???and?EDX,0x0000FFFF
???
???mov?CX,0x01000
???div?CX
???sub?EAX,1
???and?EAX,0x0000FFFF
???mov?ECX,this
???mov?[ECX]this.MaxPageIndex,EAX
pop?ECX
???pop?EDX
?}
}
//====================================================================//
//加載虛擬/線性地址,以備進(jìn)行頁(yè)面地址變換操作:
VOID?APIENTRY?MemoaryKernel::Fn_Service_LoadVirtualAddress(UDWORD VirtualAddress)
{
?this->NowLineAddress = VirtualAddress;
?if (IsPage == TRUE) {Fn_TranslateLineAddress();}
}
//====================================================================//
//執(zhí)行實(shí)際變換動(dòng)作的變換函數(shù):
VOID?APIENTRY?MemoaryKernel::Fn_TranslateLineAddress()
{?
?_asm
??{
???
???push?EBX
???push?ECX
???mov?EBX,this
???mov?EAX,[EBX]this.NowLineAddress
???mov?ECX,EAX
???and?EAX,0x0FFF //清空高24位得到頁(yè)內(nèi)偏移地址
???mov?[EBX]this.InPageOffset,EAX
???shr?ECX,12 //右移動(dòng)12位,得到頁(yè)號(hào)地址
???and?EAX,0x01FFF
???
???cmp?ECX,[EBX]this.MaxPageIndex
???jbe?OK
???mov?ECX,MAX_PAGE_NUMBER
OK:
???mov?[EBX]this.PageAddressIndex,ECX
???pop?ECX
???pop?EBX
???
??}
}
//====================================================================//
雖然完成了狀態(tài)圖上的第一部分功能,但是Venus目前仍然不具備對(duì)內(nèi)存進(jìn)行按頁(yè)分配和回收的功能。那么如何來(lái)設(shè)計(jì)這2個(gè)功能,是十分重要的,因?yàn)榉峙浜突厥帐荲enus的基礎(chǔ)的基礎(chǔ)功能。要分配和回收頁(yè)面,就需要了解整個(gè)物理內(nèi)存頁(yè)面的使用情況,最簡(jiǎn)單的辦法是采用位映射圖(BitMap)的數(shù)據(jù)結(jié)構(gòu)。BitMap,就是用一個(gè)bit位,來(lái)表示一個(gè)頁(yè)面的使用狀態(tài),只有1和0兩種狀態(tài),分別對(duì)應(yīng)頁(yè)面的 “已分配”(USED) 和“空閑”(UNUSE)2種狀態(tài)。但是,由于用來(lái)記錄內(nèi)存使用狀態(tài)的數(shù)據(jù)也是保存在內(nèi)存中的,那么,BitMap的空間效率如何呢?我們來(lái)計(jì)算一下:
Venus最大支持32MB內(nèi)存,此時(shí)最大會(huì)有8192個(gè)頁(yè)面,也就是說(shuō),需要8192個(gè)bit來(lái)記錄內(nèi)存的使用狀態(tài),即8192bit/8 = 1024Byte =1KB空間。應(yīng)該說(shuō),BitMap的空間效率還是相當(dāng)不錯(cuò)的。那么這1KB的連續(xù)數(shù)據(jù)存放在物理內(nèi)存的什么地方呢?作為操作系統(tǒng)的內(nèi)核使用的數(shù)據(jù),我將它設(shè)計(jì)為存放在物理內(nèi)存的最低地址處,即 物理地址0x0-0x03fff。這樣的話,Venue中應(yīng)該新增加一個(gè)數(shù)據(jù)成員以記錄BitMap的存放的起始物理地址。我們新增加一個(gè)數(shù)據(jù)成員 _SaveLinerAddress 來(lái)記錄它:
UDWORD??_SaveLinerAddress; //Map位圖存放的線性地址
現(xiàn)在我們來(lái)設(shè)計(jì)下BitMap的細(xì)節(jié)部分,由于這個(gè)模擬程序是在Intel 80386以上的機(jī)器上編寫(xiě)的,因此為了實(shí)現(xiàn)bit操作時(shí)方便,我們將BitMap按32bit為一組進(jìn)行劃分。每組從右向左計(jì)數(shù)。對(duì)BitMap的操作集有2個(gè)函數(shù):設(shè)置函數(shù)和查詢函數(shù),其具體實(shí)現(xiàn)代碼將在最后給出。
?
DWORD?APIENTRY?Fn_Service_SetBitMap(UDWORD? PageIndex,BOOL? Flag);
?????//設(shè)置位映射圖, 參數(shù)為分頁(yè)地址的頁(yè)號(hào).
?DWORD?APIENTRY?Fn_Service_GetBitMap(UDWORD PageIndex);
?????//取得位映射圖數(shù)值, 參數(shù)為分頁(yè)地址的頁(yè)號(hào)
現(xiàn)在通過(guò)BitMap我們已經(jīng)可以了解到物理內(nèi)存分頁(yè)狀態(tài)下內(nèi)存的使用狀態(tài)了,但是仍然不能按頁(yè)分配和回收內(nèi)存。那么要如何設(shè)計(jì)分配和回收內(nèi)存頁(yè)呢?我們可以組織一個(gè)空閑頁(yè)鏈表,每分配一個(gè)頁(yè),就摘掉一個(gè)鏈表項(xiàng),每回收一個(gè)頁(yè),就往鏈表里加一個(gè)項(xiàng)。但是這樣有幾個(gè)缺點(diǎn),一來(lái)鏈表不穩(wěn)定,一旦出錯(cuò)就會(huì)造成內(nèi)存丟失或者重復(fù)分配進(jìn)而造成進(jìn)程間沖突,二來(lái)效率相對(duì)差些。最后我想到在UNIX中,磁盤(pán)塊的分配采用的是成組鏈接法,因?yàn)閮?nèi)存空閑頁(yè)在本質(zhì)上也是一種塊,因此我們可以把這個(gè)算法適當(dāng)?shù)母脑煲幌拢脕?lái)分配和回收空閑頁(yè)。我們知道,成組鏈接分配算法采用一個(gè)堆棧來(lái)進(jìn)行分配和回收操作。我們將空閑物理頁(yè)號(hào)按1024個(gè)為一組進(jìn)行遍組,這樣最多會(huì)有8組(因?yàn)閂enus最大支持32MB內(nèi)存),并設(shè)計(jì)一個(gè)指針,在初始化時(shí)讓它指向第一組的開(kāi)頭,當(dāng)分配出去一個(gè)空閑頁(yè)面時(shí),令指針指向組中的下一個(gè)空閑物理塊號(hào),而當(dāng)回收一個(gè)空閑物理頁(yè)時(shí),則將其頁(yè)號(hào)記入上一個(gè)分配出去的頁(yè)號(hào)的位置。簡(jiǎn)單說(shuō),就是當(dāng)分配空閑物理頁(yè)時(shí)做出棧操作,當(dāng)回收時(shí)做壓棧操作。而在每組的末尾,記錄著新一組的起始物理地址,當(dāng)操作指針指向當(dāng)前組的末尾時(shí),就會(huì)跳到新一組的開(kāi)始繼續(xù)進(jìn)行分配。由于內(nèi)存的分配和回收要求高效率的操作,再加上這是Venus使用的數(shù)據(jù),因此對(duì)8個(gè)組的地址做如下規(guī)定:每組和每組之間保持連續(xù),也就是說(shuō)這8個(gè)組必須存放在連續(xù)的物理內(nèi)存空間里。每組之間以4個(gè)字節(jié)相隔。這4個(gè)字節(jié)中記錄的是下一組的起始物理地址。為了能明確知道當(dāng)前分配指針是否已經(jīng)指向了當(dāng)前組的末尾,在Venus中需要再增加一些數(shù)據(jù)成員來(lái)記錄分配的次數(shù)。由于Venus最大支持到32MB ,因此采用一個(gè)字的長(zhǎng)度來(lái)記錄空閑物理頁(yè)號(hào)。由此得到8組占用的長(zhǎng)度:1024×2Byte×8組=16KB=4頁(yè)。同樣做為Venus的數(shù)據(jù),我將起存儲(chǔ)位置設(shè)置為內(nèi)存低地址區(qū),緊挨BitMap之后,即:0x0000400- 0x000441F。新增加的數(shù)據(jù)成員如下:
??UDWORD??StackEsp;?//MallocStack操作指針.
??UDWORD??MallocCounter;?//分配次數(shù)計(jì)數(shù)器 用來(lái)記錄是否需要取下個(gè)可用頁(yè)面組或生成新可用頁(yè)面組??
??UDWORD??GroupIndex;???? //當(dāng)前操作的組號(hào)
對(duì)應(yīng)分配和回收操作,分別有2個(gè)函數(shù)提供支持,具體實(shí)現(xiàn)代碼在最后給出:
??
UDWORD?APIENTRY?Fn_Service_MallocOnePage();??
?????//分配一個(gè)頁(yè)面
??UDWORD?APIENTRY?Fn_Service_FreeOnePage(UDWORD PageIndex);?
?????//回收一個(gè)頁(yè)面,參數(shù)為待回收的頁(yè)面地址號(hào)
到目前,Venus具有了虛擬地址變換,按頁(yè)為單位對(duì)內(nèi)存進(jìn)行分配/回收操作,記錄/查詢內(nèi)存使用狀態(tài)的功能。
接著,我們來(lái)實(shí)現(xiàn)第二個(gè)功能部分:利用指定的頁(yè)表進(jìn)行地址變換,得到物理地址。那么如何利用頁(yè)表呢,這就要牽扯到頁(yè)表的數(shù)據(jù)結(jié)構(gòu)了。那么我們先來(lái)設(shè)計(jì)好頁(yè)表。在分頁(yè)系統(tǒng)中,頁(yè)表的基本功能是將邏輯頁(yè)地址映射為物理頁(yè)地址。實(shí)現(xiàn)時(shí),通常采用這樣的設(shè)計(jì):在邏輯頁(yè)表中的每一個(gè)頁(yè)表項(xiàng)中存放的是物理頁(yè)號(hào)的地址。這樣通過(guò)讀取頁(yè)表項(xiàng),可以得到對(duì)應(yīng)邏輯頁(yè)在物理內(nèi)存中的物理頁(yè)號(hào),再和頁(yè)內(nèi)偏移量相拼,就得到了要訪問(wèn)的物理地址。如上文所寫(xiě)到的,在分頁(yè)系統(tǒng)中,進(jìn)程訪問(wèn)內(nèi)存使用的都是虛擬地址,也就是說(shuō),進(jìn)程總是認(rèn)為自己的存儲(chǔ)地址是從0x0開(kāi)始的。進(jìn)程進(jìn)行內(nèi)存訪問(wèn)時(shí),傳遞給Venus的是一個(gè)虛擬的地址,Venus將這個(gè)虛擬的地址做分頁(yè)變換,取得對(duì)應(yīng)這個(gè)虛擬地址的分頁(yè)地址,分頁(yè)地址中包含了頁(yè)號(hào)和頁(yè)內(nèi)偏移量,然后Venus再利用得到的頁(yè)號(hào),去這個(gè)進(jìn)程的頁(yè)表中對(duì)應(yīng)的頁(yè)表項(xiàng)里取得物理頁(yè)號(hào)的地址,最后將取得的頁(yè)號(hào)地址再和頁(yè)內(nèi)偏移量相拼,就得到了物理地址。這樣就完成了一次由虛擬地址到物理地址的映射。回到剛才的設(shè)計(jì)上,頁(yè)表項(xiàng)必須有至少以下2個(gè)數(shù)據(jù)成員來(lái)完成地址的映射:
?UDWORD?PageIndex;?? //頁(yè)索引號(hào)用于共系統(tǒng)查找(目前未用)
?UDWORD?PageBlock;?? //物理頁(yè)號(hào) 保存該頁(yè)表項(xiàng)映射的真實(shí)物理頁(yè)號(hào)地址
而實(shí)際上,為了支持虛擬存儲(chǔ)技術(shù)和共享保護(hù)等諸多功能,頁(yè)表項(xiàng)還需要其他的數(shù)據(jù)結(jié)構(gòu)支持,比如,為了供換頁(yè)進(jìn)程參看,頁(yè)表項(xiàng)需要提供當(dāng)前單位時(shí)間內(nèi)自身是否被訪問(wèn),是否被修改,當(dāng)前該頁(yè)是否在內(nèi)存,單位時(shí)間內(nèi)頁(yè)面被訪問(wèn)的次數(shù) 等等的信息,因此綜合了一下,我將頁(yè)表項(xiàng)設(shè)計(jì)如下:
??UDWORD?PageIndex;?? //頁(yè)索引號(hào)用于共系統(tǒng)查找(目前未用)
??UDWORD?PageBlock;?? //物理頁(yè)號(hào) 保存該頁(yè)表項(xiàng)映射的真實(shí)物理頁(yè)地址
??UDWORD?AccessCounter; //訪問(wèn)計(jì)數(shù)器,用來(lái)記錄該頁(yè)面被訪問(wèn)的次數(shù)
??UDWORD?PageStatus;?? //頁(yè)面狀態(tài)標(biāo)志,標(biāo)志頁(yè)面是在內(nèi)存中還是在外存中,共換頁(yè)進(jìn)程參考
??BOOL?IsModify;?//頁(yè)面是否被修改 共換頁(yè)進(jìn)程參考
??BOOL?IsAccess;?//頁(yè)是否被訪問(wèn),共換頁(yè)進(jìn)程參考
??UDWORD?SwapAddress;??? //外存地址.頁(yè)面被存放于外存的地址
這些數(shù)據(jù)結(jié)構(gòu)將為以后設(shè)計(jì)換頁(yè)進(jìn)程提供有力的支持。Venus作為底層內(nèi)核,必須能向高層部分提供對(duì)頁(yè)表項(xiàng)內(nèi)容的查詢和修改操作,以及當(dāng)新生成一個(gè)頁(yè)表項(xiàng)時(shí),應(yīng)該能按高層的要求,進(jìn)行頁(yè)表項(xiàng)初始化操作,初始化主要用來(lái)給新頁(yè)表項(xiàng)分配一個(gè)空閑物理頁(yè)面供其映射。
?在頁(yè)表項(xiàng)的數(shù)據(jù)成員中,PageBlock和PageIndex只能在初始化時(shí)由初始化函數(shù)修改,一旦初始化成功完成,以后除非回收頁(yè)面,否則不能再修改。而其他數(shù)據(jù)成員,則可以由高層按需要進(jìn)行修改。基于以上設(shè)定,頁(yè)表項(xiàng)應(yīng)該具有的操作集有:
UDWORD?APIENTRY??Fn_Service_Init(UDWORD?Init_PageIndex); //頁(yè)表項(xiàng)對(duì)象初始化函數(shù),參數(shù)為頁(yè)索引號(hào).
//該函數(shù)將請(qǐng)求內(nèi)核分配一個(gè)空閑物理頁(yè)面以用來(lái)初始化,并將該頁(yè)面地址記入PageBlock中
??
UDWORD?APIENTRY??Fn_Service_Free();//該函數(shù)將請(qǐng)求內(nèi)核釋放其所映射的物理頁(yè)面,并將PageBlock的數(shù)值設(shè)置為NO_ALLOCATION
//被釋放的頁(yè)面將被放入內(nèi)核管理的分配堆棧,共其他進(jìn)程使用
UDWORD?APIENTRY??Fn_Service_GetPageBlock();? //取得PageBlock的值
UDWORD?APIENTRY??Fn_Service_GetPageStatu(); //取得PageStatu的值
UDWORD?APIENTRY??Fn_Service_GetAccessCounter();//取得AccessCounter的值
UDWORD?APIENTRY??Fn_Service_GetIsModify(); //取得IsModify的值
UDWORD?APIENTRY??Fn_Service_GetIsAccess(); //取得IsAccess的值
VOID?APIENTRY??Fn_Service_SetPageStatu(UDWORD?NewStatu); //設(shè)置PageStatu的值
VOID?APIENTRY??Fn_Service_IncAccessCounter(); //AccessCounter自增1
VOID?APIENTRY??Fn_Service_SetIsModidy(BOOL?NewFlag); //設(shè)置IsModify的值
VOID?APIENTRY??Fn_Service_SetIsAccess(BOOL?NewFlag);? //設(shè)置IsAccess的值
VOID?APIENTRY??Fn_Service_SetSwapAddress(UDWORD?NewSwapAddress);
//設(shè)置SwapAddress的值
當(dāng)頁(yè)表項(xiàng)設(shè)計(jì)好后,就可以實(shí)現(xiàn)Venus的第二部分功能,利用頁(yè)表進(jìn)行地址變換,映射出要訪問(wèn)的真實(shí)物理地址。對(duì)內(nèi)存的訪問(wèn),無(wú)非是讀或者寫(xiě),因此Venus需要提供一個(gè)內(nèi)存訪問(wèn)接口。EmuHAL中提供了對(duì)物理內(nèi)存進(jìn)行按字節(jié),字,雙字讀取/寫(xiě)入的接口,因此Venus中也將提供按字節(jié),字,雙字讀取/寫(xiě)入的接口。到這里有一個(gè)問(wèn)題,就是什么時(shí)候進(jìn)行利用頁(yè)表和分頁(yè)地址進(jìn)行物理地址的映射。可以有2個(gè)方案,第一,加載虛擬地址后立刻進(jìn)行分頁(yè)地址到物理地址的映射,這時(shí)候當(dāng)然需要頁(yè)表的支持。第二,加載虛擬地址后并不立刻進(jìn)行分頁(yè)地址到物理的映射,而是等到需要執(zhí)行讀/寫(xiě)操作時(shí),才利用指定的頁(yè)表進(jìn)行地址映射,隨后進(jìn)行訪問(wèn)操作。我在這里選擇了第二個(gè)方案。因?yàn)槲矣X(jué)得加載虛擬地址后并不一定馬上要進(jìn)行內(nèi)存操作,但是向Venus請(qǐng)求了讀寫(xiě)操作后則必須立刻執(zhí)行讀/寫(xiě),因此我在這里提供給高層2個(gè)地址方面的接口,一個(gè)只先加載地址并進(jìn)行虛擬地址到分頁(yè)地址的變換,另一個(gè)接口就是由上文的6個(gè)讀寫(xiě)函數(shù)中的參數(shù)提供的,使用這6個(gè)函數(shù)時(shí),Venus會(huì)一次性完成加載虛擬地址變換為分頁(yè)地址和利用分頁(yè)地址及頁(yè)表完成分頁(yè)地址到物理地址的轉(zhuǎn)換,并將讀寫(xiě)操作傳遞給EmuHAL層去執(zhí)行。Venus提供的讀寫(xiě)函數(shù)接口如下:
BYTE?APIENTRY?Fn_Service_ReadByte(Lv1_MemoaryTable*?lpPageTableAddress,
?????????? UDWORD NewVirtualAddress);
?????//按字節(jié)方式(8bit)讀取
VOID?APIENTRY?Fn_Service_WriteByte(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress,DWORD Value);
?????//按字節(jié)方式(8bit)寫(xiě)入
??
WORD?APIENTRY?Fn_Service_ReadWord(Lv1_MemoaryTable*?lpPageTableAddress,
?????????? UDWORD NewVirtualAddress);
?????//按字方式(16bit)讀取
??
VOID?APIENTRY?Fn_Service_WriteWord(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress,DWORD Value);
?????//按字方式(16bit)寫(xiě)入
DWORD?APIENTRY?Fn_Service_ReadDword(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress);
?????//按雙字方式(32bit)讀取
??
VOID?APIENTRY?Fn_Service_WriteDword(Lv1_MemoaryTable*?lpPageTableAddress,
???????????? UDWORD NewVirtualAddress,DWORD Value);
?????//按雙字方式(32bit)寫(xiě)入
?
到這里,第二和第三部分功能就相繼實(shí)現(xiàn)了,作為底層來(lái)說(shuō),現(xiàn)在基本的功能已經(jīng)實(shí)現(xiàn)了,但是還有很多的不足,比如,內(nèi)核的健壯性問(wèn)題。上面的各個(gè)功能設(shè)計(jì)都沒(méi)有考慮到操作數(shù)據(jù)錯(cuò)誤帶來(lái)的影響,并且對(duì)Venus使用的內(nèi)存部分完全沒(méi)有進(jìn)行保護(hù),任何進(jìn)程都可以輕松訪問(wèn)到系統(tǒng)使用的內(nèi)存,這是相當(dāng)危險(xiǎn)的。
上面說(shuō)了這么多,我把具體實(shí)現(xiàn)的代碼貼在下面,這些代碼實(shí)現(xiàn)上面說(shuō)的Venus 的各個(gè)基本功能,并且最了相對(duì)比較好的安全性檢測(cè),并且基本保證了在EmuHAL下系統(tǒng)用內(nèi)存空間不可訪問(wèn)。
Memoary_Class_Define.h
//================================================================//
#ifndef _MEMOARY_CLASS_DEFINE_H
#define _MEMOARY_CLASS_DEFINE_H
#include "../Include/Memoary_Define.h"
#include "../Include/Memoary_Class_Lv1Pt_Define.h"
class?CMemoaryKernel? //內(nèi)存分頁(yè)管理內(nèi)核接口類
{
?public:
??virtual?VOID??APIENTRY?Fn_Service_Init(UDWORD?NewMemoarySize)=0;
??//內(nèi)核啟動(dòng),初始化函數(shù),必須在EmuHAL被初始化后調(diào)用,否則會(huì)因?yàn)闆](méi)有EmuHAL層支持而出錯(cuò).
??//同時(shí)不調(diào)用本函數(shù)則內(nèi)核本身也不會(huì)初始化,進(jìn)而導(dǎo)致Halt.
?public: //存儲(chǔ)器管理內(nèi)核狀態(tài)查詢操作服務(wù)集
??virtual UDWORD?APIENTRY?Fn_Service_GetErrorCode()=0; //取得內(nèi)核操作錯(cuò)誤狀態(tài)代碼
??virtual VOID?APIENTRY?Fn_Service_GetMemoaryStatu()=0;//當(dāng)前內(nèi)存使用情況查看接口
?
?public: //單位頁(yè)面分配/回收服務(wù)集
??virtual UDWORD?APIENTRY?Fn_Service_MallocOnePage()=0;??
?????//分配一個(gè)頁(yè)面,返回值為分配的頁(yè)面地址
??virtual UDWORD?APIENTRY?Fn_Service_FreeOnePage(UDWORD PageIndex)=0;?
?????//回收一個(gè)頁(yè)面,參數(shù)為待回收的頁(yè)號(hào)地址.注意,該函數(shù)不會(huì)回收任何由系統(tǒng)常駐的頁(yè)面或者非法頁(yè)面
??
?public: //讀寫(xiě)服務(wù)集? 第一個(gè)參數(shù)為L(zhǎng)v1頁(yè)表對(duì)象指針? 第二個(gè)參數(shù)為虛擬地址 第3個(gè)參數(shù)為待寫(xiě)入的數(shù)據(jù)
??virtual BYTE?APIENTRY?Fn_Service_ReadByte(Lv1_MemoaryTable*?lpPageTableAddress,
?????????? UDWORD NewVirtualAddress)=0;
?????//按字節(jié)方式(8bit)讀取
??
??virtual VOID?APIENTRY?Fn_Service_WriteByte(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress,DWORD Value)=0;
?????//按字節(jié)方式(8bit)寫(xiě)入
??
??
??virtual WORD?APIENTRY?Fn_Service_ReadWord(Lv1_MemoaryTable*?lpPageTableAddress,
?????????? UDWORD NewVirtualAddress)=0;
?????//按字方式(16bit)讀取
??
??virtual VOID?APIENTRY?Fn_Service_WriteWord(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress,DWORD Value)=0;
?????//按字方式(16bit)寫(xiě)入
??
??
??virtual DWORD?APIENTRY?Fn_Service_ReadDword(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress)=0;
?????//按雙字方式(32bit)讀取
??
??virtual VOID?APIENTRY?Fn_Service_WriteDword(Lv1_MemoaryTable*?lpPageTableAddress,
???????????? UDWORD NewVirtualAddress,DWORD Value)=0;
?????//按雙字方式(32bit)寫(xiě)入
??
};
class?MemoaryKernel:public CMemoaryKernel
{
?private:
??BOOL??IsPage;???? //是否分頁(yè)管理 正常初始化時(shí)為1,即使用分頁(yè)管理
??UDWORD??_SaveLinerAddress; //Map位圖存放的線性地址
??UDWORD??PageAddressIndex;? //分頁(yè)地址中的頁(yè)號(hào)地址?
??UDWORD??InPageOffset;??? //分頁(yè)地址中的頁(yè)內(nèi)偏移地址
??UDWORD??NowLineAddress;??? //當(dāng)前等待變換或者使用的虛擬地址
??UDWORD??StackEsp;?//MallocStack操作指針.
??UDWORD??MallocCounter;?//分配次數(shù)計(jì)數(shù)器 用來(lái)記錄是否需要取下個(gè)可用頁(yè)面組或生成新可用頁(yè)面組??
??UDWORD??ErrorCode;????? //錯(cuò)誤代碼變量
??UDWORD??GroupIndex;???? //當(dāng)前操作的組號(hào)
??UDWORD??MemoarySize;??? //當(dāng)前總共內(nèi)存容量
??UDWORD??MaxPageIndex;?//最大頁(yè)面號(hào),有初始化時(shí)的總計(jì)內(nèi)存容量決定.
?public:
??MemoaryKernel();
??~MemoaryKernel();
?
?private://內(nèi)部服務(wù)
??VOID?APIENTRY?Fn_TranslateLineAddress();? //虛擬地址分頁(yè)變換機(jī)構(gòu)
??VOID?APIENTRY?Fn_Service_Init_MallocStack(); //Malloc堆棧初始化函數(shù)
??VOID?APIENTRY?Fn_Service_LoadVirtualAddress(UDWORD VirtualAddress);
?????//加載待讀取或者寫(xiě)入的內(nèi)存地址.如果使用分頁(yè)模式,則內(nèi)核會(huì)將線性地址做拆分,
?????//在PageAddressIndex中放入頁(yè)號(hào)地址,在InPageOffset中放入頁(yè)內(nèi)偏移量地址??
??
?public: //內(nèi)存使用狀況查詢/設(shè)置/內(nèi)核初始化服務(wù)集
??virtual?VOID??APIENTRY?Fn_Service_Init(UDWORD?NewMemoarySize);
?????//內(nèi)核初始化函數(shù),負(fù)責(zé)啟動(dòng)內(nèi)核,設(shè)置位映射圖和Malloc堆棧??
??DWORD?APIENTRY?Fn_Service_SetBitMap(UDWORD PageIndex,BOOL Flag);
?????//設(shè)置位映射圖, 參數(shù)為分頁(yè)地址的頁(yè)號(hào)地址.
??DWORD?APIENTRY?Fn_Service_GetBitMap(UDWORD PageIndex);
?????//取得位映射圖數(shù)值, 參數(shù)為分頁(yè)地址的頁(yè)號(hào)地址.
?public: //單位頁(yè)面分配/回收服務(wù)集
??virtual?UDWORD?APIENTRY?Fn_Service_MallocOnePage();??
?????//分配一個(gè)頁(yè)面
??virtual UDWORD?APIENTRY?Fn_Service_FreeOnePage(UDWORD PageIndex);?
?????//回收一個(gè)頁(yè)面
?public: //存儲(chǔ)器管理內(nèi)核狀態(tài)查詢操作服務(wù)集
??virtual UDWORD?APIENTRY?Fn_Service_GetErrorCode(); //取得內(nèi)核操作錯(cuò)誤狀態(tài)代碼
??virtual VOID?APIENTRY?Fn_Service_GetMemoaryStatu();//當(dāng)前內(nèi)存使用情況查看接口
??
?public: //讀寫(xiě)服務(wù)集? 第一個(gè)參數(shù)為L(zhǎng)v1頁(yè)表對(duì)象指針? 第二個(gè)參數(shù)為虛擬地址 第3個(gè)參數(shù)為待寫(xiě)入的數(shù)據(jù)
??virtual BYTE?APIENTRY?Fn_Service_ReadByte(Lv1_MemoaryTable*?lpPageTableAddress,
?????????? UDWORD NewVirtualAddress);
?????//按字節(jié)方式(8bit)讀取
??
??virtual VOID?APIENTRY?Fn_Service_WriteByte(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress,DWORD Value);
?????//按字節(jié)方式(8bit)寫(xiě)入
??
??
??virtual WORD?APIENTRY?Fn_Service_ReadWord(Lv1_MemoaryTable*?lpPageTableAddress,
?????????? UDWORD NewVirtualAddress);
?????//按字方式(16bit)讀取
??
??virtual VOID?APIENTRY?Fn_Service_WriteWord(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress,DWORD Value);
?????//按字方式(16bit)寫(xiě)入
??
??
??virtual DWORD?APIENTRY?Fn_Service_ReadDword(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress);
?????//按雙字方式(32bit)讀取
??
??virtual VOID?APIENTRY?Fn_Service_WriteDword(Lv1_MemoaryTable*?lpPageTableAddress,
???????????? UDWORD NewVirtualAddress,DWORD Value);
?????//按雙字方式(32bit)寫(xiě)入
??
};
#endif? //#ifndef _MEMOARY_CLASS_DEFINE_H
//================================================================//
Memoary_Class_Lv1PT_Define.h
//================================================================//
#ifndef?_MEMOARY_CLASS_LV1PT_DEFINE
#define _MEMOARY_CLASS_LV1PT_DEFINE
#include "../Include/Memoary_Define.h"
class?Lv1_MemoaryTable
{
?private:
??UDWORD?PageIndex;?? //頁(yè)索引號(hào)用于共系統(tǒng)查找(目前未用)
??UDWORD?PageBlock;?? //物理頁(yè)號(hào) 保存該頁(yè)表項(xiàng)映射的真實(shí)物理頁(yè)地址
??UDWORD?AccessCounter; //訪問(wèn)計(jì)數(shù)器,用來(lái)記錄該頁(yè)面被訪問(wèn)的次數(shù)
??UDWORD?PageStatus;?? //頁(yè)面狀態(tài)標(biāo)志,標(biāo)志頁(yè)面是在內(nèi)存中還是在外存中,共換頁(yè)進(jìn)程參考
??BOOL?IsModify;?//頁(yè)面是否被修改 共換頁(yè)進(jìn)程參考
??BOOL?IsAccess;?//頁(yè)是否被訪問(wèn),共換頁(yè)進(jìn)程參考
??UDWORD?SwapAddress;??? //外存地址.頁(yè)面被存放于外存的地址
?public:
??Lv1_MemoaryTable();
??~Lv1_MemoaryTable();
?
?public: //頁(yè)表項(xiàng)初始化服務(wù)集
??UDWORD?APIENTRY??Fn_Service_Init(UDWORD?Init_PageIndex); //頁(yè)表項(xiàng)對(duì)象初始化函數(shù),參數(shù)為頁(yè)索引號(hào).
???????//該函數(shù)將請(qǐng)求內(nèi)核分配一個(gè)空閑物理頁(yè)面以用來(lái)初始化,并將該頁(yè)面地址記入PageBlock中
??
??UDWORD?APIENTRY??Fn_Service_Free();//該函數(shù)將請(qǐng)求內(nèi)核釋放其所映射的物理頁(yè)面,并將PageBlock的數(shù)值設(shè)置為NO_ALLOCATION
????????? //被釋放的頁(yè)面將被放入內(nèi)核管理的分配堆棧,共其他進(jìn)程使用
?
?public: //頁(yè)表項(xiàng)狀態(tài)讀/寫(xiě)服務(wù)集
??//讀
??UDWORD?APIENTRY??Fn_Service_GetPageBlock();? //取得PageBlock的值
??UDWORD?APIENTRY??Fn_Service_GetPageStatu(); //取得PageStatu的值
??UDWORD?APIENTRY??Fn_Service_GetAccessCounter();//取得AccessCounter的值
??UDWORD?APIENTRY??Fn_Service_GetIsModify(); //取得IsModify的值
??UDWORD?APIENTRY??Fn_Service_GetIsAccess(); //取得IsAccess的值
??
??//寫(xiě)
??VOID?APIENTRY??Fn_Service_SetPageStatu(UDWORD?NewStatu); //設(shè)置PageStatu的值
??VOID?APIENTRY??Fn_Service_IncAccessCounter(); //AccessCounter自增1
??VOID?APIENTRY??Fn_Service_SetIsModidy(BOOL?NewFlag); //設(shè)置IsModify的值
??VOID?APIENTRY??Fn_Service_SetIsAccess(BOOL?NewFlag);? //設(shè)置IsAccess的值
??VOID?APIENTRY??Fn_Service_SetSwapAddress(UDWORD?NewSwapAddress); //設(shè)置SwapAddress的值
};
#endif //#ifndef?_MEMOARY_CLASS_LV1PT_DEFINE
//====================================================================//
Memoary_Define.h
//====================================================================//
#ifndef _MEMOARY_DEFINE_H
#define _MEMOARY_DEFINE_H
#define??MAX_MEMOARY???0x02000000?? //支持管理的最大內(nèi)存 32MB
#define??MIN_RUN_MEMOARY???0x00006000?? //內(nèi)核運(yùn)行需要的最小內(nèi)存,以Byte計(jì)算
#define??MAX_PAGE_NUMBER???0x00001FFF?//32MB內(nèi)存按4KB分頁(yè)的最大頁(yè)號(hào) 0-8191 共8192個(gè)
#define??PAGE_SIZE???4096?//頁(yè)尺寸4KB為4096Byte
#define??MAX_MEMOARY_STACK??1024??? //負(fù)責(zé)內(nèi)存分配回收的堆棧的長(zhǎng)度
#define??NO_ALLOCATION???0x0FFFF
#define??_I386??//類型關(guān)鍵字定義 定義為Intel 80386 及以后處理器專用
#define??_STDAPI???????? //允許函數(shù)調(diào)用使用Win32 APIENTRY(__stdcall)方式
#define??_IOSTREAM?//使用iostream.h作為I/O操作庫(kù)
#include <Base.h>
#include <EmuHAL.h>
#pragma comment(lib,"EmuHAL.lib")
#define??SWAPPER????0x00000000
#define??MEMOARY????0x00000001
#define??UNINIT????0x00000002
//以下地址基于ExHal層中的內(nèi)存,可被視為物理內(nèi)存
#define??SYSTEM_USE_START_LINE_ADDRESS???0x0000000
#define??SYSTEM_USE_START_PAGE_ADDRESS???0x0000000
#define??MEMOARY_MAP_BEGIN_STORE_LINE_ADDRESS??0x0000000
#define??MEMOARY_MAP_END_STORE_LINE_ADDRESS??0x00003FF
#define??MEMOARY_STACK_BEGIN_STORE_LINE_ADDRESS??0x0000400
#define??MEMOARY_STACK_END_STORE_LINE_ADDRESS??0x000441F
#define??MEMOARY_STACK_ESP????0x0004420
#define??SYSTEM_USE_END_PAGE_ADDRESS???0x0000004
#define??SYSTEM_USE_END_LINE_ADDRESS???0x0004423
//錯(cuò)誤代碼定義:
#define??NORMAL??????0x00000001
#define??GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY?0xF0000000
#define??GENERAL_PROTECT_ERROR_PAGE_INDEX_OVERFLOW?0xF0000001
#define??MEMOARY_ALLOCATE_ERROR_NO_ENOUGH_MEMOARY?0xF0000002
#define??MEMOARY_FREE_ERROR_NO_MEMOARY_NEED_FREE??0xF0000003
#define??MEMOARY_KERNEL_HALT_NO_ENOUGH_MEMOARY_FOR_INIT?0xF0000004
#define??MEMOARY_KERNEL_READ_FAILURE_PAGE_NOT_ALLOCATION?0xF0000005
#define??MEMOARY_KERNEL_FREE_PAGE_FAILURE_PAGE_UNUSED?0xF0000006
#define??MEMOARY_KERNEL_READ_ERROR_ADDRESS_OVERFLOW?0xF0000007
#define??MEMOARY_KERNEL_WRITE_ERROR_ADDRESS_OVERFLOW?0xF0000008
#define??MEMOARY_KERNEL_INT_READ_PAGE_NOT_IN_MEMOARY?0xF0000009
#define??MEMOARY_KERNEL_INT_WRITE_PAGE_NOT_IN_MEMOARY?0xF000000A
#define??MALLOC_STACK_END_FLAG????0xFFFFFFFF
#define??LPCMEMOAEYKERNEL?CMemoaryKernel*
//LPCMEMOAEYKERNEL?Fn_iKernel_GetMemoaryManager();??
#endif? //#ifndef _MEMOARY_DEFINE_H
//====================================================================//
?Memoary_Gloable_Define.h
//====================================================================//
#ifndef?_MEMOARY_GLOABLE_DEFINE_H
#define?_MEMOARY_GLOABLE_DEFINE_H
#include "./Include/Memoary_Define.h"
#include "./Include/Memoary_Class_Define.h"
#include "./Include/Memoary_Class_Lv1PT_Define.h"
//接口對(duì)象
MemoaryKernel?m_Venus;??? //存儲(chǔ)器管理核心對(duì)象
LPCMEMOAEYKERNEL?APIENTRY?Fn_iKernel_GetMemoaryManager();
#endif
//===================================================================//
MemoaryPageLib.h
//===================================================================//
#ifndef?_MEMPAGELIB_H
#define?_MEMPAGELIB_H
#define??MAX_MEMOARY???0x00800000?? //支持管理的最大內(nèi)存 32MB
#define??MAX_PAGE_NUMBER???0x00001FFF?//32MB內(nèi)存按4KB分頁(yè)的最大頁(yè)號(hào) 0-8191 共8192個(gè)
#define??PAGE_SIZE???4096?//頁(yè)尺寸4KB為4096Byte
#define??MAX_MEMOARY_STACK??1024??? //負(fù)責(zé)內(nèi)存分配回收的堆棧的長(zhǎng)度
#define??_I386??//類型關(guān)鍵字定義 定義為Intel 80386 及以后處理器專用
#define??_STDAPI???????? //允許函數(shù)調(diào)用使用Win32 APIENTRY(__stdcall)方式
#define??_IOSTREAM?//使用iostream.h作為I/O操作庫(kù)
#include <Base.h>
#include <EmuHAL.h>
#pragma comment(lib,"EmuHAL.lib")
#define??SWAPPER????0x00000000
#define??MEMOARY????0x00000001
#define??UNINIT????0x00000002
//以下地址基于ExHal層中的內(nèi)存,可被視為物理內(nèi)存
#define??SYSTEM_USE_START_LINE_ADDRESS???0x0000000
#define??SYSTEM_USE_START_PAGE_ADDRESS???0x0000000
#define??MEMOARY_MAP_BEGIN_STORE_LINE_ADDRESS??0x0000000
#define??MEMOARY_MAP_END_STORE_LINE_ADDRESS??0x00003FF
#define??MEMOARY_STACK_BEGIN_STORE_LINE_ADDRESS??0x0000400
#define??MEMOARY_STACK_END_STORE_LINE_ADDRESS??0x000441F
#define??MEMOARY_STACK_ESP????0x0004420
#define??SYSTEM_USE_END_PAGE_ADDRESS???0x0000004
#define??SYSTEM_USE_END_LINE_ADDRESS???0x0004423
//頁(yè)表映射的空閑物理頁(yè)面的狀態(tài)標(biāo)志
#define??SWAPPER????0x00000000?? //位于交換設(shè)備上
#define??MEMOARY????0x00000001? //在內(nèi)存中
#define??UNINIT????0x00000002? //尚未初始化的新頁(yè)表項(xiàng)
//錯(cuò)誤代碼定義:
#define??NORMAL??????0x00000001
#define??GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY?0xF0000000
#define??GENERAL_PROTECT_ERROR_PAGE_INDEX_OVERFLOW?0xF0000001
#define??MEMOARY_ALLOCATE_ERROR_NO_ENOUGH_MEMOARY?0xF0000002
#define??MEMOARY_FREE_ERROR_NO_MEMOARY_NEED_FREE??0xF0000003
#define??MEMOARY_KERNEL_HALT_NO_ENOUGH_MEMOARY_FOR_INIT?0xF0000004
#define??MEMOARY_KERNEL_READ_FAILURE_PAGE_NOT_ALLOCATION?0xF0000005
#define??MEMOARY_KERNEL_FREE_PAGE_FAILURE_PAGE_UNUSED?0xF0000006
#define??MEMOARY_KERNEL_READ_ERROR_ADDRESS_OVERFLOW?0xF0000007
#define??MEMOARY_KERNEL_WRITE_ERROR_ADDRESS_OVERFLOW?0xF0000008
#define??MEMOARY_KERNEL_INT_READ_PAGE_NOT_IN_MEMOARY?0xF0000009
#define??MEMOARY_KERNEL_INT_WRITE_PAGE_NOT_IN_MEMOARY?0xF000000A
#define??MALLOC_STACK_END_FLAG????0xFFFFFFFF
class?Lv1_MemoaryTable
{
?private:
??UDWORD?PageIndex;?? //頁(yè)索引號(hào)用于共系統(tǒng)查找(目前未用)
??UDWORD?PageBlock;?? //物理頁(yè)號(hào) 保存該頁(yè)表項(xiàng)映射的真實(shí)物理頁(yè)地址
??UDWORD?AccessCounter; //訪問(wèn)計(jì)數(shù)器,用來(lái)記錄該頁(yè)面被訪問(wèn)的次數(shù)
??UDWORD?PageStatus;?? //頁(yè)面狀態(tài)標(biāo)志,標(biāo)志頁(yè)面是在內(nèi)存中還是在外存中,共換頁(yè)進(jìn)程參考
??BOOL?IsModify;?//頁(yè)面是否被修改 共換頁(yè)進(jìn)程參考
??BOOL?IsAccess;?//頁(yè)是否被訪問(wèn),共換頁(yè)進(jìn)程參考
??UDWORD?SwapAddress;??? //外存地址.頁(yè)面被存放于外存的地址
?public:
??Lv1_MemoaryTable();
??~Lv1_MemoaryTable();
?
?public: //頁(yè)表項(xiàng)初始化服務(wù)集
??UDWORD?APIENTRY??Fn_Service_Init(UDWORD?Init_PageIndex); //頁(yè)表項(xiàng)對(duì)象初始化函數(shù),參數(shù)為頁(yè)索引號(hào).
???????//該函數(shù)將請(qǐng)求內(nèi)核分配一個(gè)空閑物理頁(yè)面以用來(lái)初始化,并將該頁(yè)面地址記入PageBlock中
??
??UDWORD?APIENTRY??Fn_Service_Free();//該函數(shù)將請(qǐng)求內(nèi)核釋放其所映射的物理頁(yè)面,并將PageBlock的數(shù)值設(shè)置為NO_ALLOCATION
????????? //被釋放的頁(yè)面將被放入內(nèi)核管理的分配堆棧,共其他進(jìn)程使用
?
?public: //頁(yè)表項(xiàng)狀態(tài)讀/寫(xiě)服務(wù)集
??//讀
??UDWORD?APIENTRY??Fn_Service_GetPageBlock();? //取得PageBlock的值
??UDWORD?APIENTRY??Fn_Service_GetPageStatu(); //取得PageStatu的值
??UDWORD?APIENTRY??Fn_Service_GetAccessCounter();//取得AccessCounter的值
??UDWORD?APIENTRY??Fn_Service_GetIsModify(); //取得IsModify的值
??UDWORD?APIENTRY??Fn_Service_GetIsAccess(); //取得IsAccess的值
??
??//寫(xiě)
??VOID?APIENTRY??Fn_Service_SetPageStatu(UDWORD?NewStatu); //設(shè)置PageStatu的值
??VOID?APIENTRY??Fn_Service_IncAccessCounter(); //AccessCounter自增1
??VOID?APIENTRY??Fn_Service_SetIsModidy(BOOL?NewFlag); //設(shè)置IsModify的值
??VOID?APIENTRY??Fn_Service_SetIsAccess(BOOL?NewFlag);? //設(shè)置IsAccess的值
??VOID?APIENTRY??Fn_Service_SetSwapAddress(UDWORD?NewSwapAddress); //設(shè)置SwapAddress的值
};
class?CMemoaryKernel
{
?public:
??virtual?VOID??APIENTRY?Fn_Service_Init(UDWORD?NewMemoarySize)=0;
??//內(nèi)核啟動(dòng),初始化函數(shù),必須在EmuHAL被初始化后調(diào)用,否則會(huì)出錯(cuò)
?public: //存儲(chǔ)器管理內(nèi)核狀態(tài)查詢操作服務(wù)集
??virtual UDWORD?APIENTRY?Fn_Service_GetErrorCode()=0; //取得內(nèi)核操作錯(cuò)誤狀態(tài)代碼
??virtual VOID?APIENTRY?Fn_Service_GetMemoaryStatu()=0;//當(dāng)前內(nèi)存使用情況查看接口
?
?public: //單位頁(yè)面分配/回收服務(wù)集
??virtual UDWORD?APIENTRY?Fn_Service_MallocOnePage()=0;??
?????//分配一個(gè)頁(yè)面
??virtual UDWORD?APIENTRY?Fn_Service_FreeOnePage(UDWORD PageIndex)=0;?
?????//回收一個(gè)頁(yè)面
??
?public: //讀寫(xiě)服務(wù)集? 第一個(gè)參數(shù)為L(zhǎng)v1頁(yè)表對(duì)象指針? 第二個(gè)參數(shù)為虛擬地址 第3個(gè)參數(shù)為待寫(xiě)入的數(shù)據(jù)
??virtual BYTE?APIENTRY?Fn_Service_ReadByte(Lv1_MemoaryTable*?lpPageTableAddress,
?????????? UDWORD NewVirtualAddress)=0;
?????//按字節(jié)方式(8bit)讀取
??
??virtual VOID?APIENTRY?Fn_Service_WriteByte(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress,DWORD Value)=0;
?????//按字節(jié)方式(8bit)寫(xiě)入
??
??
??virtual WORD?APIENTRY?Fn_Service_ReadWord(Lv1_MemoaryTable*?lpPageTableAddress,
?????????? UDWORD NewVirtualAddress)=0;
?????//按字方式(16bit)讀取
??
??virtual VOID?APIENTRY?Fn_Service_WriteWord(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress,DWORD Value)=0;
?????//按字方式(16bit)寫(xiě)入
??
??
??virtual DWORD?APIENTRY?Fn_Service_ReadDword(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress)=0;
?????//按雙字方式(32bit)讀取
??
??virtual VOID?APIENTRY?Fn_Service_WriteDword(Lv1_MemoaryTable*?lpPageTableAddress,
???????????? UDWORD NewVirtualAddress,DWORD Value)=0;
?????//按雙字方式(32bit)寫(xiě)入
??
};
#define??LPCMEMOAEYKERNEL?CMemoaryKernel*??
LPCMEMOAEYKERNEL APIENTRY?Fn_iKernel_GetMemoaryManager();
#endif
//====================================================================//
Class_Lv1pt.cpp
//====================================================================//
#ifndef?_CLASS_LV1_PT
#define?_CLASS_LV1_PT
#include "../Include/Memoary_Class_Lv1Pt_Define.h"
#include "../Include/Memoary_Class_Define.h"
extern??MemoaryKernel???m_Venus;
Lv1_MemoaryTable::~Lv1_MemoaryTable()
{;}
Lv1_MemoaryTable::Lv1_MemoaryTable()
{
?PageBlock? = NO_ALLOCATION;
?PageStatus = UNINIT;
}
//頁(yè)表項(xiàng)對(duì)象初始化函數(shù),參數(shù)為頁(yè)索引號(hào).
//該函數(shù)將請(qǐng)求內(nèi)核分配一個(gè)空閑物理頁(yè)面以用來(lái)初始化,并將該頁(yè)面地址記入PageBlock中
UDWORD APIENTRY?Lv1_MemoaryTable::Fn_Service_Init(UDWORD?Init_PageIndex)
{
?PageIndex = Init_PageIndex;
?if ((PageBlock == NO_ALLOCATION) && (PageStatus == UNINIT))
??{
???PageBlock = m_Venus.Fn_Service_MallocOnePage();
???if (this->PageBlock != MEMOARY_ALLOCATE_ERROR_NO_ENOUGH_MEMOARY)
????{
?????AccessCounter = 0;
?????IsAccess = FALSE;
?????IsModify = FALSE;
?????PageStatus = MEMOARY;
?????SwapAddress = 0x0;
?????return?SUCCESS;
????}
???else
????{
?????PageBlock = NO_ALLOCATION;
?????return?FAILURE;
????}
??}
?else
??{
???return?FAILURE;
??}
}
//該函數(shù)將請(qǐng)求內(nèi)核釋放其所映射的物理頁(yè)面,并將PageBlock的數(shù)值設(shè)置為NO_ALLOCATION
//被釋放的頁(yè)面將被放入內(nèi)核管理的分配堆棧,共其他進(jìn)程使用
UDWORD?APIENTRY?Lv1_MemoaryTable::Fn_Service_Free()
{
?UDWORD?Resault = MEMOARY_KERNEL_FREE_PAGE_FAILURE_PAGE_UNUSED;
?_asm
??{
???mov?EAX,this
???cmp?[EAX]this.PageStatus,UNINIT
???je?Exit
???cmp?[EAX]this.PageBlock,NO_ALLOCATION
???je?Exit
??}
?
?Resault = m_Venus.Fn_Service_FreeOnePage(PageBlock);
?_asm?
??{
???cmp?EAX,SUCCESS
???jne?Exit
??}
?PageBlock = NO_ALLOCATION;
?PageStatus = UNINIT;
Exit:?
?return?Resault;
}
UDWORD?APIENTRY?Lv1_MemoaryTable::Fn_Service_GetPageBlock()
{
?return?PageBlock;
}
UDWORD?APIENTRY?Lv1_MemoaryTable::Fn_Service_GetPageStatu()
{
?return?PageStatus;
}
UDWORD?APIENTRY?Lv1_MemoaryTable::Fn_Service_GetAccessCounter()
{
?return?AccessCounter;
}
UDWORD?APIENTRY?Lv1_MemoaryTable::Fn_Service_GetIsModify()
{
?return?IsModify;
}
UDWORD?APIENTRY?Lv1_MemoaryTable::Fn_Service_GetIsAccess()
{
?return?IsAccess;
}
VOID?APIENTRY?Lv1_MemoaryTable::Fn_Service_SetPageStatu(UDWORD?NewStatu)
{
?PageStatus = NewStatu;
}
VOID?APIENTRY?Lv1_MemoaryTable::Fn_Service_IncAccessCounter()
{
?AccessCounter++;
}
VOID?APIENTRY?Lv1_MemoaryTable::Fn_Service_SetIsModidy(BOOL?NewFlag)
{
?IsModify = NewFlag;
}
VOID?APIENTRY?Lv1_MemoaryTable::Fn_Service_SetIsAccess(BOOL?NewFlag)
{
?IsAccess = NewFlag;
}
VOID?APIENTRY?Lv1_MemoaryTable::Fn_Service_SetSwapAddress(UDWORD?NewSwapAddress)
{
?SwapAddress = NewSwapAddress;
}
#endif
//===================================================================//
Main_Source.cpp
//===================================================================//
#include "./Include/Memoary_Gloable_Define.h"
//接口函數(shù)
LPCMEMOAEYKERNEL?APIENTRY?Fn_iKernel_GetMemoaryManager()
{
?return?(LPCMEMOAEYKERNEL)(&m_Venus);
}
//====================================================================//
MemoaryKernel.cpp
//====================================================================//
#include "../Include/Memoary_Class_Define.h"
MemoaryKernel::MemoaryKernel()
{;}
MemoaryKernel::~MemoaryKernel()
{;}
//內(nèi)核初始化函數(shù) 參數(shù)為物理內(nèi)存容量
VOID? APIENTRY?MemoaryKernel::Fn_Service_Init(UDWORD?NewMemoarySize)
{
?_asm?//物理內(nèi)存容量是否夠內(nèi)核啟動(dòng)運(yùn)行
??{
???mov?EAX,[NewMemoarySize]
???cmp?EAX,MIN_RUN_MEMOARY
???jae?KernelStart
???mov?EAX,this
???mov?[EAX]this.ErrorCode,MEMOARY_KERNEL_HALT_NO_ENOUGH_MEMOARY_FOR_INIT
??}
?cout<<"No Enough Memoary for MemoaryKernel(Venus) Init itself."<<endl;
?cout<<"EmuSolaris SYSTEM HALTTED Now."<<endl;
?_asm?
??{
???pop???????? edi
???pop???????? esi
???mov???????? esp,ebp
???pop???????? ebp
???ret???????? 8
??}
?if(NewMemoarySize > MAX_MEMOARY) {NewMemoarySize = MAX_MEMOARY;}
?//如果物理內(nèi)存容量超過(guò)了能管理的最大容量,則按能支持的最大容量處理,更大的地址看不見(jiàn)……=.=
KernelStart:
?
?MemoarySize = NewMemoarySize;
?UDWORD?SystemUsed = SYSTEM_USE_START_PAGE_ADDRESS;
?_SaveLinerAddress? = MEMOARY_MAP_BEGIN_STORE_LINE_ADDRESS;
?InPageOffset = NULL;
?PageAddressIndex = NULL;
?NowLineAddress = NULL;
?MallocCounter = 0;
?ErrorCode = NORMAL;
?GroupIndex = 1;
?_asm//這段匯編完成計(jì)算出NewMemoarySize對(duì)應(yīng)的最大頁(yè)號(hào)地址
??{
???push?EAX
???push?EDX
???push?ECX
???
???mov?EAX,[NewMemoarySize]
???mov?EDX,EAX
???and?EAX,0x0000FFFF
???
???
???shr?EDX,0x010
???and?EDX,0x0000FFFF
???
???mov?CX,0x01000
???div?CX
???sub?EAX,1
???and?EAX,0x0000FFFF
???mov?ECX,this
???mov?[ECX]this.MaxPageIndex,EAX
???
???pop?ECX
???pop?EDX
???pop?EAX
?
??}
?for(SystemUsed;SystemUsed<=SYSTEM_USE_END_PAGE_ADDRESS;SystemUsed++) //為系統(tǒng)使用的內(nèi)存做保留操作 :)
??{??????????????????? //這些地址將被用來(lái)保存 內(nèi)存分頁(yè)使用狀態(tài)映射圖和用于內(nèi)存分配的Malloc堆棧
???Fn_Service_SetBitMap(SystemUsed,USED);
??}
?StackEsp = MEMOARY_STACK_BEGIN_STORE_LINE_ADDRESS;//Malloc堆棧指針指向棧頂
?Fn_Service_Init_MallocStack(); //Malloc堆棧初始化
?IsPage = TRUE; //設(shè)置系統(tǒng)使用分頁(yè)模式管理內(nèi)存 至此內(nèi)核初始化完畢.
}
//內(nèi)存描述Map的設(shè)置函數(shù).
DWORD APIENTRY?MemoaryKernel::Fn_Service_SetBitMap(UDWORD PageIndex,BOOL Flag)
{?
?UDWORD?OffsetAddress;
?DWORD?Content;
?BYTE?Shift;
?if (PageIndex>MaxPageIndex) {return?FAILURE;}
?_asm
??{
?????? //保存寄存器
???push?ECX
???push?EDX
???push?EBX
???
???mov?EAX,[PageIndex]? //比較頁(yè)號(hào)是否合法,32MB內(nèi)存按4KB分頁(yè)支持的最大頁(yè)號(hào)為0-8192
???cmp?EAX,MAX_PAGE_NUMBER
???ja?EXIT
???mov?CL,0x020? //映射常數(shù)因子 由于x86寄存器是32bit長(zhǎng),所以取為32方便對(duì)齊運(yùn)算
???div?CL?? //取得頁(yè)號(hào)對(duì)應(yīng)的位映射在Map中的段偏移量,段長(zhǎng)以4Byte為單位。
???mov?BX,AX?? //取得頁(yè)號(hào)對(duì)應(yīng)的位映射在段內(nèi)的偏移量,并保存在BX中
???and?EAX,0x000000FF
???mov?CL,0x04?? //段長(zhǎng)常數(shù)因子,取4表示4Byte,因?yàn)?Byte = 32bit.
???mul?CL?? //取得自Map圖開(kāi)始到對(duì)應(yīng)段的具體地址,以Byte為單位.
???mov?[Shift],BH?//將段內(nèi)偏移量放Shift
???
???and?EAX,0x0000FFFF? //EAX高16位清空
???mov?[OffsetAddress],EAX //保存段偏移地址
???
??}
?//讀取Map中對(duì)應(yīng)的段
?Content = Fn_ReadDword(_SaveLinerAddress+OffsetAddress);
???
?_asm
??{
???mov?EAX,[Content]?//取得map圖中的對(duì)應(yīng)段入EAX
???xor?EDX,EDX
???mov?DL,[Flag]?
???cmp?DL,0???
???mov?EDX,0x01
???mov?CL,[Shift]
???je?SetUnuse
??//SetUse:?????//設(shè)置對(duì)應(yīng)位為1的操作
???shl?EDX,CL???//移動(dòng)shift位
???or?EAX,EDX???//設(shè)置對(duì)應(yīng)位
???mov?[Content],EAX?
???jmp?Exit
??SetUnuse:?????//設(shè)置對(duì)應(yīng)位為0的操作??
???shl?EDX,CL
???not?EDX
???and?EAX,EDX
???mov?[Content],EAX
??EXit:??????//恢復(fù)寄存器,退出。
???pop?EBX
???pop?EDX
???pop?ECX
???
??}
?Fn_WriteDword(_SaveLinerAddress+OffsetAddress,Content);//將對(duì)應(yīng)位寫(xiě)回Map
?return?SUCCESS;
}
//讀取內(nèi)存使用狀態(tài)Map圖的函數(shù)
DWORD?APIENTRY?MemoaryKernel::Fn_Service_GetBitMap(UDWORD PageIndex)
{
?UDWORD?OffsetAddress;
?DWORD?Content=GENERAL_PROTECT_ERROR_PAGE_INDEX_OVERFLOW;? //如果出錯(cuò),
????????//則這里放的就是出錯(cuò)代碼
?BYTE?Shift;
?if (PageIndex > MaxPageIndex) {return?FAILURE;}
?_asm
??{
??????? //保存寄存器
???push?ECX
???push?EDX
???push?EBX
???
???mov?EAX,[PageIndex]? //比較頁(yè)號(hào)是否合法,32MB內(nèi)存按4KB分頁(yè)支持的最大頁(yè)號(hào)為0-8192
???cmp?EAX,MAX_PAGE_NUMBER
???ja?EXIT
???mov?CL,0x020? //映射常數(shù)因子 由于x86寄存器是32bit長(zhǎng),所以取為32方便對(duì)齊運(yùn)算
???div?CL?? //取得頁(yè)號(hào)對(duì)應(yīng)的位映射在Map中的段偏移量,段長(zhǎng)以4Byte為單位。
???mov?BX,AX?? //取得頁(yè)號(hào)對(duì)應(yīng)的位映射在段內(nèi)的偏移量,并保存在BX中
???and?EAX,0x000000FF
???mov?CL,0x04?? //段長(zhǎng)常數(shù)因子,取4表示4Byte,因?yàn)?Byte = 32bit.
???mul?CL?? //取得自Map圖開(kāi)始到對(duì)應(yīng)段的具體地址,以Byte為單位.
???mov?[Shift],BH?//將段內(nèi)偏移量放Shift
???
???and?EAX,0x0000FFFF? //EAX高16位清空
???mov?[OffsetAddress],EAX? //將總線性偏移量放對(duì)應(yīng)變量
???
??}
?
?Content = Fn_ReadDword(_SaveLinerAddress+OffsetAddress);
???
?_asm
??{
???mov?EAX,[Content]?//取得map圖中的對(duì)應(yīng)段入EAX
???mov?CL,[Shift]
???shr?EAX,CL??//將EAX中對(duì)應(yīng)的位移動(dòng)到最低位
???and?EAX,0x00000001? //其他位清0
???mov?[Content],EAX? //保存在Content中
??EXit:??????//恢復(fù)寄存器,退出。
???pop?EBX
???pop?EDX
???pop?ECX
???
??}
?
?return?Content;
}
//加載虛擬/線性地址到分頁(yè)變換機(jī)構(gòu),以備進(jìn)行頁(yè)面地址變換操作
VOID?APIENTRY?MemoaryKernel::Fn_Service_LoadVirtualAddress(UDWORD VirtualAddress)
{
?this->NowLineAddress = VirtualAddress;
?if (IsPage == TRUE) {Fn_TranslateLineAddress();}
}
VOID?APIENTRY?MemoaryKernel::Fn_TranslateLineAddress()
{?
?_asm
??{
???
???push?EBX
???push?ECX
???mov?EBX,this
???mov?EAX,[EBX]this.NowLineAddress
???mov?ECX,EAX
???and?EAX,0x0FFF //清空高24位得到頁(yè)內(nèi)偏移地址
???mov?[EBX]this.InPageOffset,EAX
???shr?ECX,12 //右移動(dòng)12位,得到頁(yè)號(hào)地址
???and?EAX,0x01FFF
???
???cmp?ECX,[EBX]this.MaxPageIndex
???jbe?OK
???mov?ECX,MAX_PAGE_NUMBER
OK:
???mov?[EBX]this.PageAddressIndex,ECX
???pop?ECX
???pop?EBX
???
??}
}
VOID??APIENTRY?MemoaryKernel::Fn_Service_Init_MallocStack()
{
?UDWORD?LoopCounter=0;
?UDWORD?PageAddressCounter = 0x0;
?UDWORD?OpAddress = StackEsp; //設(shè)置分配堆棧的開(kāi)始存儲(chǔ)地址
?DWORD?IsUsed;
?for(;PageAddressCounter<=MaxPageIndex;PageAddressCounter++)? //這個(gè)for循環(huán)構(gòu)造一個(gè)組長(zhǎng)為1024,
??{??????//共N組的成組鏈表用于分配和回收內(nèi)存頁(yè)
???IsUsed = Fn_Service_GetBitMap(PageAddressCounter);
???if(IsUsed == FALSE? && LoopCounter != 0x0400) //0x0400是1024 LoopCounter負(fù)責(zé)記錄是否分配了1024個(gè),是的話則設(shè)置新組
????{
?????Fn_WriteWord(OpAddress,PageAddressCounter); //ExHAL函數(shù),以字方式寫(xiě)寫(xiě)模擬物理內(nèi)存
?????LoopCounter++;
?????OpAddress=OpAddress+2; //每個(gè)堆棧項(xiàng)占2個(gè)字節(jié),因此這里+2
????}
???else
????{
?????if(LoopCounter == 0x0400) //等于1024 表示一個(gè)組已經(jīng)分配完了,該設(shè)置新組了
??????{
???????Fn_WriteDword(OpAddress,OpAddress+4);?//ExHAL函數(shù),以雙字(32bit)方式寫(xiě)模擬物理內(nèi)存?
????????????//系統(tǒng)中存放的組是連續(xù)的,因此新組的開(kāi)始地址就是當(dāng)前組完畢后的地址
???????PageAddressCounter--; //頁(yè)面地址減1,否則會(huì)在所有l(wèi)oopCounter=0x0400時(shí)丟失1Byte內(nèi)存... T_T
???????LoopCounter=0;
???????OpAddress=OpAddress+4;//因?yàn)槎褩5淖詈笠豁?xiàng)是指向新組的開(kāi)始地址,因此是雙字32bit 所以+4
??????}??
????}
??}
?Fn_WriteDword(OpAddress,MALLOC_STACK_END_FLAG);? //for循環(huán)完畢,寫(xiě)入堆棧結(jié)束標(biāo)志
}
UDWORD?APIENTRY?MemoaryKernel::Fn_Service_MallocOnePage()
{
?UDWORD?Resault_Address;
?Resault_Address = (UDWORD)Fn_ReadWord(StackEsp);
?if ( Resault_Address == MALLOC_STACK_END_FLAG) //如果堆棧指針已經(jīng)指向了堆棧結(jié)尾標(biāo)志,說(shuō)明沒(méi)有可用物理內(nèi)存頁(yè)共分配了
??{
???ErrorCode=MEMOARY_ALLOCATE_ERROR_NO_ENOUGH_MEMOARY;
???return MEMOARY_ALLOCATE_ERROR_NO_ENOUGH_MEMOARY;
??}
?if (this->MallocCounter != 0x0400)
??{
???StackEsp=StackEsp+2;
???Fn_Service_SetBitMap(Resault_Address,USED);
???MallocCounter++; //分配次數(shù)計(jì)數(shù)器 每分配一次加1,1024次則讀入一個(gè)新堆棧
??}
?else
??{?//以下代碼重新取得新一組空閑頁(yè)面組的地址
???StackEsp = Fn_ReadDword(StackEsp); //將新組的開(kāi)始地址讀入堆棧操作指針
???
???if (StackEsp == MALLOC_STACK_END_FLAG) ////如果堆棧指針已經(jīng)指向了堆棧結(jié)尾標(biāo)志,
????{????//說(shuō)明沒(méi)有可用物理內(nèi)存頁(yè)共分配了
?????ErrorCode=MEMOARY_ALLOCATE_ERROR_NO_ENOUGH_MEMOARY;
?????return MEMOARY_ALLOCATE_ERROR_NO_ENOUGH_MEMOARY;??
????}
???
???Resault_Address?= (UDWORD)(Fn_ReadWord(StackEsp)); //讀出新的空閑物理頁(yè)面號(hào)
???Fn_Service_SetBitMap(Resault_Address,USED); //設(shè)置該頁(yè)的分配狀態(tài)位
???StackEsp = StackEsp+2; //已經(jīng)分配了一個(gè)頁(yè)面 因此地址+2
???MallocCounter = 1; //已經(jīng)分配了一個(gè)頁(yè)面,因此為1而不是0
???GroupIndex++; //讀取了新組,因此+1
??}
?return?Resault_Address;
}
UDWORD?APIENTRY?MemoaryKernel::Fn_Service_FreeOnePage(UDWORD PageIndex)? //回收一個(gè)頁(yè)面
{
?if (PageIndex <= SYSTEM_USE_END_PAGE_ADDRESS) //檢測(cè)即將釋放的地址的合法性
??{
???ErrorCode = GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY;
???return?GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY;
??}
?if (PageIndex > MaxPageIndex) //檢測(cè)地址是否overflow
??{
???ErrorCode = GENERAL_PROTECT_ERROR_PAGE_INDEX_OVERFLOW;
???return?GENERAL_PROTECT_ERROR_PAGE_INDEX_OVERFLOW;
??}
?if (StackEsp==MEMOARY_STACK_BEGIN_STORE_LINE_ADDRESS) //簡(jiǎn)單的操作合法性檢測(cè)
??{
???ErrorCode = MEMOARY_FREE_ERROR_NO_MEMOARY_NEED_FREE;
???return MEMOARY_FREE_ERROR_NO_MEMOARY_NEED_FREE;
??}
?
?Fn_Service_GetBitMap(PageIndex); //進(jìn)一步在內(nèi)存使用狀態(tài)圖中查看該頁(yè)的當(dāng)前狀態(tài)
?_asm
??{
???cmp?EAX,USED //如果該頁(yè)已經(jīng)是空閑頁(yè),則不再對(duì)Malloc堆棧進(jìn)行操作
???jne?ErrorFree //以避免發(fā)生不同步的問(wèn)題
??}
?if (MallocCounter != 0) //!=0說(shuō)明當(dāng)前的組還未用完
??{?//先移動(dòng)指針,再讀出空閑物理頁(yè)面號(hào)
???StackEsp = StackEsp-2;
???Fn_WriteWord(StackEsp,PageIndex);
???Fn_Service_SetBitMap(PageIndex,UNUSE);
???MallocCounter--;
??}
?else
??{
???StackEsp = StackEsp-6;
???Fn_WriteWord(StackEsp,PageIndex);
???Fn_Service_SetBitMap(PageIndex,UNUSE);
???MallocCounter = 1023; //=1023是因?yàn)橐呀?jīng)分配了一個(gè)頁(yè)面 因此不是1024!
???GroupIndex--;
??}
?
?return?SUCCESS;
ErrorFree:
?ErrorCode = MEMOARY_KERNEL_FREE_PAGE_FAILURE_PAGE_UNUSED;
?return?MEMOARY_KERNEL_FREE_PAGE_FAILURE_PAGE_UNUSED;
}
UDWORD?APIENTRY?MemoaryKernel::Fn_Service_GetErrorCode()
{
?return?ErrorCode;
}
VOID?APIENTRY?MemoaryKernel::Fn_Service_GetMemoaryStatu()
{
?U32?OpAddress=0x0;
?U32?LineAddress=0x0;
?U32?DisplayOpAddress=OpAddress+0x0F;
?CHAR?Pause=NULL;
?
?cout<<"This is Memoary Use Statu Viewer. :)"<<endl;
?cout<<"Command list:"<<endl;
?cout<<"A: Display All Memoary Address Use Statu."<<endl;
?cout<<"p: Display Memoary Address Use Statu on Group Mode."<<endl;
?cout<<"q: Exit."<<endl;
?cout.setf(ios::hex);
?do{
??if (Pause != 'a' && Pause !='A')
???{
????cout<<"Input Command Here: "<<flush;
????cin>>Pause;
???}
??if(Pause == 'A'||
???? Pause == 'a'||
???? Pause == 'p'||
???? Pause == 'P')
???{
????if(IsPage == TRUE)
?????{
??????cout<<"SYSTEM working in PageMode."<<endl;
??????for(OpAddress;OpAddress<=SYSTEM_USE_END_PAGE_ADDRESS;OpAddress++) //因?yàn)橐韵虏糠质茄h(huán)為了加速用了asm 其實(shí)就是算個(gè)地址
???????{
????????_asm?mov?EAX,[OpAddress]
????????_asm?shl?EAX,0x0C
????????_asm?mov?[LineAddress],EAX?
????????cout<<"PageIndexAddress: 0x0"<<OpAddress<<" (LineAddress: 0x0"<<LineAddress<<"-"<<flush;
????????_asm?add?DWORD ptr[LineAddress],0x0FFF
????????cout<<"0x0"<<LineAddress<<")"<<" is Used By SYSTEM."<<endl;
???????}
??????for(OpAddress;OpAddress<=(DisplayOpAddress);OpAddress++)
???????{
????????_asm
?????????{
??????????
??????????push?ECX
??????????
??????????mov?EAX,[OpAddress]
??????????mov?ECX,this
??????????mov?ECX,[ECX]this.MaxPageIndex
??????????cmp?EAX,ECX
??????????ja?DisplayFinish? //檢測(cè)到最大地址已經(jīng)顯示完畢則跳出顯示循環(huán)
??????????pop?ECX
??????????
?????????}
????????if (Fn_Service_GetBitMap(OpAddress) == USED)
?????????{
??????????_asm?mov?EAX,[OpAddress]
??????????_asm?shl?EAX,0x0C
??????????_asm?mov?[LineAddress],EAX?
??????????cout<<"PageIndexAddress: 0x0"<<OpAddress<<" (LineAddress: 0x0"<<LineAddress<<"-"<<flush;
??????????_asm?add?DWORD ptr[LineAddress],0x0FFF
??????????cout<<"0x0"<<LineAddress<<")"<<" is Used By User Programme"<<endl;
?????????}
????????else
?????????{?
??????????_asm?mov?EAX,[OpAddress]
??????????_asm?shl?EAX,0x0C
??????????_asm?mov?[LineAddress],EAX?
??????????cout<<"PageIndexAddress: 0x0"<<OpAddress<<" (LineAddress: 0x0"<<LineAddress<<"-"<<flush;
??????????_asm?add?DWORD ptr[LineAddress],0x0FFF
??????????cout<<"0x0"<<LineAddress<<")"<<" is Free."<<endl;
?????????}
???????}
DisplayFinish:?
??????if (OpAddress < MaxPageIndex)
???????{
????????DisplayOpAddress = DisplayOpAddress+0x10;
???????}
??????else
???????{
????????Pause='q';
???????}
?????}
????else
?????{
??????cout<<"Now EmuSoloris SYSTEM Haltted."<<endl;
??????Pause = 'q';
?????}
???}
?}while(Pause != 'q' && Pause != 'Q');
?cout.setf(ios::dec);
}
BYTE?APIENTRY?MemoaryKernel::Fn_Service_ReadByte(Lv1_MemoaryTable*?lpPageTableAddress,
????????UDWORD NewVirtualAddress)
{
?UDWORD?CurrentPageBlock;
?BYTE?Resault=0;
?Fn_Service_LoadVirtualAddress(NewVirtualAddress);//加載虛擬地址到內(nèi)核
?lpPageTableAddress = lpPageTableAddress+PageAddressIndex; //將地址調(diào)整到對(duì)應(yīng)的頁(yè)表項(xiàng)上
?CurrentPageBlock = lpPageTableAddress->Fn_Service_GetPageBlock(); //取得對(duì)應(yīng)頁(yè)表項(xiàng)映射的物理空閑頁(yè)號(hào)
?_asm?
??{
???cmp?[CurrentPageBlock],SYSTEM_USE_END_PAGE_ADDRESS //對(duì)系統(tǒng)地址做保護(hù)
???jbe?AccessDeny
??}
??lpPageTableAddress->Fn_Service_GetPageStatu();
?_asm
??{?//這一段代碼對(duì)頁(yè)表項(xiàng)映射的合法性做進(jìn)一步檢測(cè)
???cmp?EAX,MEMOARY //標(biāo)志位是MEMOAY則合法
???jne?AddressError
???cmp?EAX,SWAPPER
???je?INT_PageSwap
???mov?EAX,this
???mov?EAX,[EAX]this.MaxPageIndex
???cmp?[CurrentPageBlock],EAX //映射的地址沒(méi)有overflow則完全合法
???ja?AddressError
//AddressOK:?
???push?ECX
???mov?EAX,[CurrentPageBlock]
???shl?EAX,0x0C
???mov?ECX,this
???mov?ECX,[ECX]this.InPageOffset
???and?ECX,0x0FFF
???add?EAX,ECX //EAX中放的就是轉(zhuǎn)換后的線性地址
???
???push?EAX
???call?Fn_ReadByte //讀取一個(gè)字節(jié)
???mov?BYTE ptr[Resault],AL
???
???pop?ECX
??}
?lpPageTableAddress->Fn_Service_SetIsAccess(TRUE);? //頁(yè)是否被訪問(wèn)屬性設(shè)置為真
?lpPageTableAddress->Fn_Service_IncAccessCounter();? //頁(yè)訪問(wèn)計(jì)數(shù)器增加1
?return?Resault;
INT_PageSwap:
?ErrorCode = MEMOARY_KERNEL_INT_READ_PAGE_NOT_IN_MEMOARY;
?_asm?mov?EAX,MEMOARY_KERNEL_INT_READ_PAGE_NOT_IN_MEMOARY
?_asm?jmp?Exit?
AccessDeny: //企圖訪問(wèn)系統(tǒng)使用的空間的出錯(cuò)處理
?ErrorCode = GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY;
?_asm?mov?EAX,GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY
?_asm?jmp?Exit
AddressError:?
?ErrorCode = MEMOARY_KERNEL_READ_FAILURE_PAGE_NOT_ALLOCATION;
?_asm?mov?EAX,MEMOARY_KERNEL_READ_FAILURE_PAGE_NOT_ALLOCATION
Exit:? //出錯(cuò)處理出口
?_asm
??{
???pop???? edi
???pop???? esi
???pop???? ebx
???mov???? esp,ebp
???pop???? ebp
???ret???? 0Ch?
??}
}
//實(shí)現(xiàn)思路同MemoaryKernel::Fn_Service_ReadByte函數(shù)
VOID?APIENTRY?MemoaryKernel::Fn_Service_WriteByte(Lv1_MemoaryTable*?lpPageTableAddress,
????????UDWORD NewVirtualAddress,DWORD Value)
{
?UDWORD?CurrentPageBlock;
?Fn_Service_LoadVirtualAddress(NewVirtualAddress);?
?lpPageTableAddress = lpPageTableAddress+PageAddressIndex;
?CurrentPageBlock = lpPageTableAddress->Fn_Service_GetPageBlock();
?_asm?
??{
???cmp?[CurrentPageBlock],SYSTEM_USE_END_PAGE_ADDRESS
???jbe?AccessDeny
??}?
?lpPageTableAddress->Fn_Service_GetPageStatu();
?_asm
??{
???cmp?EAX,MEMOARY
???jne?AddressError
???cmp?EAX,SWAPPER
???je?INT_PageSwap?
???mov?EAX,this
???mov?EAX,[EAX]this.MaxPageIndex
???cmp?[CurrentPageBlock],EAX
???ja?AddressError
?
???push?ECX
???mov?EAX,[CurrentPageBlock]
???shl?EAX,0x0C
???mov?ECX,this
???mov?ECX,[ECX]this.InPageOffset
???and?ECX,0x0FFF
???add?ECX,EAX
???mov?EAX,[Value]
???and?EAX,0x0FF
???push?EAX
???push?ECX
???call?Fn_WriteByte
???pop?ECX
??}
?
?lpPageTableAddress->Fn_Service_SetIsAccess(TRUE);? //頁(yè)是否被訪問(wèn)屬性設(shè)置為真
?lpPageTableAddress->Fn_Service_IncAccessCounter();? //頁(yè)訪問(wèn)計(jì)數(shù)器增加1
?lpPageTableAddress->Fn_Service_SetIsModidy(TRUE);? //頁(yè)表對(duì)應(yīng)的物理頁(yè)是否被修改標(biāo)志為真
?_asm
??{
???pop???? edi
???pop???? esi
???pop???? ebx
???mov???? esp,ebp
???pop???? ebp
???ret???? 10h
??}
INT_PageSwap:
?ErrorCode = MEMOARY_KERNEL_INT_WRITE_PAGE_NOT_IN_MEMOARY;
?_asm?mov?EAX,MEMOARY_KERNEL_INT_WRITE_PAGE_NOT_IN_MEMOARY
?_asm?jmp?Exit
AccessDeny:
?ErrorCode = GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY;
?_asm?mov?EAX,GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY
?_asm?jmp?Exit
AddressError:?
?ErrorCode = MEMOARY_KERNEL_READ_FAILURE_PAGE_NOT_ALLOCATION;
?_asm?mov?EAX,MEMOARY_KERNEL_READ_FAILURE_PAGE_NOT_ALLOCATION
Exit:?
?_asm
??{
???pop???? edi
???pop???? esi
???pop???? ebx
???mov???? esp,ebp
???pop???? ebp
???ret???? 10h?
??}
}
//實(shí)現(xiàn)思路同MemoaryKernel::Fn_Service_ReadByte函數(shù)
WORD?APIENTRY?MemoaryKernel::Fn_Service_ReadWord(Lv1_MemoaryTable*?lpPageTableAddress,
????????UDWORD NewVirtualAddress)
{
?UDWORD?CurrentPageBlock;
?WORD?Resault;
?Fn_Service_LoadVirtualAddress(NewVirtualAddress);?
?lpPageTableAddress = lpPageTableAddress+PageAddressIndex;
?CurrentPageBlock = lpPageTableAddress->Fn_Service_GetPageBlock();
?_asm?
??{
???cmp?[CurrentPageBlock],SYSTEM_USE_END_PAGE_ADDRESS
???jbe?AccessDeny
??}
?lpPageTableAddress->Fn_Service_GetPageStatu();
?_asm
??{
???cmp?EAX,MEMOARY
???jne?AddressError
???cmp?EAX,SWAPPER
???je?INT_PageSwap??
???mov?EAX,this
???mov?EAX,[EAX]this.MaxPageIndex
???cmp?[CurrentPageBlock],EAX
???ja?AddressError
?
??
???push?ECX
???mov?EAX,[CurrentPageBlock]
???shl?EAX,0x0C
???mov?ECX,this
???mov?ECX,[ECX]this.InPageOffset
???and?ECX,0x0FFF
???add?EAX,ECX
???
???push?EAX
???call?Fn_ReadWord
???mov?WORD ptr[Resault],AX
???
???pop?ECX
??}
?lpPageTableAddress->Fn_Service_SetIsAccess(TRUE);? //頁(yè)是否被訪問(wèn)屬性設(shè)置為真
?lpPageTableAddress->Fn_Service_IncAccessCounter();? //頁(yè)訪問(wèn)計(jì)數(shù)器增加1
?return?Resault;
INT_PageSwap:
?ErrorCode = MEMOARY_KERNEL_INT_READ_PAGE_NOT_IN_MEMOARY;
?_asm?mov?EAX,MEMOARY_KERNEL_INT_READ_PAGE_NOT_IN_MEMOARY
?_asm?jmp?Exit
AccessDeny:
?ErrorCode = GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY;
?_asm?mov?EAX,GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY
?_asm?jmp?Exit
AddressError:?
?ErrorCode = MEMOARY_KERNEL_READ_FAILURE_PAGE_NOT_ALLOCATION;
?_asm?mov?EAX,MEMOARY_KERNEL_READ_FAILURE_PAGE_NOT_ALLOCATION
Exit:?
?_asm
??{
???pop???? edi
???pop???? esi
???pop???? ebx
???mov???? esp,ebp
???pop???? ebp
???ret???? 0Ch?
??}
}
//實(shí)現(xiàn)思路同MemoaryKernel::Fn_Service_ReadByte函數(shù)
VOID?APIENTRY?MemoaryKernel::Fn_Service_WriteWord(Lv1_MemoaryTable*?lpPageTableAddress,
????????UDWORD NewVirtualAddress,DWORD Value)
{
?UDWORD?CurrentPageBlock;
?Fn_Service_LoadVirtualAddress(NewVirtualAddress);?
?lpPageTableAddress = lpPageTableAddress+PageAddressIndex;
?CurrentPageBlock = lpPageTableAddress->Fn_Service_GetPageBlock();
?_asm?
??{
???cmp?[CurrentPageBlock],SYSTEM_USE_END_PAGE_ADDRESS
???jbe?AccessDeny
??}
?lpPageTableAddress->Fn_Service_GetPageStatu();
?_asm
??{
???cmp?EAX,MEMOARY
???jne?AddressError
???cmp?EAX,SWAPPER
???je?INT_PageSwap?
???mov?EAX,this
???mov?EAX,[EAX]this.MaxPageIndex
???cmp?[CurrentPageBlock],EAX
???ja?AddressError
?
???push?ECX
???mov?EAX,[CurrentPageBlock]
???shl?EAX,0x0C
???mov?ECX,this
???mov?ECX,[ECX]this.InPageOffset
???and?ECX,0x0FFF
???add?ECX,EAX
???
???mov?EAX,[Value]
???and?EAX,0x0FFFF
???push?EAX
???push?ECX
???call?Fn_WriteWord
??}
?lpPageTableAddress->Fn_Service_SetIsAccess(TRUE);? //頁(yè)是否被訪問(wèn)屬性設(shè)置為真
?lpPageTableAddress->Fn_Service_IncAccessCounter();? //頁(yè)訪問(wèn)計(jì)數(shù)器增加1
?lpPageTableAddress->Fn_Service_SetIsModidy(TRUE); //設(shè)置是否修改標(biāo)志為真
?_asm
??{?
???pop?ECX
???pop???? edi
???pop???? esi
???pop???? ebx
???mov???? esp,ebp
???pop???? ebp
???ret???? 10h
??}
INT_PageSwap:
?ErrorCode = MEMOARY_KERNEL_INT_WRITE_PAGE_NOT_IN_MEMOARY;
?_asm?mov?EAX,MEMOARY_KERNEL_INT_WRITE_PAGE_NOT_IN_MEMOARY
?_asm?jmp?Exit
AccessDeny:
?ErrorCode = GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY;
?_asm?mov?EAX,GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY
?_asm?jmp?Exit
AddressError:?
?ErrorCode = MEMOARY_KERNEL_READ_FAILURE_PAGE_NOT_ALLOCATION;
?_asm?mov?EAX,MEMOARY_KERNEL_READ_FAILURE_PAGE_NOT_ALLOCATION
Exit:?
?_asm
??{?
???pop???? edi
???pop???? esi
???pop???? ebx
???mov???? esp,ebp
???pop???? ebp
???ret???? 10h?
??}
}
//實(shí)現(xiàn)思路同MemoaryKernel::Fn_Service_ReadByte函數(shù)
DWORD?APIENTRY?MemoaryKernel::Fn_Service_ReadDword(Lv1_MemoaryTable*?lpPageTableAddress,
???????? UDWORD NewVirtualAddress)
{
?UDWORD?CurrentPageBlock;
?DWORD?Resault;
?Fn_Service_LoadVirtualAddress(NewVirtualAddress);?
?lpPageTableAddress = lpPageTableAddress+PageAddressIndex;
?CurrentPageBlock = lpPageTableAddress->Fn_Service_GetPageBlock();
?_asm?
??{
???cmp?[CurrentPageBlock],SYSTEM_USE_END_PAGE_ADDRESS
???jbe?AccessDeny
??}
?lpPageTableAddress->Fn_Service_GetPageStatu();
?_asm
??{
???cmp?EAX,MEMOARY
???jne?AddressError
???cmp?EAX,SWAPPER
???je?INT_PageSwap??
???mov?EAX,this
???mov?EAX,[EAX]this.MaxPageIndex
???cmp?[CurrentPageBlock],EAX
???ja?AddressError
?
???push?ECX
???mov?EAX,[CurrentPageBlock]
???shl?EAX,0x0C
???mov?ECX,this
???mov?ECX,[ECX]this.InPageOffset
???and?ECX,0x0FFF
???add?EAX,ECX
???
???push?EAX
???call?Fn_ReadDword
???mov?DWORD ptr[Resault],EAX
???
???pop?ECX
??}
?lpPageTableAddress->Fn_Service_SetIsAccess(TRUE);? //頁(yè)是否被訪問(wèn)屬性設(shè)置為真
?lpPageTableAddress->Fn_Service_IncAccessCounter();? //頁(yè)訪問(wèn)計(jì)數(shù)器增加1
?return?Resault;
INT_PageSwap:
?ErrorCode = MEMOARY_KERNEL_INT_READ_PAGE_NOT_IN_MEMOARY;
?_asm?mov?EAX,MEMOARY_KERNEL_INT_READ_PAGE_NOT_IN_MEMOARY
?_asm?jmp?Exit?
AccessDeny:
?ErrorCode = GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY;
?_asm?mov?EAX,GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY
?_asm?jmp?Exit
AddressError:?
?ErrorCode = MEMOARY_KERNEL_READ_FAILURE_PAGE_NOT_ALLOCATION;
?_asm?mov?EAX,MEMOARY_KERNEL_READ_FAILURE_PAGE_NOT_ALLOCATION
Exit:
?_asm
??{
???pop???? edi
???pop???? esi
???pop???? ebx
???mov???? esp,ebp
???pop???? ebp
???ret???? 0Ch?
??}
}
//實(shí)現(xiàn)思路同MemoaryKernel::Fn_Service_ReadByte函數(shù)
VOID?APIENTRY?MemoaryKernel::Fn_Service_WriteDword(Lv1_MemoaryTable* lpPageTableAddress,
????????UDWORD NewVirtualAddress,DWORD Value)
{
?UDWORD?CurrentPageBlock;
?Fn_Service_LoadVirtualAddress(NewVirtualAddress);?
?lpPageTableAddress = lpPageTableAddress+PageAddressIndex;
?CurrentPageBlock = lpPageTableAddress->Fn_Service_GetPageBlock();
?_asm?
??{
???cmp?[CurrentPageBlock],SYSTEM_USE_END_PAGE_ADDRESS
???jbe?AccessDeny
??}
?lpPageTableAddress->Fn_Service_GetPageStatu();
?_asm
??{
???cmp?EAX,MEMOARY
???jne?AddressError
???cmp?EAX,SWAPPER
???je?INT_PageSwap?
???mov?EAX,this
???mov?EAX,[EAX]this.MaxPageIndex
???cmp?[CurrentPageBlock],EAX
???ja?AddressError
?
???push?ECX
???mov?EAX,[CurrentPageBlock]
???shl?EAX,0x0C
???mov?ECX,this
???mov?ECX,[ECX]this.InPageOffset
???and?ECX,0x0FFF
???add?ECX,EAX
???
???mov?EAX,[Value]
???push?EAX
???push?ECX
???call?Fn_WriteDword
??}
?lpPageTableAddress->Fn_Service_SetIsAccess(TRUE);? //頁(yè)是否被訪問(wèn)屬性設(shè)置為真
?lpPageTableAddress->Fn_Service_IncAccessCounter();? //頁(yè)訪問(wèn)計(jì)數(shù)器增加1
?lpPageTableAddress->Fn_Service_SetIsModidy(TRUE);? //設(shè)置是否修改標(biāo)志為真
?_asm
??{
???pop?ECX
???pop???? edi
???pop???? esi
???pop???? ebx
???mov???? esp,ebp
???pop???? ebp
???ret???? 10h?
??}
INT_PageSwap:
?ErrorCode = MEMOARY_KERNEL_INT_WRITE_PAGE_NOT_IN_MEMOARY;
?_asm?mov?EAX,MEMOARY_KERNEL_INT_WRITE_PAGE_NOT_IN_MEMOARY
?_asm?jmp?Exit
AccessDeny:
?ErrorCode = GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY;
?_asm?mov?EAX,GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY
?_asm?jmp?Exit
AddressError:?
?ErrorCode = MEMOARY_KERNEL_READ_FAILURE_PAGE_NOT_ALLOCATION;
?_asm?mov?EAX,MEMOARY_KERNEL_READ_FAILURE_PAGE_NOT_ALLOCATION
Exit:
?_asm
??{?
???pop???? edi
???pop???? esi
???pop???? ebx
???mov???? esp,ebp
???pop???? ebp
???ret???? 10h?
??}
}
上面的代碼如果編譯不正常,歡迎大家連續(xù)我。 :)
?