From e3dfa1f016ad007e2068889bf2093d52a7fa1aa5 Mon Sep 17 00:00:00 2001 From: msh356 Date: Fri, 3 Jul 2026 14:37:22 +0300 Subject: [PATCH] =?UTF-8?q?KERNEL:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BA=D1=83=D1=87=D0=B0=20=D1=8F=D0=B4?= =?UTF-8?q?=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 1 + README.md | 2 +- kernel/heap.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/heap.h | 26 ++++++++++++++++ kernel/kmain.c | 35 +++++++++++++++++++++ 5 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 kernel/heap.c create mode 100644 kernel/heap.h diff --git a/Makefile b/Makefile index d055018..0451037 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ OBJ = boot/boot.o \ kernel/pmm.o \ kernel/vmm.o \ kernel/vmm_asm.o \ + kernel/heap.o \ drivers/serial.o \ drivers/vga.o \ drivers/speaker.o \ diff --git a/README.md b/README.md index 1d2aa42..4c861a3 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ - [x] Физ. менеджер памяти - [x] Вирт. менеджер памяти -- [ ] Куча ядра +- [x] Куча ядра - [ ] Потоки ядра - [ ] **VFS** - [ ] DebugFS diff --git a/kernel/heap.c b/kernel/heap.c new file mode 100644 index 0000000..2c0c56b --- /dev/null +++ b/kernel/heap.c @@ -0,0 +1,83 @@ +#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; + } +} diff --git a/kernel/heap.h b/kernel/heap.h new file mode 100644 index 0000000..2c7ab77 --- /dev/null +++ b/kernel/heap.h @@ -0,0 +1,26 @@ +#ifndef HEAP_H +#define HEAP_H + +#include +#include + +// Начальный виртуальный адрес кучи ядра (3 МБ) +#define HEAP_START 0x00300000 + +// Структура заголовка блока памяти +typedef struct heap_chunk { + size_t size; // Размер полезных данных в байтах + uint8_t is_free; // Флаг: 1 - свободен, 0 - занят + struct heap_chunk* next; // Указатель на следующий блок +} heap_chunk_t; + +// Инициализация кучи +void kheap_init(void); + +// Выделение памяти +void* kmalloc(size_t size); + +// Освобождение памяти +void kfree(void* ptr); + +#endif diff --git a/kernel/kmain.c b/kernel/kmain.c index 33321ae..b0b275d 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -5,6 +5,7 @@ #include "../drivers/speaker.h" #include "gdt.h" #include "idt.h" +#include "heap.h" #include "pmm.h" #include "vmm.h" #include "pic.h" @@ -49,6 +50,7 @@ void kernel_main(uint32_t magic, uint32_t mboot_addr) { timer_init(100); log_info(LOG_NORMAL, "Registering mouse"); mouse_init(); + kprint_serial("--------------------\n"); log_info(LOG_NORMAL, "Enabling PMM..."); pmm_init(mbi, (uint32_t)&end); kprint_serial("--- Memory Map From GRUB ---"); @@ -123,6 +125,39 @@ void kernel_main(uint32_t magic, uint32_t mboot_addr) { kprint_serial("------------------------\n\n"); log_info(LOG_NORMAL, "Enabling VMM..."); vmm_init(); + log_info(LOG_NORMAL, "Enabling KHeap..."); + kheap_init(); + + kprint_serial("--- HEAP TESTING ---\n"); + + // Выделяем три разных куска памяти + int* arr1 = (int*)kmalloc(10 * sizeof(int)); + char* str = (char*)kmalloc(64); + int* arr2 = (int*)kmalloc(5 * sizeof(int)); + char hbuf[32]; + kprint_serial("Allocated arr1 at virtual address: 0x"); + itoa((uint32_t)arr1, hbuf, 16); + kprint_serial(hbuf); + kprint_serial("\n"); + kprint_serial("Allocated str at virtual address: 0x"); + itoa((uint32_t)str, hbuf, 16); + kprint_serial(hbuf); + kprint_serial("\n"); + // Запишем туда данные, чтобы проверить, что маппинг страниц не падает при записи + arr1[0] = 1337; + str[0] = 'H'; + str[1] = 'A'; + str[2] = 'I'; + str[3] = '\0'; + kprint_serial("Data integrity check: str is "); + kprint_serial(str); + kprint_serial("\n"); + // Освобождаем память обратно + kfree(arr1); + kfree(str); + kfree(arr2); + + kprint_serial("Kfree done. It don't died twice!\n"); log_info(LOG_NORMAL, "Enabling IRQ..."); __asm__ __volatile__("sti"); vga_set_color(VGA_COLOR_LIGHT_GREEN, VGA_COLOR_BLACK);