/* Calcite, src/kernel/heap.c * Copyright 2025 Benji Dial * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "paging.h" #include "heap.h" struct dealloc_record { //0 for unused uint64_t length; void *start; }; struct dealloc_record_page { struct dealloc_record records[255]; struct dealloc_record_page *prev_page; }; static struct dealloc_record_page *last_page; static void *map_pages(uint64_t page_count) { void *vma = find_free_kernel_region(page_count * 4096); for (uint64_t i = 0; i < page_count; ++i) { uint64_t pma = take_free_physical_page(); map_in_kernel_page_table(pma, vma + i * 4096, 1, 0); } return vma; } static struct dealloc_record *get_unused_record() { for (struct dealloc_record_page *page = last_page; page != 0; page = page->prev_page) for (int i = 0; i < 255; ++i) if (page->records[i].length == 0) return &page->records[i]; struct dealloc_record_page *page = map_pages(1); page->prev_page = last_page; last_page = page; page->records[0].start = (void *)page + 4096 - 8; page->records[0].length = 8; for (int i = 2; i < 255; ++i) page->records[i].length = 0; return &page->records[1]; } void *heap_alloc(uint64_t length) { for (struct dealloc_record_page *page = last_page; page != 0; page = page->prev_page) for (int i = 0; i < 255; ++i) if (page->records[i].length == length) { page->records[i].length = 0; return page->records[i].start; } for (struct dealloc_record_page *page = last_page; page != 0; page = page->prev_page) for (int i = 0; i < 255; ++i) if (page->records[i].length > length) { page->records[i].length -= length; return page->records[i].start + page->records[i].length; } uint64_t pages = (length - 1) / 4096 + 1; void *vma = map_pages(pages); if (pages * 4096 != length) { struct dealloc_record *record = get_unused_record(); record->start = vma + length; record->length = pages * 4096 - length; } return vma; } void heap_dealloc(void *start, uint64_t length) { struct dealloc_record *record = get_unused_record(); record->start = start; record->length = length; }