From 5a4206acb629d581fb20ee74a879e65f0c1843e7 Mon Sep 17 00:00:00 2001 From: RarDog Date: Thu, 3 Sep 2026 11:03:35 +0300 Subject: [PATCH] feat(microkernel): implement pure microkernel architecture with vfs_server, net_server, and procmgr - Added vfs_server in Ring 3 (Endpoint 5) managing unified VFS tree (/, /bin, /etc, /proc, /dev, /tmp) - Added net_server in Ring 3 (Endpoint 6) owning RTL8139 hardware NIC, DHCP, DNS, and TCP/IPv4 stack - Refactored procmgr in Ring 3 (Endpoint 4) to handle userspace process spawning via PROC_OP_SPAWN - Added primitive microkernel syscalls in Ring 0: SYS_TASK_CREATE (29), SYS_TASK_MAP_PAGE (30), SYS_TASK_START (31) - Updated shell (sh) and desktop GUI (gui_server) to delegate process management and I/O to Ring 3 daemons - Expanded boot pipeline to orchestrate 7 concurrent Ring 3 servers across dedicated SMP CPU cores --- Makefile | 16 ++- include/abi/net.h | 6 + include/abi/syscalls.h | 42 +++++++ include/abi/vfs.h | 22 ++++ kernel/src/arch/syscall.rs | 106 ++++++++++++++++++ kernel/src/main.rs | 10 +- kernel/src/sched/mod.rs | 58 +++++++++- kernel/src/sched/thread.rs | 1 + limine.cfg | 4 +- limine.conf | 4 +- servers/gui_server/main.cpp | 19 ++-- servers/net_server/main.cpp | 85 ++++++++++++++ servers/procmgr/main.cpp | 19 ++++ servers/sh/main.cpp | 32 +++--- servers/vfs_server/main.cpp | 214 ++++++++++++++++++++++++++++++++++++ 15 files changed, 604 insertions(+), 34 deletions(-) create mode 100644 include/abi/vfs.h create mode 100644 servers/net_server/main.cpp create mode 100644 servers/vfs_server/main.cpp diff --git a/Makefile b/Makefile index e36df44..2f08a6d 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,8 @@ KERNEL_BIN := target/x86_64-unknown-none/release/opencore_kernel KERNEL_ELF := $(BUILD_DIR)/opencore_kernel.elf INIT_SERVER := $(BUILD_DIR)/init_server.elf UART_DRIVER := $(BUILD_DIR)/uart_driver.elf +VFS_SERVER := $(BUILD_DIR)/vfs_server.elf +NET_SERVER := $(BUILD_DIR)/net_server.elf SH_SERVER := $(BUILD_DIR)/sh.elf PROCMGR := $(BUILD_DIR)/procmgr.elf GUI_SERVER := $(BUILD_DIR)/gui_server.elf @@ -53,7 +55,7 @@ all: kernel libc hal servers @echo "=======================================================" @echo " [SUCCESS] opencoreC Build Complete!" @echo " Kernel: $(KERNEL_ELF)" - @echo " Servers: $(INIT_SERVER), $(UART_DRIVER), $(SH_SERVER), $(PROCMGR), $(GUI_SERVER)" + @echo " Servers: $(INIT_SERVER), $(UART_DRIVER), $(VFS_SERVER), $(NET_SERVER), $(PROCMGR), $(SH_SERVER), $(GUI_SERVER)" @echo " Run: make run (Serial CLI) or make gui (LVGL Desktop Window)" @echo "=======================================================" @@ -99,6 +101,14 @@ servers: libc hal $(LVGL_LIB) @$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(SERVERS_DIR)/uart_driver/main.c -o $(BUILD_DIR)/uart_driver_main.o @$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(UART_DRIVER) \ $(BUILD_DIR)/uart_driver_main.o $(BUILD_DIR)/uart.o $(LIBC_OBJS) + @# Standalone Virtual File System Server + @$(CXX) $(CXXFLAGS) -c $(SERVERS_DIR)/vfs_server/main.cpp -o $(BUILD_DIR)/vfs_server_main.o + @$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(VFS_SERVER) \ + $(BUILD_DIR)/vfs_server_main.o $(BUILD_DIR)/ipc.o $(LIBC_OBJS) + @# Standalone Network Stack Server + @$(CXX) $(CXXFLAGS) -c $(SERVERS_DIR)/net_server/main.cpp -o $(BUILD_DIR)/net_server_main.o + @$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(NET_SERVER) \ + $(BUILD_DIR)/net_server_main.o $(BUILD_DIR)/ipc.o $(NET_OBJS) $(LIBC_OBJS) @# Interactive Shell with Networking & Framebuffer @$(CXX) $(CXXFLAGS) -c $(SERVERS_DIR)/sh/main.cpp -o $(BUILD_DIR)/sh_main.o @$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(SH_SERVER) \ @@ -137,8 +147,10 @@ image: all limine-setup @mcopy -i $(DISK_IMG)@@1M $(KERNEL_ELF) ::/boot/ @mcopy -i $(DISK_IMG)@@1M $(INIT_SERVER) ::/boot/ @mcopy -i $(DISK_IMG)@@1M $(UART_DRIVER) ::/boot/ - @mcopy -i $(DISK_IMG)@@1M $(SH_SERVER) ::/boot/ + @mcopy -i $(DISK_IMG)@@1M $(VFS_SERVER) ::/boot/ + @mcopy -i $(DISK_IMG)@@1M $(NET_SERVER) ::/boot/ @mcopy -i $(DISK_IMG)@@1M $(PROCMGR) ::/boot/ + @mcopy -i $(DISK_IMG)@@1M $(SH_SERVER) ::/boot/ @mcopy -i $(DISK_IMG)@@1M $(GUI_SERVER) ::/boot/ @mcopy -i $(DISK_IMG)@@1M $(HELLO_APP) ::/boot/ @# Bootloader config diff --git a/include/abi/net.h b/include/abi/net.h index 03d91f5..9dc20b0 100644 --- a/include/abi/net.h +++ b/include/abi/net.h @@ -16,6 +16,12 @@ extern "C" { #define ICMP_ECHO_REPLY 0 #define ICMP_ECHO_REQUEST 8 +/* NET_ENDPOINT (6) IPC Opcodes */ +#define NET_OP_GET_CONFIG 1 +#define NET_OP_PING 2 +#define NET_OP_DNS 3 +#define NET_OP_DHCP 4 + #pragma pack(push, 1) typedef struct { diff --git a/include/abi/syscalls.h b/include/abi/syscalls.h index 52dfb4c..38e95f6 100644 --- a/include/abi/syscalls.h +++ b/include/abi/syscalls.h @@ -31,6 +31,21 @@ #define SYS_NOTIFY_RECV 26 /* Poll pending desktop notifications non-blockingly */ #define SYS_MODULE_EXEC 27 /* Find and execute boot module by name (.opc or .elf) */ #define SYS_MODULE_LIST 28 /* List available boot modules in memory */ +#define SYS_TASK_CREATE 29 /* Allocate new user PML4 & thread structure: (name, name_len) -> tid */ +#define SYS_TASK_MAP_PAGE 30 /* Map page into target task: (target_tid, vaddr, src_buf, flags) -> status */ +#define SYS_TASK_START 31 /* Activate thread: (target_tid, entry_rip, user_rsp) -> status */ + +/* Standard Ring 3 Service Endpoints */ +#define UART_SERVICE_ENDPOINT 2 +#define PROCMGR_ENDPOINT 4 +#define VFS_ENDPOINT 5 +#define NET_ENDPOINT 6 + +/* PROCMGR_ENDPOINT (4) IPC Opcodes */ +#define PROC_OP_LIST 1 +#define PROC_OP_KILL 2 +#define PROC_OP_SPAWN 3 +#define PROC_OP_STAT 4 /* POSIX Process Signals */ #define SIGHUP 1 @@ -249,6 +264,33 @@ static inline int sys_module_list(char *out_buf, size_t max_len) { return (int)rax; } +static inline int64_t sys_task_create(const char *name, size_t name_len) { + register uint64_t rax __asm__("rax") = SYS_TASK_CREATE; + register uint64_t rdi __asm__("rdi") = (uint64_t)name; + register uint64_t rsi __asm__("rsi") = (uint64_t)name_len; + __asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi) : "rcx", "r11", "memory"); + return (int64_t)rax; +} + +static inline int64_t sys_task_map_page(uint64_t target_tid, uint64_t vaddr, const void *src_buf, uint64_t flags) { + register uint64_t rax __asm__("rax") = SYS_TASK_MAP_PAGE; + register uint64_t rdi __asm__("rdi") = target_tid; + register uint64_t rsi __asm__("rsi") = vaddr; + register uint64_t rdx __asm__("rdx") = (uint64_t)src_buf; + register uint64_t r8 __asm__("r8") = flags; + __asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi), "r"(rdx), "r"(r8) : "rcx", "r11", "memory"); + return (int64_t)rax; +} + +static inline int64_t sys_task_start(uint64_t target_tid, uint64_t entry_rip, uint64_t user_rsp) { + register uint64_t rax __asm__("rax") = SYS_TASK_START; + register uint64_t rdi __asm__("rdi") = target_tid; + register uint64_t rsi __asm__("rsi") = entry_rip; + register uint64_t rdx __asm__("rdx") = user_rsp; + __asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi), "r"(rdx) : "rcx", "r11", "memory"); + return (int64_t)rax; +} + #ifdef __cplusplus } #endif diff --git a/include/abi/vfs.h b/include/abi/vfs.h new file mode 100644 index 0000000..80c27f3 --- /dev/null +++ b/include/abi/vfs.h @@ -0,0 +1,22 @@ +#pragma once + +#include "types.h" +#include "syscalls.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define VFS_OP_STAT 1 +#define VFS_OP_READ_FILE 2 +#define VFS_OP_WRITE_FILE 3 +#define VFS_OP_LIST 4 + +typedef struct vfs_file_stat { + uint32_t size; + uint32_t is_dir; +} vfs_file_stat_t; + +#ifdef __cplusplus +} +#endif diff --git a/kernel/src/arch/syscall.rs b/kernel/src/arch/syscall.rs index 190f023..e82982c 100644 --- a/kernel/src/arch/syscall.rs +++ b/kernel/src/arch/syscall.rs @@ -433,6 +433,7 @@ pub extern "C" fn kernel_syscall_dispatcher(regs: &mut SyscallRegisters) { entry.tid = t.id; entry.state = match t.state { crate::sched::thread::ThreadState::Unused => 0, + crate::sched::thread::ThreadState::Dormant => 0, crate::sched::thread::ThreadState::Ready => 1, crate::sched::thread::ThreadState::Running => 2, crate::sched::thread::ThreadState::BlockedOnSend(_) | @@ -727,6 +728,111 @@ pub extern "C" fn kernel_syscall_dispatcher(regs: &mut SyscallRegisters) { } regs.rax = 0; } + // SYS_TASK_CREATE = 29: (rdi: name, rsi: name_len) -> tid + 29 => unsafe { + let pfa = core::ptr::addr_of_mut!(crate::mm::pfa::PFA); + let vmm = core::ptr::addr_of_mut!(crate::mm::vmm::VMM); + let sched = core::ptr::addr_of_mut!(crate::sched::SCHEDULER); + + let new_pml4 = (*vmm).create_user_address_space().unwrap_or(0); + if new_pml4 == 0 { + regs.rax = (-1i64) as u64; + return; + } + + // Allocate 16 KiB (4 frames) for kernel stack + let _ = (*pfa).alloc_frame(); + let _ = (*pfa).alloc_frame(); + let _ = (*pfa).alloc_frame(); + let kstack_frame3 = (*pfa).alloc_frame().unwrap_or(0); + if kstack_frame3 == 0 { + regs.rax = (-1i64) as u64; + return; + } + let kstack_top = (*vmm).phys_to_virt::(kstack_frame3 + 4096) as u64; + + let name_ptr = regs.rdi as *const u8; + let name_len = (regs.rsi as usize).min(31); + let static_name: &'static str = if !name_ptr.is_null() && name_len > 0 { + let s = core::str::from_utf8(core::slice::from_raw_parts(name_ptr, name_len)).unwrap_or("user_proc"); + if s.starts_with("hello") { "hello" } + else if s.starts_with("calc") { "calculator" } + else if s.starts_with("edit") { "editor" } + else { "user_proc" } + } else { + "user_proc" + }; + + match (*sched).create_dormant_task(static_name, new_pml4, kstack_top) { + Some(tid) => { + regs.rax = tid; + } + None => { + regs.rax = (-1i64) as u64; + } + } + }, + // SYS_TASK_MAP_PAGE = 30: (rdi: target_tid, rsi: target_vaddr, rdx: src_buf, r8: flags) -> status + 30 => unsafe { + let target_tid = regs.rdi; + let target_vaddr = regs.rsi & !0xFFF; + let src_buf = regs.rdx as *const u8; + let flags = regs.r8; + + let sched = core::ptr::addr_of_mut!(crate::sched::SCHEDULER); + let vmm = core::ptr::addr_of_mut!(crate::mm::vmm::VMM); + let pfa = core::ptr::addr_of_mut!(crate::mm::pfa::PFA); + + let mut target_pml4 = 0; + for t in &(*sched).threads { + if t.id == target_tid { + target_pml4 = t.pml4_paddr; + break; + } + } + + if target_pml4 == 0 { + regs.rax = (-1i64) as u64; + return; + } + + let frame = (*pfa).alloc_frame().unwrap_or(0); + if frame == 0 { + regs.rax = (-2i64) as u64; + return; + } + + let frame_virt = (*vmm).phys_to_virt::(frame); + if !src_buf.is_null() { + core::ptr::copy_nonoverlapping(src_buf, frame_virt, 4096); + } else { + core::ptr::write_bytes(frame_virt, 0, 4096); + } + + let mut page_flags = crate::mm::vmm::PAGE_USER | crate::mm::vmm::PAGE_PRESENT; + if (flags & 2) != 0 { + page_flags |= crate::mm::vmm::PAGE_WRITABLE; + } + + if (*vmm).map_page(target_pml4, target_vaddr, frame, page_flags).is_ok() { + regs.rax = 0; + } else { + regs.rax = (-3i64) as u64; + } + }, + // SYS_TASK_START = 31: (rdi: target_tid, rsi: entry_rip, rdx: user_rsp) -> status + 31 => unsafe { + let target_tid = regs.rdi; + let entry_rip = regs.rsi; + let user_rsp = regs.rdx; + + let sched = core::ptr::addr_of_mut!(crate::sched::SCHEDULER); + if (*sched).start_task(target_tid, entry_rip, user_rsp) { + regs.rax = 0; + } else { + regs.rax = (-1i64) as u64; + } + }, _ => { regs.rax = (-1i64) as u64; // SYS_ERR_INVALID_ARG } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index e3831d4..4edd413 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -100,7 +100,7 @@ pub extern "C" fn _start() -> ! { for i in 0..count { let mod_file = *(*mod_resp).modules.add(i as usize); - if i >= 5 { + if i >= 7 { let path_ptr = (*mod_file).path; let mut path_len = 0; while !path_ptr.is_null() && *path_ptr.add(path_len) != 0 && path_len < 64 { @@ -119,9 +119,11 @@ pub extern "C" fn _start() -> ! { let name = match i { 0 => "init_server", 1 => "uart_driver", - 2 => "sh", - 3 => "procmgr", - 4 => "gui_server", + 2 => "vfs_server", + 3 => "net_server", + 4 => "procmgr", + 5 => "sh", + 6 => "gui_server", _ => "user_server", }; diff --git a/kernel/src/sched/mod.rs b/kernel/src/sched/mod.rs index 355161a..3d5e548 100644 --- a/kernel/src/sched/mod.rs +++ b/kernel/src/sched/mod.rs @@ -76,7 +76,7 @@ impl Scheduler { self.threads[i].cpu_affinity = Some(1); } else if name.starts_with("sh") { self.threads[i].cpu_affinity = Some(2); - } else if name.starts_with("init") || name.starts_with("proc") || name.starts_with("uart") { + } else if name.starts_with("init") || name.starts_with("proc") || name.starts_with("uart") || name.starts_with("vfs") || name.starts_with("net") { self.threads[i].cpu_affinity = Some(3); } else { self.threads[i].cpu_affinity = None; @@ -105,6 +105,62 @@ impl Scheduler { None } + pub fn create_dormant_task( + &mut self, + name: &'static str, + pml4_paddr: u64, + kernel_stack_top: u64, + ) -> Option { + for i in 1..MAX_THREADS { + if self.threads[i].state == ThreadState::Unused { + let tid = self.next_tid; + self.next_tid += 1; + + self.threads[i].id = tid; + self.threads[i].name = name; + self.threads[i].state = ThreadState::Dormant; // Dormant until started + self.threads[i].pml4_paddr = pml4_paddr; + self.threads[i].kernel_stack_top = kernel_stack_top; + self.threads[i].user_rsp = 0; + self.threads[i].user_rip = 0; + self.threads[i].cpu_ticks = 0; + self.threads[i].cpu_affinity = None; + + kprintln!("[SCHED] Created Dormant Task [TID {}] '{}' (PML4: {:#x})", tid, name, pml4_paddr); + return Some(tid); + } + } + None + } + + pub fn start_task(&mut self, tid: u64, entry_rip: u64, user_rsp: u64) -> bool { + for i in 1..MAX_THREADS { + if self.threads[i].id == tid && self.threads[i].state == ThreadState::Dormant { + self.threads[i].user_rip = entry_rip; + self.threads[i].user_rsp = user_rsp; + + unsafe { + let k = self.threads[i].kernel_stack_top as *mut u64; + *k.sub(1) = thread_entry_trampoline as *const () as u64; // ret address + *k.sub(2) = 0; // rbp + *k.sub(3) = 0; // rbx + *k.sub(4) = user_rsp; // r12 -> user_rsp + *k.sub(5) = entry_rip; // r13 -> entry_rip + *k.sub(6) = 0; // r14 + *k.sub(7) = 0; // r15 + + self.threads[i].context.rsp = k.sub(7) as u64; + } + + self.threads[i].state = ThreadState::Ready; + kprintln!("[SCHED] Activated Task [TID {}] '{}' (Entry: {:#x}, RSP: {:#x})", + tid, self.threads[i].name, entry_rip, user_rsp); + return true; + } + } + false + } + pub fn get_current_mut(&mut self) -> &mut Thread { &mut self.threads[self.current_tid] } diff --git a/kernel/src/sched/thread.rs b/kernel/src/sched/thread.rs index 5f7c502..24476d7 100644 --- a/kernel/src/sched/thread.rs +++ b/kernel/src/sched/thread.rs @@ -8,6 +8,7 @@ pub const KERNEL_STACK_SIZE: usize = 16384; // 16 KiB #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ThreadState { Unused, + Dormant, Ready, Running, BlockedOnSend(u64), // Waiting on destination endpoint ID diff --git a/limine.cfg b/limine.cfg index 525c382..aedff77 100644 --- a/limine.cfg +++ b/limine.cfg @@ -9,7 +9,9 @@ interface_resolution: 1280x800 kernel_path: boot():/boot/opencore_kernel.elf module_path: boot():/boot/init_server.elf module_path: boot():/boot/uart_driver.elf - module_path: boot():/boot/sh.elf + module_path: boot():/boot/vfs_server.elf + module_path: boot():/boot/net_server.elf module_path: boot():/boot/procmgr.elf + module_path: boot():/boot/sh.elf module_path: boot():/boot/gui_server.elf module_path: boot():/boot/hello.opc diff --git a/limine.conf b/limine.conf index 525c382..aedff77 100644 --- a/limine.conf +++ b/limine.conf @@ -9,7 +9,9 @@ interface_resolution: 1280x800 kernel_path: boot():/boot/opencore_kernel.elf module_path: boot():/boot/init_server.elf module_path: boot():/boot/uart_driver.elf - module_path: boot():/boot/sh.elf + module_path: boot():/boot/vfs_server.elf + module_path: boot():/boot/net_server.elf module_path: boot():/boot/procmgr.elf + module_path: boot():/boot/sh.elf module_path: boot():/boot/gui_server.elf module_path: boot():/boot/hello.opc diff --git a/servers/gui_server/main.cpp b/servers/gui_server/main.cpp index 7ce64cf..616d04b 100644 --- a/servers/gui_server/main.cpp +++ b/servers/gui_server/main.cpp @@ -654,20 +654,17 @@ static void execute_console_command(const char *raw_cmd) { exec_target++; } - int64_t tid = sys_module_exec(exec_target); - if (tid < 0 && !strstr(exec_target, ".")) { - char opc_name[70]; - snprintf(opc_name, sizeof(opc_name), "%s.opc", exec_target); - tid = sys_module_exec(opc_name); - if (tid < 0) { - char elf_name[70]; - snprintf(elf_name, sizeof(elf_name), "%s.elf", exec_target); - tid = sys_module_exec(elf_name); - } + uint64_t p0 = 0, p1 = 0; + memcpy(&p0, exec_target, strlen(exec_target) < 8 ? strlen(exec_target) : 8); + if (strlen(exec_target) > 8) { + memcpy(&p1, exec_target + 8, strlen(exec_target) - 8 < 8 ? strlen(exec_target) - 8 : 8); } + uint64_t out0 = 0, out1 = 0; + sysret_t ret = sys_ipc_call_raw(PROCMGR_ENDPOINT, PROC_OP_SPAWN, p0, p1, 0, 0, &out0, &out1); + int64_t tid = (ret == 0) ? (int64_t)out0 : -1; if (tid >= 0) { - snprintf(buf, sizeof(buf), "[osh] Process spawned with TID %ld on Ring 3\n", (long)tid); + snprintf(buf, sizeof(buf), "[procmgr] Process spawned with TID %ld on Ring 3\n", (long)tid); lv_textarea_add_text(g_txt_term_output, buf); } else { snprintf(buf, sizeof(buf), "osh: %s: command not found\n", raw_cmd); diff --git a/servers/net_server/main.cpp b/servers/net_server/main.cpp new file mode 100644 index 0000000..984aae1 --- /dev/null +++ b/servers/net_server/main.cpp @@ -0,0 +1,85 @@ +/** + * opencoreC - Network Stack Server (Ring 3 User Space) + * Centralized network daemon managing RTL8139 hardware NIC, ARP, DHCP, DNS, TCP/IP. + * Listens on NET_ENDPOINT (6) and handles synchronous IPC requests from sh and gui_server. + */ + +#include "stdio.h" +#include "string.h" +#include "abi/syscalls.h" +#include "abi/ipc.h" +#include "abi/net.h" + +extern "C" void _start(void) { + puts("[NET-SERVER] Initializing Hardware RTL8139 NIC & TCP/IP Stack in Ring 3..."); + net_init(); + + // Acquire DHCP lease on startup + int dhcp_res = net_dhcp_discover(); + char ip_str[32], gw_str[32]; + format_ip(g_net_cfg.ip, ip_str); + format_ip(g_net_cfg.gateway, gw_str); + if (dhcp_res == 0) { + printf("[NET-SERVER] DHCP OK: IP %s, Gateway %s\n", ip_str, gw_str); + } else { + printf("[NET-SERVER] DHCP fallback: IP %s, Gateway %s\n", ip_str, gw_str); + } + + uint64_t last_client = 0; + uint64_t reply_val0 = 0; + uint64_t reply_val1 = 0; + + while (1) { + uint64_t sender_tid = 0; + uint64_t opcode = 0; + uint64_t arg0 = 0; + uint64_t arg1 = 0; + + sysret_t ret = sys_ipc_reply_recv_raw( + NET_ENDPOINT, + last_client, + reply_val0, + reply_val1, + &sender_tid, + &opcode, + &arg0, + &arg1 + ); + + if (ret == 0 && sender_tid != 0) { + last_client = sender_tid; + + if (opcode == NET_OP_GET_CONFIG) { + // reply_val0 = ip (low 32 bits) | (gateway << 32) + // reply_val1 = netmask (low 32 bits) | (dns_server << 32) + reply_val0 = ((uint64_t)g_net_cfg.gateway << 32) | (uint64_t)g_net_cfg.ip; + reply_val1 = ((uint64_t)g_net_cfg.dns_server << 32) | (uint64_t)g_net_cfg.netmask; + } else if (opcode == NET_OP_PING) { + uint32_t target_ip = (uint32_t)arg0; + uint16_t seq = (uint16_t)(arg1 ? arg1 : 1); + int ping_res = net_send_icmp_ping(target_ip, seq); + reply_val0 = (ping_res == 0) ? 0 : (uint64_t)-1; + reply_val1 = 0; + } else if (opcode == NET_OP_DNS) { + // Domain string passed in arg0 (8 bytes) + arg1 (8 bytes) + char domain[20] = {0}; + memcpy(domain, &arg0, 8); + memcpy(domain + 8, &arg1, 8); + uint32_t resolved_ip = 0; + int res = net_dns_resolve(domain, &resolved_ip); + reply_val0 = (res == 0) ? (uint64_t)resolved_ip : 0; + reply_val1 = (uint64_t)res; + } else if (opcode == NET_OP_DHCP) { + int res = net_dhcp_discover(); + reply_val0 = (res == 0) ? (uint64_t)g_net_cfg.ip : 0; + reply_val1 = (uint64_t)g_net_cfg.gateway; + } else { + reply_val0 = (uint64_t)-1; + reply_val1 = 0; + } + } else { + last_client = 0; + sys_yield(); + } + } +} diff --git a/servers/procmgr/main.cpp b/servers/procmgr/main.cpp index a68454a..002ee7b 100644 --- a/servers/procmgr/main.cpp +++ b/servers/procmgr/main.cpp @@ -53,6 +53,25 @@ extern "C" void _start() { __asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi) : "rcx", "r11", "memory"); reply_val0 = (rax > 0) ? rax : 0; reply_val1 = 0; + } else if (opcode == PROC_OP_SPAWN) { + // Program name passed in arg0 (8 bytes) + arg1 (8 bytes) + char prog[20] = {0}; + memcpy(prog, &arg0, 8); + memcpy(prog + 8, &arg1, 8); + + int64_t tid = sys_module_exec(prog); + if (tid < 0 && !strstr(prog, ".")) { + char opc_name[28]; + snprintf(opc_name, sizeof(opc_name), "%s.opc", prog); + tid = sys_module_exec(opc_name); + if (tid < 0) { + char elf_name[28]; + snprintf(elf_name, sizeof(elf_name), "%s.elf", prog); + tid = sys_module_exec(elf_name); + } + } + reply_val0 = (uint64_t)tid; + reply_val1 = 0; } else { reply_val0 = 0; reply_val1 = 0; diff --git a/servers/sh/main.cpp b/servers/sh/main.cpp index 23c1c11..5268e72 100644 --- a/servers/sh/main.cpp +++ b/servers/sh/main.cpp @@ -339,10 +339,17 @@ static void cmd_run_module(const char *mod_name) { while (*mod_name == '.' || *mod_name == '/') { mod_name++; } - printf("[osh] Launching native program '%s' via kernel loader...\n", mod_name); - int64_t tid = sys_module_exec(mod_name); + printf("[osh] Requesting Process Manager (procmgr) to spawn '%s'...\n", mod_name); + uint64_t p0 = 0, p1 = 0; + memcpy(&p0, mod_name, strlen(mod_name) < 8 ? strlen(mod_name) : 8); + if (strlen(mod_name) > 8) { + memcpy(&p1, mod_name + 8, strlen(mod_name) - 8 < 8 ? strlen(mod_name) - 8 : 8); + } + uint64_t out0 = 0, out1 = 0; + sysret_t ret = sys_ipc_call_raw(PROCMGR_ENDPOINT, PROC_OP_SPAWN, p0, p1, 0, 0, &out0, &out1); + int64_t tid = (ret == 0) ? (int64_t)out0 : -1; if (tid >= 0) { - printf("[osh] Process successfully spawned with TID %ld on Ring 3!\n", (long)tid); + printf("[procmgr] Process successfully spawned with TID %ld on Ring 3!\n", (long)tid); for (int i = 0; i < 6; i++) sys_yield(); } else { printf("osh: failed to execute '%s' (module not found or invalid format)\n", mod_name); @@ -965,20 +972,17 @@ static void handle_command(char *cmd) { exec_target++; } - int64_t tid = sys_module_exec(exec_target); - if (tid < 0 && !strstr(exec_target, ".")) { - char opc_name[70]; - snprintf(opc_name, sizeof(opc_name), "%s.opc", exec_target); - tid = sys_module_exec(opc_name); - if (tid < 0) { - char elf_name[70]; - snprintf(elf_name, sizeof(elf_name), "%s.elf", exec_target); - tid = sys_module_exec(elf_name); - } + uint64_t p0 = 0, p1 = 0; + memcpy(&p0, exec_target, strlen(exec_target) < 8 ? strlen(exec_target) : 8); + if (strlen(exec_target) > 8) { + memcpy(&p1, exec_target + 8, strlen(exec_target) - 8 < 8 ? strlen(exec_target) - 8 : 8); } + uint64_t out0 = 0, out1 = 0; + sysret_t ret = sys_ipc_call_raw(PROCMGR_ENDPOINT, PROC_OP_SPAWN, p0, p1, 0, 0, &out0, &out1); + int64_t tid = (ret == 0) ? (int64_t)out0 : -1; if (tid >= 0) { - printf("[osh] Process spawned with TID %ld on Ring 3\n", (long)tid); + printf("[procmgr] Process spawned with TID %ld on Ring 3\n", (long)tid); for (int i = 0; i < 6; i++) sys_yield(); } else { printf("osh: command not found: %s\n", cmd); diff --git a/servers/vfs_server/main.cpp b/servers/vfs_server/main.cpp new file mode 100644 index 0000000..44f0b77 --- /dev/null +++ b/servers/vfs_server/main.cpp @@ -0,0 +1,214 @@ +/** + * opencoreC - Virtual File System Server (Ring 3 User Space) + * Centralized file system daemon managing in-memory and virtual file hierarchy. + * Listens on VFS_ENDPOINT (5) and handles synchronous IPC requests. + */ + +#include "stdio.h" +#include "string.h" +#include "abi/syscalls.h" +#include "abi/ipc.h" +#include "abi/vfs.h" + +#define MAX_VFS_NODES 64 + +struct VfsNode { + char name[48]; + bool is_dir; + uint32_t size; + char content[1024]; +}; + +static VfsNode g_nodes[MAX_VFS_NODES]; +static size_t g_node_count = 0; + +static void vfs_add_dir(const char *name) { + if (g_node_count >= MAX_VFS_NODES) return; + strncpy(g_nodes[g_node_count].name, name, sizeof(g_nodes[0].name) - 1); + g_nodes[g_node_count].is_dir = true; + g_nodes[g_node_count].size = 4096; + g_nodes[g_node_count].content[0] = '\0'; + g_node_count++; +} + +static void vfs_add_file(const char *name, const char *content) { + if (g_node_count >= MAX_VFS_NODES) return; + strncpy(g_nodes[g_node_count].name, name, sizeof(g_nodes[0].name) - 1); + g_nodes[g_node_count].is_dir = false; + uint32_t len = (uint32_t)strlen(content); + if (len >= sizeof(g_nodes[0].content)) len = sizeof(g_nodes[0].content) - 1; + memcpy(g_nodes[g_node_count].content, content, len); + g_nodes[g_node_count].content[len] = '\0'; + g_nodes[g_node_count].size = len; + g_node_count++; +} + +static void vfs_init() { + g_node_count = 0; + + vfs_add_dir("/"); + vfs_add_dir("/bin"); + vfs_add_dir("/etc"); + vfs_add_dir("/proc"); + vfs_add_dir("/dev"); + vfs_add_dir("/tmp"); + + vfs_add_file("/etc/os-release", + "NAME=\"opencoreC\"\n" + "VERSION=\"0.1.0-release\"\n" + "ID=opencorec\n" + "PRETTY_NAME=\"opencoreC Microkernel x86_64\"\n"); + + vfs_add_file("/etc/motd", + "=======================================================\n" + " Welcome to opencoreC Pure Microkernel (x86_64)!\n" + " Servers: init, uart, vfs, net, procmgr, sh, gui\n" + "=======================================================\n"); + + vfs_add_file("/etc/hosts", "127.0.0.1 localhost\n"); + vfs_add_file("/proc/version", "opencoreC version 0.1.0-microkernel (Rust Ring 0 + C++ Ring 3)\n"); + vfs_add_file("/proc/cpuinfo", "model name: x86_64 SMP Microkernel Processor\ncores: 4\n"); + vfs_add_file("/dev/null", ""); + vfs_add_file("/dev/uart0", ""); + vfs_add_file("/dev/net0", ""); + + // Dynamically discover in-memory boot modules from Limine + char mbuf[512] = {0}; + int len = sys_module_list(mbuf, sizeof(mbuf) - 1); + if (len > 0) { + char *p = mbuf; + while (*p) { + char mod_name[48] = {0}; + int mi = 0; + while (*p && *p != ' ' && mi < 40) { + mod_name[mi++] = *p++; + } + while (*p == ' ') p++; + + if (mi > 0) { + char full_path[56]; + snprintf(full_path, sizeof(full_path), "/bin/%s", mod_name); + vfs_add_file(full_path, "[Executable Binary Module]"); + } + } + } +} + +extern "C" void _start(void) { + vfs_init(); + puts("[VFS-SERVER] Virtual File System Daemon Started (Endpoint 5, Ring 3)."); + + uint64_t last_client = 0; + uint64_t reply_val0 = 0; + uint64_t reply_val1 = 0; + + while (1) { + uint64_t sender_tid = 0; + uint64_t opcode = 0; + uint64_t arg0 = 0; + uint64_t arg1 = 0; + + sysret_t ret = sys_ipc_reply_recv_raw( + VFS_ENDPOINT, + last_client, + reply_val0, + reply_val1, + &sender_tid, + &opcode, + &arg0, + &arg1 + ); + + if (ret == 0 && sender_tid != 0) { + last_client = sender_tid; + + if (opcode == VFS_OP_STAT) { + // Path passed packed in arg0 (first 8 bytes) + arg1 (next 8 bytes) + char path[32] = {0}; + memcpy(path, &arg0, 8); + memcpy(path + 8, &arg1, 8); + + bool found = false; + for (size_t i = 0; i < g_node_count; i++) { + if (strcmp(g_nodes[i].name, path) == 0) { + reply_val0 = 0; // Success + reply_val1 = g_nodes[i].size | (g_nodes[i].is_dir ? 0x80000000ULL : 0ULL); + found = true; + break; + } + } + if (!found) { + reply_val0 = (uint64_t)-1; // Not found + reply_val1 = 0; + } + } else if (opcode == VFS_OP_LIST) { + // arg0 = index + size_t idx = (size_t)arg0; + if (idx < g_node_count) { + reply_val0 = 0; // Success + reply_val1 = (uint64_t)g_nodes[idx].size | (g_nodes[idx].is_dir ? 0x80000000ULL : 0ULL); + } else { + reply_val0 = (uint64_t)-1; // End of list + reply_val1 = 0; + } + } else if (opcode == VFS_OP_READ_FILE) { + // arg0: packed name (first 8 bytes), arg1: offset + char path[16] = {0}; + memcpy(path, &arg0, 8); + size_t offset = (size_t)arg1; + + bool found = false; + for (size_t i = 0; i < g_node_count; i++) { + if (strcmp(g_nodes[i].name, path) == 0) { + found = true; + if (offset < g_nodes[i].size) { + uint64_t chunk = 0; + size_t avail = g_nodes[i].size - offset; + if (avail > 8) avail = 8; + memcpy(&chunk, g_nodes[i].content + offset, avail); + reply_val0 = avail; + reply_val1 = chunk; + } else { + reply_val0 = 0; // EOF + reply_val1 = 0; + } + break; + } + } + if (!found) { + reply_val0 = (uint64_t)-1; + reply_val1 = 0; + } + } else if (opcode == VFS_OP_WRITE_FILE) { + // arg0: packed name (first 8 bytes), arg1: 8 bytes data + char path[16] = {0}; + memcpy(path, &arg0, 8); + + bool found = false; + for (size_t i = 0; i < g_node_count; i++) { + if (strcmp(g_nodes[i].name, path) == 0) { + found = true; + memcpy(g_nodes[i].content, &arg1, 8); + g_nodes[i].size = 8; + reply_val0 = 0; + reply_val1 = 8; + break; + } + } + if (!found && g_node_count < MAX_VFS_NODES) { + vfs_add_file(path, ""); + memcpy(g_nodes[g_node_count - 1].content, &arg1, 8); + g_nodes[g_node_count - 1].size = 8; + reply_val0 = 0; + reply_val1 = 8; + } + } else { + reply_val0 = (uint64_t)-1; + reply_val1 = 0; + } + } else { + last_client = 0; + sys_yield(); + } + } +}