-
Notifications
You must be signed in to change notification settings - Fork 2
/
k-vmiter.cc
109 lines (99 loc) · 2.73 KB
/
k-vmiter.cc
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
#include "k-vmiter.hh"
void vmiter::down() {
while (level_ > 0 && (*pep_ & (PTE_P | PTE_PS)) == PTE_P) {
perm_ &= *pep_;
--level_;
uintptr_t pa = *pep_ & PTE_PAMASK;
x86_64_pagetable* pt = pa2ka<x86_64_pagetable*>(pa);
pep_ = &pt->entry[pageindex(va_, level_)];
}
}
void vmiter::real_find(uintptr_t va) {
if ((va_ ^ va) & ~pageoffmask(level_ + 1)) {
level_ = 3;
pep_ = &pt_->entry[pageindex(va, level_)];
perm_ = initial_perm;
} else {
int curidx = (reinterpret_cast<uintptr_t>(pep_) & PAGEOFFMASK) >> 3;
pep_ += pageindex(va, level_) - curidx;
}
va_ = va;
down();
}
void vmiter::next() {
int level = 0;
if (level_ > 0 && !perm()) {
level = level_;
}
real_find((va_ | pageoffmask(level)) + 1);
}
int vmiter::map(uintptr_t pa, int perm) {
assert(!(va_ & PAGEOFFMASK));
if (perm & PTE_P) {
assert((pa & PTE_PAMASK) == pa);
} else {
assert(!(pa & PTE_P));
}
assert(!(perm & ~perm_ & (PTE_P | PTE_W | PTE_U)));
while (level_ > 0 && perm) {
assert(!(*pep_ & PTE_P));
x86_64_pagetable* pt = reinterpret_cast<x86_64_pagetable*>
(kallocpage());
if (!pt) {
return -1;
}
memset(pt, 0, PAGESIZE);
*pep_ = ka2pa(pt) | PTE_P | PTE_W | PTE_U;
down();
}
if (level_ == 0) {
*pep_ = pa | perm;
}
return 0;
}
bool vmiter::check_range(size_t sz, uint64_t perms) {
uintptr_t start = va();
while (va() < start + sz) {
if (!perm(perms))
return false;
step();
}
return true;
}
void ptiter::go(uintptr_t va) {
level_ = 3;
pep_ = &pt_->entry[pageindex(va, level_)];
va_ = va;
down(false);
}
void ptiter::down(bool skip) {
int stop_level = 1;
while (1) {
if ((*pep_ & (PTE_P | PTE_PS)) == PTE_P && !skip) {
if (level_ == stop_level) {
break;
} else {
--level_;
uintptr_t pa = *pep_ & PTE_PAMASK;
x86_64_pagetable* pt = pa2ka<x86_64_pagetable*>(pa);
pep_ = &pt->entry[pageindex(va_, level_)];
}
} else {
uintptr_t va = (va_ | pageoffmask(level_)) + 1;
if ((va ^ va_) & ~pageoffmask(level_ + 1)) {
// up one level
if (level_ == 3) {
va_ = VA_NONCANONMAX + 1;
return;
}
stop_level = level_ + 1;
level_ = 3;
pep_ = &pt_->entry[pageindex(va_, level_)];
} else {
++pep_;
va_ = va;
}
skip = false;
}
}
}