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:
Karina
2026-01-29 22:28:41 +04:00
parent 55ea8fc533
commit 67e232cabd
14 changed files with 159 additions and 52 deletions
+2 -1
View File
@@ -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();
+16 -1
View File
@@ -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);
+3
View File
@@ -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);
+2 -1
View File
@@ -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
View File
@@ -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");
}
+18 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+22 -1
View File
@@ -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");
}
+5 -2
View File
@@ -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 -1
View File
@@ -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)
+10
View File
@@ -0,0 +1,10 @@
[bits 64]
section .text
global start
extern main
start:
call main
.hang:
jmp .hang
-17
View File
@@ -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
+16
View File
@@ -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");
}