-
Notifications
You must be signed in to change notification settings - Fork 0
/
kmalloc.cpp
130 lines (102 loc) · 3.14 KB
/
kmalloc.cpp
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
#include <kmalloc.h>
class small_alloc {
public:
small_alloc * next;
size_t block_size;
uint32_t num_blocks;
void * blocks_start;
uint8_t bitmask[]; //let's see if C++ supports flexible arrays...
}
struct large_alloc {
size_t num_pages;
int32_t magic;
}
#define PAGE_BITS 12
#define PAGE_SIZE (1 << PAGE_BITS) //4KiB
#define PAGE_SPLIT 2 //power of two less than page size that will do a large allocation
#define LARGE_PAGE_MAGIC 0x7fca82b9
#define SMALL_PAGE_MAGIC 0x298c98a4
static uint8_t memspace[0x1000000]; //16MiB of space
static uint8_t mem_bitmap[sizeof(memspace) >> PAGE_BITS >> 3]; //1 bit per 4KiB page
static small_alloc *small_allocations[PAGE_BITS - PAGE_SPLIT + 1];
//mallocs > 4KiB are allocated in units of 4KiB
void * memset(void * mem, uint8_t value, size_t size){
for (uint8_t * ptr = mem; size > 0; size -= sizeof(uint8_t)){
*ptr++ = value;
}
return mem;
}
void kmeminit(){
memset(&mem_bitmap, sizeof(mem_bitmap), 0);
memset(&small_allocations, sizeof(small_allocations), 0);
}
void * kmalloc(size_t size){
if (size > PAGE_SIZE / 4){
//large allocation
size_t num_pages = (size + sizeof(large_alloc) + PAGE_SIZE - 1) >> PAGE_BITS;
//search for a point in the map with enough contiguous pages free
int32_t bitmap_loc = search_bitmap(num_pages);
if (bitmap_loc == -1){
return NULL;
}
//otherwise we're good, write to the bitmap to indicate that the pages are now reserved
set_bitmask(bitmap_loc, num_pages);
//write a large_alloc descriptor
large_alloc *descriptor = (large_alloc*)(&memspace[bitmap_loc << PAGE_BITS]);
descriptor->num_pages = num_pages;
descriptor->magic = LARGE_PAGE_MAGIC;
return (void*)(descriptor + 1);
} else {
//small allocation
}
}
void kfree(void * alloc){
//read the magic number
int32_t magic = *(((int32_t*)alloc) - 1);
if (magic == LARGE_PAGE_MAGIC){
large_alloc *descriptor = ((large_alloc*)alloc) - 1;
//translate the address to a page #
int32_t page_num = ((uintptr_t)descriptor - (uintptr_t)memspace) >> PAGE_BITS;
clear_bitmask(page_num, descriptor->num_pages);
descriptor->magic = 0x00000000;
}
}
#define BIT_TEST(x,n) ((x) & (1 << n))
//returns the page# of the first match found, or -1 on error
int32_t search_bitmap(size_t numpages){
size_t pagesleft = numpages;
for (int32_t i = 0; i < sizeof(memspace) && pagesleft != 0; i++){
if (BIT_TEST(mem_bitmap[i >> 3], i & 0x7)){
pagesleft--;
} else {
pagesleft = numpages;
}
}
if (pagesleft == 0){
//found it
return i - numpages;
} else {
return -1;
}
}
void set_bitmask(int32_t block_start, size_t numpages){
uint8_t *ptr = mem_bitmap[block_start >> 3];
uint8_t init_mask = 0xff >> (block_start & 0x7);
*ptr++ |= init_mask;
numpages -= (block_start & 0x7);
while (numpages >= 8){
*ptr++ = 0xff;
}
*ptr |= 0xff << (8 - num_pages);
}
//assumes that the bits are already set - bad stuff if they aren't
void clear_bitmask(int32_t block_start, size_t numpages){
uint8_t *ptr = mem_bitmap[block_start >> 3];
uint8_t init_mask = 0xff >> (block_start & 0x7);
*ptr++ ^= init_mask;
numpages -= (block_start & 0x7);
while (numpages >= 8){
*ptr++ ^= 0xff;
}
*ptr ^= 0xff << (8 - num_pages);
}