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, 0x400000, 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 int
143 mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
144 {
145 uint64 a, last;
146 pte_t *pte;
147
148 if(size == 0)
149 panic("mappages: size");
150
151 a = PGROUNDDOWN(va);
152 last = PGROUNDDOWN(va + size - 1);
153 for(;;){
154 if((pte = walk(pagetable, a, 1)) == 0)
155 return -1;
156 if(*pte & PTE_V)
157 panic("mappages: remap");
158 *pte = PA2PTE(pa) | perm | PTE_V;
159 if(a == last)
160 break;
161 a += PGSIZE;
162 pa += PGSIZE;
163 }
164 return 0;
165 }
166
167
168
169
170 void
171 uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
172 {
173 uint64 a;
174 pte_t *pte;
175
176 if((va % PGSIZE) != 0)
177 panic("uvmunmap: not aligned");
178
179 for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
180 if((pte = walk(pagetable, a, 0)) == 0)
181 panic("uvmunmap: walk");
182 if((*pte & PTE_V) == 0)
183 panic("uvmunmap: not mapped");
184 if(PTE_FLAGS(*pte) == PTE_V)
185 panic("uvmunmap: not a leaf");
186 if(do_free){
187 uint64 pa = PTE2PA(*pte);
188 kfree((void*)pa);
189 }
190 *pte = 0;
191 }
192 }
193
194
195
196 pagetable_t
197 uvmcreate()
198 {
199 pagetable_t pagetable;
200 pagetable = (pagetable_t) kalloc();
201 if(pagetable == 0)
202 return 0;
203 memset(pagetable, 0, PGSIZE);
204 return pagetable;
205 }
206
207
208
209
210 void
211 uvmfirst(pagetable_t pagetable, uchar *src, uint sz)
212 {
213 char *mem;
214
215 if(sz >= PGSIZE)
216 panic("uvmfirst: more than a page");
217 mem = kalloc();
218 memset(mem, 0, PGSIZE);
219 mappages(pagetable, 0, PGSIZE, (uint64)mem, PTE_W|PTE_R|PTE_X|PTE_U);
220 memmove(mem, src, sz);
221 }
222
223
224
225 uint64
226 uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz, int xperm)
227 {
228 char *mem;
229 uint64 a;
230
231 if(newsz < oldsz)
232 return oldsz;
233
234 oldsz = PGROUNDUP(oldsz);
235 for(a = oldsz; a < newsz; a += PGSIZE){
236 mem = kalloc();
237 if(mem == 0){
238 uvmdealloc(pagetable, a, oldsz);
239 return 0;
240 }
241 memset(mem, 0, PGSIZE);
242 if(mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_R|PTE_U|xperm) != 0){
243 kfree(mem);
244 uvmdealloc(pagetable, a, oldsz);
245 return 0;
246 }
247 }
248 return newsz;
249 }
250
251
252
253
254
255 uint64
256 uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz)
257 {
258 if(newsz >= oldsz)
259 return oldsz;
260
261 if(PGROUNDUP(newsz) < PGROUNDUP(oldsz)){
262 int npages = (PGROUNDUP(oldsz) - PGROUNDUP(newsz)) / PGSIZE;
263 uvmunmap(pagetable, PGROUNDUP(newsz), npages, 1);
264 }
265
266 return newsz;
267 }
268
269
270
271 void
272 freewalk(pagetable_t pagetable)
273 {
274
275 for(int i = 0; i < 512; i++){
276 pte_t pte = pagetable[i];
277 if((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0){
278
279 uint64 child = PTE2PA(pte);
280 freewalk((pagetable_t)child);
281 pagetable[i] = 0;
282 } else if(pte & PTE_V){
283 panic("freewalk: leaf");
284 }
285 }
286 kfree((void*)pagetable);
287 }
288
289
290
291 void
292 uvmfree(pagetable_t pagetable, uint64 sz)
293 {
294 if(sz > 0)
295 uvmunmap(pagetable, 0, PGROUNDUP(sz)/PGSIZE, 1);
296 freewalk(pagetable);
297 }
298
299
300
301
302
303
304
305 int
306 uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
307 {
308 pte_t *pte;
309 uint64 pa, i;
310 uint flags;
311 char *mem;
312
313 for(i = 0; i < sz; i += PGSIZE){
314 if((pte = walk(old, i, 0)) == 0)
315 panic("uvmcopy: pte should exist");
316 if((*pte & PTE_V) == 0)
317 panic("uvmcopy: page not present");
318 pa = PTE2PA(*pte);
319 flags = PTE_FLAGS(*pte);
320 if((mem = kalloc()) == 0)
321 goto err;
322 memmove(mem, (char*)pa, PGSIZE);
323 if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){
324 kfree(mem);
325 goto err;
326 }
327 }
328 return 0;
329
330 err:
331 uvmunmap(new, 0, i / PGSIZE, 1);
332 return -1;
333 }
334
335
336
337 void
338 uvmclear(pagetable_t pagetable, uint64 va)
339 {
340 pte_t *pte;
341
342 pte = walk(pagetable, va, 0);
343 if(pte == 0)
344 panic("uvmclear");
345 *pte &= ~PTE_U;
346 }
347
348
349
350
351 int
352 copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
353 {
354 uint64 n, va0, pa0;
355
356 while(len > 0){
357 va0 = PGROUNDDOWN(dstva);
358 pa0 = walkaddr(pagetable, va0);
359 if(pa0 == 0)
360 return -1;
361 n = PGSIZE - (dstva - va0);
362 if(n > len)
363 n = len;
364 memmove((void *)(pa0 + (dstva - va0)), src, n);
365
366 len -= n;
367 src += n;
368 dstva = va0 + PGSIZE;
369 }
370 return 0;
371 }
372
373
374
375
376 int
377 copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len)
378 {
379 uint64 n, va0, pa0;
380
381 while(len > 0){
382 va0 = PGROUNDDOWN(srcva);
383 pa0 = walkaddr(pagetable, va0);
384 if(pa0 == 0)
385 return -1;
386 n = PGSIZE - (srcva - va0);
387 if(n > len)
388 n = len;
389 memmove(dst, (void *)(pa0 + (srcva - va0)), n);
390
391 len -= n;
392 dst += n;
393 srcva = va0 + PGSIZE;
394 }
395 return 0;
396 }
397
398
399
400
401
402 int
403 copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
404 {
405 uint64 n, va0, pa0;
406 int got_null = 0;
407
408 while(got_null == 0 && max > 0){
409 va0 = PGROUNDDOWN(srcva);
410 pa0 = walkaddr(pagetable, va0);
411 if(pa0 == 0)
412 return -1;
413 n = PGSIZE - (srcva - va0);
414 if(n > max)
415 n = max;
416
417 char *p = (char *) (pa0 + (srcva - va0));
418 while(n > 0){
419 if(*p == '\0'){
420 *dst = '\0';
421 got_null = 1;
422 break;
423 } else {
424 *dst = *p;
425 }
426 --n;
427 --max;
428 p++;
429 dst++;
430 }
431
432 srcva = va0 + PGSIZE;
433 }
434 if(got_null){
435 return 0;
436 } else {
437 return -1;
438 }
439 }