feature: kmalloc kfree and krealloc are good
This commit is contained in:
parent
0467c45bf0
commit
943f2beab9
85
headers/alloc.h
Normal file
85
headers/alloc.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// boolean types
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
// size_t, already in libft.h but for readability
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// Remove this and replace it with <assert.h> header
|
||||||
|
// for debugging purposes
|
||||||
|
/* #include <assert.h> */
|
||||||
|
#define assert(bool)
|
||||||
|
|
||||||
|
// BPZ = Blocks Per Zone, which is the max
|
||||||
|
// number of blocks for a new zone
|
||||||
|
enum { BPZ = 128, PAGES_TINY = 16, PAGES_SMALL = 64, MEM_ALIGN = 8 };
|
||||||
|
|
||||||
|
typedef enum { TINY, SMALL, LARGE } block_type_t;
|
||||||
|
|
||||||
|
/* METADATA:
|
||||||
|
* ptr: the ptr to return with kalloc (aligned)
|
||||||
|
* size: the actual size
|
||||||
|
* sub_size: the size asked by the user (different
|
||||||
|
* from size only if krealloc and krealloc size < size)
|
||||||
|
* in_use: bool to track block state
|
||||||
|
* zone: the zone containing the block
|
||||||
|
*
|
||||||
|
* LINKED LIST:
|
||||||
|
* next and prev will never change, it's the original block's
|
||||||
|
* position (initialized when creating the blocks)
|
||||||
|
* next/prev_used: linked list for the
|
||||||
|
* in_use blocks (Block *used in struct Zone)
|
||||||
|
* next/prev_free: linked list for the
|
||||||
|
* available blocks (Block *free in struct Zone)
|
||||||
|
*/
|
||||||
|
typedef struct Block {
|
||||||
|
|
||||||
|
void *ptr;
|
||||||
|
size_t size;
|
||||||
|
size_t sub_size;
|
||||||
|
bool in_use;
|
||||||
|
struct Zone *zone;
|
||||||
|
|
||||||
|
struct Block *prev;
|
||||||
|
struct Block *next;
|
||||||
|
struct Block *prev_used;
|
||||||
|
struct Block *next_used;
|
||||||
|
struct Block *prev_free;
|
||||||
|
struct Block *next_free;
|
||||||
|
} Block;
|
||||||
|
|
||||||
|
/* free is the first list, when creating the blocks
|
||||||
|
* used is a list at the end of the free list, which contains all the blocks
|
||||||
|
* in_use
|
||||||
|
*/
|
||||||
|
typedef struct Zone {
|
||||||
|
size_t size;
|
||||||
|
struct Zone *prev;
|
||||||
|
struct Zone *next;
|
||||||
|
block_type_t type;
|
||||||
|
Block *free;
|
||||||
|
Block *used;
|
||||||
|
} Zone;
|
||||||
|
|
||||||
|
/* Linked list to store all the zones (pages) mapped.
|
||||||
|
* The attribute type is either TINY, SMALL or LARGE.
|
||||||
|
* For TINY and SMALL, the zone will be divided in blocks.
|
||||||
|
* For LARGE, it will be entire page(s).
|
||||||
|
*/
|
||||||
|
extern Zone *zones[3];
|
||||||
|
|
||||||
|
/*----------- UTILS ----------*/
|
||||||
|
block_type_t get_type(size_t size);
|
||||||
|
size_t get_zone_size(block_type_t type);
|
||||||
|
size_t align_mem(size_t addr);
|
||||||
|
/*----------------------------*/
|
||||||
|
|
||||||
|
/*-------- ALLOCATOR ---------*/
|
||||||
|
int new_zone(block_type_t type, size_t size);
|
||||||
|
/*----------------------------*/
|
||||||
|
|
||||||
|
void *kalloc(size_t size);
|
||||||
|
void kfree(void *ptr);
|
||||||
|
void *krealloc(void *ptr, size_t size);
|
||||||
|
void show_alloc_mem(void);
|
@ -11,4 +11,4 @@
|
|||||||
|
|
||||||
void init_memory(void);
|
void init_memory(void);
|
||||||
void *kalloc_frame(uint32_t nb_frames);
|
void *kalloc_frame(uint32_t nb_frames);
|
||||||
void kfree_frame(void *frame, uint32_t nb_frames);
|
int kfree_frame(void *frame, uint32_t nb_frames);
|
||||||
|
@ -1,34 +1,38 @@
|
|||||||
SRCDIR = src
|
SSRC := $(shell find src -name '*.s')
|
||||||
OBJDIR = obj
|
CSRC := $(shell find src -name '*.c')
|
||||||
BUILDDIR = build
|
OBJ := $(patsubst src/%.c,obj/%.o,$(CSRC))\
|
||||||
|
$(patsubst src/%.s,obj/%.o,$(SSRC))
|
||||||
|
|
||||||
SRC := $(shell find $(SRCDIR) -name '*.c')
|
CC := i386-elf-gcc
|
||||||
OBJ := $(patsubst $(SRCDIR)/%.c,$(OBJDIR)/%.o,$(SRC))
|
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -iquoteheaders -c
|
||||||
|
|
||||||
CC = i386-elf-gcc
|
AS := i386-elf-as
|
||||||
CFLAGS = -std=gnu99 -ffreestanding -O2 -Wall -Wextra -iquoteheaders -c
|
ASFLAGS :=
|
||||||
|
AR := ar
|
||||||
AR = ar
|
ARFLAGS :=
|
||||||
ARFLAGS =
|
|
||||||
|
|
||||||
NAME = libbozo.a
|
NAME = libbozo.a
|
||||||
|
|
||||||
$(OBJDIR)/%.o: $(SRCDIR)/%.c
|
obj/%.o: src/%.s
|
||||||
|
mkdir -p $(dir $@)
|
||||||
|
$(AS) $(ASFLAGS) $< -o $@
|
||||||
|
|
||||||
|
obj/%.o: src/%.c
|
||||||
mkdir -p $(dir $@)
|
mkdir -p $(dir $@)
|
||||||
$(CC) $(CFLAGS) $< -o $@
|
$(CC) $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
all : $(NAME)
|
all : $(NAME)
|
||||||
|
|
||||||
clean :
|
clean :
|
||||||
rm -rf $(OBJDIR)
|
rm -rf obj
|
||||||
|
|
||||||
fclean : clean
|
fclean : clean
|
||||||
rm -rf $(BUILDDIR)
|
rm -rf build
|
||||||
|
|
||||||
$(NAME) : $(OBJ)
|
$(NAME) : $(OBJ)
|
||||||
mkdir -p $(BUILDDIR)
|
mkdir -p build
|
||||||
$(AR) -rc $(BUILDDIR)/$(NAME) $(OBJ)
|
$(AR) -rc build/$(NAME) $(OBJ)
|
||||||
|
|
||||||
re: fclean all
|
re: fclean all
|
||||||
|
|
||||||
.PHONY: clean fclean test all re
|
.PHONY: clean fclean all re
|
||||||
|
@ -7,6 +7,8 @@ int strcmp(const char *s1, const char *s2);
|
|||||||
int strncmp(const char *s1, const char *s2, size_t n);
|
int strncmp(const char *s1, const char *s2, size_t n);
|
||||||
size_t strlen(const char *str);
|
size_t strlen(const char *str);
|
||||||
char *strstr(const char *haystack, const char *needle);
|
char *strstr(const char *haystack, const char *needle);
|
||||||
|
char *strcpy(char *dest, const char *src);
|
||||||
void *memcpy(void *dest, const void *src, size_t n);
|
void *memcpy(void *dest, const void *src, size_t n);
|
||||||
int memcmp(const void *s1, const void *s2, size_t n);
|
int memcmp(const void *s1, const void *s2, size_t n);
|
||||||
void *memset(void *str, int c, size_t n);
|
void *memset(void *str, int c, size_t n);
|
||||||
|
void *memmove(void *dest, const void *src, size_t n);
|
||||||
|
21
libbozo/src/string/memmove.c
Normal file
21
libbozo/src/string/memmove.c
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void *memmove(void *dest, const void *src, size_t n)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
const char *cast1 = (const char *)src;
|
||||||
|
char *cast2 = (char *)dest;
|
||||||
|
|
||||||
|
if (!cast1 && !cast2 && n > 0)
|
||||||
|
return (0);
|
||||||
|
if (&cast1[0] > &cast2[0]) {
|
||||||
|
while (i < n) {
|
||||||
|
cast2[i] = cast1[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (n--)
|
||||||
|
cast2[n] = cast1[n];
|
||||||
|
}
|
||||||
|
return cast2;
|
||||||
|
}
|
12
libbozo/src/string/strcpy.c
Normal file
12
libbozo/src/string/strcpy.c
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
char *strcpy(char *dest, const char *src)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
if (!src)
|
||||||
|
return NULL;
|
||||||
|
for (; src[i]; i++)
|
||||||
|
dest[i] = src[i];
|
||||||
|
dest[i] = '\0';
|
||||||
|
return dest;
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "alloc.h"
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "kprintf.h"
|
#include "kprintf.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
@ -31,5 +32,11 @@ void kernel_main(void)
|
|||||||
kprintf(KERN_NOTICE "KERN_NOTICE\n");
|
kprintf(KERN_NOTICE "KERN_NOTICE\n");
|
||||||
kprintf(KERN_INFO "KERN_INFO\n");
|
kprintf(KERN_INFO "KERN_INFO\n");
|
||||||
kprintf(KERN_DEBUG "KERN_DEBUG\n");
|
kprintf(KERN_DEBUG "KERN_DEBUG\n");
|
||||||
|
char *str = kalloc(10);
|
||||||
|
kfree(str);
|
||||||
|
str = kalloc(10);
|
||||||
|
show_alloc_mem();
|
||||||
|
strcpy(str, "Hello world\n");
|
||||||
|
kprintf("%s", str);
|
||||||
shell_init();
|
shell_init();
|
||||||
}
|
}
|
||||||
|
64
src/memory/alloc/allocator.c
Normal file
64
src/memory/alloc/allocator.c
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#include "alloc.h"
|
||||||
|
#include "kprintf.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
Zone *zones[3];
|
||||||
|
|
||||||
|
static void add_zone(Zone *zone, block_type_t type)
|
||||||
|
{
|
||||||
|
// We put the zone at the beginning of the list
|
||||||
|
if (zones[type]) {
|
||||||
|
zone->next = zones[type];
|
||||||
|
zones[type]->prev = zone;
|
||||||
|
}
|
||||||
|
zones[type] = zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void new_block(Zone *zone, size_t zone_size)
|
||||||
|
{
|
||||||
|
Block *new_block = (Block *)align_mem((size_t)zone + sizeof(Zone));
|
||||||
|
|
||||||
|
// Metadata
|
||||||
|
new_block->in_use = false;
|
||||||
|
new_block->size = zone_size - sizeof(Zone) - sizeof(Block);
|
||||||
|
new_block->sub_size = new_block->size;
|
||||||
|
new_block->ptr = (Block *)((size_t)new_block + sizeof(Block));
|
||||||
|
new_block->zone = zone;
|
||||||
|
|
||||||
|
// Init future linked lists
|
||||||
|
new_block->prev = NULL;
|
||||||
|
new_block->prev_free = NULL;
|
||||||
|
new_block->prev_used = NULL;
|
||||||
|
new_block->next = NULL;
|
||||||
|
new_block->next_free = NULL;
|
||||||
|
new_block->next_used = NULL;
|
||||||
|
|
||||||
|
if (zone->free) {
|
||||||
|
zone->free->prev = new_block;
|
||||||
|
zone->free->prev_free = new_block;
|
||||||
|
new_block->next = zone->free;
|
||||||
|
new_block->next_free = zone->free;
|
||||||
|
}
|
||||||
|
zone->free = new_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
int new_zone(block_type_t type, size_t size)
|
||||||
|
{
|
||||||
|
void *heap = kalloc_frame(size);
|
||||||
|
if (heap == NULL) {
|
||||||
|
kprintf(KERN_ERR "error: syscall mmap failed\n");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Zone *zone = (Zone *)heap;
|
||||||
|
zone->type = type;
|
||||||
|
zone->size = size;
|
||||||
|
zone->used = NULL;
|
||||||
|
zone->next = NULL;
|
||||||
|
zone->prev = NULL;
|
||||||
|
|
||||||
|
new_block(zone, size);
|
||||||
|
add_zone(heap, type);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
49
src/memory/alloc/info.c
Normal file
49
src/memory/alloc/info.c
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include "alloc.h"
|
||||||
|
#include "kprintf.h"
|
||||||
|
|
||||||
|
// FULL_INFO is to display (or not) both used and unused blocks
|
||||||
|
#define FULL_INFO 0
|
||||||
|
|
||||||
|
void show_alloc_mem(void)
|
||||||
|
{
|
||||||
|
char *const zones_name[3] = {"TINY", "SMALL", "LARGE"};
|
||||||
|
size_t total_size = 0;
|
||||||
|
|
||||||
|
for (block_type_t type = 0; type < 3; ++type) {
|
||||||
|
int count = 0;
|
||||||
|
for (Zone *zone_it = zones[type]; zone_it != NULL;
|
||||||
|
zone_it = zone_it->next) {
|
||||||
|
#if FULL_INFO
|
||||||
|
if (zone_it->kfree)
|
||||||
|
kprintf("---------- AVAILABLE %s [n°%d - %p] "
|
||||||
|
"----------\n",
|
||||||
|
zones_name[type], count, zone_it);
|
||||||
|
for (Block *block_it = zone_it->kfree; block_it != NULL;
|
||||||
|
block_it = block_it->next_kfree) {
|
||||||
|
kprintf("%p - %p : %u bytes\n", block_it->ptr,
|
||||||
|
(size_t)block_it->ptr +
|
||||||
|
block_it->sub_size + sizeof(Block),
|
||||||
|
block_it->sub_size);
|
||||||
|
}
|
||||||
|
if (zone_it->kfree)
|
||||||
|
ft_printf("\n");
|
||||||
|
#endif
|
||||||
|
if (zone_it->used)
|
||||||
|
kprintf("---------- IN_USE %s [n°%d - %p] "
|
||||||
|
"----------\n",
|
||||||
|
zones_name[type], count, zone_it);
|
||||||
|
for (Block *block_it = zone_it->used; block_it != NULL;
|
||||||
|
block_it = block_it->next_used) {
|
||||||
|
kprintf("%p - %p : %u bytes\n", block_it->ptr,
|
||||||
|
(size_t)block_it->ptr +
|
||||||
|
block_it->sub_size + sizeof(Block),
|
||||||
|
block_it->sub_size);
|
||||||
|
total_size += block_it->sub_size;
|
||||||
|
}
|
||||||
|
if (zone_it->used)
|
||||||
|
kprintf("\n");
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kprintf("Total: %u\n", total_size);
|
||||||
|
}
|
150
src/memory/alloc/kalloc.c
Normal file
150
src/memory/alloc/kalloc.c
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
#include "alloc.h"
|
||||||
|
#include "kprintf.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find first available (not in_use) block
|
||||||
|
* in a zone matching the size we need
|
||||||
|
*/
|
||||||
|
static Block *find_block(Zone *head, size_t size)
|
||||||
|
{
|
||||||
|
for (Zone *zone_it = head; zone_it != NULL; zone_it = zone_it->next) {
|
||||||
|
for (Block *block_it = zone_it->free; block_it != NULL;
|
||||||
|
block_it = block_it->next_free) {
|
||||||
|
assert(!block_it->in_use);
|
||||||
|
if (size <= block_it->size) {
|
||||||
|
assert(block_it->zone == zone_it);
|
||||||
|
return (block_it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PARTIALLY DEPRECATED
|
||||||
|
/*
|
||||||
|
* This will split the newly allocated block to use
|
||||||
|
* the remaining bytes for a new block
|
||||||
|
* This is our linked list of blocks
|
||||||
|
* ... -> [5] -> [6] -> ...
|
||||||
|
* After the allocation, this will become
|
||||||
|
* ... -> [5] -> [new] -> [6] -> ...
|
||||||
|
*
|
||||||
|
* For an example of [5].size = 32 and requiring a kalloc of 10
|
||||||
|
* Let's say the metadata takes a size of 2:
|
||||||
|
* ... -> [metadata][data][remaining size] -> [6]
|
||||||
|
* ^ ^ ^
|
||||||
|
* 2 10 20
|
||||||
|
*
|
||||||
|
* So now our block [new] will become:
|
||||||
|
* [5] -> [metadata][available data] -> [6]
|
||||||
|
* ^ ^
|
||||||
|
* 2 18
|
||||||
|
* We can see that it now has its own metadata and available
|
||||||
|
* data and it points towards [6]
|
||||||
|
*/
|
||||||
|
static void frag_block(Zone *zone, Block *old_block, size_t size)
|
||||||
|
{
|
||||||
|
Block *new_block = (Block *)align_mem((size_t)old_block + size);
|
||||||
|
assert(!(new_block >=
|
||||||
|
(Block *)((size_t)zone + get_zone_size(zone->type))));
|
||||||
|
|
||||||
|
// Newly created block metadata
|
||||||
|
new_block->size = old_block->size - size;
|
||||||
|
new_block->sub_size = new_block->size;
|
||||||
|
new_block->in_use = false;
|
||||||
|
new_block->ptr = (void *)((size_t)new_block + sizeof(Block));
|
||||||
|
new_block->zone = zone;
|
||||||
|
|
||||||
|
new_block->prev = old_block;
|
||||||
|
new_block->next = old_block->next;
|
||||||
|
old_block->next = new_block;
|
||||||
|
|
||||||
|
new_block->prev_used = NULL;
|
||||||
|
new_block->next_used = NULL;
|
||||||
|
|
||||||
|
new_block->prev_free = old_block->prev_free;
|
||||||
|
new_block->next_free = old_block->next_free;
|
||||||
|
|
||||||
|
if (zone->free == old_block)
|
||||||
|
zone->free = new_block;
|
||||||
|
|
||||||
|
old_block->next_free = NULL;
|
||||||
|
old_block->prev_free = NULL;
|
||||||
|
|
||||||
|
// Newly in_use block metadata
|
||||||
|
old_block->in_use = true;
|
||||||
|
old_block->size = size - sizeof(Block);
|
||||||
|
old_block->sub_size = old_block->size;
|
||||||
|
|
||||||
|
if (zone->used == NULL) {
|
||||||
|
zone->used = old_block;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
old_block->prev_used = NULL;
|
||||||
|
old_block->next_used = zone->used;
|
||||||
|
zone->used->prev_used = old_block;
|
||||||
|
zone->used = old_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the block to use and unset free
|
||||||
|
static void save_block(Zone *head, Block *block, Zone *zone)
|
||||||
|
{
|
||||||
|
zone->free = NULL;
|
||||||
|
block->in_use = true;
|
||||||
|
if (head->used) {
|
||||||
|
head->used->prev_used = block;
|
||||||
|
head->used->prev = block;
|
||||||
|
block->next = head->used;
|
||||||
|
block->next_used = head->used;
|
||||||
|
}
|
||||||
|
head->used = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* size: size needed by the user to get allocated
|
||||||
|
*
|
||||||
|
* First, we init the allocator if it's the first time
|
||||||
|
* Then we search if there is an available block in all
|
||||||
|
* the zones currently mapped
|
||||||
|
* If no block has been found (NULL), we create 1 new zone of
|
||||||
|
* the corresponding type
|
||||||
|
* We then search again for an available block (should not be NULL)
|
||||||
|
* Finally, if type == LARGE, we just have to change the block to used
|
||||||
|
* else, we frag the block to use just what's needed
|
||||||
|
*
|
||||||
|
* ptr: returns the aligned pointer of the block (after the metadata)
|
||||||
|
*/
|
||||||
|
void *kalloc(size_t size)
|
||||||
|
{
|
||||||
|
void *ptr = NULL;
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
kprintf(KERN_WARNING "kalloc: can't kalloc(0)\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the zone we need to search
|
||||||
|
block_type_t type = get_type(size);
|
||||||
|
Zone *head = zones[type];
|
||||||
|
|
||||||
|
// Find an available block in a zone of type "type"
|
||||||
|
Block *available = find_block(head, size);
|
||||||
|
if (available == NULL) {
|
||||||
|
size_t full_size;
|
||||||
|
if (type == LARGE)
|
||||||
|
full_size = size + sizeof(Block) + sizeof(Zone);
|
||||||
|
else
|
||||||
|
full_size = get_zone_size(type);
|
||||||
|
if (new_zone(type, full_size) == -1)
|
||||||
|
return NULL;
|
||||||
|
head = zones[type];
|
||||||
|
available = find_block(head, size);
|
||||||
|
}
|
||||||
|
assert(available != NULL);
|
||||||
|
if (type == LARGE)
|
||||||
|
save_block(head, available, available->zone);
|
||||||
|
else
|
||||||
|
frag_block(available->zone, available, size + sizeof(Block));
|
||||||
|
ptr = available->ptr;
|
||||||
|
return ptr;
|
||||||
|
}
|
115
src/memory/alloc/kfree.c
Normal file
115
src/memory/alloc/kfree.c
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#include "alloc.h"
|
||||||
|
#include "kprintf.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
static void remove_used(Block *to_kfree)
|
||||||
|
{
|
||||||
|
Block *left = to_kfree->prev_used;
|
||||||
|
Block *right = to_kfree->next_used;
|
||||||
|
|
||||||
|
to_kfree->next_used = NULL;
|
||||||
|
to_kfree->prev_used = NULL;
|
||||||
|
|
||||||
|
if (!left && !right) {
|
||||||
|
to_kfree->zone->used = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!left)
|
||||||
|
to_kfree->zone->used = right;
|
||||||
|
else
|
||||||
|
left->next_used = right;
|
||||||
|
if (right)
|
||||||
|
right->prev_used = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If all the blocks of the zone have been kfreed,
|
||||||
|
* we can unmap the zone and delete it from the list of zones
|
||||||
|
*/
|
||||||
|
static int unmap_zone(Zone *zone)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
block_type_t type = zone->type;
|
||||||
|
Zone *left = zone->prev;
|
||||||
|
Zone *right = zone->next;
|
||||||
|
zone->prev = NULL;
|
||||||
|
zone->next = NULL;
|
||||||
|
|
||||||
|
if (!left && !right) {
|
||||||
|
zones[type] = NULL;
|
||||||
|
goto unmap;
|
||||||
|
}
|
||||||
|
if (!left)
|
||||||
|
zones[type] = right;
|
||||||
|
else
|
||||||
|
left->next = right;
|
||||||
|
if (right)
|
||||||
|
right->prev = left;
|
||||||
|
unmap:
|
||||||
|
err = kfree_frame((void *)zone, zone->size);
|
||||||
|
if (err)
|
||||||
|
kprintf(KERN_ERR "error: munmap failed\n");
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the newly kfreed block is next to another previously
|
||||||
|
* kfreed block, merge both of these and update the size
|
||||||
|
*/
|
||||||
|
static Block *merge_blocks(Block *left, Block *right)
|
||||||
|
{
|
||||||
|
if (right->next)
|
||||||
|
right->next->prev = left;
|
||||||
|
if (right->next_free) {
|
||||||
|
right->next_free->prev_free = left;
|
||||||
|
left->next_free = right->next_free;
|
||||||
|
}
|
||||||
|
left->next = right->next;
|
||||||
|
left->size += right->size + sizeof(Block);
|
||||||
|
return (left);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simply add the new block to the list of available blocks
|
||||||
|
static int add_available(Block *available, Block *merged)
|
||||||
|
{
|
||||||
|
Zone *zone = available->zone;
|
||||||
|
if (merged != zone->free && available != zone->free)
|
||||||
|
available->next_free = zone->free;
|
||||||
|
if (zone->free)
|
||||||
|
zone->free->prev_free = available;
|
||||||
|
zone->free = available;
|
||||||
|
if (zone->type == LARGE)
|
||||||
|
return (unmap_zone(zone));
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ptr: pointer to kfree, if the pointer is invalid the kfree()
|
||||||
|
* function will have an undefined behavior (most likely segfault)
|
||||||
|
*
|
||||||
|
* First, we remove the block from the list of in_use blocks
|
||||||
|
* Then, we check if the block needs to be merged with another
|
||||||
|
* neighboring block, if so we replace the previous block by the
|
||||||
|
* newly merged block
|
||||||
|
* Finally, we add the block to the list of available blocks
|
||||||
|
*/
|
||||||
|
void kfree(void *ptr)
|
||||||
|
{
|
||||||
|
if (ptr == NULL)
|
||||||
|
return;
|
||||||
|
Block *to_kfree = (Block *)((size_t)ptr - sizeof(Block));
|
||||||
|
Block *to_merge = NULL;
|
||||||
|
to_kfree->in_use = false;
|
||||||
|
remove_used(to_kfree);
|
||||||
|
if (to_kfree->prev && !to_kfree->prev->in_use) {
|
||||||
|
to_merge = to_kfree;
|
||||||
|
to_kfree = merge_blocks(to_kfree->prev, to_kfree);
|
||||||
|
}
|
||||||
|
if (to_kfree->next && !to_kfree->next->in_use) {
|
||||||
|
to_merge = to_kfree->next;
|
||||||
|
to_kfree = merge_blocks(to_kfree, to_kfree->next);
|
||||||
|
}
|
||||||
|
int err = add_available(to_kfree, to_merge);
|
||||||
|
if (err)
|
||||||
|
kprintf(KERN_ERR "kfree: fatal error\n");
|
||||||
|
}
|
36
src/memory/alloc/krealloc.c
Normal file
36
src/memory/alloc/krealloc.c
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include "alloc.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
// Prototype for kfree and kalloc
|
||||||
|
void kfree(void *ptr);
|
||||||
|
void *kalloc(size_t size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ptr: block to resize (undefined behavior if invalid)
|
||||||
|
* size: size needed by the user to get kreallocated
|
||||||
|
*
|
||||||
|
* If we have a size <= to the previous size, we don't have
|
||||||
|
* to do anything, we just change sub_size for info purposes
|
||||||
|
* and return the same pointer
|
||||||
|
* Else, we allocate a new block and copy the content of
|
||||||
|
* the previous block in the new one and kfree the old block
|
||||||
|
*
|
||||||
|
* ptr: returns the aligned pointer of the kreallocated block
|
||||||
|
*/
|
||||||
|
void *krealloc(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
void *new_ptr = NULL;
|
||||||
|
if (ptr == NULL)
|
||||||
|
return NULL;
|
||||||
|
Block *block = (Block *)((size_t)ptr - sizeof(Block));
|
||||||
|
if (block->size >= size) {
|
||||||
|
block->sub_size = size;
|
||||||
|
return (ptr);
|
||||||
|
}
|
||||||
|
new_ptr = kalloc(size);
|
||||||
|
if (new_ptr == NULL)
|
||||||
|
return NULL;
|
||||||
|
memmove(new_ptr, ptr, block->size);
|
||||||
|
kfree(ptr);
|
||||||
|
return (new_ptr);
|
||||||
|
}
|
34
src/memory/alloc/utils.c
Normal file
34
src/memory/alloc/utils.c
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include "alloc.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
static size_t get_block_size(block_type_t type)
|
||||||
|
{
|
||||||
|
if (type == TINY)
|
||||||
|
return ((PAGES_TINY * PAGE_SIZE) / BPZ - sizeof(Block));
|
||||||
|
if (type == SMALL)
|
||||||
|
return ((PAGES_SMALL * PAGE_SIZE) / BPZ - sizeof(Block));
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
block_type_t get_type(size_t size)
|
||||||
|
{
|
||||||
|
if (size <= get_block_size(TINY))
|
||||||
|
return (TINY);
|
||||||
|
if (size <= get_block_size(SMALL))
|
||||||
|
return (SMALL);
|
||||||
|
return (LARGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t get_zone_size(block_type_t type)
|
||||||
|
{
|
||||||
|
if (type == TINY)
|
||||||
|
return (PAGES_TINY * PAGE_SIZE);
|
||||||
|
if (type == SMALL)
|
||||||
|
return (PAGES_SMALL * PAGE_SIZE);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t align_mem(size_t addr)
|
||||||
|
{
|
||||||
|
return (addr + (MEM_ALIGN - 1)) & ~(MEM_ALIGN - 1);
|
||||||
|
}
|
@ -21,12 +21,14 @@ extern uint32_t end_kernel;
|
|||||||
static uint8_t frame_table[CEIL(MAX_FRAMES, 8)];
|
static uint8_t frame_table[CEIL(MAX_FRAMES, 8)];
|
||||||
static uint32_t remaining_frames = MAX_FRAMES;
|
static uint32_t remaining_frames = MAX_FRAMES;
|
||||||
|
|
||||||
void *kalloc_frame(uint32_t nb_frames)
|
void *kalloc_frame(size_t size)
|
||||||
{
|
{
|
||||||
|
const uint32_t nb_frames = CEIL(size, PAGE_SIZE);
|
||||||
if (nb_frames > remaining_frames) {
|
if (nb_frames > remaining_frames) {
|
||||||
kprintf(KERN_CRIT "Not enough frames (max: %d)\n", MAX_FRAMES);
|
kprintf(KERN_CRIT "Not enough frames (max: %d)\n", MAX_FRAMES);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while (i < MAX_FRAMES) {
|
while (i < MAX_FRAMES) {
|
||||||
size_t free_frames = 1;
|
size_t free_frames = 1;
|
||||||
@ -48,21 +50,23 @@ end:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void kfree_frame(void *frame, uint32_t nb_frames)
|
int kfree_frame(void *frame, size_t size)
|
||||||
{
|
{
|
||||||
|
const uint32_t nb_frames = CEIL(size, PAGE_SIZE);
|
||||||
const uint32_t start = (frame - (void *)&end_kernel) / PAGE_SIZE;
|
const uint32_t start = (frame - (void *)&end_kernel) / PAGE_SIZE;
|
||||||
|
|
||||||
if (start > MAX_FRAMES || frame < (void *)&end_kernel) {
|
if (start > MAX_FRAMES || frame < (void *)&end_kernel) {
|
||||||
kprintf(KERN_WARNING "Address out of range\n");
|
kprintf(KERN_WARNING "Address out of range\n");
|
||||||
return;
|
return -1;
|
||||||
} else if ((uint32_t)frame % PAGE_SIZE) {
|
} else if ((uint32_t)frame % PAGE_SIZE) {
|
||||||
kprintf(KERN_WARNING "Invalid address\n");
|
kprintf(KERN_WARNING "Invalid address\n");
|
||||||
return;
|
return -1;
|
||||||
} else if (start + nb_frames > MAX_FRAMES) {
|
} else if (start + nb_frames > MAX_FRAMES) {
|
||||||
kprintf(KERN_WARNING "Invalid number of frames\n");
|
kprintf(KERN_WARNING "Invalid number of frames\n");
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
for (size_t i = start; i < start + nb_frames; i++)
|
for (size_t i = start; i < start + nb_frames; i++)
|
||||||
SET_FRAME(i, 0);
|
SET_FRAME(i, 0);
|
||||||
remaining_frames += nb_frames;
|
remaining_frames += nb_frames;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,8 @@ void shell_init(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (invalid && screen->line[0])
|
if (invalid && screen->line[0])
|
||||||
kprintf("invalid command: %s\n", screen->line);
|
kprintf(KERN_WARNING "invalid command: %s\n",
|
||||||
|
screen->line);
|
||||||
memset(screen->line, '\0', sizeof(screen->line));
|
memset(screen->line, '\0', sizeof(screen->line));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user