diff options
Diffstat (limited to '02-usart/src/kern/mem.c')
-rw-r--r-- | 02-usart/src/kern/mem.c | 280 |
1 files changed, 0 insertions, 280 deletions
diff --git a/02-usart/src/kern/mem.c b/02-usart/src/kern/mem.c deleted file mode 100644 index 5234fff..0000000 --- a/02-usart/src/kern/mem.c +++ /dev/null @@ -1,280 +0,0 @@ -#include "arch.h" -#include "kern/mem.h" -#include "kern/common.h" - -#ifdef ARCH_STM32L4 -/* Provide a definition for memset() when not provided for the - * microcontroller. */ -void* memset(void* dest, int c, size_t n) -{ - uint8_t c8 = (uint8_t) c; - uint8_t* dest8 = (uint8_t*) dest; - uint8_t* to = dest8 + n; - - while(dest8 < to) { - *(dest8 ++) = c8; - } - - return dest; -} - -#else - -void* memset(void* dest, int c, size_t n); - -#endif - -typedef uint16_t halloc_off_t; - -#define CANARY 0x5a - -// The sizes will count the number of WORDS allocated. -// Since there's a max size of 16k, only 12 bits will be -// needed for this. -typedef struct HALLOC_NODE { - union { - uint32_t header; - struct { - /* Is this memory block currently in use (hasn't been hfree'd) */ - uint8_t used:1; - /* Number of words allocated. Does not include the header. */ - uint16_t size:12; - /* The location of the previous block (in WORDS from offest) */ - halloc_off_t prev:12; - uint8_t canary:7; - } PACKED; - }; - - uint8_t mem[]; /* The memory to use. */ -} halloc_node_t; - -static_assert(offsetof(halloc_node_t, mem) == 4, "Offset check failed."); - -halloc_node_t* halloc_start; - -#define halloc_node_out_of_range(node) \ - ((uint8_t*) (node) == ((uint8_t*)&DATA_SEGMENT_STOP) + MAX_HEAP_SIZE) - -#define halloc_node_next(cur) \ - ((halloc_node_t*)(((uint8_t*)(cur)) + (((cur)->size + 1) * 4))) - -#define halloc_node_prev(cur) halloc_node_at_off(cur->prev) - -#define halloc_node_at_off(offset) \ - ((halloc_node_t*)(((uint8_t*) halloc_start) + (offset) * 4)) - -#define halloc_node_get_off(node) \ - (((uint32_t)(((uint8_t*)(node)) - ((uint8_t*)(halloc_start)))) / 4) - -#define get_halloc_node(mem) \ - ((halloc_node_t*)(((uint8_t*)mem) - 4)) - -#define size_for(n) \ - (((n) / 4) + ((n) % 4 != 0)) - -void* halloc(size_t size) -{ - if (!halloc_start) { - halloc_start = (halloc_node_t*) DATA_SEGMENT_STOP_ADDR; - memset(halloc_start, 0, sizeof(halloc_node_t)); - halloc_start->size = (MAX_HEAP_SIZE / 4) - 1; - halloc_start->canary = CANARY; - } - - size_t realsz = size_for(size); /* Clip the size to the nearest word. */ - halloc_off_t offset = 0; - while (offset < (MAX_HEAP_SIZE / 4)) { - halloc_node_t* cur = halloc_node_at_off(offset); - - if (!cur->used && (cur->size >= realsz)) { - cur->used = true; - size_t orig_size = cur->size; - cur->size = realsz; - - if (orig_size > realsz) { - /* This halloc node needs to split into two blocks. */ - halloc_node_t* next = halloc_node_next(cur); - next->used = 0; - next->size = orig_size - realsz - sizeof(halloc_node_t) / 4; - next->prev = offset; - next->canary = CANARY; - - halloc_node_t* nextnext = halloc_node_next(next); - if (halloc_node_get_off(nextnext) < (MAX_HEAP_SIZE / 4)) { - nextnext->prev = halloc_node_get_off(next); - } - } - - return (void*) cur->mem; - } - - offset += (sizeof(halloc_node_t) / 4) + cur->size; - } - - return NULL; -} - - -/* Joins this node with the previous and next nodes if they're free. */ -static void coalesce(halloc_node_t* cur) -{ - halloc_node_t* orig = cur; - halloc_node_t* last_freed; - halloc_node_t* next_used; - - /* Find the earliest contiguous free'd block. */ - while (!cur->used && cur != halloc_start) { - cur = halloc_node_prev(cur); - } - - if (cur == halloc_start && !cur->used) { - last_freed = cur; - } else { - last_freed = halloc_node_next(cur); - } - - /* Find the next used block. */ - cur = orig; - while (!cur->used && !halloc_node_out_of_range(cur)) { - cur = halloc_node_next(cur); - } - - next_used = cur; - - if (!halloc_node_out_of_range(next_used)) { - next_used->prev = halloc_node_get_off(last_freed); - } - - last_freed->size = ((uint8_t*) next_used - (last_freed->mem)) / 4; -} - -#ifdef FOR_TESTING -#include <assert.h> -#include <stdio.h> -void panic(const char* x) -{ - fprintf(stderr, "%s\n", x); - assert(0); -} -#else -void panic(const char* x) -{ - for(;;); -} -#endif - -void hfree(void* mem) -{ - /* Like normal free(), do nothing on free'ing NULL */ - if (!mem) return; - - halloc_node_t* header = get_halloc_node(mem); - if (!header->used) { - panic("Heap double free or corruption!\n"); - return; - } - - header->used = 0; - coalesce(header); -} - -#ifdef FOR_TESTING - -#include <stdio.h> - -void* debug_halloc_get_next_ptr(void* ptr) -{ - halloc_node_t* node = ptr - sizeof(halloc_node_t); - halloc_node_t* next = halloc_node_next(node); - - return next->mem; -} - -void* debug_halloc_get_prev_ptr(void* ptr) -{ - halloc_node_t* node = ptr - sizeof(halloc_node_t); - halloc_node_t* prev = halloc_node_prev(node); - - return prev->mem; -} - -void debug_print_blocks() -{ - printf("------ Print Blocks -------\n"); - halloc_node_t* cur = halloc_node_at_off(0); - - while (!halloc_node_out_of_range(cur)) { - printf("header (%04x) {used=%d, size=%5d, prev=%04x, canary=%02x}\n", - halloc_node_get_off(cur), cur->used, cur->size, cur->prev, cur->canary); - cur = halloc_node_next(cur); - } -} - -/* Tests that we can walk up and down the allocated blocks and that they - * are properly aligned. */ -int debug_halloc_assert_consistency(char* error, size_t len) -{ - halloc_node_t* cur = halloc_node_at_off(0); - size_t total_size = 0; - size_t loop_check = 0; - size_t n_blocks = 1; - size_t n_blocks_back = 1; - - while(1) { - if (cur->canary != CANARY) { - snprintf(error, len, "Node has corrupted canary. %02x vs expected %02x\n", - cur->canary, CANARY); - return 1; - } - - total_size += cur->size + 1; - - halloc_node_t* next = halloc_node_next(cur); - if ((uint8_t*) next == ((uint8_t*)&DATA_SEGMENT_STOP) + MAX_HEAP_SIZE) { - break; - } else if ((uint8_t*) next > (uint8_t*)DATA_SEGMENT_STOP_ADDR + MAX_HEAP_SIZE){ - snprintf( - error, len, "Next node points is out of bounds. %p vs max of %p\n", - next, - (void*)(DATA_SEGMENT_STOP_ADDR + MAX_HEAP_SIZE)); - return 1; - } - - cur = next; - ++ n_blocks; - } - - if (total_size * 4 != MAX_HEAP_SIZE) { - snprintf( - error, len, "Total recorded size is inconsistent. %lu vs %lu\n", - total_size * 4, MAX_HEAP_SIZE); - return 1; - } - - if (cur == halloc_start) { - return 0; - } - - while (loop_check < 10000) { - halloc_node_t* prev = halloc_node_prev(cur); - ++ n_blocks_back; - - if (prev == halloc_start) { - if (n_blocks != n_blocks_back) { - snprintf( - error, len, "Different number of blocks found on the way back. Found %lu on the way back vs %lu up.\n", - n_blocks_back, n_blocks); - return 1; - } - return 0; - } - - cur = prev; - ++ loop_check; - } - - snprintf(error, len, "Loop check failed.\n"); - return 1; -} - -#endif |