KERNEL: добавлена куча ядра
This commit is contained in:
parent
27c70b881b
commit
e3dfa1f016
5 changed files with 146 additions and 1 deletions
1
Makefile
1
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 \
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
- [x] Физ. менеджер памяти
|
||||
- [x] Вирт. менеджер памяти
|
||||
- [ ] Куча ядра
|
||||
- [x] Куча ядра
|
||||
- [ ] Потоки ядра
|
||||
- [ ] **VFS**
|
||||
- [ ] DebugFS
|
||||
|
|
|
|||
83
kernel/heap.c
Normal file
83
kernel/heap.c
Normal 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
26
kernel/heap.h
Normal 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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue