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
|
#include "kernel/mm.h"
#include "kernel/pmm.h"
#include "drivers/uart.h"
#include "common/types.h"
extern "C" char text_start[];
extern "C" char text_end[];
extern "C" char rodata_start[];
extern "C" char rodata_end[];
extern "C" char data_start[];
extern "C" char kernel_end[];
namespace VM
{
pagetable_t kernel_pagetable;
#define PX(level, va) ((((uint64)va) >> (12 + 9 * (level))) & 0x1FF)
#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)
#define PTE2PA(pte) (((pte) >> 10) << 12)
pte_t *walk(pagetable_t pagetable, uint64 va, int alloc)
{
for (int level = 2; level > 0; level--)
{
pte_t *pte = &pagetable[PX(level, va)];
if (*pte & PTE_V)
{
pagetable = (pagetable_t)PTE2PA(*pte);
}
else
{
if (!alloc)
return 0;
pagetable = (pagetable_t)PMM::alloc_page();
if (!pagetable)
return 0;
*pte = PA2PTE(pagetable) | PTE_V;
}
}
return &pagetable[PX(0, va)];
}
int mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
{
uint64 a, last;
pte_t *pte;
a = (va / PGSIZE) * PGSIZE;
last = ((va + size - 1) / PGSIZE) * PGSIZE;
for(;;)
{
if((pte = walk(pagetable, a, 1)) == 0)
return -1;
if (*pte & PTE_V)
{
Drivers::uart_puts("Remap error\n");
return -1;
}
*pte = PA2PTE(pa) | perm | PTE_V;
if (a == last)
break;
a += PGSIZE;
pa += PGSIZE;
}
return 0;
}
void kvminit()
{
kernel_pagetable = (pagetable_t)PMM::alloc_page();
mappages(kernel_pagetable, 0x10000000, 0x10000, 0x10000000, PTE_R | PTE_W);
mappages(kernel_pagetable, (uint64)text_start, (uint64)text_end - (uint64)text_start,
(uint64)text_start, PTE_R | PTE_X);
mappages(kernel_pagetable, (uint64)data_start, PHYSTOP - (uint64)data_start,
(uint64)data_start, PTE_R | PTE_W);
mappages(kernel_pagetable, (uint64)rodata_start, (uint64)rodata_end - (uint64)rodata_start,
(uint64)rodata_start, PTE_R);
}
void kvminithart()
{
asm volatile("sfence.vma zero, zero");
uint64 satp_val = MAKE_SATP(kernel_pagetable);
asm volatile("csrw satp, %0" : : "r"(satp_val));
asm volatile("sfence.vma zero, zero");
}
}
|