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