blob: b8135ef17a601010bef43f12ff49466c53ca2d09 (
plain)
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
|
#include <stdint.h>
#include <stddef.h>
#include <memory.h>
#define MEMORY_INTERNAL
#include <memory/virtalloc.h>
struct addr_node {
uintptr_t start;
uintptr_t end;
struct addr_node *next;
struct addr_node *prev;
uint8_t is_alloc;
uint8_t is_bss;
};
#define BOOTSTRAP_BSS_NODES 16
static uint8_t bss_nodes = 0;
static struct addr_node nodes[BOOTSTRAP_BSS_NODES];
static struct addr_node *start_node;
static struct addr_node *alloc_node(void) {
if (bss_nodes >= BOOTSTRAP_BSS_NODES) {
//FIXME: alloc on heap
} else {
struct addr_node *node = &nodes[bss_nodes];
bss_nodes += 1;
node->is_bss = false;
return node;
}
return NULL;
}
static void free_node(struct addr_node *node) {
if (!node->is_bss)
free(node);
}
void virtaddr_init(void) {
struct addr_node init = {
.start = 0,
.end = UINT64_MAX,
.next = NULL,
.prev = NULL,
.is_alloc = false,
.is_bss = true,
};
nodes[0] = init;
start_node = &nodes[0];
bss_nodes++;
}
void *virtaddr_alloc(int n_pages) {
long n_length = n_pages * PAGE_SIZE;
struct addr_node *node = start_node;
for (; node != NULL ; node = node->next) {
if (node->is_alloc)
continue;
long length = node->end - node->start;
if (length >= n_length) {
struct addr_node *new = alloc_node();
if (node == NULL)
return NULL;
new->next = node;
node->prev = new;
if (node->prev != NULL) {
node->prev->next = new;
}
new->start = node->start;
new->end = new->start + n_length;
node->start = new->end;
new->is_alloc = true;
return (void *) new->start;
}
}
return NULL;
}
static void merge_back(struct addr_node *node) {
while(node->prev && !node->is_alloc) {
struct addr_node *temp = node->prev;
node->start = node->prev->start;
node->prev = node->prev->prev;
free_node(temp);
}
if (node->prev == NULL) {
start_node = node;
}
}
static void merge_forward(struct addr_node *node) {
while(node->next && !node->is_alloc) {
struct addr_node *temp = node->next;
node->end = node->next->end;
node->next = node->next->next;
free_node(temp);
}
}
long virtaddr_free(void *virtaddr) {
uintptr_t virt = (uintptr_t) virtaddr;
if (virt % PAGE_SIZE)
return -1; // not page aligned, we did not give this out!!!
struct addr_node *node = start_node;
for (; node != NULL; node = node->next) {
if (node->start == virt) {
int length = node->end - node->start;
int pages = length / PAGE_SIZE;
merge_back(node);
merge_forward(node);
return pages;
}
}
return -1;
}
|