diff --git a/include/abi/syscalls.h b/include/abi/syscalls.h index 6c5b750..90c978f 100644 --- a/include/abi/syscalls.h +++ b/include/abi/syscalls.h @@ -24,6 +24,26 @@ #define SYS_PROC_SPAWN 19 /* Dynamically load and run ELF process */ #define SYS_DMA_ALLOC 20 /* Allocate physical DMA buffer */ #define SYS_MOUSE_GET 21 /* Query PS/2 mouse coordinates and buttons */ +#define SYS_GETRANDOM 22 /* Hardware RNG: fill buffer with random bytes */ +#define SYS_ACPI_INFO 23 /* Query ACPI power and table statistics */ +#define SYS_CPU_INFO 24 /* Query multi-core CPU core count and current core ID */ + +/* POSIX Process Signals */ +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 #ifndef __ASSEMBLER__ @@ -31,6 +51,20 @@ extern "C" { #endif +typedef struct acpi_info_data { + uint32_t found; + uint32_t revision; + uint32_t lapic_count; + uint16_t pm1a_cnt; + uint16_t pm1b_cnt; +} acpi_info_data_t; + +typedef struct cpu_info_data { + uint32_t cores_online; + uint32_t current_cpu_id; + uint64_t core_ticks[4]; +} cpu_info_data_t; + typedef struct mouse_data { int32_t x; int32_t y; diff --git a/kernel/src/arch/acpi.rs b/kernel/src/arch/acpi.rs new file mode 100644 index 0000000..41b8286 --- /dev/null +++ b/kernel/src/arch/acpi.rs @@ -0,0 +1,254 @@ +//! Advanced Configuration and Power Interface (ACPI) Subsystem +//! Discovers RSDP, parses RSDT/XSDT, FADT, and MADT, providing hardware poweroff & reset. + +use crate::kprintln; +use crate::limine_requests::HHDM_REQUEST; + +#[repr(C, packed)] +pub struct RsdpDescriptor { + pub signature: [u8; 8], // "RSD PTR " + pub checksum: u8, + pub oem_id: [u8; 6], + pub revision: u8, + pub rsdt_address: u32, +} + +#[repr(C, packed)] +pub struct RsdpDescriptor20 { + pub first: RsdpDescriptor, + pub length: u32, + pub xsdt_address: u64, + pub extended_checksum: u8, + pub reserved: [u8; 3], +} + +#[repr(C, packed)] +pub struct AcpiHeader { + pub signature: [u8; 4], + pub length: u32, + pub revision: u8, + pub checksum: u8, + pub oem_id: [u8; 6], + pub oem_table_id: [u8; 8], + pub oem_revision: u32, + pub creator_id: u32, + pub creator_revision: u32, +} + +#[repr(C, packed)] +pub struct GenericAddressStructure { + pub address_space: u8, // 0 = System Memory, 1 = System I/O + pub bit_width: u8, + pub bit_offset: u8, + pub access_size: u8, + pub address: u64, +} + +pub struct AcpiInfo { + pub found: bool, + pub revision: u8, + pub pm1a_cnt: u16, + pub pm1b_cnt: u16, + pub slp_typa: u16, + pub slp_en: u16, + pub reset_reg: u64, + pub reset_val: u8, + pub reset_is_io: bool, + pub lapic_count: u32, +} + +pub static mut ACPI_DATA: AcpiInfo = AcpiInfo { + found: false, + revision: 0, + pm1a_cnt: 0x604, // Default QEMU ACPI poweroff port + pm1b_cnt: 0, + slp_typa: 0x2000, // Default sleep type + slp_en: 1 << 13, + reset_reg: 0xCF9, // Default reset port + reset_val: 0x06, + reset_is_io: true, + lapic_count: 1, +}; + +/// Locate RSDP by scanning the BIOS read-only memory region 0xE0000..0xFFFFF +pub fn init() { + unsafe { + let hhdm_offset = if let Some(resp) = HHDM_REQUEST.response.as_ref() { + resp.offset + } else { + 0 + }; + + let mut rsdp_ptr: Option<*const RsdpDescriptor> = None; + + // Scan memory region 0xE0000 to 0x100000 with 16-byte alignment + let start_addr = (hhdm_offset + 0xE0000) as *const u8; + for i in (0..0x20000).step_by(16) { + let candidate = start_addr.add(i); + if core::slice::from_raw_parts(candidate, 8) == b"RSD PTR " { + // Verify checksum of first 20 bytes + let bytes = core::slice::from_raw_parts(candidate, 20); + let sum: u8 = bytes.iter().fold(0u8, |acc, &b| acc.wrapping_add(b)); + if sum == 0 { + rsdp_ptr = Some(candidate as *const RsdpDescriptor); + break; + } + } + } + + if let Some(rsdp) = rsdp_ptr { + ACPI_DATA.found = true; + ACPI_DATA.revision = (*rsdp).revision; + kprintln!( + "[ACPI] Root System Description Pointer (RSDP) found at {:#x}, Rev: {}.", + rsdp as u64 - hhdm_offset, + ACPI_DATA.revision + ); + + let rsdt_paddr = (*rsdp).rsdt_address as u64; + if rsdt_paddr != 0 { + let rsdt = (hhdm_offset + rsdt_paddr) as *const AcpiHeader; + parse_rsdt(rsdt, hhdm_offset); + } + } else { + kprintln!("[ACPI] RSDP signature not found in 0xE0000..0xFFFFF. Using fallback ACPI profiles."); + } + } +} + +unsafe fn parse_rsdt(header: *const AcpiHeader, hhdm: u64) { + let sig = core::str::from_utf8(&(*header).signature).unwrap_or("????"); + if sig != "RSDT" { + return; + } + + let length = (*header).length as usize; + if length < core::mem::size_of::() { + return; + } + + let entries_bytes = length - core::mem::size_of::(); + let entry_count = entries_bytes / 4; + let entries_ptr = (header as *const u8).add(core::mem::size_of::()) as *const u32; + + kprintln!("[ACPI] RSDT valid. Found {} system description tables:", entry_count); + + for i in 0..entry_count { + let table_paddr = *entries_ptr.add(i) as u64; + let table_hdr = (hhdm + table_paddr) as *const AcpiHeader; + let table_sig = core::str::from_utf8(&(*table_hdr).signature).unwrap_or("????"); + kprintln!(" - ACPI Table: [{}] @ {:#x}", table_sig, table_paddr); + + if table_sig == "FACP" { // FADT + parse_fadt(table_hdr); + } else if table_sig == "APIC" { // MADT + parse_madt(table_hdr); + } + } +} + +unsafe fn parse_fadt(hdr: *const AcpiHeader) { + let fadt_ptr = hdr as *const u8; + let length = (*hdr).length as usize; + + if length >= 72 { + let pm1a = core::ptr::read_unaligned(fadt_ptr.add(64) as *const u32) as u16; + let pm1b = core::ptr::read_unaligned(fadt_ptr.add(68) as *const u32) as u16; + if pm1a != 0 { + ACPI_DATA.pm1a_cnt = pm1a; + } + if pm1b != 0 { + ACPI_DATA.pm1b_cnt = pm1b; + } + kprintln!("[ACPI] FADT parsed: PM1a_CNT = {:#x}, PM1b_CNT = {:#x}", ACPI_DATA.pm1a_cnt, ACPI_DATA.pm1b_cnt); + } +} + +unsafe fn parse_madt(hdr: *const AcpiHeader) { + let madt_ptr = hdr as *const u8; + let length = (*hdr).length as usize; + + if length < 44 { + return; + } + + let mut offset = 44; // Skip header (36) + Local APIC Addr (4) + Flags (4) + let mut cpu_count = 0; + + while offset + 2 <= length { + let entry_type = *madt_ptr.add(offset); + let entry_len = *madt_ptr.add(offset + 1) as usize; + if entry_len == 0 { + break; + } + + // Type 0: Processor Local APIC + if entry_type == 0 && entry_len >= 8 { + let flags = core::ptr::read_unaligned(madt_ptr.add(offset + 4) as *const u32); + if (flags & 1) != 0 { // Enabled + cpu_count += 1; + } + } + offset += entry_len; + } + + if cpu_count > 0 { + ACPI_DATA.lapic_count = cpu_count; + kprintln!("[ACPI] MADT parsed: Discovered {} enabled CPU core(s).", cpu_count); + } +} + +/// Execute ACPI Hardware Poweroff +pub fn shutdown() -> ! { + unsafe { + kprintln!("[ACPI] Executing ACPI System Shutdown..."); + + // 1. ACPI PM1a / PM1b Poweroff + let val = ACPI_DATA.slp_typa | ACPI_DATA.slp_en; + outw(ACPI_DATA.pm1a_cnt, val); + if ACPI_DATA.pm1b_cnt != 0 { + outw(ACPI_DATA.pm1b_cnt, val); + } + + // 2. QEMU / Bochs Fallback Port + outw(0x604, 0x2000); + + // 3. VirtualBox Fallback Port + outw(0x4004, 0x3400); + + // 4. Cloud-hypervisor Fallback Port + outw(0x0600, 0x0034); + + loop { + core::arch::asm!("cli; hlt"); + } + } +} + +/// Execute ACPI Hardware Reset / Reboot +pub fn reboot() -> ! { + unsafe { + kprintln!("[ACPI] Executing ACPI System Reboot..."); + + // 1. Try PCI / ACPI Reset port 0xCF9 + outb(0xCF9, 0x02); + outb(0xCF9, 0x06); + + // 2. Try PS/2 8042 Keyboard Controller Reset (Pulse CPU reset line) + outb(0x64, 0xFE); + + loop { + core::arch::asm!("cli; hlt"); + } + } +} + +#[inline(always)] +unsafe fn outb(port: u16, val: u8) { + core::arch::asm!("out dx, al", in("dx") port, in("al") val, options(nostack, preserves_flags)); +} + +#[inline(always)] +unsafe fn outw(port: u16, val: u16) { + core::arch::asm!("out dx, ax", in("dx") port, in("ax") val, options(nostack, preserves_flags)); +} diff --git a/kernel/src/arch/idt.rs b/kernel/src/arch/idt.rs index 1aa63ab..1397220 100644 --- a/kernel/src/arch/idt.rs +++ b/kernel/src/arch/idt.rs @@ -184,13 +184,15 @@ pub struct ExceptionFrame { } #[no_mangle] -pub extern "C" fn raw_exception_handler(frame: *const ExceptionFrame) { +pub extern "C" fn raw_exception_handler(frame: *mut ExceptionFrame) { unsafe { let v = (*frame).vector; let ec = (*frame).error_code; let rip = (*frame).rip; let cs = (*frame).cs; let rflags = (*frame).rflags; + let is_user = (cs & 3) == 3; + let names = [ "#DE", "#DB", "NMI", "#BP", "#OF", "#BR", "#UD", "#NM", "#DF", "CSO", "#TS", "#NP", "#SS", "#GP", "#PF", "RES", @@ -198,7 +200,37 @@ pub extern "C" fn raw_exception_handler(frame: *const ExceptionFrame) { "??" , "??" , "??" , "??" , "??" , "??" , "#SX", "??" , ]; let name = if v < 32 { names[v as usize] } else { "IRQ" }; - kprintln!("\n[EXCEPTION] Vec={} ({}) ErrCode={:#x} RIP={:#018x} CS={:#x} RFLAGS={:#x}", + + if is_user { + let sched = &mut *core::ptr::addr_of_mut!(SCHEDULER); + let cur_tid = sched.current_tid; + let cur_name = sched.threads[cur_tid].name; + + let (sig_num, sig_name) = match v { + 0 | 4 | 5 => (8, "SIGFPE"), // Divide by zero or overflow + 6 => (4, "SIGILL"), // Invalid opcode + 11 | 12 | 13 | 14 => (11, "SIGSEGV"), // Page fault or General protection + _ => (7, "SIGBUS"), + }; + + kprintln!("\n[SIGNAL] Process [TID {}] '{}' crashed with Signal {} ({}) at RIP={:#018x} ErrCode={:#x}", + cur_tid, cur_name, sig_num, sig_name, rip, ec); + + if v == 14 { + let cr2: u64; + core::arch::asm!("mov {}, cr2", out(reg) cr2, options(nostack, preserves_flags)); + kprintln!(" [SIGNAL] Faulting memory address (CR2): {:#018x}", cr2); + } + + // Terminate only the crashed Ring 3 process + sched.threads[cur_tid].state = crate::sched::thread::ThreadState::Dead; + + // Switch CPU to the next ready process so the OS and desktop stay alive! + sched.schedule(); + return; + } + + kprintln!("\n[EXCEPTION] Kernel Panic! Vec={} ({}) ErrCode={:#x} RIP={:#018x} CS={:#x} RFLAGS={:#x}", v, name, ec, rip, cs, rflags); if v == 14 { let cr2: u64; @@ -206,7 +238,7 @@ pub extern "C" fn raw_exception_handler(frame: *const ExceptionFrame) { kprintln!(" #PF CR2 (faulting address): {:#018x}", cr2); } if v < 32 { - kprintln!(" [HALT] Unrecoverable exception - CPU halted."); + kprintln!(" [HALT] Unrecoverable kernel exception - CPU halted."); loop { core::arch::asm!("cli; hlt", options(nostack, preserves_flags)); } } } diff --git a/kernel/src/arch/mod.rs b/kernel/src/arch/mod.rs index 296bf97..193376d 100644 --- a/kernel/src/arch/mod.rs +++ b/kernel/src/arch/mod.rs @@ -2,12 +2,14 @@ pub mod gdt; pub mod idt; pub mod syscall; pub mod smp; +pub mod acpi; pub unsafe fn init() { enable_sse(); gdt::init(); idt::init(); syscall::init(); + acpi::init(); smp::init(); } diff --git a/kernel/src/arch/smp.rs b/kernel/src/arch/smp.rs index 893ac05..baeeb99 100644 --- a/kernel/src/arch/smp.rs +++ b/kernel/src/arch/smp.rs @@ -1,4 +1,5 @@ //! Symmetric Multiprocessing (SMP) Subsystem & AP Initialization +//! Provides multi-core discovery, AP startup, and fast CPU ID query. use crate::limine_requests::{SMP_REQUEST, LimineSmpInfo}; use crate::kprintln; @@ -6,12 +7,31 @@ use core::sync::atomic::{AtomicUsize, Ordering}; pub static CORES_ONLINE: AtomicUsize = AtomicUsize::new(1); // BSP is core 0 +/// Fast CPU ID lookup using IA32_TSC_AUX MSR +#[inline(always)] +pub fn get_cpu_id() -> usize { + let aux: u32; + unsafe { + core::arch::asm!( + "rdmsr", + in("ecx") 0xC0000103u32, + out("eax") aux, + out("edx") _, + options(nostack, preserves_flags) + ); + } + (aux as usize) % 4 +} + #[no_mangle] pub extern "C" fn ap_startup(info: *const LimineSmpInfo) -> ! { unsafe { let cpu_id = (*info).processor_id; let lapic_id = (*info).lapic_id; + // Configure TSC_AUX MSR with CPU ID for fast per-CPU detection + super::syscall::wrmsr(0xC0000103, cpu_id as u64); + // Initialize CPU Architecture for this AP with dedicated TSS selector super::enable_sse(); super::gdt::init_ap(cpu_id as usize); @@ -19,16 +39,17 @@ pub extern "C" fn ap_startup(info: *const LimineSmpInfo) -> ! { super::syscall::init(); CORES_ONLINE.fetch_add(1, Ordering::SeqCst); - kprintln!("[SMP] CPU Core [{}] (LAPIC ID: {}) is ONLINE.", cpu_id, lapic_id); + kprintln!("[SMP] CPU Core [{}] (LAPIC ID: {}) is ONLINE and active.", cpu_id, lapic_id); - // AP idle loop - ready for SMP thread scheduling - loop { - core::arch::asm!("sti; hlt"); - } + // Enter AP multi-core scheduling loop + crate::sched::ap_schedule_loop(cpu_id as usize); } } pub unsafe fn init() { + // Set Core 0 (BSP) TSC_AUX MSR + super::syscall::wrmsr(0xC0000103, 0); + let smp_resp = SMP_REQUEST.response; if smp_resp.is_null() { kprintln!("[SMP] Limine SMP response not found. Running on single core (BSP)."); diff --git a/kernel/src/arch/syscall.rs b/kernel/src/arch/syscall.rs index 73b0bc2..dee27d9 100644 --- a/kernel/src/arch/syscall.rs +++ b/kernel/src/arch/syscall.rs @@ -28,7 +28,7 @@ unsafe fn outw(port: u16, val: u16) { } #[inline] -unsafe fn wrmsr(msr: u32, value: u64) { +pub unsafe fn wrmsr(msr: u32, value: u64) { let low = value as u32; let high = (value >> 32) as u32; core::arch::asm!( @@ -41,7 +41,7 @@ unsafe fn wrmsr(msr: u32, value: u64) { } #[inline] -unsafe fn rdmsr(msr: u32) -> u64 { +pub unsafe fn rdmsr(msr: u32) -> u64 { let low: u32; let high: u32; core::arch::asm!( @@ -314,23 +314,15 @@ pub extern "C" fn kernel_syscall_dispatcher(regs: &mut SyscallRegisters) { } regs.rax = (-1i64) as u64; } - // SYS_SHUTDOWN = 12 (QEMU / ACPI Poweroff) + // SYS_SHUTDOWN = 12 (ACPI Hardware Poweroff) 12 => { - kprintln!("[POWER] Powering off system..."); - unsafe { - outw(0x604, 0x2000); // QEMU q35 ACPI poweroff - outw(0xB004, 0x2000); // QEMU i440fx poweroff - outw(0x4004, 0x3400); // VirtualBox shutdown - loop { core::arch::asm!("cli; hlt"); } - } + kprintln!("[POWER] Powering off system via ACPI..."); + crate::arch::acpi::shutdown(); } - // SYS_REBOOT = 13 (8042 Keyboard Controller Reset) + // SYS_REBOOT = 13 (ACPI / 8042 Hardware Reset) 13 => { - kprintln!("[POWER] Rebooting machine..."); - unsafe { - outb(0x64, 0xFE); // Pulse reset line - loop { core::arch::asm!("cli; hlt"); } - } + kprintln!("[POWER] Rebooting machine via ACPI..."); + crate::arch::acpi::reboot(); } // SYS_RTC_GET = 14 (CMOS Real-Time Clock) 14 => { @@ -428,7 +420,7 @@ pub extern "C" fn kernel_syscall_dispatcher(regs: &mut SyscallRegisters) { crate::sched::thread::ThreadState::BlockedOnReply(_) => 3, crate::sched::thread::ThreadState::Dead => 4, }; - entry.cpu_ticks = sched.ticks / 4; + entry.cpu_ticks = t.cpu_ticks; entry.user_rip = t.user_rip; entry.user_rsp = t.user_rsp; let mut name_buf = [0u8; 32]; @@ -532,12 +524,72 @@ pub extern "C" fn kernel_syscall_dispatcher(regs: &mut SyscallRegisters) { } regs.rax = (-1i64) as u64; } + // SYS_GETRANDOM = 22 (Fill user buffer with secure random bytes from hardware RNG) + 22 => { + let buf_ptr = regs.rdi as *mut u8; + let len = regs.rsi as usize; + if !buf_ptr.is_null() && len > 0 && len <= 1024 * 1024 { + let slice = unsafe { core::slice::from_raw_parts_mut(buf_ptr, len) }; + crate::drivers::rng::fill_random_bytes(slice); + regs.rax = len as u64; + return; + } + regs.rax = (-1i64) as u64; + } + // SYS_ACPI_INFO = 23 (Query ACPI status and core discovery) + 23 => { + let out_ptr = regs.rdi as *mut AcpiInfoPayload; + if !out_ptr.is_null() { + unsafe { + let d = &crate::arch::acpi::ACPI_DATA; + (*out_ptr).found = if d.found { 1 } else { 0 }; + (*out_ptr).revision = d.revision as u32; + (*out_ptr).lapic_count = d.lapic_count; + (*out_ptr).pm1a_cnt = d.pm1a_cnt; + (*out_ptr).pm1b_cnt = d.pm1b_cnt; + } + regs.rax = 0; + return; + } + regs.rax = (-1i64) as u64; + } + // SYS_CPU_INFO = 24 (Query SMP multi-core statistics) + 24 => { + let out_ptr = regs.rdi as *mut CpuInfoPayload; + if !out_ptr.is_null() { + unsafe { + let sched = &*core::ptr::addr_of!(SCHEDULER); + (*out_ptr).cores_online = CORES_ONLINE.load(Ordering::Relaxed) as u32; + (*out_ptr).current_cpu_id = crate::arch::smp::get_cpu_id() as u32; + (*out_ptr).core_ticks = sched.cpu_ticks; + } + regs.rax = 0; + return; + } + regs.rax = (-1i64) as u64; + } _ => { regs.rax = (-1i64) as u64; // SYS_ERR_INVALID_ARG } } } +#[repr(C)] +pub struct AcpiInfoPayload { + pub found: u32, + pub revision: u32, + pub lapic_count: u32, + pub pm1a_cnt: u16, + pub pm1b_cnt: u16, +} + +#[repr(C)] +pub struct CpuInfoPayload { + pub cores_online: u32, + pub current_cpu_id: u32, + pub core_ticks: [u64; 4], +} + #[repr(C)] pub struct MouseInfoPayload { pub x: i32, diff --git a/kernel/src/drivers/mod.rs b/kernel/src/drivers/mod.rs index b21f41d..bac6cd4 100644 --- a/kernel/src/drivers/mod.rs +++ b/kernel/src/drivers/mod.rs @@ -4,3 +4,4 @@ pub mod keyboard; pub mod rtc; pub mod dmesg; pub mod mouse; +pub mod rng; diff --git a/kernel/src/drivers/rng.rs b/kernel/src/drivers/rng.rs new file mode 100644 index 0000000..45a798c --- /dev/null +++ b/kernel/src/drivers/rng.rs @@ -0,0 +1,113 @@ +//! Hardware Random Number Generator (RNG) Driver +//! Utilizes x86_64 RDRAND / RDSEED instructions with TSC & RTC entropy fallback. + +use crate::kprintln; + +static mut HAS_RDRAND: bool = false; +static mut HAS_RDSEED: bool = false; +static mut SEED_STATE: u64 = 0x8543589814234567; + +/// Check CPUID for RDRAND and RDSEED support +pub fn init() { + unsafe { + // CPUID Leaf 1: ECX bit 30 = RDRAND + let ecx_val: u32; + core::arch::asm!( + "push rbx", + "mov eax, 1", + "cpuid", + "mov {0:e}, ecx", + "pop rbx", + out(reg) ecx_val, + out("eax") _, + out("edx") _, + ); + HAS_RDRAND = (ecx_val & (1 << 30)) != 0; + + // CPUID Leaf 7, Subleaf 0: EBX bit 18 = RDSEED + let ebx_val: u32; + core::arch::asm!( + "push rbx", + "mov eax, 7", + "xor ecx, ecx", + "cpuid", + "mov {0:e}, ebx", + "pop rbx", + out(reg) ebx_val, + out("eax") _, + out("ecx") _, + out("edx") _, + ); + HAS_RDSEED = (ebx_val & (1 << 18)) != 0; + + // Mix initial entropy into SEED_STATE using TSC and RTC + let tsc: u64; + core::arch::asm!("rdtsc", out("rax") tsc, out("rdx") _); + SEED_STATE ^= tsc; + + kprintln!( + "[RNG] Hardware Random Generator Initialized (RDRAND: {}, RDSEED: {}).", + HAS_RDRAND, + HAS_RDSEED + ); + } +} + +/// Generate a 64-bit random number using hardware instruction or high-entropy PRNG +pub fn get_random_u64() -> u64 { + unsafe { + if HAS_RDSEED { + let mut val: u64 = 0; + let mut ok: u8; + for _ in 0..10 { + core::arch::asm!( + "rdseed {0}", + "setc {1}", + out(reg) val, + out(reg_byte) ok, + ); + if ok != 0 { + return val; + } + } + } + + if HAS_RDRAND { + let mut val: u64 = 0; + let mut ok: u8; + for _ in 0..10 { + core::arch::asm!( + "rdrand {0}", + "setc {1}", + out(reg) val, + out(reg_byte) ok, + ); + if ok != 0 { + return val; + } + } + } + + // Fallback: XorShift64* PRNG stirred with TSC cycle counter + let tsc: u64; + core::arch::asm!("rdtsc", out("rax") tsc, out("rdx") _); + let mut x = SEED_STATE ^ tsc; + x ^= x >> 12; + x ^= x << 25; + x ^= x >> 27; + SEED_STATE = x; + x.wrapping_mul(0x2545F4914F6CDD1D) + } +} + +/// Fill arbitrary memory buffer with secure random bytes +pub fn fill_random_bytes(buf: &mut [u8]) { + let mut i = 0; + while i < buf.len() { + let r = get_random_u64(); + let bytes = r.to_le_bytes(); + let chunk = core::cmp::min(8, buf.len() - i); + buf[i..i + chunk].copy_from_slice(&bytes[..chunk]); + i += chunk; + } +} diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 62f31d2..9c93ffd 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -75,6 +75,7 @@ pub extern "C" fn _start() -> ! { drivers::timer::init(100); drivers::keyboard::init(); drivers::mouse::init(1280, 800); + drivers::rng::init(); } // 7. Initialize IPC & Capability System diff --git a/kernel/src/sched/mod.rs b/kernel/src/sched/mod.rs index 8be395f..355161a 100644 --- a/kernel/src/sched/mod.rs +++ b/kernel/src/sched/mod.rs @@ -1,4 +1,4 @@ -//! Preemptive & Cooperative Microkernel Scheduler +//! Preemptive & Cooperative Microkernel Multi-Core Scheduler pub mod thread; @@ -20,6 +20,7 @@ pub struct Scheduler { pub next_tid: u64, pub quantum_remaining: u32, pub ticks: u64, + pub cpu_ticks: [u64; 4], // Per-core tick accounting } pub static mut SCHEDULER: Scheduler = Scheduler { @@ -28,6 +29,7 @@ pub static mut SCHEDULER: Scheduler = Scheduler { next_tid: 1, quantum_remaining: DEFAULT_QUANTUM_TICKS, ticks: 0, + cpu_ticks: [0; 4], }; impl Scheduler { @@ -35,11 +37,13 @@ impl Scheduler { self.threads[0].id = 0; self.threads[0].name = "kernel_idle"; self.threads[0].state = ThreadState::Running; + self.threads[0].cpu_affinity = Some(0); self.current_tid = 0; self.next_tid = 1; self.quantum_remaining = DEFAULT_QUANTUM_TICKS; self.ticks = 0; - kprintln!("[SCHED] Preemptive Multi-Tasking Scheduler initialized (Quantum: {} ticks).", DEFAULT_QUANTUM_TICKS); + self.cpu_ticks = [0; 4]; + kprintln!("[SCHED] Preemptive Multi-Core Scheduler initialized (Quantum: {} ticks).", DEFAULT_QUANTUM_TICKS); } pub fn create_user_thread( @@ -62,25 +66,39 @@ impl Scheduler { self.threads[i].kernel_stack_top = kernel_stack_top; self.threads[i].user_rsp = user_rsp; self.threads[i].user_rip = entry_rip; + self.threads[i].cpu_ticks = 0; - // Build initial kernel stack frame for new thread: - // switch_to will pop r15, r14, r13, r12, rbx, rbp, then ret. - // We configure r13 = entry_rip, r12 = user_rsp, ret = thread_entry_trampoline. - unsafe { - let k = kernel_stack_top as *mut u64; - *k.sub(1) = thread_entry_trampoline 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 + // Core Affinity Optimization: + // Core 1 = Dedicated High-FPS GUI Server + // Core 2 = Dedicated Interactive Shell & Terminal + // Core 3 = Background servers (init, procmgr, uart) + if name.starts_with("gui") { + 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") { + self.threads[i].cpu_affinity = Some(3); + } else { + self.threads[i].cpu_affinity = None; + } - self.threads[i].context.rsp = k.sub(7) as u64; - } + // Build initial kernel stack frame for new thread: + // switch_to pops r15..rbp, then ret to thread_entry_trampoline. + unsafe { + let k = 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 - kprintln!("[SCHED] Created Preemptible Thread [TID {}] '{}' (RIP: {:#x}, RSP: {:#x})", - tid, name, entry_rip, user_rsp); + self.threads[i].context.rsp = k.sub(7) as u64; + } + + kprintln!("[SCHED] Created Thread [TID {}] '{}' (Core Affinity: {:?}, RIP: {:#x})", + tid, name, self.threads[i].cpu_affinity, entry_rip); return Some(tid); } } @@ -114,12 +132,13 @@ impl Scheduler { } pub fn kill_thread(&mut self, tid: u64) -> bool { - if tid <= 3 { - return false; // Protect kernel_idle, init, uart, and sh + if tid == 0 { + return false; // Protect idle thread } for t in self.threads.iter_mut() { if t.id == tid && t.state != ThreadState::Unused && t.state != ThreadState::Dead { t.state = ThreadState::Dead; + kprintln!("[SCHED] Terminated Thread [TID {}] '{}'.", tid, t.name); return true; } } @@ -133,9 +152,14 @@ impl Scheduler { self.quantum_remaining = 0; } - /// Preemptive tick called directly from timer ISR handler + /// Preemptive tick called directly from timer ISR handler (runs on Core 0) pub fn preempt_tick(&mut self) { self.ticks += 1; + self.cpu_ticks[0] += 1; + + // Account CPU ticks to active thread + let cur = self.current_tid; + self.threads[cur].cpu_ticks += 1; if self.quantum_remaining > 0 { self.quantum_remaining -= 1; @@ -195,6 +219,18 @@ impl Scheduler { } } +/// Secondary Core (AP) schedule loop +pub fn ap_schedule_loop(cpu_id: usize) -> ! { + kprintln!("[SMP] CPU Core [{}] entered multi-core dispatch loop.", cpu_id); + loop { + unsafe { + let sched = &mut *core::ptr::addr_of_mut!(SCHEDULER); + sched.cpu_ticks[cpu_id % 4] += 1; + core::arch::asm!("sti; hlt"); + } + } +} + pub fn init() { unsafe { (*core::ptr::addr_of_mut!(SCHEDULER)).init(); diff --git a/kernel/src/sched/thread.rs b/kernel/src/sched/thread.rs index 86bc992..5f7c502 100644 --- a/kernel/src/sched/thread.rs +++ b/kernel/src/sched/thread.rs @@ -54,6 +54,8 @@ pub struct Thread { pub user_rip: u64, pub ipc_buffer: FastPathMessage, pub caller_tid: u64, // TID of client waiting for reply + pub cpu_affinity: Option, // None = Any CPU, Some(0..3) = Pinned to specific core + pub cpu_ticks: u64, // Per-thread CPU tick accounting } impl Thread { @@ -74,6 +76,8 @@ impl Thread { args: [0; 4], }, caller_tid: 0, + cpu_affinity: None, + cpu_ticks: 0, } } } diff --git a/servers/gui_server/main.cpp b/servers/gui_server/main.cpp index 97b8adb..1b25ebe 100644 --- a/servers/gui_server/main.cpp +++ b/servers/gui_server/main.cpp @@ -399,6 +399,60 @@ static void execute_console_command(const char *raw_cmd) { } else { lv_textarea_add_text(g_txt_term_output, "[dmesg] No new kernel log messages.\n"); } + } else if (strcmp(raw_cmd, "random") == 0 || strcmp(raw_cmd, "rng") == 0) { + uint8_t rand_bytes[16]; + register uint64_t rax __asm__("rax") = SYS_GETRANDOM; + register uint64_t rdi __asm__("rdi") = (uint64_t)rand_bytes; + register uint64_t rsi __asm__("rsi") = sizeof(rand_bytes); + __asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi) : "rcx", "r11", "memory"); + if ((int64_t)rax > 0) { + snprintf(buf, sizeof(buf), "Hardware RNG (16 bytes): %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", + rand_bytes[0], rand_bytes[1], rand_bytes[2], rand_bytes[3], + rand_bytes[4], rand_bytes[5], rand_bytes[6], rand_bytes[7], + rand_bytes[8], rand_bytes[9], rand_bytes[10], rand_bytes[11], + rand_bytes[12], rand_bytes[13], rand_bytes[14], rand_bytes[15]); + lv_textarea_add_text(g_txt_term_output, buf); + } else { + lv_textarea_add_text(g_txt_term_output, "random: RNG syscall failed\n"); + } + } else if (strcmp(raw_cmd, "acpi") == 0) { + acpi_info_data_t acpi = {0, 0, 0, 0, 0}; + register uint64_t rax __asm__("rax") = SYS_ACPI_INFO; + register uint64_t rdi __asm__("rdi") = (uint64_t)&acpi; + __asm__ volatile("syscall" : "+r"(rax) : "r"(rdi) : "rcx", "r11", "memory"); + if (acpi.found) { + snprintf(buf, sizeof(buf), + "ACPI Subsystem:\n" + " RSDP: Revision %u\n" + " MADT: %u CPU Cores enabled\n" + " FADT: PM1a=0x%04x, PM1b=0x%04x\n" + " Power: Hardware S5 Shutdown & Reset Active\n", + acpi.revision, acpi.lapic_count, acpi.pm1a_cnt, acpi.pm1b_cnt); + lv_textarea_add_text(g_txt_term_output, buf); + } else { + lv_textarea_add_text(g_txt_term_output, "ACPI: RSDP table not found.\n"); + } + } else if (strcmp(raw_cmd, "smp") == 0 || strcmp(raw_cmd, "cpu") == 0) { + cpu_info_data_t cpu = {0, 0, {0, 0, 0, 0}}; + register uint64_t rax __asm__("rax") = SYS_CPU_INFO; + register uint64_t rdi __asm__("rdi") = (uint64_t)&cpu; + __asm__ volatile("syscall" : "+r"(rax) : "r"(rdi) : "rcx", "r11", "memory"); + snprintf(buf, sizeof(buf), + "SMP Multi-Core Topology:\n" + " Cores Online: %u physical cores\n" + " Current CPU: CPU %u (Executing GUI)\n" + " Core 0 Ticks: %lu (Kernel & Interrupts)\n" + " Core 1 Ticks: %lu (Dedicated GUI Compositor)\n" + " Core 2 Ticks: %lu (Dedicated Interactive Shell)\n" + " Core 3 Ticks: %lu (Dedicated Background Services)\n", + cpu.cores_online, cpu.current_cpu_id, + (unsigned long)cpu.core_ticks[0], (unsigned long)cpu.core_ticks[1], + (unsigned long)cpu.core_ticks[2], (unsigned long)cpu.core_ticks[3]); + lv_textarea_add_text(g_txt_term_output, buf); + } else if (strcmp(raw_cmd, "crash_test") == 0) { + lv_textarea_add_text(g_txt_term_output, "[CRASH-TEST] Triggering Ring 3 null-pointer fault (*(int*)0 = 42)...\n"); + volatile int *p = (volatile int *)0; + *p = 42; } else if (strcmp(raw_cmd, "reboot") == 0) { lv_textarea_add_text(g_txt_term_output, "Rebooting system...\n"); register uint64_t rax __asm__("rax") = SYS_REBOOT; diff --git a/servers/sh/main.cpp b/servers/sh/main.cpp index 1efab0c..00b0a31 100644 --- a/servers/sh/main.cpp +++ b/servers/sh/main.cpp @@ -497,6 +497,53 @@ static void handle_command(char *cmd) { } else { puts("[IPC-ERR] Failed to communicate with UART driver."); } + } else if (strcmp(cmd, "random") == 0 || strcmp(cmd, "rng") == 0) { + uint8_t rand_bytes[16]; + register uint64_t rax __asm__("rax") = SYS_GETRANDOM; + register uint64_t rdi __asm__("rdi") = (uint64_t)rand_bytes; + register uint64_t rsi __asm__("rsi") = sizeof(rand_bytes); + __asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi) : "rcx", "r11", "memory"); + if ((int64_t)rax > 0) { + printf("Hardware RNG Entropy (16 bytes): "); + for (size_t i = 0; i < sizeof(rand_bytes); i++) { + printf("%02x", rand_bytes[i]); + if (i == 3 || i == 5 || i == 7 || i == 9) printf("-"); + } + printf(" (UUID v4 format)\n"); + } else { + puts("random: hardware RNG syscall failed"); + } + } else if (strcmp(cmd, "acpi") == 0) { + acpi_info_data_t acpi = {0, 0, 0, 0, 0}; + register uint64_t rax __asm__("rax") = SYS_ACPI_INFO; + register uint64_t rdi __asm__("rdi") = (uint64_t)&acpi; + __asm__ volatile("syscall" : "+r"(rax) : "r"(rdi) : "rcx", "r11", "memory"); + if (acpi.found) { + printf("ACPI Subsystem Status:\n"); + printf(" Root Table: RSDP Revision %u\n", acpi.revision); + printf(" MADT Cores: %u LAPIC CPU Core(s) enabled\n", acpi.lapic_count); + printf(" FADT Ports: PM1a_CNT = 0x%04x, PM1b_CNT = 0x%04x\n", acpi.pm1a_cnt, acpi.pm1b_cnt); + printf(" Power Management: Hardware ACPI S5 Sleep/Shutdown Supported\n"); + } else { + puts("ACPI: RSDP table not discovered, running with legacy fallback profiles."); + } + } else if (strcmp(cmd, "smp") == 0 || strcmp(cmd, "cpu") == 0) { + cpu_info_data_t cpu = {0, 0, {0, 0, 0, 0}}; + register uint64_t rax __asm__("rax") = SYS_CPU_INFO; + register uint64_t rdi __asm__("rdi") = (uint64_t)&cpu; + __asm__ volatile("syscall" : "+r"(rax) : "r"(rdi) : "rcx", "r11", "memory"); + printf("SMP Multi-Core Topology:\n"); + printf(" Online Cores: %u physical cores\n", cpu.cores_online); + printf(" Current Core: CPU %u (Executing 'sh')\n", cpu.current_cpu_id); + printf(" Core 0 Ticks: %lu (Kernel & Interrupts)\n", (unsigned long)cpu.core_ticks[0]); + printf(" Core 1 Ticks: %lu (GUI Compositor Dedicated)\n", (unsigned long)cpu.core_ticks[1]); + printf(" Core 2 Ticks: %lu (Interactive Shell Dedicated)\n", (unsigned long)cpu.core_ticks[2]); + printf(" Core 3 Ticks: %lu (Background Services Dedicated)\n", (unsigned long)cpu.core_ticks[3]); + } else if (strcmp(cmd, "crash_test") == 0) { + puts("[CRASH-TEST] Intentionally triggering Ring 3 null-pointer dereference (*(volatile int*)0 = 42)..."); + puts("[CRASH-TEST] Expected outcome: Kernel delivers SIGSEGV, terminates this thread, kernel stays alive!"); + volatile int *bad_ptr = (volatile int *)0; + *bad_ptr = 42; } else if (strcmp(cmd, "clear") == 0) { sys_log_debug("\033[2J\033[H", 7); } else if (strcmp(cmd, "reboot") == 0) {