1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
|
@@ -92,6 +92,7 @@ int fork(void); int growproc(int); pagetable_t proc_pagetable(struct proc *); void proc_freepagetable(pagetable_t, uint64); +// void proc_freekpagetable(pagetable_t, uint64, uint64); int kill(int); struct cpu* mycpu(void); struct cpu* getmycpu(void); @@ -161,7 +162,7 @@ int uartgetc(void); void kvminit(void); void kvminithart(void); uint64 kvmpa(uint64); -void kvmmap(uint64, uint64, uint64, int); +void kvmmap(pagetable_t, uint64, uint64, uint64, int); int mappages(pagetable_t, uint64, uint64, uint64, int); pagetable_t uvmcreate(void); void uvminit(pagetable_t, uchar *, uint); @@ -179,6 +180,8 @@ int copyout(pagetable_t, uint64, char *, uint64); int copyin(pagetable_t, char *, uint64, uint64); int copyinstr(pagetable_t, char *, uint64, uint64); void vmprint(pagetable_t); +pagetable_t kvmmake(void); +void kvmfree(pagetable_t); // plic.c void plicinit(void);
@@ -34,14 +34,16 @@ procinit(void) // Allocate a page for the process's kernel stack. // Map it high in memory, followed by an invalid // guard page. + /* char *pa = kalloc(); if(pa == 0) panic("kalloc"); uint64 va = KSTACK((int) (p - proc)); kvmmap(va, (uint64)pa, PGSIZE, PTE_R | PTE_W); p->kstack = va; + */ } - kvminithart(); + // kvminithart(); } // Must be called with interrupts disabled, @@ -112,6 +114,24 @@ found: release(&p->lock); return 0; } + + // A kernel page table + if((p->kpagetable = kvmmake()) == 0){ + freeproc(p); + release(&p->lock); + return 0; + } + + // Allocate a page for the process's kernel stack. + // Map it high in memory, followed by an invalid + // guard page. + char *pa = kalloc(); + if(pa == 0) + panic("kalloc"); + uint64 va = KSTACK((int)(p - proc)); + // uint64 va = KSTACK(0); + kvmmap(p->kpagetable, va, (uint64)pa, PGSIZE, PTE_R | PTE_W); + p->kstack = va; // An empty user page table. p->pagetable = proc_pagetable(p); @@ -139,6 +159,12 @@ freeproc(struct proc *p) if(p->trapframe) kfree((void*)p->trapframe); p->trapframe = 0; + if(p->kstack) + uvmunmap(p->kpagetable, p->kstack, 1, 1); + p->kstack = 0; + if(p->kpagetable) + kvmfree(p->kpagetable); + p->kpagetable = 0; if(p->pagetable) proc_freepagetable(p->pagetable, p->sz); p->pagetable = 0; @@ -195,6 +221,14 @@ proc_freepagetable(pagetable_t pagetable, uint64 sz) uvmfree(pagetable, sz); } +/* +void +proc_freekpagetable(pagetable_t kpgtbl, uint64 kstack, uint64 sz) { + uvmunmap(kpgtbl, kstack, 1, 1); + kvmfree(kpgtbl); +} +*/ + // a user program that calls exec("/init") // od -t xC initcode uchar initcode[] = { @@ -473,11 +507,18 @@ scheduler(void) // before jumping back to us. p->state = RUNNING; c->proc = p; + + w_satp(MAKE_SATP(p->kpagetable)); + sfence_vma(); + swtch(&c->context, &p->context); // Process is done running for now. // It should have changed its p->state before coming back. c->proc = 0; + + // use kernel_pagetable when no process is running. + kvminithart(); found = 1; } @@ -486,7 +527,11 @@ scheduler(void) #if !defined (LAB_FS) if(found == 0) { intr_on(); - asm volatile("wfi"); + + // use kernel_pagetable when no process is running. + // kvminithart(); + + asm volatile("wfi"); } #else ;
@@ -98,6 +98,7 @@ struct proc { uint64 kstack; // Virtual address of kernel stack uint64 sz; // Size of process memory (bytes) pagetable_t pagetable; // User page table + pagetable_t kpagetable; // Kernel page table struct trapframe *trapframe; // data page for trampoline.S struct context context; // swtch() here to run process struct file *ofile[NOFILE]; // Open files
@@ -5,6 +5,8 @@ #include "riscv.h" #include "defs.h" #include "fs.h" +#include "spinlock.h" +#include "proc.h" /* * the kernel's page table. @@ -16,35 +18,48 @@ extern char etext[]; // kernel.ld sets this to end of kernel code. extern char trampoline[]; // trampoline.S /* - * create a direct-map page table for the kernel. + * make a direct-map page table for the kernel. */ -void -kvminit() +pagetable_t +kvmmake() { - kernel_pagetable = (pagetable_t) kalloc(); - memset(kernel_pagetable, 0, PGSIZE); + pagetable_t kpagetable = (pagetable_t) kalloc(); + memset(kpagetable, 0, PGSIZE); // uart registers - kvmmap(UART0, UART0, PGSIZE, PTE_R | PTE_W); + kvmmap(kpagetable, UART0, UART0, PGSIZE, PTE_R | PTE_W); // virtio mmio disk interface - kvmmap(VIRTIO0, VIRTIO0, PGSIZE, PTE_R | PTE_W); + kvmmap(kpagetable, VIRTIO0, VIRTIO0, PGSIZE, PTE_R | PTE_W); // CLINT - kvmmap(CLINT, CLINT, 0x10000, PTE_R | PTE_W); + kvmmap(kpagetable, CLINT, CLINT, 0x10000, PTE_R | PTE_W); // PLIC - kvmmap(PLIC, PLIC, 0x400000, PTE_R | PTE_W); + kvmmap(kpagetable, PLIC, PLIC, 0x400000, PTE_R | PTE_W); // map kernel text executable and read-only. - kvmmap(KERNBASE, KERNBASE, (uint64)etext-KERNBASE, PTE_R | PTE_X); + kvmmap(kpagetable, KERNBASE, KERNBASE, (uint64)etext-KERNBASE, PTE_R | PTE_X); // map kernel data and the physical RAM we'll make use of. - kvmmap((uint64)etext, (uint64)etext, PHYSTOP-(uint64)etext, PTE_R | PTE_W); + kvmmap(kpagetable, (uint64)etext, (uint64)etext, PHYSTOP-(uint64)etext, PTE_R | PTE_W); // map the trampoline for trap entry/exit to // the highest virtual address in the kernel. - kvmmap(TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X); + kvmmap(kpagetable, TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X); + + return kpagetable; +} + +/* + * create a direct-map page table for the kernel. + */ +void +kvminit() +{ + kernel_pagetable = kvmmake(); + // CLINT + // kvmmap(kernel_pagetable, CLINT, CLINT, 0x10000, PTE_R | PTE_W); } // Switch h/w page table register to the kernel's page table, @@ -115,9 +130,9 @@ walkaddr(pagetable_t pagetable, uint64 va) // only used when booting. // does not flush TLB or enable paging. void -kvmmap(uint64 va, uint64 pa, uint64 sz, int perm) +kvmmap(pagetable_t kpagetable, uint64 va, uint64 pa, uint64 sz, int perm) { - if(mappages(kernel_pagetable, va, sz, pa, perm) != 0) + if(mappages(kpagetable, va, sz, pa, perm) != 0) panic("kvmmap"); } @@ -132,7 +147,7 @@ kvmpa(uint64 va) pte_t *pte; uint64 pa; - pte = walk(kernel_pagetable, va, 0); + pte = walk(myproc()->kpagetable, va, 0); if(pte == 0) panic("kvmpa"); if((*pte & PTE_V) == 0) @@ -194,6 +209,35 @@ uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free) } } +void +kvmfree(pagetable_t kpgtbl) { + /* + uvmunmap(kpgtbl, UART0, 1, 0); + uvmunmap(kpgtbl, VIRTIO0, 1, 0); + // uvmunmap(kpgtbl, CLINT, 0x10000 / PGSIZE, 0); + uvmunmap(kpgtbl, PLIC, 0x400000 / PGSIZE, 0); + uvmunmap(kpgtbl, KERNBASE, ((uint64)etext-KERNBASE) / PGSIZE, 0); + uvmunmap(kpgtbl, (uint64)etext, (PHYSTOP-(uint64)etext) / PGSIZE, 0); + uvmunmap(kpgtbl, TRAMPOLINE, 1, 0); + // uvmunmap(kpgtbl, 0, PGROUNDUP(sz) / PGSIZE, 0); + */ + // there are 2^9 = 512 PTEs in a page table. + for(int i = 0; i < 512; i++){ + pte_t pte = kpgtbl[i]; + if (pte & PTE_V){ + kpgtbl[i] = 0; + if ((pte & (PTE_R|PTE_W|PTE_X)) == 0) { + // this PTE points to a lower-level page table. + uint64 child = PTE2PA(pte); + kvmfree((pagetable_t)child); + } + } else if(pte & PTE_V){ + panic("freewalk: leaf"); + } + } + kfree((void*)kpgtbl); +} + // create an empty user page table. // returns 0 if out of memory. pagetable_t
|