너무 오랜만이당 ㅠㅠ 너무 나태한 나 ㅡ,.ㅠ
작년 11월에 커널 플랫 페이징이 되었는데, 어제 오늘 불현듯 _-minios 다시 시작해서
커널 플랫 페이징 상태에서 새로운 페이지 추가 할 수 있도록 하였음..
아직 프로세스 별 페이지 디렉터리를 준비하진 않아서 프로세스별 4G 영역을
주진 못하는 상태
2005년 11월 3일 - 드뎌 페이징 된다.
-----------------------------------------------------------------------
이사가고 여행 다녀오느라고 정신이 없었다.
이제 양재다. 나도 서울 특별시민이다 음화하하하
그건 그렇고 일단 페이징이라도 되는 버전을 만들기 위해서 뚝딱 뚝딱했는데, 된다.
기쁘다.
페이징을 활성화하기 위해서 PDBR(Page Directory Base Register)로 쓰이는 특수레지스터
CR3에 페이지 디렉토리 시작 주소를 던져주고, CR0레지스터의 최상위 비트를 1로 하면
페이지가 시작된다.
첫번째 페이지 디렉토리를 페이지 존재하다는 PRESENT로 준 후, 이 페이지 디렉토리가
가리키는 페이지 테이블(1024개의 페이지 시작 주소가 들어있음)에 커널 전체 영역을
무식하게 4K씩 짤라서 페이징시켰다.
vmm_setup_kernel_page()는 페이징 시작하면 바로 eip가 가리키는 주소가 가상주소로
여겨져 페이징 메커니즘을 통해서 실제 물리주소로 변환되어야 하므로, 커널이 실행되는
영역을 페이지로 매핑하는 함수이다.
void vmm_setup_kernel_page()
{
int kernel_pdes;
int i, n;
unsigned int* pte, *pde;
unsigned int addr;
pde = g_page_directory;
addr = 0;
n = 0;
// 커널 영역(0x00000000 ~ KERNEL_END) 전체를 페이지로 매핑해둔다.
//kernel_pdes = (KERNEL_END/PAGE_SIZE+1;
// 일단 heap으로 쓰는 영역까지 모두 페이징 매핑 시켜두자 -_-; 무식하다.
kernel_pdes = (0x00110000+0x000fffff)/(PAGE_SIZE*1024)+1;
crt_printf("kernels page directory entries : %d
", kernel_pdes);
// 테스트로 일단 page directory 0번을 커널용 페이지 디렉토리로 사용해보자.
pte = (unsigned int*)VMM_START_PAGE_TABLE;
while( kernel_pdes-- > 0 )
{
for( i = 0 ; i < 1024; i ++)
{
pte[i] = addr | PF_PRESENT | PF_KERNEL | PF_READWRITE;
addr += PAGE_SIZE;
}
pde[n++] = (unsigned int)pte | PF_PRESENT | PF_KERNEL | PF_READWRITE;
}
}
// load BRDR(cr3)
__asm
{
mov eax, g_page_directory
mov cr3, eax
}
// PG(page) enable paging
__asm
{
mov eax, cr0
or eax, 0x80000000
mov cr0, eax
}
이러니까 된다. 일단 오늘은 이걸로 땡..
차후 해야할일은, 제대로 Paging하는 것인데, heap영역은 페이징 매핑 하지 말고 있다가
malloc() 요청이 오면 그때 페이지를 마련해서 리턴해주는 방식으로 바뀌어야 한다.
이러면 기존 flat memory model방식의 메모리 관리가 아니라 다르게 이쁘게 바꿔야 할듯하다.
또한 #PF(Page Fault) 인터럽트가 오면 이를 처리해주는 루틴도 고려해봐야 한다.
일단 그런일은 없다는 것으로 -_-;;
[KB9] Paging
2006년 4월 20일 - 커널 페이징 마련
------------------------------------------------------------------
그동안 쭉 놀다가, 어제 밤에 스타하다 이러면 안되겠다 싶어 -_-;
잠깐 vmm.c 소스를 보면서 내 OS의 메모리 맵을 다시 정리했다.
생각해 보니 지금 내가 페이징 vmm을 넣으려고 하는 것은 프로세스 마다
자신의 고유 영역 4G 주소를 갖을 수 있도록 하기 위해서 였다.
결국, 프로세스 마다 page_directory 주소를 갖고 있고, 필요에 따라서
물리적인 페이지를 할당 받아, page_directory 및 page_table을 갱신하고
프로세스 스위치가 일어날때 CR3 레지스터에 프로세스의 page_directory를
써주면 프로세스마다 자신의 4G 주소 영역을 갖을거 같다는 생각을 했다.
다음날 오재준 님의 OS 제작의 원리를 읽으니, process 구조체에 자신의
page_directory 주소를 갖고 있는것을 보고, TSS 구조체에도 CR3 필드에
page_directory 주소를 갖고 있는것을 보고 어느정도 내 추측이 맞았다는
생각을 했다.
현재는 프로세스마다 page_directory를 갖고 있지 않고, 단지 커널 전체에
하나의 page_directory가 있는 구조이다. 현재는 물리 페이지 할당 함수와
이 물리 페이지를 가상 주소로 map하는 함수를 구현하였는데 다행이 도는거
같다 ㅠㅠ. 이제 다음에는 프로세스 마다 page_directory를 갖고 프로세스
전환시 CR3값을 프로세스의 page_directory로 변경하는 것을 작성하면
진정한 멀티 프로세스 OS가 될듯 하다.
하나 알게 된 것은 새로운 물리 페이지를 할당해서 이를 page_directory와
page_table에 갱신하게 되면 cpu에게 TLB를 갱신하라는 명령을 내려야하는데
__asm
{
mov eax, cr3
mov cr3, eax
}
그냥 위처럼 해주면 TLB 전체를 갱신하게 된다.
이제 아래와 같은 테스트 코드를 작성해서
void task_vmm()
{
unsigned int* phys;
unsigned int* virt = (unsigned int*)0xFFFF0000;
phys = vmm_physic_alloc();
crt_printf("vmm_physic_alloc(): phys = 0x%08x
", phys );
vmm_map( virt, phys);
crt_printf("vmm_map(): 0x%08x => 0x%08x
", phys, virt );
*virt = 100;
crt_printf( "*virt = %d
", *virt );
}
돌려 보니 잘 돌아간다.. 오우.. 256 메가 램밖에 없는데, 0xFFFF0000번지를
접근했옹 ㅠㅠ
당연한 얘기지만, vmm_map( virt, phys); 라인을 주석 달면 page fault뜬다 ㅠㅠ
[KB9] Paging
--------------------------------------------------------------------
오전 12:23 2005-10-17
bro@shinbiro.com 조경민
paging on x86
===========================================================
전제
- paging은 IA-32에서 가능하다. (protected mode및 MMU를 지원하는 386이상)
- PSE(Page Size Extension)은 생략한다. pentium이상에서 가능
- PAE(Physical Address Extension)은 생략한다. pentium pro이상 가능
- 386이상에서 가능한 기본적인 페이징에 대해서 논한다.
- segmentation에 의한 linear address개념을 알고 있다 가정한다.
- page size는 4K byte로 가정한다.
Logical Address : Selector + Offset
Linear Address : Segment Descriptor base + Offset
virtual address : MMU Paging기능시 Linear Address는 virtual address라고 봄
MMU의 paging은 segmentation 과정을 통해 발생된 linear address를
physical address로 변환한다.
paging기능을 disable시키면 logical address가 바로 linear address가 된다.
한 페이지는 4KByte이며, 연속된 Physical address 영역이다.
CR3 레지스터에 Page Directory 시작 주소를 설정한다.
Page Directory안에 Directroy entry는 1024개가 존재한다.
각 Directory Entry는 Page Table의 시작 주소를 가리키도록 설정한다.
Page Table안에 Page Table Entry는 1024개이다.
각 Page Table Entry는 4K바이트의 Page Frame의 시작주소를 가리킨다.
Page Frame이 페이지 하나로 연속된 Physical 메모리이다.
virtual address에서 Directory index와 table index와 offset을 구분해와서
Page Directory 몇 번째가 가리키는 Page Table안에서 몇번째 Page Table
Entry가 가리키는 4K Page Frame안에서 Offset만큼이 이 linear address가
가리키는 실제 Physical address가 된다.
virtual address translation
---------------------------------
Virtual Address
31 22 21 12 11 0
+---------+------------+----------------+
|Directory| Table | Offset | 4-Kbyte Page
+---------+------------+----------------+ +----------------+
| | | | |
+--------+ | Page Table | +----------------+
| Page Directory | +----------------+ +-->|Physical Address|
| +---------------+ | | | +----------------+
| | | | +----------------+ | |
| +---------------+ +->|Page Table Entry|---->+----------------+
+->|Directory Entry|---->+----------------+
+---------------+
| |
+->+---------------+
|
| +---------------+
+--|CR3(PDBR) |
+---------------+
virtual(linear) address에서 Direcry부분으로 찾아간 Directory Entry의 present 비트가
0이면 Page Fault, Table부분으로 찾아간 Directory.Page Table Entry의 Present
비트가 0 이면 Page Fault이다.
#PF 인터럽트가 발생되면 OS는 직접 디스크에서 페이지 데이터를 읽어와 로드한후
present를 1로 설정한 후 다시 동작하게 할 수 있다. (page swap out)
Paging에서는 linear address를 virtual address라고 부른다.
paging enale 전에 해야할 일
---------------------------------
자신 커널공간에 대한 page table과 page directory table을 마련한다.
마련하지 않고 paging enable시키면 바로 eip가 가리키는 커널 공간은
page table에 존재하지 않아 Page Fault가 발생될 것이다.
morecore
---------------------------------
malloc을 구현하기 위해서 기본적으로 커널에서 제공하는 힙 할당 함수로
unix 계열에서 쓰이는 말로 WinNT기반은 MmAllocatePool 같은 것이다.
물리적으로는 떨어진 Page Frame들이 할당되지만 virtual address상으로
연속된 메모리 블럭을 리턴(virtual address를 리턴함)
void* morecore(int size)
{
int start_pte;
pte = get_page_table_entry(page_physic);
for( size/pagesize )
{
page_physic = alloc_page();
// map physical to virtual address
pde = get_directory_entry(page_physic);
if( pde.present == 0 )
{
pt_physic = alloc_page_table();
*pde = pt_physic | kernel | rw | present;
}
*pte = page_physic | kernel | rw | present;
if( start_pte == 0 )
start_pte = pte;
pte = get_next_pte(pte);
}
return start_pte;
}
void* malloc(int size)
{
morecore를 이용하여 구현
}