Paging troubleshooting
Posted: Mon Sep 07, 2015 1:40 pm
I am working on my paging code for a long time. I still have problems with it. So, first I need to know I really know paging, so am I right?
1. Paging is a memory management scheme which organize memory in pages
2. The MMU translates virtual addresses to physical addresses
3. A page is 32 bits (4 bytes) large. Structure of a page is:
5. A page directory is a collection of 1024 page tables. Page directory is loaded into CR3 register that MMU can use its page tables to translate addresses
6. Page tables and page directory are 4096 bits aligned
7. Virtual address of a page is translated to physical using its frame address.
8. A frame is a physical memory area 32 bit (0x20 in hex) (4 bytes) large
9. TLB (translate lookaside buffer) is a cache that improve translation speed
10. If we don't use a page anymore, we need to use invlpg instruction to invalidate its address
11. Paging is enabled when paging bit in CR0 register is set
This was the theory that I know on paging, now how my memory manager should work:
1. I get memory size and I divide it to frame size so I can get number of memory frames, after I create a array of all frames.
2. Next I set all frames to free
3. Then I allocate space for a kernel directory and its page tables using a placement address based allocator
4. After I use memset to clean kernel directory
5. Then I map 1:1 from 0x0 to kernel end + 1 MiB (I know it is better to map 0x0 -> 3 GiB ... kernel end -> 3 GiB + kernel size, but I just want to test if paging works, I will go to a high half kernel later). Mapping algorithm is:
7. Set paging byte in CR0 and enable paging.
This was how my memory manager should work, it is ok? Any improvements to do?
Here is a part of my code: (it is crashing)
Structures:
Frame allocator:
And there is actual paging code:
At last, I understand paging good? If no, can you explain me what I understand wrong? Can you say me why my code is crashing, what I do wrong? (It triple fault after enable paging)
You can see all my code at https://github.com/JustBeYou/PhotonOS/tree/devel/.
Thanks.
1. Paging is a memory management scheme which organize memory in pages
2. The MMU translates virtual addresses to physical addresses
3. A page is 32 bits (4 bytes) large. Structure of a page is:
- present byte
- read/write byte
- user byte
- accessed byte
- dirty byte
- 7 special bytes
- 20 bytes to store frame address
5. A page directory is a collection of 1024 page tables. Page directory is loaded into CR3 register that MMU can use its page tables to translate addresses
6. Page tables and page directory are 4096 bits aligned
7. Virtual address of a page is translated to physical using its frame address.
8. A frame is a physical memory area 32 bit (0x20 in hex) (4 bytes) large
9. TLB (translate lookaside buffer) is a cache that improve translation speed
10. If we don't use a page anymore, we need to use invlpg instruction to invalidate its address
11. Paging is enabled when paging bit in CR0 register is set
This was the theory that I know on paging, now how my memory manager should work:
1. I get memory size and I divide it to frame size so I can get number of memory frames, after I create a array of all frames.
2. Next I set all frames to free
3. Then I allocate space for a kernel directory and its page tables using a placement address based allocator
4. After I use memset to clean kernel directory
5. Then I map 1:1 from 0x0 to kernel end + 1 MiB (I know it is better to map 0x0 -> 3 GiB ... kernel end -> 3 GiB + kernel size, but I just want to test if paging works, I will go to a high half kernel later). Mapping algorithm is:
- find a free frame
- get index of page table where our page will be by dividing virtual address by 1024.
- get index of the page in page table by dividing virtual address to 4096
- get a pointer of the page
- set present byte, rw byte and user byte
- set frame bytes to frame address
7. Set paging byte in CR0 and enable paging.
This was how my memory manager should work, it is ok? Any improvements to do?
Here is a part of my code: (it is crashing)
Structures:
Code: Select all
typedef struct page {
uint32_t present : 1;
uint32_t rw : 1;
uint32_t us : 1;
uint32_t accessed : 1;
uint32_t dirty : 1;
uint32_t unused : 7;
uint32_t frame : 20;
} page_t;
typedef struct page_table {
page_t pages[1024];
} page_table_t __attribute__((aligned(4096)));
typedef struct page_directory {
page_table_t *tables[1024];
uint32_t phys_tables[1024];
} page_directory_t __attribute__((aligned(4096)));
Code: Select all
#define FRAME_SIZE 32
#define FRAME_INDEX(x) (x / FRAME_SIZE)
#define PAGE_ALIGN(x) (x & 0xFFFFF000)
#define FRAME_ADDR_FROM_INDEX(x) (x * FRAME_SIZE)
void init_pmm(uint32_t mem_size)
{
nframes = (mem_size * 1024) / FRAME_SIZE;
frames = kmalloc(sizeof(uint32_t) * nframes, 0, 0);
for (uint32_t i = 0; i < nframes; i++) {
free_frame(FRAME_ADDR_FROM_INDEX(i));
}
}
uint32_t find_frame()
{
for (uint32_t i = 0; i < nframes; i++) {
if (!frames[i]) {
uint32_t frame_addr = FRAME_ADDR_FROM_INDEX(i);
use_frame(frame_addr);
return frame_addr;
}
}
printk("[ERROR] No free frames!");
keep_running();
}
void use_frame(uint32_t addr)
{
int frame_index = FRAME_INDEX(addr);
frames[frame_index] = 1;
}
void free_frame(uint32_t addr)
{
int frame_index = FRAME_INDEX(addr);
frames[frame_index] = 0;
}
Code: Select all
void init_vmm(uint32_t mem_size)
{
// Register interrupt handler
register_interrupt_handler(14, &page_fault_handler);
// Alloc space for kernel directory
kernel_directory = kmalloc(sizeof(page_directory_t), 1, 0);
// Empty it
memset(kernel_directory, 0, sizeof(page_directory_t));
// Set current directory to kernel diretory
current_directory = kernel_directory;
// Map the memory
uint32_t mem_addr = 0x0;
uint32_t frame_addr = 0x0;
while (mem_addr < (size_t) &kernel_end + 0x10000) {
frame_addr = find_frame();
map(mem_addr, frame_addr, 1, 1);
mem_addr += 32;
}
// Switch current directory
switch_page_directory(kernel_directory);
// Enable paging
enable_paging();
}
void switch_page_directory(page_directory_t *dir)
{
current_directory = dir;
write_cr3((uint32_t) &(dir->phys_tables));
}
void enable_paging()
{
uint32_t cr0 = read_cr0();
cr0 |= 0x80000000;
write_cr0(cr0);
paging_enabled = 1;
}
void map(uint32_t va, uint32_t pa, uint32_t rw, uint32_t us)
{
page_t *page = get_page(va, current_directory);
create_page(page, pa, rw, us);
}
void unmap(uint32_t va)
{
page_t *page = get_page(va, current_directory);
free_frame(page->frame);
memset(page, 0, sizeof(page_t));
asm volatile ("invlpg (%0)" : : "a" (va));
}
void create_page(page_t *page, uint32_t frame, uint32_t rw, uint32_t us)
{
page->present = 1;
page->rw = rw;
page->us = us;
page->frame = frame;
}
page_t *get_page(uint32_t address, page_directory_t *dir)
{
int page_index = address / 0x1000;
int table_index = page_index / 1024;
if (dir->tables[table_index] != 0) {
return &(dir->tables[table_index]->pages[page_index]);
} else {
uint32_t phys_table_addr;
dir->tables[table_index] = kmalloc(sizeof(page_table_t),
1, &phys_table_addr);
memset((void*) dir->tables[table_index], 0, sizeof(page_table_t));
dir->phys_tables[table_index] = phys_table_addr | 0x7;
return &(dir->tables[table_index]->pages[page_index]);
}
return NULL;
}
You can see all my code at https://github.com/JustBeYou/PhotonOS/tree/devel/.
Thanks.