// K1300 development-only read-only EL0 process metadata and monotonic clock. use super::*; pub(super) fn dispatch( episode: &mut OsK1215AEl0Episode, frame: &mut os_k920_exception::Frame, table: &mut OsK1105Table<'_>, ) -> u64 { use turkos_kernel::runtime::process_table as process; use turkos_kernel::runtime::process_threads::State; use turkos_kernel::runtime::syscall_abi as abi; if frame.elr < episode.launch.user_pc || frame.elr >= episode.launch.user_pc + 4096 || !frame.elr.is_multiple_of(4) { park(); } if frame.x[7] == 3 { if episode.case != 1 { park(); } match frame.x[8] { 13 => { if frame.x[0] != 0xffff_0000_0000_1000 || episode.ps_denied || episode.ps_fd != 0 { park(); } let before = table.snapshot(); frame.x[0] = abi::AbiResult::Err(abi::Errno::Access).encode(); if table.snapshot() != before { park(); } episode.ps_denied = true; write_line("TURKOS/OS/K1300P-TRACE: FOREIGN-ADDRESS-EACCES-NO-OWNER"); 0 } 14 => { if !episode.ps_denied || episode.ps_fd != 0 || episode.ps_closed || table.snapshot().published != 3 || table.snapshot().zombies != 0 { park(); } episode.ps_fd = 0x1300_0001; frame.x[0] = episode.ps_fd; write_line("TURKOS/OS/K1300P-TRACE: SNAPSHOT-OPEN-THREE"); 0 } 15 => { if episode.ps_fd == 0 || frame.x[0] != episode.ps_fd || frame.x[2] != 32 || episode.ps_eof { park(); } let mut wire = [0u8; 32]; if table.copy_current_user_data(episode.pid, frame.x[1], &mut wire) .is_err() { frame.x[0] = abi::AbiResult::Err(abi::Errno::Fault).encode(); return 0; } if episode.ps_cursor == 3 { episode.ps_eof = true; frame.x[0] = 0; write_line("TURKOS/OS/K1300P-TRACE: SNAPSHOT-EOF"); return 0; } let pid = table.published().nth(episode.ps_cursor) .unwrap_or_else(|| park()); if pid.slot() != episode.ps_cursor || pid.slot() >= 4 { park(); } let record = table.record(pid).unwrap_or_else(|_| park()); let state = match record.resources.state { State::Ready => 0u32, State::Running => 1u32, State::Sleeping => 2u32, State::Dead => 3u32, _ => park(), }; let slot = u32::try_from(pid.slot() + 1).unwrap_or_else(|_| park()); let generation = u32::try_from(pid.generation()) .unwrap_or_else(|_| park()); let (parent_slot, parent_generation) = match record.parent { Some(parent) => ( u32::try_from(parent.slot() + 1).unwrap_or_else(|_| park()), u32::try_from(parent.generation()).unwrap_or_else(|_| park())), None => (0, 0), }; let birth = unsafe { read_volatile(core::ptr::addr_of!(OS_K1300_BIRTHS) .cast::().add(pid.slot())) }; let age = os_k960_counter().checked_sub(birth) .filter(|value| birth != 0 && *value > 0) .unwrap_or_else(|| park()); wire = [0; 32]; wire[..4].copy_from_slice(&slot.to_le_bytes()); wire[4..8].copy_from_slice(&generation.to_le_bytes()); wire[8..12].copy_from_slice(&parent_slot.to_le_bytes()); wire[12..16].copy_from_slice(&parent_generation.to_le_bytes()); wire[16..20].copy_from_slice(&state.to_le_bytes()); wire[24..32].copy_from_slice(&age.to_le_bytes()); episode.ps_outputs[episode.ps_cursor][..8] .copy_from_slice(&wire[..8]); episode.ps_outputs[episode.ps_cursor][8..] .copy_from_slice(&wire[24..32]); table.write_current_user_data(episode.pid, frame.x[1], &wire) .unwrap_or_else(|_| park()); episode.ps_cursor += 1; frame.x[0] = 1; write_str("TURKOS/OS/K1300P-TRACE: ROW SLOT=0x"); write_hex(slot as usize); write_str(" GEN=0x"); write_hex(generation as usize); write_str(" PARENT=0x"); write_hex(parent_slot as usize); write_str(" STATE=0x"); write_hex(state as usize); write_str(" AGE=0x"); write_hex(age as usize); write_line(""); 0 } 16 => { if !episode.ps_closed || episode.ps_fd != 0 || episode.ps_clock_reads >= 2 || frame.x[1] != 24 { park(); } let mut wire = [0u8; 24]; if table.copy_current_user_data(episode.pid, frame.x[0], &mut wire) .is_err() { frame.x[0] = abi::AbiResult::Err(abi::Errno::Fault).encode(); return 0; } let boot = unsafe { read_volatile(core::ptr::addr_of!(OS_K680_EVIDENCE) .cast::()) }; let start = unsafe { read_volatile(core::ptr::addr_of!(OS_K1300_BOOT_COUNTER)) }; let ticks = os_k960_counter().checked_sub(start) .filter(|value| start != 0 && *value > 0) .unwrap_or_else(|| park()); let frequency = os_k960_frequency(); if boot == 0 || frequency == 0 || ticks < episode.ps_last_ticks { park(); } wire[..8].copy_from_slice(&boot.to_le_bytes()); wire[8..16].copy_from_slice(&ticks.to_le_bytes()); wire[16..24].copy_from_slice(&frequency.to_le_bytes()); if episode.ps_clock_reads == 1 { let seconds = ticks / frequency; let nanos = (u128::from(ticks % frequency) * 1_000_000_000 / u128::from(frequency)) as u32; episode.ps_outputs[3][..8] .copy_from_slice(&seconds.to_le_bytes()); episode.ps_outputs[3][8..12] .copy_from_slice(&nanos.to_le_bytes()); } table.write_current_user_data(episode.pid, frame.x[0], &wire) .unwrap_or_else(|_| park()); episode.ps_last_ticks = ticks; episode.ps_clock_reads += 1; frame.x[0] = 0; write_str("TURKOS/OS/K1300P-TRACE: UPTIME BOOT=0x"); write_hex(boot as usize); write_str(" TICKS=0x"); write_hex(ticks as usize); write_str(" FREQ=0x"); write_hex(frequency as usize); write_line(""); 0 } 17 => { if episode.ps_fd == 0 || frame.x[0] != episode.ps_fd || !episode.ps_eof || episode.ps_cursor != 3 { park(); } episode.ps_fd = 0; episode.ps_closed = true; frame.x[0] = 0; write_line("TURKOS/OS/K1300P-TRACE: SNAPSHOT-CLOSED"); 0 } _ => { frame.x[0] = abi::AbiResult::Err(abi::Errno::NoSys).encode(); 0 } } } else 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 { park(); } } else if code != 42 || episode.calls != 1 || !episode.ps_denied || !episode.ps_eof || !episode.ps_closed || episode.ps_fd != 0 || episode.ps_cursor != 3 || episode.ps_clock_reads != 2 || episode.ps_write_calls != 4 { park(); } table.exit_current(code).unwrap_or_else(|_| park()); let outcome = process::Outcome::Exited(code); if table.record(episode.pid).map(|r| r.outcome) != Ok(Some(outcome)) { park(); } episode.outcome = Some(outcome); write_str("TURKOS/OS/K1300P-TRACE: EXIT=0x"); write_hex(code as usize); write_line(""); 1 } else { 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 != 1 { park(); } return os_k1215a_run_child(episode as *mut _, frame as *mut _, episode.launch.kernel_root); } if let abi::Call::Write(request) = call { if episode.case != 1 || request.fd() != 1 || request.bytes() != 16 || !episode.ps_closed || episode.ps_clock_reads != 2 || episode.ps_write_calls >= 4 { park(); } let mut bytes = [0u8; 16]; table.copy_current_user_data(episode.pid, request.address(), &mut bytes) .unwrap_or_else(|_| park()); if bytes != episode.ps_outputs[episode.ps_write_calls as usize] { park(); } for byte in bytes { write_byte(byte); } episode.ps_write_calls += 1; frame.x[0] = 16; write_str("TURKOS/OS/K1300P-TRACE: WRITE=0x"); write_hex(episode.ps_write_calls as usize); write_line(""); return 0; } park() } }