// 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; 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, handle_live: bool, handle_closes: u8, stale_rejected: bool, quota_denied: bool, child: Option, old_vbar: u64, outcome: Option, } #[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(()) } #[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 }; 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 || frame.interrupted_sp != address + os_k920_exception::FRAME_BYTES as u64 || episode.outcome.is_some() { park(); } if frame.esr != abi::SVC_ESR { park(); } 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 { if episode.calls != 2 || episode.allocs != 0 || frame.elr != launch.user_pc + 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 svc_return = 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 { if episode.calls != 2 || episode.allocs != 1 || episode.frees != 0 || address != 0x80004000 || frame.elr != launch.user_pc + 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 svc_return = 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) => { if frame.elr != launch.user_pc + 0x78 || episode.case == 0 && (code != 0 || episode.calls != 2 || episode.allocs != 1 || episode.frees != 1) || episode.case == 1 && (code != 42 || episode.calls != 1 || 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_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 episode.case == 0 { if let abi::Call::RunChild(1) = call { if episode.calls != 1 || frame.elr != launch.user_pc + 0xb0 { park(); } return os_k1215a_run_child(active as *mut OsK1215AEl0Episode, pointer, kernel_root); } if call == abi::Call::Version { if episode.calls != 2 || episode.allocs != 1 || episode.frees != 1 || frame.elr != launch.user_pc + 0x118 { park(); } frame.x[0] = abi::ABI_VERSION; 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 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 }; 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 = 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; 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, handle_live: false, handle_closes: 0, stale_rejected: false, quota_denied: false, child: None, old_vbar, outcome: None}; 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"); 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 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"); } 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"); } Ok(()) }