KERNEL: добавлена куча ядра

This commit is contained in:
msh356 2026-07-03 14:37:22 +03:00
parent 27c70b881b
commit e3dfa1f016
5 changed files with 146 additions and 1 deletions

View file

@ -24,6 +24,7 @@ OBJ = boot/boot.o \
kernel/pmm.o \ kernel/pmm.o \
kernel/vmm.o \ kernel/vmm.o \
kernel/vmm_asm.o \ kernel/vmm_asm.o \
kernel/heap.o \
drivers/serial.o \ drivers/serial.o \
drivers/vga.o \ drivers/vga.o \
drivers/speaker.o \ drivers/speaker.o \

View file

@ -21,7 +21,7 @@
- [x] Физ. менеджер памяти - [x] Физ. менеджер памяти
- [x] Вирт. менеджер памяти - [x] Вирт. менеджер памяти
- [ ] Куча ядра - [x] Куча ядра
- [ ] Потоки ядра - [ ] Потоки ядра
- [ ] **VFS** - [ ] **VFS**
- [ ] DebugFS - [ ] DebugFS

83
kernel/heap.c Normal file
View file

@ -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;
}
}

26
kernel/heap.h Normal file
View file

@ -0,0 +1,26 @@
#ifndef HEAP_H
#define HEAP_H
#include <stdint.h>
#include <stddef.h>
// Начальный виртуальный адрес кучи ядра (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

View file

@ -5,6 +5,7 @@
#include "../drivers/speaker.h" #include "../drivers/speaker.h"
#include "gdt.h" #include "gdt.h"
#include "idt.h" #include "idt.h"
#include "heap.h"
#include "pmm.h" #include "pmm.h"
#include "vmm.h" #include "vmm.h"
#include "pic.h" #include "pic.h"
@ -49,6 +50,7 @@ void kernel_main(uint32_t magic, uint32_t mboot_addr) {
timer_init(100); timer_init(100);
log_info(LOG_NORMAL, "Registering mouse"); log_info(LOG_NORMAL, "Registering mouse");
mouse_init(); mouse_init();
kprint_serial("--------------------\n");
log_info(LOG_NORMAL, "Enabling PMM..."); log_info(LOG_NORMAL, "Enabling PMM...");
pmm_init(mbi, (uint32_t)&end); pmm_init(mbi, (uint32_t)&end);
kprint_serial("--- Memory Map From GRUB ---"); kprint_serial("--- Memory Map From GRUB ---");
@ -123,6 +125,39 @@ void kernel_main(uint32_t magic, uint32_t mboot_addr) {
kprint_serial("------------------------\n\n"); kprint_serial("------------------------\n\n");
log_info(LOG_NORMAL, "Enabling VMM..."); log_info(LOG_NORMAL, "Enabling VMM...");
vmm_init(); 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..."); log_info(LOG_NORMAL, "Enabling IRQ...");
__asm__ __volatile__("sti"); __asm__ __volatile__("sti");
vga_set_color(VGA_COLOR_LIGHT_GREEN, VGA_COLOR_BLACK); vga_set_color(VGA_COLOR_LIGHT_GREEN, VGA_COLOR_BLACK);