mm: make malloc and free system calls
This is required because the heap is shared among all tasks and protected using a mutex which only works in kernel space.
This commit is contained in:
parent
040b5af5d6
commit
fb9ec2a8bc
20 changed files with 214 additions and 72 deletions
|
@ -3,13 +3,32 @@
|
|||
#pragma once
|
||||
|
||||
#include <config.h>
|
||||
#include <toolchain.h>
|
||||
|
||||
#if 1
|
||||
|
||||
#ifdef DEBUG
|
||||
# define __breakpoint __asm__ volatile("bkpt")
|
||||
#else
|
||||
# define __breakpoint
|
||||
# define NDEBUG
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define __breakpoint
|
||||
#endif
|
||||
|
||||
__always_inline int __is_kernel(void) {
|
||||
int psr_val;
|
||||
|
||||
__asm__ volatile(
|
||||
" mrs %0, psr \n"
|
||||
: "=&r" (psr_val)
|
||||
);
|
||||
|
||||
return psr_val & 0x01ff; /* bits 8-0 hold ISR_NUMBER */
|
||||
}
|
||||
|
||||
/*
|
||||
* This file is part of Ardix.
|
||||
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#define ARCH_SYS_read 0
|
||||
#define ARCH_SYS_write 1
|
||||
#define ARCH_SYS_sleep 2
|
||||
#define ARCH_SYS_malloc 3
|
||||
#define ARCH_SYS_free 4
|
||||
|
||||
/*
|
||||
* This file is part of Ardix.
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include <toolchain.h>
|
||||
|
||||
/**
|
||||
* @defgroup malloc Memory Management
|
||||
* @defgroup kmalloc Kernel Memory Management
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
@ -15,18 +15,18 @@
|
|||
* @brief Allocate `size` bytes of memory *w/out initializing it*.
|
||||
*
|
||||
* This method may block if an allocation is already taking place.
|
||||
* Use `atomic_malloc()` if you are in kernel space and in atomic context.
|
||||
* Use `atomic_kmalloc()` if you are in kernel space and in atomic context.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
__shared __malloc(free, 1) void *malloc(size_t size);
|
||||
__malloc(kfree, 1) void *kmalloc(size_t size);
|
||||
|
||||
/**
|
||||
* @brief Allocate `size` bytes of memory *w/out initializing it*.
|
||||
*
|
||||
* Unlike `malloc()`, this method is guaranteed not to sleep. It does this by
|
||||
* Unlike `kmalloc()`, this method is guaranteed not to sleep. It does this by
|
||||
* using a completely separate, smaller heap. Only use this if you already are
|
||||
* in atomic context, like when in an irq.
|
||||
*
|
||||
|
@ -34,18 +34,7 @@ __shared __malloc(free, 1) void *malloc(size_t size);
|
|||
* @return A pointer to the beginning of the memory area, or `NULL` if
|
||||
* `size` was 0 or there is not enough free memory left.
|
||||
*/
|
||||
__malloc(free, 1) void *atomic_malloc(size_t size);
|
||||
|
||||
/**
|
||||
* @brief Allocate an array and initialize the memory to zeroes.
|
||||
* The allocated size will be at least `nmemb * size`.
|
||||
* If the multiplication would overflow, the allocation fails.
|
||||
*
|
||||
* @param nmemb The amount of members.
|
||||
* @param size The size of an individual member.
|
||||
* @return A pointer to the zeroed-out memory, or `NULL` if OOM.
|
||||
*/
|
||||
__shared __malloc(free, 1) void *calloc(size_t nmemb, size_t size);
|
||||
__malloc(kfree, 1) void *atomic_kmalloc(size_t size);
|
||||
|
||||
/**
|
||||
* @brief Free a previously allocated memory region.
|
||||
|
@ -53,12 +42,12 @@ __shared __malloc(free, 1) void *calloc(size_t nmemb, size_t size);
|
|||
*
|
||||
* @param ptr The pointer, as returned by `malloc`/`calloc`.
|
||||
*/
|
||||
__shared void free(void *ptr);
|
||||
|
||||
/** @} */
|
||||
void kfree(void *ptr);
|
||||
|
||||
/** Initialize the memory allocator, this is only called by the bootloader on early bootstrap. */
|
||||
void malloc_init(void *heap, size_t size);
|
||||
void kmalloc_init(void *heap, size_t size);
|
||||
|
||||
/** @} */
|
||||
|
||||
/*
|
||||
* This file is part of Ardix.
|
||||
|
|
|
@ -13,6 +13,8 @@ enum syscall {
|
|||
SYS_read = ARCH_SYS_read,
|
||||
SYS_write = ARCH_SYS_write,
|
||||
SYS_sleep = ARCH_SYS_sleep,
|
||||
SYS_malloc = ARCH_SYS_malloc,
|
||||
SYS_free = ARCH_SYS_free,
|
||||
NSYSCALLS
|
||||
};
|
||||
|
||||
|
|
24
include/stdassert.h
Normal file
24
include/stdassert.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/* See the end of this file for copyright, license, and warranty information. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <arch/debug.h>
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define assert(expr)
|
||||
#else
|
||||
# define assert(expr) if (!(expr)) { __breakpoint; }
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file is part of Ardix.
|
||||
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
|
||||
*
|
||||
* Ardix is non-violent software: you may only use, redistribute,
|
||||
* and/or modify it under the terms of the CNPLv6+ as found in
|
||||
* the LICENSE file in the source code root directory or at
|
||||
* <https://git.pixie.town/thufie/CNPL>.
|
||||
*
|
||||
* Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
|
||||
* permitted by applicable law. See the CNPLv6+ for details.
|
||||
*/
|
58
include/stdlib.h
Normal file
58
include/stdlib.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* See the end of this file for copyright, license, and warranty information. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ardix/types.h>
|
||||
#include <toolchain.h>
|
||||
|
||||
/**
|
||||
* @defgroup malloc Memory Management
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Allocate `size` bytes of memory *w/out initializing it*.
|
||||
*
|
||||
* This method may block if an allocation is already taking place.
|
||||
* Use `atomickmalloc()` if you are in kernel space and in atomic context.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
__shared __malloc(free, 1) void *malloc(size_t size);
|
||||
|
||||
/**
|
||||
* @brief Allocate an array and initialize the memory to zeroes.
|
||||
* The allocated size will be at least `nmemb * size`.
|
||||
* If the multiplication would overflow, the allocation fails.
|
||||
*
|
||||
* @param nmemb The amount of members.
|
||||
* @param size The size of an individual member.
|
||||
* @return A pointer to the zeroed-out memory, or `NULL` if OOM.
|
||||
*/
|
||||
__malloc(free, 1) void *calloc(size_t nmemb, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Free a previously allocated memory region.
|
||||
* Passing `NULL` has no effect.
|
||||
*
|
||||
* @param ptr The pointer, as returned by `malloc`/`calloc`.
|
||||
*/
|
||||
__shared void free(void *ptr);
|
||||
|
||||
/** @} */
|
||||
|
||||
/*
|
||||
* This file is part of Ardix.
|
||||
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
|
||||
*
|
||||
* Ardix is non-violent software: you may only use, redistribute,
|
||||
* and/or modify it under the terms of the CNPLv6+ as found in
|
||||
* the LICENSE file in the source code root directory or at
|
||||
* <https://git.pixie.town/thufie/CNPL>.
|
||||
*
|
||||
* Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
|
||||
* permitted by applicable law. See the CNPLv6+ for details.
|
||||
*/
|
|
@ -15,6 +15,7 @@ target_sources(ardix_kernel PRIVATE
|
|||
kent.c
|
||||
kevent.c
|
||||
main.c
|
||||
mm.c
|
||||
mutex.c
|
||||
ringbuf.c
|
||||
sched.c
|
||||
|
|
|
@ -14,7 +14,7 @@ struct kent *devices_kent = NULL;
|
|||
static void devices_destroy(struct kent *kent)
|
||||
{
|
||||
/* should never be executed because the root devices kent is immortal */
|
||||
free(kent);
|
||||
kfree(kent);
|
||||
}
|
||||
|
||||
/** Initialize the devices subsystem. */
|
||||
|
@ -23,7 +23,7 @@ int devices_init(void)
|
|||
if (devices_kent != NULL)
|
||||
return -EEXIST;
|
||||
|
||||
devices_kent = malloc(sizeof(*devices_kent));
|
||||
devices_kent = kmalloc(sizeof(*devices_kent));
|
||||
if (devices_kent == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -36,7 +36,7 @@ int devices_init(void)
|
|||
static void device_destroy(struct kent *kent)
|
||||
{
|
||||
struct device *dev = kent_to_device(kent);
|
||||
free(dev);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
int device_init(struct device *dev)
|
||||
|
@ -54,12 +54,12 @@ static void device_kevent_destroy(struct kent *kent)
|
|||
{
|
||||
struct kevent *event = container_of(kent, struct kevent, kent);
|
||||
struct device_kevent *device_kevent = container_of(event, struct device_kevent, kevent);
|
||||
free(device_kevent);
|
||||
kfree(device_kevent);
|
||||
}
|
||||
|
||||
struct device_kevent *device_kevent_create(struct device *device, enum device_kevent_flags flags)
|
||||
{
|
||||
struct device_kevent *event = atomic_malloc(sizeof(*event));
|
||||
struct device_kevent *event = atomic_kmalloc(sizeof(*event));
|
||||
if (event == NULL)
|
||||
return NULL;
|
||||
|
||||
|
@ -70,7 +70,7 @@ struct device_kevent *device_kevent_create(struct device *device, enum device_ke
|
|||
event->kevent.kent.destroy = device_kevent_destroy;
|
||||
int err = kent_init(&event->kevent.kent);
|
||||
if (err) {
|
||||
free(event);
|
||||
kfree(event);
|
||||
event = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
static void dmabuf_destroy(struct kent *kent)
|
||||
{
|
||||
struct dmabuf *buf = kent_to_dmabuf(kent);
|
||||
free(buf);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
struct dmabuf *dmabuf_create(struct device *dev, size_t len)
|
||||
|
@ -22,7 +22,7 @@ struct dmabuf *dmabuf_create(struct device *dev, size_t len)
|
|||
* allocation needs to be atomic because the buffer might be
|
||||
* free()d from within an irq handler which cannot sleep
|
||||
*/
|
||||
struct dmabuf *buf = atomic_malloc(sizeof(*buf) + len);
|
||||
struct dmabuf *buf = atomic_kmalloc(sizeof(*buf) + len);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
|
@ -31,7 +31,7 @@ struct dmabuf *dmabuf_create(struct device *dev, size_t len)
|
|||
|
||||
err = kent_init(&buf->kent);
|
||||
if (err) {
|
||||
free(buf);
|
||||
kfree(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ static void file_destroy(struct kent *kent)
|
|||
fdtab[file->fd] = NULL;
|
||||
mutex_unlock(&fdtab_lock);
|
||||
|
||||
free(file);
|
||||
kfree(file);
|
||||
}
|
||||
|
||||
struct file *file_create(struct device *device, enum file_type type, int *err)
|
||||
|
@ -41,7 +41,7 @@ struct file *file_create(struct device *device, enum file_type type, int *err)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
f = malloc(sizeof(*f));
|
||||
f = kmalloc(sizeof(*f));
|
||||
if (f == NULL) {
|
||||
*err = -ENOMEM;
|
||||
mutex_unlock(&fdtab_lock);
|
||||
|
@ -102,7 +102,7 @@ static int io_device_kevent_listener(struct kevent *event, void *_extra)
|
|||
return KEVENT_CB_NONE;
|
||||
|
||||
extra->task->state = TASK_QUEUE;
|
||||
free(extra);
|
||||
kfree(extra);
|
||||
file_put(extra->file);
|
||||
kent_put(&extra->task->kent);
|
||||
return KEVENT_CB_LISTENER_DEL | KEVENT_CB_STOP;
|
||||
|
@ -114,7 +114,7 @@ static int iowait_device(struct file *file, enum device_kevent_flags flags)
|
|||
kent_get(¤t->kent);
|
||||
|
||||
/* this must be atomic because event listeners can't sleep but need to call free() */
|
||||
struct io_device_kevent_extra *extra = atomic_malloc(sizeof(*extra));
|
||||
struct io_device_kevent_extra *extra = atomic_kmalloc(sizeof(*extra));
|
||||
if (extra == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -201,12 +201,12 @@ static void file_kevent_destroy(struct kent *kent)
|
|||
{
|
||||
struct kevent *kevent = container_of(kent, struct kevent, kent);
|
||||
struct file_kevent *file_kevent = container_of(kevent, struct file_kevent, kevent);
|
||||
free(file_kevent);
|
||||
kfree(file_kevent);
|
||||
}
|
||||
|
||||
struct file_kevent *file_kevent_create(struct file *f, enum file_kevent_flags flags)
|
||||
{
|
||||
struct file_kevent *event = atomic_malloc(sizeof(*event));
|
||||
struct file_kevent *event = atomic_kmalloc(sizeof(*event));
|
||||
if (event == NULL)
|
||||
return NULL;
|
||||
|
||||
|
@ -217,7 +217,7 @@ struct file_kevent *file_kevent_create(struct file *f, enum file_kevent_flags fl
|
|||
event->kevent.kent.destroy = file_kevent_destroy;
|
||||
int err = kent_init(&event->kevent.kent);
|
||||
if (err != 0) {
|
||||
free(event);
|
||||
kfree(event);
|
||||
event = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ long sys_read(int fd, __user void *buf, size_t len)
|
|||
if (f == NULL)
|
||||
return -EBADF;
|
||||
|
||||
copy = malloc(len);
|
||||
copy = kmalloc(len);
|
||||
if (copy == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -26,7 +26,7 @@ long sys_read(int fd, __user void *buf, size_t len)
|
|||
if (ret >= 0)
|
||||
ret = copy_to_user(buf, copy, ret);
|
||||
|
||||
free(copy);
|
||||
kfree(copy);
|
||||
file_put(f);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ long sys_write(int fd, __user const void *buf, size_t len)
|
|||
if (f == NULL)
|
||||
return -EBADF;
|
||||
|
||||
copy = malloc(len);
|
||||
copy = kmalloc(len);
|
||||
if (copy == NULL) {
|
||||
file_put(f);
|
||||
return -ENOMEM;
|
||||
|
@ -27,7 +27,7 @@ long sys_write(int fd, __user const void *buf, size_t len)
|
|||
len = copy_from_user(copy, buf, len);
|
||||
ret = file_write(f, copy, len);
|
||||
|
||||
free(copy);
|
||||
kfree(copy);
|
||||
file_put(f);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ static inline void process_single_queue(struct kevent_queue *queue, struct list_
|
|||
|
||||
if (cb_ret & KEVENT_CB_LISTENER_DEL) {
|
||||
list_delete(&listener->link);
|
||||
free(listener);
|
||||
kfree(listener);
|
||||
}
|
||||
|
||||
if (cb_ret & KEVENT_CB_STOP)
|
||||
|
@ -102,7 +102,6 @@ void kevents_process(void)
|
|||
process_single_queue(&kev_queues[i], &kev_listeners[i]);
|
||||
}
|
||||
|
||||
/* called from irq context only */
|
||||
void kevent_dispatch(struct kevent *event)
|
||||
{
|
||||
struct kevent_queue *queue = &kev_queues[event->kind];
|
||||
|
@ -138,7 +137,7 @@ struct kevent_listener *kevent_listener_add(enum kevent_kind kind,
|
|||
int (*cb)(struct kevent *, void *),
|
||||
void *extra)
|
||||
{
|
||||
struct kevent_listener *listener = malloc(sizeof(*listener));
|
||||
struct kevent_listener *listener = kmalloc(sizeof(*listener));
|
||||
|
||||
if (listener != NULL) {
|
||||
listener->cb = cb;
|
||||
|
@ -158,7 +157,7 @@ void kevent_listener_del(struct kevent_listener *listener)
|
|||
list_delete(&listener->link);
|
||||
mutex_unlock(&kev_listeners_lock);
|
||||
|
||||
free(listener);
|
||||
kfree(listener);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
* header containing its size w/out overhead; free blocks additionally have a
|
||||
* `struct list_head` after that in order to keep track of where the free blocks
|
||||
* are. This list is ordered by size ascendingly, so we can directly take the
|
||||
* first sufficiently sized block when iterating over the list in `malloc()`.
|
||||
* first sufficiently sized block when iterating over the list in kmalloc()`.
|
||||
*
|
||||
* Additionally, the effective block size is copied to the very end of the block
|
||||
* (directly after the last usable address) in order to be able to find a
|
||||
|
@ -106,7 +106,7 @@ struct memblk {
|
|||
/** @brief If the block is allocated, this will be overwritten */
|
||||
struct list_head list;
|
||||
|
||||
/** @brief Used as the return value for `malloc()` */
|
||||
/** @brief Used as the return value for kmalloc()` */
|
||||
uint8_t data[0];
|
||||
/** @brief Used to get the copy of the size field at the end of the block */
|
||||
size_t endsz[0];
|
||||
|
@ -164,7 +164,18 @@ static struct memblk *blk_try_merge(struct list_head *heap, struct memblk *blk);
|
|||
/** @brief Cut a slice from a free block and return the slice. */
|
||||
static struct memblk *blk_slice(struct list_head *heap, struct memblk *bottom, size_t bottom_size);
|
||||
|
||||
void malloc_init(void *heap, size_t size)
|
||||
long sys_malloc(size_t size)
|
||||
{
|
||||
void *ptr = kmalloc(size);
|
||||
return *(long *)&ptr;
|
||||
}
|
||||
|
||||
void sys_free(void *ptr)
|
||||
{
|
||||
kfree(ptr);
|
||||
}
|
||||
|
||||
void kmalloc_init(void *heap, size_t size)
|
||||
{
|
||||
memset(heap, 0, size);
|
||||
|
||||
|
@ -191,7 +202,7 @@ void malloc_init(void *heap, size_t size)
|
|||
atomic_heap_free = blk_get_size(atomic_block);
|
||||
}
|
||||
|
||||
void *malloc(size_t size)
|
||||
void *kmalloc(size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return NULL; /* as per POSIX */
|
||||
|
@ -230,7 +241,7 @@ void *malloc(size_t size)
|
|||
return ptr;
|
||||
}
|
||||
|
||||
void *atomic_malloc(size_t size)
|
||||
void *atomic_kmalloc(size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
@ -260,23 +271,7 @@ void *atomic_malloc(size_t size)
|
|||
return ptr;
|
||||
}
|
||||
|
||||
void *calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
size_t total = nmemb * size;
|
||||
|
||||
/* check for overflow as mandated by POSIX */
|
||||
if (size != 0 && total / size != nmemb)
|
||||
return NULL;
|
||||
|
||||
void *ptr = malloc(total);
|
||||
|
||||
if (ptr != NULL)
|
||||
memset(ptr, 0, total);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void free(void *ptr)
|
||||
void kfree(void *ptr)
|
||||
{
|
||||
if (ptr == NULL)
|
||||
return; /* as per POSIX.1-2008 */
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
struct ringbuf *ringbuf_create(size_t size)
|
||||
{
|
||||
struct ringbuf *buf = malloc(sizeof(*buf) + size);
|
||||
struct ringbuf *buf = kmalloc(sizeof(*buf) + size);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
|
@ -24,7 +24,7 @@ struct ringbuf *ringbuf_create(size_t size)
|
|||
|
||||
inline void ringbuf_destroy(struct ringbuf *buf)
|
||||
{
|
||||
free(buf);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
size_t ringbuf_read(void *dest, struct ringbuf *buf, size_t len)
|
||||
|
|
|
@ -57,7 +57,7 @@ static void task_destroy(struct kent *kent)
|
|||
{
|
||||
struct task *task = container_of(kent, struct task, kent);
|
||||
tasks[task->pid] = NULL;
|
||||
free(task);
|
||||
kfree(task);
|
||||
}
|
||||
|
||||
int sched_init(void)
|
||||
|
|
|
@ -13,6 +13,8 @@ long (*const sys_table[NSYSCALLS])(sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
|
|||
sys_table_entry(SYS_read, sys_read),
|
||||
sys_table_entry(SYS_write, sys_write),
|
||||
sys_table_entry(SYS_sleep, sys_sleep),
|
||||
sys_table_entry(SYS_malloc, sys_malloc),
|
||||
sys_table_entry(SYS_free, sys_free),
|
||||
};
|
||||
|
||||
long sys_stub(void)
|
||||
|
|
|
@ -10,8 +10,8 @@ target_sources(ardix_lib PRIVATE
|
|||
ctype.c
|
||||
errno.c
|
||||
list.c
|
||||
malloc.c
|
||||
printf.c
|
||||
stdlib.c
|
||||
string.c
|
||||
unistd.c
|
||||
)
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
/* See the end of this file for copyright, license, and warranty information. */
|
||||
|
||||
#include <ardix/malloc.h>
|
||||
|
||||
#include <errno.h>
|
||||
/* Using GCC's stdarg.h is recommended even with -nodefaultlibs and -fno-builtin */
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
|
52
lib/stdlib.c
Normal file
52
lib/stdlib.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
/* See the end of this file for copyright, license, and warranty information. */
|
||||
|
||||
#include <ardix/syscall.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
* kmalloc() and free() are system calls in Ardix because the heap is shared
|
||||
* among all tasks and locked using a mutex. If the lock is already claimed,
|
||||
* the `mutex_lock()` routine will suspend the current task until the lock
|
||||
* becomes available to the current process. However, this can only happen
|
||||
* when we already are in kernel space.
|
||||
*/
|
||||
|
||||
void *malloc(size_t size)
|
||||
{
|
||||
if (size == 0) {
|
||||
return NULL;
|
||||
} else {
|
||||
long int intptr = syscall(SYS_malloc, (sysarg_t)size);
|
||||
return *(void **)&intptr;
|
||||
}
|
||||
}
|
||||
|
||||
void *calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
size_t total = nmemb * size;
|
||||
if (nmemb != 0 && total / nmemb != size)
|
||||
return NULL; /* overflow check as mandated by POSIX.1 */
|
||||
long int intptr = syscall(SYS_malloc, (sysarg_t)total);
|
||||
return *(void **)&intptr;
|
||||
}
|
||||
|
||||
void free(void *ptr)
|
||||
{
|
||||
if (ptr != NULL)
|
||||
syscall(SYS_free, (sysarg_t)ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* This file is part of Ardix.
|
||||
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
|
||||
*
|
||||
* Ardix is non-violent software: you may only use, redistribute,
|
||||
* and/or modify it under the terms of the CNPLv6+ as found in
|
||||
* the LICENSE file in the source code root directory or at
|
||||
* <https://git.pixie.town/thufie/CNPL>.
|
||||
*
|
||||
* Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
|
||||
* permitted by applicable law. See the CNPLv6+ for details.
|
||||
*/
|
Loading…
Reference in a new issue