This source file includes following definitions.
- kvmmake
- kvmmap
- kvminit
- kvminithart
- walk
- walkaddr
- mappages
- uvmcreate
- uvmunmap
- uvmalloc
- uvmdealloc
- freewalk
- uvmfree
- uvmcopy
- uvmclear
- copyout
- copyin
- copyinstr
- vmfault
- ismapped
1 #include "param.h"
2 #include "types.h"
3 #include "memlayout.h"
4 #include "elf.h"
5 #include "riscv.h"
6 #include "defs.h"
7 #include "spinlock.h"
8 #include "proc.h"
9 #include "fs.h"
10
11
12
13
14 pagetable_t kernel_pagetable;
15
16 extern char etext[];
17
18 extern char trampoline[];
19
20
21 pagetable_t
22 kvmmake(void)
23 {
24 pagetable_t kpgtbl;
25
26 kpgtbl = (pagetable_t) kalloc();
27 memset(kpgtbl, 0, PGSIZE);
28
29
30 kvmmap(kpgtbl, UART0, UART0, PGSIZE, PTE_R | PTE_W);
31
32
33 kvmmap(kpgtbl, VIRTIO0, VIRTIO0, PGSIZE, PTE_R | PTE_W);
34
35
36 kvmmap(kpgtbl, PLIC, PLIC, 0x4000000, PTE_R | PTE_W);
37
38
39 kvmmap(kpgtbl, KERNBASE, KERNBASE, (uint64)etext-KERNBASE, PTE_R | PTE_X);
40
41
42 kvmmap(kpgtbl, (uint64)etext, (uint64)etext, PHYSTOP-(uint64)etext, PTE_R | PTE_W);
43
44
45
46 kvmmap(kpgtbl, TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X);
47
48
49 proc_mapstacks(kpgtbl);
50
51 return kpgtbl;
52 }
53
54
55
56
57 void
58 kvmmap(pagetable_t kpgtbl, uint64 va, uint64 pa, uint64 sz, int perm)
59 {
60 if(mappages(kpgtbl, va, sz, pa, perm) != 0)
61 panic("kvmmap");
62 }
63
64
65 void
66 kvminit(void)
67 {
68 kernel_pagetable = kvmmake();
69 }
70
71
72
73 void
74 kvminithart()
75 {
76
77 sfence_vma();
78
79 w_satp(MAKE_SATP(kernel_pagetable));
80
81
82 sfence_vma();
83 }
84
85
86
87
88
89
90
91
92
93
94
95
96
97 pte_t *
98 walk(pagetable_t pagetable, uint64 va, int alloc)
99 {
100 if(va >= MAXVA)
101 panic("walk");
102
103 for(int level = 2; level > 0; level--) {
104 pte_t *pte = &pagetable[PX(level, va)];
105 if(*pte & PTE_V) {
106 pagetable = (pagetable_t)PTE2PA(*pte);
107 } else {
108 if(!alloc || (pagetable = (pde_t*)kalloc()) == 0)
109 return 0;
110 memset(pagetable, 0, PGSIZE);
111 *pte = PA2PTE(pagetable) | PTE_V;
112 }
113 }
114 return &pagetable[PX(0, va)];
115 }
116
117
118
119
120 uint64
121 walkaddr(pagetable_t pagetable, uint64 va)
122 {
123 pte_t *pte;
124 uint64 pa;
125
126 if(va >= MAXVA)
127 return 0;
128
129 pte = walk(pagetable, va, 0);
130 if(pte == 0)
131 return 0;
132 if((*pte & PTE_V) == 0)
133 return 0;
134 if((*pte & PTE_U) == 0)
135 return 0;
136 pa = PTE2PA(*pte);
137 return pa;
138 }
139
140
141
142
143
144
145 int
146 mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
147 {
148 uint64 a, last;
149 pte_t *pte;
150
151 if((va % PGSIZE) != 0)
152 panic("mappages: va not aligned");
153
154 if((size % PGSIZE) != 0)
155 panic("mappages: size not aligned");
156
157 if(size == 0)
158 panic("mappages: size");
159
160 a = va;
161 last = va + size - PGSIZE;
162 for(;;){
163 if((pte = walk(pagetable, a, 1)) == 0)
164 return -1;
165 if(*pte & PTE_V)
166 panic("mappages: remap");
167 *pte = PA2PTE(pa) | perm | PTE_V;
168 if(a == last)
169 break;
170 a += PGSIZE;
171 pa += PGSIZE;
172 }
173 return 0;
174 }
175
176
177
178 pagetable_t
179 uvmcreate()
180 {
181 pagetable_t pagetable;
182 pagetable = (pagetable_t) kalloc();
183 if(pagetable == 0)
184 return 0;
185 memset(pagetable, 0, PGSIZE);
186 return pagetable;
187 }
188
189
190
191
192 void
193 uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
194 {
195 uint64 a;
196 pte_t *pte;
197
198 if((va % PGSIZE) != 0)
199 panic("uvmunmap: not aligned");
200
201 for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
202 if((pte = walk(pagetable, a, 0)) == 0)
203 continue;
204 if((*pte & PTE_V) == 0)
205 continue;
206 if(do_free){
207 uint64 pa = PTE2PA(*pte);
208 kfree((void*)pa);
209 }
210 *pte = 0;
211 }
212 }
213
214
215
216 uint64
217 uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz, int xperm)
218 {
219 char *mem;
220 uint64 a;
221
222 if(newsz < oldsz)
223 return oldsz;
224
225 oldsz = PGROUNDUP(oldsz);
226 for(a = oldsz; a < newsz; a += PGSIZE){
227 mem = kalloc();
228 if(mem == 0){
229 uvmdealloc(pagetable, a, oldsz);
230 return 0;
231 }
232 memset(mem, 0, PGSIZE);
233 if(mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_R|PTE_U|xperm) != 0){
234 kfree(mem);
235 uvmdealloc(pagetable, a, oldsz);
236 return 0;
237 }
238 }
239 return newsz;
240 }
241
242
243
244
245
246 uint64
247 uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz)
248 {
249 if(newsz >= oldsz)
250 return oldsz;
251
252 if(PGROUNDUP(newsz) < PGROUNDUP(oldsz)){
253 int npages = (PGROUNDUP(oldsz) - PGROUNDUP(newsz)) / PGSIZE;
254 uvmunmap(pagetable, PGROUNDUP(newsz), npages, 1);
255 }
256
257 return newsz;
258 }
259
260
261
262 void
263 freewalk(pagetable_t pagetable)
264 {
265
266 for(int i = 0; i < 512; i++){
267 pte_t pte = pagetable[i];
268 if((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0){
269
270 uint64 child = PTE2PA(pte);
271 freewalk((pagetable_t)child);
272 pagetable[i] = 0;
273 } else if(pte & PTE_V){
274 panic("freewalk: leaf");
275 }
276 }
277 kfree((void*)pagetable);
278 }
279
280
281
282 void
283 uvmfree(pagetable_t pagetable, uint64 sz)
284 {
285 if(sz > 0)
286 uvmunmap(pagetable, 0, PGROUNDUP(sz)/PGSIZE, 1);
287 freewalk(pagetable);
288 }
289
290
291
292
293
294
295
296 int
297 uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
298 {
299 pte_t *pte;
300 uint64 pa, i;
301 uint flags;
302 char *mem;
303
304 for(i = 0; i < sz; i += PGSIZE){
305 if((pte = walk(old, i, 0)) == 0)
306 continue;
307 if((*pte & PTE_V) == 0)
308 continue;
309 pa = PTE2PA(*pte);
310 flags = PTE_FLAGS(*pte);
311 if((mem = kalloc()) == 0)
312 goto err;
313 memmove(mem, (char*)pa, PGSIZE);
314 if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){
315 kfree(mem);
316 goto err;
317 }
318 }
319 return 0;
320
321 err:
322 uvmunmap(new, 0, i / PGSIZE, 1);
323 return -1;
324 }
325
326
327
328 void
329 uvmclear(pagetable_t pagetable, uint64 va)
330 {
331 pte_t *pte;
332
333 pte = walk(pagetable, va, 0);
334 if(pte == 0)
335 panic("uvmclear");
336 *pte &= ~PTE_U;
337 }
338
339
340
341
342 int
343 copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
344 {
345 uint64 n, va0, pa0;
346 pte_t *pte;
347
348 while(len > 0){
349 va0 = PGROUNDDOWN(dstva);
350 if(va0 >= MAXVA)
351 return -1;
352
353 pa0 = walkaddr(pagetable, va0);
354 if(pa0 == 0) {
355 if((pa0 = vmfault(pagetable, va0, 0)) == 0) {
356 return -1;
357 }
358 }
359
360 pte = walk(pagetable, va0, 0);
361
362 if((*pte & PTE_W) == 0)
363 return -1;
364
365 n = PGSIZE - (dstva - va0);
366 if(n > len)
367 n = len;
368 memmove((void *)(pa0 + (dstva - va0)), src, n);
369
370 len -= n;
371 src += n;
372 dstva = va0 + PGSIZE;
373 }
374 return 0;
375 }
376
377
378
379
380 int
381 copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len)
382 {
383 uint64 n, va0, pa0;
384
385 while(len > 0){
386 va0 = PGROUNDDOWN(srcva);
387 pa0 = walkaddr(pagetable, va0);
388 if(pa0 == 0) {
389 if((pa0 = vmfault(pagetable, va0, 0)) == 0) {
390 return -1;
391 }
392 }
393 n = PGSIZE - (srcva - va0);
394 if(n > len)
395 n = len;
396 memmove(dst, (void *)(pa0 + (srcva - va0)), n);
397
398 len -= n;
399 dst += n;
400 srcva = va0 + PGSIZE;
401 }
402 return 0;
403 }
404
405
406
407
408
409 int
410 copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
411 {
412 uint64 n, va0, pa0;
413 int got_null = 0;
414
415 while(got_null == 0 && max > 0){
416 va0 = PGROUNDDOWN(srcva);
417 pa0 = walkaddr(pagetable, va0);
418 if(pa0 == 0)
419 return -1;
420 n = PGSIZE - (srcva - va0);
421 if(n > max)
422 n = max;
423
424 char *p = (char *) (pa0 + (srcva - va0));
425 while(n > 0){
426 if(*p == '\0'){
427 *dst = '\0';
428 got_null = 1;
429 break;
430 } else {
431 *dst = *p;
432 }
433 --n;
434 --max;
435 p++;
436 dst++;
437 }
438
439 srcva = va0 + PGSIZE;
440 }
441 if(got_null){
442 return 0;
443 } else {
444 return -1;
445 }
446 }
447
448
449
450
451
452 uint64
453 vmfault(pagetable_t pagetable, uint64 va, int read)
454 {
455 uint64 mem;
456 struct proc *p = myproc();
457
458 if (va >= p->sz)
459 return 0;
460 va = PGROUNDDOWN(va);
461 if(ismapped(pagetable, va)) {
462 return 0;
463 }
464 mem = (uint64) kalloc();
465 if(mem == 0)
466 return 0;
467 memset((void *) mem, 0, PGSIZE);
468 if (mappages(p->pagetable, va, PGSIZE, mem, PTE_W|PTE_U|PTE_R) != 0) {
469 kfree((void *)mem);
470 return 0;
471 }
472 return mem;
473 }
474
475 int
476 ismapped(pagetable_t pagetable, uint64 va)
477 {
478 pte_t *pte = walk(pagetable, va, 0);
479 if (pte == 0) {
480 return 0;
481 }
482 if (*pte & PTE_V){
483 return 1;
484 }
485 return 0;
486 }