KERNEL: добавлен менеджер виртуальной памяти

This commit is contained in:
msh356 2026-07-03 14:12:33 +03:00
parent ea0a395cc5
commit 27c70b881b
6 changed files with 143 additions and 28 deletions

View file

@ -22,6 +22,8 @@ OBJ = boot/boot.o \
kernel/pic.o \ kernel/pic.o \
kernel/string.o \ kernel/string.o \
kernel/pmm.o \ kernel/pmm.o \
kernel/vmm.o \
kernel/vmm_asm.o \
drivers/serial.o \ drivers/serial.o \
drivers/vga.o \ drivers/vga.o \
drivers/speaker.o \ drivers/speaker.o \
@ -52,6 +54,12 @@ kernel/gdt_asm.o: kernel/gdt.asm
kernel/interrupt.o: kernel/interrupt.asm kernel/interrupt.o: kernel/interrupt.asm
@echo "[+] Компилируем interrupt.asm..." @echo "[+] Компилируем interrupt.asm..."
$(AS) $(ASFLAGS) kernel/interrupt.asm -o kernel/interrupt.o $(AS) $(ASFLAGS) kernel/interrupt.asm -o kernel/interrupt.o
# Компиляция ассемблера VMM
kernel/vmm_asm.o: kernel/vmm_asm.asm
@echo "[+] Компилируем vmm_asm.asm..."
$(AS) $(ASFLAGS) kernel/vmm_asm.asm -o kernel/vmm_asm.o
# Компиляция драйверов # Компиляция драйверов
drivers/%.o: drivers/%.c drivers/%.o: drivers/%.c
@echo "[+] Компилируем драйвер: $<" @echo "[+] Компилируем драйвер: $<"

View file

@ -20,7 +20,7 @@
## 2. Процессы, память, user mode, еще драйвера ## 2. Процессы, память, user mode, еще драйвера
- [x] Физ. менеджер памяти - [x] Физ. менеджер памяти
- [ ] Вирт. менеджер памяти - [x] Вирт. менеджер памяти
- [ ] Куча ядра - [ ] Куча ядра
- [ ] Потоки ядра - [ ] Потоки ядра
- [ ] **VFS** - [ ] **VFS**

View file

@ -6,6 +6,7 @@
#include "gdt.h" #include "gdt.h"
#include "idt.h" #include "idt.h"
#include "pmm.h" #include "pmm.h"
#include "vmm.h"
#include "pic.h" #include "pic.h"
#include "logger.h" #include "logger.h"
#include "string.h" #include "string.h"
@ -50,33 +51,6 @@ void kernel_main(uint32_t magic, uint32_t mboot_addr) {
mouse_init(); mouse_init();
log_info(LOG_NORMAL, "Enabling PMM..."); log_info(LOG_NORMAL, "Enabling PMM...");
pmm_init(mbi, (uint32_t)&end); pmm_init(mbi, (uint32_t)&end);
log_info(LOG_NORMAL, "Enabling IRQ...");
__asm__ __volatile__("sti");
vga_set_color(VGA_COLOR_LIGHT_GREEN, VGA_COLOR_BLACK);
vga_print("h");
speaker_beep(100, 10);
vga_print("a");
speaker_beep(125, 10);
vga_print("i");
speaker_beep(150, 10);
vga_print("!");
speaker_beep(175, 10);
vga_print("!");
speaker_beep(200, 10);
vga_print("!");
speaker_beep(225, 10);
vga_print("!");
speaker_beep(250, 10);
vga_print("!");
speaker_beep(275, 10);
vga_print("!");
speaker_beep(300, 10);
vga_print("!");
speaker_beep(325, 10);
vga_print("\n # ### #### \n #### ### # ## ### #### # # # \n # # ##### ## ##### # # # # ### \n # # # # # # # # # # \n #### ### # ### #### ### #### \n # \n");
speaker_beep(350, 400);
vga_init();
vga_set_color(VGA_COLOR_LIGHT_GRAY, VGA_COLOR_BLACK);
kprint_serial("--- Memory Map From GRUB ---"); kprint_serial("--- Memory Map From GRUB ---");
struct multiboot_mmap_entry* mmap = (struct multiboot_mmap_entry*)mbi->mmap_addr; struct multiboot_mmap_entry* mmap = (struct multiboot_mmap_entry*)mbi->mmap_addr;
@ -147,6 +121,35 @@ void kernel_main(uint32_t magic, uint32_t mboot_addr) {
kprint_serial(" MB\n"); kprint_serial(" MB\n");
kprint_serial("------------------------\n\n"); kprint_serial("------------------------\n\n");
log_info(LOG_NORMAL, "Enabling VMM...");
vmm_init();
log_info(LOG_NORMAL, "Enabling IRQ...");
__asm__ __volatile__("sti");
vga_set_color(VGA_COLOR_LIGHT_GREEN, VGA_COLOR_BLACK);
vga_print("h");
speaker_beep(100, 10);
vga_print("a");
speaker_beep(125, 10);
vga_print("i");
speaker_beep(150, 10);
vga_print("!");
speaker_beep(175, 10);
vga_print("!");
speaker_beep(200, 10);
vga_print("!");
speaker_beep(225, 10);
vga_print("!");
speaker_beep(250, 10);
vga_print("!");
speaker_beep(275, 10);
vga_print("!");
speaker_beep(300, 10);
vga_print("!");
speaker_beep(325, 10);
vga_print("\n # ### #### \n #### ### # ## ### #### # # # \n # # ##### ## ##### # # # # ### \n # # # # # # # # # # \n #### ### # ### #### ### #### \n # \n");
speaker_beep(350, 400);
vga_init();
vga_set_color(VGA_COLOR_LIGHT_GRAY, VGA_COLOR_BLACK);
while (1); while (1);
} }

67
kernel/vmm.c Normal file
View file

@ -0,0 +1,67 @@
#include "vmm.h"
#include "../drivers/serial.h"
#include "string.h"
// Каталог страниц (1024 элемента по 4 байта = 4КБ)
static uint32_t page_directory[1024] __attribute__((aligned(4096)));
// Первая таблица страниц для маппинга первых 4 Мегабайт памяти
static uint32_t first_page_table[1024] __attribute__((aligned(4096)));
extern void vmm_enable_paging(uint32_t* directory);
void vmm_init(void) {
kprint_serial("VMM: Initializing paging...\n");
// 1. Очищаем каталог страниц (ставим не-present)
// Ставим флаг 0x2 (Read/Write, но Not Present)
for (int i = 0; i < 1024; i++) {
page_directory[i] = 0x00000002;
}
// 2. Делаем Identity Mapping для первых 4 МБ (0x00000000 - 0x003FFFFF)
// Пробегаемся по всей первой таблице страниц
for (uint32_t i = 0; i < 1024; i++) {
// Физический адрес = i * 4096
// Флаги: Present (0x1) + Read/Write (0x2)
first_page_table[i] = (i * 4096) | 3;
}
// 3. Засовываем первую таблицу страниц в первый элемент каталога
// Адрес таблицы | флаги Present + Read/Write
page_directory[0] = ((uint32_t)first_page_table) | 3;
kprint_serial("VMM: Paging structures configured. Enabling CR0 bits...\n");
// 4. Прыгаем в ассемблер, чтобы загрузить CR3 и выставить флаг в CR0
vmm_enable_paging(page_directory);
kprint_serial("VMM: HOLY SHIT IT WORKS! Paging is active!\n");
}
void vmm_map_page(uint32_t phys, uint32_t virt, uint32_t flags) {
// Выковыриваем индексы из виртуального адреса
uint32_t pd_idx = virt >> 22; // Старшие 10 бит — индекс каталога
uint32_t pt_idx = (virt >> 12) & 0x3FF; // Средние 10 бит — индекс таблицы
// Проверяем, создана ли таблица страниц для этого региона
// Наше ядро пока создало только одну таблицу для первых 4 МБ (pd_idx == 0)
if (!(page_directory[pd_idx] & 1)) {
// Если таблицы нет, по-хорошему надо выделить 4КБ через pmm_alloc_page(),
// очистить её и засунуть в каталог. Но пока выкинем ошибку для отладки:
kprint_serial("VMM ERROR: Page table not allocated for this virtual address!\n");
return;
}
// Достаем адрес таблицы страниц из каталога (обнуляем нижние 12 бит флагов)
uint32_t* table = (uint32_t*)(page_directory[pd_idx] & 0xFFFFF000);
// Запихиваем физический адрес и флаги в таблицу страниц
// PAGE_SIZE у нас 4096, поэтому phys должен быть выровнен (нижние 12 бит затрутся флагами)
table[pt_idx] = (phys & 0xFFFFF000) | flags;
// ВАЖНО: Процессор кэширует таблицы в TLB (Translation Lookaside Buffer).
// Если мы изменили маппинг существующей страницы, процессор об этом не узнает.
// Нужно сбросить кэш для этого адреса инструкцией invlpg:
__asm__ __volatile__("invlpg (%0)" : : "r"(virt) : "memory");
}

17
kernel/vmm.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef VMM_H
#define VMM_H
#include <stdint.h>
// Элемент каталога/таблицы страниц
#define PAGE_PRESENT 0x1 // Страница есть в памяти
#define PAGE_WRITE 0x2 // Можно писать (Read/Write)
#define PAGE_USER 0x4 // Доступно из Ring 3 (User mode)
// Инициализация страничного обмена
void vmm_init(void);
// Отобразить виртуальный адрес на физический
void vmm_map_page(uint32_t phys, uint32_t virt, uint32_t flags);
#endif

20
kernel/vmm_asm.asm Normal file
View file

@ -0,0 +1,20 @@
global vmm_enable_paging
section .text
vmm_enable_paging:
push ebp
mov ebp, esp
; 1. Загружаем адрес каталога страниц в регистр CR3
mov eax, [ebp + 8]
mov cr3, eax
; 2. Включаем пейджинг: выставляем 31-й бит (PG) в регистре CR0
mov eax, cr0
or eax, 0x80000000
mov cr0, eax
mov esp, ebp
pop ebp
ret