// Mode 34 runs an EL0 shell and child from one immutable ABI-v2 Rust ELF. // The child fills three separately mapped heap pages and sees quota ENOMEM. static mut OS_K1215A_EL0_ERROR: Option<&'static str> = None; #[unsafe(no_mangle)] static mut OS_K1215A_ACTIVE: u64 = 0; #[unsafe(no_mangle)] static mut OS_K1215A_KERNEL_ROOT: u64 = 0; #[unsafe(no_mangle)] static mut OS_K1215A_USER_TTBR: u64 = 0; #[unsafe(no_mangle)] static mut OS_K1215A_TRAP_TTBR: u64 = 0; #[unsafe(no_mangle)] static mut OS_K1215A_KERNEL_FRAME: u64 = 0; static mut OS_K1215A_INIT_PID: Option = None; static mut OS_K1220_FORMAT_PROBE: bool = false; static mut OS_K1225_TYPED_PROBE: bool = false; static mut OS_K1230_IO_PROBE: bool = false; static mut OS_K1235_HANDLE_PROBE: bool = false; static mut OS_K1240_COMPAT_PROBE: bool = false; static mut OS_K1245_MANIFEST_PROBE: bool = false; static mut OS_K1250_STARTUP_PROBE: bool = false; static mut OS_K1255_RESTART_PROBE: bool = false; static mut OS_K1260_REAPER_PROBE: bool = false; static mut OS_K1265_WORDS_PROBE: bool = false; static mut OS_K1270_DISPATCH_PROBE: bool = false; static mut OS_K1275_FOREGROUND_PROBE: bool = false; static mut OS_K1280_INPUT_PROBE: bool = false; static mut OS_K1285_ECHO_PROBE: bool = false; static mut OS_K1290_CAT_PROBE: bool = false; static mut OS_K1290_CAT_DISK: *mut k1290_cat_disk::CatDisk = core::ptr::null_mut(); struct OsK1260Wait<'a, 'b> { table: &'a mut OsK1105Table<'b>, shell: turkos_kernel::runtime::process_table::ProcessId, key: turkos_os_init_reaper::Pid, fail_once: bool, } impl turkos_os_init_reaper::WaitAdapter for OsK1260Wait<'_, '_> { fn wait_child(&mut self, pid: turkos_os_init_reaper::Pid) -> Result { use turkos_os_init_reaper::{Cause, Outcome}; use turkos_kernel::runtime::process_table::Outcome as ProcessOutcome; if pid != self.key { return Err(Cause::Stale); } if self.fail_once { self.fail_once = false; return Err(Cause::Busy); } match self.table.wait_child_outcome(self.shell).map_err(|_| Cause::Busy)? { ProcessOutcome::Exited(code) => Ok(Outcome::Exited(code)), ProcessOutcome::Fault(fault) => Ok(Outcome::Fault(fault.far())), } } } struct OsK1275Published { key: turkos_os_shell_foreground::Pid } impl turkos_os_shell_foreground::Adapter for OsK1275Published { fn spawn(&mut self) -> Result { Ok(self.key) } fn wait(&mut self, _: turkos_os_shell_foreground::Pid) -> Result { Err(turkos_os_shell_foreground::Cause::Injected) } } struct OsK1275Wait<'a, 'b> { table: &'a mut OsK1105Table<'b>, child: turkos_kernel::runtime::process_table::ProcessId, key: turkos_os_shell_foreground::Pid, busy_once: bool, } impl turkos_os_shell_foreground::Adapter for OsK1275Wait<'_, '_> { fn spawn(&mut self) -> Result { Err(turkos_os_shell_foreground::Cause::Injected) } fn wait(&mut self, pid: turkos_os_shell_foreground::Pid) -> Result { use turkos_os_shell_foreground::{Cause, Outcome}; use turkos_kernel::runtime::process_table::Outcome as ProcessOutcome; if pid != self.key { return Err(Cause::Stale); } if self.busy_once { self.busy_once = false; return Err(Cause::Busy); } match self.table.wait_child_outcome(self.child).map_err(|_| Cause::Busy)? { ProcessOutcome::Exited(code) => Ok(Outcome::Exited(code)), ProcessOutcome::Fault(fault) => Ok(Outcome::Fault(fault.far())), } } } struct OsK1215AEl0Episode { table: *mut u8, pid: turkos_kernel::runtime::process_table::ProcessId, launch: turkos_kernel::runtime::process_table::GuestLaunch, case: usize, calls: u8, waits: u8, allocs: u8, frees: u8, io_calls: u8, compat_queries: u8, startup_queries: u8, restart_queries: u8, shell_words_queries: u8, shell_dispatch_queries: u8, shell_input_queries: u8, handle_live: bool, handle_closes: u8, stale_rejected: bool, quota_denied: bool, child: Option, old_vbar: u64, outcome: Option, cat_files_closed: u8, cat_negative: u8, cat_fd: u64, cat_written: usize, cat_eof: bool, } #[inline(never)] fn os_k1215a_el0_on_work_stack( memory: &mut OsK660Memory, tables: &mmu::Tables, ) -> Result<(), &'static str> { let guard = core::ptr::addr_of!(OS_K1105_WORK_STACK) as u64; let low = guard + 4096; let end = low + 262144; let before = os_k1120_registers(); if before.sp >= guard && before.sp < end || before.cpu != 0 || before.daif & 128 == 0 || before.current_el != 4 || before.irq_active || before.ttbr != tables.root { return Err("exit-work-stack-context"); } let (slot, descriptor) = unsafe { tables.os_k1105_acquire_work_guard(guard, end, core::ptr::addr_of!(_image_start) as u64, core::ptr::addr_of!(_image_end) as u64) }.map_err(|_| "exit-work-stack-guard")?; unsafe { write_volatile(low as *mut u64, OS_K1105_LOW_CANARY); write_volatile((end - 8) as *mut u64, OS_K1105_HIGH_CANARY); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_EL0_ERROR), None); } unsafe extern "C" { fn __os_k1215a_el0_on_stack(memory: *mut u8, tables: *const u8) -> u64; } write_line("TURKOS/OS/K1215A-TRACE: WORK-STACK-READY"); let status = unsafe { __os_k1215a_el0_on_stack( (memory as *mut OsK660Memory).cast(), (tables as *const mmu::Tables).cast()) }; let after = os_k1120_registers(); let canaries = unsafe { read_volatile(low as *const u64) == OS_K1105_LOW_CANARY && read_volatile((end - 8) as *const u64) == OS_K1105_HIGH_CANARY }; unsafe { tables.os_k1105_restore_work_guard(guard, end, slot, descriptor) } .map_err(|_| "exit-work-stack-restore")?; if after.sp != before.sp || after.spsel != before.spsel || after.ttbr != before.ttbr || after.tcr != before.tcr || after.sctlr != before.sctlr || after.daif != before.daif || !canaries { return Err("exit-work-stack-return"); } if status != 0 { return Err(unsafe { read_volatile(core::ptr::addr_of!(OS_K1215A_EL0_ERROR)) } .unwrap_or("exit-work-stack-body")); } Ok(()) } fn os_k1290_cat_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_K1290_CAT_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] { 9 => { 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 name = [0u8; 24]; if table.copy_current_user_data(episode.pid, frame.x[0], &mut name[..len]).is_err() { frame.x[0] = abi::AbiResult::Err(abi::Errno::Fault).encode(); return 0; } if episode.cat_files_closed == 3 { if &name[..len] != b"MISSING" { park(); } frame.x[0] = abi::AbiResult::Err( disk.open(&name[..len]).err().unwrap_or_else(|| park())).encode(); episode.cat_negative += 1; write_line("TURKOS/OS/K1290C-TRACE: MISSING-ENOENT"); return 0; } let expected: &[u8] = match episode.cat_files_closed { 0 => b"README", 1 => b"ONE", 2 => b"TAIL", _ => park(), }; if &name[..len] != expected || episode.cat_fd != 0 { park(); } let fd = disk.open(&name[..len]).unwrap_or_else(|_| park()); episode.cat_fd = fd; episode.cat_written = 0; episode.cat_eof = false; frame.x[0] = fd; write_str("TURKOS/OS/K1290C-TRACE: OPEN "); write_line( core::str::from_utf8(expected).unwrap_or_else(|_| park())); return 0; } 8 => { let len = usize::try_from(frame.x[2]).unwrap_or(usize::MAX); if len > 256 { frame.x[0] = abi::AbiResult::Err(abi::Errno::Invalid).encode(); return 0; } if frame.x[0] == 0 && episode.cat_files_closed == 3 && episode.cat_negative == 1 { frame.x[0] = abi::AbiResult::Err(abi::Errno::BadFd).encode(); episode.cat_negative += 1; write_line("TURKOS/OS/K1290C-TRACE: STALE-READ-EBADF"); return 0; } if frame.x[0] != episode.cat_fd || episode.cat_fd == 0 || episode.cat_eof || len == 0 { park(); } let mut scratch = [0u8; 256]; if table.copy_current_user_data(episode.pid, frame.x[1], &mut scratch[..len]).is_err() { frame.x[0] = abi::AbiResult::Err(abi::Errno::Fault).encode(); return 0; } let count = disk.read(episode.cat_fd, &mut scratch[..len]) .unwrap_or_else(|_| park()); table.write_current_user_data(episode.pid, frame.x[1], &scratch[..count]).unwrap_or_else(|_| park()); if count == 0 { episode.cat_eof = true; } frame.x[0] = count as u64; write_str("TURKOS/OS/K1290C-TRACE: READ=0x"); write_hex(count); write_line(""); return 0; } 7 => { if frame.x[0] == 0 && episode.cat_files_closed == 3 && episode.cat_negative == 2 { frame.x[0] = abi::AbiResult::Err(abi::Errno::BadFd).encode(); episode.cat_negative += 1; write_line("TURKOS/OS/K1290C-TRACE: STALE-CLOSE-EBADF"); return 0; } if frame.x[0] != episode.cat_fd || episode.cat_fd == 0 || !episode.cat_eof || disk.current_len() != Some(episode.cat_written) { park(); } disk.close(episode.cat_fd).unwrap_or_else(|_| park()); episode.cat_fd = 0; episode.cat_files_closed += 1; frame.x[0] = 0; write_str("TURKOS/OS/K1290C-TRACE: CLOSED=0x"); write_hex(episode.cat_files_closed as usize); write_line(""); return 0; } _ => { 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 { park(); } } else if code != 42 || episode.calls != 1 || episode.cat_files_closed != 3 || episode.cat_negative != 3 || episode.cat_fd != 0 || !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/K1290C-TRACE: EXIT=0x"); write_hex(code as usize); write_line(""); 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 != 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 || episode.cat_fd == 0 { 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()); if !disk.matches_output(episode.cat_written, &bytes[..count]) { park(); } for byte in &bytes[..count] { write_byte(*byte); } episode.cat_written += count; frame.x[0] = count as u64; write_str("TURKOS/OS/K1290C-TRACE: WRITE=0x"); write_hex(count); write_line(""); return 0; } park() } #[unsafe(no_mangle)] unsafe extern "C" fn __os_k1215a_el0_body(memory: *mut u8, tables: *const u8) -> u64 { let result = os_k1215a_el0_probe( unsafe { &mut *memory.cast::() }, unsafe { &*tables.cast::() }); match result { Ok(()) => 0, Err(error) => { unsafe { write_volatile(core::ptr::addr_of_mut!(OS_K1215A_EL0_ERROR), Some(error)); } 1 } } } #[unsafe(no_mangle)] extern "C" fn os_k1215a_dispatch(pointer: *mut os_k920_exception::Frame) -> u64 { write_line("TURKOS/OS/K1215A-TRACE: DISPATCH-ENTRY"); use turkos_kernel::runtime::process_table as process; use turkos_kernel::runtime::syscall_abi as abi; let kernel_root = unsafe { read_volatile(core::ptr::addr_of!(OS_K1215A_KERNEL_ROOT)) }; let user_ttbr = unsafe { read_volatile(core::ptr::addr_of!(OS_K1215A_USER_TTBR)) }; let trap_ttbr = unsafe { read_volatile(core::ptr::addr_of!(OS_K1215A_TRAP_TTBR)) }; let active = unsafe { read_volatile(core::ptr::addr_of!(OS_K1215A_ACTIVE)) }; let registers = os_k1120_registers(); if kernel_root == 0 || user_ttbr == 0 || active == 0 || pointer.is_null() || registers.cpu != 0 || registers.current_el != 4 || registers.daif & 128 == 0 || registers.irq_active || registers.ttbr != kernel_root || registers.spsel != 1 || trap_ttbr != user_ttbr { park(); } let episode = unsafe { &mut *(active as *mut OsK1215AEl0Episode) }; let table = unsafe { &mut *episode.table.cast::>() }; let launch = table.current_launch(episode.pid).unwrap_or_else(|_| park()); write_line("TURKOS/OS/K1215A-TRACE: DISPATCH-OWNER"); let shell = unsafe { read_volatile(core::ptr::addr_of!(OS_K1215A_INIT_PID)) } .unwrap_or_else(|| park()); if episode.case == 0 && episode.pid != shell || episode.case == 1 && table.record(episode.pid).map(|r| r.parent) != Ok(Some(shell)) { park(); } if launch != episode.launch || launch.kernel_root != kernel_root || launch.user_root | ((launch.user_asid as u64) << 48) != user_ttbr { park(); } let address = pointer as u64; if address < launch.kernel_stack_low || address.checked_add(os_k920_exception::FRAME_BYTES as u64) .is_none_or(|end| end > launch.kernel_stack_high) || !address.is_multiple_of(os_k920_exception::FRAME_ALIGNMENT as u64) { park(); } let frame = unsafe { &mut *pointer }; let shell_helper = episode.case == 0 && (unsafe { read_volatile(core::ptr::addr_of!(OS_K1265_WORDS_PROBE)) } && frame.elr == launch.user_pc + 0xa00 || unsafe { read_volatile(core::ptr::addr_of!(OS_K1270_DISPATCH_PROBE)) } && frame.elr == launch.user_pc + 0x858 || unsafe { read_volatile(core::ptr::addr_of!(OS_K1280_INPUT_PROBE)) } && frame.elr == launch.user_pc + if unsafe { read_volatile(core::ptr::addr_of!(OS_K1285_ECHO_PROBE)) } { 0x790 } else { 0x3c0 }); if frame.validate_header().is_err() || frame.vector_slot != 8 || frame.spsr & 0x3ff != launch.user_spsr || frame.sp_el0 < 0x80003000 || frame.sp_el0 > launch.user_sp || frame.sp_el0 & 15 != 0 || episode.case == 0 && frame.sp_el0 != launch.user_sp && !shell_helper || frame.interrupted_sp != address + os_k920_exception::FRAME_BYTES as u64 || episode.outcome.is_some() { park(); } if frame.esr != abi::SVC_ESR { park(); } if unsafe { read_volatile(core::ptr::addr_of!(OS_K1290_CAT_PROBE)) } { return os_k1290_cat_dispatch(episode, frame, table); } write_str("TURKOS/OS/K1215A-TRACE: SVC=0x"); write_hex(frame.x[8] as usize); write_line(""); if frame.x[7] == 2 { use turkos_os_user_runtime_abi as abi2; let request = abi2::decode(frame.x[7], frame.x[8], core::array::from_fn(|i| frame.x[i])).unwrap_or_else(|_| park()); match request { abi2::Request::Alloc { bytes, alignment } => { if episode.case == 0 { let words = unsafe { read_volatile(core::ptr::addr_of!(OS_K1265_WORDS_PROBE)) || read_volatile(core::ptr::addr_of!(OS_K1270_DISPATCH_PROBE)) || read_volatile(core::ptr::addr_of!(OS_K1280_INPUT_PROBE)) }; if episode.calls != 2 || episode.allocs != 0 || frame.elr != launch.user_pc + if words { 0xd8 } else { 0xd0 } || bytes != 8 || alignment != 8 { park(); } let address = table.alloc_current_heap(bytes, alignment) .unwrap_or_else(|_| park()); if address != 0x80004000 { park(); } episode.allocs = 1; frame.x[0] = address; write_line("TURKOS/OS/K1215A-TRACE: SHELL-ALLOC-AFTER-CHILD"); } else { let typed = unsafe { read_volatile(core::ptr::addr_of!(OS_K1225_TYPED_PROBE)) }; let io = unsafe { read_volatile(core::ptr::addr_of!(OS_K1230_IO_PROBE)) }; let compat = unsafe { read_volatile(core::ptr::addr_of!(OS_K1240_COMPAT_PROBE)) }; let manifest = unsafe { read_volatile(core::ptr::addr_of!(OS_K1245_MANIFEST_PROBE)) }; let startup = unsafe { read_volatile(core::ptr::addr_of!(OS_K1250_STARTUP_PROBE)) }; let restart = unsafe { read_volatile(core::ptr::addr_of!(OS_K1255_RESTART_PROBE)) }; let words = unsafe { read_volatile(core::ptr::addr_of!(OS_K1265_WORDS_PROBE)) }; let svc_return = if words { 0x460 } else if restart { 0x488 } else if startup { 0x4ac } else if manifest { 0x588 } else if compat { 0x424 } else if io { 0x498 } else if typed { 0x360 } else { 0x8c }; if episode.calls != 1 || frame.elr != launch.user_pc + svc_return || episode.frees != 0 || restart && episode.restart_queries != 1 || startup && episode.startup_queries != 1 || compat && episode.compat_queries != if manifest { 3 } else { 2 } { park(); } let expected = match episode.allocs { 0 => (16, 16), 1 => (32, 16), 2 => (64, 16), 3 => (1, 1), _ => park(), }; if (bytes, alignment) != expected { park(); } if episode.allocs == 3 { let before = table.snapshot(); if table.alloc_current_heap(bytes, alignment) != Err(abi::Errno::NoMem) || table.snapshot() != before { park(); } frame.x[0] = abi::AbiResult::Err(abi::Errno::NoMem).encode(); episode.quota_denied = true; write_line("TURKOS/OS/K1215A-TRACE: CHILD-QUOTA-ENOMEM"); } else { let address = table.alloc_current_heap(bytes, alignment) .unwrap_or_else(|_| park()); if address != 0x80004000 + episode.allocs as u64 * 4096 { park(); } frame.x[0] = address; write_line("TURKOS/OS/K1215A-TRACE: CHILD-HEAP-PAGE"); } episode.allocs += 1; } return 0; } abi2::Request::Free(address) => { if episode.case == 0 { let words = unsafe { read_volatile(core::ptr::addr_of!(OS_K1265_WORDS_PROBE)) || read_volatile(core::ptr::addr_of!(OS_K1270_DISPATCH_PROBE)) || read_volatile(core::ptr::addr_of!(OS_K1280_INPUT_PROBE)) }; if episode.calls != 2 || episode.allocs != 1 || episode.frees != 0 || address != 0x80004000 || frame.elr != launch.user_pc + if words { 0x110 } else { 0x108 } { park(); } table.free_current_heap(address).unwrap_or_else(|_| park()); episode.frees = 1; write_line("TURKOS/OS/K1215A-TRACE: SHELL-FREE-AFTER-CHILD"); } else { let typed = unsafe { read_volatile(core::ptr::addr_of!(OS_K1225_TYPED_PROBE)) }; let io = unsafe { read_volatile(core::ptr::addr_of!(OS_K1230_IO_PROBE)) }; let compat = unsafe { read_volatile(core::ptr::addr_of!(OS_K1240_COMPAT_PROBE)) }; let manifest = unsafe { read_volatile(core::ptr::addr_of!(OS_K1245_MANIFEST_PROBE)) }; let startup = unsafe { read_volatile(core::ptr::addr_of!(OS_K1250_STARTUP_PROBE)) }; let restart = unsafe { read_volatile(core::ptr::addr_of!(OS_K1255_RESTART_PROBE)) }; let words = unsafe { read_volatile(core::ptr::addr_of!(OS_K1265_WORDS_PROBE)) }; let svc_return = if words { 0x460 } else if restart { 0x488 } else if startup { 0x4ac } else if manifest { 0x588 } else if compat { 0x424 } else if io { 0x498 } else if typed { 0x360 } else { 0x9c }; if episode.calls != 1 || !episode.quota_denied || episode.allocs != 4 || episode.frees >= 3 || frame.elr != launch.user_pc + svc_return || address != 0x80004000 + episode.frees as u64 * 4096 { park(); } table.free_current_heap(address).unwrap_or_else(|_| park()); episode.frees += 1; write_line("TURKOS/OS/K1215A-TRACE: CHILD-HEAP-FREED"); } frame.x[0] = 0; return 0; } abi2::Request::Exit(code) => { let dispatch = unsafe { read_volatile(core::ptr::addr_of!(OS_K1270_DISPATCH_PROBE)) }; let input = unsafe { read_volatile(core::ptr::addr_of!(OS_K1280_INPUT_PROBE)) }; if frame.elr != launch.user_pc + 0x78 || episode.case == 0 && (code != 0 || episode.calls != 2 || episode.allocs != 1 || episode.frees != 1 || unsafe { read_volatile(core::ptr::addr_of!(OS_K1265_WORDS_PROBE)) } && episode.shell_words_queries != 1 || dispatch && episode.shell_dispatch_queries != 1 || input && episode.shell_input_queries != 1) || episode.case == 1 && (code != 42 || episode.calls != 1 || (if dispatch || input { episode.allocs != 0 || episode.frees != 0 || episode.quota_denied || unsafe { read_volatile(core::ptr::addr_of!(OS_K1285_ECHO_PROBE)) } && episode.io_calls != 6 } else { episode.allocs != 4 || episode.frees != 3 || !episode.quota_denied || unsafe { read_volatile(core::ptr::addr_of!(OS_K1230_IO_PROBE)) } && episode.io_calls != 4 || unsafe { read_volatile(core::ptr::addr_of!(OS_K1235_HANDLE_PROBE)) } && (episode.handle_live || episode.handle_closes != 1 || !episode.stale_rejected) || unsafe { read_volatile(core::ptr::addr_of!(OS_K1240_COMPAT_PROBE)) } && episode.compat_queries != if unsafe { read_volatile(core::ptr::addr_of!(OS_K1245_MANIFEST_PROBE)) } { 3 } else { 2 } || unsafe { read_volatile(core::ptr::addr_of!(OS_K1250_STARTUP_PROBE)) } && episode.startup_queries != 1 || unsafe { read_volatile(core::ptr::addr_of!(OS_K1255_RESTART_PROBE)) } && episode.restart_queries != 1 })) { park(); } if table.exit_current(code).is_err() { park(); } if episode.case == 0 { write_line("TURKOS/OS/K1215A-TRACE: SHELL-EXIT-0"); } else { write_line("TURKOS/OS/K1215A-TRACE: CHILD-EXIT-42"); } let outcome = process::Outcome::Exited(code); if table.record(episode.pid).map(|r| r.outcome) != Ok(Some(outcome)) || table.snapshot().zombies != 1 { park(); } episode.outcome = Some(outcome); return 1; } } } if frame.x[7] == 3 && unsafe { read_volatile(core::ptr::addr_of!(OS_K1235_HANDLE_PROBE)) } { if episode.case != 1 || episode.io_calls != 4 || frame.elr != launch.user_pc + 0x9c0 { park(); } match frame.x[8] { 6 => { if episode.handle_live || episode.handle_closes != 0 || frame.x[0] != 0 { park(); } episode.handle_live = true; frame.x[0] = 0x1235_0001; write_line("TURKOS/OS/K1235H-TRACE: HANDLE-OPENED"); } 7 => { if frame.x[0] != 0x1235_0001 { park(); } if episode.handle_live { episode.handle_live = false; episode.handle_closes = 1; frame.x[0] = 0; write_line("TURKOS/OS/K1235H-TRACE: DROP-CLOSED-ONCE"); } else { if episode.handle_closes != 1 || episode.stale_rejected { park(); } frame.x[0] = abi::AbiResult::Err(abi::Errno::BadFd).encode(); episode.stale_rejected = true; write_line("TURKOS/OS/K1235H-TRACE: SECOND-CLOSE-STALE"); } } _ => park(), } return 0; } 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 unsafe { read_volatile(core::ptr::addr_of!(OS_K1285_ECHO_PROBE)) } && let abi::Call::Write(request) = call { const EXPECTED: &[u8; 12] = b"hello world\n"; if episode.case != 1 || frame.elr != launch.user_pc + 0x1ac || request.fd() != 1 || episode.io_calls >= 6 { park(); } let offset = episode.io_calls as usize * 2; let remaining = &EXPECTED[offset..]; if request.bytes() != remaining.len() { park(); } let mut copied = [0u8; 12]; table.copy_current_user_data(episode.pid, request.address(), &mut copied[..remaining.len()]).unwrap_or_else(|_| park()); if &copied[..remaining.len()] != remaining { park(); } write_str("TURKOS/OS/K1285E-SERIAL: "); write_str(core::str::from_utf8(&copied[..2]).unwrap_or_else(|_| park())); write_line(""); frame.x[0] = 2; episode.io_calls += 1; return 0; } if unsafe { read_volatile(core::ptr::addr_of!(OS_K1230_IO_PROBE)) } && let abi::Call::Write(request) = call { let handle = unsafe { read_volatile(core::ptr::addr_of!(OS_K1235_HANDLE_PROBE)) }; let svc_return = if handle { 0xa84 } else { 0x8a0 }; if episode.case != 1 || frame.elr != launch.user_pc + svc_return || request.fd() != 1 || episode.io_calls >= 4 { park(); } let (expected, count): (&[u8], usize) = match episode.io_calls { 0 => (b"ABCDEF", 2), 1 => (b"CDEF", 2), 2 => (b"EF", 2), 3 => (b"Z", 0), _ => park(), }; if request.bytes() != expected.len() { park(); } let mut copied = [0u8; 6]; table.copy_current_user_data(episode.pid, request.address(), &mut copied[..expected.len()]).unwrap_or_else(|_| park()); if &copied[..expected.len()] != expected { park(); } if count == 0 { write_line("TURKOS/OS/K1230I-TRACE: ZERO-RETURN"); } else { write_str("TURKOS/OS/K1230I-SERIAL: "); write_str(core::str::from_utf8(&copied[..count]).unwrap_or_else(|_| park())); write_line(""); } frame.x[0] = count as u64; episode.io_calls += 1; return 0; } if call == abi::Call::Role { if episode.calls != 0 || frame.elr != launch.user_pc + 12 { park(); } frame.x[0] = episode.case as u64; episode.calls = 1; write_line("TURKOS/OS/K1215A-TRACE: ROLE-RETURNED"); return 0; } if call == abi::Call::Version && episode.case == 1 && unsafe { read_volatile(core::ptr::addr_of!(OS_K1240_COMPAT_PROBE)) } { let manifest = unsafe { read_volatile(core::ptr::addr_of!(OS_K1245_MANIFEST_PROBE)) }; let expected = if manifest { 3 } else { 2 }; let svc_return = if manifest { 0xa78 } else { 0x744 }; if episode.calls != 1 || episode.allocs != 0 || episode.frees != 0 || frame.elr != launch.user_pc + svc_return || episode.compat_queries >= expected { park(); } let before = table.snapshot(); frame.x[0] = abi::ABI_VERSION; if table.snapshot() != before { park(); } if manifest && episode.compat_queries == 0 { write_line("TURKOS/OS/K1245M-TRACE: MANIFEST-VALIDATED-AND-REJECTIONS-BEFORE-HEAP"); } else if episode.compat_queries == if manifest { 1 } else { 0 } { write_line("TURKOS/OS/K1240C-TRACE: V1-ACCEPTED-BEFORE-HEAP"); } else { write_line("TURKOS/OS/K1240C-TRACE: V2-REJECTED-BEFORE-HEAP"); } episode.compat_queries += 1; return 0; } if call == abi::Call::Version && episode.case == 1 && unsafe { read_volatile(core::ptr::addr_of!(OS_K1250_STARTUP_PROBE)) } { if episode.calls != 1 || episode.allocs != 0 || episode.frees != 0 || episode.startup_queries != 0 || frame.elr != launch.user_pc + 0xad0 { park(); } let before = table.snapshot(); frame.x[0] = abi::ABI_VERSION; if table.snapshot() != before { park(); } episode.startup_queries = 1; write_line("TURKOS/OS/K1250S-TRACE: ORDERED-RETRY-REVERSE-ROLLBACK-BEFORE-HEAP"); return 0; } if call == abi::Call::Version && episode.case == 1 && unsafe { read_volatile(core::ptr::addr_of!(OS_K1255_RESTART_PROBE)) } { if episode.calls != 1 || episode.allocs != 0 || episode.frees != 0 || episode.restart_queries != 0 || frame.elr != launch.user_pc + 0x850 { park(); } let before = table.snapshot(); frame.x[0] = abi::ABI_VERSION; if table.snapshot() != before { park(); } episode.restart_queries = 1; write_line("TURKOS/OS/K1255R-TRACE: BOUNDED-RETRY-OWNER-RETAINED-EXHAUSTED-BEFORE-HEAP"); return 0; } if call == abi::Call::Version && episode.case == 0 && unsafe { read_volatile(core::ptr::addr_of!(OS_K1280_INPUT_PROBE)) } && episode.calls == 1 { if episode.allocs != 0 || episode.frees != 0 || episode.shell_input_queries != 0 || frame.elr != launch.user_pc + if unsafe { read_volatile(core::ptr::addr_of!(OS_K1285_ECHO_PROBE)) } { 0x790 } else { 0x3c0 } { park(); } let before = table.snapshot(); frame.x[0] = abi::ABI_VERSION; if table.snapshot() != before { park(); } episode.shell_input_queries = 1; write_line("TURKOS/OS/K1280I-TRACE: CANCEL-STALE-REJECTED NEW-LINE-COMMITTED-BEFORE-CHILD"); return 0; } if call == abi::Call::Version && episode.case == 0 && unsafe { read_volatile(core::ptr::addr_of!(OS_K1270_DISPATCH_PROBE)) } && episode.calls == 1 { if episode.allocs != 0 || episode.frees != 0 || episode.shell_dispatch_queries != 0 || frame.elr != launch.user_pc + 0x858 { park(); } let before = table.snapshot(); frame.x[0] = abi::ABI_VERSION; if table.snapshot() != before { park(); } episode.shell_dispatch_queries = 1; write_line("TURKOS/OS/K1270D-TRACE: EXTERNAL-RUN BUILTIN-HELP-BEFORE-CHILD"); return 0; } if call == abi::Call::Version && episode.case == 0 && unsafe { read_volatile(core::ptr::addr_of!(OS_K1265_WORDS_PROBE)) } && episode.calls == 1 { if episode.allocs != 0 || episode.frees != 0 || episode.shell_words_queries != 0 || frame.elr != launch.user_pc + 0xa00 { park(); } let before = table.snapshot(); frame.x[0] = abi::ABI_VERSION; if table.snapshot() != before { park(); } episode.shell_words_queries = 1; write_line("TURKOS/OS/K1265W-TRACE: SHELL-PARSED-WORDS-BEFORE-CHILD"); return 0; } if episode.case == 0 { if let abi::Call::RunChild(1) = call { let words = unsafe { read_volatile(core::ptr::addr_of!(OS_K1265_WORDS_PROBE)) || read_volatile(core::ptr::addr_of!(OS_K1270_DISPATCH_PROBE)) || read_volatile(core::ptr::addr_of!(OS_K1280_INPUT_PROBE)) }; if episode.calls != 1 || frame.elr != launch.user_pc + if words { 0xb8 } else { 0xb0 } || unsafe { read_volatile(core::ptr::addr_of!(OS_K1265_WORDS_PROBE)) } && episode.shell_words_queries != 1 || unsafe { read_volatile(core::ptr::addr_of!(OS_K1270_DISPATCH_PROBE)) } && episode.shell_dispatch_queries != 1 || unsafe { read_volatile(core::ptr::addr_of!(OS_K1280_INPUT_PROBE)) } && episode.shell_input_queries != 1 { park(); } return os_k1215a_run_child(active as *mut OsK1215AEl0Episode, pointer, kernel_root); } if call == abi::Call::Version { let words = unsafe { read_volatile(core::ptr::addr_of!(OS_K1265_WORDS_PROBE)) || read_volatile(core::ptr::addr_of!(OS_K1270_DISPATCH_PROBE)) || read_volatile(core::ptr::addr_of!(OS_K1280_INPUT_PROBE)) }; if episode.calls != 2 || episode.allocs != 1 || episode.frees != 1 || frame.elr != launch.user_pc + if words { 0x120 } else { 0x118 } { park(); } frame.x[0] = abi::ABI_VERSION; if unsafe { read_volatile(core::ptr::addr_of!(OS_K1270_DISPATCH_PROBE)) || read_volatile(core::ptr::addr_of!(OS_K1280_INPUT_PROBE)) } { write_line("TURKOS/OS/K1215A-TRACE: SHELL-VERSION-AFTER-CHILD"); } else { write_line("TURKOS/OS/K1215A-TRACE: SHELL-VERSION-AFTER-ENOMEM"); } return 0; } } park(); } fn os_k1215a_run_child( parent_ptr: *mut OsK1215AEl0Episode, frame_ptr: *mut os_k920_exception::Frame, kernel_root: u64, ) -> u64 { write_line("TURKOS/OS/K1215A-TRACE: RUN-CHILD-ENTRY"); use turkos_kernel::runtime::process_guest as guest; use turkos_kernel::runtime::process_table as process; let foreground_probe = unsafe { read_volatile(core::ptr::addr_of!(OS_K1275_FOREGROUND_PROBE)) }; let mut foreground = turkos_os_shell_foreground::Foreground::new(); let parent = unsafe { &mut *parent_ptr }; let table_ptr = parent.table.cast::>(); let child = { let table = unsafe { &mut *table_ptr }; let snapshot = table.snapshot(); write_str("TURKOS/OS/K1215A-TRACE: PARENT PUBLISHED=0x"); write_hex(snapshot.published); write_str(" ZOMBIES=0x"); write_hex(snapshot.zombies); write_str(" STATE=0x"); write_hex(table.record(parent.pid).map(|r| r.resources.state as usize) .unwrap_or(usize::MAX)); write_line(""); if table.snapshot().published != 1 || table.snapshot().zombies != 0 || table.record(parent.pid).map(|r| r.resources.state) != Ok(turkos_kernel::runtime::process_threads::State::Running) { park(); } write_line("TURKOS/OS/K1215A-TRACE: CHILD-OWNER-CHECKED"); let request = process::Spawn {handles: 3, code_entry: guest::CODE, user_stack_top: guest::STACK_TOP}; let ticket = table.begin(request).unwrap_or_else(|_| park()); write_line("TURKOS/OS/K1215A-TRACE: CHILD-BEGIN"); let ticket = table.prepare(ticket).ok().unwrap_or_else(|| park()); write_line("TURKOS/OS/K1215A-TRACE: CHILD-PREPARED"); let child = table.publish(ticket).ok().unwrap_or_else(|| park()); write_line("TURKOS/OS/K1215A-TRACE: CHILD-PUBLISH-COMMITTED"); if table.record(child).map(|r| r.parent) != Ok(Some(parent.pid)) || table.snapshot().published != 2 { park(); } child }; if foreground_probe { let key = turkos_os_shell_foreground::Pid(child.generation().wrapping_add(1)); if foreground.launch(&mut OsK1275Published {key}) != Ok(key) || foreground.owner() != Some(key) { park(); } write_line("TURKOS/OS/K1275F-TRACE: FOREGROUND-OWNER-ACQUIRED"); } parent.child = Some(child); write_line("TURKOS/OS/K1215A-TRACE: SHELL-CHILD-PUBLISHED"); let saved_active = unsafe { read_volatile(core::ptr::addr_of!(OS_K1215A_ACTIVE)) }; let saved_user_ttbr = unsafe { read_volatile(core::ptr::addr_of!(OS_K1215A_USER_TTBR)) }; let saved_trap_ttbr = unsafe { read_volatile(core::ptr::addr_of!(OS_K1215A_TRAP_TTBR)) }; let saved_frame = unsafe { read_volatile(core::ptr::addr_of!(OS_K1215A_KERNEL_FRAME)) }; if saved_active != parent_ptr as u64 || saved_frame == 0 || saved_trap_ttbr != saved_user_ttbr { park(); } let stack_top = { let table = unsafe { &mut *table_ptr }; if unsafe { table.release_actual_current_to_ready() }.is_err() { park(); } table.landing_stack_from_suspended_parent(parent.pid, child) .unwrap_or_else(|_| park()).1 }; unsafe { write_volatile(core::ptr::addr_of_mut!(OS_K1215A_CASE), 1); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_RESULT), None); } unsafe extern "C" { fn __os_k1215a_enter_el0_process_stack( table: *mut u8, pid: *const u8, stack_top: u64, kernel_root: u64) -> u64; } let status = unsafe { __os_k1215a_enter_el0_process_stack( parent.table, (&child as *const process::ProcessId).cast(), stack_top, kernel_root) }; if status != 0 { park(); } unsafe { write_volatile(core::ptr::addr_of_mut!(OS_K1215A_ACTIVE), saved_active); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_KERNEL_ROOT), kernel_root); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_USER_TTBR), saved_user_ttbr); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_TRAP_TTBR), saved_trap_ttbr); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_KERNEL_FRAME), saved_frame); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_CASE), 0); } let table = unsafe { &mut *table_ptr }; if unsafe { table.register_actual_landing(parent.pid) }.is_err() { park(); } let observed = unsafe { read_volatile(core::ptr::addr_of!(OS_K1215A_RESULT)) } .unwrap_or_else(|| park()); if observed != process::Outcome::Exited(42) || table.record(child).map(|r| r.outcome) != Ok(Some(observed)) || table.record(parent.pid).map(|r| r.resources.state) != Ok(turkos_kernel::runtime::process_threads::State::Running) || table.snapshot().zombies != 1 { park(); } let outcome = if foreground_probe { let key = turkos_os_shell_foreground::Pid(child.generation().wrapping_add(1)); let before_wait = table.snapshot(); let mut adapter = OsK1275Wait {table, child, key, busy_once: true}; if foreground.collect(&mut adapter) != Err(turkos_os_shell_foreground::Error::Wait( turkos_os_shell_foreground::Cause::Busy)) || foreground.owner() != Some(key) || adapter.table.snapshot() != before_wait { park(); } write_line("TURKOS/OS/K1275F-TRACE: WAIT-BUSY-OWNER-RETAINED"); if foreground.collect(&mut adapter) != Ok(turkos_os_shell_foreground::Outcome::Exited(42)) || foreground.owner().is_some() { park(); } write_line("TURKOS/OS/K1275F-TRACE: FOREGROUND-CHILD-REAPED"); process::Outcome::Exited(42) } else { table.wait_child_outcome(child).unwrap_or_else(|_| park()) }; if outcome != observed || table.snapshot().published != 1 || table.snapshot().zombies != 0 { park(); } let frame = unsafe { &mut *frame_ptr }; frame.x[0] = 42; frame.x[1] = 0; parent.calls = 2; if unsafe { read_volatile(core::ptr::addr_of!(OS_K1270_DISPATCH_PROBE)) || read_volatile(core::ptr::addr_of!(OS_K1280_INPUT_PROBE)) } { write_line("TURKOS/OS/K1215A-TRACE: SHELL-RESUMES-AFTER-CHILD"); } else { write_line("TURKOS/OS/K1215A-TRACE: SHELL-RESUMES-AFTER-ENOMEM"); } 0 } #[unsafe(no_mangle)] unsafe extern "C" fn __os_k1215a_el0_process_body( table: *mut u8, pid: *const u8, kernel_root: u64, ) -> u64 { write_line("TURKOS/OS/K1215A-TRACE: BODY-ENTRY"); use turkos_kernel::runtime::process_table as process; let table_ptr = table.cast::>(); let pid = unsafe { *pid.cast::() }; if unsafe { (&mut *table_ptr).register_actual_landing(pid) }.is_err() { park(); } write_line("TURKOS/OS/K1215A-TRACE: BODY-LANDED"); let result = (|| -> Result<(), &'static str> { let launch = unsafe { &*table_ptr }.current_launch(pid) .map_err(|_| "exit-launch-owner")?; if launch.kernel_root != kernel_root || launch.user_asid == 0 || launch.user_root == kernel_root || launch.user_root == 0 { return Err("exit-launch-root"); } let case = unsafe { read_volatile(core::ptr::addr_of!(OS_K1215A_CASE)) } as usize; if case >= 2 { return Err("exit-case"); } let old_vbar: u64; unsafe { asm!("mrs {vbar}, VBAR_EL1", vbar=out(reg) old_vbar, options(nomem, nostack, preserves_flags)); } let mut episode = OsK1215AEl0Episode {table, pid, launch, case, calls: 0, waits: 0, allocs: 0, frees: 0, io_calls: 0, compat_queries: 0, startup_queries: 0, restart_queries: 0, shell_words_queries: 0, shell_dispatch_queries: 0, shell_input_queries: 0, handle_live: false, handle_closes: 0, stale_rejected: false, quota_denied: false, child: None, old_vbar, outcome: None, cat_files_closed: 0, cat_negative: 0, cat_fd: 0, cat_written: 0, cat_eof: false}; let user_ttbr = launch.user_root | ((launch.user_asid as u64) << 48); unsafe { write_volatile(core::ptr::addr_of_mut!(OS_K1215A_KERNEL_ROOT), kernel_root); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_USER_TTBR), user_ttbr); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_TRAP_TTBR), 0); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_KERNEL_FRAME), 0); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_ACTIVE), (&mut episode as *mut OsK1215AEl0Episode) as u64); } unsafe extern "C" { fn __os_k1215a_enter_el0(user_ttbr: u64, pc: u64, sp: u64, spsr: u64); } unsafe { __os_k1215a_enter_el0(user_ttbr, launch.user_pc, launch.user_sp, launch.user_spsr); } write_line("TURKOS/OS/K1215A-TRACE: BODY-USER-RETURNED"); unsafe { asm!("msr VBAR_EL1, {vbar}", "isb", vbar=in(reg) episode.old_vbar, options(nostack, preserves_flags)); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_ACTIVE), 0); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_KERNEL_ROOT), 0); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_USER_TTBR), 0); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_TRAP_TTBR), 0); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_KERNEL_FRAME), 0); } write_str("TURKOS/OS/K1215A-TRACE: RETURN OUTCOME=0x"); write_hex(episode.outcome.is_some() as usize); write_str(" TTBR=0x"); write_hex(os_k1120_registers().ttbr as usize); write_str(" ROOT=0x"); write_hex(kernel_root as usize); write_str(" RECORD=0x"); write_hex((unsafe { &*table_ptr }.record(pid).map(|r| r.outcome) == Ok(episode.outcome)) as usize); write_line(""); if episode.outcome.is_none() || os_k1120_registers().ttbr != kernel_root || unsafe { &*table_ptr }.record(pid).map(|r| r.outcome) != Ok(episode.outcome) { return Err("exit-completion-owner"); } unsafe { write_volatile(core::ptr::addr_of_mut!(OS_K1215A_RESULT), episode.outcome); } Ok(()) })(); // exit_current/fault_current already made the thread Dead and cleared current. match result { Ok(()) => 0, Err(error) => { unsafe { write_volatile(core::ptr::addr_of_mut!(OS_K1215A_EL0_ERROR), Some(error)); } 1 } } } static mut OS_K1215A_CASE: u64 = 0; static mut OS_K1215A_RESULT: Option = None; #[inline(never)] fn os_k1215a_el0_probe( memory: &mut OsK660Memory, tables: &mmu::Tables, ) -> Result<(), &'static str> { write_line("TURKOS/OS/K1215A-TRACE: PROBE-ENTRY"); use turkos_kernel::runtime::address_spaces as spaces; use turkos_kernel::runtime::process_guest as guest; use turkos_kernel::runtime::process_image_recipe::{Recipe, TrustedImage}; use turkos_kernel::runtime::process_table as process; let before = memory.allocator.os_authority().audit() .map_err(|_| "exit-before-inventory")?; let hardware = OsK1120Hardware { tables }; let registers = os_k1120_registers(); let guard = core::ptr::addr_of!(OS_K1105_WORK_STACK) as u64; let binding = guest::StackBinding { owner: guard, low: guard + 4096 + 16, high: guard + 4096 + 262144 - 16, spsel: registers.spsel }; let gate = unsafe { guest::Gate::new(&hardware, binding) } .map_err(|_| "shell-primary-gate")?; let authority = guest::AuthorityCell::new(memory.allocator.os_authority_mut()); let store = guest::FrameStore::new(0x1210_5, &authority, &gate) .map_err(|_| "shell-frame-store")?; write_line("TURKOS/OS/K1215A-TRACE: FRAME-STORE"); let frame_baseline = store.snapshot().map_err(|_| "shell-frame-baseline")?; let trusted = unsafe { TrustedImage::from_kernel(&OS_K1215A_USER_ELF, OS_K1215A_USER_ELF.len()) }.map_err(|_| "shell-trusted-image")?; write_line("TURKOS/OS/K1215A-TRACE: TRUSTED-IMAGE"); let recipe = Recipe::new(trusted, &[b"runtime", b"alloc"], &[]) .map_err(|_| "shell-image-recipe")?; write_line("TURKOS/OS/K1215A-TRACE: RECIPE"); let image = OsK1120PreparedImage(recipe); let config = spaces::Configuration::from_registers(5, registers.tcr) .map_err(|_| "shell-space-config")?; write_line("TURKOS/OS/K1215A-TRACE: INSTALL-START"); let table_ptr = os_k1105_install_table(&gate, &authority, &store, &image, config)?; write_line("TURKOS/OS/K1215A-TRACE: TABLE-INSTALLED"); let table = unsafe { &mut *table_ptr }; let format_probe = unsafe { read_volatile(core::ptr::addr_of!(OS_K1220_FORMAT_PROBE)) }; if format_probe { if OS_K1220_HOST_MACHO[..4] != [0xcf, 0xfa, 0xed, 0xfe] || table.snapshot() != process::Snapshot::default() { return Err("macho-preflight-input"); } let before_table = table.snapshot(); let before_frames = store.snapshot().map_err(|_| "macho-frame-before")?; let before_physical = authority.observe(&gate, |allocator| allocator.audit()) .map_err(|_| "macho-authority-before")? .map_err(|_| "macho-physical-before")?; let macho = unsafe { TrustedImage::from_kernel(&OS_K1220_HOST_MACHO, OS_K1220_HOST_MACHO.len()) }.map_err(|_| "macho-trusted-input")?; if Recipe::new(macho, &[b"runtime", b"alloc"], &[]).is_ok() || table.snapshot() != before_table || store.snapshot() != Ok(before_frames) || authority.observe(&gate, |allocator| allocator.audit()) .map_err(|_| "macho-authority-after")? .map_err(|_| "macho-physical-after")? != before_physical { return Err("macho-format-rejection"); } write_line("TURKOS/OS/K1220M-EL0: MACHO-REJECTED-BEFORE-PID-AND-PAGES"); } let request = process::Spawn { handles: 3, code_entry: guest::CODE, user_stack_top: guest::STACK_TOP }; let reservation = table.begin(request).map_err(|_| "shell-begin")?; let prepared = table.prepare(reservation).map_err(|_| "shell-prepare")?; let shell = table.publish(prepared).map_err(|_| "shell-publish")?; write_line("TURKOS/OS/K1215A-TRACE: SHELL-PUBLISHED"); let reaper_probe = unsafe { read_volatile(core::ptr::addr_of!(OS_K1260_REAPER_PROBE)) }; let shell_key = turkos_os_init_reaper::Pid(shell.generation().wrapping_add(1)); let mut reaper = turkos_os_init_reaper::Reaper::<1>::new(); if reaper_probe { reaper.track(shell_key).map_err(|_| "init-reaper-track")?; if reaper.owned() != 1 || reaper.ready() != 0 { return Err("init-reaper-track-state"); } write_line("TURKOS/OS/K1260R-TRACE: INIT-TRACKS-SHELL"); } unsafe { write_volatile(core::ptr::addr_of_mut!(OS_K1215A_CASE), 0); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_RESULT), None); write_volatile(core::ptr::addr_of_mut!(OS_K1215A_INIT_PID), Some(shell)); } let (_, stack_top) = table.landing_stack(shell).map_err(|_| "shell-stack")?; unsafe extern "C" { fn __os_k1215a_enter_el0_process_stack( table: *mut u8, pid: *const u8, stack_top: u64, kernel_root: u64) -> u64; } let status = unsafe { __os_k1215a_enter_el0_process_stack( table_ptr.cast(), (&shell as *const process::ProcessId).cast(), stack_top, tables.root) }; write_line("TURKOS/OS/K1215A-TRACE: SHELL-RETURNED"); if status != 0 { return Err(unsafe { read_volatile(core::ptr::addr_of!(OS_K1215A_EL0_ERROR)) } .unwrap_or("shell-process-body")); } let observed = unsafe { read_volatile(core::ptr::addr_of!(OS_K1215A_RESULT)) } .ok_or("shell-missing-result")?; if observed != process::Outcome::Exited(0) || table.record(shell).map(|r| r.outcome) != Ok(Some(observed)) || table.snapshot().zombies != 1 || table.snapshot().published != 1 { return Err("shell-zombie-result"); } if reaper_probe { reaper.observe_exit(shell_key).map_err(|_| "init-reaper-observe")?; let before_wait = table.snapshot(); let mut adapter = OsK1260Wait {table, shell, key: shell_key, fail_once: true}; if reaper.reap_next(&mut adapter) != Err(turkos_os_init_reaper::Error::Wait( turkos_os_init_reaper::Cause::Busy)) || reaper.owned() != 1 || reaper.ready() != 1 || adapter.table.snapshot() != before_wait { return Err("init-reaper-failed-wait-retention"); } write_line("TURKOS/OS/K1260R-TRACE: WAIT-ERROR-OWNER-RETAINED"); if reaper.reap_next(&mut adapter) != Ok(Some((shell_key, turkos_os_init_reaper::Outcome::Exited(0)))) || reaper.owned() != 0 || reaper.ready() != 0 || adapter.table.snapshot() != process::Snapshot::default() { return Err("init-reaper-successful-wait"); } write_line("TURKOS/OS/K1260R-TRACE: INIT-REAPED-SHELL-EXIT0"); } else if table.wait_child_outcome(shell) != Ok(process::Outcome::Exited(0)) || table.snapshot() != process::Snapshot::default() { return Err("shell-reap-result"); } unsafe { write_volatile(core::ptr::addr_of_mut!(OS_K1215A_INIT_PID), None); } let backend = os_k1105_finish_table(table_ptr)?; if backend.inventory().map_err(|_| "shell-owner-inventory")? != [0, 0, 0, before.live_pages] { return Err("shell-owner-leak"); } drop(backend); if gate.faulted() || store.snapshot() != Ok(frame_baseline) || authority.observe(&gate, |allocator| allocator.audit()) .map_err(|_| "shell-after-gate")? .map_err(|_| "shell-after-inventory")? != before { return Err("shell-physical-rollback"); } if unsafe { read_volatile(core::ptr::addr_of!(OS_K1290_CAT_PROBE)) } { write_line("TURKOS/OS/K1215A-EL0: CHILD-EXIT42 SHELL-EXIT0 OWNER=RELEASED"); } else if unsafe { read_volatile(core::ptr::addr_of!(OS_K1270_DISPATCH_PROBE)) || read_volatile(core::ptr::addr_of!(OS_K1280_INPUT_PROBE)) } { write_line("TURKOS/OS/K1215A-EL0: CHILD-EXIT42 SHELL-ALLOC-FREE VERSION1 SHELL-EXIT0 OWNER=RELEASED"); } else { write_line("TURKOS/OS/K1215A-EL0: CHILD-THREE-HEAP-PAGES ENOMEM SHELL-ALLOC-FREE VERSION1 SHELL-EXIT0 OWNER=RELEASED"); } write_line("TURKOS/OS/K1215: PASS"); if format_probe { write_line("TURKOS/OS/K1220M-EL0: MACHO-REJECTED HEALTHY-EL0-PROGRAM-EXIT42 SHELL-EXIT0 OWNER=RELEASED"); write_line("TURKOS/OS/K1220: PASS"); } if unsafe { read_volatile(core::ptr::addr_of!(OS_K1225_TYPED_PROBE)) } { write_line("TURKOS/OS/K1225T-EL0: TYPED-NATIVE-SVC CHILD-ENOMEM FREE SHELL-EXIT0 OWNER=RELEASED"); write_line("TURKOS/OS/K1225: PASS"); } if unsafe { read_volatile(core::ptr::addr_of!(OS_K1230_IO_PROBE)) } { write_line("TURKOS/OS/K1230I-EL0: THREE-PART-SERIAL ZERO-RETURN BUDGET-EXCEEDED OWNER=RELEASED"); write_line("TURKOS/OS/K1230: PASS"); } if unsafe { read_volatile(core::ptr::addr_of!(OS_K1235_HANDLE_PROBE)) } { write_line("TURKOS/OS/K1235H-EL0: MOVE DROP-CLOSE-ONCE SECOND-CLOSE-STALE OWNER=RELEASED"); write_line("TURKOS/OS/K1235: PASS"); } if unsafe { read_volatile(core::ptr::addr_of!(OS_K1240_COMPAT_PROBE)) } { write_line("TURKOS/OS/K1240C-EL0: V1-ACCEPTED V2-REJECTED BEFORE-HEAP OWNER=RELEASED"); write_line("TURKOS/OS/K1240: PASS"); } if unsafe { read_volatile(core::ptr::addr_of!(OS_K1245_MANIFEST_PROBE)) } { write_line("TURKOS/OS/K1245M-EL0: VALID-ID IMAGE-ID-NONZERO ABI BUDGET DUPLICATE-REJECTED OWNER=RELEASED"); write_line("TURKOS/OS/K1245: PASS"); } if unsafe { read_volatile(core::ptr::addr_of!(OS_K1250_STARTUP_PROBE)) } { write_line("TURKOS/OS/K1250S-EL0: DEPENDENCY-ORDER FAILURE RETAIN-AND-RETRY REVERSE-ROLLBACK OWNER=RELEASED"); write_line("TURKOS/OS/K1250: PASS"); } if unsafe { read_volatile(core::ptr::addr_of!(OS_K1255_RESTART_PROBE)) } { write_line("TURKOS/OS/K1255R-EL0: RETRY-2 BACKOFF STOP-ERROR-RETAINED EXHAUSTED OWNER=RELEASED"); write_line("TURKOS/OS/K1255: PASS"); } if reaper_probe { write_line("TURKOS/OS/K1260R-EL0: INIT-TRACK WAIT-ERROR-RETAINED SHELL-EXIT0-REAPED OWNER=RELEASED"); write_line("TURKOS/OS/K1260: PASS"); } if unsafe { read_volatile(core::ptr::addr_of!(OS_K1265_WORDS_PROBE)) } { write_line("TURKOS/OS/K1265W-EL0: QUOTED-THREE-WORDS SHELL-VERSION-BEFORE-CHILD OWNER=RELEASED"); write_line("TURKOS/OS/K1265: PASS"); } if unsafe { read_volatile(core::ptr::addr_of!(OS_K1270_DISPATCH_PROBE)) } { write_line("TURKOS/OS/K1270D-EL0: EXTERNAL-RUN BUILTIN-HELP CHILD-EXIT42 OWNER=RELEASED"); write_line("TURKOS/OS/K1270: PASS"); } if unsafe { read_volatile(core::ptr::addr_of!(OS_K1275_FOREGROUND_PROBE)) } { write_line("TURKOS/OS/K1275F-EL0: FOREGROUND-CHILD42 WAIT-BUSY-RETAINED REAPED OWNER=RELEASED"); write_line("TURKOS/OS/K1275: PASS"); } if unsafe { read_volatile(core::ptr::addr_of!(OS_K1280_INPUT_PROBE)) } { write_line("TURKOS/OS/K1280I-EL0: SYNTHETIC-CANCEL STALE-REJECTED NEW-LINE-COMMITTED CHILD-EXIT42 OWNER=RELEASED"); write_line("TURKOS/OS/K1280: PASS"); } if unsafe { read_volatile(core::ptr::addr_of!(OS_K1285_ECHO_PROBE)) } { write_line("TURKOS/OS/K1285E-EL0: ECHO-12-BYTES SIX-SHORT-WRITES CHILD-EXIT42 OWNER=RELEASED"); write_line("TURKOS/OS/K1285: PASS"); } Ok(()) }