peredOS/kernel/vmm.c

67 lines
3.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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");
}