From 437bd0e75104056ece3c374ff9ee16486e114b1d Mon Sep 17 00:00:00 2001 From: xamidev Date: Fri, 3 Apr 2026 18:45:12 +0200 Subject: [PATCH 1/2] process_create_user --- include/sched/process.h | 2 +- src/arch/x86/idt.c | 5 ++--- src/kmain.c | 15 ++++++--------- src/mem/vmm.c | 10 ++++++---- src/sched/process.c | 39 ++++++++++++++++++++++++++++++++------- src/sched/scheduler.c | 24 +++++++++++++----------- 6 files changed, 60 insertions(+), 35 deletions(-) diff --git a/include/sched/process.h b/include/sched/process.h index ef00d3e..13fe331 100644 --- a/include/sched/process.h +++ b/include/sched/process.h @@ -38,6 +38,6 @@ void process_exit(void); void process_display_list(struct process* processes_list); -void process_create_user(struct limine_file* file); +void process_create_user(struct limine_file* file, char* name); #endif diff --git a/src/arch/x86/idt.c b/src/arch/x86/idt.c index 4a29524..a319c95 100644 --- a/src/arch/x86/idt.c +++ b/src/arch/x86/idt.c @@ -264,10 +264,9 @@ struct cpu_status* interrupt_dispatch(struct cpu_status* context) // Send an EOI so that we can continue having interrupts outb(0x20, 0x20); - // Scheduler is temporarily disabled to test user trampoline - /* if (ticks % SCHEDULER_QUANTUM == 0) { + if (ticks % SCHEDULER_QUANTUM == 0) { return scheduler_schedule(context); - } */ + } break; diff --git a/src/kmain.c b/src/kmain.c index 89bd3b0..ccbd883 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -118,22 +118,19 @@ void kmain() process_init(); idle_proc = process_create("idle", (void*)idle_main, 0); - process_create("pedicel", (void*)pedicel_main, 0); - - scheduler_init(); if (!boot_ctx.module) { panic(NULL, "could not load 'hello' executable :("); } + if (boot_ctx.module->module_count == 1) { + file = boot_ctx.module->modules[0]; + DEBUG("file: addr=%p size=%u", file->address, file->size); + process_create_user(file, "hello"); + } + scheduler_init(); printf(PEPPEROS_SPLASH); init.all = true; - if (boot_ctx.module->module_count == 1) { - file = boot_ctx.module->modules[0]; - DEBUG("file: addr=%p size=%u", file->address, file->size); - process_create_user(file); - } - idle(); } diff --git a/src/mem/vmm.c b/src/mem/vmm.c index d17970a..2c851de 100644 --- a/src/mem/vmm.c +++ b/src/mem/vmm.c @@ -246,17 +246,19 @@ uintptr_t vmm_alloc_user_stack(uint64_t* pml4) for (size_t i=stack_top; i>stack_top-stack_size; i-=PAGE_SIZE) { vmm_map(pml4, i, PTE_PRESENT | PTE_WRITABLE | PTE_USER); } - return stack_top; } uintptr_t vmm_alloc_user_code(uint64_t* pml4, void* code_addr, uint64_t code_size) { uintptr_t code_start = USER_CODE_START; - - for (size_t i=code_start; iroot_page_table = kernel_pml4; + proc->kernel_stack = kalloc_stack(); + proc->next = 0; process_add(&processes_list, proc); @@ -229,29 +231,52 @@ extern struct tss tss; /* * process_create_user - Create a new user process * @file: pointer to Limine file structure + * @name: name for the new process * * This function takes a loaded Limine executable * module, and maps its code, a user stack, sets the * TSS RSP0 for interrupts, and finally jumps to the * user code. */ -void process_create_user(struct limine_file* file) +void process_create_user(struct limine_file* file, char* name) { + CLEAR_INTERRUPTS; + struct process* proc = (struct process*)kmalloc(sizeof(struct process)); + struct cpu_status* ctx = (struct cpu_status*)kmalloc(sizeof(struct cpu_status)); + + if (!proc || !ctx) panic(NULL, "out of memory while creating user process"); + + strncpy(proc->name, name, PROCESS_NAME_MAX); + memset(ctx, 0, sizeof(struct cpu_status)); // set GP registers to zero + proc->pid = next_free_pid++; + proc->status = READY; + proc->next = 0; + proc->context = ctx; + proc->context->iret_ss = USER_DATA_SEGMENT | 3; + proc->context->iret_cs = USER_CODE_SEGMENT | 3; + proc->context->iret_flags = 0x202; // Interrupt Flag set + void* exec_addr = file->address; uint64_t exec_size = file->size; uint64_t* user_pml4 = vmm_create_address_space(); + if (!user_pml4) panic(NULL, "failed to create user address space"); + proc->root_page_table = user_pml4; + uintptr_t stack_top = vmm_alloc_user_stack(user_pml4); uint64_t code = vmm_alloc_user_code(user_pml4, exec_addr, exec_size); - // Could be kalloc_stack()ed PER PROCESS when we grow that - tss.rsp0 = (uint64_t)(interrupt_stack + sizeof(interrupt_stack)); + proc->context->iret_rsp = stack_top; + proc->context->iret_rip = code; + proc->kernel_stack = kalloc_stack(); + if (!proc->kernel_stack) panic(NULL, "failed to allocate kernel stack"); - // Load user_pml4 into cr3 along here?? + // Copy code into user pages; for that we need to temporarily switch to the user pml4 load_cr3(VIRT_TO_PHYS((uint64_t)user_pml4)); - - // Copy code into user pages memcpy((uint64_t*)code, exec_addr, exec_size); + load_cr3(VIRT_TO_PHYS((uint64_t)kernel_pml4)); - process_jump_to_user(stack_top, code); + process_add(&processes_list, proc); + DEBUG("user process '%s' (pid=%u) enqueued for scheduling", name, proc->pid); + SET_INTERRUPTS; } \ No newline at end of file diff --git a/src/sched/scheduler.c b/src/sched/scheduler.c index c320b70..421f4fa 100644 --- a/src/sched/scheduler.c +++ b/src/sched/scheduler.c @@ -9,17 +9,21 @@ #include #include #include +#include extern struct process* processes_list; extern struct process* current_process; extern struct process* idle_proc; +extern struct tss tss; + /* * scheduler_init - Choose the first process */ void scheduler_init() { current_process = processes_list; + DEBUG("scheduler starting with: pid=%u, name='%s', context=%p", current_process->pid, current_process->name, current_process->context); } /* @@ -39,13 +43,15 @@ struct cpu_status* scheduler_schedule(struct cpu_status* context) } if (current_process == NULL) { - // If no more processes, then set IDLE as the current process, that's it. - current_process = idle_proc; + panic(NULL, "current_process is NULL"); + } + + if (current_process->context == NULL) { + panic(NULL, "current_process->context is NULL"); } - if (current_process == idle_proc && current_process->next == NULL) - { - return idle_proc->context; + if (current_process->next == NULL) { + return current_process->context; } current_process->context = context; @@ -61,20 +67,16 @@ struct cpu_status* scheduler_schedule(struct cpu_status* context) if (current_process != NULL && current_process->status == DEAD) { process_delete(&prev_process, current_process); current_process = NULL; + return idle_proc->context; } else { current_process->status = RUNNING; -/* if (prev_process != current_process) { - DEBUG("Changed from {pid=%u, name=%s} to {pid=%u, name=%s}", prev_process->pid, prev_process->name, current_process->pid, current_process->name); - } */ break; } } - //DEBUG("current_process={pid=%u, name='%s', root_page_table[virt]=%p}", current_process->pid, current_process->name, current_process->root_page_table); - + tss.rsp0 = (uint64_t)current_process->kernel_stack; load_cr3(VIRT_TO_PHYS((uint64_t)current_process->root_page_table)); - //DEBUG("Loaded process PML4 into CR3"); return current_process->context; } \ No newline at end of file -- 2.52.0 From 0240220796b5cc8fee696d23715b5df5d35759f6 Mon Sep 17 00:00:00 2001 From: xamidev Date: Fri, 3 Apr 2026 19:18:08 +0200 Subject: [PATCH 2/2] Scheduler fix, User RR --- Makefile | 4 +++- limine.conf | 1 + src/arch/x86/syscall.c | 15 ++++++++++++ src/kmain.c | 7 ++++-- src/sched/scheduler.c | 52 +++++++++++++++++++++++++++--------------- user/hello.S | 5 ++++ user/pedicel.S | 25 ++++++++++++++++++++ 7 files changed, 88 insertions(+), 21 deletions(-) create mode 100644 user/pedicel.S diff --git a/Makefile b/Makefile index 1542d6d..ffefdfc 100644 --- a/Makefile +++ b/Makefile @@ -16,12 +16,13 @@ endif OBJFILES := $(patsubst $(SRC)/%.c, $(BUILDDIR)/%.o, $(SOURCES)) CC := x86_64-elf-gcc -CC_FLAGS=-Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fstack-protector -fno-omit-frame-pointer -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel +CC_FLAGS=-Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fstack-protector -fno-omit-frame-pointer -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel -mno-red-zone LD := x86_64-elf-ld $(ELFFILE): $(BUILDDIR) $(OBJFILES) nasm -f bin user/hello.S -o $(BUILDDIR)/hello + nasm -f bin user/pedicel.S -o $(BUILDDIR)/pedicel nasm -f elf64 src/arch/x86/idt.S -o $(BUILDDIR)/idt_stub.o $(LD) -o $(ELFFILE) -T linker.ld $(OBJFILES) $(BUILDDIR)/idt_stub.o # Get the symbols for debugging @@ -49,6 +50,7 @@ build-iso: limine/limine $(ELFFILE) mkdir -p iso_root/boot/limine cp -v limine.conf iso_root/boot/limine cp $(BUILDDIR)/hello iso_root/boot/ + cp $(BUILDDIR)/pedicel iso_root/boot/ mkdir -p iso_root/EFI/BOOT cp -v limine/limine-bios.sys limine/limine-bios-cd.bin limine/limine-uefi-cd.bin iso_root/boot/limine/ cp -v limine/BOOTX64.EFI iso_root/EFI/BOOT/ diff --git a/limine.conf b/limine.conf index 980ace0..7988d0b 100644 --- a/limine.conf +++ b/limine.conf @@ -7,3 +7,4 @@ interface_branding: Welcome to the PepperOS disk! comment: Default configuration (warning: spicy) path: boot():/boot/pepperk module_path: boot():/boot/hello + module_path: boot():/boot/pedicel \ No newline at end of file diff --git a/src/arch/x86/syscall.c b/src/arch/x86/syscall.c index 8adb178..839969f 100644 --- a/src/arch/x86/syscall.c +++ b/src/arch/x86/syscall.c @@ -9,6 +9,9 @@ #include #include #include +#include + +extern struct process* current_process; void sys_write(unsigned int fd, const char* buf, size_t count) { @@ -20,10 +23,19 @@ void sys_write(unsigned int fd, const char* buf, size_t count) break; case 2: //stderr + for (size_t i=0; istatus = DEAD; + DEBUG("exiting process PID=%u name=%s", current_process->pid, current_process->name); +} + /* * syscall_handler - System call dispatcher * @regs: CPU state @@ -53,6 +65,9 @@ struct cpu_status* syscall_handler(struct cpu_status* regs) case 1: //sys_write sys_write(regs->rdi, (char*)regs->rsi, regs->rdx); break; + case 60: //sys_exit + sys_exit(regs->rdi); + break; default: regs->rax = 0xbad515ca11; break; diff --git a/src/kmain.c b/src/kmain.c index ccbd883..6f2b862 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -121,11 +121,14 @@ void kmain() if (!boot_ctx.module) { panic(NULL, "could not load 'hello' executable :("); - } - if (boot_ctx.module->module_count == 1) { + } + if (boot_ctx.module->module_count == 2) { file = boot_ctx.module->modules[0]; DEBUG("file: addr=%p size=%u", file->address, file->size); process_create_user(file, "hello"); + + file = boot_ctx.module->modules[1]; + process_create_user(file, "pedicel"); } scheduler_init(); diff --git a/src/sched/scheduler.c b/src/sched/scheduler.c index 421f4fa..474e43a 100644 --- a/src/sched/scheduler.c +++ b/src/sched/scheduler.c @@ -50,31 +50,47 @@ struct cpu_status* scheduler_schedule(struct cpu_status* context) panic(NULL, "current_process->context is NULL"); } - if (current_process->next == NULL) { - return current_process->context; - } - current_process->context = context; - for (;;) { - struct process* prev_process = current_process; - if (current_process->next != NULL) { - current_process = current_process->next; - } else { - current_process = processes_list; - } - - if (current_process != NULL && current_process->status == DEAD) { - process_delete(&prev_process, current_process); - current_process = NULL; + if (current_process->status == DEAD) { + struct process* dead_process = current_process; + struct process* next_process = (dead_process->next != NULL) ? dead_process->next : processes_list; + process_delete(&processes_list, dead_process); + + if (processes_list == NULL || next_process == dead_process) { + current_process = idle_proc; return idle_proc->context; - } else { - current_process->status = RUNNING; - break; } + + current_process = next_process; + } else if (current_process->next != NULL) { + current_process = current_process->next; + } else { + current_process = processes_list; } + for (;;) { + if (current_process->status == DEAD) { + struct process* dead_process = current_process; + struct process* next_process = (current_process->next != NULL) ? current_process->next : processes_list; + + process_delete(&processes_list, dead_process); + + if (processes_list == NULL || next_process == dead_process) { + current_process = idle_proc; + return idle_proc->context; + } + + current_process = next_process; + continue; + } + + current_process->status = RUNNING; + break; + } + + // Here, we chose next running process so we load its kernel stack & page tables tss.rsp0 = (uint64_t)current_process->kernel_stack; load_cr3(VIRT_TO_PHYS((uint64_t)current_process->root_page_table)); diff --git a/user/hello.S b/user/hello.S index d3e94f7..0afc808 100644 --- a/user/hello.S +++ b/user/hello.S @@ -12,5 +12,10 @@ hello: mov rdx, 33 ;count int 0x80 +.end: + mov rax, 0x3C ;sys_exit + mov rdi, 0x0 ;error_code + int 0x80 + .loop: jmp .loop \ No newline at end of file diff --git a/user/pedicel.S b/user/pedicel.S new file mode 100644 index 0000000..4214e82 --- /dev/null +++ b/user/pedicel.S @@ -0,0 +1,25 @@ +bits 64 + +section .data +hello db 0x0A, 0x0D, "User program 2 speaking", 0 + +section .text + +_start: + mov rax, 0x1 ;sys_write + mov rdi, 0x1 ;stdout + lea rsi, [rel hello] + mov rdx, 25 ;count + int 0x80 + +; when we are ready to have an os specific toolchain, +; this bit (exit & loop) should be appended at the end of every +; C program we compile. + +.end: + mov rax, 0x3C + mov rdi, 0x0 + int 0x80 + +.loop: + jmp .loop \ No newline at end of file -- 2.52.0