해당 과정부터는 설명을 적지 않을 예정이다.
적을 시간에 한 글자라도 더 보는 것이 좋을 것 같아서, 간단히 기록만 해둔다.
페이지 테이블은 각 엔트리의 집합이므로, 페이지 엔트리를 나타내는 자료구조를 먼저 정의한다.
아래는 8바이트 크기의 페이지 엔트리 자료구조를 정의한 것이다.
typedef struct pageTableEntryStruct{
DWORD dwAttributeAndLowerBaseAddress;
DWORD dwUpperBaseAddressAndEXB;
} PWL4TENTRY, PDPTENTRY, PDENTRY, PTENTRY;
페이지 엔트리 속성 필드를 매크로로 정의한 것이다.
// 하위 32비트용 속성 필드
#define PAGE_FLAGS_P 0x00000001 //Present
#define PAGE_FLAGS_RW 0X00000002 //Read/Write
#define PAGE_FLAGS_US 0X00000004 //User/Supervisor (플래그 설정시, 유저 레벨)
#define PAGE_FLAGS_PWT 0X00000008 //Page Level Write-through
#define PAGE_FLAGS_PCD 0x00000010 //Page Level Cache Disable
#define PAGE_FLAGS_A 0x00000020 //Accessed
#define PAGE_FLAGS_D 0x00000040 //Dirty
#define PAGE_FLAGS_PS 0x00000080 //Page Size
#define PAGE_FLAGS_G 0x00000100 //Global
#define PAGE_FLAGS_PAT 0x00001000 //Page Attribute Table Index
// 상위 32비트용 속성 필드
#define PAGE_FLAGS_EXB 0x80000000 //Execute Disable 비트
// 기타
#define PAGE_FLAGS_DEFAULT ( PAGE_FLAGS_P | PAGE_FLAGS_RW )
자료구조와 매크로를 사용하여, 페이지 엔트리와 페이지 테이블을 생성한다.
PML4 테이블 생성 코드
// 페이지 엔트리에 데이터를 설정하는 함수
void kSetPageEntryData( PTENTRY* pstEntry, DWORD dwUpperBaseAddress, DWORD dwLowerFlags, DWORD dwUpperFlags){
pstEntry -> dwAttributeAndLowerBaseAddress = dwLowerBaseAddress | dwLowerFlags;
pstEntry -> dwUpperBaseAddressAndEXB = (dwUpperBaseAddress & 0xFF ) | dwUpperFlags;
}
// 페이지 테이블을 생성하는 함수
void kInitializePageTables ( void ){
PML4TENTRY* pstPML4TEntry;
int i;
pstPML4Entry = (PWL4ENTRY*) 0X100000;
kSetPageEntryData( &( pstPML4TEntry [ 0 ] ), 0x00, 0x101000, PAGE_FLAGS_DEFAULT, 0);
for (i = 1; i <512; i++){
kSetPageEntryData ( &(pstPMLTEntry[i]), 0, 0, 0, 0);
}
}
64GB까지 매핑하는 페이지 디렉터리를 생성하는 코드
pstPDEntry = (PDENTRY*) 0x102000;
dwMappingAddress = 0;
for(i = 0; i<512 * 64; i++){ //64GB 영역을 매핑하는데 필요한 페이지 디렉터리의 개수
kSetPageEntryData ( &( psPDEntry[i]), (i * (0x200000 >> 20))>> 12, dwMappingAddress, PAGE_FLAGS_DEFAULT | PAGE_FLAGS_PS, 0);
dwMappingAddress += PAGE_DEFAULTSIZE;
}
페이징 기능을 활성화하는 방법은 CR0 레지스터의 PG 비트와 CR3 레지스터, CR4 레지스터의 PAE 비트만 1로 설정하면 페이징 기능을 사용할 수 있다.
IA-32e 모드에서 동작하며, 2MB 크기를 가지는 페이징을 활성화하는 것이 목적이다.
프로세서의 페이징 기능을 활성화하는 코드
; PAE 비트를 1로 설정
mov eax, cr4 ;CR4 컨트롤 레지스터의 값을 EAX 레지스터에 저장
or eax, 0x20 ;PAE 비트(비트5)를 1로 설정
mov cr4, eax ;설정된 값을 다시 CR4 컨트롤 레지스터에 저장
; PML4 테이블의 어드레스와 캐시 활성화
mov eax, 0x100000 ;EAX 레지스터에 PML4 테이블이 존재하는 0x100000(1MB)를 저장
mov cr3, eax ;CR3 컨트롤 레지스터에 0x100000(1MB)을 저장
;프로세서의 페이징 기능 활성화
mov eax, cr0 ;EAX 레지스터에 CR0 컨트롤 레지스터를 저장
or eax, 0x80000000 ;PG 비트(비트31)를 1로 설정
mov cr0, eax ;설정된 값을 다시 CR0 컨트롤 레지스터에 저장