From 116db01939f3af0b32435c939a7e5a63a68803c3 Mon Sep 17 00:00:00 2001 From: Zihao Yu Date: Fri, 6 Mar 2020 15:55:23 +0800 Subject: [PATCH] *-nemu,vme: refactor ptw code --- am/include/mips.h | 11 ------ am/include/riscv.h | 20 ---------- am/src/nemu/include/nemu.h | 24 +++++++++++- am/src/nemu/isa/mips/vme.c | 10 ++--- am/src/nemu/isa/x86/vme.c | 75 ++++++++++++++------------------------ 5 files changed, 54 insertions(+), 86 deletions(-) diff --git a/am/include/mips.h b/am/include/mips.h index 4d565fe5..08ab6f32 100644 --- a/am/include/mips.h +++ b/am/include/mips.h @@ -17,22 +17,11 @@ static inline void outl(uintptr_t addr, uint32_t data) { *(volatile uint32_t *)a #define PTE_D 0x4 // Page directory and page table constants -#define NR_PDE 1024 // # directory entries per page directory -#define NR_PTE 1024 // # PTEs per page table -#define PGSHFT 12 // log2(PGSIZE) #define PTXSHFT 12 // Offset of PTX in a linear address #define PDXSHFT 22 // Offset of PDX in a linear address -// +--------10------+-------10-------+---------12----------+ -// | Page Directory | Page Table | Offset within Page | -// | Index | Index | | -// +----------------+----------------+---------------------+ -// \--- PDX(va) --/ \--- PTX(va) --/\------ OFF(va) ------/ -typedef uint32_t PTE; -typedef uint32_t PDE; #define PDX(va) (((uint32_t)(va) >> PDXSHFT) & 0x3ff) #define PTX(va) (((uint32_t)(va) >> PTXSHFT) & 0x3ff) -#define OFF(va) ((uint32_t)(va) & 0xfff) // Address in page table or page directory entry #define PTE_ADDR(pte) ((uint32_t)(pte) & ~0xfff) diff --git a/am/include/riscv.h b/am/include/riscv.h index 56dd7a0b..a22de5d9 100644 --- a/am/include/riscv.h +++ b/am/include/riscv.h @@ -35,33 +35,13 @@ enum { MODE_U = 0, MODE_S, MODE_H, MODE_M }; #define PTE_X 0x08 #define PTE_U 0x10 -typedef uintptr_t PTE; -#define PGSHFT 12 // log2(PGSIZE) -#define PN(addr) ((uintptr_t)(addr) >> PGSHFT) -#define OFF(va) ((uintptr_t)(va) & (PGSIZE - 1)) - // Address in page table entry #define PTE_ADDR(pte) (((uintptr_t)(pte) & ~0x3ff) << 2) -typedef struct { - int ptw_level; - int vpn_width; -} ptw_config; - #define PTW_SV32 ((ptw_config) { .ptw_level = 2, .vpn_width = 10 }) #define PTW_SV39 ((ptw_config) { .ptw_level = 3, .vpn_width = 9 }) #define PTW_SV48 ((ptw_config) { .ptw_level = 4, .vpn_width = 9 }) -// Offset of VPN[i] in a virtual address -static inline int VPNiSHFT(const ptw_config c, int i) { - return (PGSHFT) + c.vpn_width * i; -} -// Extract the VPN[i] field in a virtual address -static inline uintptr_t VPNi(const ptw_config c, uintptr_t va, int i) { - uintptr_t vpn_mask = (1 << c.vpn_width) - 1; - return (va >> VPNiSHFT(c, i)) & vpn_mask; -} - #endif #endif diff --git a/am/src/nemu/include/nemu.h b/am/src/nemu/include/nemu.h index f10e7864..58b63284 100644 --- a/am/src/nemu/include/nemu.h +++ b/am/src/nemu/include/nemu.h @@ -33,8 +33,6 @@ # define FB_ADDR 0xa0000000 #endif -#define PGSIZE 4096 - #define MMIO_BASE 0xa0000000 #define MMIO_SIZE 0x10000000 @@ -45,4 +43,26 @@ extern char _pmem_start, _pmem_end; RANGE(0xa0000000, 0xa0000000 + 0x80000), /* vmem */ \ RANGE(0xa1000000, 0xa1000000 + 0x1000) /* serial, rtc, screen, keyboard */ +#define PGSIZE 4096 +#define PGSHFT 12 // log2(PGSIZE) +#define PN(addr) ((uintptr_t)(addr) >> PGSHFT) +#define OFF(va) ((uintptr_t)(va) & (PGSIZE - 1)) + +typedef uintptr_t PTE; + +typedef struct { + int ptw_level; + int vpn_width; +} ptw_config; + +// Offset of VPN[i] in a virtual address +static inline int VPNiSHFT(const ptw_config c, int i) { + return (PGSHFT) + c.vpn_width * i; +} +// Extract the VPN[i] field in a virtual address +static inline uintptr_t VPNi(const ptw_config c, uintptr_t va, int i) { + uintptr_t vpn_mask = (1 << c.vpn_width) - 1; + return (va >> VPNiSHFT(c, i)) & vpn_mask; +} + #endif diff --git a/am/src/nemu/isa/mips/vme.c b/am/src/nemu/isa/mips/vme.c index 05ee48cc..b029ee14 100644 --- a/am/src/nemu/isa/mips/vme.c +++ b/am/src/nemu/isa/mips/vme.c @@ -17,7 +17,7 @@ int _vme_init(void* (*pgalloc_f)(size_t), void (*pgfree_f)(void*)) { } void _protect(_AddressSpace *as) { - as->ptr = (PDE*)(pgalloc_usr(PGSIZE)); + as->ptr = (PTE*)(pgalloc_usr(PGSIZE)); as->pgsize = PGSIZE; as->area = USER_SPACE; } @@ -25,7 +25,7 @@ void _protect(_AddressSpace *as) { void _unprotect(_AddressSpace *as) { } -static PDE *cur_pdir = NULL; +static PTE *cur_pdir = NULL; void __am_get_cur_as(_Context *c) { c->pdir = cur_pdir; } @@ -43,8 +43,8 @@ void __am_switch(_Context *c) { void _map(_AddressSpace *as, void *va, void *pa, int prot) { assert((uintptr_t)va % PGSIZE == 0); assert((uintptr_t)pa % PGSIZE == 0); - PDE *pdir = (PDE*)as->ptr; - PDE *pde = &pdir[PDX(va)]; + PTE *pdir = (PTE*)as->ptr; + PTE *pde = &pdir[PDX(va)]; if (!(*pde & PTE_V)) { *pde = PTE_V | (uint32_t)pgalloc_usr(PGSIZE); } @@ -82,7 +82,7 @@ void __am_tlb_refill() { uint32_t va = hi & ~0x1fff; assert(cur_pdir != NULL); - PDE *pde = &cur_pdir[PDX(va)]; + PTE *pde = &cur_pdir[PDX(va)]; assert(*pde & PTE_V); PTE *pte = &((PTE*)PTE_ADDR(*pde))[PTX(va)]; diff --git a/am/src/nemu/isa/x86/vme.c b/am/src/nemu/isa/x86/vme.c index f27761f8..7e7783ca 100644 --- a/am/src/nemu/isa/x86/vme.c +++ b/am/src/nemu/isa/x86/vme.c @@ -2,24 +2,9 @@ #include #include -typedef uint32_t PTE; -typedef uint32_t PDE; +#define PTE_ADDR(pte) ((uintptr_t)(pte) & ~0xfff) -#define NR_PDE 1024 // # directory entries per page directory -#define NR_PTE 1024 // # PTEs per page table -#define PGSHFT 12 // log2(PGSIZE) -#define PTXSHFT 12 // Offset of PTX in a linear address -#define PDXSHFT 22 // Offset of PDX in a linear address - -#define PDX(va) (((uint32_t)(va) >> PDXSHFT) & 0x3ff) -#define PTX(va) (((uint32_t)(va) >> PTXSHFT) & 0x3ff) -#define OFF(va) ((uint32_t)(va) & 0xfff) -#define PTE_ADDR(pte) ((uint32_t)(pte) & ~0xfff) -#define PGADDR(d, t, o) ((uint32_t)((d) << PDXSHFT | (t) << PTXSHFT | (o))) -#define PG_ALIGN __attribute((aligned(PGSIZE))) - -static PDE kpdirs[NR_PDE] PG_ALIGN = {}; -static PTE kptabs[(PMEM_SIZE + MMIO_SIZE) / PGSIZE] PG_ALIGN = {}; +static _AddressSpace kas; // Kernel address space static void* (*pgalloc_usr)(size_t) = NULL; static void (*pgfree_usr)(void*) = NULL; static int vme_enable = 0; @@ -34,32 +19,19 @@ int _vme_init(void* (*pgalloc_f)(size_t), void (*pgfree_f)(void*)) { pgalloc_usr = pgalloc_f; pgfree_usr = pgfree_f; + kas.ptr = pgalloc_f(PGSIZE); + // make all PTEs invalid + memset(kas.ptr, 0, PGSIZE); + int i; - - // make all PDEs invalid - for (i = 0; i < NR_PDE; i ++) { - kpdirs[i] = 0; - } - - PTE *ptab = kptabs; for (i = 0; i < LENGTH(segments); i ++) { - uint32_t pdir_idx = (uintptr_t)segments[i].start / (PGSIZE * NR_PTE); - uint32_t pdir_idx_end = (uintptr_t)segments[i].end / (PGSIZE * NR_PTE); - for (; pdir_idx < pdir_idx_end; pdir_idx ++) { - // fill PDE - kpdirs[pdir_idx] = (uintptr_t)ptab | PTE_P; - - // fill PTE - PTE pte = PGADDR(pdir_idx, 0, 0) | PTE_P; - PTE pte_end = PGADDR(pdir_idx + 1, 0, 0) | PTE_P; - for (; pte < pte_end; pte += PGSIZE) { - *ptab = pte; - ptab ++; - } + void *va = segments[i].start; + for (; va < segments[i].end; va += PGSIZE) { + _map(&kas, va, va, 0); } } - set_cr3(kpdirs); + set_cr3(kas.ptr); set_cr0(get_cr0() | CR0_PG); vme_enable = 1; @@ -67,14 +39,12 @@ int _vme_init(void* (*pgalloc_f)(size_t), void (*pgfree_f)(void*)) { } void _protect(_AddressSpace *as) { - PDE *updir = (PDE*)(pgalloc_usr(PGSIZE)); + PTE *updir = (PTE*)(pgalloc_usr(PGSIZE)); as->ptr = updir; as->area = USER_SPACE; as->pgsize = PGSIZE; // map kernel space - for (int i = 0; i < NR_PDE; i ++) { - updir[i] = kpdirs[i]; - } + memcpy(updir, kas.ptr, PGSIZE); } void _unprotect(_AddressSpace *as) { @@ -88,17 +58,26 @@ void __am_switch(_Context *c) { if (vme_enable && c->cr3 != NULL) { set_cr3(c->cr3); } } +#define PTW_CONFIG ((ptw_config) { .ptw_level = 2, .vpn_width = 10 }) + void _map(_AddressSpace *as, void *va, void *pa, int prot) { assert((uintptr_t)va % PGSIZE == 0); assert((uintptr_t)pa % PGSIZE == 0); - PDE *pt = (PDE*)as->ptr; - PDE *pde = &pt[PDX(va)]; - if (!(*pde & PTE_P)) { - *pde = PTE_P | PTE_W | PTE_U | (uint32_t)pgalloc_usr(PGSIZE); + 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 == 0) break; + if (!(*pte & PTE_P)) { + pg_base = pgalloc_usr(PGSIZE); + *pte = PTE_P | PTE_W | PTE_U | (uintptr_t)pg_base; + } } - PTE *pte = &((PTE*)PTE_ADDR(*pde))[PTX(va)]; + if (!(*pte & PTE_P)) { - *pte = PTE_P | PTE_W | PTE_U | (uint32_t)pa; + *pte = PTE_P | PTE_W | PTE_U | (uintptr_t)pa; } }