diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h index c432b078..c721afb8 100644 --- a/arch/x86/include/asm/page.h +++ b/arch/x86/include/asm/page.h @@ -33,13 +33,13 @@ #include /// Page offset bits -#define PAGE_SHIFT 12 +#define PAGE_BITS 12 #ifdef CONFIG_X86_32 /// Number of page map indirections #define PAGE_MAP_LEVELS 2 /// Page map bits - #define PAGE_MAP_SHIFT 10 + #define PAGE_MAP_BITS 10 /// Total operand width in bits #define BITS 32 /// Linear/virtual address width @@ -50,7 +50,7 @@ /// Number of page map indirections #define PAGE_MAP_LEVELS 4 /// Page map bits - #define PAGE_MAP_SHIFT 9 + #define PAGE_MAP_BITS 9 /// Total operand width in bits #define BITS 64 /// Linear/virtual address width @@ -60,13 +60,15 @@ #endif /// The size of a single page in bytes -#define PAGE_SIZE ( 1L << PAGE_SHIFT) +#define PAGE_SIZE ( 1L << PAGE_BITS) /// The number of entries in a page map table -#define PAGE_MAP_ENTRIES ( 1L << PAGE_MAP_SHIFT) +#define PAGE_MAP_ENTRIES ( 1L << PAGE_MAP_BITS) /// Mask the page address -#define PAGE_MASK (-1L << PAGE_SHIFT) +#define PAGE_MASK (-1L << PAGE_BITS) /// Mask the entry in a page table -#define PAGE_ENTRY_MASK (-1L << (PAGE_SHIFT-PAGE_MAP_SHIFT)) +#define PAGE_ENTRY_MASK (-1L << (PAGE_BITS-PAGE_MAP_BITS)) +/// Mask for all flag bits in a page map entry (including ignored bits) +#define PAGE_FLAGS_MASK (~(-1L << PAGE_BITS) | (-1L << VIRT_BITS)) /// Align to next page #define PAGE_FLOOR(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) @@ -100,14 +102,14 @@ #define PG_ACCESSED (1 << 5) /// Page is dirty due to recentwrite-access (set by CPU) #define PG_DIRTY (1 << 6) -/// Big page: 4MB (or 2MB) +/// Huge page: 4MB (or 2MB, 1GB) #define PG_PSE (1 << 7) /// Page is part of the MPB (SCC specific entry) #define PG_MPE PG_PSE +/// Page attribute table +#define PG_PAT PG_PSE /// Global TLB entry (Pentium Pro and later) #define PG_GLOBAL (1 << 8) -/// Pattern flag -#define PG_PAT (1 << 7) /// This virtual address range is used by SVM system as marked #define PG_SVM (1 << 9) #define PG_SVM_STRONG PG_SVM @@ -115,6 +117,8 @@ #define PG_SVM_LAZYRELEASE (1 << 10) /// Currently, no page frame is behind this page (only the MBP proxy) #define PG_SVM_INIT (1 << 11) +/// Disable execution for this page +#define PG_XD (1L << 63) /// This is a whole set of flags (PRESENT,RW,ACCESSED,DIRTY) for kernelspace tables #define KERN_TABLE (PG_PRESENT|PG_RW|PG_ACCESSED|PG_DIRTY) @@ -146,6 +150,16 @@ typedef struct page_map { */ typedef int (*page_cb_t)(page_entry_t* entry, int level); +/** @brief Get the corresponding page map entry to a given virtual address */ +static inline page_entry_t* virt_to_entry(size_t addr, int level) { + return (page_entry_t*) ((((ssize_t) addr | (-1L << VIRT_BITS)) >> ((level+1) * PAGE_MAP_BITS)) & ~0x7); +} + +/** @brief Get the corresponding virtual address to a page map entry */ +static inline size_t entry_to_virt(page_entry_t* entry, int level) { + return VIRT_SEXT((size_t) entry << ((level+1) * PAGE_MAP_BITS)); +} + /** @brief Converts a virtual address to a physical * * @param viraddr Virtual address to convert diff --git a/arch/x86/mm/page64.c b/arch/x86/mm/page64.c index 23fc31fb..28aafd11 100644 --- a/arch/x86/mm/page64.c +++ b/arch/x86/mm/page64.c @@ -56,23 +56,13 @@ page_map_t* get_boot_page_map(void) return &boot_pml4; } -/** @brief Get the corresponding page map entry to a given virtual address */ -static page_entry_t* virt_to_entry(size_t addr, int level) { - return (page_entry_t*) ((((ssize_t) addr | (-1L << VIRT_BITS)) >> ((level+1) * PAGE_MAP_SHIFT)) & ~0x7); -} - -/** @brief Get the corresponding virtual address to a page map entry */ -static size_t entry_to_virt(page_entry_t* entry, int level) { - return VIRT_SEXT((size_t) entry << ((level+1) * PAGE_MAP_SHIFT)); -} - size_t virt_to_phys(size_t viraddr) { task_t* task = per_core(current_task); spinlock_irqsave_lock(&task->page_lock); size_t* entry = (size_t*) (PAGE_MAP_PGT | (viraddr >> 9)); - size_t phyaddr = (*entry & PAGE_MASK) | (viraddr & ~PAGE_MASK); + size_t phyaddr = (*entry & ~PAGE_FLAGS_MASK) | (viraddr & ~PAGE_MASK); spinlock_irqsave_unlock(&task->page_lock); @@ -161,20 +151,21 @@ int page_iterate(size_t start, size_t end, page_cb_t pre, page_cb_t post) void page_dump(size_t from, size_t to) { - int flags = 0; + task_t* task = per_core(current_task); + + size_t flags = 0; size_t start = 0; - void print(size_t start, size_t end, int flags) { + void print(size_t start, size_t end, size_t flags) { size_t size = end - start; - kprintf("%#018lx-%#018lx %#14x %c%c%c%c%c (%#x)\n", start, end, size, - //(flags & PG_XD) ? '-' : 'x', + kprintf("%#018lx-%#018lx %#14x %c%c%c%c%c%c\n", start, end, size, + (flags & PG_XD) ? '-' : 'x', (flags & PG_GLOBAL) ? 'g' : '-', (flags & PG_DIRTY) ? 'd' : '-', (flags & PG_ACCESSED) ? 'a' : '-', (flags & PG_USER) ? 'u' : '-', - (flags & PG_RW) ? 'w' : '-', - flags + (flags & PG_RW) ? 'w' : '-' ); } @@ -184,14 +175,14 @@ void page_dump(size_t from, size_t to) if (*entry & PG_PRESENT) { if (!level || (*entry & PG_PSE)) { if (!flags) { - flags = *entry & ~PAGE_MASK; + flags = *entry & PAGE_FLAGS_MASK; start = entry_to_virt(entry, level); } - else if (flags != (*entry & ~PAGE_MASK)) { + else if (flags != (*entry & PAGE_FLAGS_MASK)) { end = entry_to_virt(entry, level); print(start, end, flags); start = end; - flags = *entry & ~PAGE_MASK; + flags = *entry & PAGE_FLAGS_MASK; } } } @@ -204,31 +195,50 @@ void page_dump(size_t from, size_t to) return 0; } - kprintf("%-18s-%18s %14s %-5s %s\n", "start", "end", "size", "flags", "(hex)"); // header + // lock tables + spinlock_lock(&kslock); + spinlock_irqsave_lock(&task->page_lock); + + kprintf("%-18s-%18s %14s %-6s\n", "start", "end", "size", "flags"); // header page_iterate(from, to, cb, NULL); + // unlock tables + spinlock_unlock(&kslock); + spinlock_irqsave_unlock(&task->page_lock); + // workaround to print last mapping - if (flags) print(start, PAGE_FLOOR(to), flags); + if (flags) + print(start, PAGE_FLOOR(to), flags); } -// TODO: add NX bit void page_stats(size_t from, size_t to, int reset) { - int i, stats[PAGE_SHIFT] = { 0 }; - const char* labels[] = { "present", "writable", "user accessable", "write through", "cache disabled", - "accessed", "dirty", "huge pages", "global", "svm", "svm lazy", "svm init" }; + task_t* task = per_core(current_task); + + int i, stats[13] = { 0 }; + const char* labels[] = { [0] = "present", "writable", "user accessable", "write through", "cache disabled", // IA-32 "legacy" bits + "accessed", "dirty", "huge pages", "global", "svm", "svm lazy", "svm init", + [12] = "exec disabled" // IA-32e / PAE bits + }; int cb(page_entry_t* entry, int level) { if (*entry & PG_PRESENT) { if (!level || (*entry & PG_PSE)) { // increment stat counters - for (i=0; ipage_lock); + page_iterate(from, to, cb, NULL); + // unlock tables + spinlock_unlock(&kslock); + spinlock_irqsave_unlock(&task->page_lock); + kprintf("total pages:\n"); - for (i=0; i 1 // reserve page for smp boot code - if (!map_region(SMP_SETUP_ADDR, SMP_SETUP_ADDR, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE)) { + if (!map_region(SMP_SETUP_ADDR, SMP_SETUP_ADDR, 1, MAP_NO_CACHE | MAP_REMAP)) { kputs("could not reserve page for smp boot code\n"); return -ENOMEM; } @@ -707,7 +725,7 @@ int arch_paging_init(void) npages = mmap->len / PAGE_SIZE; if ((mmap->addr+mmap->len) % PAGE_SIZE) npages++; - map_region(mmap->addr, mmap->addr, npages, MAP_KERNEL_SPACE|MAP_NO_CACHE); + map_region(mmap->addr, mmap->addr, npages, MAP_NO_CACHE | MAP_REMAP); } mmap++; } @@ -720,15 +738,15 @@ int arch_paging_init(void) */ if (mb_info && (mb_info->flags & MULTIBOOT_INFO_MODS)) { multiboot_module_t* mmodule = (multiboot_module_t*) ((size_t) mb_info->mods_addr); - npages = PAGE_FLOOR(mb_info->mods_count*sizeof(multiboot_module_t)) >> PAGE_SHIFT; + npages = PAGE_FLOOR(mb_info->mods_count*sizeof(multiboot_module_t)) >> PAGE_BITS; - map_region((size_t) mmodule, (size_t) mmodule, npages, MAP_REMAP|MAP_KERNEL_SPACE); + map_region((size_t) mmodule, (size_t) mmodule, npages, MAP_REMAP); for(i=0; imods_count; i++, mmodule++) { // map physical address to the same virtual address - npages = PAGE_FLOOR(mmodule->mod_end - mmodule->mod_start) >> PAGE_SHIFT; - kprintf("Map module %s at 0x%x (%u pages)\n", (char*)(size_t) mmodule->cmdline, mmodule->mod_start, npages); - map_region((size_t) (mmodule->mod_start), (size_t) (mmodule->mod_start), npages, MAP_REMAP|MAP_KERNEL_SPACE); + npages = PAGE_FLOOR(mmodule->mod_end - mmodule->mod_start) >> PAGE_BITS; + kprintf("Map module %s at %#x (%u pages)\n", (char*)(size_t) mmodule->cmdline, mmodule->mod_start, npages); + map_region((size_t) (mmodule->mod_start), (size_t) (mmodule->mod_start), npages, MAP_REMAP); } } #endif