diff --git a/Makefile b/Makefile index 3fbba85..b316fc2 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,7 @@ quickstart: KERNEL_OBJ := \ kern/entry.o \ kern/start.o \ + kern/libkern/freelist.o \ kern/libkern/string.o \ kern/libkern/proc.o \ kern/libkern/uart.o \ diff --git a/kern/libkern/freelist.c b/kern/libkern/freelist.c new file mode 100644 index 0000000..cba0b1f --- /dev/null +++ b/kern/libkern/freelist.c @@ -0,0 +1,117 @@ +#include "freelist.h" +#include "stddef.h" +#include +#include +#include +#include + +/* Fiddle these around according to your need. */ +#ifdef FREELIST_NOALIGN +#define ALIGN(x) (x) +#else // FREELIST_NOALIGN + +/* Align to nearest multiple of sizeof(void*) */ +static inline size_t align_up(size_t n) { + return (n + sizeof(void *) - 1) & ~(sizeof(void *) - 1); +} + +#define ALIGN(x) (align_up(x)) +#endif // FREELIST_NOALIGN + +/* Initialize the FreeList */ +int fl_init(FreeList *fl, uintptr_t start, uintptr_t end, size_t itemsize) { + size_t size = ALIGN(itemsize + sizeof(FreeListBlock)); + + if (!fl || end <= start) + return EXIT_FAILURE; + + fl->start = start; + fl->end = end; + fl->size = size; + fl->allocated = 0; + + FreeListBlock *block = (FreeListBlock *)start; + for (size_t i = 0; i < fl_capacity(fl); i++) { + block->next = (FreeListBlock *)((void *)block + size); + block->block_state = FL_FREE; + block = block->next; + } + + block->next = NULL; + + fl->free = (FreeListBlock *)start; + return EXIT_SUCCESS; +} + +/* Allocate some memory from the FreeList */ +void *fl_alloc(FreeList *fl) { + if (!fl->free || fl->free->block_state != FL_FREE) + return NULL; + + FreeListBlock *m = fl->free; + m->block_state = FL_USED; + + fl->free = fl->free->next; + fl->allocated++; + + return ((void *)m) + sizeof(FreeListBlock); +} + +/* Return some memory to the FreeList */ +int fl_free(FreeList *fl, void *ptr) { + if (!fl_is_managed(fl, ptr)) { + return EXIT_FAILURE; /* We cant free memory we do not own */ + } + + FreeListBlock *block = (FreeListBlock *)((uintptr_t)ptr - sizeof(FreeListBlock)); + + if (block->block_state != FL_USED) { + return EXIT_FAILURE; /* Block must be used */ + } + + block->block_state = FL_FREE; + block->next = fl->free; + fl->free = block; + fl->allocated--; + + return EXIT_SUCCESS; +} + +/* Returns how many slots are occupied */ +size_t fl_allocated(FreeList *fl) { + return fl->allocated; +} + +/* Returns how many free slots are available (O(1)) */ +size_t fl_available(FreeList *fl) { + return fl_capacity(fl) - fl->allocated; +} + +/* Returns the total amount of items the freelist will hold */ +size_t fl_capacity(FreeList *fl) { + return (fl->end - fl->start) / fl->size; +} + +/* Check if a piece of memory is managed by the FreeList */ +int fl_is_managed(FreeList *fl, void *ptr) { + return ((uintptr_t)ptr >= fl->start && (uintptr_t)ptr < fl->end); +} + +/* Returns the ratio of metadata versus data as a scalar in range 0..1 */ +float fl_utilization(FreeList *fl, size_t itemsize) { + return (float)itemsize / fl->size; +} + +/* Walks the free pages/slots, returns total count (O(n), given no cycles) */ +size_t fl_check(FreeList *fl) { + int avail = 0; + FreeListBlock *cursor = fl->free; + + while (cursor->next != NULL) { + avail++; + assert(cursor->block_state == FL_FREE); + cursor = cursor->next; + } + + return avail; +} diff --git a/kern/libkern/freelist.h b/kern/libkern/freelist.h new file mode 100644 index 0000000..885b58a --- /dev/null +++ b/kern/libkern/freelist.h @@ -0,0 +1,34 @@ +#ifndef FREELIST_H +#define FREELIST_H + +#include +#include +#include + +#define FL_FREE ((uint8_t)0x00) +#define FL_USED ((uint8_t)0x01) + +typedef struct FreeListBlock { + struct FreeListBlock *next; + uint8_t block_state; +} FreeListBlock; + +typedef struct { + uintptr_t start; + uintptr_t end; + FreeListBlock *free; + size_t size; + size_t allocated; +} FreeList; + +int fl_init(FreeList *fl, uintptr_t start, uintptr_t end, size_t itemsize); +int fl_free(FreeList *fl, void *ptr); +int fl_is_managed(FreeList *fl, void *ptr); +void *fl_alloc(FreeList *fl); +size_t fl_check(FreeList *fl); +size_t fl_allocated(FreeList *fl); +size_t fl_available(FreeList *fl); +size_t fl_capacity(FreeList *fl); +float fl_utilization(FreeList *fl, size_t itemsize); + +#endif // FREELIST_H diff --git a/kern/libkern/string.c b/kern/libkern/string.c index 308292f..0d37792 100644 --- a/kern/libkern/string.c +++ b/kern/libkern/string.c @@ -178,3 +178,20 @@ size_t strnlen(const char *s, size_t maxlen) { } return len; } + +int strncmp(const char *p, const char *q, u32 n) { + while (n > 0 && *p && *p == *q) n--, p++, q++; + if (n == 0) + return 0; + return (u8)*p - (u8)*q; +} + +char *strncpy(char *s, const char *t, int n) { + char *os; + + os = s; + while (n-- > 0 && (*s++ = *t++) != 0) { + } + while (n-- > 0) *s++ = 0; + return os; +} diff --git a/kern/libkern/string.h b/kern/libkern/string.h index bd152e3..7254a3c 100644 --- a/kern/libkern/string.h +++ b/kern/libkern/string.h @@ -31,13 +31,14 @@ size_t strlen(const char *s); /** Return length of string `s`, up to a max of `maxlen` bytes */ size_t strnlen(const char *s, size_t maxlen); +int strncmp(const char *p, const char *q, u32 n); + +char *strncpy(char *s, const char *t, int n); + // TODO: These: /* int strcmp(const char *s1, const char *s2); -int strncmp(const char *s1, const char *s2, size_t n); - char *strcpy(char *dst, const char *src); -char *strncpy(char *dst, const char *src, size_t n); char *strchr(const char *s, int c); char *strrchr(const char *s, int c); diff --git a/kern/libkern/util.h b/kern/libkern/util.h index ffb9cf2..24df71d 100644 --- a/kern/libkern/util.h +++ b/kern/libkern/util.h @@ -4,6 +4,7 @@ /* * Give hints to the compiler for branch prediction optimization. */ +#include #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 2)) #define likely(c) (__builtin_expect(!!(c), 1)) #define unlikely(c) (__builtin_expect(!!(c), 0)) @@ -12,4 +13,16 @@ #define unlikely(c) (c) #endif +/* Round up to nearest power of two */ +static inline uint32_t next_power_of_two(uint32_t v) { + /* See: https://graphics.stanford.edu/%7Eseander/bithacks.html#RoundUpPowerOf2 */ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return ++v; +} + #endif // UTIL_H diff --git a/licenses/LICENSE.xv6-riscv b/licenses/LICENSE.xv6-riscv new file mode 100644 index 0000000..f2252c9 --- /dev/null +++ b/licenses/LICENSE.xv6-riscv @@ -0,0 +1,23 @@ +The xv6 software is: + +Copyright (c) 2006-2024 Frans Kaashoek, Robert Morris, Russ Cox, + Massachusetts Institute of Technology + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.