diff --git a/am/am.h b/am/am.h index 8363ce88f9450713886ca1857fb8f5b0d883db4b..f9e1bf93a57631fe28db6c47b5827687f2e6dc90 100644 --- a/am/am.h +++ b/am/am.h @@ -84,6 +84,9 @@ void _unprotect(_AddressSpace *as); void _map(_AddressSpace *as, void *va, void *pa, int prot); _Context *_ucontext(_AddressSpace *as, _Area kstack, void *entry); +// hugepage map for xiangshan testing +void _map_rv_hugepage(_AddressSpace *as, void *va, void *pa, int prot, int pagetable_level); + // ================= Multi-Processor Extension (MPE) ================= int _mpe_init(void (*entry)()); diff --git a/am/src/nemu/isa/riscv/vme.c b/am/src/nemu/isa/riscv/vme.c index 1ae368ed60590397368262a62e1140e6f6d087ba..00e8f69db2c83a4c3b33b528416ca5355439ced4 100644 --- a/am/src/nemu/isa/riscv/vme.c +++ b/am/src/nemu/isa/riscv/vme.c @@ -61,6 +61,7 @@ static inline void *new_page() { memset(p, 0, PGSIZE); return p; } + /* * Virtual Memory initialize * pgalloc_f: pointer of page table memory allocater, must return page-aligned address @@ -101,12 +102,14 @@ void _protect(_AddressSpace *as) { void _unprotect(_AddressSpace *as) { } + /* * get current satp */ void __am_get_cur_as(_Context *c) { c->pdir = (vme_enable ? (void *)get_satp() : NULL); } + /* * switch page table to the given context */ @@ -115,6 +118,7 @@ void __am_switch(_Context *c) { set_satp(c->pdir); } } + /* * map va to pa with prot permission with page table root as * Note that RISC-V allow hardware to fault when A and D bit is not set @@ -140,6 +144,45 @@ void _map(_AddressSpace *as, void *va, void *pa, int prot) { } } +/* + * map va to pa with prot permission with page table root as + * pagetable_level indicates page table level to be used + * 0: basic 4KiB page + * 1: 2MiB megapage + * 2: 1GiB gigapage + * Note that RISC-V allow hardware to fault when A and D bit is not set + */ +void _map_rv_hugepage(_AddressSpace *as, void *va, void *pa, int prot, int pagetable_level) { + int hugepage_size; + switch (pagetable_level) { + case 0: hugepage_size = PGSIZE; break; // 4KiB + case 1: hugepage_size = PGSIZE * 512; break; // 2MiB + case 2: hugepage_size = PGSIZE * 512 * 512; break; // 1GiB + default: assert(0); + } + assert((uintptr_t)va % hugepage_size == 0); + // printf("pa %lx sz %lx\n", pa, hugepage_size); + assert((uintptr_t)pa % hugepage_size == 0); + PTE *pg_base = as->ptr; + PTE *pte; + int level; + for (level = PTW_CONFIG.ptw_level - 1; ; level --) { + pte = &pg_base[VPNi(PTW_CONFIG, (uintptr_t)va, level)]; + pg_base = (PTE *)PTE_ADDR(*pte); + if (level == pagetable_level) break; + if (!(*pte & PTE_V)) { + pg_base = new_page(); + *pte = PTE_V | (PN(pg_base) << 10); + } + } + + int hugepage_pn_shift = pagetable_level * 9; + if (!(*pte & PTE_V)) { + *pte = PTE_V | prot | (PN(pa) >> hugepage_pn_shift << hugepage_pn_shift << 10); + } + printf("map huge page level %d, pte value %lx\n", pagetable_level, *pte); +} + _Context *_ucontext(_AddressSpace *as, _Area kstack, void *entry) { _Context *c = (_Context*)kstack.end - 1; diff --git a/tests/amtest/src/main.c b/tests/amtest/src/main.c index 4e3a69b5c123452e268a8b1c575a020542d12102..196352bce7ed05454c5b9f78b79d5107e5b3ee91 100644 --- a/tests/amtest/src/main.c +++ b/tests/amtest/src/main.c @@ -33,6 +33,7 @@ int main(const char *args) { CASE('p', vm_test, CTE(vm_handler), VME(simple_pgalloc, simple_pgfree)); CASE('c', pmp_test, CTE(simple_trap)); CASE('s', sv39_test, IOE, CTE(simple_trap)); + CASE('f', sv39_hp_atom_test, IOE, CTE(simple_trap)); CASE('b', cache_test); case 'H': default: diff --git a/tests/amtest/src/tests/pmp.c b/tests/amtest/src/tests/pmp.c index 1f5325e7edfb50f8176f6faf3687b88989188665..5824290fa171b7b83b6bd3e271e7b3d7d62d0a11 100644 --- a/tests/amtest/src/tests/pmp.c +++ b/tests/amtest/src/tests/pmp.c @@ -15,60 +15,60 @@ inline int inst_is_compressed(uint64_t addr){ return (byte & 0x3) != 0x3; } -uint64_t store_access_fault_to_be_reported = 0; -uint64_t store_access_fault_reported = 0; -uint64_t load_access_fault_to_be_reported = 0; -uint64_t load_access_fault_reported = 0; +volatile uint64_t pmp_store_access_fault_to_be_reported = 0; +volatile uint64_t pmp_store_access_fault_reported = 0; +volatile uint64_t pmp_load_access_fault_to_be_reported = 0; +volatile uint64_t pmp_load_access_fault_reported = 0; volatile int result_blackhole = 0; void reset_result_flags() { - store_access_fault_to_be_reported = 0; - store_access_fault_reported = 0; - load_access_fault_to_be_reported = 0; - load_access_fault_reported = 0; + pmp_store_access_fault_to_be_reported = 0; + pmp_store_access_fault_reported = 0; + pmp_load_access_fault_to_be_reported = 0; + pmp_load_access_fault_reported = 0; } void result_check() { - assert(!(store_access_fault_to_be_reported && load_access_fault_to_be_reported)); - if (store_access_fault_to_be_reported) { - if (!store_access_fault_reported || load_access_fault_reported) { - printf("store_access_fault_reported %x, load_access_fault_reported %x\n", - store_access_fault_reported, load_access_fault_reported); + assert(!(pmp_store_access_fault_to_be_reported && pmp_load_access_fault_to_be_reported)); + if (pmp_store_access_fault_to_be_reported) { + if (!pmp_store_access_fault_reported || pmp_load_access_fault_reported) { + printf("pmp_store_access_fault_reported %x, pmp_load_access_fault_reported %x\n", + pmp_store_access_fault_reported, pmp_load_access_fault_reported); _halt(1); } - } else if (load_access_fault_to_be_reported) { - if (!load_access_fault_reported || store_access_fault_reported) { - printf("store_access_fault_reported %x, load_access_fault_reported %x\n", - store_access_fault_reported, load_access_fault_reported); + } else if (pmp_load_access_fault_to_be_reported) { + if (!pmp_load_access_fault_reported || pmp_store_access_fault_reported) { + printf("pmp_store_access_fault_reported %x, pmp_load_access_fault_reported %x\n", + pmp_store_access_fault_reported, pmp_load_access_fault_reported); _halt(1); } } else { - if (load_access_fault_reported || store_access_fault_reported) { - printf("store_access_fault_reported %x, load_access_fault_reported %x\n", - store_access_fault_reported, load_access_fault_reported); + if (pmp_load_access_fault_reported || pmp_store_access_fault_reported) { + printf("pmp_store_access_fault_reported %x, pmp_load_access_fault_reported %x\n", + pmp_store_access_fault_reported, pmp_load_access_fault_reported); _halt(1); } } // result check passed, reset flags - store_access_fault_to_be_reported = 0; - store_access_fault_reported = 0; - load_access_fault_to_be_reported = 0; - load_access_fault_reported = 0; + pmp_store_access_fault_to_be_reported = 0; + pmp_store_access_fault_reported = 0; + pmp_load_access_fault_to_be_reported = 0; + pmp_load_access_fault_reported = 0; } -_Context* store_access_fault_handler(_Event* ev, _Context *c) { +_Context* pmp_store_access_fault_handler(_Event* ev, _Context *c) { printf("store access fault triggered, sepc %lx\n", c->sepc); - store_access_fault_reported = 1; + pmp_store_access_fault_reported = 1; // skip the inst that triggered the exception c->sepc = inst_is_compressed(c->sepc) ? c->sepc + 2: c->sepc + 4; // printf("goto %x\n", c->sepc); return c; } -_Context* load_access_fault_handler(_Event* ev, _Context *c) { +_Context* pmp_load_access_fault_handler(_Event* ev, _Context *c) { printf("load access fault triggered, sepc %lx\n", c->sepc); - load_access_fault_reported = 1; + pmp_load_access_fault_reported = 1; // skip the inst that triggered the exception c->sepc = inst_is_compressed(c->sepc) ? c->sepc + 2: c->sepc + 4; // printf("goto %x\n", c->sepc); @@ -76,12 +76,12 @@ _Context* load_access_fault_handler(_Event* ev, _Context *c) { } void pmp_test() { - irq_handler_reg(EXCEPTION_STORE_ACCESS_FAULT, &store_access_fault_handler); - irq_handler_reg(EXCEPTION_LOAD_ACCESS_FAULT, &load_access_fault_handler); + irq_handler_reg(EXCEPTION_STORE_ACCESS_FAULT, &pmp_store_access_fault_handler); + irq_handler_reg(EXCEPTION_LOAD_ACCESS_FAULT, &pmp_load_access_fault_handler); printf("start pmp test\n"); #if defined(__ARCH_RISCV64_NOOP) || defined(__ARCH_RISCV32_NOOP) || defined(__ARCH_RISCV64_XS) // Case: store to address protected by pmp - store_access_fault_to_be_reported = 1; + pmp_store_access_fault_to_be_reported = 1; volatile int *a = (int *)(0x90000040UL); *a = 1; // should trigger a fault result_check(); @@ -94,35 +94,35 @@ void pmp_test() { printf("line %d passed\n", __LINE__); // Case: store to address protected by pmp tor - store_access_fault_to_be_reported = 1; + pmp_store_access_fault_to_be_reported = 1; int *c = (int *)(0xb0000040UL); *c = 1; // should trigger a fault result_check(); printf("line %d passed\n", __LINE__); // Case: load from address protected by pmp - load_access_fault_to_be_reported = 1; + pmp_load_access_fault_to_be_reported = 1; volatile int *d = (int *)(0x90000040UL); result_blackhole = (*d); // should trigger a fault result_check(); printf("line %d passed\n", __LINE__); // Case: load from address protected by pmp tor - load_access_fault_to_be_reported = 1; + pmp_load_access_fault_to_be_reported = 1; volatile int *e = (int *)(0xb0000040UL); result_blackhole = (*e); // should trigger a fault result_check(); printf("line %d passed\n", __LINE__); // Case: store to address protected by pmp (use pmpcfg2) - store_access_fault_to_be_reported = 1; + pmp_store_access_fault_to_be_reported = 1; int *f = (int *)(0xb0010000UL); *f = 1; // should trigger a fault result_check(); printf("line %d passed\n", __LINE__); // Case: lr from address protected by pmp - load_access_fault_to_be_reported = 1; + pmp_load_access_fault_to_be_reported = 1; asm volatile( "li s4, 0xb0000040;" "lr.d s5, (s4);" @@ -134,7 +134,7 @@ void pmp_test() { printf("line %d passed\n", __LINE__); // Case: sc to address protected by pmp - store_access_fault_to_be_reported = 1; + pmp_store_access_fault_to_be_reported = 1; asm volatile( "li s4, 0xb0000040;" "sc.d s5, s5, (s4);" @@ -146,7 +146,7 @@ void pmp_test() { printf("line %d passed\n", __LINE__); // Case: amo to address protected by pmp - store_access_fault_to_be_reported = 1; + pmp_store_access_fault_to_be_reported = 1; asm volatile( "li s4, 0xb0000040;" "amoadd.d s5, s6, (s4);" @@ -158,7 +158,7 @@ void pmp_test() { printf("line %d passed\n", __LINE__); // Case: amo to address protected by pmp (w,!r) - store_access_fault_to_be_reported = 1; + pmp_store_access_fault_to_be_reported = 1; asm volatile( "li s4, 0xb0008000;" "amoadd.d s5, s6, (s4);" @@ -170,7 +170,7 @@ void pmp_test() { printf("line %d passed\n", __LINE__); // Case: amo to address protected by pmp (!w,r) - store_access_fault_to_be_reported = 1; + pmp_store_access_fault_to_be_reported = 1; asm volatile( "li s4, 0xb0004000;" "amoadd.d s5, s6, (s4);" @@ -183,12 +183,12 @@ void pmp_test() { #elif defined(__ARCH_RISCV64_XS_SOUTHLAKE) || defined(__ARCH_RISCV64_XS_SOUTHLAKE_FLASH) // TODO: update pmp test for southlake - store_access_fault_to_be_reported = 0; + pmp_store_access_fault_to_be_reported = 0; int *b = (int *)(0x2030000000UL); *b = 1; // should not trigger a fault result_check(); - store_access_fault_to_be_reported = 1; + pmp_store_access_fault_to_be_reported = 1; volatile int *a = (int *)(0x2010000040UL); *a = 1; // should trigger a fault result_check(); diff --git a/tests/amtest/src/tests/sv39.c b/tests/amtest/src/tests/sv39.c index a2df7171bb951585b7b15207d11070022b9e4e18..78e2493614d625d0edcd45598ccb8339bfd6ef03 100644 --- a/tests/amtest/src/tests/sv39.c +++ b/tests/amtest/src/tests/sv39.c @@ -6,6 +6,8 @@ * RISC-V 64 SV39 Virutal Memory test */ +#define EXCEPTION_LOAD_ACCESS_FAULT 5 +#define EXCEPTION_STORE_ACCESS_FAULT 7 #define EXCEPTION_LOAD_PAGE_FAULT 13 #define EXCEPTION_STORE_PAGE_FAULT 15 @@ -17,7 +19,11 @@ static char *sv39_alloc_base = (char *)(0x2040000000UL); // invalid arch #endif -uint64_t page_fault_to_be_reported = 0; +volatile uint64_t load_page_fault_to_be_reported = 0; +volatile uint64_t store_page_fault_to_be_reported = 0; +volatile uint64_t load_access_fault_to_be_reported = 0; +volatile uint64_t store_access_fault_to_be_reported = 0; + inline int inst_is_compressed(uint64_t addr){ uint8_t byte = *(uint8_t*)addr; @@ -26,20 +32,40 @@ inline int inst_is_compressed(uint64_t addr){ _Context* store_page_fault_handler(_Event* ev, _Context *c) { printf("store page fault triggered\n"); - if(!page_fault_to_be_reported){ + if(!store_page_fault_to_be_reported){ _halt(1); // something went wrong } - page_fault_to_be_reported = 0; + store_page_fault_to_be_reported = 0; c->sepc = inst_is_compressed(c->sepc) ? c->sepc + 2: c->sepc + 4; return c; } _Context* load_page_fault_handler(_Event* ev, _Context *c) { printf("load page fault triggered\n"); - if(!page_fault_to_be_reported){ + if(!load_page_fault_to_be_reported){ + _halt(1); // something went wrong + } + load_page_fault_to_be_reported = 0; + c->sepc = inst_is_compressed(c->sepc) ? c->sepc + 2: c->sepc + 4; + return c; +} + +_Context* load_access_fault_handler(_Event* ev, _Context *c) { + printf("load access fault triggered\n"); + if(!load_access_fault_to_be_reported){ _halt(1); // something went wrong } - page_fault_to_be_reported = 0; + load_access_fault_to_be_reported = 0; + c->sepc = inst_is_compressed(c->sepc) ? c->sepc + 2: c->sepc + 4; + return c; +} + +_Context* store_access_fault_handler(_Event* ev, _Context *c) { + printf("store access fault triggered\n"); + if(!store_access_fault_to_be_reported){ + _halt(1); // something went wrong + } + store_access_fault_to_be_reported = 0; c->sepc = inst_is_compressed(c->sepc) ? c->sepc + 2: c->sepc + 4; return c; } @@ -94,17 +120,144 @@ void sv39_test() { assert(*r_ptr == 'a'); printf("test sv39 store page fault\n"); - page_fault_to_be_reported = 1; - *fault_ptr = 'b'; // store: not compressed - if(page_fault_to_be_reported){ + store_page_fault_to_be_reported = 1; + *fault_ptr = 'b'; + if(store_page_fault_to_be_reported){ _halt(1); } printf("test sv39 load page fault\n"); - page_fault_to_be_reported = 1; + load_page_fault_to_be_reported = 1; *w_ptr = *fault_ptr; - if(page_fault_to_be_reported){ + if(load_page_fault_to_be_reported){ _halt(1); } _halt(0); } + +/* + * RISC-V 64 SV39 Hugepage + Hugepage Atom Inst test + */ + +void sv39_hp_atom_test() { + printf("start sv39 hugepage atom test\n"); + _vme_init(sv39_pgalloc, sv39_pgfree); + printf("sv39 setup done\n"); +#if defined(__ARCH_RISCV64_NOOP) || defined(__ARCH_RISCV32_NOOP) || defined(__ARCH_RISCV64_XS) + _map(&kas, (void *)0x900000000UL, (void *)0x80200000, PTE_R | PTE_A | PTE_D); + // allocate a metapage, not protected by pmp + _map_rv_hugepage(&kas, (void *)0xa00000000UL, (void *)0x80200000, PTE_W | PTE_R | PTE_A | PTE_D, 1); + // allocate a metapage, not protected by pmp, without write perm + _map_rv_hugepage(&kas, (void *)0xb00000000UL, (void *)0x80200000, PTE_R | PTE_A | PTE_D, 1); + // allocate a metapage, not protected by pmp, without read perm + _map_rv_hugepage(&kas, (void *)0xc00000000UL, (void *)0x80200000, PTE_W | PTE_A | PTE_D, 1); + // allocate a metapage, protected by pmp (!rw) + _map_rv_hugepage(&kas, (void *)0xd00000000UL, (void *)0xb0000000, PTE_W | PTE_R | PTE_A | PTE_D, 1); + char *normal_rw_ptr = (char *)(0x900000000UL); + char *hp_rw_ptr = (char *)(0xa00000000UL); + char *hp_r_ptr = (char *)(0xb00000000UL); + char *hp_w_ptr = (char *)(0xc00000000UL); + char *hp_pmp_ptr = (char *)(0xd00000000UL); + printf("memory map done\n"); +#elif defined(__ARCH_RISCV64_XS_SOUTHLAKE) || defined(__ARCH_RISCV64_XS_SOUTHLAKE_FLASH) + // TODO +#else + // invalid arch + _halt(1); +#endif + irq_handler_reg(EXCEPTION_STORE_PAGE_FAULT, &store_page_fault_handler); + irq_handler_reg(EXCEPTION_LOAD_PAGE_FAULT, &load_page_fault_handler); + irq_handler_reg(EXCEPTION_STORE_ACCESS_FAULT, &store_access_fault_handler); + irq_handler_reg(EXCEPTION_LOAD_ACCESS_FAULT, &load_access_fault_handler); + + printf("test sv39 hugepage data write\n"); + *hp_rw_ptr = 'a'; + + printf("test sv39 hugepage data read\n"); + assert(*hp_rw_ptr == 'a'); + + printf("test sv39 normalpage data read\n"); + assert(*normal_rw_ptr == 'a'); + + printf("test sv39 hugepage store page fault\n"); + store_page_fault_to_be_reported = 1; + *hp_r_ptr = 'b'; + if(store_page_fault_to_be_reported){ + _halt(1); + } + + printf("test sv39 hugepage load page fault\n"); + load_page_fault_to_be_reported = 1; + *hp_rw_ptr = *hp_w_ptr; + if(load_page_fault_to_be_reported){ + _halt(1); + } + + printf("test sv39 hugepage store access fault\n"); + store_access_fault_to_be_reported = 1; + *hp_pmp_ptr = 'b'; + if(store_page_fault_to_be_reported){ + _halt(1); + } + + printf("test sv39 hugepage load access fault\n"); + load_access_fault_to_be_reported = 1; + *hp_rw_ptr = *hp_pmp_ptr; + if(load_access_fault_to_be_reported){ + _halt(1); + } + + printf("test sv39 hugepage atom store page fault\n"); + store_page_fault_to_be_reported = 1; + asm volatile( + "li s4, 0xb00000000;" + "amoadd.d s5, s6, (s4);" + : + : + :"s4","s5","s6" + ); + if(store_page_fault_to_be_reported){ + _halt(1); + } + + printf("test sv39 hugepage atom load page fault\n"); + load_page_fault_to_be_reported = 1; + asm volatile( + "li s4, 0xc00000000;" + "lr.d s5, (s4);" + : + : + :"s4","s5","s6" + ); + if(load_page_fault_to_be_reported){ + _halt(1); + } + + printf("test sv39 hugepage atom store access fault\n"); + store_access_fault_to_be_reported = 1; + asm volatile( + "li s4, 0xd00000000;" + "amoadd.d s5, s6, (s4);" + : + : + :"s4","s5","s6" + ); + if(store_page_fault_to_be_reported){ + _halt(1); + } + + printf("test sv39 hugepage atom load access fault\n"); + load_access_fault_to_be_reported = 1; + asm volatile( + "li s4, 0xd00000000;" + "lr.d s5, (s4);" + : + : + :"s4","s5","s6" + ); + if(load_access_fault_to_be_reported){ + _halt(1); + } + + _halt(0); +} \ No newline at end of file