diff --git a/Makefile b/Makefile index c66beeb..aa95a40 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,8 @@ # Define the object files -OBJS = bin/boot.o bin/kernel.o bin/idt.o bin/isr.o bin/screen.o bin/utils.o bin/string.o bin/stdio.o bin/disk.o bin/pic.o bin/pit.o bin/keyboard.o bin/paging.o bin/fat.o bin/task.o bin/switch.o +OBJS = bin/boot.o bin/kernel.o bin/idt.o bin/isr.o bin/screen.o \ + bin/utils.o bin/string.o bin/stdio.o bin/disk.o bin/pic.o bin/pit.o \ + bin/keyboard.o bin/paging.o bin/heap.o bin/page_alloc.o bin/page_tables.o \ + bin/fat.o bin/task.o bin/switch.o # Define the compiler and assembler CC = gcc -D__is_katauos @@ -93,6 +96,15 @@ bin/keyboard.o: src/drivers/keyboard.c bin/paging.o: src/mm/paging.c $(CC) $(CFLAGS) -c $< -o $@ +bin/heap.o: src/mm/heap.c + $(CC) $(CFLAGS) -c $< -o $@ + +bin/page_alloc.o: src/mm/page_alloc.c + $(CC) $(CFLAGS) -c $< -o $@ + +bin/page_tables.o: src/mm/page_tables.c + $(CC) $(CFLAGS) -c $< -o $@ + bin/fat.o: src/drivers/fat.c $(CC) $(CFLAGS) -c $< -o $@ diff --git a/include/paging.h b/include/paging.h index 4a68149..c2653ff 100644 --- a/include/paging.h +++ b/include/paging.h @@ -1,11 +1,33 @@ #ifndef PAGING_H #define PAGING_H + +#include "../include/stdio.h" #include + +extern uint32_t kernel_page_directory[1024] __attribute__((aligned(4096))); +extern uint32_t kernel_page_table[1024] __attribute__((aligned(4096))); + + +//paging.c +void enablePaging(); +void loadPageDirectory(uint32_t* page_directory); void paging_init(); +void test_paging(); + +//page_alloc.c +void init_allocator(); +void* alloc_page(); +void free_page(void* physaddr); + +//page_tables.c +void *get_physaddr(void *virtualaddr); +void map_page(void* physaddr, void* virtualaddr, unsigned int flags); +void map_kernel_page(void* virtualaddr, unsigned int flags); + +//heap.c void heap_init(); void* heap_alloc(uint32_t size); -void heap_free(void *ptr); -void test_paging(); -void init_allocator(); -#endif +void heap_free(void* ptr); + +#endif \ No newline at end of file diff --git a/src/mm/heap.c b/src/mm/heap.c new file mode 100644 index 0000000..fbfb746 --- /dev/null +++ b/src/mm/heap.c @@ -0,0 +1,127 @@ +#include "../include/paging.h" +#include +#include "../include/stdio.h" + +// Структура заголовка блока памяти +typedef struct Block { + uint32_t size; // Размер блока (в байтах, включая заголовок) + uint32_t is_free; // 1 = свободен, 0 = занят + struct Block* next; // Указатель на следующий блок +} Block; + +// Структура для управления кучей +typedef struct { + void* start; // Начало кучи + uint32_t size; // Текущий размер кучи в байтах + Block* first; // Первый блок в куче +} Heap; + +Heap kernel_heap; + +void heap_init() { + kernel_heap.start = (void*)0xD0000000; // Начало кучи в ядре + kernel_heap.size = 0x1000; // Начальный размер — 1 страница (4 КБ) + printf("before map_kernel_page\n"); + // Отображаем первую страницу + map_kernel_page(kernel_heap.start, 0x2); // writable, supervisor + printf("after map_kernel_page\n"); + // Создаём первый блок, который занимает всю страницу + Block* initial_block = (Block*)kernel_heap.start; + initial_block->size = 0x1000 - sizeof(Block); // Размер без учёта заголовка + initial_block->is_free = 1; // Свободен + initial_block->next = (Block*)0; // Пока нет следующего + + kernel_heap.first = initial_block; +} + +void* heap_alloc(uint32_t size) { + // Выравниваем размер до 4 байт + size = (size + 3) & ~3; + + Block* current = kernel_heap.first; + Block* prev = (Block*)0; + + // Ищем подходящий свободный блок + while (current) { + if (current->is_free && current->size >= size) { + if (current->size >= size + sizeof(Block) + 4) { + Block* new_block = (Block*)((uint32_t)current + sizeof(Block) + size); + new_block->size = current->size - size - sizeof(Block); + new_block->is_free = 1; + new_block->next = current->next; + + current->size = size; + current->next = new_block; + } + current->is_free = 0; + return (void*)((uint32_t)current + sizeof(Block)); + } + prev = current; + current = current->next; + } + + // Нет подходящего блока — выделяем нужное количество страниц + uint32_t total_size = size + sizeof(Block); // Размер с заголовком + uint32_t pages_needed = (total_size + 0xFFF) / 0x1000; // Округляем вверх до страниц + uint32_t alloc_size = pages_needed * 0x1000; // Сколько байт выделяем + + void* new_page = (void*)((uint32_t)kernel_heap.start + kernel_heap.size); + for (uint32_t i = 0; i < pages_needed; i++) { + map_kernel_page((void*)((uint32_t)new_page + i * 0x1000), 0x2); + } + kernel_heap.size += alloc_size; + + Block* new_block = (Block*)new_page; + new_block->size = alloc_size - sizeof(Block); + new_block->is_free = 1; + new_block->next = (Block*)0; + + if (prev) prev->next = new_block; + if (!kernel_heap.first) kernel_heap.first = new_block; + + // Теперь current указывает на новый блок, продолжаем цикл + current = new_block; + if (current->size >= size) { + if (current->size >= size + sizeof(Block) + 4) { + Block* split_block = (Block*)((uint32_t)current + sizeof(Block) + size); + split_block->size = current->size - size - sizeof(Block); + split_block->is_free = 1; + split_block->next = current->next; + + current->size = size; + current->next = split_block; + } + current->is_free = 0; + return (void*)((uint32_t)current + sizeof(Block)); + } + + // Если что-то пошло не так, возвращаем NULL + return (void*)0; +} + +void heap_free(void* ptr) { + if (!ptr || (uint32_t)ptr < (uint32_t)kernel_heap.start) return; + + // Находим блок по указателю (указатель указывает после заголовка) + Block* block = (Block*)((uint32_t)ptr - sizeof(Block)); + block->is_free = 1; + + // Слияние с предыдущим блоком, если он свободен + Block* current = kernel_heap.first; + Block* prev = (Block*)0; + while (current && current != block) { + prev = current; + current = current->next; + } + if (prev && prev->is_free) { + prev->size += sizeof(Block) + block->size; + prev->next = block->next; + block = prev; + } + + // Слияние с следующим блоком, если он свободен + if (block->next && block->next->is_free) { + block->size += sizeof(Block) + block->next->size; + block->next = block->next->next; + } +} \ No newline at end of file diff --git a/src/mm/page_alloc.c b/src/mm/page_alloc.c new file mode 100644 index 0000000..7fe9ffe --- /dev/null +++ b/src/mm/page_alloc.c @@ -0,0 +1,40 @@ +#include "../include/paging.h" +#include +#include "../include/stdio.h" + +uint8_t page_bitmap[512]; // 1 бит на страницу + +void init_allocator() { + int i; + // Помечаем все страницы как свободные (0) + for (i = 0; i < 512; i++) { + page_bitmap[i] = 0; + } + // Первые 4 МБ уже заняты ядром (0x00000000–0x003FFFFF) + for (i = 0; i < 1024 / 8; i++) { // 1024 страницы = 128 байт + page_bitmap[i] = 0xFF; // Все биты = 1 (занято) + } +} + +void* alloc_page() { + int i, j; + for (i = 0; i < 512; i++) { + if (page_bitmap[i] != 0xFF) { + for (j = 0; j < 8; j++) { + if (!(page_bitmap[i] & (1 << j))) { + page_bitmap[i] |= (1 << j); + return (void*)(((i * 8) + j) * 0x1000); + } + } + } + } + printf("no bitches? no free pages?\n"); + return (void*)0; // Нет свободных страниц +} + +void free_page(void* physaddr) { + uint32_t page_num = (uint32_t)physaddr / 0x1000; + uint32_t byte_idx = page_num / 8; + uint32_t bit_idx = page_num % 8; + page_bitmap[byte_idx] &= ~(1 << bit_idx); // Сбрасываем бит +} \ No newline at end of file diff --git a/src/mm/page_tables.c b/src/mm/page_tables.c new file mode 100644 index 0000000..9b33af9 --- /dev/null +++ b/src/mm/page_tables.c @@ -0,0 +1,88 @@ +#include "../include/paging.h" +#include + +void *get_physaddr(void *virtualaddr) { + unsigned long pdindex = (unsigned long)virtualaddr >> 22; + unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF; + + unsigned long *pd = (unsigned long *)0xFFFFF000; + // Here you need to check whether the PD entry is present. + + unsigned long *pt = ((unsigned long *)0xFFC00000) + (0x400 * pdindex); + // Here you need to check whether the PT entry is present. + + return (void *)((pt[ptindex] & ~0xFFF) + ((unsigned long)virtualaddr & 0xFFF)); +} + +void map_page(void* physaddr, void* virtualaddr, unsigned int flags) { + // Убеждаемся, что адреса выровнены по 4 КБ + uint32_t phys = (uint32_t)physaddr & ~0xFFF; // Обнуляем младшие 12 бит + uint32_t virt = (uint32_t)virtualaddr & ~0xFFF; + + // Вычисляем индексы + uint32_t pdindex = virt >> 22; // Индекс в каталоге страниц + uint32_t ptindex = (virt >> 12) & 0x3FF; // Индекс в таблице страниц + + uint32_t *pd = (uint32_t *)0xFFFFF000; // Адрес каталога страниц в виртуальной памяти + + // Проверяем, существует ли таблица страниц + if (!(pd[pdindex] & 0x1)) { // Бит 0 — "present" + // Если таблицы нет, создаём новую + void *new_pt = alloc_page(); + if (!new_pt) while (1); // Нет памяти + pd[pdindex] = (uint32_t)new_pt | 0x3; // present, writable + + // Очищаем новую таблицу + uint32_t *pt = ((uint32_t *)0xFFC00000) + (0x400 * pdindex); + for (int i = 0; i < 1024; i++) { + pt[i] = 0; // Все страницы "не присутствуют" + } + } + + // Получаем адрес таблицы страниц + uint32_t *pt = ((uint32_t *)0xFFC00000) + (0x400 * pdindex); + + // Устанавливаем отображение + pt[ptindex] = phys | (flags & 0xFFF) | 0x1; // Флаги + present + + // Сбрасываем TLB для этого адреса + asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory"); +} + +void map_kernel_page(void* virtualaddr, unsigned int flags) { + uint32_t virt = (uint32_t)virtualaddr & ~0xFFF; // Выравниваем по 4 КБ + if (virt < 0xC0000000) while(1); // Ошибка: ядро только выше 3 ГБ + + uint32_t pdindex = virt >> 22; // Индекс в каталоге + uint32_t ptindex = (virt >> 12) & 0x3FF; // Индекс в таблице страниц + + uint32_t* pd = (uint32_t*)0xFFFFF000; // Каталог страниц + + // Проверяем, существует ли таблица страниц + if (!(pd[pdindex] & 0x1)) { + void* new_pt = alloc_page(); + if (!new_pt) while(1); // Нет памяти + + // Убеждаемся, что адрес выровнен + if ((uint32_t)new_pt & 0xFFF) while(1); // Ошибка выравнивания + + pd[pdindex] = ((uint32_t)new_pt) | 0x3; // Временно записываем в каталог + asm volatile("invlpg (%0)" : : "r" ((uint32_t)&pd[pdindex]) : "memory"); // Инвалидируем TLB + + uint32_t* pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex); + for (int i = 0; i < 1024; i++) { + pt[i] = 0; + } + } + + // Получаем таблицу страниц + uint32_t* pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex); + void* phys = alloc_page(); + if (!phys) while(1); + + // Проверяем, не занята ли страница + if (pt[ptindex] & 0x1) while(1); // Ошибка: страница уже отображена + + pt[ptindex] = (uint32_t)phys | (flags & 0xFFF) | 0x1; // supervisor, present + asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory"); +} \ No newline at end of file diff --git a/src/mm/paging.c b/src/mm/paging.c index e6f37d5..dedbb9b 100644 --- a/src/mm/paging.c +++ b/src/mm/paging.c @@ -1,6 +1,8 @@ #include "../include/paging.h" #include -#include "../include/stdio.h" + +uint32_t kernel_page_directory[1024] __attribute__((aligned(4096))); +uint32_t kernel_page_table[1024] __attribute__((aligned(4096))); void enablePaging() { asm volatile ( @@ -27,79 +29,8 @@ void loadPageDirectory(uint32_t* page_directory) { ); } -uint32_t kernel_page_directory[1024] __attribute__((aligned(4096))); -uint32_t kernel_page_table[1024] __attribute__((aligned(4096))); - -// 16 МБ = 16 * 1024 * 1024 байт = 4096 страниц (по 4 КБ) -// 4096 бит = 512 байт -uint8_t page_bitmap[512]; // 1 бит на страницу - -/** -page_bitmap — массив, где каждый бит соответствует странице (0 = свободна, 1 = занята). -init_allocator помечает первые 4 МБ как занятые (там ядро). -alloc_page ищет первый свободный бит и возвращает адрес страницы. -free_page освобождает страницу, сбрасывая бит. -**/ - -void init_allocator() { +void paging_init() { int i; - // Помечаем все страницы как свободные (0) - for (i = 0; i < 512; i++) { - page_bitmap[i] = 0; - } - // Первые 4 МБ уже заняты ядром (0x00000000–0x003FFFFF) - for (i = 0; i < 1024 / 8; i++) { // 1024 страницы = 128 байт - page_bitmap[i] = 0xFF; // Все биты = 1 (занято) - } -} - -// Выделяем свободную страницу -void* alloc_page() { -// printf("alloc_page called\n"); - int i, j; - for (i = 0; i < 512; i++) { - if (page_bitmap[i] != 0xFF) { - for (j = 0; j < 8; j++) { - if (!(page_bitmap[i] & (1 << j))) { - page_bitmap[i] |= (1 << j); - return (void*)(((i * 8) + j) * 0x1000); - } - } - } - } - printf("no bitches? no free pages?\n"); - return (void*)0; // Нет свободных страниц -} - -void test_paging() { - uint32_t* pd = (uint32_t*)0xFFFFF000; - uint32_t expected = (uint32_t)kernel_page_table | 0x3; - // Игнорируем дополнительные флаги, проверяем только базовый адрес и present - if ((pd[0] & ~0xFFF) == (expected & ~0xFFF)) { - // Успех - } else { - printf("RECURSION BROKEN!!\n"); - printf("pd[0] = 0x%X\n"); - printf("(uint32_t)first_page_table | 0x3 = %X", (uint32_t)kernel_page_table | 0x3); - while (1); // Рекурсия сломана - } -} - -// Освобождаем страницу -void free_page(void *physaddr) { - uint32_t page_num = (uint32_t)physaddr / 0x1000; - uint32_t byte_idx = page_num / 8; - uint32_t bit_idx = page_num % 8; - page_bitmap[byte_idx] &= ~(1 << bit_idx); // Сбрасываем бит -} - -/** -Теперь первые 4 МБ физической памяти отображаются на виртуальный адрес 0xC0000000 (3 ГБ), а не на 0x00000000. -Это оставляет нижние 3 ГБ (0x00000000–0xBFFFFFFF) свободными для пользовательских процессов. -**/ -void paging_init() -{ - int i; // Проверяем физические адреса uint32_t pd_phys = (uint32_t)kernel_page_directory; @@ -129,375 +60,20 @@ void paging_init() printf("OSHIBKA ZAPISI BLYA\n"); while (1); // Ошибка записи } - loadPageDirectory(kernel_page_directory); - enablePaging(); + loadPageDirectory(kernel_page_directory); + enablePaging(); } -void *get_physaddr(void *virtualaddr) { - unsigned long pdindex = (unsigned long)virtualaddr >> 22; - unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF; - - unsigned long *pd = (unsigned long *)0xFFFFF000; - // Here you need to check whether the PD entry is present. - - unsigned long *pt = ((unsigned long *)0xFFC00000) + (0x400 * pdindex); - // Here you need to check whether the PT entry is present. - - return (void *)((pt[ptindex] & ~0xFFF) + ((unsigned long)virtualaddr & 0xFFF)); -} - -/** -Проверяем, существует ли таблица страниц (бит present в записи каталога). -Используем invlpg (inline assembly) для сброса TLB, чтобы процессор увидел изменения. -Пока вместо выделения новой таблицы страниц я добавил бесконечный цикл (while(1)). Позже мы заменим это аллокатором. -**/ - -void map_page(void *physaddr, void *virtualaddr, unsigned int flags) { - // Убеждаемся, что адреса выровнены по 4 КБ - uint32_t phys = (uint32_t)physaddr & ~0xFFF; // Обнуляем младшие 12 бит - uint32_t virt = (uint32_t)virtualaddr & ~0xFFF; - - // Вычисляем индексы - uint32_t pdindex = virt >> 22; // Индекс в каталоге страниц - uint32_t ptindex = (virt >> 12) & 0x3FF; // Индекс в таблице страниц - - uint32_t *pd = (uint32_t *)0xFFFFF000; // Адрес каталога страниц в виртуальной памяти - - // Проверяем, существует ли таблица страниц - if (!(pd[pdindex] & 0x1)) { // Бит 0 — "present" - // Если таблицы нет, создаём новую (для простоты пока паникуем) - void *new_pt = alloc_page(); - if (!new_pt) while (1); // Нет памяти - pd[pdindex] = (uint32_t)new_pt | 0x3; // present, writable - - // Очищаем новую таблицу - uint32_t *pt = ((uint32_t *)0xFFC00000) + (0x400 * pdindex); - for (int i = 0; i < 1024; i++) { - pt[i] = 0; // Все страницы "не присутствуют" - } - } - - // Получаем адрес таблицы страниц - uint32_t *pt = ((uint32_t *)0xFFC00000) + (0x400 * pdindex); - - // Устанавливаем отображение - pt[ptindex] = phys | (flags & 0xFFF) | 0x1; // Флаги + present - - // Сбрасываем TLB для этого адреса - asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory"); -} - -//map_kernel_page((void*)0xC0100000, 0x2); — отобразит страницу в ядре. -void map_kernel_page(void* virtualaddr, unsigned int flags) { - uint32_t virt = (uint32_t)virtualaddr & ~0xFFF; // Выравниваем по 4 КБ - if (virt < 0xC0000000) while(1); // Ошибка: ядро только выше 3 ГБ - - uint32_t pdindex = virt >> 22; // Индекс в каталоге - uint32_t ptindex = (virt >> 12) & 0x3FF; // Индекс в таблице страниц - - uint32_t* pd = (uint32_t*)0xFFFFF000; // Каталог страниц - - // Проверяем, существует ли таблица страниц - if (!(pd[pdindex] & 0x1)) { - void* new_pt = alloc_page(); - if (!new_pt) while(1); // Нет памяти - - // Убеждаемся, что адрес выровнен (опционально, если alloc_page() не гарантирует) - if ((uint32_t)new_pt & 0xFFF) while(1); // Ошибка выравнивания - - pd[pdindex] = ((uint32_t)new_pt) | 0x3; // Временно записываем в каталог - asm volatile("invlpg (%0)" : : "r" ((uint32_t)&pd[pdindex]) : "memory"); // Инвалидируем TLB - - uint32_t* pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex); - for (int i = 0; i < 1024; i++) { - pt[i] = 0; - } - } - - // Получаем таблицу страниц - uint32_t* pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex); - void* phys = alloc_page(); - if (!phys) while(1); - - // Проверяем, не занята ли страница - if (pt[ptindex] & 0x1) while(1); // Ошибка: страница уже отображена - - pt[ptindex] = (uint32_t)phys | (flags & 0xFFF) | 0x1; // supervisor, present - asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory"); -} - -/** -Dalshe idyot to chto napisal grok dlya processov v buduschem -**/ -/* -// Структура для процесса -typedef struct { - uint32_t page_directory[1024] __attribute__((aligned(4096))); // Каталог страниц процесса - uint32_t pid; // ID процесса (для примера) -} Process; - -// Создание нового процесса -//Создаёт новый каталог страниц для процесса, копируя ядро (768–1023 записи) и оставляя нижние 3 ГБ пустыми. -Process* create_process(uint32_t pid) { - Process* proc = (Process*)alloc_page(); // Выделяем страницу под структуру - if (!proc) return (Process*)0; // Нет памяти - - int i; - // Копируем каталог ядра в каталог процесса - for (i = 0; i < 1024; i++) { - proc->page_directory[i] = kernel_page_directory[i]; - } - - // Нижние 3 ГБ (0-767) изначально пустые - for (i = 0; i < 768; i++) { - proc->page_directory[i] = 0x00000002; // not present - } - - proc->pid = pid; - return proc; -} - -// Переключение на процесс -//Переключает процессор на каталог страниц процесса. -void switch_to_process(Process* proc) { - loadPageDirectory(proc->page_directory); -} - -//Выделяет страницу в пользовательском пространстве (ниже 0xC0000000) с флагами user-level (бит 2 = 1). -void map_user_page(Process* proc, void* virtualaddr, unsigned int flags) { - uint32_t virt = (uint32_t)virtualaddr & ~0xFFF; - if (virt >= 0xC0000000) while(1); // Ошибка: пользователь не может трогать ядро! - - uint32_t pdindex = virt >> 22; - uint32_t ptindex = (virt >> 12) & 0x3FF; - - // Проверяем, есть ли таблица страниц - if (!(proc->page_directory[pdindex] & 0x1)) { - void* new_pt = alloc_page(); - if (!new_pt) while(1); // Нет памяти - - // Новая таблица: user, writable, present (0x7 = 111b) - proc->page_directory[pdindex] = ((uint32_t)new_pt) | 0x7; - - // Очищаем таблицу - uint32_t* pt = (uint32_t*)new_pt; - for (int i = 0; i < 1024; i++) { - pt[i] = 0; // Все страницы "не присутствуют" - } - } - - // Получаем таблицу страниц - uint32_t* pt = (uint32_t*)(proc->page_directory[pdindex] & ~0xFFF); - void* phys = alloc_page(); - if (!phys) while(1); // Нет памяти - - // Отображаем страницу: user, flags, present - pt[ptindex] = (uint32_t)phys | (flags & 0xFFF) | 0x5; // 0x5 = 101b (present, user) - - // Сбрасываем TLB - asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory"); -} - -// Пример использования -void test_process() { - Process* proc = create_process(1); // Создаём процесс с PID 1 - map_user_page(proc, (void*)0x1000, 0x6); // Отображаем страницу на 0x1000 (writable, user) - switch_to_process(proc); // Переключаемся на процесс -} -*/ - -// Структура заголовка блока памяти -typedef struct Block { - uint32_t size; // Размер блока (в байтах, включая заголовок) - uint32_t is_free; // 1 = свободен, 0 = занят - struct Block* next; // Указатель на следующий блок -} Block; - -// Структура для управления кучей -typedef struct { - void* start; // Начало кучи - uint32_t size; // Текущий размер кучи в байтах - Block* first; // Первый блок в куче -} Heap; - -Heap kernel_heap; - -void heap_init() { - kernel_heap.start = (void*)0xD0000000; // Начало кучи в ядре - kernel_heap.size = 0x1000; // Начальный размер — 1 страница (4 КБ) - printf("before map_kernel_page\n"); - // Отображаем первую страницу - map_kernel_page(kernel_heap.start, 0x2); // writable, supervisor - printf("after map_kernel_page\n"); - // Создаём первый блок, который занимает всю страницу - Block* initial_block = (Block*)kernel_heap.start; - initial_block->size = 0x1000 - sizeof(Block); // Размер без учёта заголовка - initial_block->is_free = 1; // Свободен - initial_block->next = (Block*)0; // Пока нет следующего - - kernel_heap.first = initial_block; -} - -// Выделение памяти из кучи -//Ищет свободный блок подходящего размера. Если блок большой, делит его. -//Если свободных блоков нет, добавляет страницу. -void* heap_alloc(uint32_t size) { - // Выравниваем размер до 4 байт - size = (size + 3) & ~3; - - Block* current = kernel_heap.first; - Block* prev = (Block*)0; - - // Ищем подходящий свободный блок - while (current) { - if (current->is_free && current->size >= size) { - if (current->size >= size + sizeof(Block) + 4) { - Block* new_block = (Block*)((uint32_t)current + sizeof(Block) + size); - new_block->size = current->size - size - sizeof(Block); - new_block->is_free = 1; - new_block->next = current->next; - - current->size = size; - current->next = new_block; - } - current->is_free = 0; - return (void*)((uint32_t)current + sizeof(Block)); - } - prev = current; - current = current->next; - } - - // Нет подходящего блока — выделяем нужное количество страниц - uint32_t total_size = size + sizeof(Block); // Размер с заголовком - uint32_t pages_needed = (total_size + 0xFFF) / 0x1000; // Округляем вверх до страниц - uint32_t alloc_size = pages_needed * 0x1000; // Сколько байт выделяем - - void* new_page = (void*)((uint32_t)kernel_heap.start + kernel_heap.size); - for (uint32_t i = 0; i < pages_needed; i++) { - map_kernel_page((void*)((uint32_t)new_page + i * 0x1000), 0x2); - } - kernel_heap.size += alloc_size; - - Block* new_block = (Block*)new_page; - new_block->size = alloc_size - sizeof(Block); - new_block->is_free = 1; - new_block->next = (Block*)0; - - if (prev) prev->next = new_block; - if (!kernel_heap.first) kernel_heap.first = new_block; - - // Теперь current указывает на новый блок, продолжаем цикл - current = new_block; - if (current->size >= size) { - if (current->size >= size + sizeof(Block) + 4) { - Block* split_block = (Block*)((uint32_t)current + sizeof(Block) + size); - split_block->size = current->size - size - sizeof(Block); - split_block->is_free = 1; - split_block->next = current->next; - - current->size = size; - current->next = split_block; - } - current->is_free = 0; - return (void*)((uint32_t)current + sizeof(Block)); - } - - // Если что-то пошло не так, возвращаем NULL - return (void*)0; -} - -// Освобождение памяти -//Помечает блок как свободный и пытается объединить его с соседними свободными блоками, -//чтобы уменьшить фрагментацию. -void heap_free(void* ptr) { - if (!ptr || (uint32_t)ptr < (uint32_t)kernel_heap.start) return; - - // Находим блок по указателю (указатель указывает после заголовка) - Block* block = (Block*)((uint32_t)ptr - sizeof(Block)); - block->is_free = 1; - - // Слияние с предыдущим блоком, если он свободен - Block* current = kernel_heap.first; - Block* prev = (Block*)0; - while (current && current != block) { - prev = current; - current = current->next; - } - if (prev && prev->is_free) { - prev->size += sizeof(Block) + block->size; - prev->next = block->next; - block = prev; - } - - // Слияние с следующим блоком, если он свободен - if (block->next && block->next->is_free) { - block->size += sizeof(Block) + block->next->size; - block->next = block->next->next; - } -} - - -// Функция проверки страниц -void test_pages() { - // Тест 1: Проверка ядра - void* kernel_addr = (void*)0xC0100000; - map_kernel_page(kernel_addr, 0x2); // writable, supervisor - - // Записываем значение в страницу - uint32_t* kernel_ptr = (uint32_t*)kernel_addr; - *kernel_ptr = 0xDEADBEEF; - - // Проверяем, что значение записалось - if (*kernel_ptr == 0xDEADBEEF) { - // Успех! (в реальной ОС тут можно вывести сообщение через UART или VGA) +void test_paging() { + uint32_t* pd = (uint32_t*)0xFFFFF000; + uint32_t expected = (uint32_t)kernel_page_table | 0x3; + // Игнорируем дополнительные флаги, проверяем только базовый адрес и present + if ((pd[0] & ~0xFFF) == (expected & ~0xFFF)) { + // Успех } else { - while (1); // Ошибка + printf("RECURSION BROKEN!!\n"); + printf("pd[0] = 0x%X\n"); + printf("(uint32_t)first_page_table | 0x3 = %X", (uint32_t)kernel_page_table | 0x3); + while (1); // Рекурсия сломана } - /* - // Тест 2: Проверка пользовательского процесса - Process* proc = create_process(1); // Создаём процесс - void* user_addr = (void*)0x1000; - map_user_page(proc, user_addr, 0x6); // writable, user - - // Переключаемся на процесс - switch_to_process(proc); - - // Записываем значение - uint32_t* user_ptr = (uint32_t*)user_addr; - *user_ptr = 0xCAFEBABE; - - // Проверяем - if (*user_ptr == 0xCAFEBABE) { - // Успех! - } else { - while (1); // Ошибка - } - - // Возвращаемся в ядро - switch_to_process((Process*)0); // Предполагаем, что 0 вернёт нас к kernel_page_directory - */ - // Тест 3: Проверка кучи - heap_init(); - void* heap_ptr1 = heap_alloc(16); - uint32_t* heap_data1 = (uint32_t*)heap_ptr1; - *heap_data1 = 0x12345678; - - void* heap_ptr2 = heap_alloc(200); - uint32_t* heap_data2 = (uint32_t*)heap_ptr2; - *heap_data2 = 0x87654321; - - heap_free(heap_ptr1); - void* heap_ptr3 = heap_alloc(12); // Должно взять место ptr1 - - if (*heap_data1 == 0x12345678 && *heap_data2 == 0x87654321 && - heap_ptr3 == heap_ptr1) { - // Успех! - } else { - while (1); // Ошибка - } -} -/** -0xD0000000: Произвольный адрес в ядре (выше 0xC0000000), выбран для кучи, чтобы не пересекаться с другими данными. -0xFFFFF000: Виртуальный адрес каталога страниц благодаря рекурсивному отображению (последняя запись указывает на себя). -0xFFC00000: Начало области, где лежат все таблицы страниц, доступные через рекурсию. -**/ +} \ No newline at end of file diff --git a/src/mm/paging1.c b/src/mm/paging1.c new file mode 100644 index 0000000..31dd5f2 --- /dev/null +++ b/src/mm/paging1.c @@ -0,0 +1,503 @@ +#include "../include/paging.h" +#include +#include "../include/stdio.h" + +void enablePaging() { + asm volatile ( + "mov %%cr0, %%eax\n" + "or $0x80000000, %%eax\n" + "mov %%eax, %%cr0\n" + "jmp 1f\n" + "1:\n" + "mov %%cr3, %%eax\n" // Перезагрузка CR3 для сброса TLB + "mov %%eax, %%cr3\n" + "nop\n" + : + : + : "eax", "memory" + ); +} + +void loadPageDirectory(uint32_t* page_directory) { + asm volatile ( + "mov %0, %%cr3\n" // Загружаем физический адрес каталога страниц в CR3 + : // Нет выходных операндов + : "r" (page_directory) // Входной операнд — адрес каталога + : // Нет изменяемых регистров + ); +} + +uint32_t kernel_page_directory[1024] __attribute__((aligned(4096))); +uint32_t kernel_page_table[1024] __attribute__((aligned(4096))); + +// 16 МБ = 16 * 1024 * 1024 байт = 4096 страниц (по 4 КБ) +// 4096 бит = 512 байт +uint8_t page_bitmap[512]; // 1 бит на страницу + +/** +page_bitmap — массив, где каждый бит соответствует странице (0 = свободна, 1 = занята). +init_allocator помечает первые 4 МБ как занятые (там ядро). +alloc_page ищет первый свободный бит и возвращает адрес страницы. +free_page освобождает страницу, сбрасывая бит. +**/ + +void init_allocator() { + int i; + // Помечаем все страницы как свободные (0) + for (i = 0; i < 512; i++) { + page_bitmap[i] = 0; + } + // Первые 4 МБ уже заняты ядром (0x00000000–0x003FFFFF) + for (i = 0; i < 1024 / 8; i++) { // 1024 страницы = 128 байт + page_bitmap[i] = 0xFF; // Все биты = 1 (занято) + } +} + +// Выделяем свободную страницу +void* alloc_page() { +// printf("alloc_page called\n"); + int i, j; + for (i = 0; i < 512; i++) { + if (page_bitmap[i] != 0xFF) { + for (j = 0; j < 8; j++) { + if (!(page_bitmap[i] & (1 << j))) { + page_bitmap[i] |= (1 << j); + return (void*)(((i * 8) + j) * 0x1000); + } + } + } + } + printf("no bitches? no free pages?\n"); + return (void*)0; // Нет свободных страниц +} + +void test_paging() { + uint32_t* pd = (uint32_t*)0xFFFFF000; + uint32_t expected = (uint32_t)kernel_page_table | 0x3; + // Игнорируем дополнительные флаги, проверяем только базовый адрес и present + if ((pd[0] & ~0xFFF) == (expected & ~0xFFF)) { + // Успех + } else { + printf("RECURSION BROKEN!!\n"); + printf("pd[0] = 0x%X\n"); + printf("(uint32_t)first_page_table | 0x3 = %X", (uint32_t)kernel_page_table | 0x3); + while (1); // Рекурсия сломана + } +} + +// Освобождаем страницу +void free_page(void *physaddr) { + uint32_t page_num = (uint32_t)physaddr / 0x1000; + uint32_t byte_idx = page_num / 8; + uint32_t bit_idx = page_num % 8; + page_bitmap[byte_idx] &= ~(1 << bit_idx); // Сбрасываем бит +} + +/** +Теперь первые 4 МБ физической памяти отображаются на виртуальный адрес 0xC0000000 (3 ГБ), а не на 0x00000000. +Это оставляет нижние 3 ГБ (0x00000000–0xBFFFFFFF) свободными для пользовательских процессов. +**/ +void paging_init() +{ + int i; + + // Проверяем физические адреса + uint32_t pd_phys = (uint32_t)kernel_page_directory; + uint32_t pt_phys = (uint32_t)kernel_page_table; + + if (pd_phys & 0xFFF || pt_phys & 0xFFF) { + while (1); // Ошибка выравнивания + } + + // Заполняем каталог страниц + for (i = 0; i < 1024; i++) { + kernel_page_directory[i] = 0x00000002; // not present + } + + // Identity mapping для 0x00000000–0x003FFFFF + for (i = 0; i < 1024; i++) { + kernel_page_table[i] = (i * 0x1000) | 0x3; // supervisor, present + } + kernel_page_directory[0] = pt_phys | 0x3; + + // Рекурсивное отображение + kernel_page_directory[1023] = pd_phys | 0x3; + + // Проверяем перед загрузкой + if (kernel_page_directory[0] != (pt_phys | 0x3) || + kernel_page_directory[1023] != (pd_phys | 0x3)) { + printf("OSHIBKA ZAPISI BLYA\n"); + while (1); // Ошибка записи + } + loadPageDirectory(kernel_page_directory); + enablePaging(); +} + +void *get_physaddr(void *virtualaddr) { + unsigned long pdindex = (unsigned long)virtualaddr >> 22; + unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF; + + unsigned long *pd = (unsigned long *)0xFFFFF000; + // Here you need to check whether the PD entry is present. + + unsigned long *pt = ((unsigned long *)0xFFC00000) + (0x400 * pdindex); + // Here you need to check whether the PT entry is present. + + return (void *)((pt[ptindex] & ~0xFFF) + ((unsigned long)virtualaddr & 0xFFF)); +} + +/** +Проверяем, существует ли таблица страниц (бит present в записи каталога). +Используем invlpg (inline assembly) для сброса TLB, чтобы процессор увидел изменения. +Пока вместо выделения новой таблицы страниц я добавил бесконечный цикл (while(1)). Позже мы заменим это аллокатором. +**/ + +void map_page(void *physaddr, void *virtualaddr, unsigned int flags) { + // Убеждаемся, что адреса выровнены по 4 КБ + uint32_t phys = (uint32_t)physaddr & ~0xFFF; // Обнуляем младшие 12 бит + uint32_t virt = (uint32_t)virtualaddr & ~0xFFF; + + // Вычисляем индексы + uint32_t pdindex = virt >> 22; // Индекс в каталоге страниц + uint32_t ptindex = (virt >> 12) & 0x3FF; // Индекс в таблице страниц + + uint32_t *pd = (uint32_t *)0xFFFFF000; // Адрес каталога страниц в виртуальной памяти + + // Проверяем, существует ли таблица страниц + if (!(pd[pdindex] & 0x1)) { // Бит 0 — "present" + // Если таблицы нет, создаём новую (для простоты пока паникуем) + void *new_pt = alloc_page(); + if (!new_pt) while (1); // Нет памяти + pd[pdindex] = (uint32_t)new_pt | 0x3; // present, writable + + // Очищаем новую таблицу + uint32_t *pt = ((uint32_t *)0xFFC00000) + (0x400 * pdindex); + for (int i = 0; i < 1024; i++) { + pt[i] = 0; // Все страницы "не присутствуют" + } + } + + // Получаем адрес таблицы страниц + uint32_t *pt = ((uint32_t *)0xFFC00000) + (0x400 * pdindex); + + // Устанавливаем отображение + pt[ptindex] = phys | (flags & 0xFFF) | 0x1; // Флаги + present + + // Сбрасываем TLB для этого адреса + asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory"); +} + +//map_kernel_page((void*)0xC0100000, 0x2); — отобразит страницу в ядре. +void map_kernel_page(void* virtualaddr, unsigned int flags) { + uint32_t virt = (uint32_t)virtualaddr & ~0xFFF; // Выравниваем по 4 КБ + if (virt < 0xC0000000) while(1); // Ошибка: ядро только выше 3 ГБ + + uint32_t pdindex = virt >> 22; // Индекс в каталоге + uint32_t ptindex = (virt >> 12) & 0x3FF; // Индекс в таблице страниц + + uint32_t* pd = (uint32_t*)0xFFFFF000; // Каталог страниц + + // Проверяем, существует ли таблица страниц + if (!(pd[pdindex] & 0x1)) { + void* new_pt = alloc_page(); + if (!new_pt) while(1); // Нет памяти + + // Убеждаемся, что адрес выровнен (опционально, если alloc_page() не гарантирует) + if ((uint32_t)new_pt & 0xFFF) while(1); // Ошибка выравнивания + + pd[pdindex] = ((uint32_t)new_pt) | 0x3; // Временно записываем в каталог + asm volatile("invlpg (%0)" : : "r" ((uint32_t)&pd[pdindex]) : "memory"); // Инвалидируем TLB + + uint32_t* pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex); + for (int i = 0; i < 1024; i++) { + pt[i] = 0; + } + } + + // Получаем таблицу страниц + uint32_t* pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex); + void* phys = alloc_page(); + if (!phys) while(1); + + // Проверяем, не занята ли страница + if (pt[ptindex] & 0x1) while(1); // Ошибка: страница уже отображена + + pt[ptindex] = (uint32_t)phys | (flags & 0xFFF) | 0x1; // supervisor, present + asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory"); +} + +// Структура заголовка блока памяти +typedef struct Block { + uint32_t size; // Размер блока (в байтах, включая заголовок) + uint32_t is_free; // 1 = свободен, 0 = занят + struct Block* next; // Указатель на следующий блок +} Block; + +// Структура для управления кучей +typedef struct { + void* start; // Начало кучи + uint32_t size; // Текущий размер кучи в байтах + Block* first; // Первый блок в куче +} Heap; + +Heap kernel_heap; + +void heap_init() { + kernel_heap.start = (void*)0xD0000000; // Начало кучи в ядре + kernel_heap.size = 0x1000; // Начальный размер — 1 страница (4 КБ) + printf("before map_kernel_page\n"); + // Отображаем первую страницу + map_kernel_page(kernel_heap.start, 0x2); // writable, supervisor + printf("after map_kernel_page\n"); + // Создаём первый блок, который занимает всю страницу + Block* initial_block = (Block*)kernel_heap.start; + initial_block->size = 0x1000 - sizeof(Block); // Размер без учёта заголовка + initial_block->is_free = 1; // Свободен + initial_block->next = (Block*)0; // Пока нет следующего + + kernel_heap.first = initial_block; +} + +// Выделение памяти из кучи +//Ищет свободный блок подходящего размера. Если блок большой, делит его. +//Если свободных блоков нет, добавляет страницу. +void* heap_alloc(uint32_t size) { + // Выравниваем размер до 4 байт + size = (size + 3) & ~3; + + Block* current = kernel_heap.first; + Block* prev = (Block*)0; + + // Ищем подходящий свободный блок + while (current) { + if (current->is_free && current->size >= size) { + if (current->size >= size + sizeof(Block) + 4) { + Block* new_block = (Block*)((uint32_t)current + sizeof(Block) + size); + new_block->size = current->size - size - sizeof(Block); + new_block->is_free = 1; + new_block->next = current->next; + + current->size = size; + current->next = new_block; + } + current->is_free = 0; + return (void*)((uint32_t)current + sizeof(Block)); + } + prev = current; + current = current->next; + } + + // Нет подходящего блока — выделяем нужное количество страниц + uint32_t total_size = size + sizeof(Block); // Размер с заголовком + uint32_t pages_needed = (total_size + 0xFFF) / 0x1000; // Округляем вверх до страниц + uint32_t alloc_size = pages_needed * 0x1000; // Сколько байт выделяем + + void* new_page = (void*)((uint32_t)kernel_heap.start + kernel_heap.size); + for (uint32_t i = 0; i < pages_needed; i++) { + map_kernel_page((void*)((uint32_t)new_page + i * 0x1000), 0x2); + } + kernel_heap.size += alloc_size; + + Block* new_block = (Block*)new_page; + new_block->size = alloc_size - sizeof(Block); + new_block->is_free = 1; + new_block->next = (Block*)0; + + if (prev) prev->next = new_block; + if (!kernel_heap.first) kernel_heap.first = new_block; + + // Теперь current указывает на новый блок, продолжаем цикл + current = new_block; + if (current->size >= size) { + if (current->size >= size + sizeof(Block) + 4) { + Block* split_block = (Block*)((uint32_t)current + sizeof(Block) + size); + split_block->size = current->size - size - sizeof(Block); + split_block->is_free = 1; + split_block->next = current->next; + + current->size = size; + current->next = split_block; + } + current->is_free = 0; + return (void*)((uint32_t)current + sizeof(Block)); + } + + // Если что-то пошло не так, возвращаем NULL + return (void*)0; +} + +// Освобождение памяти +//Помечает блок как свободный и пытается объединить его с соседними свободными блоками, +//чтобы уменьшить фрагментацию. +void heap_free(void* ptr) { + if (!ptr || (uint32_t)ptr < (uint32_t)kernel_heap.start) return; + + // Находим блок по указателю (указатель указывает после заголовка) + Block* block = (Block*)((uint32_t)ptr - sizeof(Block)); + block->is_free = 1; + + // Слияние с предыдущим блоком, если он свободен + Block* current = kernel_heap.first; + Block* prev = (Block*)0; + while (current && current != block) { + prev = current; + current = current->next; + } + if (prev && prev->is_free) { + prev->size += sizeof(Block) + block->size; + prev->next = block->next; + block = prev; + } + + // Слияние с следующим блоком, если он свободен + if (block->next && block->next->is_free) { + block->size += sizeof(Block) + block->next->size; + block->next = block->next->next; + } +} + + +// Функция проверки страниц +void test_pages() { + // Тест 1: Проверка ядра + void* kernel_addr = (void*)0xC0100000; + map_kernel_page(kernel_addr, 0x2); // writable, supervisor + + // Записываем значение в страницу + uint32_t* kernel_ptr = (uint32_t*)kernel_addr; + *kernel_ptr = 0xDEADBEEF; + + // Проверяем, что значение записалось + if (*kernel_ptr == 0xDEADBEEF) { + // Успех! (в реальной ОС тут можно вывести сообщение через UART или VGA) + } else { + while (1); // Ошибка + } + /* + // Тест 2: Проверка пользовательского процесса + Process* proc = create_process(1); // Создаём процесс + void* user_addr = (void*)0x1000; + map_user_page(proc, user_addr, 0x6); // writable, user + + // Переключаемся на процесс + switch_to_process(proc); + + // Записываем значение + uint32_t* user_ptr = (uint32_t*)user_addr; + *user_ptr = 0xCAFEBABE; + + // Проверяем + if (*user_ptr == 0xCAFEBABE) { + // Успех! + } else { + while (1); // Ошибка + } + + // Возвращаемся в ядро + switch_to_process((Process*)0); // Предполагаем, что 0 вернёт нас к kernel_page_directory + */ + // Тест 3: Проверка кучи + heap_init(); + void* heap_ptr1 = heap_alloc(16); + uint32_t* heap_data1 = (uint32_t*)heap_ptr1; + *heap_data1 = 0x12345678; + + void* heap_ptr2 = heap_alloc(200); + uint32_t* heap_data2 = (uint32_t*)heap_ptr2; + *heap_data2 = 0x87654321; + + heap_free(heap_ptr1); + void* heap_ptr3 = heap_alloc(12); // Должно взять место ptr1 + + if (*heap_data1 == 0x12345678 && *heap_data2 == 0x87654321 && + heap_ptr3 == heap_ptr1) { + // Успех! + } else { + while (1); // Ошибка + } +} +/** +0xD0000000: Произвольный адрес в ядре (выше 0xC0000000), выбран для кучи, чтобы не пересекаться с другими данными. +0xFFFFF000: Виртуальный адрес каталога страниц благодаря рекурсивному отображению (последняя запись указывает на себя). +0xFFC00000: Начало области, где лежат все таблицы страниц, доступные через рекурсию. +**/ + +/** +Dalshe idyot to chto napisal grok dlya processov v buduschem +**/ +/* +// Структура для процесса +typedef struct { + uint32_t page_directory[1024] __attribute__((aligned(4096))); // Каталог страниц процесса + uint32_t pid; // ID процесса (для примера) +} Process; + +// Создание нового процесса +//Создаёт новый каталог страниц для процесса, копируя ядро (768–1023 записи) и оставляя нижние 3 ГБ пустыми. +Process* create_process(uint32_t pid) { + Process* proc = (Process*)alloc_page(); // Выделяем страницу под структуру + if (!proc) return (Process*)0; // Нет памяти + + int i; + // Копируем каталог ядра в каталог процесса + for (i = 0; i < 1024; i++) { + proc->page_directory[i] = kernel_page_directory[i]; + } + + // Нижние 3 ГБ (0-767) изначально пустые + for (i = 0; i < 768; i++) { + proc->page_directory[i] = 0x00000002; // not present + } + + proc->pid = pid; + return proc; +} + +// Переключение на процесс +//Переключает процессор на каталог страниц процесса. +void switch_to_process(Process* proc) { + loadPageDirectory(proc->page_directory); +} + +//Выделяет страницу в пользовательском пространстве (ниже 0xC0000000) с флагами user-level (бит 2 = 1). +void map_user_page(Process* proc, void* virtualaddr, unsigned int flags) { + uint32_t virt = (uint32_t)virtualaddr & ~0xFFF; + if (virt >= 0xC0000000) while(1); // Ошибка: пользователь не может трогать ядро! + + uint32_t pdindex = virt >> 22; + uint32_t ptindex = (virt >> 12) & 0x3FF; + + // Проверяем, есть ли таблица страниц + if (!(proc->page_directory[pdindex] & 0x1)) { + void* new_pt = alloc_page(); + if (!new_pt) while(1); // Нет памяти + + // Новая таблица: user, writable, present (0x7 = 111b) + proc->page_directory[pdindex] = ((uint32_t)new_pt) | 0x7; + + // Очищаем таблицу + uint32_t* pt = (uint32_t*)new_pt; + for (int i = 0; i < 1024; i++) { + pt[i] = 0; // Все страницы "не присутствуют" + } + } + + // Получаем таблицу страниц + uint32_t* pt = (uint32_t*)(proc->page_directory[pdindex] & ~0xFFF); + void* phys = alloc_page(); + if (!phys) while(1); // Нет памяти + + // Отображаем страницу: user, flags, present + pt[ptindex] = (uint32_t)phys | (flags & 0xFFF) | 0x5; // 0x5 = 101b (present, user) + + // Сбрасываем TLB + asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory"); +} + +// Пример использования +void test_process() { + Process* proc = create_process(1); // Создаём процесс с PID 1 + map_user_page(proc, (void*)0x1000, 0x6); // Отображаем страницу на 0x1000 (writable, user) + switch_to_process(proc); // Переключаемся на процесс +} +*/ \ No newline at end of file