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/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 \
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
- [x] Физ. менеджер памяти
|
- [x] Физ. менеджер памяти
|
||||||
- [x] Вирт. менеджер памяти
|
- [x] Вирт. менеджер памяти
|
||||||
- [ ] Куча ядра
|
- [x] Куча ядра
|
||||||
- [ ] Потоки ядра
|
- [ ] Потоки ядра
|
||||||
- [ ] **VFS**
|
- [ ] **VFS**
|
||||||
- [ ] DebugFS
|
- [ ] 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 "../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);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue