Final refactor, initialize allocator on init

pull/1/head
Felix Kopp 4 years ago
parent fc75cb2014
commit bdf3f008d7
No known key found for this signature in database
GPG Key ID: C478BA0A85F75728

@ -4,6 +4,7 @@
#include <stddef.h>
#include <stdint.h>
#include <arch/at91sam3x8e/interrupt.h>
#include <ardix/malloc.h>
#include <ardix/string.h>
#include <toolchain.h>
@ -15,6 +16,7 @@ extern uint32_t _srelocate; /* relocate (.data) start */
extern uint32_t _erelocate; /* relocate end */
extern uint32_t _szero; /* zero area (.bss) start */
extern uint32_t _ezero; /* zero area end */
/* the entire heap sits in between _ezero and _sstack */
extern uint32_t _sstack; /* stack start */
extern uint32_t _estack; /* stack end */
@ -34,6 +36,12 @@ void irq_reset(void)
(size_t)(&_ezero) - (size_t)(&_szero)
);
/* There is no userspace yet, so the Kernel gets the entire heap for now */
malloc_init(
&_ezero + sizeof(void *),
(size_t)(&_sstack) - (size_t)(&_ezero) - sizeof(void *)
);
/* start the Kernel */
do_bootstrap();
@ -107,7 +115,7 @@ __section(.vectors) const void *exception_table[] = {
&irq_reset, /* reset vector */
NULL, /* reserved */
&irq_hard_fault, /* hard fault */
&irq_mem_fault, /* hemory management fault */
&irq_mem_fault, /* memory management fault */
&irq_bus_fault, /* bus fault */
&irq_usage_fault, /* usage fault */
NULL, /* reserved */

@ -69,29 +69,11 @@ struct list_head {
tmp != (head); \
cursor = tmp, tmp = list_next_entry(tmp, member))
void list_insert(struct list_head *head, struct list_head *new)
{
new->next = head->next;
head->next->prev = new;
new->prev = head;
head->next = new;
}
void list_insert_before(struct list_head *head, struct list_head *new)
{
new->next = head;
head->prev->next = new;
new->prev = head->prev;
head->prev = new;
}
void list_delete(struct list_head *head)
{
head->next->prev = head->prev;
head->prev->next = head->next;
}
void list_insert(struct list_head *head, struct list_head *new);
void list_insert_before(struct list_head *head, struct list_head *new);
void list_delete(struct list_head *head);
/*
* Copyright (c) 2020 Felix Kopp <sandtler@sandtler.club>

@ -4,7 +4,7 @@
#pragma once
#include <ardix/types.h>
#include <ardix/list.h>
#include <toolchain.h>
/**
* Allocate `size` bytes of memory *w/out initializing it*.
@ -24,6 +24,18 @@ void *malloc(size_t size);
*/
void *calloc(size_t nmemb, size_t size);
/**
* Allocate at least `size` bytes of memory and initialize it to zero.
*
* @param size The amount of bytes to allocate.
* @return A pointer to the beginning of the memory area, or `NULL` if
* `size` was 0 or there is not enough free memory left.
*/
__always_inline void *zalloc(size_t size)
{
return calloc(1, size);
}
/**
* Free a previously allocated memory region.
* Passing `NULL` has no effect.

@ -27,5 +27,6 @@ ARDIX_LIB_PWD := $(PWD)/lib
ARDIX_SOURCES += \
$(ARDIX_LIB_PWD)/ctype.c \
$(ARDIX_LIB_PWD)/list.c \
$(ARDIX_LIB_PWD)/malloc.c \
$(ARDIX_LIB_PWD)/string.c

@ -0,0 +1,53 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* See the end of this file for copyright, licensing, and warranty information. */
#include <ardix/list.h>
void list_insert(struct list_head *head, struct list_head *new)
{
new->next = head->next;
head->next->prev = new;
new->prev = head;
head->next = new;
}
void list_insert_before(struct list_head *head, struct list_head *new)
{
new->next = head;
head->prev->next = new;
new->prev = head->prev;
head->prev = new;
}
void list_delete(struct list_head *head)
{
head->next->prev = head->prev;
head->prev->next = head->next;
}
/*
* Copyright (c) 2020 Felix Kopp <sandtler@sandtler.club>
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

@ -2,7 +2,7 @@
/* See the end of this file for copyright, licensing, and warranty information. */
#include <ardix/list.h>
#include <ardix/mem.h>
#include <ardix/malloc.h>
#include <ardix/string.h>
#include <ardix/types.h>
@ -55,7 +55,7 @@
struct memblk {
/**
* The block's effectively usable size, i.e. the total block size minus
* `2 * MEMBLK_HDR_SIZE_LENGTH`.
* `2 * MEMBLK_SIZE_LENGTH`.
*
* This size will also be written to the very end of the block, just after
* the last usable address. Additionally, since blocks are always aligned
@ -75,21 +75,24 @@ struct memblk {
};
/** The length of the `size` member in `struct memblk`. */
#define MEMBLK_HDR_SIZE_LENGTH (sizeof( typeof(((struct memblk *)0)->size) ))
#define MEMBLK_OVERHEAD (2 * MEMBLK_HDR_SIZE_LENGTH)
#define MEMBLK_SIZE_LENGTH (sizeof( typeof(((struct memblk *)0)->size) ))
/** Total overhead per allocated block in bytes (2 * size_t). */
#define MEMBLK_OVERHEAD (2 * MEMBLK_SIZE_LENGTH)
/** Minimum effective allocation size */
/** Minimum effective allocation size (and all sizes must be a multiple of this one). */
#define MIN_BLKSZ (sizeof(struct list_head))
/** The list of free blocks, ordered ascending by size. */
#define without_lsb(x) (((x) >> 1u) << 1u)
/** The list of free blocks, ordered by ascending size. */
LIST_HEAD(memblk_free_list);
static void memblk_set_size(struct memblk *block, size_t size)
{
block->size = size;
void *endptr = block;
endptr += MEMBLK_HDR_SIZE_LENGTH;
endptr += ((size >> 1u) << 1u); /* discard the allocated bit */
endptr += MEMBLK_SIZE_LENGTH;
endptr += without_lsb(size); /* discard the allocated bit */
*(size_t *)(endptr) = size;
}
@ -106,9 +109,9 @@ static void memblk_set_size(struct memblk *block, size_t size)
static struct memblk *memblk_split(struct memblk *blk, size_t size)
{
struct memblk *cursor;
struct memblk *newblk = (void *)blk + MEMBLK_OVERHEAD + ((size >> 1u) << 1u);
struct memblk *newblk = (void *)blk + MEMBLK_OVERHEAD + without_lsb(size);
memblk_set_size(newblk, blk->size - MEMBLK_OVERHEAD - ((size >> 1u) << 1u));
memblk_set_size(newblk, blk->size - MEMBLK_OVERHEAD - without_lsb(size));
memblk_set_size(blk, size);
list_for_each_entry_reverse(&blk->list, cursor, list) {
@ -131,6 +134,7 @@ void malloc_init(void *heap, size_t size)
* dispatching/handling routines, we should do that here.
*/
if (list_is_empty(&memblk_free_list)) {
memset(heap, 0, size);
memblk_set_size(blk, size - MEMBLK_OVERHEAD);
list_insert(&memblk_free_list, &blk->list);
}
@ -173,7 +177,7 @@ void *malloc(size_t size)
list_delete(&blk->list);
/* Keep the size field intact */
return ((void *)blk) + MEMBLK_HDR_SIZE_LENGTH;
return ((void *)blk) + MEMBLK_SIZE_LENGTH;
}
__attribute__((malloc))
@ -190,7 +194,7 @@ void *calloc(size_t nmemb, size_t size)
/** Merge two neighboring free blocks to one big block */
static void memblk_merge(struct memblk *lblk, struct memblk *hblk)
{
size_t *endsz = (void *)hblk + hblk->size + MEMBLK_HDR_SIZE_LENGTH;
size_t *endsz = (void *)hblk + hblk->size + MEMBLK_SIZE_LENGTH;
lblk->size = lblk->size + hblk->size + MEMBLK_OVERHEAD;
*endsz = lblk->size;
}
@ -198,7 +202,7 @@ static void memblk_merge(struct memblk *lblk, struct memblk *hblk)
void free(void *ptr)
{
struct memblk *tmp;
struct memblk *blk = ptr - MEMBLK_HDR_SIZE_LENGTH;
struct memblk *blk = ptr - MEMBLK_SIZE_LENGTH;
size_t *neighsz;
if (ptr == NULL)
@ -207,7 +211,7 @@ void free(void *ptr)
if ((blk->size & 0x1u) == 0)
return; /* TODO: Raise exception on double-free */
memblk_set_size(blk, (blk->size >> 1u) << 1u /* clear allocated bit */);
memblk_set_size(blk, without_lsb(blk->size));
/* check if our higher/right neighbor is allocated and merge if it is not */
neighsz = (void *)blk + MEMBLK_OVERHEAD + blk->size;
@ -218,9 +222,9 @@ void free(void *ptr)
}
/* same thing for the lower/left block */
neighsz = (void *)blk - MEMBLK_HDR_SIZE_LENGTH;
neighsz = (void *)blk - MEMBLK_SIZE_LENGTH;
if ((*neighsz & 0x1u) == 0) {
tmp = (void *)neighsz - *neighsz - MEMBLK_HDR_SIZE_LENGTH;
tmp = (void *)neighsz - *neighsz - MEMBLK_SIZE_LENGTH;
memblk_merge(tmp, blk);
list_delete(&tmp->list);
blk = tmp; /* discard the higher (now partial) block */

Loading…
Cancel
Save