// K1295 development-only native EL0 directory boundary. use super::*; const OUTPUT: &[u8] = b"README\nMULTI\nTAIL\nONE\nSUB\n"; 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::syscall_abi as abi; let disk_ptr = unsafe { read_volatile(core::ptr::addr_of!(OS_K1295_LS_DISK)) }; if disk_ptr.is_null() || frame.elr < episode.launch.user_pc || frame.elr >= episode.launch.user_pc + 4096 || !frame.elr.is_multiple_of(4) { park(); } let disk = unsafe { &mut *disk_ptr }; if frame.x[7] == 3 { if episode.case != 1 { park(); } match frame.x[8] { 10 => { let len = usize::try_from(frame.x[1]).unwrap_or(usize::MAX); if len == 0 || len > 24 { frame.x[0] = abi::AbiResult::Err(abi::Errno::Invalid).encode(); return 0; } let mut path = [0u8; 24]; if table.copy_current_user_data(episode.pid, frame.x[0], &mut path[..len]).is_err() { frame.x[0] = abi::AbiResult::Err(abi::Errno::Fault).encode(); return 0; } if !episode.ls_denied { if &path[..len] != b"/SUB" { park(); } let error = disk.open(&path[..len]).err().unwrap_or_else(|| park()); if error != abi::Errno::Access || !disk.owner_released() { park(); } episode.ls_denied = true; frame.x[0] = abi::AbiResult::Err(error).encode(); write_line("TURKOS/OS/K1295L-TRACE: SUB-EACCES-NO-OWNER"); return 0; } if episode.ls_fd != 0 || episode.ls_closed || &path[..len] != b"/" { park(); } let fd = disk.open(&path[..len]).unwrap_or_else(|_| park()); episode.ls_fd = fd; frame.x[0] = fd; write_line("TURKOS/OS/K1295L-TRACE: OPEN-ROOT"); 0 } 11 => { if frame.x[0] == 0 && episode.ls_closed && !episode.ls_stale { if disk.next(0) != Err(abi::Errno::BadFd) { park(); } episode.ls_stale = true; frame.x[0] = abi::AbiResult::Err(abi::Errno::BadFd).encode(); write_line("TURKOS/OS/K1295L-TRACE: STALE-EBADF"); return 0; } if episode.ls_fd == 0 || frame.x[0] != episode.ls_fd || frame.x[2] != 32 { 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; } match disk.next(episode.ls_fd).unwrap_or_else(|_| park()) { None => { frame.x[0] = 0; write_line("TURKOS/OS/K1295L-TRACE: EOF"); } Some((entry, kind)) => { wire = [0; 32]; wire[..4].copy_from_slice(&entry.inode.to_le_bytes()); wire[4] = kind; wire[5] = entry.name_len; wire[8..].copy_from_slice(&entry.name); table.write_current_user_data(episode.pid, frame.x[1], &wire) .unwrap_or_else(|_| park()); frame.x[0] = 1; write_str("TURKOS/OS/K1295L-TRACE: ENTRY "); write_line(core::str::from_utf8( &entry.name[..entry.name_len as usize]) .unwrap_or_else(|_| park())); } } 0 } 12 => { if episode.ls_fd == 0 || frame.x[0] != episode.ls_fd || episode.ls_closed { park(); } disk.close(episode.ls_fd).unwrap_or_else(|_| park()); episode.ls_fd = 0; episode.ls_closed = true; frame.x[0] = 0; write_line("TURKOS/OS/K1295L-TRACE: CLOSED-ROOT"); 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.ls_denied || !episode.ls_closed || !episode.ls_stale || episode.ls_fd != 0 || episode.ls_written != OUTPUT.len() || !disk.owner_released() { 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/K1295L-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() == 0 || request.bytes() > 256 || !episode.ls_closed { park(); } let count = request.bytes().min(32); let mut bytes = [0u8; 256]; table.copy_current_user_data(episode.pid, request.address(), &mut bytes[..request.bytes()]).unwrap_or_else(|_| park()); let end = episode.ls_written.checked_add(count) .unwrap_or_else(|| park()); if end > OUTPUT.len() || &bytes[..count] != &OUTPUT[episode.ls_written..end] { park(); } for byte in &bytes[..count] { write_byte(*byte); } episode.ls_written = end; frame.x[0] = count as u64; write_str("TURKOS/OS/K1295L-TRACE: WRITE=0x"); write_hex(count); write_line(""); return 0; } park() } }