83 lines
3.4 KiB
C
83 lines
3.4 KiB
C
#include "heap.h"
|
||
#include "vmm.h"
|
||
#include "pmm.h"
|
||
#include "../drivers/serial.h"
|
||
|
||
static heap_chunk_t* heap_start_chunk = NULL;
|
||
|
||
void kheap_init(void) {
|
||
kprint_serial("HEAP: Initializing Kernel Heap...\n");
|
||
|
||
// 1. Выделяем одну физ. страницу под старт кучи
|
||
void* phys_page = pmm_alloc_page();
|
||
|
||
// 2. Мапим её на виртуальный адрес HEAP_START
|
||
// Нам нужны флаги Present (1) + Write (2) = 3
|
||
vmm_map_page((uint32_t)phys_page, HEAP_START, 3);
|
||
|
||
// 3. Создаем базовый блок на всю эту страницу
|
||
heap_start_chunk = (heap_chunk_t*)HEAP_START;
|
||
heap_start_chunk->size = PAGE_SIZE - sizeof(heap_chunk_t);
|
||
heap_start_chunk->is_free = 1;
|
||
heap_start_chunk->next = NULL;
|
||
|
||
kprint_serial("HEAP: Kernel Heap initialized successfully at 0x00400000!\n");
|
||
}
|
||
|
||
void* kmalloc(size_t size) {
|
||
if (size == 0) return NULL;
|
||
|
||
// Выравниваем размер по 4 байта для стабильности на x86
|
||
size = (size + 3) & ~3;
|
||
|
||
heap_chunk_t* current = heap_start_chunk;
|
||
|
||
// Ищем подходящий свободный блок (First Fit)
|
||
while (current != NULL) {
|
||
if (current->is_free && current->size >= size) {
|
||
|
||
// Если блок сильно больше, чем надо, дробим его
|
||
// sizeof(heap_chunk_t) + 4 байта минимально на остаток
|
||
if (current->size >= size + sizeof(heap_chunk_t) + 4) {
|
||
heap_chunk_t* new_chunk = (heap_chunk_t*)((uint32_t)current + sizeof(heap_chunk_t) + size);
|
||
new_chunk->size = current->size - size - sizeof(heap_chunk_t);
|
||
new_chunk->is_free = 1;
|
||
new_chunk->next = current->next;
|
||
|
||
current->size = size;
|
||
current->next = new_chunk;
|
||
}
|
||
|
||
current->is_free = 0;
|
||
|
||
// Возвращаем указатель на память СРАЗУ ЗА заголовком
|
||
return (void*)((uint32_t)current + sizeof(heap_chunk_t));
|
||
}
|
||
current = current->next;
|
||
}
|
||
|
||
// По-хорошему, если памяти не хватило, нужно выделить еще страницу из PMM
|
||
// и расширить кучу. Но для первого теста выкинем панику.
|
||
kprint_serial("HEAP ERROR: OUT OF KERNEL HEAP MEMORY!\n");
|
||
return NULL;
|
||
}
|
||
|
||
void kfree(void* ptr) {
|
||
if (ptr == NULL) return;
|
||
|
||
// Смещаемся назад, чтобы получить доступ к заголовку блока
|
||
heap_chunk_t* chunk = (heap_chunk_t*)((uint32_t)ptr - sizeof(heap_chunk_t));
|
||
chunk->is_free = 1;
|
||
|
||
// Склеиваем последовательные свободные блоки (Coalescing), чтобы не было фрагментации
|
||
heap_chunk_t* current = heap_start_chunk;
|
||
while (current != NULL) {
|
||
if (current->is_free && current->next && current->next->is_free) {
|
||
current->size += sizeof(heap_chunk_t) + current->next->size;
|
||
current->next = current->next->next;
|
||
// Не шагаем вперед, проверяем текущий блок еще раз с новым next
|
||
continue;
|
||
}
|
||
current = current->next;
|
||
}
|
||
}
|