diff --git a/Makefile b/Makefile index aa95a40..43a2b54 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/fat.o bin/task.o bin/switch.o bin/sys_exit.o # Define the compiler and assembler CC = gcc -D__is_katauos @@ -114,6 +114,9 @@ bin/switch.o: src/tasking/switch.asm bin/task.o: src/tasking/task.c $(CC) $(CFLAGS) -c $< -o $@ +bin/sys_exit.o: src/tasking/sys_exit.asm + $(AS) $(ASFLAGS) $< -o $@ + clean: rm -rf bin/ rm -f $(OUTPUT) diff --git a/include/paging.h b/include/paging.h index c2653ff..8f2a0f5 100644 --- a/include/paging.h +++ b/include/paging.h @@ -7,6 +7,7 @@ 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))); //paging.c @@ -24,10 +25,11 @@ void free_page(void* physaddr); void *get_physaddr(void *virtualaddr); void map_page(void* physaddr, void* virtualaddr, unsigned int flags); void map_kernel_page(void* virtualaddr, unsigned int flags); +void* setup_user_process(void* user_code_phys, uint32_t* user_stack_top); //heap.c void heap_init(); void* heap_alloc(uint32_t size); void heap_free(void* ptr); -#endif \ No newline at end of file +#endif diff --git a/src/kernel/isr.c b/src/kernel/isr.c index 68a6814..2217b08 100644 --- a/src/kernel/isr.c +++ b/src/kernel/isr.c @@ -22,6 +22,8 @@ __attribute__((interrupt)) void isr_timer(struct interrupt_frame *frame); void isr_custom(); void default_handler(); +extern void sys_exit_handler(); + void isr_install() { idt_set_descriptor(0, (uint32)isr0, 0x8E); idt_set_descriptor(1, (uint32)isr1, 0x8E); @@ -62,6 +64,7 @@ void isr_install() { idt_set_descriptor(0x20, (uint32)isr_timer, 0x8E); idt_set_descriptor(0x21, (uint32)isr_custom, 0x8E); + idt_set_descriptor(0x80, (uint32)sys_exit_handler, 0xEE); idt_set(); // Load with ASM printf("isr_install done\n"); diff --git a/src/mm/page_alloc.c b/src/mm/page_alloc.c index 7fe9ffe..e3f557e 100644 --- a/src/mm/page_alloc.c +++ b/src/mm/page_alloc.c @@ -37,4 +37,4 @@ void free_page(void* physaddr) { 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 index 9b33af9..34a01b1 100644 --- a/src/mm/page_tables.c +++ b/src/mm/page_tables.c @@ -1,6 +1,26 @@ #include "../include/paging.h" #include +static uint32_t next_user_virt = 0x00400000; +void* setup_user_process(void* user_code_phys, uint32_t* user_stack_top) { + 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 КБ + map_page(user_code_phys, (void*)code_virt, 0x7); + map_page(stack_phys, (void*)stack_virt, 0x7); + + *user_stack_top = stack_virt + 0x1000; + next_user_virt += 0x400000; // Следующий 4 МБ блок + return (void*)code_virt; +} + +void free_user_process(void* code_phys, void* stack_phys) { + free_page(code_phys); + free_page(stack_phys); +} + void *get_physaddr(void *virtualaddr) { unsigned long pdindex = (unsigned long)virtualaddr >> 22; unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF; @@ -85,4 +105,4 @@ void map_kernel_page(void* virtualaddr, unsigned int flags) { 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 dedbb9b..4eb0764 100644 --- a/src/mm/paging.c +++ b/src/mm/paging.c @@ -3,6 +3,8 @@ uint32_t kernel_page_directory[1024] __attribute__((aligned(4096))); uint32_t kernel_page_table[1024] __attribute__((aligned(4096))); +uint32_t user_page_table[1024] __attribute__((aligned(4096))); + void enablePaging() { asm volatile ( @@ -35,8 +37,9 @@ void paging_init() { // Проверяем физические адреса uint32_t pd_phys = (uint32_t)kernel_page_directory; uint32_t pt_phys = (uint32_t)kernel_page_table; + uint32_t user_pt_phys = (uint32_t)user_page_table; - if (pd_phys & 0xFFF || pt_phys & 0xFFF) { + if (pd_phys & 0xFFF || pt_phys & 0xFFF || user_pt_phys & 0xFFF) { while (1); // Ошибка выравнивания } @@ -51,6 +54,12 @@ void paging_init() { } kernel_page_directory[0] = pt_phys | 0x3; + // Ring 3: 0x00400000–0x007FFFFF, User-accessible + for (i = 0; i < 1024; i++) { + user_page_table[i] = 0; // Изначально не отображено + } + kernel_page_directory[1] = user_pt_phys | 0x7; // Present, R/W, User + // Рекурсивное отображение kernel_page_directory[1023] = pd_phys | 0x3; @@ -76,4 +85,4 @@ void test_paging() { printf("(uint32_t)first_page_table | 0x3 = %X", (uint32_t)kernel_page_table | 0x3); while (1); // Рекурсия сломана } -} \ No newline at end of file +} diff --git a/src/tasking/switch.asm b/src/tasking/switch.asm index 277e7ca..02ace7e 100644 --- a/src/tasking/switch.asm +++ b/src/tasking/switch.asm @@ -94,3 +94,24 @@ switchProcess: ; |------------------------| ret + +global jump_usermode +extern test_user_function +jump_usermode: + mov ax, (4 * 8) | 3 ; ring 3 data with bottom 2 bits set for ring 3 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax ; SS is handled by iret + + ; and eax, ~0x80000000 + ; mov cr0, eax + + ; set up the stack frame iret expects + mov eax, esp + push (4 * 8) | 3 ; data selector + push eax ; current esp + pushf ; eflags + push (3 * 8) | 3 ; code selector (ring 3 code with bottom 2 bits set for ring 3) + push test_user_function ; instruction address to return to + iret diff --git a/src/tasking/sys_exit.asm b/src/tasking/sys_exit.asm new file mode 100644 index 0000000..0ba5c0a --- /dev/null +++ b/src/tasking/sys_exit.asm @@ -0,0 +1,41 @@ +; TODO: maybe put it near idt.c? +global sys_exit_handler +extern printf +sys_exit_handler: + ; Сохраняем регистры Ring 3 + pusha + push ds + push es + push fs + push gs + + ; Переключаемся на сегменты Ring 0 + mov ax, 0x10 ; Селектор данных Ring 0 (gdt_data) + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ; Выполняем действие + push sys_exit_msg + call printf + add esp, 4 + + ; Восстанавливаем сегменты Ring 3 + pop gs + pop fs + pop es + pop ds + popa + + ; Возвращаемся в Ring 3 + iret + +global test_user_function +test_user_function: + mov eax, 0xDEADBEEF + int 0x80 + jmp $ + +section .data +sys_exit_msg: db "Returned from Ring 3", 0 diff --git a/src/tasking/task.c b/src/tasking/task.c index e37167d..22801a5 100644 --- a/src/tasking/task.c +++ b/src/tasking/task.c @@ -107,14 +107,68 @@ void task2(int arg1, int arg2) while(1){printf("task2 %X %X\n", arg1, arg2);} } +void jump_usermode2(void); + void scheduler_init() { + 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); + //task_create((EntryPoint)&idle, NULL, 0); + //task_create((EntryPoint)&idle, NULL, 0); void* args1[] = {(void*)42, (void*)"ebalo"}; - task_create((EntryPoint)&task1, args1, 2); + //task_create((EntryPoint)&task1, args1, 2); void* args2[] = {(void*)69, (void*)420}; - task_create((EntryPoint)&task2, args2, 2); + //task_create((EntryPoint)&task2, args2, 2); +} + +extern void test_user_function(void); +void jump_usermode2(void) { + void* code_phys = alloc_page(); + if (!code_phys) { + printf("No memory for user code\n"); + while (1); + } + + // Временно отображаем code_phys в ядре + uint32_t kernel_temp_virt = 0xC0100000; + map_page(code_phys, (void*)kernel_temp_virt, 0x3); // Present, R/W, Supervisor + + // Копируем код + 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]); + + // Настраиваем Ring 3 + uint32_t user_stack_top; + void* user_code_virt = setup_user_process(code_phys, &user_stack_top); + if (!user_code_virt) { + printf("Failed to setup user process\n"); + while (1); + } + + printf("user_code_virt: 0x%x, user_stack_top: 0x%x\n", + (uint32_t)user_code_virt, user_stack_top); + + 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" + ); + __builtin_unreachable(); }