feat(ipc): implement synchronous Rendezvous IPC and multi-thread cooperative scheduler
This commit is contained in:
@@ -45,6 +45,30 @@ static inline sysret_t sys_ipc_call_raw(cap_t dest_cap, uint64_t msg_code,
|
|||||||
return (sysret_t)rax;
|
return (sysret_t)rax;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline sysret_t sys_ipc_reply_recv_raw(cap_t listen_ep, uint64_t reply_to_tid,
|
||||||
|
uint64_t reply_val0, uint64_t reply_val1,
|
||||||
|
uint64_t *sender_tid, uint64_t *opcode,
|
||||||
|
uint64_t *arg0, uint64_t *arg1) {
|
||||||
|
register uint64_t rax __asm__("rax") = SYS_IPC_REPLY_RECV;
|
||||||
|
register uint64_t rdi __asm__("rdi") = listen_ep;
|
||||||
|
register uint64_t rsi __asm__("rsi") = reply_to_tid;
|
||||||
|
register uint64_t rdx __asm__("rdx") = reply_val0;
|
||||||
|
register uint64_t r8 __asm__("r8") = reply_val1;
|
||||||
|
|
||||||
|
__asm__ volatile(
|
||||||
|
"syscall"
|
||||||
|
: "+r"(rax), "+r"(rdi), "+r"(rsi), "+r"(rdx), "+r"(r8)
|
||||||
|
:
|
||||||
|
: "rcx", "r11", "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sender_tid) *sender_tid = rdi;
|
||||||
|
if (opcode) *opcode = rsi;
|
||||||
|
if (arg0) *arg0 = rdx;
|
||||||
|
if (arg1) *arg1 = r8;
|
||||||
|
return (sysret_t)rax;
|
||||||
|
}
|
||||||
|
|
||||||
static inline sysret_t sys_yield(void) {
|
static inline sysret_t sys_yield(void) {
|
||||||
register uint64_t rax __asm__("rax") = SYS_THREAD_YIELD;
|
register uint64_t rax __asm__("rax") = SYS_THREAD_YIELD;
|
||||||
__asm__ volatile("syscall" : "+r"(rax) : : "rcx", "r11", "memory");
|
__asm__ volatile("syscall" : "+r"(rax) : : "rcx", "r11", "memory");
|
||||||
|
|||||||
+7
-5
@@ -30,9 +30,11 @@ typedef uint32_t tid_t; /* Thread ID */
|
|||||||
|
|
||||||
/* Standard Special Capabilities */
|
/* Standard Special Capabilities */
|
||||||
#define CAP_NULL 0
|
#define CAP_NULL 0
|
||||||
|
#define CAP_KERNEL_CONTROL 1
|
||||||
#define CAP_SELF_TASK 1
|
#define CAP_SELF_TASK 1
|
||||||
#define CAP_SELF_THREAD 2
|
#define CAP_ROOT_SERVER 2
|
||||||
#define CAP_SELF_VMSPACE 3
|
#define CAP_SELF_THREAD 3
|
||||||
#define CAP_ROOT_CSPACE 4
|
#define CAP_SELF_VMSPACE 4
|
||||||
#define CAP_ROOT_IRQ 5
|
#define CAP_ROOT_CSPACE 5
|
||||||
#define CAP_ROOT_IO 6
|
#define CAP_ROOT_IRQ 6
|
||||||
|
#define CAP_ROOT_IO 7
|
||||||
|
|||||||
+58
-16
@@ -1,5 +1,8 @@
|
|||||||
//! x86_64 Fast Syscall / Sysret Setup and Fast-Path Dispatch
|
//! x86_64 Fast Syscall / Sysret Setup and Fast-Path & Rendezvous Dispatch
|
||||||
|
|
||||||
|
use crate::ipc::endpoint::EP_MANAGER;
|
||||||
|
use crate::ipc::fastpath::{CAP_KERNEL_CONTROL, handle_fastpath_call};
|
||||||
|
use crate::sched::SCHEDULER;
|
||||||
use crate::kprintln;
|
use crate::kprintln;
|
||||||
|
|
||||||
const IA32_EFER: u32 = 0xC0000080;
|
const IA32_EFER: u32 = 0xC0000080;
|
||||||
@@ -39,20 +42,13 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init() {
|
pub unsafe fn init() {
|
||||||
// 1. Enable System Call Extension (SCE) in IA32_EFER
|
|
||||||
let efer = rdmsr(IA32_EFER);
|
let efer = rdmsr(IA32_EFER);
|
||||||
wrmsr(IA32_EFER, efer | 1);
|
wrmsr(IA32_EFER, efer | 1);
|
||||||
|
|
||||||
// 2. Set STAR MSR:
|
|
||||||
// Bits [47:32] = Kernel CS/SS selectors (0x0008)
|
|
||||||
// Bits [63:48] = User CS/SS selectors base (0x0010 -> SS=0x18, CS=0x20)
|
|
||||||
let star = (0x0010u64 << 48) | (0x0008u64 << 32);
|
let star = (0x0010u64 << 48) | (0x0008u64 << 32);
|
||||||
wrmsr(IA32_STAR, star);
|
wrmsr(IA32_STAR, star);
|
||||||
|
|
||||||
// 3. Set LSTAR to our assembly entry trampoline
|
|
||||||
wrmsr(IA32_LSTAR, syscall_entry as *const () as usize as u64);
|
wrmsr(IA32_LSTAR, syscall_entry as *const () as usize as u64);
|
||||||
|
|
||||||
// 4. Set FMASK to clear IF (bit 9, 0x200), DF (bit 10), TF (bit 8)
|
|
||||||
wrmsr(IA32_FMASK, 0x00000200);
|
wrmsr(IA32_FMASK, 0x00000200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,8 +66,13 @@ pub struct SyscallRegisters {
|
|||||||
/// Dispatcher called directly from syscall_entry assembly trampoline
|
/// Dispatcher called directly from syscall_entry assembly trampoline
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn kernel_syscall_dispatcher(regs: &mut SyscallRegisters) {
|
pub extern "C" fn kernel_syscall_dispatcher(regs: &mut SyscallRegisters) {
|
||||||
|
let current_tid = unsafe {
|
||||||
|
let sched = &mut *core::ptr::addr_of_mut!(SCHEDULER);
|
||||||
|
sched.get_current_mut().id
|
||||||
|
};
|
||||||
|
|
||||||
match regs.rax {
|
match regs.rax {
|
||||||
// SYS_IPC_CALL = 1
|
// SYS_IPC_CALL = 1 (Client: Send & Wait for Reply)
|
||||||
1 => {
|
1 => {
|
||||||
let dest_cap = regs.rdi;
|
let dest_cap = regs.rdi;
|
||||||
let opcode = regs.rsi;
|
let opcode = regs.rsi;
|
||||||
@@ -80,16 +81,57 @@ pub extern "C" fn kernel_syscall_dispatcher(regs: &mut SyscallRegisters) {
|
|||||||
let arg2 = regs.r9;
|
let arg2 = regs.r9;
|
||||||
let arg3 = regs.r10;
|
let arg3 = regs.r10;
|
||||||
|
|
||||||
let (ret, out0, out1) = crate::ipc::fastpath::handle_fastpath_call(
|
if dest_cap == CAP_KERNEL_CONTROL {
|
||||||
dest_cap, opcode, arg0, arg1, arg2, arg3,
|
let (ret, out0, out1) = handle_fastpath_call(dest_cap, opcode, arg0, arg1, arg2, arg3);
|
||||||
);
|
regs.rax = ret as u64;
|
||||||
|
regs.rdx = out0;
|
||||||
|
regs.r8 = out1;
|
||||||
|
} else {
|
||||||
|
// Inter-Process Rendezvous IPC Call
|
||||||
|
unsafe {
|
||||||
|
let ep_mgr = &mut *core::ptr::addr_of_mut!(EP_MANAGER);
|
||||||
|
match ep_mgr.ipc_call(dest_cap, opcode, [arg0, arg1, arg2, arg3], current_tid) {
|
||||||
|
Ok((out0, out1)) => {
|
||||||
|
regs.rax = 0;
|
||||||
|
regs.rdx = out0;
|
||||||
|
regs.r8 = out1;
|
||||||
|
}
|
||||||
|
Err(code) => {
|
||||||
|
regs.rax = code as u64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// SYS_IPC_REPLY_RECV = 2 (Server: Reply to Caller & Wait for Request)
|
||||||
|
2 => {
|
||||||
|
let listen_ep = regs.rdi;
|
||||||
|
let reply_to_tid = regs.rsi;
|
||||||
|
let reply_val0 = regs.rdx;
|
||||||
|
let reply_val1 = regs.r8;
|
||||||
|
|
||||||
regs.rax = ret as u64;
|
unsafe {
|
||||||
regs.rdx = out0;
|
let ep_mgr = &mut *core::ptr::addr_of_mut!(EP_MANAGER);
|
||||||
regs.r8 = out1;
|
match ep_mgr.ipc_reply_recv(listen_ep, reply_to_tid, reply_val0, reply_val1, current_tid) {
|
||||||
|
Ok((sender_tid, opcode, a0, a1)) => {
|
||||||
|
regs.rax = 0;
|
||||||
|
regs.rdi = sender_tid;
|
||||||
|
regs.rsi = opcode;
|
||||||
|
regs.rdx = a0;
|
||||||
|
regs.r8 = a1;
|
||||||
|
}
|
||||||
|
Err(code) => {
|
||||||
|
regs.rax = code as u64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// SYS_THREAD_YIELD = 7
|
// SYS_THREAD_YIELD = 7
|
||||||
7 => {
|
7 => {
|
||||||
|
unsafe {
|
||||||
|
let sched = &mut *core::ptr::addr_of_mut!(SCHEDULER);
|
||||||
|
sched.yield_current();
|
||||||
|
}
|
||||||
regs.rax = 0;
|
regs.rax = 0;
|
||||||
}
|
}
|
||||||
// SYS_LOG_DEBUG = 9
|
// SYS_LOG_DEBUG = 9
|
||||||
@@ -99,7 +141,7 @@ pub extern "C" fn kernel_syscall_dispatcher(regs: &mut SyscallRegisters) {
|
|||||||
if !msg_ptr.is_null() && len > 0 && len < 4096 {
|
if !msg_ptr.is_null() && len > 0 && len < 4096 {
|
||||||
let slice = unsafe { core::slice::from_raw_parts(msg_ptr, len) };
|
let slice = unsafe { core::slice::from_raw_parts(msg_ptr, len) };
|
||||||
if let Ok(s) = core::str::from_utf8(slice) {
|
if let Ok(s) = core::str::from_utf8(slice) {
|
||||||
kprintln!("[USER LOG] {}", s);
|
kprintln!("[USER TID {}] {}", current_tid, s);
|
||||||
regs.rax = 0;
|
regs.rax = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,195 @@
|
|||||||
|
//! IPC Endpoints and Synchronous Rendezvous Engine
|
||||||
|
|
||||||
|
use crate::ipc::fastpath::FastPathMessage;
|
||||||
|
use crate::sched::SCHEDULER;
|
||||||
|
use crate::sched::thread::ThreadState;
|
||||||
|
use crate::kprintln;
|
||||||
|
|
||||||
|
pub const MAX_ENDPOINTS: usize = 32;
|
||||||
|
pub const MAX_QUEUE_PER_EP: usize = 8;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct Endpoint {
|
||||||
|
pub id: u64,
|
||||||
|
pub receiver_tid: u64,
|
||||||
|
pub send_queue: [u64; MAX_QUEUE_PER_EP],
|
||||||
|
pub send_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Endpoint {
|
||||||
|
pub const fn empty() -> Self {
|
||||||
|
Self {
|
||||||
|
id: 0,
|
||||||
|
receiver_tid: 0,
|
||||||
|
send_queue: [0; MAX_QUEUE_PER_EP],
|
||||||
|
send_count: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EndpointManager {
|
||||||
|
pub endpoints: [Endpoint; MAX_ENDPOINTS],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static mut EP_MANAGER: EndpointManager = EndpointManager {
|
||||||
|
endpoints: [const { Endpoint::empty() }; MAX_ENDPOINTS],
|
||||||
|
};
|
||||||
|
|
||||||
|
impl EndpointManager {
|
||||||
|
pub fn init(&mut self) {
|
||||||
|
for i in 0..MAX_ENDPOINTS {
|
||||||
|
self.endpoints[i].id = i as u64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_endpoint_mut(&mut self, ep_id: u64) -> Option<&mut Endpoint> {
|
||||||
|
let idx = ep_id as usize;
|
||||||
|
if idx < MAX_ENDPOINTS {
|
||||||
|
Some(&mut self.endpoints[idx])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Client performs synchronous Call (Send + Wait for Reply)
|
||||||
|
pub unsafe fn ipc_call(
|
||||||
|
&mut self,
|
||||||
|
dest_ep: u64,
|
||||||
|
opcode: u64,
|
||||||
|
args: [u64; 4],
|
||||||
|
caller_tid: u64,
|
||||||
|
) -> Result<(u64, u64), i64> {
|
||||||
|
let ep = self.get_endpoint_mut(dest_ep).ok_or(-2i64)?; // Invalid Cap/Endpoint
|
||||||
|
let sched = &mut *core::ptr::addr_of_mut!(SCHEDULER);
|
||||||
|
|
||||||
|
if ep.receiver_tid != 0 {
|
||||||
|
// Rendezvous: Server is already blocked waiting for a request!
|
||||||
|
let server_tid = ep.receiver_tid;
|
||||||
|
ep.receiver_tid = 0; // Clear receiver wait state
|
||||||
|
|
||||||
|
// Transfer message directly into server's context
|
||||||
|
if let Some(server) = sched.get_thread_mut(server_tid) {
|
||||||
|
server.caller_tid = caller_tid;
|
||||||
|
server.ipc_buffer = FastPathMessage {
|
||||||
|
dest_cap: dest_ep,
|
||||||
|
opcode,
|
||||||
|
args,
|
||||||
|
};
|
||||||
|
server.state = ThreadState::Ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block caller on reply from server
|
||||||
|
if let Some(caller) = sched.get_thread_mut(caller_tid) {
|
||||||
|
caller.state = ThreadState::BlockedOnReply(server_tid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Direct context handoff to server
|
||||||
|
sched.schedule();
|
||||||
|
|
||||||
|
// When unblocked after reply, return results stored in caller's buffer
|
||||||
|
if let Some(caller) = sched.get_thread_mut(caller_tid) {
|
||||||
|
return Ok((caller.ipc_buffer.args[0], caller.ipc_buffer.args[1]));
|
||||||
|
}
|
||||||
|
Ok((0, 0))
|
||||||
|
} else {
|
||||||
|
// Receiver not waiting: Enqueue sender and block
|
||||||
|
if ep.send_count >= MAX_QUEUE_PER_EP {
|
||||||
|
return Err(-9); // SYS_ERR_BUSY
|
||||||
|
}
|
||||||
|
|
||||||
|
ep.send_queue[ep.send_count] = caller_tid;
|
||||||
|
ep.send_count += 1;
|
||||||
|
|
||||||
|
if let Some(caller) = sched.get_thread_mut(caller_tid) {
|
||||||
|
caller.ipc_buffer = FastPathMessage {
|
||||||
|
dest_cap: dest_ep,
|
||||||
|
opcode,
|
||||||
|
args,
|
||||||
|
};
|
||||||
|
caller.state = ThreadState::BlockedOnSend(dest_ep);
|
||||||
|
}
|
||||||
|
|
||||||
|
sched.schedule();
|
||||||
|
|
||||||
|
if let Some(caller) = sched.get_thread_mut(caller_tid) {
|
||||||
|
return Ok((caller.ipc_buffer.args[0], caller.ipc_buffer.args[1]));
|
||||||
|
}
|
||||||
|
Ok((0, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Server handles Reply to current caller and waits for Next Request
|
||||||
|
pub unsafe fn ipc_reply_recv(
|
||||||
|
&mut self,
|
||||||
|
listen_ep: u64,
|
||||||
|
reply_to_tid: u64,
|
||||||
|
reply_val0: u64,
|
||||||
|
reply_val1: u64,
|
||||||
|
server_tid: u64,
|
||||||
|
) -> Result<(u64, u64, u64, u64), i64> {
|
||||||
|
let ep = self.get_endpoint_mut(listen_ep).ok_or(-2i64)?;
|
||||||
|
let sched = &mut *core::ptr::addr_of_mut!(SCHEDULER);
|
||||||
|
|
||||||
|
// 1. Deliver reply to previous caller if requested
|
||||||
|
if reply_to_tid != 0 {
|
||||||
|
if let Some(caller) = sched.get_thread_mut(reply_to_tid) {
|
||||||
|
caller.ipc_buffer.args[0] = reply_val0;
|
||||||
|
caller.ipc_buffer.args[1] = reply_val1;
|
||||||
|
caller.state = ThreadState::Ready;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Check if a sender is already queued
|
||||||
|
if ep.send_count > 0 {
|
||||||
|
let next_sender_tid = ep.send_queue[0];
|
||||||
|
// Shift queue
|
||||||
|
for i in 0..(ep.send_count - 1) {
|
||||||
|
ep.send_queue[i] = ep.send_queue[i + 1];
|
||||||
|
}
|
||||||
|
ep.send_count -= 1;
|
||||||
|
|
||||||
|
let mut ret_opcode = 0;
|
||||||
|
let mut ret_arg0 = 0;
|
||||||
|
let mut ret_arg1 = 0;
|
||||||
|
|
||||||
|
if let Some(sender) = sched.get_thread_mut(next_sender_tid) {
|
||||||
|
ret_opcode = sender.ipc_buffer.opcode;
|
||||||
|
ret_arg0 = sender.ipc_buffer.args[0];
|
||||||
|
ret_arg1 = sender.ipc_buffer.args[1];
|
||||||
|
sender.state = ThreadState::BlockedOnReply(server_tid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(srv) = sched.get_thread_mut(server_tid) {
|
||||||
|
srv.caller_tid = next_sender_tid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok((next_sender_tid, ret_opcode, ret_arg0, ret_arg1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. No sender queued: block server on endpoint
|
||||||
|
ep.receiver_tid = server_tid;
|
||||||
|
if let Some(srv) = sched.get_thread_mut(server_tid) {
|
||||||
|
srv.state = ThreadState::BlockedOnRecv(listen_ep);
|
||||||
|
}
|
||||||
|
|
||||||
|
sched.schedule();
|
||||||
|
|
||||||
|
// Server woke up with incoming message delivered
|
||||||
|
if let Some(srv) = sched.get_thread_mut(server_tid) {
|
||||||
|
let sender_tid = srv.caller_tid;
|
||||||
|
let opcode = srv.ipc_buffer.opcode;
|
||||||
|
let a0 = srv.ipc_buffer.args[0];
|
||||||
|
let a1 = srv.ipc_buffer.args[1];
|
||||||
|
return Ok((sender_tid, opcode, a0, a1));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((0, 0, 0, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
unsafe {
|
||||||
|
(*core::ptr::addr_of_mut!(EP_MANAGER)).init();
|
||||||
|
kprintln!("[IPC] Synchronous Rendezvous Engine initialized ({} Endpoints).", MAX_ENDPOINTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
pub mod fastpath;
|
pub mod fastpath;
|
||||||
|
pub mod endpoint;
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
crate::kprintln!("[IPC] Capability-based Fast-Path IPC Ready.");
|
endpoint::init();
|
||||||
|
crate::kprintln!("[IPC] Capability-based Fast-Path & Rendezvous IPC Ready.");
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-27
@@ -11,26 +11,17 @@ pub mod loader;
|
|||||||
|
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
use limine_requests::*;
|
use limine_requests::*;
|
||||||
|
use sched::SCHEDULER;
|
||||||
|
|
||||||
// Include assembly trampolines directly into the binary
|
// Include assembly trampolines directly into the binary
|
||||||
core::arch::global_asm!(include_str!("../asm/context.S"));
|
core::arch::global_asm!(include_str!("../asm/context.S"));
|
||||||
core::arch::global_asm!(include_str!("../asm/syscall_entry.S"));
|
core::arch::global_asm!(include_str!("../asm/syscall_entry.S"));
|
||||||
core::arch::global_asm!(include_str!("../asm/ring3_enter.S"));
|
core::arch::global_asm!(include_str!("../asm/ring3_enter.S"));
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
fn enter_user_mode(
|
|
||||||
entry_rip: u64,
|
|
||||||
user_rsp: u64,
|
|
||||||
pml4_paddr: u64,
|
|
||||||
kernel_stack_top: u64,
|
|
||||||
) -> !;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn _start() -> ! {
|
pub extern "C" fn _start() -> ! {
|
||||||
// 1. Validate Limine Base Revision
|
// 1. Validate Limine Base Revision
|
||||||
if BASE_REVISION.revision != 3 {
|
if BASE_REVISION.revision != 3 {
|
||||||
// Revision mismatch
|
|
||||||
loop { core::hint::spin_loop(); }
|
loop { core::hint::spin_loop(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,29 +75,44 @@ pub extern "C" fn _start() -> ! {
|
|||||||
);
|
);
|
||||||
kprintln!("[TEST] IPC Fast-Path Ping Result: status={}, opcode={:#x}, val={}", status, resp_op, val);
|
kprintln!("[TEST] IPC Fast-Path Ping Result: status={}, opcode={:#x}, val={}", status, resp_op, val);
|
||||||
|
|
||||||
// 9. Inspect and Load Initial Userspace Process (Ring 3 Transition)
|
// 9. Inspect and Load Initial Userspace Processes
|
||||||
unsafe {
|
unsafe {
|
||||||
let mod_resp = MODULE_REQUEST.response;
|
let mod_resp = MODULE_REQUEST.response;
|
||||||
if !mod_resp.is_null() && (*mod_resp).module_count > 0 {
|
if !mod_resp.is_null() && (*mod_resp).module_count > 0 {
|
||||||
kprintln!("[BOOT] Loading root userspace module [0] into Ring 3...");
|
let count = (*mod_resp).module_count;
|
||||||
let mod_file = *(*mod_resp).modules;
|
kprintln!("[BOOT] Detected {} userspace boot modules. Creating tasks...", count);
|
||||||
let elf_slice = core::slice::from_raw_parts((*mod_file).address, (*mod_file).size as usize);
|
|
||||||
|
|
||||||
match loader::elf::load_elf(elf_slice, hhdm_offset) {
|
let sched_ptr = core::ptr::addr_of_mut!(SCHEDULER);
|
||||||
Ok(proc) => {
|
|
||||||
kprintln!("[BOOT] Transitioning CPU to Ring 3 (User Mode) via IRETQ...");
|
for i in 0..count {
|
||||||
kprintln!("-------------------------------------------------------");
|
let mod_file = *(*mod_resp).modules.add(i as usize);
|
||||||
enter_user_mode(
|
let elf_slice = core::slice::from_raw_parts((*mod_file).address, (*mod_file).size as usize);
|
||||||
proc.entry_rip,
|
let name = match i {
|
||||||
proc.user_rsp,
|
0 => "init_server",
|
||||||
proc.pml4_paddr,
|
1 => "uart_driver",
|
||||||
proc.kernel_stack_top,
|
_ => "user_server",
|
||||||
);
|
};
|
||||||
}
|
|
||||||
Err(err) => {
|
match loader::elf::load_elf(elf_slice, hhdm_offset) {
|
||||||
kprintln!("[ERROR] Failed to load ELF process: {}", err);
|
Ok(proc) => {
|
||||||
|
let tid = (*sched_ptr).create_user_thread(
|
||||||
|
name,
|
||||||
|
proc.entry_rip,
|
||||||
|
proc.user_rsp,
|
||||||
|
proc.pml4_paddr,
|
||||||
|
proc.kernel_stack_top,
|
||||||
|
);
|
||||||
|
kprintln!("[BOOT] Registered Thread '{}' with TID {:?}", name, tid);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
kprintln!("[ERROR] Failed to load module [{}]: {}", i, err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kprintln!("[BOOT] Starting Multi-Tasking & IPC Rendezvous...");
|
||||||
|
kprintln!("-------------------------------------------------------");
|
||||||
|
(*sched_ptr).schedule();
|
||||||
} else {
|
} else {
|
||||||
kprintln!("[BOOT] No userspace modules detected. Staying in Ring 0 idle loop.");
|
kprintln!("[BOOT] No userspace modules detected. Staying in Ring 0 idle loop.");
|
||||||
}
|
}
|
||||||
|
|||||||
+203
-26
@@ -1,35 +1,212 @@
|
|||||||
//! Minimal Thread & Task Scheduler Subsystem
|
//! Preemptive & Cooperative Microkernel Scheduler
|
||||||
|
|
||||||
#[repr(C)]
|
pub mod thread;
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum ThreadState {
|
use thread::{Thread, ThreadState, MAX_THREADS};
|
||||||
Ready,
|
use crate::arch::gdt::set_kernel_stack;
|
||||||
Running,
|
use crate::mm::vmm::VMM;
|
||||||
BlockedOnIpc,
|
use crate::kprintln;
|
||||||
Dead,
|
|
||||||
|
extern "C" {
|
||||||
|
fn switch_to(prev_rsp: *mut u64, next_rsp: u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
pub struct Scheduler {
|
||||||
pub struct ContextFrame {
|
pub threads: [Thread; MAX_THREADS],
|
||||||
pub r15: u64,
|
pub current_tid: usize,
|
||||||
pub r14: u64,
|
pub next_tid: u64,
|
||||||
pub r13: u64,
|
|
||||||
pub r12: u64,
|
|
||||||
pub rbx: u64,
|
|
||||||
pub rbp: u64,
|
|
||||||
pub rsp: u64,
|
|
||||||
pub rip: u64,
|
|
||||||
pub rflags: u64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Thread {
|
pub static mut SCHEDULER: Scheduler = Scheduler {
|
||||||
pub id: u64,
|
threads: [const { Thread::empty() }; MAX_THREADS],
|
||||||
pub state: ThreadState,
|
current_tid: 0,
|
||||||
pub rsp: u64,
|
next_tid: 1,
|
||||||
pub cr3: u64,
|
};
|
||||||
pub kernel_stack_top: u64,
|
|
||||||
|
impl Scheduler {
|
||||||
|
pub fn init(&mut self) {
|
||||||
|
// Slot 0 is reserved for Kernel Idle/Bootstrap thread
|
||||||
|
self.threads[0].id = 0;
|
||||||
|
self.threads[0].name = "kernel_idle";
|
||||||
|
self.threads[0].state = ThreadState::Running;
|
||||||
|
self.current_tid = 0;
|
||||||
|
self.next_tid = 1;
|
||||||
|
kprintln!("[SCHED] Scheduler initialized (Multi-Thread TCB table ready).");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_user_thread(
|
||||||
|
&mut self,
|
||||||
|
name: &'static str,
|
||||||
|
entry_rip: u64,
|
||||||
|
user_rsp: u64,
|
||||||
|
pml4_paddr: u64,
|
||||||
|
kernel_stack_top: u64,
|
||||||
|
) -> Option<u64> {
|
||||||
|
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::Ready;
|
||||||
|
self.threads[i].pml4_paddr = pml4_paddr;
|
||||||
|
self.threads[i].kernel_stack_top = kernel_stack_top;
|
||||||
|
self.threads[i].user_rsp = user_rsp;
|
||||||
|
self.threads[i].user_rip = entry_rip;
|
||||||
|
|
||||||
|
// Setup initial kernel stack for IRETQ return
|
||||||
|
unsafe {
|
||||||
|
let kstack = kernel_stack_top as *mut u64;
|
||||||
|
let stack_ptr = kstack.sub(16);
|
||||||
|
|
||||||
|
*stack_ptr.add(0) = 0; // r15
|
||||||
|
*stack_ptr.add(1) = 0; // r14
|
||||||
|
*stack_ptr.add(2) = 0; // r13
|
||||||
|
*stack_ptr.add(3) = 0; // r12
|
||||||
|
*stack_ptr.add(4) = 0; // rbx
|
||||||
|
*stack_ptr.add(5) = 0; // rbp
|
||||||
|
*stack_ptr.add(6) = initial_user_trampoline as *const () as usize as u64; // RIP for switch_to
|
||||||
|
|
||||||
|
self.threads[i].context.rsp = stack_ptr as u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
kprintln!("[SCHED] Created User Thread [TID {}] '{}' (RIP: {:#x}, RSP: {:#x})",
|
||||||
|
tid, name, entry_rip, user_rsp);
|
||||||
|
return Some(tid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_current_mut(&mut self) -> &mut Thread {
|
||||||
|
&mut self.threads[self.current_tid]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_thread_mut(&mut self, tid: u64) -> Option<&mut Thread> {
|
||||||
|
for t in self.threads.iter_mut() {
|
||||||
|
if t.id == tid && t.state != ThreadState::Unused {
|
||||||
|
return Some(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn block_current(&mut self, new_state: ThreadState) {
|
||||||
|
self.threads[self.current_tid].state = new_state;
|
||||||
|
self.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unblock(&mut self, tid: u64) {
|
||||||
|
if let Some(t) = self.get_thread_mut(tid) {
|
||||||
|
if t.state != ThreadState::Unused && t.state != ThreadState::Dead {
|
||||||
|
t.state = ThreadState::Ready;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn yield_current(&mut self) {
|
||||||
|
if self.threads[self.current_tid].state == ThreadState::Running {
|
||||||
|
self.threads[self.current_tid].state = ThreadState::Ready;
|
||||||
|
}
|
||||||
|
self.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn schedule(&mut self) {
|
||||||
|
let prev_idx = self.current_tid;
|
||||||
|
let mut next_idx = (prev_idx + 1) % MAX_THREADS;
|
||||||
|
|
||||||
|
// Find next Ready thread (Round-Robin)
|
||||||
|
let mut found = false;
|
||||||
|
for _ in 0..MAX_THREADS {
|
||||||
|
if self.threads[next_idx].state == ThreadState::Ready {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next_idx = (next_idx + 1) % MAX_THREADS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
if self.threads[prev_idx].state == ThreadState::Running {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
next_idx = 0; // idle thread
|
||||||
|
}
|
||||||
|
|
||||||
|
if prev_idx == next_idx && self.threads[prev_idx].state == ThreadState::Running {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.threads[prev_idx].state == ThreadState::Running {
|
||||||
|
self.threads[prev_idx].state = ThreadState::Ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.current_tid = next_idx;
|
||||||
|
self.threads[next_idx].state = ThreadState::Running;
|
||||||
|
|
||||||
|
let next_pml4 = self.threads[next_idx].pml4_paddr;
|
||||||
|
let next_kstack = self.threads[next_idx].kernel_stack_top;
|
||||||
|
let next_rsp = self.threads[next_idx].context.rsp;
|
||||||
|
let prev_rsp_ptr = core::ptr::addr_of_mut!(self.threads[prev_idx].context.rsp);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if next_pml4 != 0 {
|
||||||
|
(*core::ptr::addr_of_mut!(VMM)).load_cr3(next_pml4);
|
||||||
|
}
|
||||||
|
if next_kstack != 0 {
|
||||||
|
set_kernel_stack(next_kstack);
|
||||||
|
}
|
||||||
|
switch_to(prev_rsp_ptr, next_rsp);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
crate::kprintln!("[SCHED] Scheduler initialized (Round-Robin preemptive stub).");
|
unsafe {
|
||||||
|
(*core::ptr::addr_of_mut!(SCHEDULER)).init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn initial_user_trampoline() {
|
||||||
|
let (entry_rip, user_rsp) = unsafe {
|
||||||
|
let sched = &mut *core::ptr::addr_of_mut!(SCHEDULER);
|
||||||
|
let curr = sched.get_current_mut();
|
||||||
|
(curr.user_rip, curr.user_rsp)
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// IRETQ to Ring 3
|
||||||
|
core::arch::asm!(
|
||||||
|
"mov ax, 0x1B",
|
||||||
|
"mov ds, ax",
|
||||||
|
"mov es, ax",
|
||||||
|
"mov fs, ax",
|
||||||
|
"mov gs, ax",
|
||||||
|
"push 0x1B", // User SS
|
||||||
|
"push {user_rsp}", // User RSP
|
||||||
|
"push 0x0202", // RFLAGS (IF enabled)
|
||||||
|
"push 0x23", // User CS
|
||||||
|
"push {entry_rip}", // User RIP
|
||||||
|
"xor rax, rax",
|
||||||
|
"xor rbx, rbx",
|
||||||
|
"xor rcx, rcx",
|
||||||
|
"xor rdx, rdx",
|
||||||
|
"xor rsi, rsi",
|
||||||
|
"xor rdi, rdi",
|
||||||
|
"xor rbp, rbp",
|
||||||
|
"xor r8, r8",
|
||||||
|
"xor r9, r9",
|
||||||
|
"xor r10, r10",
|
||||||
|
"xor r11, r11",
|
||||||
|
"xor r12, r12",
|
||||||
|
"xor r13, r13",
|
||||||
|
"xor r14, r14",
|
||||||
|
"xor r15, r15",
|
||||||
|
"iretq",
|
||||||
|
user_rsp = in(reg) user_rsp,
|
||||||
|
entry_rip = in(reg) entry_rip,
|
||||||
|
options(noreturn)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
//! Thread Control Block (TCB) & Context Definition
|
||||||
|
|
||||||
|
use crate::ipc::fastpath::FastPathMessage;
|
||||||
|
|
||||||
|
pub const MAX_THREADS: usize = 16;
|
||||||
|
pub const KERNEL_STACK_SIZE: usize = 16384; // 16 KiB
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum ThreadState {
|
||||||
|
Unused,
|
||||||
|
Ready,
|
||||||
|
Running,
|
||||||
|
BlockedOnSend(u64), // Waiting on destination endpoint ID
|
||||||
|
BlockedOnRecv(u64), // Waiting for messages on endpoint ID
|
||||||
|
BlockedOnReply(u64), // Client waiting for specific server TID reply
|
||||||
|
Dead,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct SavedContext {
|
||||||
|
pub r15: u64,
|
||||||
|
pub r14: u64,
|
||||||
|
pub r13: u64,
|
||||||
|
pub r12: u64,
|
||||||
|
pub rbx: u64,
|
||||||
|
pub rbp: u64,
|
||||||
|
pub rsp: u64, // Saved kernel RSP
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SavedContext {
|
||||||
|
pub const fn empty() -> Self {
|
||||||
|
Self {
|
||||||
|
r15: 0,
|
||||||
|
r14: 0,
|
||||||
|
r13: 0,
|
||||||
|
r12: 0,
|
||||||
|
rbx: 0,
|
||||||
|
rbp: 0,
|
||||||
|
rsp: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Thread {
|
||||||
|
pub id: u64,
|
||||||
|
pub name: &'static str,
|
||||||
|
pub state: ThreadState,
|
||||||
|
pub context: SavedContext,
|
||||||
|
pub pml4_paddr: u64,
|
||||||
|
pub kernel_stack_base: u64,
|
||||||
|
pub kernel_stack_top: u64,
|
||||||
|
pub user_rsp: u64,
|
||||||
|
pub user_rip: u64,
|
||||||
|
pub ipc_buffer: FastPathMessage,
|
||||||
|
pub caller_tid: u64, // TID of client waiting for reply
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Thread {
|
||||||
|
pub const fn empty() -> Self {
|
||||||
|
Self {
|
||||||
|
id: 0,
|
||||||
|
name: "",
|
||||||
|
state: ThreadState::Unused,
|
||||||
|
context: SavedContext::empty(),
|
||||||
|
pml4_paddr: 0,
|
||||||
|
kernel_stack_base: 0,
|
||||||
|
kernel_stack_top: 0,
|
||||||
|
user_rsp: 0,
|
||||||
|
user_rip: 0,
|
||||||
|
ipc_buffer: FastPathMessage {
|
||||||
|
dest_cap: 0,
|
||||||
|
opcode: 0,
|
||||||
|
args: [0; 4],
|
||||||
|
},
|
||||||
|
caller_tid: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,13 @@ struct FastResponse {
|
|||||||
uint64_t out1;
|
uint64_t out1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct IncomingRequest {
|
||||||
|
uint64_t sender_tid;
|
||||||
|
uint64_t opcode;
|
||||||
|
uint64_t arg0;
|
||||||
|
uint64_t arg1;
|
||||||
|
};
|
||||||
|
|
||||||
// RAII Capability Handle
|
// RAII Capability Handle
|
||||||
class Capability {
|
class Capability {
|
||||||
private:
|
private:
|
||||||
@@ -56,7 +63,7 @@ public:
|
|||||||
[[nodiscard]] constexpr bool is_valid() const noexcept { return handle_ != CAP_NULL; }
|
[[nodiscard]] constexpr bool is_valid() const noexcept { return handle_ != CAP_NULL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// RAII IPC Endpoint Wrapper
|
// RAII IPC Client Endpoint Wrapper
|
||||||
class Endpoint {
|
class Endpoint {
|
||||||
private:
|
private:
|
||||||
Capability cap_;
|
Capability cap_;
|
||||||
@@ -82,6 +89,36 @@ public:
|
|||||||
[[nodiscard]] cap_t raw_handle() const noexcept { return cap_.get(); }
|
[[nodiscard]] cap_t raw_handle() const noexcept { return cap_.get(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// RAII IPC Server Endpoint Wrapper
|
||||||
|
class ServerEndpoint {
|
||||||
|
private:
|
||||||
|
Capability cap_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ServerEndpoint(Capability&& cap) noexcept : cap_(static_cast<Capability&&>(cap)) {}
|
||||||
|
explicit ServerEndpoint(cap_t cap) noexcept : cap_(cap) {}
|
||||||
|
|
||||||
|
// Server main loop: Reply to previous sender and wait for next request
|
||||||
|
[[nodiscard]] Result<IncomingRequest> reply_and_recv(
|
||||||
|
uint64_t reply_to_tid = 0,
|
||||||
|
uint64_t reply_val0 = 0,
|
||||||
|
uint64_t reply_val1 = 0
|
||||||
|
) const noexcept {
|
||||||
|
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(cap_.get(), reply_to_tid, reply_val0, reply_val1,
|
||||||
|
&sender_tid, &opcode, &arg0, &arg1);
|
||||||
|
return Result<IncomingRequest>{
|
||||||
|
.status = ret,
|
||||||
|
.value = { sender_tid, opcode, arg0, arg1 }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] cap_t raw_handle() const noexcept { return cap_.get(); }
|
||||||
|
};
|
||||||
|
|
||||||
// RAII Shared Memory Buffer
|
// RAII Shared Memory Buffer
|
||||||
class SharedBuffer {
|
class SharedBuffer {
|
||||||
private:
|
private:
|
||||||
|
|||||||
+20
-15
@@ -2,29 +2,34 @@
|
|||||||
#include "stdio.h"
|
#include "stdio.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
|
||||||
|
#define UART_SERVICE_ENDPOINT 2
|
||||||
|
|
||||||
extern "C" void _start() {
|
extern "C" void _start() {
|
||||||
puts("[INIT-SERVER] Userspace Root Init Server Started (Ring 3)!");
|
puts("[INIT-SERVER] Userspace Root Init Server Started (Ring 3)!");
|
||||||
|
|
||||||
// 1. Instantiate RAII IPC Endpoint for Kernel Control
|
// 1. Communicate with Kernel Control (Endpoint 1)
|
||||||
ipc::Endpoint kernel_ctrl(CAP_SELF_TASK);
|
ipc::Endpoint kernel_ctrl(CAP_KERNEL_CONTROL);
|
||||||
|
puts("[INIT-SERVER] Sending Fast-Path IPC Ping to Microkernel (CAP 1)...");
|
||||||
|
auto kping = kernel_ctrl.call(IPC_OP_PING, 777);
|
||||||
|
if (kping.is_ok()) {
|
||||||
|
puts("[INIT-SERVER] Received Pong from Microkernel!");
|
||||||
|
}
|
||||||
|
|
||||||
puts("[INIT-SERVER] Sending Fast-Path IPC Ping to Microkernel...");
|
// 2. Communicate with UART Driver Service (Endpoint 2) via Rendezvous IPC
|
||||||
auto ping_res = kernel_ctrl.call(IPC_OP_PING, 100);
|
ipc::Endpoint uart_service(UART_SERVICE_ENDPOINT);
|
||||||
|
puts("[INIT-SERVER] Sending Synchronous Rendezvous IPC to UART Driver (Endpoint 2)...");
|
||||||
|
|
||||||
if (ping_res.is_ok()) {
|
// Pack 4 characters 'O', 'K', '!', '\n' into 32-bit arg0
|
||||||
puts("[INIT-SERVER] Received IPC Ping Response from Microkernel!");
|
uint64_t msg_chars = 'O' | ('K' << 8) | ('!' << 16) | ('\n' << 24);
|
||||||
|
auto uart_res = uart_service.call(IPC_OP_WRITE, msg_chars);
|
||||||
|
|
||||||
|
if (uart_res.is_ok()) {
|
||||||
|
puts("[INIT-SERVER] Rendezvous IPC Call to UART Driver SUCCEEDED!");
|
||||||
} else {
|
} else {
|
||||||
puts("[INIT-SERVER] IPC Call Failed!");
|
puts("[INIT-SERVER] Rendezvous IPC Call failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Register Server Endpoint
|
puts("[INIT-SERVER] Root Init Server running. Entering worker loop.");
|
||||||
puts("[INIT-SERVER] Registering Root Server Capability...");
|
|
||||||
auto reg_res = kernel_ctrl.call(IPC_OP_REGISTER_SERVER, 0x1337BEEF);
|
|
||||||
if (reg_res.is_ok()) {
|
|
||||||
puts("[INIT-SERVER] Server Registered Successfully!");
|
|
||||||
}
|
|
||||||
|
|
||||||
puts("[INIT-SERVER] Root Init Server ready. Entering event loop.");
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
sys_yield();
|
sys_yield();
|
||||||
|
|||||||
@@ -1,17 +1,63 @@
|
|||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
#include "stdio.h"
|
#include "stdio.h"
|
||||||
#include "abi/syscalls.h"
|
#include "abi/syscalls.h"
|
||||||
|
#include "abi/ipc.h"
|
||||||
|
|
||||||
|
#define UART_SERVICE_ENDPOINT 2
|
||||||
|
|
||||||
extern void _start(void) {
|
extern void _start(void) {
|
||||||
uart_init(UART_COM1_PORT, 115200);
|
uart_init(UART_COM1_PORT, 115200);
|
||||||
uart_puts(UART_COM1_PORT, "[RING3-UART-DRIVER] 16550 UART COM1 initialized from userspace!\n");
|
puts("[UART-DRIVER] 16550 UART Server started in Ring 3. Listening for IPC requests...");
|
||||||
|
|
||||||
|
uint64_t last_client = 0;
|
||||||
|
uint64_t reply_val0 = 0;
|
||||||
|
uint64_t reply_val1 = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (uart_has_data(UART_COM1_PORT)) {
|
uint64_t sender_tid = 0;
|
||||||
char c = uart_getc(UART_COM1_PORT);
|
uint64_t opcode = 0;
|
||||||
// Echo back
|
uint64_t arg0 = 0;
|
||||||
uart_putc(UART_COM1_PORT, c);
|
uint64_t arg1 = 0;
|
||||||
|
|
||||||
|
// Block and wait for next client IPC request, replying to last client if any
|
||||||
|
sysret_t ret = sys_ipc_reply_recv_raw(
|
||||||
|
UART_SERVICE_ENDPOINT,
|
||||||
|
last_client,
|
||||||
|
reply_val0,
|
||||||
|
reply_val1,
|
||||||
|
&sender_tid,
|
||||||
|
&opcode,
|
||||||
|
&arg0,
|
||||||
|
&arg1
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ret == 0 && sender_tid != 0) {
|
||||||
|
last_client = sender_tid;
|
||||||
|
|
||||||
|
if (opcode == IPC_OP_WRITE) {
|
||||||
|
// Write received characters to UART hardware
|
||||||
|
char c0 = (char)(arg0 & 0xFF);
|
||||||
|
char c1 = (char)((arg0 >> 8) & 0xFF);
|
||||||
|
char c2 = (char)((arg0 >> 16) & 0xFF);
|
||||||
|
char c3 = (char)((arg0 >> 24) & 0xFF);
|
||||||
|
|
||||||
|
if (c0) uart_putc(UART_COM1_PORT, c0);
|
||||||
|
if (c1) uart_putc(UART_COM1_PORT, c1);
|
||||||
|
if (c2) uart_putc(UART_COM1_PORT, c2);
|
||||||
|
if (c3) uart_putc(UART_COM1_PORT, c3);
|
||||||
|
|
||||||
|
reply_val0 = 0; // Success
|
||||||
|
reply_val1 = 4; // Bytes written
|
||||||
|
} else if (opcode == IPC_OP_PING) {
|
||||||
|
reply_val0 = IPC_OP_PONG;
|
||||||
|
reply_val1 = arg0 + 1;
|
||||||
|
} else {
|
||||||
|
reply_val0 = (uint64_t)-1;
|
||||||
|
reply_val1 = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
last_client = 0;
|
||||||
|
sys_yield();
|
||||||
}
|
}
|
||||||
sys_yield();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user