操作系統中分頁管理內核的模擬與實現
??
?現代操作系統大部分都采用了分頁的方式對物理內存進行管理,Intel 從80386之后也在硬件上支持的分頁管理,為操作系統的設計和實現帶來了很多便利之處。
?由于實際去實現一個操作系統的內存管理內核是一件相對比較困難的事情,因此我們今天將用模擬的方式來設計和實現一個操作系統的分頁管理內核。由于我自己也是一個學生,因此有說的不妥甚至錯誤的地方,請各位看官不要吝嗇您的意見建議甚至批評。如無特別說明,下文的物理內存地址一詞均指模擬物理內存中的物理地址。
一切開始以前先來確定一些基準數據:
1.?物理頁的大?。何锢眄摰拇笮⊥ǔ:陀布到y有關,
2.?比如Intel80386及以后的處理器都是按4KB大小來分頁。這里我們也選擇用4KB來作為分頁的尺寸。
3.?邏輯頁的大?。哼壿嬳摰拇笮€人認為和物理頁取同4.?樣大小最好,5.?因為這樣可以不6.?用擔心頁邊界問題,7.?并且在設計分頁變換機構時比較容易實現。因此也取為4KB。
8.?系統能有效管理的最大內存:作為一個模擬系統,9.?這里我取32MB作為最大內存管理上限,10.?太大了沒什么實際意義,11.?再說模擬系統跑起來也會很占資源。
12.?頁號地址范圍:依照邏輯頁尺寸和支持的最大內存,13.?系統中最多可有8192個邏輯頁面,14.?則頁面地址為0x0-0x1FFF
15.?頁內偏移量范圍:頁尺寸取為4KB 則頁內偏移地址為0x0-0x0fff.。
在分頁管理系統中,地址的通常不止一種。在我們現在要做的系統中,地址分為3類,既分頁地址,線性地址,虛擬地址。
線性地址:線性地址既存儲器的物理地址,在系統內核未初始化和初始化時,都將使用線性地址操作內存。
虛擬地址:虛擬地址是在分頁后產生的。其含義和線形地址相同,在系統中存在的各個進程,都使用虛擬地址訪問內存,虛擬地址傳入內核后,內核利用該進程的頁表和自身的頁地址變換機構將虛擬地址映射為某一個線性地址。
分頁地址:分頁地址由2部分組成,按照上文的基準數據設定,其結構如下:
????BBBBBBBBBBBBB:BBBBBBBBBBBB
?前一部分共13bit用來記錄頁號地址,后一部分共12bit用來記錄頁內偏移量。由于我們將物理頁和邏輯頁的尺寸統一了,因此分頁地址所表示的整體意義和線性地址是一樣的。
例如:分頁地址0000000000001000000000001 是0x1001。作為分頁地址,它表示物理內存中第二個物理頁(注意,不是第一個物理頁,因為0x0000也是有效地址,表示的是第一個物理頁),頁內偏移量為01。這個分頁地址所表示的線性地址為:頁號×頁尺寸+頁內偏移量,即:1×4096+1=4097 (0x1001)??梢钥吹?,從整體上來看,分頁地址和線性地址在意義上一樣的,但是分頁地址和線性地址所表示的自身含義則是完全不同的,這一點在邏輯頁和物理頁尺寸不統一的情況下尤為明顯,并且在這種情況下,分頁地址和線性地址的整體含義也就完全不同了。由此看出,邏輯頁和物理頁尺寸的統一給我們設計和實現內核的地址變換部分提供了很大的便利。
?在正式開始設計內核前,先來看看現代操作系統的一個重要特征:硬件無關性。這個特征通常是提供給用戶的。但是個人認為,在操作系統的底層設計中,也應該有一個接口部分是直接操作硬件,而其他部分在這個部分之上,通過這個接口去訪問和控制硬件。這樣做可以使得操作系統的實現可以在某種程度上脫離具體硬件規格,并且可以給移植帶來方便。這種設計思路在Microsoft Windows NT家族的中得到了具體的體現,NT中使用了“硬件抽象層”(HAL)的概念來分離操作系統的相對高層部分和底層硬件。各個高層部分通過HAL層來訪問和控制硬件,而不是將各種對硬件的訪問和控制操作分散在系統的各個角落。這種設計思路將在我們今天即將開始設計的模擬內核中再一次得到體現。這就是“模擬硬件抽象層”(EmuHAL)。
?EmuHAL的設計思路完全取自Windows NT的HAL。作為給這個模擬內核搭配的HAL層,EmuHAL將提供一個基本上完全真實的物理內存環境供我們來操作,你可以認為通過EmuHAL層進行操作和訪問的是完全的一個物理硬件,而不必要將其想象成別的什么。在這里,EmuHAL層通過利用一個數組,來提供真實的物理內存操作環境。下面是其提供的接口函數:
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);
這些函數都是對內存的原子操作的模擬。除去第一初始化函數外,從上到下一共3組,每組對應一個讀寫服務集,分別為:字節讀/寫集,字讀/寫集, 雙字讀/寫集。EmuHAL層的實現源代碼如下:
宏定義頭文件::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 層源代碼實現文件: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個文件中,Base.h 是我個人給自己寫的類型定義和宏定義文件。在后面設計實現內核時也會用到。從現在開始,我們正式進入內核的設計。
?首先,我們要實現的模擬內核是內存分頁管理內核,但是由于分頁管理時有可能出現頁表過長的情況(這在頁尺寸較小但需要管理的內存總量很大時尤其明顯),這時我們采用的方法是將頁表分組,即多級頁表的方式。那么我們現在正在設計的模擬內核也需要實現這樣的功能嗎?我個人給出的答案是否。并不是因為我們管理的最大內存只有32MB所以不需要這樣的功能,而是由我們所設計的模擬內核在一個真實的操作系統所處的位置導致的。個人認為,在真實的操作系統中,內存管理內核應該并不是一個單獨整體,而是由一個層次結構組成。大致上如下:
???????系統調用接口層
???????頁表管理層(高級)
???????頁表管理層(低級)
???????HAL層
其中“頁表管理層(高級)”部分實現對二級或者多級頁表的管理,而頁表管理層(低級)部分則實現對于一級頁表中的地址映射,變換操作,同時由于該部分是緊挨HAL層的,因此對物理內存的訪問也將通過該層傳遞到HAL層??赡芎芏嗳艘獑枺瑸槭裁床话褜σ患夗摫淼牟僮鳘毩⒊鰜砟??我是這樣考慮的,由于無論頁表是多級還是一級,最終存放待映射地址的總是一級頁表,在訪問到一級頁表后,緊接著馬上就要進行對硬件的操作和訪問,因此為了高效,我將從一級頁表到傳遞給HAL操作的實現部分包含在了“頁表管理層(低級)”中?,F在我們就依照這樣的層次結構,來設計這個模擬內核。以下是這個工程的名字和這個模擬內核的代號,在后文中,我可能將頻繁使用到這些代號。
?工程名:??操作系統中分頁管理內核的模擬
?工程代號:??EmuSolaris
?內核代號:??Venus
我將采用C++來設計和實現這個模擬內核,并且為了快速和方便,會使用一些asm指令,但是不會太復雜。
?作為操作系統中內存管理內核的最底層部分(僅高于HAL層),Venus必須明確知道其將要管理的硬件對象的具體參數,在這里,就是物理內存的尺寸,并且利用這個數據,可以計算出系統中合法物理和邏輯頁面號的范圍。另外,在整個EmuSolaris中,Venus應該是做為在HAL層被加載后首先被加載的內核。在加載后,整個物理內存的操作和訪問都將由Venus去控制。并且在加載完后,分頁地址就應該可以開始使用,物理內存也已經被劃分為邏輯頁和物理頁,并且可以開始對物理內存按頁為單位進行分配和回收,提供給高層部分的內存訪問接口也已經初始化完畢,可以利用指定的頁表對內存進行訪問了。以上就是我認為應該最先設計并實現的基礎功能。相對的,Venus應該有如下的數據結構以用于支持分頁變換和地址映射功能。注意,這里所有的數據類型定義符都請參看前文的Base.h。
BOOL?IsPage;???? //是否分頁管理 正常初始化時為1,即使用分頁管理
??UDWORD??PageAddressIndex;? //虛擬地址中的頁號地址?
??UDWORD??InPageOffset;??? //虛擬地址中的頁內偏移地址
??UDWORD??NowLineAddress;??? //當前等待變換或者使用的虛擬地址
??UDWORD??ErrorCode;????? //錯誤代碼變量
??UDWORD??MemoarySize;??? //當前總共內存容量
??UDWORD??MaxPageIndex;?//最大頁面號,有初始化時的總計內存容量決定.
為了實現上面所說的基礎功能,Venus應該具有如下的操作函數:
??
VOID?APIENTRY?Fn_TranslateLineAddress();
?VOID?APIENTRY?Fn_Service_LoadVirtualAddress(UDWORD VirtualAddress);
VOID?APIENTRY?Fn_Service_Init(UDWORD?NewMemoarySize);
Fn_Service_LoadVirtualAddress(UDWORD VirtualAddress)函數實現加載虛擬地址到Venus的操作。在上文中的數據結構中,PageAddressIndex和InPageOffset分別用來保存當前加載的虛擬地址中的頁號地址和頁內偏移量地址。Fn_Service_LoadVirtualAddress函數就是對這個2個數據對象進行操作。而Fn_TranslateLineAddress();則是執行具體變換動作的函數,在IsPage為真的情況下,這個函數將會按照由Fn_Service_LoadVirtualAddress的參數傳遞過來的地址進行變換,并將結果分別放在PageAddressIndex和InPageOffset中。而Fn_Service_LoadVirtualAddress中所帶的參數則會保存在NowLineAddress中。這個設計可以供以后在擴展系統時使用。到這里,虛擬地址和線性地址轉換為分頁地址的操作就完成了。
由于分頁管理的緣故,EmuSolaris中運行的其他進程都將使用虛擬地址來訪問內存,并且必須提供頁表以供Venus進行從虛擬地址到物理地址的映射和變換。由此可以得到Venus的運行圖:
加載待讀取的虛擬地址à利用指定的頁表進行地址變換,得到物理地址à將待訪問的地址傳遞給EmuHAL層àEmuHAL層完成硬件操作
按照這個運行圖,可以看出,第一部分已經設計完畢,那么我們首先來實現這個部分。代碼如下:
首先是Venus啟動和初始化函數:
VOID? APIENTRY?MemoaryKernel::Fn_Service_Init(UDWORD?NewMemoarySize)
{
?MemoarySize = NewMemoarySize;
?InPageOffset = NULL;
?PageAddressIndex = NULL;
?NowLineAddress = NULL;
ErrorCode = NORMAL;
?
?_asm//這段匯編完成計算出NewMemoarySize對應的最大頁號地址
??{
???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
?}
}
//====================================================================//
//加載虛擬/線性地址,以備進行頁面地址變換操作:
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位得到頁內偏移地址
???mov?[EBX]this.InPageOffset,EAX
???shr?ECX,12 //右移動12位,得到頁號地址
???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
???
??}
}
//====================================================================//
雖然完成了狀態圖上的第一部分功能,但是Venus目前仍然不具備對內存進行按頁分配和回收的功能。那么如何來設計這2個功能,是十分重要的,因為分配和回收是Venus的基礎的基礎功能。要分配和回收頁面,就需要了解整個物理內存頁面的使用情況,最簡單的辦法是采用位映射圖(BitMap)的數據結構。BitMap,就是用一個bit位,來表示一個頁面的使用狀態,只有1和0兩種狀態,分別對應頁面的 “已分配”(USED) 和“空閑”(UNUSE)2種狀態。但是,由于用來記錄內存使用狀態的數據也是保存在內存中的,那么,BitMap的空間效率如何呢?我們來計算一下:
Venus最大支持32MB內存,此時最大會有8192個頁面,也就是說,需要8192個bit來記錄內存的使用狀態,即8192bit/8 = 1024Byte =1KB空間。應該說,BitMap的空間效率還是相當不錯的。那么這1KB的連續數據存放在物理內存的什么地方呢?作為操作系統的內核使用的數據,我將它設計為存放在物理內存的最低地址處,即 物理地址0x0-0x03fff。這樣的話,Venue中應該新增加一個數據成員以記錄BitMap的存放的起始物理地址。我們新增加一個數據成員 _SaveLinerAddress 來記錄它:
UDWORD??_SaveLinerAddress; //Map位圖存放的線性地址
現在我們來設計下BitMap的細節部分,由于這個模擬程序是在Intel 80386以上的機器上編寫的,因此為了實現bit操作時方便,我們將BitMap按32bit為一組進行劃分。每組從右向左計數。對BitMap的操作集有2個函數:設置函數和查詢函數,其具體實現代碼將在最后給出。
?
DWORD?APIENTRY?Fn_Service_SetBitMap(UDWORD? PageIndex,BOOL? Flag);
?????//設置位映射圖, 參數為分頁地址的頁號.
?DWORD?APIENTRY?Fn_Service_GetBitMap(UDWORD PageIndex);
?????//取得位映射圖數值, 參數為分頁地址的頁號
現在通過BitMap我們已經可以了解到物理內存分頁狀態下內存的使用狀態了,但是仍然不能按頁分配和回收內存。那么要如何設計分配和回收內存頁呢?我們可以組織一個空閑頁鏈表,每分配一個頁,就摘掉一個鏈表項,每回收一個頁,就往鏈表里加一個項。但是這樣有幾個缺點,一來鏈表不穩定,一旦出錯就會造成內存丟失或者重復分配進而造成進程間沖突,二來效率相對差些。最后我想到在UNIX中,磁盤塊的分配采用的是成組鏈接法,因為內存空閑頁在本質上也是一種塊,因此我們可以把這個算法適當的改造一下,用來分配和回收空閑頁。我們知道,成組鏈接分配算法采用一個堆棧來進行分配和回收操作。我們將空閑物理頁號按1024個為一組進行遍組,這樣最多會有8組(因為Venus最大支持32MB內存),并設計一個指針,在初始化時讓它指向第一組的開頭,當分配出去一個空閑頁面時,令指針指向組中的下一個空閑物理塊號,而當回收一個空閑物理頁時,則將其頁號記入上一個分配出去的頁號的位置。簡單說,就是當分配空閑物理頁時做出棧操作,當回收時做壓棧操作。而在每組的末尾,記錄著新一組的起始物理地址,當操作指針指向當前組的末尾時,就會跳到新一組的開始繼續進行分配。由于內存的分配和回收要求高效率的操作,再加上這是Venus使用的數據,因此對8個組的地址做如下規定:每組和每組之間保持連續,也就是說這8個組必須存放在連續的物理內存空間里。每組之間以4個字節相隔。這4個字節中記錄的是下一組的起始物理地址。為了能明確知道當前分配指針是否已經指向了當前組的末尾,在Venus中需要再增加一些數據成員來記錄分配的次數。由于Venus最大支持到32MB ,因此采用一個字的長度來記錄空閑物理頁號。由此得到8組占用的長度:1024×2Byte×8組=16KB=4頁。同樣做為Venus的數據,我將起存儲位置設置為內存低地址區,緊挨BitMap之后,即:0x0000400- 0x000441F。新增加的數據成員如下:
??UDWORD??StackEsp;?//MallocStack操作指針.
??UDWORD??MallocCounter;?//分配次數計數器 用來記錄是否需要取下個可用頁面組或生成新可用頁面組??
??UDWORD??GroupIndex;???? //當前操作的組號
對應分配和回收操作,分別有2個函數提供支持,具體實現代碼在最后給出:
??
UDWORD?APIENTRY?Fn_Service_MallocOnePage();??
?????//分配一個頁面
??UDWORD?APIENTRY?Fn_Service_FreeOnePage(UDWORD PageIndex);?
?????//回收一個頁面,參數為待回收的頁面地址號
到目前,Venus具有了虛擬地址變換,按頁為單位對內存進行分配/回收操作,記錄/查詢內存使用狀態的功能。
接著,我們來實現第二個功能部分:利用指定的頁表進行地址變換,得到物理地址。那么如何利用頁表呢,這就要牽扯到頁表的數據結構了。那么我們先來設計好頁表。在分頁系統中,頁表的基本功能是將邏輯頁地址映射為物理頁地址。實現時,通常采用這樣的設計:在邏輯頁表中的每一個頁表項中存放的是物理頁號的地址。這樣通過讀取頁表項,可以得到對應邏輯頁在物理內存中的物理頁號,再和頁內偏移量相拼,就得到了要訪問的物理地址。如上文所寫到的,在分頁系統中,進程訪問內存使用的都是虛擬地址,也就是說,進程總是認為自己的存儲地址是從0x0開始的。進程進行內存訪問時,傳遞給Venus的是一個虛擬的地址,Venus將這個虛擬的地址做分頁變換,取得對應這個虛擬地址的分頁地址,分頁地址中包含了頁號和頁內偏移量,然后Venus再利用得到的頁號,去這個進程的頁表中對應的頁表項里取得物理頁號的地址,最后將取得的頁號地址再和頁內偏移量相拼,就得到了物理地址。這樣就完成了一次由虛擬地址到物理地址的映射?;氐絼偛诺脑O計上,頁表項必須有至少以下2個數據成員來完成地址的映射:
?UDWORD?PageIndex;?? //頁索引號用于共系統查找(目前未用)
?UDWORD?PageBlock;?? //物理頁號 保存該頁表項映射的真實物理頁號地址
而實際上,為了支持虛擬存儲技術和共享保護等諸多功能,頁表項還需要其他的數據結構支持,比如,為了供換頁進程參看,頁表項需要提供當前單位時間內自身是否被訪問,是否被修改,當前該頁是否在內存,單位時間內頁面被訪問的次數 等等的信息,因此綜合了一下,我將頁表項設計如下:
??UDWORD?PageIndex;?? //頁索引號用于共系統查找(目前未用)
??UDWORD?PageBlock;?? //物理頁號 保存該頁表項映射的真實物理頁地址
??UDWORD?AccessCounter; //訪問計數器,用來記錄該頁面被訪問的次數
??UDWORD?PageStatus;?? //頁面狀態標志,標志頁面是在內存中還是在外存中,共換頁進程參考
??BOOL?IsModify;?//頁面是否被修改 共換頁進程參考
??BOOL?IsAccess;?//頁是否被訪問,共換頁進程參考
??UDWORD?SwapAddress;??? //外存地址.頁面被存放于外存的地址
這些數據結構將為以后設計換頁進程提供有力的支持。Venus作為底層內核,必須能向高層部分提供對頁表項內容的查詢和修改操作,以及當新生成一個頁表項時,應該能按高層的要求,進行頁表項初始化操作,初始化主要用來給新頁表項分配一個空閑物理頁面供其映射。
?在頁表項的數據成員中,PageBlock和PageIndex只能在初始化時由初始化函數修改,一旦初始化成功完成,以后除非回收頁面,否則不能再修改。而其他數據成員,則可以由高層按需要進行修改?;谝陨显O定,頁表項應該具有的操作集有:
UDWORD?APIENTRY??Fn_Service_Init(UDWORD?Init_PageIndex); //頁表項對象初始化函數,參數為頁索引號.
//該函數將請求內核分配一個空閑物理頁面以用來初始化,并將該頁面地址記入PageBlock中
??
UDWORD?APIENTRY??Fn_Service_Free();//該函數將請求內核釋放其所映射的物理頁面,并將PageBlock的數值設置為NO_ALLOCATION
//被釋放的頁面將被放入內核管理的分配堆棧,共其他進程使用
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); //設置PageStatu的值
VOID?APIENTRY??Fn_Service_IncAccessCounter(); //AccessCounter自增1
VOID?APIENTRY??Fn_Service_SetIsModidy(BOOL?NewFlag); //設置IsModify的值
VOID?APIENTRY??Fn_Service_SetIsAccess(BOOL?NewFlag);? //設置IsAccess的值
VOID?APIENTRY??Fn_Service_SetSwapAddress(UDWORD?NewSwapAddress);
//設置SwapAddress的值
當頁表項設計好后,就可以實現Venus的第二部分功能,利用頁表進行地址變換,映射出要訪問的真實物理地址。對內存的訪問,無非是讀或者寫,因此Venus需要提供一個內存訪問接口。EmuHAL中提供了對物理內存進行按字節,字,雙字讀取/寫入的接口,因此Venus中也將提供按字節,字,雙字讀取/寫入的接口。到這里有一個問題,就是什么時候進行利用頁表和分頁地址進行物理地址的映射。可以有2個方案,第一,加載虛擬地址后立刻進行分頁地址到物理地址的映射,這時候當然需要頁表的支持。第二,加載虛擬地址后并不立刻進行分頁地址到物理的映射,而是等到需要執行讀/寫操作時,才利用指定的頁表進行地址映射,隨后進行訪問操作。我在這里選擇了第二個方案。因為我覺得加載虛擬地址后并不一定馬上要進行內存操作,但是向Venus請求了讀寫操作后則必須立刻執行讀/寫,因此我在這里提供給高層2個地址方面的接口,一個只先加載地址并進行虛擬地址到分頁地址的變換,另一個接口就是由上文的6個讀寫函數中的參數提供的,使用這6個函數時,Venus會一次性完成加載虛擬地址變換為分頁地址和利用分頁地址及頁表完成分頁地址到物理地址的轉換,并將讀寫操作傳遞給EmuHAL層去執行。Venus提供的讀寫函數接口如下:
BYTE?APIENTRY?Fn_Service_ReadByte(Lv1_MemoaryTable*?lpPageTableAddress,
?????????? UDWORD NewVirtualAddress);
?????//按字節方式(8bit)讀取
VOID?APIENTRY?Fn_Service_WriteByte(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress,DWORD Value);
?????//按字節方式(8bit)寫入
??
WORD?APIENTRY?Fn_Service_ReadWord(Lv1_MemoaryTable*?lpPageTableAddress,
?????????? UDWORD NewVirtualAddress);
?????//按字方式(16bit)讀取
??
VOID?APIENTRY?Fn_Service_WriteWord(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress,DWORD Value);
?????//按字方式(16bit)寫入
DWORD?APIENTRY?Fn_Service_ReadDword(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress);
?????//按雙字方式(32bit)讀取
??
VOID?APIENTRY?Fn_Service_WriteDword(Lv1_MemoaryTable*?lpPageTableAddress,
???????????? UDWORD NewVirtualAddress,DWORD Value);
?????//按雙字方式(32bit)寫入
?
到這里,第二和第三部分功能就相繼實現了,作為底層來說,現在基本的功能已經實現了,但是還有很多的不足,比如,內核的健壯性問題。上面的各個功能設計都沒有考慮到操作數據錯誤帶來的影響,并且對Venus使用的內存部分完全沒有進行保護,任何進程都可以輕松訪問到系統使用的內存,這是相當危險的。
上面說了這么多,我把具體實現的代碼貼在下面,這些代碼實現上面說的Venus 的各個基本功能,并且最了相對比較好的安全性檢測,并且基本保證了在EmuHAL下系統用內存空間不可訪問。
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? //內存分頁管理內核接口類
{
?public:
??virtual?VOID??APIENTRY?Fn_Service_Init(UDWORD?NewMemoarySize)=0;
??//內核啟動,初始化函數,必須在EmuHAL被初始化后調用,否則會因為沒有EmuHAL層支持而出錯.
??//同時不調用本函數則內核本身也不會初始化,進而導致Halt.
?public: //存儲器管理內核狀態查詢操作服務集
??virtual UDWORD?APIENTRY?Fn_Service_GetErrorCode()=0; //取得內核操作錯誤狀態代碼
??virtual VOID?APIENTRY?Fn_Service_GetMemoaryStatu()=0;//當前內存使用情況查看接口
?
?public: //單位頁面分配/回收服務集
??virtual UDWORD?APIENTRY?Fn_Service_MallocOnePage()=0;??
?????//分配一個頁面,返回值為分配的頁面地址
??virtual UDWORD?APIENTRY?Fn_Service_FreeOnePage(UDWORD PageIndex)=0;?
?????//回收一個頁面,參數為待回收的頁號地址.注意,該函數不會回收任何由系統常駐的頁面或者非法頁面
??
?public: //讀寫服務集? 第一個參數為Lv1頁表對象指針? 第二個參數為虛擬地址 第3個參數為待寫入的數據
??virtual BYTE?APIENTRY?Fn_Service_ReadByte(Lv1_MemoaryTable*?lpPageTableAddress,
?????????? UDWORD NewVirtualAddress)=0;
?????//按字節方式(8bit)讀取
??
??virtual VOID?APIENTRY?Fn_Service_WriteByte(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress,DWORD Value)=0;
?????//按字節方式(8bit)寫入
??
??
??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)寫入
??
??
??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)寫入
??
};
class?MemoaryKernel:public CMemoaryKernel
{
?private:
??BOOL??IsPage;???? //是否分頁管理 正常初始化時為1,即使用分頁管理
??UDWORD??_SaveLinerAddress; //Map位圖存放的線性地址
??UDWORD??PageAddressIndex;? //分頁地址中的頁號地址?
??UDWORD??InPageOffset;??? //分頁地址中的頁內偏移地址
??UDWORD??NowLineAddress;??? //當前等待變換或者使用的虛擬地址
??UDWORD??StackEsp;?//MallocStack操作指針.
??UDWORD??MallocCounter;?//分配次數計數器 用來記錄是否需要取下個可用頁面組或生成新可用頁面組??
??UDWORD??ErrorCode;????? //錯誤代碼變量
??UDWORD??GroupIndex;???? //當前操作的組號
??UDWORD??MemoarySize;??? //當前總共內存容量
??UDWORD??MaxPageIndex;?//最大頁面號,有初始化時的總計內存容量決定.
?public:
??MemoaryKernel();
??~MemoaryKernel();
?
?private://內部服務
??VOID?APIENTRY?Fn_TranslateLineAddress();? //虛擬地址分頁變換機構
??VOID?APIENTRY?Fn_Service_Init_MallocStack(); //Malloc堆棧初始化函數
??VOID?APIENTRY?Fn_Service_LoadVirtualAddress(UDWORD VirtualAddress);
?????//加載待讀取或者寫入的內存地址.如果使用分頁模式,則內核會將線性地址做拆分,
?????//在PageAddressIndex中放入頁號地址,在InPageOffset中放入頁內偏移量地址??
??
?public: //內存使用狀況查詢/設置/內核初始化服務集
??virtual?VOID??APIENTRY?Fn_Service_Init(UDWORD?NewMemoarySize);
?????//內核初始化函數,負責啟動內核,設置位映射圖和Malloc堆棧??
??DWORD?APIENTRY?Fn_Service_SetBitMap(UDWORD PageIndex,BOOL Flag);
?????//設置位映射圖, 參數為分頁地址的頁號地址.
??DWORD?APIENTRY?Fn_Service_GetBitMap(UDWORD PageIndex);
?????//取得位映射圖數值, 參數為分頁地址的頁號地址.
?public: //單位頁面分配/回收服務集
??virtual?UDWORD?APIENTRY?Fn_Service_MallocOnePage();??
?????//分配一個頁面
??virtual UDWORD?APIENTRY?Fn_Service_FreeOnePage(UDWORD PageIndex);?
?????//回收一個頁面
?public: //存儲器管理內核狀態查詢操作服務集
??virtual UDWORD?APIENTRY?Fn_Service_GetErrorCode(); //取得內核操作錯誤狀態代碼
??virtual VOID?APIENTRY?Fn_Service_GetMemoaryStatu();//當前內存使用情況查看接口
??
?public: //讀寫服務集? 第一個參數為Lv1頁表對象指針? 第二個參數為虛擬地址 第3個參數為待寫入的數據
??virtual BYTE?APIENTRY?Fn_Service_ReadByte(Lv1_MemoaryTable*?lpPageTableAddress,
?????????? UDWORD NewVirtualAddress);
?????//按字節方式(8bit)讀取
??
??virtual VOID?APIENTRY?Fn_Service_WriteByte(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress,DWORD Value);
?????//按字節方式(8bit)寫入
??
??
??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)寫入
??
??
??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)寫入
??
};
#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;?? //頁索引號用于共系統查找(目前未用)
??UDWORD?PageBlock;?? //物理頁號 保存該頁表項映射的真實物理頁地址
??UDWORD?AccessCounter; //訪問計數器,用來記錄該頁面被訪問的次數
??UDWORD?PageStatus;?? //頁面狀態標志,標志頁面是在內存中還是在外存中,共換頁進程參考
??BOOL?IsModify;?//頁面是否被修改 共換頁進程參考
??BOOL?IsAccess;?//頁是否被訪問,共換頁進程參考
??UDWORD?SwapAddress;??? //外存地址.頁面被存放于外存的地址
?public:
??Lv1_MemoaryTable();
??~Lv1_MemoaryTable();
?
?public: //頁表項初始化服務集
??UDWORD?APIENTRY??Fn_Service_Init(UDWORD?Init_PageIndex); //頁表項對象初始化函數,參數為頁索引號.
???????//該函數將請求內核分配一個空閑物理頁面以用來初始化,并將該頁面地址記入PageBlock中
??
??UDWORD?APIENTRY??Fn_Service_Free();//該函數將請求內核釋放其所映射的物理頁面,并將PageBlock的數值設置為NO_ALLOCATION
????????? //被釋放的頁面將被放入內核管理的分配堆棧,共其他進程使用
?
?public: //頁表項狀態讀/寫服務集
??//讀
??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); //設置PageStatu的值
??VOID?APIENTRY??Fn_Service_IncAccessCounter(); //AccessCounter自增1
??VOID?APIENTRY??Fn_Service_SetIsModidy(BOOL?NewFlag); //設置IsModify的值
??VOID?APIENTRY??Fn_Service_SetIsAccess(BOOL?NewFlag);? //設置IsAccess的值
??VOID?APIENTRY??Fn_Service_SetSwapAddress(UDWORD?NewSwapAddress); //設置SwapAddress的值
};
#endif //#ifndef?_MEMOARY_CLASS_LV1PT_DEFINE
//====================================================================//
Memoary_Define.h
//====================================================================//
#ifndef _MEMOARY_DEFINE_H
#define _MEMOARY_DEFINE_H
#define??MAX_MEMOARY???0x02000000?? //支持管理的最大內存 32MB
#define??MIN_RUN_MEMOARY???0x00006000?? //內核運行需要的最小內存,以Byte計算
#define??MAX_PAGE_NUMBER???0x00001FFF?//32MB內存按4KB分頁的最大頁號 0-8191 共8192個
#define??PAGE_SIZE???4096?//頁尺寸4KB為4096Byte
#define??MAX_MEMOARY_STACK??1024??? //負責內存分配回收的堆棧的長度
#define??NO_ALLOCATION???0x0FFFF
#define??_I386??//類型關鍵字定義 定義為Intel 80386 及以后處理器專用
#define??_STDAPI???????? //允許函數調用使用Win32 APIENTRY(__stdcall)方式
#define??_IOSTREAM?//使用iostream.h作為I/O操作庫
#include <Base.h>
#include <EmuHAL.h>
#pragma comment(lib,"EmuHAL.lib")
#define??SWAPPER????0x00000000
#define??MEMOARY????0x00000001
#define??UNINIT????0x00000002
//以下地址基于ExHal層中的內存,可被視為物理內存
#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
//錯誤代碼定義:
#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"
//接口對象
MemoaryKernel?m_Venus;??? //存儲器管理核心對象
LPCMEMOAEYKERNEL?APIENTRY?Fn_iKernel_GetMemoaryManager();
#endif
//===================================================================//
MemoaryPageLib.h
//===================================================================//
#ifndef?_MEMPAGELIB_H
#define?_MEMPAGELIB_H
#define??MAX_MEMOARY???0x00800000?? //支持管理的最大內存 32MB
#define??MAX_PAGE_NUMBER???0x00001FFF?//32MB內存按4KB分頁的最大頁號 0-8191 共8192個
#define??PAGE_SIZE???4096?//頁尺寸4KB為4096Byte
#define??MAX_MEMOARY_STACK??1024??? //負責內存分配回收的堆棧的長度
#define??_I386??//類型關鍵字定義 定義為Intel 80386 及以后處理器專用
#define??_STDAPI???????? //允許函數調用使用Win32 APIENTRY(__stdcall)方式
#define??_IOSTREAM?//使用iostream.h作為I/O操作庫
#include <Base.h>
#include <EmuHAL.h>
#pragma comment(lib,"EmuHAL.lib")
#define??SWAPPER????0x00000000
#define??MEMOARY????0x00000001
#define??UNINIT????0x00000002
//以下地址基于ExHal層中的內存,可被視為物理內存
#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
//頁表映射的空閑物理頁面的狀態標志
#define??SWAPPER????0x00000000?? //位于交換設備上
#define??MEMOARY????0x00000001? //在內存中
#define??UNINIT????0x00000002? //尚未初始化的新頁表項
//錯誤代碼定義:
#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;?? //頁索引號用于共系統查找(目前未用)
??UDWORD?PageBlock;?? //物理頁號 保存該頁表項映射的真實物理頁地址
??UDWORD?AccessCounter; //訪問計數器,用來記錄該頁面被訪問的次數
??UDWORD?PageStatus;?? //頁面狀態標志,標志頁面是在內存中還是在外存中,共換頁進程參考
??BOOL?IsModify;?//頁面是否被修改 共換頁進程參考
??BOOL?IsAccess;?//頁是否被訪問,共換頁進程參考
??UDWORD?SwapAddress;??? //外存地址.頁面被存放于外存的地址
?public:
??Lv1_MemoaryTable();
??~Lv1_MemoaryTable();
?
?public: //頁表項初始化服務集
??UDWORD?APIENTRY??Fn_Service_Init(UDWORD?Init_PageIndex); //頁表項對象初始化函數,參數為頁索引號.
???????//該函數將請求內核分配一個空閑物理頁面以用來初始化,并將該頁面地址記入PageBlock中
??
??UDWORD?APIENTRY??Fn_Service_Free();//該函數將請求內核釋放其所映射的物理頁面,并將PageBlock的數值設置為NO_ALLOCATION
????????? //被釋放的頁面將被放入內核管理的分配堆棧,共其他進程使用
?
?public: //頁表項狀態讀/寫服務集
??//讀
??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); //設置PageStatu的值
??VOID?APIENTRY??Fn_Service_IncAccessCounter(); //AccessCounter自增1
??VOID?APIENTRY??Fn_Service_SetIsModidy(BOOL?NewFlag); //設置IsModify的值
??VOID?APIENTRY??Fn_Service_SetIsAccess(BOOL?NewFlag);? //設置IsAccess的值
??VOID?APIENTRY??Fn_Service_SetSwapAddress(UDWORD?NewSwapAddress); //設置SwapAddress的值
};
class?CMemoaryKernel
{
?public:
??virtual?VOID??APIENTRY?Fn_Service_Init(UDWORD?NewMemoarySize)=0;
??//內核啟動,初始化函數,必須在EmuHAL被初始化后調用,否則會出錯
?public: //存儲器管理內核狀態查詢操作服務集
??virtual UDWORD?APIENTRY?Fn_Service_GetErrorCode()=0; //取得內核操作錯誤狀態代碼
??virtual VOID?APIENTRY?Fn_Service_GetMemoaryStatu()=0;//當前內存使用情況查看接口
?
?public: //單位頁面分配/回收服務集
??virtual UDWORD?APIENTRY?Fn_Service_MallocOnePage()=0;??
?????//分配一個頁面
??virtual UDWORD?APIENTRY?Fn_Service_FreeOnePage(UDWORD PageIndex)=0;?
?????//回收一個頁面
??
?public: //讀寫服務集? 第一個參數為Lv1頁表對象指針? 第二個參數為虛擬地址 第3個參數為待寫入的數據
??virtual BYTE?APIENTRY?Fn_Service_ReadByte(Lv1_MemoaryTable*?lpPageTableAddress,
?????????? UDWORD NewVirtualAddress)=0;
?????//按字節方式(8bit)讀取
??
??virtual VOID?APIENTRY?Fn_Service_WriteByte(Lv1_MemoaryTable*?lpPageTableAddress,
??????????? UDWORD NewVirtualAddress,DWORD Value)=0;
?????//按字節方式(8bit)寫入
??
??
??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)寫入
??
??
??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)寫入
??
};
#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;
}
//頁表項對象初始化函數,參數為頁索引號.
//該函數將請求內核分配一個空閑物理頁面以用來初始化,并將該頁面地址記入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;
??}
}
//該函數將請求內核釋放其所映射的物理頁面,并將PageBlock的數值設置為NO_ALLOCATION
//被釋放的頁面將被放入內核管理的分配堆棧,共其他進程使用
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"
//接口函數
LPCMEMOAEYKERNEL?APIENTRY?Fn_iKernel_GetMemoaryManager()
{
?return?(LPCMEMOAEYKERNEL)(&m_Venus);
}
//====================================================================//
MemoaryKernel.cpp
//====================================================================//
#include "../Include/Memoary_Class_Define.h"
MemoaryKernel::MemoaryKernel()
{;}
MemoaryKernel::~MemoaryKernel()
{;}
//內核初始化函數 參數為物理內存容量
VOID? APIENTRY?MemoaryKernel::Fn_Service_Init(UDWORD?NewMemoarySize)
{
?_asm?//物理內存容量是否夠內核啟動運行
??{
???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;}
?//如果物理內存容量超過了能管理的最大容量,則按能支持的最大容量處理,更大的地址看不見……=.=
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//這段匯編完成計算出NewMemoarySize對應的最大頁號地址
??{
???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++) //為系統使用的內存做保留操作 :)
??{??????????????????? //這些地址將被用來保存 內存分頁使用狀態映射圖和用于內存分配的Malloc堆棧
???Fn_Service_SetBitMap(SystemUsed,USED);
??}
?StackEsp = MEMOARY_STACK_BEGIN_STORE_LINE_ADDRESS;//Malloc堆棧指針指向棧頂
?Fn_Service_Init_MallocStack(); //Malloc堆棧初始化
?IsPage = TRUE; //設置系統使用分頁模式管理內存 至此內核初始化完畢.
}
//內存描述Map的設置函數.
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]? //比較頁號是否合法,32MB內存按4KB分頁支持的最大頁號為0-8192
???cmp?EAX,MAX_PAGE_NUMBER
???ja?EXIT
???mov?CL,0x020? //映射常數因子 由于x86寄存器是32bit長,所以取為32方便對齊運算
???div?CL?? //取得頁號對應的位映射在Map中的段偏移量,段長以4Byte為單位。
???mov?BX,AX?? //取得頁號對應的位映射在段內的偏移量,并保存在BX中
???and?EAX,0x000000FF
???mov?CL,0x04?? //段長常數因子,取4表示4Byte,因為4Byte = 32bit.
???mul?CL?? //取得自Map圖開始到對應段的具體地址,以Byte為單位.
???mov?[Shift],BH?//將段內偏移量放Shift
???
???and?EAX,0x0000FFFF? //EAX高16位清空
???mov?[OffsetAddress],EAX //保存段偏移地址
???
??}
?//讀取Map中對應的段
?Content = Fn_ReadDword(_SaveLinerAddress+OffsetAddress);
???
?_asm
??{
???mov?EAX,[Content]?//取得map圖中的對應段入EAX
???xor?EDX,EDX
???mov?DL,[Flag]?
???cmp?DL,0???
???mov?EDX,0x01
???mov?CL,[Shift]
???je?SetUnuse
??//SetUse:?????//設置對應位為1的操作
???shl?EDX,CL???//移動shift位
???or?EAX,EDX???//設置對應位
???mov?[Content],EAX?
???jmp?Exit
??SetUnuse:?????//設置對應位為0的操作??
???shl?EDX,CL
???not?EDX
???and?EAX,EDX
???mov?[Content],EAX
??EXit:??????//恢復寄存器,退出。
???pop?EBX
???pop?EDX
???pop?ECX
???
??}
?Fn_WriteDword(_SaveLinerAddress+OffsetAddress,Content);//將對應位寫回Map
?return?SUCCESS;
}
//讀取內存使用狀態Map圖的函數
DWORD?APIENTRY?MemoaryKernel::Fn_Service_GetBitMap(UDWORD PageIndex)
{
?UDWORD?OffsetAddress;
?DWORD?Content=GENERAL_PROTECT_ERROR_PAGE_INDEX_OVERFLOW;? //如果出錯,
????????//則這里放的就是出錯代碼
?BYTE?Shift;
?if (PageIndex > MaxPageIndex) {return?FAILURE;}
?_asm
??{
??????? //保存寄存器
???push?ECX
???push?EDX
???push?EBX
???
???mov?EAX,[PageIndex]? //比較頁號是否合法,32MB內存按4KB分頁支持的最大頁號為0-8192
???cmp?EAX,MAX_PAGE_NUMBER
???ja?EXIT
???mov?CL,0x020? //映射常數因子 由于x86寄存器是32bit長,所以取為32方便對齊運算
???div?CL?? //取得頁號對應的位映射在Map中的段偏移量,段長以4Byte為單位。
???mov?BX,AX?? //取得頁號對應的位映射在段內的偏移量,并保存在BX中
???and?EAX,0x000000FF
???mov?CL,0x04?? //段長常數因子,取4表示4Byte,因為4Byte = 32bit.
???mul?CL?? //取得自Map圖開始到對應段的具體地址,以Byte為單位.
???mov?[Shift],BH?//將段內偏移量放Shift
???
???and?EAX,0x0000FFFF? //EAX高16位清空
???mov?[OffsetAddress],EAX? //將總線性偏移量放對應變量
???
??}
?
?Content = Fn_ReadDword(_SaveLinerAddress+OffsetAddress);
???
?_asm
??{
???mov?EAX,[Content]?//取得map圖中的對應段入EAX
???mov?CL,[Shift]
???shr?EAX,CL??//將EAX中對應的位移動到最低位
???and?EAX,0x00000001? //其他位清0
???mov?[Content],EAX? //保存在Content中
??EXit:??????//恢復寄存器,退出。
???pop?EBX
???pop?EDX
???pop?ECX
???
??}
?
?return?Content;
}
//加載虛擬/線性地址到分頁變換機構,以備進行頁面地址變換操作
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位得到頁內偏移地址
???mov?[EBX]this.InPageOffset,EAX
???shr?ECX,12 //右移動12位,得到頁號地址
???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; //設置分配堆棧的開始存儲地址
?DWORD?IsUsed;
?for(;PageAddressCounter<=MaxPageIndex;PageAddressCounter++)? //這個for循環構造一個組長為1024,
??{??????//共N組的成組鏈表用于分配和回收內存頁
???IsUsed = Fn_Service_GetBitMap(PageAddressCounter);
???if(IsUsed == FALSE? && LoopCounter != 0x0400) //0x0400是1024 LoopCounter負責記錄是否分配了1024個,是的話則設置新組
????{
?????Fn_WriteWord(OpAddress,PageAddressCounter); //ExHAL函數,以字方式寫寫模擬物理內存
?????LoopCounter++;
?????OpAddress=OpAddress+2; //每個堆棧項占2個字節,因此這里+2
????}
???else
????{
?????if(LoopCounter == 0x0400) //等于1024 表示一個組已經分配完了,該設置新組了
??????{
???????Fn_WriteDword(OpAddress,OpAddress+4);?//ExHAL函數,以雙字(32bit)方式寫模擬物理內存?
????????????//系統中存放的組是連續的,因此新組的開始地址就是當前組完畢后的地址
???????PageAddressCounter--; //頁面地址減1,否則會在所有loopCounter=0x0400時丟失1Byte內存... T_T
???????LoopCounter=0;
???????OpAddress=OpAddress+4;//因為堆棧的最后一項是指向新組的開始地址,因此是雙字32bit 所以+4
??????}??
????}
??}
?Fn_WriteDword(OpAddress,MALLOC_STACK_END_FLAG);? //for循環完畢,寫入堆棧結束標志
}
UDWORD?APIENTRY?MemoaryKernel::Fn_Service_MallocOnePage()
{
?UDWORD?Resault_Address;
?Resault_Address = (UDWORD)Fn_ReadWord(StackEsp);
?if ( Resault_Address == MALLOC_STACK_END_FLAG) //如果堆棧指針已經指向了堆棧結尾標志,說明沒有可用物理內存頁共分配了
??{
???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++; //分配次數計數器 每分配一次加1,1024次則讀入一個新堆棧
??}
?else
??{?//以下代碼重新取得新一組空閑頁面組的地址
???StackEsp = Fn_ReadDword(StackEsp); //將新組的開始地址讀入堆棧操作指針
???
???if (StackEsp == MALLOC_STACK_END_FLAG) ////如果堆棧指針已經指向了堆棧結尾標志,
????{????//說明沒有可用物理內存頁共分配了
?????ErrorCode=MEMOARY_ALLOCATE_ERROR_NO_ENOUGH_MEMOARY;
?????return MEMOARY_ALLOCATE_ERROR_NO_ENOUGH_MEMOARY;??
????}
???
???Resault_Address?= (UDWORD)(Fn_ReadWord(StackEsp)); //讀出新的空閑物理頁面號
???Fn_Service_SetBitMap(Resault_Address,USED); //設置該頁的分配狀態位
???StackEsp = StackEsp+2; //已經分配了一個頁面 因此地址+2
???MallocCounter = 1; //已經分配了一個頁面,因此為1而不是0
???GroupIndex++; //讀取了新組,因此+1
??}
?return?Resault_Address;
}
UDWORD?APIENTRY?MemoaryKernel::Fn_Service_FreeOnePage(UDWORD PageIndex)? //回收一個頁面
{
?if (PageIndex <= SYSTEM_USE_END_PAGE_ADDRESS) //檢測即將釋放的地址的合法性
??{
???ErrorCode = GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY;
???return?GENERAL_PROTECT_ERROR_ACCESS_SYSTEM_MEMOARY;
??}
?if (PageIndex > MaxPageIndex) //檢測地址是否overflow
??{
???ErrorCode = GENERAL_PROTECT_ERROR_PAGE_INDEX_OVERFLOW;
???return?GENERAL_PROTECT_ERROR_PAGE_INDEX_OVERFLOW;
??}
?if (StackEsp==MEMOARY_STACK_BEGIN_STORE_LINE_ADDRESS) //簡單的操作合法性檢測
??{
???ErrorCode = MEMOARY_FREE_ERROR_NO_MEMOARY_NEED_FREE;
???return MEMOARY_FREE_ERROR_NO_MEMOARY_NEED_FREE;
??}
?
?Fn_Service_GetBitMap(PageIndex); //進一步在內存使用狀態圖中查看該頁的當前狀態
?_asm
??{
???cmp?EAX,USED //如果該頁已經是空閑頁,則不再對Malloc堆棧進行操作
???jne?ErrorFree //以避免發生不同步的問題
??}
?if (MallocCounter != 0) //!=0說明當前的組還未用完
??{?//先移動指針,再讀出空閑物理頁面號
???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是因為已經分配了一個頁面 因此不是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++) //因為以下部分是循環為了加速用了asm 其實就是算個地址
???????{
????????_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? //檢測到最大地址已經顯示完畢則跳出顯示循環
??????????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);//加載虛擬地址到內核
?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 //標志位是MEMOAY則合法
???jne?AddressError
???cmp?EAX,SWAPPER
???je?INT_PageSwap
???mov?EAX,this
???mov?EAX,[EAX]this.MaxPageIndex
???cmp?[CurrentPageBlock],EAX //映射的地址沒有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中放的就是轉換后的線性地址
???
???push?EAX
???call?Fn_ReadByte //讀取一個字節
???mov?BYTE ptr[Resault],AL
???
???pop?ECX
??}
?lpPageTableAddress->Fn_Service_SetIsAccess(TRUE);? //頁是否被訪問屬性設置為真
?lpPageTableAddress->Fn_Service_IncAccessCounter();? //頁訪問計數器增加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?
??}
}
//實現思路同MemoaryKernel::Fn_Service_ReadByte函數
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);? //頁是否被訪問屬性設置為真
?lpPageTableAddress->Fn_Service_IncAccessCounter();? //頁訪問計數器增加1
?lpPageTableAddress->Fn_Service_SetIsModidy(TRUE);? //頁表對應的物理頁是否被修改標志為真
?_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?
??}
}
//實現思路同MemoaryKernel::Fn_Service_ReadByte函數
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);? //頁是否被訪問屬性設置為真
?lpPageTableAddress->Fn_Service_IncAccessCounter();? //頁訪問計數器增加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?
??}
}
//實現思路同MemoaryKernel::Fn_Service_ReadByte函數
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);? //頁是否被訪問屬性設置為真
?lpPageTableAddress->Fn_Service_IncAccessCounter();? //頁訪問計數器增加1
?lpPageTableAddress->Fn_Service_SetIsModidy(TRUE); //設置是否修改標志為真
?_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?
??}
}
//實現思路同MemoaryKernel::Fn_Service_ReadByte函數
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);? //頁是否被訪問屬性設置為真
?lpPageTableAddress->Fn_Service_IncAccessCounter();? //頁訪問計數器增加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?
??}
}
//實現思路同MemoaryKernel::Fn_Service_ReadByte函數
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);? //頁是否被訪問屬性設置為真
?lpPageTableAddress->Fn_Service_IncAccessCounter();? //頁訪問計數器增加1
?lpPageTableAddress->Fn_Service_SetIsModidy(TRUE);? //設置是否修改標志為真
?_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?
??}
}
上面的代碼如果編譯不正常,歡迎大家連續我。 :)
?