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