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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
#include <apos/string.h>
#include <apos/pmem.h>
#include <apos/vmem.h>
#include <apos/mem.h>
#include <apos/debug.h>
#include <pages.h>
#include <vmem.h>
#define pte_ppn(pte) (((pm_t)(pte)) >> 10)
#define pte_flags(pte) (((pm_t)(pte)) & 0xff)
#define to_pte(p, f) ((pm_to_pnum((pm_t)__pa(p)) << 10) | (f))
#define pte_addr(pte) __va(pnum_to_paddr(pte_ppn(pte)))
#define pte_paddr(pte) (pnum_to_paddr(pte_ppn(pte)))
#define vm_to_index(a, o) (pm_to_index(a, o))
#define is_active(pte) (pte_flags(pte) & VM_V)
#define is_leaf(pte) (is_active(pte) && (pte_flags(pte) & ~VM_V))
#define is_branch(pte) (is_active(pte) && !(pte_flags(pte) & ~VM_V))
static pm_t *__find_vmem(struct vm_branch_t *b, vm_t v, enum mm_order_t *o)
{
enum mm_order_t top = __mm_max_order;
if(o)
*o = MM_O0;
do {
size_t idx = vm_to_index(v, top);
pm_t pte = (pm_t)b->leaf[idx];
if(!pte)
return 0;
if(is_leaf(pte)){
if(o)
*o = top;
return (pm_t *)&b->leaf[idx];
}
b = (struct vm_branch_t *)pte_addr(pte);
} while (top--);
return 0;
}
int mod_vmem(struct vm_branch_t *branch, vm_t vaddr, pm_t paddr, uint8_t flags)
{
pm_t *pte = __find_vmem(branch, vaddr, 0);
if(pte){
*pte = to_pte(paddr, flags);
return 0;
}
return -1;
}
/* huh, should probably add status flags etc. to all my API functions. Damn, I'm
* lazy. */
int stat_vmem(struct vm_branch_t *branch, vm_t vaddr, pm_t *paddr,
enum mm_order_t *order, uint8_t *flags)
{
pm_t *pte = __find_vmem(branch, vaddr, order);
if(pte){
if(paddr)
*paddr = (pm_t)pte_addr(*pte);
if(flags)
*flags = pte_flags(*pte);
return 0;
}
return -1;
}
static struct vm_branch_t *__create_leaf()
{
pm_t new_leaf = alloc_page(MM_KPAGE, 0);
memset((void *)new_leaf, 0, sizeof(struct vm_branch_t));
return (struct vm_branch_t *)to_pte(new_leaf, VM_V);
}
static void __destroy_branch(struct vm_branch_t *b)
{
if(!b)
return;
for(size_t i = 0; i < BASE_PAGE_SIZE / sizeof(pm_t); ++i){
if(is_branch(b->leaf[i]))
__destroy_branch((struct vm_branch_t *)pte_addr(b->leaf[i]));
free_page(MM_KPAGE, (pm_t)pte_addr(b->leaf[i]));
}
}
void map_vmem(struct vm_branch_t *branch,
pm_t paddr, vm_t vaddr, uint8_t flags, enum mm_order_t order)
{
enum mm_order_t top = __mm_max_order;
while (top != order) {
size_t idx = vm_to_index(vaddr, top);
if (!branch->leaf[idx])
branch->leaf[idx] = __create_leaf();
branch = (struct vm_branch_t *)pte_addr(branch->leaf[idx]);
top--;
}
size_t idx = vm_to_index(vaddr, top);
if (is_branch(branch->leaf[idx])) /* something has gone terribly wrong */
__destroy_branch(branch->leaf[idx]);
branch->leaf[idx] = (struct vm_branch_t *)to_pte(paddr, flags);
}
void unmap_vmem(struct vm_branch_t *branch, vm_t vaddr)
{
pm_t *pte = __find_vmem(branch, vaddr, 0);
if(pte)
*pte = 0;
}
void flush_tlb(id_t cpu_id)
{
__asm__("sfence.vma %0\n" :: "rk" (cpu_id) : "memory");
}
void flush_tlb_all()
{
__asm__("sfence.vma\n" ::: "memory");
}
|