Skip to content

Commit 651fdd7

Browse files
committed
mm: Implement malloc and free
1 parent 2588e1b commit 651fdd7

2 files changed

Lines changed: 185 additions & 0 deletions

File tree

kernel/kernel.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <kcheck.h>
22
#include <kio.h>
33
#include <logger.h>
4+
#include <mm/memory_alloc.h>
45
#include <mm/page_alloc.h>
56
#include <mm/page_frame.h>
67
#include <mm/paging.h>
@@ -81,6 +82,18 @@ extern void kmain(multiboot_info_t *multiboot_info, uint32_t multiboot_magic)
8182
}
8283
#endif
8384

85+
#ifdef DEBUG
86+
{ /* sanity check for malloc */
87+
void *mem1 = malloc(10);
88+
void *mem2 = malloc(10);
89+
90+
kcheck(mem1 != mem2, "check malloc");
91+
92+
free(mem1);
93+
free(mem2);
94+
}
95+
#endif
96+
8497
klog(LOG_INFO, "\nInitialization complete.\n");
8598
kprintf("\n$ ");
8699

kernel/mm/memory_alloc.c

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
2+
#include <assert.h>
3+
#include <mm/page_alloc.h>
4+
5+
#define PAGE_SIZE 512 /* 4kb = 512 bytes */
6+
7+
typedef struct _block_t
8+
{
9+
struct _block_t *prev;
10+
struct _block_t *next;
11+
size_t size;
12+
} __attribute__((packed)) block_t;
13+
14+
typedef struct _block_info_t
15+
{
16+
size_t size;
17+
} __attribute__((packed)) block_info_t;
18+
19+
/**
20+
* Store the list of free blocks
21+
*/
22+
block_t *free_mem_list = NULL;
23+
24+
/**
25+
* Allocate a new page, wrap it in a block and return it
26+
*
27+
* @return block_t * A new free block
28+
*/
29+
static inline block_t *allocate_new_block()
30+
{
31+
struct page *page = page_alloc();
32+
block_t * block = page->address;
33+
34+
block->prev = NULL;
35+
block->next = NULL;
36+
block->size = PAGE_SIZE;
37+
38+
return block;
39+
}
40+
41+
/**
42+
* Find a block that can fix the given size request. If a block does not
43+
* already exist, it is created.
44+
*
45+
* @param size_t The requested size in bytes
46+
* @return block_t * The block which can fit this size
47+
*/
48+
static inline block_t *find_block(size_t size)
49+
{
50+
/* requested size should always be less than block size (for now) */
51+
assert(size <= PAGE_SIZE);
52+
53+
/* if we don't have any blocks left, get a new block and return it */
54+
if (free_mem_list == NULL) {
55+
free_mem_list = allocate_new_block();
56+
57+
return free_mem_list;
58+
}
59+
60+
block_t *block = free_mem_list;
61+
int found = 0;
62+
63+
while (1) {
64+
if (block->size >= size) {
65+
found = 1;
66+
break;
67+
}
68+
69+
/* ensure that reference to block is always valid */
70+
if (block->next == NULL) {
71+
break;
72+
}
73+
74+
block = block->next;
75+
}
76+
77+
if (!found) {
78+
/*
79+
* this block would always be the last block in the list. just update the
80+
* `next` for it
81+
*/
82+
block->next = allocate_new_block();
83+
block->next->prev = block;
84+
85+
/* set the new block as the current block */
86+
block = block->next;
87+
}
88+
89+
/* this block would definitely be bigger than or equal to the requested size
90+
* (see `assert` at the start) */
91+
return block;
92+
}
93+
94+
/**
95+
* Free a block and add it to the free_mem_list.
96+
*
97+
* @param block_info_t * The block info
98+
*/
99+
static inline void free_block(block_info_t *info)
100+
{
101+
size_t size = info->size;
102+
block_t *block = (void *)info;
103+
104+
/* add the block to the head of the free_mem_list */
105+
106+
/* add the size of the block info also to the size of the block */
107+
block->size = size + sizeof(block_info_t);
108+
block->prev = NULL;
109+
block->next = free_mem_list;
110+
111+
if (block->next) {
112+
block->next->prev = block;
113+
}
114+
115+
free_mem_list = block;
116+
}
117+
118+
/**
119+
* Allocate a block of memory from free_mem_list. The allocated block does not
120+
* include the block info, neither does it reserve space for it. The called
121+
* must include the size of block info before calling this function.
122+
*
123+
* @param size_t The size of the block to allocate
124+
* @return void * The address of the allocated block
125+
*/
126+
static void *malloc_raw(size_t size)
127+
{
128+
block_t *block = find_block(size);
129+
130+
/* calculate the remaining size of the block after allocating the given sized
131+
* block */
132+
size_t remaining = block->size - size;
133+
134+
if (!remaining) {
135+
/* remove this node from the list */
136+
137+
if (block->prev) {
138+
block->prev->next = block->next;
139+
}
140+
141+
if (block->next) {
142+
block->next->prev = block->prev;
143+
}
144+
145+
/* return the address of this block */
146+
return block;
147+
}
148+
149+
block->size = remaining;
150+
151+
/* return the part at the end of this block */
152+
return (void *)block + remaining;
153+
}
154+
155+
void *malloc(size_t size)
156+
{
157+
/* allocate memory for the requested sized block + info about the block */
158+
block_info_t *alloc = malloc_raw(size + sizeof(block_info_t));
159+
160+
/* store the info for the block */
161+
alloc->size = size;
162+
163+
/* return the block after the info */
164+
return (void *)alloc + sizeof(block_info_t);
165+
}
166+
167+
void free(void *block)
168+
{
169+
block_info_t *info = block - sizeof(block_info_t);
170+
171+
free_block(info);
172+
}

0 commit comments

Comments
 (0)