blob: 2a92df206d154ed4555a46945794c6781b6f7adc (
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
|
#include <kernel/pagemgr.H>
#include <util/singleton.H>
#include <kernel/console.H>
#include <sys/vfs.h>
void PageManager::init()
{
Singleton<PageManager>::instance();
}
void* PageManager::allocatePage(size_t n)
{
PageManager& pmgr = Singleton<PageManager>::instance();
return pmgr._allocatePage(n);
}
void PageManager::freePage(void* p, size_t n)
{
PageManager& pmgr = Singleton<PageManager>::instance();
return pmgr._freePage(p, n);
}
PageManager::PageManager()
{
// Determine first page of un-allocated memory.
uint64_t addr = (uint64_t) VFS_LAST_ADDRESS;
if (0 != (addr % PAGESIZE))
addr = (addr - (addr % PAGESIZE)) + PAGESIZE;
// Determine number of pages available.
page_t* page = (page_t*)((void*) addr);
size_t length = (MEMLEN - addr) / PAGESIZE;
// Display.
printk("Initializing PageManager with %zd pages starting at %llx...",
length,
(uint64_t)page);
// Allocate pages to buckets.
size_t page_length = BUCKETS-1;
while(length > 0)
{
while (length < (size_t)(1 << page_length))
page_length--;
first_page[page_length].push(page);
page = (page_t*)((uint64_t)page + (1 << page_length)*PAGESIZE);
length -= (1 << page_length);
}
printk("done\n");
}
void* PageManager::_allocatePage(size_t n)
{
size_t which_bucket = 0;
while (n > (size_t)(1 << which_bucket)) which_bucket++;
int retries = 0;
page_t* page = (page_t*)NULL;
while ((page == NULL) && (retries < 3))
{
page = pop_bucket(which_bucket);
retries++;
}
if (NULL == page)
{
// TODO: Add abort instead.
printk("Insufficient memory for allocation of size %zd!\n", n);
while(1);
}
return page;
}
void PageManager::_freePage(void* p, size_t n)
{
if ((NULL == p) || (0 == n)) return;
size_t which_bucket = 0;
while (n > (size_t)(1 << which_bucket)) which_bucket++;
push_bucket((page_t*)p, which_bucket);
return;
}
PageManager::page_t* PageManager::pop_bucket(size_t n)
{
if (n >= BUCKETS) return NULL;
page_t* p = first_page[n].pop();
if (NULL == p)
{
// Couldn't allocate from the correct size bucket, so split up an
// item from the next sized bucket.
p = pop_bucket(n+1);
if (NULL != p)
{
push_bucket((page_t*) (((uint64_t)p) + (PAGESIZE * (1 << n))),
n);
}
}
return p;
}
void PageManager::push_bucket(page_t* p, size_t n)
{
if (n >= BUCKETS) return;
first_page[n].push(p);
}
|