From 767e74976fc03979b7080660e71985202d131e0d Mon Sep 17 00:00:00 2001 From: Ruslan Isaev Date: Fri, 9 May 2025 20:07:50 +0300 Subject: [PATCH] merge branch memory-shit into higher-half --- Makefile | 7 +- include/gdt.h | 4 +- include/multiboot.h | 6 +- include/paging.h | 17 +++++ src/kernel/gdt.c | 28 +++++++- src/kernel/isr.asm | 47 +++++++++++++ src/kernel/isr.c | 28 +++++++- src/kernel/kernel.c | 31 +++++++-- src/mm/heap.c | 8 ++- src/mm/page_alloc.c | 83 +++++++++-------------- src/mm/page_tables.c | 142 +++++++++++++++++++++++++++++---------- src/mm/paging.c | 115 ++++++++++++++++++------------- src/tasking/sys_exit.asm | 2 +- src/tasking/task.c | 79 ++++++++++++++-------- 14 files changed, 419 insertions(+), 178 deletions(-) create mode 100644 src/kernel/isr.asm diff --git a/Makefile b/Makefile index 84a9b7f..6a22dad 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ 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 bin/sys_exit.o bin/gdt.o + bin/fat.o bin/task.o bin/switch.o bin/sys_exit.o bin/gdt.o bin/isr-asm.o # Define the compiler and assembler #CC = i686-elf-gcc -D__is_katauos @@ -16,7 +16,7 @@ CFLAGS = -I./include/ -std=gnu99 -ffreestanding -O0 -Wall -Wextra -m32 -fno-pie ASFLAGS = -f elf32 # Define the linker flags -LDFLAGS = -m elf_i386 -L$(shell $(CC) -print-libgcc-file-name | xargs dirname) +LDFLAGS = -m elf_i386 -L$(shell $(CC) -print-libgcc-file-name | xargs dirname)/32/ -lgcc LDSCRIPT = link.ld # Define the output file @@ -124,6 +124,9 @@ bin/sys_exit.o: src/tasking/sys_exit.asm bin/gdt.o: src/kernel/gdt.c $(CC) $(CFLAGS) -c $< -o $@ +bin/isr-asm.o: src/kernel/isr.asm + $(AS) $(ASFLAGS) $< -o $@ + clean: rm -rf bin/ rm -f $(OUTPUT) diff --git a/include/gdt.h b/include/gdt.h index 3a7a4f3..bcf6fe3 100644 --- a/include/gdt.h +++ b/include/gdt.h @@ -88,7 +88,9 @@ struct tss_entry_struct { uint32_t ldt; uint16_t trap; uint16_t iomap_base; -} __packed; +} __attribute__((packed)); + +extern struct tss_entry_struct tss; struct seg_desc gdt[NR_GDT_ENTRIES]; diff --git a/include/multiboot.h b/include/multiboot.h index 269cf9b..b2929b3 100644 --- a/include/multiboot.h +++ b/include/multiboot.h @@ -230,8 +230,10 @@ struct multiboot_color struct multiboot_mmap_entry { multiboot_uint32_t size; - multiboot_uint64_t addr; - multiboot_uint64_t len; + multiboot_uint32_t addr_low; + multiboot_uint32_t addr_high; + multiboot_uint32_t len_low; + multiboot_uint32_t len_high; #define MULTIBOOT_MEMORY_AVAILABLE 1 #define MULTIBOOT_MEMORY_RESERVED 2 #define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 diff --git a/include/paging.h b/include/paging.h index d1189ab..081339f 100644 --- a/include/paging.h +++ b/include/paging.h @@ -22,10 +22,23 @@ #define GET_PGDIR(address) ((uint32_t)((address) >> 22) & 0x3FF) #define GET_PGTBL(address) ((uint32_t)((address) >> 12) & 0x3FF) +#define PAGE_SIZE 0x1000 // 4 КБ + +// Общий размер памяти +#define MEMORY_SIZE (0xFFFFFFFF-0xC0000000) + +// Количество страниц +#define PAGE_COUNT (MEMORY_SIZE / PAGE_SIZE) + +// Размер битмапа в байтах (округлено вверх) +#define BITMAP_SIZE (PAGE_COUNT / 8) + extern uint32_t kernel_page_directory[1024] __attribute__((aligned(4096))); extern uint32_t kernel_page_table[1024] __attribute__((aligned(4096))); extern uint32_t user_page_table[1024] __attribute__((aligned(4096))); +extern uint32_t *kpage_dir; + //paging.c void grub_memory_map(unsigned int magic, struct multiboot_info* mbi); void enablePaging(); @@ -34,13 +47,17 @@ void paging_init(); void test_paging(); //page_alloc.c +void set_bit(uint32_t page_index); +void clear_bit(uint32_t page_index); void init_allocator(); void* alloc_page(); void free_page(void* physaddr); //page_tables.c void *get_physaddr(void *virtualaddr); +uint32_t get_pte(void *virtualaddr); void map_page(void* physaddr, void* virtualaddr, unsigned int flags); +void unmap_page(void *virtualaddr); void map_kernel_page(void* virtualaddr, unsigned int flags); void* setup_user_process(void* user_code_phys, uint32_t* user_stack_top); diff --git a/src/kernel/gdt.c b/src/kernel/gdt.c index 5cfe527..1a19b84 100644 --- a/src/kernel/gdt.c +++ b/src/kernel/gdt.c @@ -2,6 +2,8 @@ #include "../include/string.h" #include "../include/paging.h" +struct tss_entry_struct tss; + void bss_init() { memset((void *)((int)_edata), 0, KERNEL_BSS_SIZE); @@ -29,6 +31,16 @@ void load_gdt(uint32_t gdt_ptr) { ); } +void flush_tss(void) { + asm volatile ( + "mov %0, %%ax\n\t" + "ltr %%ax\n\t" + : + : "i" (0x28) + : "ax" + ); +} + static void gdt_set_entry(int num, uint32_t base_addr, uint32_t limit, char loflags, char hiflags) { num /= sizeof(struct seg_desc); @@ -44,6 +56,17 @@ void gdt_init(void) { uint8_t loflags; + memset(&tss, 0, sizeof(tss)); + tss.ss0 = KERNEL_DS; + tss.iomap_base = 0xFFFF; // Disable I/O bitmap + tss.esp0 = 0xC0010000; /* kernel stack address (firstly defined in boot.asm)*/ + tss.cs = KERNEL_CS; + tss.ds = KERNEL_DS; + tss.es = KERNEL_DS; + tss.fs = KERNEL_DS; + tss.gs = KERNEL_DS; + tss.ss = KERNEL_DS; + gdt_set_entry(0, 0, 0, 0, 0); /* null descriptor */ loflags = SD_CODE | SD_CD | SD_DPL0 | SD_PRESENT; @@ -56,8 +79,9 @@ void gdt_init(void) loflags = SD_DATA | SD_CD | SD_DPL3 | SD_PRESENT; gdt_set_entry(USER_DS, 0, 0xFFFFFFFF, loflags, SD_OPSIZE32 | SD_PAGE4KB); - loflags = SD_TSSPRESENT; - gdt_set_entry(TSS, 0, sizeof(struct tss_entry_struct), loflags, SD_OPSIZE32); + loflags = 0x89; // P=1, DPL=0, S=0 (system), Type=0x9 (32-bit TSS) + gdt_set_entry(TSS, (uint32_t)&tss, sizeof(struct tss_entry_struct) - 1, SD_PRESENT | SD_DPL0 | SD_TSSPRESENT, 0); load_gdt((uint32_t)&gdtr); + flush_tss(); } diff --git a/src/kernel/isr.asm b/src/kernel/isr.asm new file mode 100644 index 0000000..8822ba4 --- /dev/null +++ b/src/kernel/isr.asm @@ -0,0 +1,47 @@ +section .text +global page_fault_handler +extern handle_page_fault ; C function to process the fault + +page_fault_handler: + ; Save registers to preserve state + pushad ; Push EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI + push ds + push es + push fs + push gs + + ; Set up kernel data segment + mov ax, 0x10 ; Kernel data segment selector (adjust based on your GDT) + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ; Get the faulting address from CR2 + mov eax, cr2 + + ; Push parameters for the C function: + ; - Faulting address (from CR2) + ; - Error code (at [esp + 48], after pushed registers and segment selectors) + push eax ; Push CR2 (faulting address) + mov ebx, [esp + 48] ; Get error code (adjust offset based on stack layout) + push ebx ; Push error code + + ; Call the C handler + call handle_page_fault + + ; Clean up parameters from stack + add esp, 8 ; Remove error code and CR2 + + ; Restore registers + pop gs + pop fs + pop es + pop ds + popad + + ; Remove error code from stack + add esp, 4 ; Pop error code + + ; Return from interrupt + iret ; Restore EIP, CS, EFLAGS (and ESP, SS if privilege change) diff --git a/src/kernel/isr.c b/src/kernel/isr.c index 2217b08..918473e 100644 --- a/src/kernel/isr.c +++ b/src/kernel/isr.c @@ -23,6 +23,7 @@ void isr_custom(); void default_handler(); extern void sys_exit_handler(); +extern void page_fault_handler(); void isr_install() { idt_set_descriptor(0, (uint32)isr0, 0x8E); @@ -39,7 +40,7 @@ void isr_install() { idt_set_descriptor(11, (uint32)isr11, 0x8E); idt_set_descriptor(12, (uint32)isr12, 0x8E); idt_set_descriptor(13, (uint32)isr13, 0x8E); - idt_set_descriptor(14, (uint32)isr14, 0x8E); + idt_set_descriptor(14, (uint32)page_fault_handler, 0x8E); idt_set_descriptor(15, (uint32)isr15, 0x8E); idt_set_descriptor(16, (uint32)isr16, 0x8E); idt_set_descriptor(17, (uint32)isr17, 0x8E); @@ -75,6 +76,31 @@ void default_handler() } +#include "../include/paging.h" + +void handle_page_fault(uint32_t error_code, uint32_t faulting_address) +{ + int present = !(error_code & 0x1); // Bit 0: 0 = not present, 1 = protection violation + int write = error_code & 0x2; // Bit 1: 0 = read, 1 = write + int user = error_code & 0x4; // Bit 2: 0 = supervisor, 1 = user + int reserved = error_code & 0x8; // Bit 3: 0 = no reserved bits, 1 = reserved bits + int instruction = error_code & 0x10; // Bit 4: 0 = data, 1 = instruction fetch + + uint32_t pte = get_pte((void*)faulting_address); + + printf("Page fault at address 0x%x\n", faulting_address); + printf("Present: %X, Write: %X, User: %X, Reserved: %X, Instruction: %X\n", + present, write, user, reserved, instruction); + + printf("PTE: 0x%X (phys: 0x%X, %s, %s)\n", pte, pte & ~0xFFF, + (pte & 0x2) ? "writable" : "read-only", + (pte & 0x4) ? "user" : "supervisor"); + + printf("ERR: 0x%X\n", error_code); + + asm("hlt"); +} + __attribute__((interrupt)) void isr_timer(struct interrupt_frame *frame) { pit_init(100); diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 7caa3f5..4dc7567 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -153,7 +153,13 @@ void kmain(unsigned int magic, unsigned int info) printf("bootloader: %s\n", mbi.boot_loader_name); } + printf("init_allocator..."); + init_allocator(); + printf("done\n"); + + printf("grub_memory_map..."); grub_memory_map(magic, &mbi); + printf("done\n"); isr_install(); pic_remap(0x20, 0x28); @@ -161,14 +167,27 @@ void kmain(unsigned int magic, unsigned int info) apply_pic_masks(); + printf("done fucking with pages and memory map!\n"); + char *test_str; + printf("test_str: %X, &test_str %X\n", test_str, &test_str); + test_str = alloc_page(); + printf("test_str: %X, &test_str %X\n", test_str, &test_str); + free_page(test_str); + + alloc_page();//TODO: fix this this, because now we MUST allocate a page for checks of successfulness of allocation to pass + //the first page is at 0x0 and in check we check by if(!) which returns 0 (false), yeah + + + //while(1){} + //paging_init(); //printf("paging_init done\n"); //test_paging(); - init_allocator(); - heap_init(); - printf("after heap_init\n"); + + //heap_init(); + //printf("after heap_init\n"); __asm__ __volatile__ ("sti"); - //scheduler_init(); + scheduler_init(); printf("Kernel init sequence completed\n"); char yooo[256] = "heheh"; @@ -185,8 +204,8 @@ void kmain(unsigned int magic, unsigned int info) char temp1[1024] = "rusya_krutoy"; char temp2[1024] = "katya_tozhe_krutaya"; - huy = heap_alloc(1024); - huy2 = heap_alloc(1024); + huy = alloc_page();//heap_alloc(1024); + huy2 = alloc_page();//heap_alloc(1024); memcpy(huy, temp1, sizeof(temp1)); memcpy(huy2, temp2, sizeof(temp1)); diff --git a/src/mm/heap.c b/src/mm/heap.c index fbfb746..b0f0bef 100644 --- a/src/mm/heap.c +++ b/src/mm/heap.c @@ -33,7 +33,7 @@ void heap_init() { kernel_heap.first = initial_block; } - +/* void* heap_alloc(uint32_t size) { // Выравниваем размер до 4 байт size = (size + 3) & ~3; @@ -98,6 +98,12 @@ void* heap_alloc(uint32_t size) { // Если что-то пошло не так, возвращаем NULL return (void*)0; } +*/ +//TODO: fix it yo +void *heap_alloc(uint32_t size) +{ + return alloc_page(); +} void heap_free(void* ptr) { if (!ptr || (uint32_t)ptr < (uint32_t)kernel_heap.start) return; diff --git a/src/mm/page_alloc.c b/src/mm/page_alloc.c index f367ac5..bb16eb9 100644 --- a/src/mm/page_alloc.c +++ b/src/mm/page_alloc.c @@ -1,61 +1,61 @@ #include "../include/paging.h" #include #include "../include/stdio.h" - -#define PAGE_SIZE 0x1000 // 4 КБ - -// Общий размер памяти -#define MEMORY_SIZE 0x100000000 // 4 ГБ - -// Количество страниц -#define PAGE_COUNT (MEMORY_SIZE / PAGE_SIZE) // 1 048 576 страниц - -// Размер битмапа в байтах (округлено вверх) -#define BITMAP_SIZE (PAGE_COUNT / 8) // 131 072 байт +#include "../include/string.h" // Битмап для отслеживания страниц // Каждый бит представляет одну страницу: 0 = свободна, 1 = занята uint8_t page_bitmap[BITMAP_SIZE]; +// Установить бит (пометить страницу как занятую) +void set_bit(uint32_t page_index) { + uint32_t byte_index = page_index / 8; // Номер байта в битовой карте + uint8_t bit_offset = page_index % 8; // Смещение бита в байте + page_bitmap[byte_index] |= (1 << bit_offset); // Устанавливаем бит +} + +// Сбросить бит (пометить страницу как свободную) +void clear_bit(uint32_t page_index) { + if (page_index >= PAGE_COUNT) { + printf("clear_bit: address out of range\n"); + return; + } + + uint32_t byte_index = page_index / 8; + uint8_t bit_offset = page_index % 8; + + //check if this is needed at all except for debug purposes + if(!(page_bitmap[byte_index] & (1 << bit_offset))) + { + printf("clear_bit: page #0x%X already free\n", page_index); + return; + } + + page_bitmap[byte_index] &= ~(1 << bit_offset); // Сбрасываем бит +} + // Инициализация аллокатора страниц void init_allocator() { int i; - // Помечаем все страницы как свободные (0) - for (i = 0; i < BITMAP_SIZE; i++) { - page_bitmap[i] = 0; - } - - // Резервируем первые 4 МБ для ядра (0x00000000-0x003FFFFF) - // Это 1024 страницы или 128 байт битмапа - for (i = 0; i < 1024 / 8; i++) { - page_bitmap[i] = 0xFF; // Все биты = 1 (занято) - } - - // Если вы используете higher-half kernel, то нужно также - // зарезервировать соответствующую область в верхней части памяти - // Например, если ядро отображено начиная с 0xC0000000 (3 ГБ): - uint32_t kernel_higher_start = 0xC0000000 / PAGE_SIZE / 8; // Индекс в битмапе - for (i = kernel_higher_start; i < kernel_higher_start + 1024 / 8; i++) { - page_bitmap[i] = 0xFF; - } + memset(page_bitmap, 0x00, BITMAP_SIZE); } void* alloc_page() { int i, j; - // Проходим по всему битмапу for (i = 0; i < BITMAP_SIZE; i++) { if (page_bitmap[i] != 0xFF) { // Если в этом байте есть свободная страница + //printf("!!!free page at 0x%X!!!\n", i); for (j = 0; j < 8; j++) { if (!(page_bitmap[i] & (1 << j))) { // Если этот бит = 0 (свободен) page_bitmap[i] |= (1 << j); // Помечаем как занятый // Вычисляем физический адрес страницы uint32_t page_num = i * 8 + j; - void* addr = (void*)(page_num * PAGE_SIZE); + void* addr = (void*)(page_num * PAGE_SIZE); - printf("allocated page at 0x%X (page #0x%X)\n", addr, page_num); + //printf("allocated page at 0x%X (page #0x%X)\n", addr, page_num); return (void*)(page_num * PAGE_SIZE); } @@ -79,22 +79,5 @@ void free_page(void* physaddr) { // Вычисляем номер страницы uint32_t page_num = addr / PAGE_SIZE; - // Проверка границ - if (page_num >= PAGE_COUNT) { - printf("free_page: address out of range\n"); - return; - } - - // Вычисляем индекс байта и бита в битмапе - uint32_t byte_idx = page_num / 8; - uint32_t bit_idx = page_num % 8; - - // Проверяем, не освобождаем ли уже свободную страницу - if (!(page_bitmap[byte_idx] & (1 << bit_idx))) { - printf("free_page: page already free\n"); - return; - } - - // Освобождаем страницу - page_bitmap[byte_idx] &= ~(1 << bit_idx); + clear_bit(page_num); } diff --git a/src/mm/page_tables.c b/src/mm/page_tables.c index 34a01b1..263eb03 100644 --- a/src/mm/page_tables.c +++ b/src/mm/page_tables.c @@ -1,17 +1,67 @@ #include "../include/paging.h" #include +#include "../include/string.h" + +uint32_t get_pte(void *virtualaddr) { + uint32_t pdindex = (uint32_t)virtualaddr >> 22; + uint32_t ptindex = (uint32_t)virtualaddr >> 12 & 0x3FF; + uint32_t *pd = (uint32_t *)0xFFFFF000; + + if (!(pd[pdindex] & 0x1)) { + printf("GET_PTE ERROR: PT not present\n"); + return 0; + } + + uint32_t *pt = (uint32_t*)(0xFFC00000 + (pdindex << 12)); + + return pt[ptindex]; +} static uint32_t next_user_virt = 0x00400000; void* setup_user_process(void* user_code_phys, uint32_t* user_stack_top) { + if ((uint32_t)user_code_phys & 0xFFF) { + printf("SETUP_USER_PROCESS ERROR: user_code_phys not aligned\n"); + return 0; + } + + void* stack_phys = alloc_page(); if (!stack_phys) return 0; uint32_t code_virt = next_user_virt; uint32_t stack_virt = code_virt + 0x3FF000; // 4 МБ - 4 КБ + + if (next_user_virt >= 0xC0000000 - 0x400000) { + printf("SETUP_USER_PROCESS ERROR: out of user address space\n"); + return 0; + } + + unmap_page((void*)code_virt); + unmap_page((void*)stack_virt); + + map_page(user_code_phys, (void*)code_virt, 0x7); map_page(stack_phys, (void*)stack_virt, 0x7); + + // Verify mappings + uint32_t code_pte = get_pte((void*)code_virt); + uint32_t stack_pte = get_pte((void*)stack_virt); + uint32_t check_pte = get_pte((void*)0x00400000); - *user_stack_top = stack_virt + 0x1000; + printf("Code PTE at 0x%x: 0x%x (phys 0x%x, %s, %s)\n", + code_virt, code_pte, code_pte & ~0xFFF, + (code_pte & 0x2) ? "writable" : "read-only", + (code_pte & 0x4) ? "user" : "supervisor"); + printf("Stack PTE at 0x%x: 0x%x (phys 0x%x, %s, %s)\n", + stack_virt, stack_pte, stack_pte & ~0xFFF, + (stack_pte & 0x2) ? "writable" : "read-only", + (stack_pte & 0x4) ? "user" : "supervisor"); + printf("PTE for 0x00400000: 0x%x (phys 0x%x, %s, %s)\n", + check_pte, check_pte & ~0xFFF, + (check_pte & 0x2) ? "writable" : "read-only", + (check_pte & 0x4) ? "user" : "supervisor"); + + *user_stack_top = stack_virt + 0x1000 -4;//here we place the stack pointer to its top (because the stack is growing down) next_user_virt += 0x400000; // Следующий 4 МБ блок return (void*)code_virt; } @@ -34,41 +84,62 @@ void *get_physaddr(void *virtualaddr) { 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; // Все страницы "не присутствуют" - } +void map_page(void *physaddr, void *virtualaddr, unsigned int flags) { + // Make sure that both addresses are page-aligned. + if ((unsigned long)physaddr & 0xFFF || (unsigned long)virtualaddr & 0xFFF) { + // Error handling: addresses not page-aligned + printf("MAP_PAGE ERROR: address not page-aligned\n"); + return; } - // Получаем адрес таблицы страниц - uint32_t *pt = ((uint32_t *)0xFFC00000) + (0x400 * pdindex); - // Устанавливаем отображение - pt[ptindex] = phys | (flags & 0xFFF) | 0x1; // Флаги + present + unsigned long pdindex = (unsigned long)virtualaddr >> 22; + unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF; - // Сбрасываем TLB для этого адреса + unsigned long *pd = (unsigned long *)0xFFFFF000; + // Here you need to check whether the PD entry is present. + // When it is not present, you need to create a new empty PT and + // adjust the PDE accordingly. + + if (!(pd[pdindex] & 0x1)) { // If PDE not present + unsigned long *new_pt = alloc_page(); + unsigned long *virt_pt = (unsigned long *)(0xC0000000 + new_pt); + memset(virt_pt, 0, 4096); + //pd[pdindex] = (uint32_t)new_pt | 0x3; // Present, R/W + pd[pdindex] = (uint32_t)new_pt | (flags & 0x7); // Add User bit if needed + } + + unsigned long *pt = ((unsigned long *)0xFFC00000) + (0x400 * pdindex); + // Here you need to check whether the PT entry is present. + // When it is, then there is already a mapping present. What do you do now? + + pt[ptindex] = ((unsigned long)physaddr) | (flags & 0xFFF); // Present + + // Now you need to flush the entry in the TLB + // or you might not notice the change. asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory"); } +void unmap_page(void *virtualaddr) { + // Calculate page directory and page table indices + unsigned long pdindex = (unsigned long)virtualaddr >> 22; + unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF; + + // Get the page directory + unsigned long *pd = (unsigned long *)0xFFFFF000; + + if (pd[pdindex] & 0x1) { // Check if the page directory entry is present + // Get the page table + unsigned long *pt = (unsigned long *)(0xFFC00000 + (pdindex << 12)); + + // Clear the page table entry (remove the mapping) + pt[ptindex] = 0; + + // Invalidate the TLB entry for this virtual address + 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 ГБ @@ -76,27 +147,26 @@ void map_kernel_page(void* virtualaddr, unsigned int flags) { uint32_t pdindex = virt >> 22; // Индекс в каталоге uint32_t ptindex = (virt >> 12) & 0x3FF; // Индекс в таблице страниц - uint32_t* pd = (uint32_t*)0xFFFFF000; // Каталог страниц - // Проверяем, существует ли таблица страниц - if (!(pd[pdindex] & 0x1)) { + if (!(kpage_dir[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 + kpage_dir[pdindex] = ((uint32_t)new_pt) | 0x3; // Временно записываем в каталог + asm volatile("invlpg (%0)" : : "r" ((uint32_t)&kpage_dir[pdindex]) : "memory"); // Инвалидируем TLB - uint32_t* pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex); + uint32_t* pt = ((uint32_t*)kpage_dir+0x1000) + (0x400 * pdindex); + for (int i = 0; i < 1024; i++) { pt[i] = 0; } } // Получаем таблицу страниц - uint32_t* pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex); + uint32_t* pt = ((uint32_t*)kpage_dir+0x1000) + (0x400 * pdindex); void* phys = alloc_page(); if (!phys) while(1); diff --git a/src/mm/paging.c b/src/mm/paging.c index 2f0029b..b3eb8e5 100644 --- a/src/mm/paging.c +++ b/src/mm/paging.c @@ -10,56 +10,51 @@ uint32_t *kpage_dir; uint32_t setup_tmp_pgdir(uint32_t magic, uint32_t info) { - int n, pd; - uint32_t pagedir_address, memksize; - uint32_t *page_table; - struct multiboot_info *mbi; + int n, pd; + uint32_t pagedir_address, memksize; + uint32_t *page_table; + struct multiboot_info *mbi; - if(magic != MULTIBOOT_BOOTLOADER_MAGIC) { - /* 4MB of memory assumed */ - memksize = 4096; - } else { - mbi = (struct multiboot_info *)(PAGE_OFFSET + info); - if(!(mbi->flags & MULTIBOOT_INFO_MEMORY)) { - /* 4MB of memory assumed */ - memksize = 4096; - } else { - /* we need to add the first 1MB to memksize */ - memksize = (uint32_t)mbi->mem_upper + 1024; - if(memksize > ((0xFFFFFFFF - PAGE_OFFSET) / 1024)) { - memksize = (0xFFFFFFFF - PAGE_OFFSET) / 1024; - } - } - } + if(magic != MULTIBOOT_BOOTLOADER_MAGIC) { + memksize = 4096; + } else { + mbi = (struct multiboot_info *)(PAGE_OFFSET + info); + if(!(mbi->flags & MULTIBOOT_INFO_MEMORY)) { + memksize = 4096; + } else { + memksize = (uint32_t)mbi->mem_upper + 1024; + if(memksize > ((0xFFFFFFFF - PAGE_OFFSET) / 1024)) { + memksize = (0xFFFFFFFF - PAGE_OFFSET) / 1024; + } + } + } - /* address becomes PAGE_OFFSET (0xC0000000) plus the size of memory minus the first page */ - /* TODO: check if I wrote the comment above correctly*/ - pagedir_address = PAGE_OFFSET + (memksize * 1024) - memksize; - pagedir_address = PAGE_ALIGN(pagedir_address); + /* Address is PAGE_OFFSET plus memory size minus 4KB */ + pagedir_address = PAGE_OFFSET + (memksize * 1024) - 4096; + pagedir_address = PAGE_ALIGN(pagedir_address); - /* - memory pages: - 0 -> page directory - 1 -> page table - */ - kpage_dir = (uint32_t *)pagedir_address; - memset(kpage_dir, 0, PAGE_SIZE); + kpage_dir = (uint32_t *)pagedir_address; + memset(kpage_dir, 0, PAGE_SIZE); - pagedir_address += PAGE_SIZE; - page_table = (uint32_t *)pagedir_address; - memset(page_table, 0, memksize); + pagedir_address += PAGE_SIZE; + page_table = (uint32_t *)pagedir_address; + memset(page_table, 0, memksize); - /* if we have 4MB assumed earlier, the memksize will be 4096 and this loop will run while n < 1024 */ - /* so basically 4MB is 1024 pages */ - for(n = 0; n < memksize / sizeof(uint32_t); n++) { - page_table[n] = (n << PAGE_SHIFT) | PAGE_PRESENT | PAGE_RW; - if(!(n % 1024)) { - pd = n / 1024; - kpage_dir[pd] = (uint32_t)(pagedir_address + (PAGE_SIZE * pd) + GDT_BASE) | PAGE_PRESENT | PAGE_RW; - kpage_dir[GET_PGDIR(PAGE_OFFSET) + pd] = (uint32_t)(pagedir_address + (PAGE_SIZE * pd) + GDT_BASE) | PAGE_PRESENT | PAGE_RW; - } - } - return (uint32_t)kpage_dir - PAGE_OFFSET; + for(n = 0; n < memksize / sizeof(uint32_t); n++) { + page_table[n] = (n << PAGE_SHIFT) | PAGE_PRESENT | PAGE_RW; + if(!(n % 1024)) { + pd = n / 1024; + uint32_t pt_phys = (uint32_t)page_table - PAGE_OFFSET + (PAGE_SIZE * pd); + kpage_dir[pd] = pt_phys | PAGE_PRESENT | PAGE_RW | PAGE_USER;//TODO: fix, I don't think pd should have DPL3 + kpage_dir[GET_PGDIR(PAGE_OFFSET) + pd] = pt_phys | PAGE_PRESENT | PAGE_RW | PAGE_USER;//TODO: fix, I don't think pd should have DPL3 + } + } + + uint32_t pd_phys = (uint32_t)kpage_dir - PAGE_OFFSET; + kpage_dir[1023] = pd_phys | PAGE_PRESENT | PAGE_RW; // Recursive mapping + + + return (uint32_t)kpage_dir - PAGE_OFFSET; } void grub_memory_map(unsigned int magic, struct multiboot_info* mbi) @@ -79,16 +74,40 @@ void grub_memory_map(unsigned int magic, struct multiboot_info* mbi) (multiboot_memory_map_t*) (mbi->mmap_addr + i); printf("Start Addr: %x | Length: %x | Size: %x | Type: %x\n", - mmmt->addr, mmmt->len, mmmt->size, mmmt->type); + mmmt->addr_low, mmmt->len_low, mmmt->size, mmmt->type); - if(mmmt->type == MULTIBOOT_MEMORY_AVAILABLE) { + if(mmmt->type != MULTIBOOT_MEMORY_AVAILABLE) { /* * Do something with this memory block! * BE WARNED that some of memory shown as availiable is actually * actively being used by the kernel! You'll need to take that * into account before writing to memory! */ - printf("available\n"); + printf("not available\n"); + uint32_t size_in_pages = mmmt->len_low / PAGE_SIZE; + printf("size_in_pages: 0x%X\n", size_in_pages); + + uint32_t base_page = mmmt->addr_low / PAGE_SIZE; + uint32_t page_count = mmmt->len_low / PAGE_SIZE; + printf("page_base: %X, page_count: %X\n", base_page, page_count); + for (uint32_t j = 0; j < page_count; j++) { + set_bit(base_page + j); + } + } + } + extern uint32_t _start, _end; // From linker script + uint32_t kernel_start_phys = (uint32_t)&_start - 0xC0000000; + uint32_t kernel_end_phys = (uint32_t)&_end - 0xC0000000; + uint32_t kernel_start_page = kernel_start_phys / PAGE_SIZE; + uint32_t kernel_end_page = (kernel_end_phys + PAGE_SIZE - 1) / PAGE_SIZE; + printf("Kernel phys range: 0x%X to 0x%X, pages: 0x%X to 0x%X\n", + kernel_start_phys, kernel_end_phys, kernel_start_page, kernel_end_page); + + for (uint32_t i = kernel_start_page; i < kernel_end_page; i++) { + if (i < BITMAP_SIZE) { + set_bit(i); + } else { + printf("Bitmap overflow at kernel page %u\n", i); } } } diff --git a/src/tasking/sys_exit.asm b/src/tasking/sys_exit.asm index 0ba5c0a..2376554 100644 --- a/src/tasking/sys_exit.asm +++ b/src/tasking/sys_exit.asm @@ -33,7 +33,7 @@ sys_exit_handler: global test_user_function test_user_function: - mov eax, 0xDEADBEEF + mov eax, 0xB00B1E5 ; 0xDEADBEEF int 0x80 jmp $ diff --git a/src/tasking/task.c b/src/tasking/task.c index 3ff1b86..5b18e73 100644 --- a/src/tasking/task.c +++ b/src/tasking/task.c @@ -87,7 +87,7 @@ void schedule() next = queue; if(next != current) { - loadPageDirectory(next->page_directory); + //loadPageDirectory(next->page_directory); switchProcess(next); } } @@ -116,7 +116,7 @@ void jump_usermode2(void); void scheduler_init() { - //jump_usermode2(); + jump_usermode2(); //we create this task two times because in other case it just won't start task_create((EntryPoint)&idle, NULL, 0); task_create((EntryPoint)&idle, NULL, 0); @@ -127,6 +127,8 @@ void scheduler_init() task_create((EntryPoint)&task2, args2, 2); } +#include "../include/string.h" + extern void test_user_function(void); void jump_usermode2(void) { void* code_phys = alloc_page(); @@ -135,18 +137,25 @@ void jump_usermode2(void) { while (1); } - // Временно отображаем code_phys в ядре - uint32_t kernel_temp_virt = 0xC0100000; - map_page(code_phys, (void*)kernel_temp_virt, 0x3); // Present, R/W, Supervisor + // Temporarily map code_phys into kernel space + uint32_t kernel_temp_virt = 0xC0500000; + map_page(code_phys, (void*)kernel_temp_virt, 0x3); // R/W in kernel - // Копируем код - uint32_t* src = (uint32_t*)test_user_function; - uint32_t* dst = (uint32_t*)kernel_temp_virt; - for (int i = 0; i < 1024; i++) { - dst[i] = src[i]; - } - printf("Copied code to 0x%x (virt 0x%x): 0x%x 0x%x 0x%x\n", - (uint32_t)code_phys, kernel_temp_virt, dst[0], dst[1], dst[2]); + // Copy user code + memcpy((void*)kernel_temp_virt, test_user_function, 4096); // Use memcpy + + printf("Copied code at 0x%x: 0x%x 0x%x 0x%x\n", + kernel_temp_virt, + *(uint32_t*)kernel_temp_virt, + *(uint32_t*)(kernel_temp_virt + 4), + *(uint32_t*)(kernel_temp_virt + 8)); + + // Unmap temporary kernel mapping + unmap_page((void*)kernel_temp_virt); + + + printf("Copied code to 0x%x (virt 0x%x)\n", + (uint32_t)code_phys, kernel_temp_virt); // Настраиваем Ring 3 uint32_t user_stack_top; @@ -158,22 +167,36 @@ void jump_usermode2(void) { printf("user_code_virt: 0x%x, user_stack_top: 0x%x\n", (uint32_t)user_code_virt, user_stack_top); + + //map_page(alloc_page(), (void*)0x400000, 0x7); + map_page(alloc_page(), (void*)0x800000, 0x7); + uint32_t code_pte = get_pte(user_code_virt); + printf("Before iret: Code PTE at 0x%x: 0x%x (phys 0x%x, %s, %s)\n", + (uint32_t)user_code_virt, code_pte, code_pte & ~0xFFF, + (code_pte & 0x2) ? "writable" : "read-only", + (code_pte & 0x4) ? "user" : "supervisor"); + + // Switch to user mode with interrupts enabled asm volatile ( - "mov $0x23, %%dx\n" - "mov %%dx, %%ds\n" - "mov %%dx, %%es\n" - "mov %%dx, %%fs\n" - "mov %%dx, %%gs\n" - "push $0x23\n" - "push %0\n" - "pushf\n" - "push $0x1B\n" - "push %1\n" - "iret\n" - : - : "r" (user_stack_top), "r" (user_code_virt) - : "dx", "memory" - ); + "pushf\n" + "pop %%eax\n" + "or $0x200, %%eax\n" // Enable interrupts (IF) + "push %%eax\n" + "mov $0x23, %%dx\n" + "mov %%dx, %%ds\n" + "mov %%dx, %%es\n" + "mov %%dx, %%fs\n" + "mov %%dx, %%gs\n" + "push $0x23\n" // SS (user data segment) + "push %0\n" // ESP (user_stack_top) + "push %%eax\n" // EFLAGS (with IF) + "push $0x1B\n" // CS (user code segment) + "push %1\n" // EIP (user_code_virt) + "iret\n" + : + : "r" (user_stack_top), "r" (user_code_virt) + : "dx", "eax", "memory", "cc" + ); __builtin_unreachable(); }