pae.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /* Simple PAE paging test. See lib/x86/vm.c for similar code which sets up
  2. * non-PAE paging. */
  3. #include "fwcfg.h"
  4. #include "asm/page.h"
  5. #include "processor.h"
  6. #ifdef __x86_64__
  7. #error This test is 32-bit only.
  8. #endif
  9. #define HUGE_PAGE_SIZE (1UL << 21)
  10. uint64_t pdpt[4] __attribute__((aligned(0x20)));
  11. uint64_t page_dirs[4 * 512] __attribute__((aligned(0x1000)));
  12. uint64_t page_tables[512 * 512] __attribute__((aligned(0x1000)));
  13. static bool is_pae_supported(void) {
  14. struct cpuid c = cpuid(1);
  15. return c.d & (1 << 6);
  16. }
  17. /* Fill page directory at `pd` with huge page entries. */
  18. static void setup_pd_huge_pages(uint64_t *pd, uint64_t start, uint64_t end) {
  19. uint64_t phys = start;
  20. for (unsigned int i = 0; i < 512; i++) {
  21. *pd++ = phys | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK |
  22. PT_PAGE_SIZE_MASK;
  23. phys += HUGE_PAGE_SIZE;
  24. if (phys >= end)
  25. return;
  26. }
  27. }
  28. /* Fill page directory at `pd` with page table entries, and use memory at `pt`
  29. * to create page tables. */
  30. static void setup_pd(uint64_t *pd, uint64_t *pt, uint64_t start, uint64_t end) {
  31. uint64_t phys = start;
  32. for (unsigned int i = 0; i < 512; i++) {
  33. *pd++ = (uint32_t)pt | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK;
  34. for (unsigned int j = 0; j < 512; j++) {
  35. *pt++ = phys | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK;
  36. phys += PAGE_SIZE;
  37. if (phys >= end)
  38. return;
  39. }
  40. }
  41. }
  42. static void setup_mmu(void) {
  43. uint64_t mem_size = fwcfg_get_u64(FW_CFG_RAM_SIZE);
  44. if (mem_size > (1ULL << 32))
  45. mem_size = 1ULL << 32;
  46. /* Map physical memory at 0000_0000 using huge pages */
  47. pdpt[0] = (uint32_t)&page_dirs[0 * 512] | PT_PRESENT_MASK;
  48. setup_pd_huge_pages(&page_dirs[0 * 512], 0, mem_size);
  49. /* Map physical memory at 4000_0000 using huge pages */
  50. pdpt[1] = (uint32_t)&page_dirs[1 * 512] | PT_PRESENT_MASK;
  51. setup_pd_huge_pages(&page_dirs[1 * 512], 0, mem_size);
  52. /* Map physical memory at 8000_0000 using huge pages */
  53. pdpt[2] = (uint32_t)&page_dirs[2 * 512] | PT_PRESENT_MASK;
  54. setup_pd_huge_pages(&page_dirs[2 * 512], 0, mem_size);
  55. /* Map physical memory at C000_0000 using normal tables */
  56. pdpt[3] = (uint32_t)&page_dirs[3 * 512] | PT_PRESENT_MASK;
  57. setup_pd(&page_dirs[3 * 512], &page_tables[0], 0, mem_size);
  58. write_cr0(0);
  59. write_cr4(read_cr4() | X86_CR4_PAE);
  60. write_cr3((uint32_t)pdpt);
  61. write_cr0(X86_CR0_PG | X86_CR0_PE | X86_CR0_WP);
  62. printf("paging enabled\n");
  63. }
  64. int main(void)
  65. {
  66. if (!is_pae_supported()) {
  67. printf("PAE not supported\n");
  68. return 1;
  69. }
  70. printf("PAE supported\n");
  71. setup_mmu();
  72. volatile unsigned int test;
  73. for (int i = 1; i < 4; i++) {
  74. volatile unsigned int *ptr = (unsigned int*)((uint32_t)&test + (i << 30));
  75. printf("writing %u to %p, and reading from %p\n", i, ptr, &test);
  76. *ptr = i;
  77. if (test != i) {
  78. printf("error, got %u\n", i);
  79. return 1;
  80. }
  81. }
  82. printf("everything OK\n");
  83. return 0;
  84. }