KERNEL: добавлен менеджер виртуальной памяти
This commit is contained in:
parent
ea0a395cc5
commit
27c70b881b
6 changed files with 143 additions and 28 deletions
8
Makefile
8
Makefile
|
|
@ -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 "[+] Компилируем драйвер: $<"
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
## 2. Процессы, память, user mode, еще драйвера
|
## 2. Процессы, память, user mode, еще драйвера
|
||||||
|
|
||||||
- [x] Физ. менеджер памяти
|
- [x] Физ. менеджер памяти
|
||||||
- [ ] Вирт. менеджер памяти
|
- [x] Вирт. менеджер памяти
|
||||||
- [ ] Куча ядра
|
- [ ] Куча ядра
|
||||||
- [ ] Потоки ядра
|
- [ ] Потоки ядра
|
||||||
- [ ] **VFS**
|
- [ ] **VFS**
|
||||||
|
|
|
||||||
|
|
@ -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
67
kernel/vmm.c
Normal 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
17
kernel/vmm.h
Normal 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
20
kernel/vmm_asm.asm
Normal 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
|
||||||
Loading…
Reference in a new issue