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
|
#include "kernel.h"
#include "kmalloc.h"
#include "spinlock.h"
#include "log.h"
#define BLOCKS KMALLOC_MEM_SIZE/KMALLOC_BLOCK_SIZE
// this is in .bss so we can assume it was zeroed!
static uint8_t data[KMALLOC_MEM_SIZE] __attribute__((aligned (4096))); // bytes
static uint8_t map[BLOCKS];
//
static uint32_t data_addr;
static uint32_t next;
static uint32_t first;
static uint8_t init=0;
static uint32_t next_free(uint32_t start)
{
for(int i=start;i<BLOCKS;i++)
{
if(!map[i])return i;
return next_free(i+map[i]);
}
return BLOCKS; // out of mem
}
static uint32_t next_used(uint32_t start,uint32_t max)
{
for(int i=start;i<BLOCKS;i++)
{
if(map[i])return i;
//means i is free
if(i-start>=max)return i;
}
return BLOCKS; // all free
}
static uint32_t free_cont(uint32_t blocks)
{
uint32_t pos=0;
while(1)
{
pos=next_free(pos);
// klog("next_free:%d",pos);
if(pos==BLOCKS)return BLOCKS; // out of mem
uint32_t end=next_used(pos,blocks);
// klog("next_used:%d",end);
if(end-pos>=blocks)return pos;
// klog("here we have only %d blocks but we need at least %d",end-pos+1,blocks);
pos=end;
}
}
static void mark_used(uint32_t start,uint32_t blocks)
{
uint32_t b=blocks;
for(int i=start;i<start+blocks;i++)
{
if(map[i]!=0)kpanic("memory map corrupted?");
map[i]=b;
b--;
}
}
static void mark_free(uint32_t start,uint32_t blocks)
{
if(map[start]!=blocks)
{
kpanic("mark_free(%d,%d),mem map corrupted at %d (value=%d)?",start,blocks,start,map[start]);
}
if(start!=0&&(map[start-1]!=1&&map[start-1]!=0))
{
kpanic("mem map corrupted one before %d (value=%d)?",start,map[start-1]);
}
map[start]=0;
if(blocks>1)mark_free(start+1,blocks-1);
}
// will be initialized on first call to kballoc() //
static void kmallocinit()
{
next=&(data[0]);
data_addr=next;
first=next;
if(next%4096)kpanic("kmalloc data not aligned properly.");
klog("In-Kernel Block Memory Allocation Initialized at: 0x%08X (free: %d x 4096KB BLOCKS)",next,BLOCKS);
init=1;
}
// kernel block memory allocation //
uint32_t kballoc(uint32_t size)
{
if(size>255)kpanic("max supported size 255 blocks");
spinlock_spin(SPINLOCK_ALLOC);
if(!init)kmallocinit();
uint32_t blk=free_cont(size);
if(blk==BLOCKS)kpanic("out of mem");
mark_used(blk,size);
spinlock_release(SPINLOCK_ALLOC);
return data_addr+blk*4096;
}
void kbfree(uint32_t pos)
{
uint32_t blk=(pos-data_addr)/4096;
spinlock_spin(SPINLOCK_ALLOC);
klog("freeing %d blocks ad 0x%08X",map[blk],pos);
mark_free(blk,map[blk]);
spinlock_release(SPINLOCK_ALLOC);
}
void kmalloc_sysfs(ringbuffer *r,void (*f)(ringbuffer *r,char *fmt, ...))
{
uint32_t free=0;
uint32_t used=0;
for(int i=0;i<BLOCKS;i++)
{
if(map[i]) used++;
else free++;
}
f(r,"kernel blocks allocation/deallocation");
f(r,"total 4096kb blocks: %d (%d bytes)",BLOCKS,BLOCKS*4096);
f(r,"used 4096kb blocks: %d (%d bytes)",used,used*4096);
f(r,"free 4096kb blocks: %d (%d bytes)",free,free*4096);
}
|