diff --git a/kernel/inc/core/loader.h b/kernel/inc/core/loader.h index d57cdc7..e57b41d 100644 --- a/kernel/inc/core/loader.h +++ b/kernel/inc/core/loader.h @@ -4,6 +4,7 @@ #pragma once #include +#include -bool exec_init(const char* path); +bool exec_init(process* p, const char* path); void init_task_entry(); \ No newline at end of file diff --git a/kernel/inc/core/scheduler.h b/kernel/inc/core/scheduler.h index d2efc49..6861d51 100644 --- a/kernel/inc/core/scheduler.h +++ b/kernel/inc/core/scheduler.h @@ -3,15 +3,30 @@ #pragma once #include + +typedef enum process_state { + DEAD, + RUNNING, +} process_state; + +typedef struct process { + u64 pid; + process_state state; + u64 pml4_phys; + struct process* parent; + char name[32]; +} process; + typedef struct task { u64 rsp; struct task* next; u32 id; u32 sleep_ticks; u64 kernel_stack_top; + process* proc; } task; void sched_init(); -task* sched_spawn(void(*entry)()); +task* sched_spawn(void(*entry)(), process* owner); u64 sched_next(u64 curr_rsp); void yield(u64 ticks); \ No newline at end of file diff --git a/kernel/inc/mm/vmm.h b/kernel/inc/mm/vmm.h index ceb3be6..22cdabc 100644 --- a/kernel/inc/mm/vmm.h +++ b/kernel/inc/mm/vmm.h @@ -37,3 +37,6 @@ void vmm_init(Bootinfo* info); u64* vmm_map_page(u64* pml4, u64 phys, u64 virt, u64 flags); +u64 vmm_create_address_space(); +u64 vmm_get_current_cr3(); +void load_cr3(u64 pml4_addr); \ No newline at end of file diff --git a/kernel/inc/shell/builtins.h b/kernel/inc/shell/builtins.h index 4de38a8..af2c384 100644 --- a/kernel/inc/shell/builtins.h +++ b/kernel/inc/shell/builtins.h @@ -11,4 +11,5 @@ void print_regs(); void cmd_sleep(); void cmd_debug(); void cmd_rand(); -void cmd_ver(); \ No newline at end of file +void cmd_ver(); +void cmd_userspace(); \ No newline at end of file diff --git a/kernel/src/core/loader.c b/kernel/src/core/loader.c index e98bdb8..0d08938 100644 --- a/kernel/src/core/loader.c +++ b/kernel/src/core/loader.c @@ -4,11 +4,13 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -16,9 +18,9 @@ #include #include -extern u64* pml4_kernel; +extern task* curr_task; -bool exec_init(const char* path) { +bool exec_init(process* p, const char* path) { kprintf("[Loader] loading %s...\n", path); fs_node* file = vfs_open(path); if (!file) { @@ -41,7 +43,7 @@ bool exec_init(const char* path) { return false; } - vmm_map_page(pml4_kernel, (u64)phys, virt_code + (page_idx * 4096), PTE_PRESENT | PTE_RW | PTE_USER); + vmm_map_page((u64*)p->pml4_phys, (u64)phys, virt_code + (page_idx * 4096), PTE_PRESENT | PTE_RW | PTE_USER); void* k_ptr = (void*)(HHDM_OFFSET + (u64)phys); memset(k_ptr, 0, 4096); @@ -56,15 +58,17 @@ bool exec_init(const char* path) { for (u64 i = 0; i < (stack_size / 4096); i++) { void* phys = pmm_alloc_page(); - vmm_map_page(pml4_kernel, (u64)phys, virt_stack + (i * 4096), PTE_PRESENT | PTE_RW | PTE_USER); + vmm_map_page((u64*)p->pml4_phys, (u64)phys, virt_stack + (i * 4096), PTE_PRESENT | PTE_RW | PTE_USER); memset((void*)(HHDM_OFFSET + (u64)phys), 0, 4096); } - __asm__ volatile( - "mov %%cr3, %%rax\n\t" - "mov %%rax, %%cr3\n\t" - ::: "rax", "memory" - ); + load_cr3(p->pml4_phys); + + // __asm__ volatile( + // "mov %%cr3, %%rax\n\t" + // "mov %%rax, %%cr3\n\t" + // ::: "rax", "memory" + // ); kprintf("[Loader] Transferring control to userspace...\n"); jump_to_userspace((void*)virt_code, (void*)(virt_stack + stack_size)); @@ -73,9 +77,17 @@ bool exec_init(const char* path) { } void init_task_entry() { - if (!exec_init("/init")) { + process* init_proc = (process*)malloc(sizeof(process)); + init_proc->pid = 1; + init_proc->state = RUNNING; + init_proc->pml4_phys = vmm_create_address_space(); + strcpy(init_proc->name, "init"); + + curr_task->proc = init_proc; + + if (!exec_init(init_proc, "/init")) { kprintf("FATAL: Could not load /init\n"); - sched_spawn(ksh); + sched_spawn(ksh, nullptr); while(1) __asm__("hlt"); } diff --git a/kernel/src/core/scheduler.c b/kernel/src/core/scheduler.c index 7b2a713..8367c44 100644 --- a/kernel/src/core/scheduler.c +++ b/kernel/src/core/scheduler.c @@ -3,29 +3,41 @@ #include #include +#include #include +#include #include #include task* curr_task = nullptr; u32 next_pid = 1; + extern void irq0_handler(); +extern u64 pml4_kernel_phys; + +static process kernel_process; void sched_init() { - task* kt = (task*)malloc(sizeof(task)); + kernel_process.pid = 0; + kernel_process.state = RUNNING; + kernel_process.pml4_phys = pml4_kernel_phys; + strcpy(kernel_process.name, "kernel"); + task* kt = (task*)malloc(sizeof(task)); kt->id = 0; + kt->proc = &kernel_process; kt->sleep_ticks = 0; kt->next = kt; curr_task = kt; } -task* sched_spawn(void(*entry)()) { +task* sched_spawn(void(*entry)(), process* owner) { task* t = (task*)malloc(sizeof(task)); if (!t) return nullptr; - + if (!owner) owner = &kernel_process; + u64 stack_size = 16384; u8* stack_base = (u8*)malloc(stack_size); if (!stack_base) panic("OOM for task stack"); @@ -43,6 +55,7 @@ task* sched_spawn(void(*entry)()) { for (u8 i = 0; i < 15; i++) *--rsp = 0; // R15 .. RAX t->rsp = (u64)rsp; + t->proc = owner; t->id = next_pid++; t->sleep_ticks = 0; t->next = curr_task->next; @@ -67,6 +80,8 @@ u64 sched_next(u64 curr_rsp) { task* next = curr_task->next; while (next != curr_task && next->sleep_ticks > 0) next = next->next; // what the fuck i just wrote + if (next->proc->pml4_phys != curr_task->proc->pml4_phys) load_cr3(next->proc->pml4_phys); + curr_task = next; tss.rsp0 = curr_task->kernel_stack_top; g_cpu.kernel_rsp = curr_task->kernel_stack_top; diff --git a/kernel/src/kmain.c b/kernel/src/kmain.c index 115025a..383b58a 100644 --- a/kernel/src/kmain.c +++ b/kernel/src/kmain.c @@ -101,8 +101,8 @@ void kmain(Bootinfo* info) { c = console_getc(); if (c != '\n') staying_in_ksh = true; - if (staying_in_ksh) sched_spawn(ksh); - else sched_spawn(init_task_entry); + if (staying_in_ksh) sched_spawn(ksh, nullptr); + else sched_spawn(init_task_entry, nullptr); __asm__ volatile("sti"); diff --git a/kernel/src/mm/vmm.c b/kernel/src/mm/vmm.c index 0bc0666..1a28563 100644 --- a/kernel/src/mm/vmm.c +++ b/kernel/src/mm/vmm.c @@ -11,6 +11,7 @@ #include "bootinfo.h" u64* pml4_kernel = nullptr; +u64 pml4_kernel_phys = 0; static bool is_initialized = false; extern u64 _kernel_start; @@ -89,26 +90,30 @@ void vmm_unmap_page(u64* pml4, u64 virt) { u64 pdpt_idx = VMM_PDPT_INDEX(virt); u64 pml4_idx = VMM_PML4_INDEX(virt); - if (!(pml4[pml4_idx] & PTE_PRESENT)) return; - u64* pdpt = get_table_virt(PTE_GET_ADDR(pml4[pml4_idx])); - - if (!(pdpt[pdpt_idx] & PTE_PRESENT)) return; - u64* pd = get_table_virt(PTE_GET_ADDR(pdpt[pdpt_idx])); - - if (!(pd[pd_idx] & PTE_PRESENT)) return; - u64* pt = get_table_virt(PTE_GET_ADDR(pd[pd_idx])); + u64* pml4_virt = pml4; + if (is_initialized) pml4_virt = (u64*)PHYS_TO_HHDM((u64)pml4); - pt[pt_idx] = 0; + if (!(pml4_virt[pml4_idx] & PTE_PRESENT)) return; + u64* pdpt_virt = get_table_virt(PTE_GET_ADDR(pml4_virt[pml4_idx])); + + if (!(pdpt_virt[pdpt_idx] & PTE_PRESENT)) return; + u64* pd_virt = get_table_virt(PTE_GET_ADDR(pdpt_virt[pdpt_idx])); + + if (!(pd_virt[pd_idx] & PTE_PRESENT)) return; + u64* pt_virt = get_table_virt(PTE_GET_ADDR(pd_virt[pd_idx])); + + pt_virt[pt_idx] = 0; __asm__ volatile("invlpg (%0)" :: "r" (virt) : "memory"); } -static inline void load_cr3(u64 pml4_addr) { +void load_cr3(u64 pml4_addr) { __asm__ volatile ("mov %0, %%cr3" :: "r"(pml4_addr) : "memory"); } void vmm_init(Bootinfo* info) { - pml4_kernel = pmm_alloc_page(); + pml4_kernel_phys = (u64)pmm_alloc_page(); + pml4_kernel = (u64*)pml4_kernel_phys; memset(pml4_kernel, 0, PAGE_SIZE); u64 k_virt_start = (u64)&_kernel_start; @@ -126,6 +131,28 @@ void vmm_init(Bootinfo* info) { bitmap = (u8*)PHYS_TO_HHDM((u64)bitmap); info->framebuffer.base = (u32*)FB_VIRT_BASE; - load_cr3((u64)pml4_kernel); + load_cr3(pml4_kernel_phys); is_initialized = true; +} + +u64 vmm_create_address_space() { + u64 phys = (u64)pmm_alloc_page(); + if (!phys) return 0; + + u64* virt = (u64*)PHYS_TO_HHDM(phys); + memset(virt, 0, PAGE_SIZE); + + u64* kernel_pml4_virt = get_table_virt((u64)pml4_kernel); + + for (u32 i = 256; i < 512; i++) { + virt[i] = kernel_pml4_virt[i]; + } + + return phys; +} + +u64 vmm_get_current_cr3() { + u64 cr3; + __asm__ volatile("mov %%cr3, %0" : "=r"(cr3)); + return cr3; } \ No newline at end of file diff --git a/kernel/src/shell/builtins.c b/kernel/src/shell/builtins.c index f9143a0..90ddd88 100644 --- a/kernel/src/shell/builtins.c +++ b/kernel/src/shell/builtins.c @@ -9,10 +9,19 @@ #include #include +#include +#include +#include + +#include +#include + #include #include "../data/cats.h" +extern task* curr_task; + const char* ascii_logo[] = { " /\\___/\\ ", " | > < | ", @@ -48,7 +57,6 @@ void cmd_meow() { void cmd_help() { kprintf("Welcome to ^ptermOS^!'s ^gk^!ernel ^gsh^!ell!\n"); kprintf("It loads when userspace is failed to load and acts as a basic rescue environment\n"); - kprintf("At this moment i dont have userspace so it loads always\n"); kprintf("Available commands:\n"); kprintf("\t^rDebug^!:\n"); @@ -58,6 +66,7 @@ void cmd_help() { kprintf("\t\t^ypanic^! \t\tPanics (lol)\n"); kprintf("\t\t^yud2^! \t\tPanics with #UD\n"); kprintf("\t\t^ypf^! \t\tPanics with #PF\n"); + kprintf("\t\t^yuserspace^! \t\tAttempt to jump in ring 3\n"); kprintf("\t^pFun^!:\n"); kprintf("\t\t^ysplash^! \t\tShows splash (works kinda unstable)\n"); @@ -112,4 +121,16 @@ void cmd_ver() { kprintf("termOS version %s\n", TERMOS_VERSION); kprintf("Dewar Kernel (x86_64), build: %s %s\n", __DATE__, __TIME__); kprintf("License: GPL-3.0-or-later\n"); +} + +void cmd_userspace() { + process* init_proc = (process*)malloc(sizeof(process)); + init_proc->pid = 1; + init_proc->state = RUNNING; + init_proc->pml4_phys = vmm_create_address_space(); + strcpy(init_proc->name, "init"); + + curr_task->proc = init_proc; + kprintf("Trying to jump in ring 3...\n"); + if (!exec_init(init_proc, "/init")) kprintf("Failed to jump.\n"); } \ No newline at end of file diff --git a/kernel/src/shell/ksh.c b/kernel/src/shell/ksh.c index a42a8d3..a5304ab 100644 --- a/kernel/src/shell/ksh.c +++ b/kernel/src/shell/ksh.c @@ -33,6 +33,7 @@ typedef enum { TOKEN_PANIC, TOKEN_PANIC_UD2, TOKEN_PANIC_PF, + TOKEN_USERSPACE, TOKEN_CLEAR, TOKEN_BLINKING, @@ -61,6 +62,7 @@ static const ksh_command_map token_map[] = { {"panic", TOKEN_PANIC}, {"ud2", TOKEN_PANIC_UD2}, {"pf", TOKEN_PANIC_PF}, + {"userspace", TOKEN_USERSPACE}, // fun {"meow", TOKEN_MEOW}, @@ -84,7 +86,7 @@ ksh_token char2token(char* token) { } void ksh() { - sched_spawn(cursor_blinker_sched_task); + sched_spawn(cursor_blinker_sched_task, nullptr); while (true) { kprintf("ksh_> "); char cmdbuff[256]; @@ -103,7 +105,8 @@ void ksh() { case TOKEN_PANIC: panic("Manually initiated panic"); case TOKEN_PANIC_UD2: __asm__ volatile ("ud2"); case TOKEN_PANIC_PF: u64* bad_ptr = (u64*)0xDEADBEEF; *bad_ptr = 666; - + case TOKEN_USERSPACE: cmd_userspace(); break; + case TOKEN_SPLASH: show_splash(console_get_context()); break; case TOKEN_KFETCH: cmd_kfetch(); break; case TOKEN_MEOW: cmd_meow(); break; diff --git a/userspace/init/CMakeLists.txt b/userspace/init/CMakeLists.txt index d30d8cb..da3e34b 100644 --- a/userspace/init/CMakeLists.txt +++ b/userspace/init/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.20) -project(termOSinit LANGUAGES C ASM_NASM) +project(termOSinit LANGUAGES C) set(CMAKE_C_STANDARD 23) set(CMAKE_C_STANDARD_REQUIRED ON) diff --git a/userspace/init/src/crt0.asm b/userspace/init/src/crt0.asm new file mode 100644 index 0000000..a39c6a7 --- /dev/null +++ b/userspace/init/src/crt0.asm @@ -0,0 +1,10 @@ +[bits 64] + +section .text +global start +extern main + +start: + call main +.hang: + jmp .hang \ No newline at end of file diff --git a/userspace/init/src/entry.asm b/userspace/init/src/entry.asm deleted file mode 100644 index 9e49484..0000000 --- a/userspace/init/src/entry.asm +++ /dev/null @@ -1,17 +0,0 @@ -[BITS 64] - -start: - mov rax, 2 ; SYS_WRITE - mov rdi, msg_hello ; Адрес строки - syscall - - mov rax, 1 ; SYS_EXEC - syscall - - mov rax, 0 ; SYS_EXIT - mov rdi, 1337 - syscall - - jmp $ - -msg_hello: db "Hello from init!", 0xA, 0 \ No newline at end of file diff --git a/userspace/init/src/main.c b/userspace/init/src/main.c new file mode 100644 index 0000000..f4bb7e8 --- /dev/null +++ b/userspace/init/src/main.c @@ -0,0 +1,16 @@ +static inline void sys_write(const char* str) { + __asm__ volatile ( + "mov $2, %%rax\n\t" + "mov %0, %%rdi\n\t" + "syscall" + : + : "r"(str) + : "rax", "rdi", "rcx", "r11", "memory" + ); +} + +int main() { + sys_write("Meowww!!!\n"); + sys_write("Nyaaaaa"); + for (int i = 0; i < 100; i++) sys_write("a"); +} \ No newline at end of file