Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions kernel/include/mm/memory_alloc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#ifndef MEMORY_ALLOC_H_ZPNDLSE1
#define MEMORY_ALLOC_H_ZPNDLSE1

#include <types.h>

/**
* Allocate memory of given size and return its starting address.
*
* @param size_t size of the memory to allocate
* @return void * address of the memory. NULL if allocation failed
*/
void *malloc(size_t);

/**
* Reallocate a piece of memory with the new size.
*
* @param void * address of memory to reallocate
* @param size_t size of the new memory
* @return void * address of the newly reallocated memory. NULL if
* reallocation failed.
*/
void *realloc(void *, size_t);

/**
* Allocates memory for the given number of array elements of the given array
* size. The memory is set to 0.
*
* @param size_t size of the array to allocate memory for
* @param size_t size of each array element
* @return void * address of the newly allocated memory. NULL if
* allocation failed.
*/
void *calloc(size_t, size_t);

/**
* Free a piece of allocated memory.
*
* @param void * address of the allocated memory
*/
void free(void *);

#endif /* end of include guard: MEMORY_ALLOC_H_ZPNDLSE1 */
19 changes: 19 additions & 0 deletions kernel/kernel.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <kcheck.h>
#include <kio.h>
#include <logger.h>
#include <mm/memory_alloc.h>
#include <mm/page_alloc.h>
#include <mm/page_frame.h>
#include <mm/paging.h>
Expand Down Expand Up @@ -62,19 +63,37 @@ extern void kmain(multiboot_info_t *multiboot_info, uint32_t multiboot_magic)
uintptr_t * addr1 = (void *)0x00400000;
uintptr_t * addr2 = addr1 + 1024;

/* map both addresses to same physical memory page */
paging_map_page(page, addr1, 0x02);
paging_map_page(page, addr2, 0x02);

/* update the values at both addresses */
*addr1 = 0xcafebabe;
*addr2 = 0xdeadbeef;

/* the second update should overwrite the first since the physical address
* is same */
kcheck(*addr1 == *addr2, "paging enabled");

/* cleanup */
paging_unmap_page(page, addr1);
paging_unmap_page(page, addr2);
page_free(page);
}
#endif

#ifdef DEBUG
{ /* sanity check for malloc */
void *mem1 = malloc(10);
void *mem2 = malloc(10);

kcheck(mem1 != mem2, "check malloc");

free(mem1);
free(mem2);
}
#endif

klog(LOG_INFO, "\nInitialization complete.\n");
kprintf("\n$ ");

Expand Down
194 changes: 194 additions & 0 deletions kernel/mm/memory_alloc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@

#include <assert.h>
#include <mm/page_alloc.h>
#include <mm/memory_alloc.h>
#include <string.h>

#define PAGE_SIZE 512 /* 4kb = 512 bytes */

typedef struct _block_t
{
struct _block_t *prev;
struct _block_t *next;
size_t size;
} __attribute__((packed)) block_t;

typedef struct _block_info_t
{
size_t size;
} __attribute__((packed)) block_info_t;

/**
* Store the list of free blocks
*/
block_t *free_mem_list = NULL;

/**
* Allocate a new page, wrap it in a block and return it
*
* @return block_t * A new free block
*/
static inline block_t *allocate_new_block()
{
struct page *page = page_alloc();
block_t * block = page->address;

block->prev = NULL;
block->next = NULL;
block->size = PAGE_SIZE;

return block;
}

/**
* Find a block that can fix the given size request. If a block does not
* already exist, it is created.
*
* @param size_t The requested size in bytes
* @return block_t * The block which can fit this size
*/
static inline block_t *find_block(size_t size)
{
/* requested size should always be less than block size (for now) */
assert(size <= PAGE_SIZE);

/* if we don't have any blocks left, get a new block and return it */
if (free_mem_list == NULL) {
free_mem_list = allocate_new_block();

return free_mem_list;
}

block_t *block = free_mem_list;
int found = 0;

while (1) {
if (block->size >= size) {
found = 1;
break;
}

/* ensure that reference to block is always valid */
if (block->next == NULL) {
break;
}

block = block->next;
}

if (!found) {
/*
* this block would always be the last block in the list. just update the
* `next` for it
*/
block->next = allocate_new_block();
block->next->prev = block;

/* set the new block as the current block */
block = block->next;
}

/* this block would definitely be bigger than or equal to the requested size
* (see `assert` at the start) */
return block;
}

/**
* Free a block and add it to the free_mem_list.
*
* @param block_info_t * The block info
*/
static inline void free_block(block_info_t *info)
{
size_t size = info->size;
block_t *block = (void *)info;

/* add the block to the head of the free_mem_list */

/* add the size of the block info also to the size of the block */
block->size = size + sizeof(block_info_t);
block->prev = NULL;
block->next = free_mem_list;

if (block->next) {
block->next->prev = block;
}

free_mem_list = block;
}

/**
* Allocate a block of memory from free_mem_list. The allocated block does not
* include the block info, neither does it reserve space for it. The called
* must include the size of block info before calling this function.
*
* @param size_t The size of the block to allocate
* @return void * The address of the allocated block
*/
static void *malloc_raw(size_t size)
{
block_t *block = find_block(size);

/* calculate the remaining size of the block after allocating the given sized
* block */
size_t remaining = block->size - size;

if (!remaining) {
/* remove this node from the list */

if (block->prev) {
block->prev->next = block->next;
}

if (block->next) {
block->next->prev = block->prev;
}

/* return the address of this block */
return block;
}

block->size = remaining;

/* return the part at the end of this block */
return (void *)block + remaining;
}

void *malloc(size_t size)
{
/* allocate memory for the requested sized block + info about the block */
block_info_t *alloc = malloc_raw(size + sizeof(block_info_t));

/* store the info for the block */
alloc->size = size;

/* return the block after the info */
return (void *)alloc + sizeof(block_info_t);
}

void *realloc(void *block, size_t size)
{
free(block);

return malloc(size);
}

void *calloc(size_t num_elements, size_t element_size)
{
size_t size = num_elements * element_size;

/* allocate memory for all the array elements */
void *mem = malloc(size);

/* set the memory to 0 */
memset(mem, 0, size);

return mem;
}

void free(void *block)
{
block_info_t *info = block - sizeof(block_info_t);

free_block(info);
}
4 changes: 3 additions & 1 deletion kernel/mm/page_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ void page_alloc_init()
size_t pages_array_page_count =
page_address_to_index(pages_array_mem_size) + 1;

/* we have some unused memory at this point but we'll ignore it for now */

/* allocate the pages for the array */
pages = page_frame_n_alloc(pages_array_page_count);

Expand All @@ -44,7 +46,7 @@ struct page *page_n_alloc(size_t count)

for (size_t i = 0; i < count; i++) {
pages[page_index + i].address = page_address;
page_address += 0x1000;
page_address += 0x1000; /* add 4kb to the page address (0x1000 = 4096) */
}

return &pages[page_index];
Expand Down
2 changes: 1 addition & 1 deletion kernel/mm/page_frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ static uint32_t frames_bitmap_size;
static uint32_t frames_bitmap_num_pages;

/* size of each frame that is allocated in bytes */
#define FRAME_SIZE 4096 /* 4KB */
#define FRAME_SIZE 4096 /* 4Kb */
#define FRAME_SIZE_BYTES 512 /* 4096/8 */
#define BLOCK_SIZE 1024
#define BLOCKS_PER_FRAME 4 /* each block is 1KB */
Expand Down