// K1400 development probe. The kernel copies bounded name bytes between two // EL0 processes and supplies the client's authenticated ProcessId. use super::*; use turkos_kernel::runtime::process_table::{Outcome, ProcessId}; use turkos_kernel::runtime::syscall_abi as abi; static mut OS_K1400_REQUEST: Option<(usize, u64, ProcessId)> = None; static mut OS_K1400_BYTES: [u8; 24] = [0; 24]; static mut OS_K1400_REPLIED: bool = false; static mut OS_K1400_RESPONSE: u64 = 0; static mut OS_K1400_COUNT: u64 = 0; static mut OS_K1400_CANARY: [u8; 16] = *b"DISCOVERY-GUARD!"; fn count() -> u64 { unsafe { read_volatile(core::ptr::addr_of!(OS_K1400_COUNT)) } } fn request() -> Option<(usize, u64, ProcessId)> { unsafe { read_volatile(core::ptr::addr_of!(OS_K1400_REQUEST)) } } pub(super) fn begin() { unsafe { write_volatile(core::ptr::addr_of_mut!(OS_K1400_REQUEST), None); write_volatile(core::ptr::addr_of_mut!(OS_K1400_BYTES), [0; 24]); write_volatile(core::ptr::addr_of_mut!(OS_K1400_REPLIED), false); write_volatile(core::ptr::addr_of_mut!(OS_K1400_RESPONSE), 0); write_volatile(core::ptr::addr_of_mut!(OS_K1400_COUNT), 0); write_volatile(core::ptr::addr_of_mut!(OS_K1400_CANARY), *b"DISCOVERY-GUARD!"); write_volatile(core::ptr::addr_of_mut!(OS_K1380_SAVED_FRAME), os_k920_exception::Frame::EMPTY); write_volatile(core::ptr::addr_of_mut!(OS_K1380_SAVED_VALID), false); write_volatile(core::ptr::addr_of_mut!(OS_K1380_SUSPENDED), false); } } pub(super) fn finish() -> Result<(), &'static str> { if count() != 4 || request().is_some() || unsafe { read_volatile(core::ptr::addr_of!(OS_K1400_REPLIED)) } || unsafe { read_volatile(core::ptr::addr_of!(OS_K1380_SAVED_VALID)) } || unsafe { read_volatile(core::ptr::addr_of!(OS_K1380_SUSPENDED)) } || unsafe { read_volatile(core::ptr::addr_of!(OS_K1400_CANARY)) } != *b"DISCOVERY-GUARD!" { return Err("discovery-incomplete-or-state-corrupt"); } Ok(()) } pub(super) fn dispatch(episode: &mut OsK1215AEl0Episode, frame: &mut os_k920_exception::Frame, table: &mut OsK1105Table<'_>) -> u64 { if frame.elr < episode.launch.user_pc || frame.elr >= episode.launch.user_pc + 4096 || !frame.elr.is_multiple_of(4) { park(); } let pid = episode.pid; if frame.x[7] == 3 { match frame.x[8] { 210 => { if episode.case != 0 || episode.calls != 1 || frame.x[0] != 0 || frame.x[1] != 0 || pid.slot() >= u32::MAX as usize { park(); } frame.x[0] = pid.slot() as u64 + 1; frame.x[1] = pid.generation().checked_add(1) .unwrap_or_else(|| park()); } 220 => { let length = frame.x[1] as usize; let namespace = frame.x[2]; if episode.case != 1 || episode.calls != 1 || request().is_some() || count() > 3 || length != [7, 4, 5, 7][count() as usize] || namespace != [0, 0, 1, 1][count() as usize] || frame.x[0] == 0 { park(); } let before = table.snapshot(); let resources = table.record(pid).unwrap_or_else(|_| park()).resources; let bytes = unsafe { &mut *core::ptr::addr_of_mut!(OS_K1400_BYTES) }; table.copy_current_user_data(pid, frame.x[0], &mut bytes[..length]) .unwrap_or_else(|_| park()); if table.snapshot() != before || table.record(pid).map(|r| r.resources) != Ok(resources) || unsafe { read_volatile(core::ptr::addr_of!(OS_K1400_CANARY)) } != *b"DISCOVERY-GUARD!" { park(); } unsafe { write_volatile(core::ptr::addr_of_mut!(OS_K1400_REQUEST), Some((length, namespace, pid))); write_volatile(core::ptr::addr_of_mut!(OS_K1380_SAVED_FRAME), *frame); (*core::ptr::addr_of_mut!(OS_K1380_SAVED_FRAME)).x[0] = 0; write_volatile(core::ptr::addr_of_mut!(OS_K1380_SAVED_VALID), true); } if unsafe { table.release_actual_current_to_ready() }.is_err() { park(); } unsafe { write_volatile(core::ptr::addr_of_mut!(OS_K1380_SUSPENDED), true); } write_line("TURKOS/OS/K1400D-TRACE: CLIENT-QUERY-YIELDED"); return 1; } 221 => { if episode.case != 0 || episode.calls != 1 || frame.x[1] < 24 || unsafe { read_volatile(core::ptr::addr_of!(OS_K1400_REPLIED)) } { park(); } let (length, namespace, caller) = request().unwrap_or_else(|| park()); if table.record(caller).map(|r| r.parent) != Ok(Some(pid)) || caller.slot() >= u32::MAX as usize { park(); } let bytes = unsafe { &*core::ptr::addr_of!(OS_K1400_BYTES) }; table.write_current_user_data(pid, frame.x[0], &bytes[..length]) .unwrap_or_else(|_| park()); frame.x[0] = length as u64; frame.x[1] = namespace; frame.x[2] = caller.slot() as u64 + 1; frame.x[3] = caller.generation().checked_add(1) .unwrap_or_else(|| park()); if count() == 0 { write_line("TURKOS/OS/K1400D-TRACE: AUTHENTICATED-PRINCIPAL"); } } 222 => { if episode.case != 0 || episode.calls != 1 || frame.x[1] != 0 || unsafe { read_volatile(core::ptr::addr_of!(OS_K1400_REPLIED)) } || request().is_none() || frame.x[0] != [0x71, 0x92, u64::MAX, u64::MAX][count() as usize] { park(); } unsafe { write_volatile(core::ptr::addr_of_mut!(OS_K1400_RESPONSE), frame.x[0]); write_volatile(core::ptr::addr_of_mut!(OS_K1400_REPLIED), true); } frame.x[0] = 0; match count() { 0 => write_line("TURKOS/OS/K1400D-TRACE: PUBLIC-CONSOLE-FOUND"), 1 => write_line("TURKOS/OS/K1400D-TRACE: PUBLIC-FILE-FOUND"), 2 => write_line("TURKOS/OS/K1400D-TRACE: MANAGEMENT-HIDDEN"), 3 => write_line("TURKOS/OS/K1400D-TRACE: UNKNOWN-SAME-RESPONSE"), _ => park(), } } 223 => { if episode.case != 1 || episode.calls != 1 || !unsafe { read_volatile(core::ptr::addr_of!(OS_K1400_REPLIED)) } || request().map(|(_, _, caller)| caller) != Some(pid) { park(); } frame.x[0] = unsafe { read_volatile(core::ptr::addr_of!(OS_K1400_RESPONSE)) }; unsafe { write_volatile(core::ptr::addr_of_mut!(OS_K1400_REQUEST), None); write_volatile(core::ptr::addr_of_mut!(OS_K1400_REPLIED), false); write_volatile(core::ptr::addr_of_mut!(OS_K1400_COUNT), count() + 1); } } _ => frame.x[0] = abi::AbiResult::Err(abi::Errno::NoSys).encode(), } return 0; } if frame.x[7] == 2 && frame.x[8] == 3 { let request = turkos_os_user_runtime_abi::decode( frame.x[7], frame.x[8], core::array::from_fn(|i| frame.x[i])) .unwrap_or_else(|_| park()); let turkos_os_user_runtime_abi::Request::Exit(code) = request else { park(); }; if episode.case == 0 { if code != 0 || episode.calls != 2 || count() != 4 { park(); } } else if code != 42 || episode.calls != 1 || count() != 4 { park(); } table.exit_current(code).unwrap_or_else(|_| park()); let outcome = Outcome::Exited(code); if table.record(pid).map(|r| r.outcome) != Ok(Some(outcome)) { park(); } episode.outcome = Some(outcome); return 1; } if frame.x[7] != abi::ABI_VERSION { park(); } let mut abi_frame = turkos_os_exceptions::exceptions::Frame::EMPTY; abi_frame.x = frame.x; let call = abi::decode_call(&abi_frame).unwrap_or_else(|_| park()); if call == abi::Call::Role { if episode.calls != 0 { park(); } episode.calls = 1; frame.x[0] = episode.case as u64; return 0; } if let abi::Call::RunChild(1) = call { if episode.case != 0 || episode.calls == 0 || episode.calls > 2 || count() > 4 || request().is_some() && !unsafe { read_volatile(core::ptr::addr_of!(OS_K1400_REPLIED)) } { park(); } return os_k1215a_run_child(episode as *mut _, frame as *mut _, episode.launch.kernel_root); } park() }