Quantcast
Channel: Active questions tagged gcc - Stack Overflow
Viewing all articles
Browse latest Browse all 22093

Identity mapping dosen't work after enabling paging

$
0
0

I try to implement my own OS, and now I try to implement paging mechanism.
I created a page directory, and created identity mapping of the kernel code.However, after storing the physical address of the first page table and enabling paging, my code seems lost - meaning, the virtual address not mapped to a physical address, or mapped to a wrong one.I can see this behaviour in GDB: my code opcodes turn to add [eax], al.

My structs are:

#define MAX_PAGES_PER_TABLE 1024#define MAX_TABLES_PER_DIR 1024typedef struct {    uint32_t present    : 1;   // Page present in memory    uint32_t rw         : 1;   // Read-only if clear, readwrite if set    uint32_t user       : 1;   // Supervisor level only if clear    uint32_t accessed   : 1;   // Has the page been accessed since last refresh?    uint32_t dirty      : 1;   // Has the page been written to since last refresh?    uint32_t unused     : 7;   // Amalgamation of unused and reserved bits    uint32_t frame      : 20;  // Frame address (shifted right 12 bits)} page_t;typedef struct {    page_t pages[MAX_PAGES_PER_TABLE];} page_table_t;typedef struct {    page_table_t* page_tables[MAX_TABLES_PER_DIR]; // Array of pointers to pagetables.    /*       Array of pointers to the pagetables above, but gives their *physical*       location, for loading into the CR3 register.    */    uint32_t page_tables_physical[MAX_TABLES_PER_DIR];    /*       The physical address of page_tables_physical. This comes into play       when we get our kernel heap allocated and the directory       may be in a different location in virtual memory.    */    uint32_t physical_address;} page_directory_t;

Here is my enabling paging code:

page_directory_t* current_page_dir;void switch_page_directory(page_directory_t* new_page_directory){    current_page_dir = new_page_directory;    // let the cpu know the physical address of the page tables    asm volatile("mov %0, %%cr3" : : "r"(&new_page_directory->page_tables_physical));    uint32_t cr0;    asm volatile("mov %%cr0, %0" : "=r"(cr0));    cr0 |= 0x80000000; // set the PG flag of cr0 - enable paging    asm volatile("mov %0, %%cr0" : : "r" (cr0));}

I double checked that the page directory looks ok, but maybe I am wrong so here is the identity mapping code:

void alloc_frame(page_t *page, int is_kernel, int is_writeable){    if (page->frame != 0) {        // there is already a frame associated with the page        return;    }    uint32_t first_free_frame_address = first_not_set(frames);    if (first_free_frame_address == frames.len + 1) {        panic("no free pages");    }    set_bit(first_free_frame_address, frames);    page->frame = first_free_frame_address * ALIGNMENT;    page->present = 1;    page->rw = is_writeable ? 1: 0;    page->user = is_kernel ? 0 : 1;}page_t* get_page(uint32_t address, int create, page_directory_t* dir){    // when dividing the address by alignment, the index of the page is received    uint32_t address_index = address / ALIGNMENT;    // according to the index of the address,    // the index of the table, and the index of the page in the table are calculated    uint32_t table_index = address_index / MAX_PAGES_PER_TABLE;    uint32_t page_index = address_index % MAX_PAGES_PER_TABLE;    if (dir->page_tables[table_index]) {        // page table exists        return &dir->page_tables[table_index]->pages[page_index];    } else if (create) {        // page table doesn't exist - creating it        uint32_t physical_address;        dir->page_tables[table_index] = (page_table_t*) kmalloc_internal(sizeof(page_table_t), 1, &physical_address);        // set a first entry in the table        memory_set((uint8_t*)dir->page_tables[table_index], 0, ALIGNMENT);        // give the first page, the attributes: Present, Read/Write, Kernel page        physical_address |= 0x3;        // save the physical address of the table        dir->page_tables_physical[table_index] = physical_address;        return &dir->page_tables[table_index]->pages[page_index];    } else {        //page table doesn't exist - page cannot be retrieved        return 0;    }}void initialize_paging(){    initialize_frames();    page_directory_t* page_dir = (page_directory_t*) kmalloc(sizeof(page_directory_t));    memory_set((uint8_t*) page_dir, 0, sizeof(page_directory_t));    // set the physical addresses of the page tables to 0 with attributes:    // kernel tables, rw, not present    int j;    uint8_t* tmp = (uint8_t*) page_dir->page_tables_physical;    for (j = 0; j < 1024; j++) {        memory_set(tmp, 2, 1);        tmp++;        memory_set(tmp, 0, 3);        tmp += 3;    }    current_page_dir = page_dir;    // We need to identity map (phys addr = virt addr) from    // 0x0 to the end of used memory, so we can access this    // transparently, as if paging wasn't enabled.    // NOTE that we use a while loop here deliberately.    // inside the loop body we actually change free_physical_address    // by calling kmalloc(). A while loop causes this to be    // computed on-the-fly rather than once at the start.    uint32_t free_physical_address = get_current_physicall_address();    uint32_t i = 0;    while (i <= free_physical_address)    {        // Kernel code is readable but not writeable from userspace.        alloc_frame(get_page(i, 1, page_dir), 1, 1);        i += ALIGNMENT;        // get_page() may allocate more space for new tables        free_physical_address = get_current_physicall_address();    }

That's a lot of code so I will sum up:
alloc_frame() finds the next free frame - using a bitset (I don't put the bitset code here because it works correctly.
get_page(), returns the page entry corresponding to the given address, and creates the page table if it doesn't exist.
initialize_paging() creates the page directory and does the identity mapping.

The following functions are not here but that's their summary:
kmalloc() allocates memory aligned to 4096.
get_current_physicall_address() returns the address which kmalloc will allocate on the next run.
memory_set() is my implementation of memset().

Any help will be appreciated!
Thanks in advance!


Viewing all articles
Browse latest Browse all 22093

Trending Articles