-
Notifications
You must be signed in to change notification settings - Fork 0
/
pagemap.c
103 lines (89 loc) · 2.59 KB
/
pagemap.c
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
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include "pagemap.h"
/* Keep track of all mapped pages so that we can easily get a list of
all of them --- but also efficiently add and remove from the list. */
typedef struct mpage {
void *addr;
struct mpage *prev, *next;
} mpage;
static mpage *all_mapped_pages;
static mpage ***page_maps1;
#define PAGEMAP64_LEVEL1_SIZE (1 << 16)
#define PAGEMAP64_LEVEL2_SIZE (1 << 16)
#define PAGEMAP64_LEVEL3_SIZE (1 << (32 - LOG_APAGE_SIZE))
#define PAGEMAP64_LEVEL1_BITS(p) (((uintptr_t)(p)) >> 48)
#define PAGEMAP64_LEVEL2_BITS(p) ((((uintptr_t)(p)) >> 32) & ((PAGEMAP64_LEVEL2_SIZE) - 1))
#define PAGEMAP64_LEVEL3_BITS(p) ((((uintptr_t)(p)) >> LOG_APAGE_SIZE) & ((PAGEMAP64_LEVEL3_SIZE) - 1))
void pagemap_modify(void *p, int mapped) {
uintptr_t pos;
mpage **page_maps2;
mpage *page_maps3;
mpage *page;
if (!page_maps1) {
page_maps1 = calloc(PAGEMAP64_LEVEL1_SIZE, sizeof(mpage **));
}
pos = PAGEMAP64_LEVEL1_BITS(p);
page_maps2 = page_maps1[pos];
if (!page_maps2) {
page_maps2 = calloc(PAGEMAP64_LEVEL2_SIZE, sizeof(mpage *));
page_maps1[pos] = page_maps2;
}
pos = PAGEMAP64_LEVEL2_BITS(p);
page_maps3 = page_maps2[pos];
if (!page_maps3) {
page_maps3 = calloc(PAGEMAP64_LEVEL3_SIZE, sizeof(mpage));
page_maps2[pos] = page_maps3;
}
page = &page_maps3[PAGEMAP64_LEVEL3_BITS(p)];
if (mapped) {
if (page->addr) {
fprintf(stderr, "internal error: page is already mapped\n");
abort();
}
if (page == all_mapped_pages)
abort();
page->addr = p;
page->prev = NULL;
page->next = all_mapped_pages;
if (all_mapped_pages)
all_mapped_pages->prev = page;
all_mapped_pages = page;
} else {
if (!page->addr) {
fprintf(stderr, "internal error: not currently mapped\n");
abort();
}
page->addr = NULL;
if (page->prev)
page->prev->next = page->next;
else
all_mapped_pages = page->next;
if (page->next)
page->next->prev = page->prev;
}
}
int pagemap_is_mapped(void *p) {
mpage **page_maps2;
mpage *page_maps3;
if (!page_maps1) return 0;
page_maps2 = page_maps1[PAGEMAP64_LEVEL1_BITS(p)];
if (!page_maps2) return 0;
page_maps3 = page_maps2[PAGEMAP64_LEVEL2_BITS(p)];
if (!page_maps3) return 0;
return !!page_maps3[PAGEMAP64_LEVEL3_BITS(p)].addr;
}
void pagemap_for_each(page_callback f, int do_unmap) {
mpage *p, *next;
p = all_mapped_pages;
while (p) {
next = p->next;
f(p->addr);
if (do_unmap)
pagemap_modify(p->addr, 0);
p = next;
}
if (do_unmap)
all_mapped_pages = NULL;
}