feat(kernel): implement SMP multi-core affinity, ACPI subsystem, hardware RNG (RDRAND), and Ring 3 signal fault isolation
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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::<AcpiHeader>() {
|
||||
return;
|
||||
}
|
||||
|
||||
let entries_bytes = length - core::mem::size_of::<AcpiHeader>();
|
||||
let entry_count = entries_bytes / 4;
|
||||
let entries_ptr = (header as *const u8).add(core::mem::size_of::<AcpiHeader>()) 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));
|
||||
}
|
||||
+35
-3
@@ -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)); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
+26
-5
@@ -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).");
|
||||
|
||||
+69
-17
@@ -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,
|
||||
|
||||
@@ -4,3 +4,4 @@ pub mod keyboard;
|
||||
pub mod rtc;
|
||||
pub mod dmesg;
|
||||
pub mod mouse;
|
||||
pub mod rng;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
+57
-21
@@ -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();
|
||||
|
||||
@@ -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<usize>, // 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user