-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpage.c
145 lines (128 loc) · 3.7 KB
/
page.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
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
133
134
135
136
137
138
139
140
141
142
143
144
145
#include "page.h"
#include "uart.h"
static inline void _clear(struct page* p)
{
p->flags = 0;
}
static inline int _is_free(struct page *p)
{
if(p->flags & PAGE_TAKEN) {
return 0;
} else {
return 1;
}
}
static inline void _set_flag(struct page* p, uint8_t flags)
{
p->flags |= flags; /* or operation on the flags */
}
static inline int _is_last(struct page* p)
{
if (p->flags & PAGE_LAST) {
return 1;
} else {
return 0;
}
}
/* align the address to the border of page (4kB) */
static uint32_t _align_page(uint32_t address)
{
uint32_t order = (1 << PAGE_ORDER) - 1;
return (address + order) & (~order);
}
static uint32_t _num_pages = 0;
static uint32_t _alloc_start = 0;
static uint32_t _alloc_end = 0;
void page_init(void)
{
/*
* We reserved 8 pages (8 * 4096 Bytes) to hold the structure
* for page management. It should be enough to manage at most
* 128 MB ( 8 * 4096 * 4096 Bytes)
*/
_num_pages = (HEAP_SIZE / PAGE_SIZE) - NUM_RESERVED_PAGES;
printf("HEAP_START = %x, HEAP_SIZE = %x, num of pages = %d\n", HEAP_START, HEAP_SIZE, _num_pages);
struct page* ptrPage = (struct page *)HEAP_START;
for (int i = 0; i < _num_pages; i++) {
_clear(ptrPage);
ptrPage++;
}
_alloc_start = _align_page(HEAP_START + NUM_RESERVED_PAGES * PAGE_SIZE);
_alloc_end = _alloc_start + (PAGE_SIZE * _num_pages);
printf("TEXT: 0x%x -> 0x%x\n", TEXT_START, TEXT_END);
printf("RODATA: 0x%x -> 0x%x\n", RODATA_START, RODATA_END);
printf("DATA: 0x%x -> 0x%x\n", DATA_START, DATA_END);
printf("BSS: 0x%x -> 0x%x\n", BSS_START, BSS_END);
printf("HEAP: 0x%x -> 0x%x\n", _alloc_start, _alloc_end);
}
/* allocator */
// TODO: improve performance
void *page_alloc(int npages)
{
int found = 0;
struct page *ptrPage_i = (struct page *)HEAP_START;
for (int i = 0; i <= (_num_pages - npages); i++) {
if (_is_free(ptrPage_i)) {
found = 1;
struct page *ptrPage_j = ptrPage_i + 1;
for (int j = i + 1; j <= (i + npages); j++) {
if ( !_is_free(ptrPage_j) ) {
found = 0;
break;
}
ptrPage_j++;
}
/* Get a memory block which is enough for us,
* return the actual start address of the first
* page of this block.
*/
if (found) {
struct page *ptrPage_k = ptrPage_i;
for (int k = i; k < (i + npages); k++) {
_set_flag(ptrPage_k, PAGE_TAKEN);
ptrPage_k++;
}
ptrPage_k--;
_set_flag(ptrPage_k, PAGE_LAST);
return (void *)(_alloc_start + i * PAGE_SIZE);
}
}
ptrPage_i++;
}
return NULL;
}
/* Free the memory block */
void page_free(void *p)
{
/* Assert if p is invalid */
if (!p || (uint32_t)p >= _alloc_end) {
return;
}
/* The first page descriptor of the memory block */
struct page *ptrPage = (struct page *)HEAP_START;
ptrPage += ((uint32_t)p - _alloc_start) / PAGE_SIZE;
/* loop and clear all the page descriptors of this memory block */
while (!_is_free(ptrPage)) {
_clear(ptrPage);
if(_is_last(ptrPage)){
break;
} else{
ptrPage++;
}
}
}
void page_test(void)
{
void *p1 = page_alloc(2);
printf("p1 = 0x%x\n", p1);
void *p2 = page_alloc(12);
printf("p2 = 0x%x\n", p2);
void *p3 = page_alloc(5);
printf("p3 = 0x%x\n", p3);
page_free(p1);
p1 = NULL;
page_free(p2);
p2 = NULL;
page_free(p3);
p3 = NULL;
}