Spaces:
Runtime error
Runtime error
| /* Simple PAE paging test. See lib/x86/vm.c for similar code which sets up | |
| * non-PAE paging. */ | |
| uint64_t pdpt[4] __attribute__((aligned(0x20))); | |
| uint64_t page_dirs[4 * 512] __attribute__((aligned(0x1000))); | |
| uint64_t page_tables[512 * 512] __attribute__((aligned(0x1000))); | |
| static bool is_pae_supported(void) { | |
| struct cpuid c = cpuid(1); | |
| return c.d & (1 << 6); | |
| } | |
| /* Fill page directory at `pd` with huge page entries. */ | |
| static void setup_pd_huge_pages(uint64_t *pd, uint64_t start, uint64_t end) { | |
| uint64_t phys = start; | |
| for (unsigned int i = 0; i < 512; i++) { | |
| *pd++ = phys | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK | | |
| PT_PAGE_SIZE_MASK; | |
| phys += HUGE_PAGE_SIZE; | |
| if (phys >= end) | |
| return; | |
| } | |
| } | |
| /* Fill page directory at `pd` with page table entries, and use memory at `pt` | |
| * to create page tables. */ | |
| static void setup_pd(uint64_t *pd, uint64_t *pt, uint64_t start, uint64_t end) { | |
| uint64_t phys = start; | |
| for (unsigned int i = 0; i < 512; i++) { | |
| *pd++ = (uint32_t)pt | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK; | |
| for (unsigned int j = 0; j < 512; j++) { | |
| *pt++ = phys | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK; | |
| phys += PAGE_SIZE; | |
| if (phys >= end) | |
| return; | |
| } | |
| } | |
| } | |
| static void setup_mmu(void) { | |
| uint64_t mem_size = fwcfg_get_u64(FW_CFG_RAM_SIZE); | |
| if (mem_size > (1ULL << 32)) | |
| mem_size = 1ULL << 32; | |
| /* Map physical memory at 0000_0000 using huge pages */ | |
| pdpt[0] = (uint32_t)&page_dirs[0 * 512] | PT_PRESENT_MASK; | |
| setup_pd_huge_pages(&page_dirs[0 * 512], 0, mem_size); | |
| /* Map physical memory at 4000_0000 using huge pages */ | |
| pdpt[1] = (uint32_t)&page_dirs[1 * 512] | PT_PRESENT_MASK; | |
| setup_pd_huge_pages(&page_dirs[1 * 512], 0, mem_size); | |
| /* Map physical memory at 8000_0000 using huge pages */ | |
| pdpt[2] = (uint32_t)&page_dirs[2 * 512] | PT_PRESENT_MASK; | |
| setup_pd_huge_pages(&page_dirs[2 * 512], 0, mem_size); | |
| /* Map physical memory at C000_0000 using normal tables */ | |
| pdpt[3] = (uint32_t)&page_dirs[3 * 512] | PT_PRESENT_MASK; | |
| setup_pd(&page_dirs[3 * 512], &page_tables[0], 0, mem_size); | |
| write_cr0(0); | |
| write_cr4(read_cr4() | X86_CR4_PAE); | |
| write_cr3((uint32_t)pdpt); | |
| write_cr0(X86_CR0_PG | X86_CR0_PE | X86_CR0_WP); | |
| printf("paging enabled\n"); | |
| } | |
| int main(void) | |
| { | |
| if (!is_pae_supported()) { | |
| printf("PAE not supported\n"); | |
| return 1; | |
| } | |
| printf("PAE supported\n"); | |
| setup_mmu(); | |
| volatile unsigned int test; | |
| for (int i = 1; i < 4; i++) { | |
| volatile unsigned int *ptr = (unsigned int*)((uint32_t)&test + (i << 30)); | |
| printf("writing %u to %p, and reading from %p\n", i, ptr, &test); | |
| *ptr = i; | |
| if (test != i) { | |
| printf("error, got %u\n", i); | |
| return 1; | |
| } | |
| } | |
| printf("everything OK\n"); | |
| return 0; | |
| } | |