// SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2022 Martin Whitaker. #include #include "boot.h" #include "memsize.h" #include "pmem.h" #include "heap.h" //------------------------------------------------------------------------------ // Types //------------------------------------------------------------------------------ typedef struct { int segment; uintptr_t start; uintptr_t end; } heap_t; //------------------------------------------------------------------------------ // Private Variables //------------------------------------------------------------------------------ static heap_t heaps[HEAP_TYPE_LAST] = { { .segment = -1, .start = 0, .end = 0 }, { .segment = -1, .start = 0, .end = 0 } }; //------------------------------------------------------------------------------ // Private Functions //------------------------------------------------------------------------------ static size_t num_pages(size_t size) { return (size + PAGE_SIZE - 1) >> PAGE_SHIFT; } uintptr_t heap_alloc(heap_type_t heap_id, size_t size, uintptr_t alignment) { const heap_t * heap = &heaps[heap_id]; if (heap->segment < 0) { return 0; } uintptr_t addr = pm_map[heap->segment].end - num_pages(size); addr &= ~((alignment - 1) >> PAGE_SHIFT); if (addr < heap->start) { return 0; } pm_map[heap->segment].end = addr; return addr << PAGE_SHIFT; } uintptr_t heap_mark(heap_type_t heap_id) { const heap_t * heap = &heaps[heap_id]; if (heap->segment < 0) { return 0; } return pm_map[heap->segment].end; } void heap_rewind(heap_type_t heap_id, uintptr_t mark) { const heap_t * heap = &heaps[heap_id]; if (heap->segment >= 0 && mark > pm_map[heap->segment].end && mark <= heap->end) { pm_map[heap->segment].end = mark; } } //------------------------------------------------------------------------------ // Public Functions //------------------------------------------------------------------------------ void heap_init(void) { // Use the largest 20-bit addressable physical memory segment for the low-memory heap. // Use the largest 32-bit addressable physical memory segment for the high-memory heap. // Exclude memory occupied by the program or below it in that segment. uintptr_t program_start = (uintptr_t)_start >> PAGE_SHIFT; uintptr_t program_end = program_start + num_pages(_end - _start); uintptr_t max_segment_size = 0; for (int i = 0; i < pm_map_size && pm_map[i].end <= PAGE_C(4,GB); i++) { uintptr_t try_heap_start = pm_map[i].start; uintptr_t try_heap_end = pm_map[i].end; if (program_start >= try_heap_start && program_end <= try_heap_end) { try_heap_start = program_end; } uintptr_t segment_size = try_heap_end - try_heap_start; if (segment_size >= max_segment_size) { max_segment_size = segment_size; if (try_heap_end <= PAGE_C(1,MB)) { heaps[HEAP_TYPE_LM_1].segment = i; heaps[HEAP_TYPE_LM_1].start = try_heap_start; heaps[HEAP_TYPE_LM_1].end = try_heap_end; } heaps[HEAP_TYPE_HM_1].segment = i; heaps[HEAP_TYPE_HM_1].start = try_heap_start; heaps[HEAP_TYPE_HM_1].end = try_heap_end; } } }