feat(core): v0.5.1 - process isolation and syscalls
- Implemented CR3 switching in scheduler for process isolation - Added 'process' structure and PML4 cloning (vmm_create_address_space) - Added NASM crt0 and C entry point for userspace apps
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <types.h>
|
||||
#include <core/scheduler.h>
|
||||
|
||||
bool exec_init(const char* path);
|
||||
bool exec_init(process* p, const char* path);
|
||||
void init_task_entry();
|
||||
@@ -3,15 +3,30 @@
|
||||
|
||||
#pragma once
|
||||
#include <types.h>
|
||||
|
||||
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);
|
||||
@@ -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);
|
||||
@@ -11,4 +11,5 @@ void print_regs();
|
||||
void cmd_sleep();
|
||||
void cmd_debug();
|
||||
void cmd_rand();
|
||||
void cmd_ver();
|
||||
void cmd_ver();
|
||||
void cmd_userspace();
|
||||
+23
-11
@@ -4,11 +4,13 @@
|
||||
#include <core/loader.h>
|
||||
#include <core/userspace.h>
|
||||
#include <core/scheduler.h>
|
||||
#include <core/string.h>
|
||||
|
||||
#include <shell/ksh.h>
|
||||
|
||||
#include <mm/pmm.h>
|
||||
#include <mm/vmm.h>
|
||||
#include <mm/heap.h>
|
||||
#include <mm/memory.h>
|
||||
|
||||
#include <fs/vfs.h>
|
||||
@@ -16,9 +18,9 @@
|
||||
#include <drivers/console.h>
|
||||
#include <types.h>
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -3,29 +3,41 @@
|
||||
|
||||
#include <core/panic.h>
|
||||
#include <core/scheduler.h>
|
||||
#include <core/string.h>
|
||||
#include <mm/heap.h>
|
||||
#include <mm/vmm.h>
|
||||
#include <cpuinfo.h>
|
||||
#include <gdt.h>
|
||||
|
||||
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;
|
||||
|
||||
+2
-2
@@ -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");
|
||||
|
||||
|
||||
+39
-12
@@ -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;
|
||||
}
|
||||
@@ -9,10 +9,19 @@
|
||||
#include <drivers/timer.h>
|
||||
|
||||
#include <core/rand.h>
|
||||
#include <core/loader.h>
|
||||
#include <core/scheduler.h>
|
||||
#include <core/string.h>
|
||||
|
||||
#include <mm/vmm.h>
|
||||
#include <mm/heap.h>
|
||||
|
||||
#include <shell/dbgcmd.h>
|
||||
|
||||
#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");
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
[bits 64]
|
||||
|
||||
section .text
|
||||
global start
|
||||
extern main
|
||||
|
||||
start:
|
||||
call main
|
||||
.hang:
|
||||
jmp .hang
|
||||
@@ -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
|
||||
@@ -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");
|
||||
}
|
||||
Reference in New Issue
Block a user