// Mode 16 executes the trusted K1135 ELF from its retained ProcessTable root. // A single masked CPU owns all globals from activation until the fifth SVC. static mut OS_K1135_EL0_ERROR: Option<&'static str> = None; #[unsafe(no_mangle)] static mut OS_K1135_ACTIVE: u64 = 0; #[unsafe(no_mangle)] static mut OS_K1135_KERNEL_ROOT: u64 = 0; #[unsafe(no_mangle)] static mut OS_K1135_USER_TTBR: u64 = 0; #[unsafe(no_mangle)] static mut OS_K1135_TRAP_TTBR: u64 = 0; #[unsafe(no_mangle)] static mut OS_K1135_KERNEL_FRAME: u64 = 0; struct OsK1135El0Episode { table: *mut u8, pid: turkos_kernel::runtime::process_table::ProcessId, launch: turkos_kernel::runtime::process_table::GuestLaunch, calls: u64, write_budget: u64, old_vbar: u64, } #[inline(never)] fn os_k1135_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 + 131072; 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("el0-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(|_| "el0-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_K1135_EL0_ERROR), None); } unsafe extern "C" { fn __os_k1135_el0_on_stack(memory: *mut u8, tables: *const u8) -> u64; } let status = unsafe { __os_k1135_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(|_| "el0-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("el0-work-stack-return"); } if status != 0 { return Err(unsafe { read_volatile(core::ptr::addr_of!(OS_K1135_EL0_ERROR)) } .unwrap_or("el0-work-stack-body")); } Ok(()) } #[unsafe(no_mangle)] unsafe extern "C" fn __os_k1135_el0_body(memory: *mut u8, tables: *const u8) -> u64 { let result = os_k1135_el0_probe( unsafe { &mut *memory.cast::() }, unsafe { &*tables.cast::() }); match result { Ok(()) => 0, Err(error) => { unsafe { write_volatile(core::ptr::addr_of_mut!(OS_K1135_EL0_ERROR), Some(error)); } 1 } } } #[unsafe(no_mangle)] extern "C" fn os_k1135_dispatch(pointer: *mut os_k920_exception::Frame) -> u64 { use turkos_kernel::runtime::process_table as process; use turkos_kernel::runtime::syscall_abi as abi; write_line("TURKOS/OS/K1135-TRACE: DISPATCH"); let kernel_root = unsafe { read_volatile(core::ptr::addr_of!(OS_K1135_KERNEL_ROOT)) }; let user_ttbr = unsafe { read_volatile(core::ptr::addr_of!(OS_K1135_USER_TTBR)) }; let trap_ttbr = unsafe { read_volatile(core::ptr::addr_of!(OS_K1135_TRAP_TTBR)) }; let active = unsafe { read_volatile(core::ptr::addr_of!(OS_K1135_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(); } write_line("TURKOS/OS/K1135-TRACE: ROOT"); let episode = unsafe { &mut *(active as *mut OsK1135El0Episode) }; let table = unsafe { &*episode.table.cast::>() }; let launch = table.current_launch(episode.pid).unwrap_or_else(|_| park()); write_line("TURKOS/OS/K1135-TRACE: OWNER"); 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(); } write_line("TURKOS/OS/K1135-TRACE: STACK"); let frame = unsafe { &mut *pointer }; write_str("TURKOS/OS/K1135-TRACE: ESR=0x"); write_hex(frame.esr as usize); write_str(" ELR=0x"); write_hex(frame.elr as usize); write_line(""); let expected_elr = [0xe8u64, 0xe8, 0xe8, 0xb8, 0xcc] .get(episode.calls as usize).copied().unwrap_or_else(|| park()); if frame.validate_header().is_err() || frame.vector_slot != 8 || frame.esr != abi::SVC_ESR || frame.spsr & 0x3ff != launch.user_spsr || frame.sp_el0 != launch.user_sp || frame.interrupted_sp != address + os_k920_exception::FRAME_BYTES as u64 || frame.elr != launch.user_pc + expected_elr { park(); } write_line("TURKOS/OS/K1135-TRACE: FRAME"); let mut abi_frame = turkos_os_exceptions::exceptions::Frame::EMPTY; abi_frame.x = frame.x; if frame.x[7] != abi::ABI_VERSION { park(); } if episode.calls == 4 { if frame.x[8] != abi::CALL_VERSION || abi::decode_call(&abi_frame) != Ok(abi::Call::Version) { park(); } for (index, expected) in [1u64, 2, 3, 4, 5, 0].into_iter().enumerate() { if unsafe { read_volatile((launch.data_frame + index as u64 * 8) as *const u64) } != expected { park(); } } episode.calls = 5; write_line("TURKOS/OS/K1135-TRACE: COMPLETE"); return 1; } let resources_before = table.snapshot(); let result = if episode.calls == 3 { if frame.x[8] != abi::CALL_VERSION || abi::decode_call(&abi_frame) != Ok(abi::Call::Version) { park(); } abi::AbiResult::Ok(abi::Success::new(abi::ABI_VERSION).unwrap()) } else { if frame.x[8] != abi::CALL_WRITE || frame.x[2] != 8 { park(); } let decoded = abi::decode_call(&abi_frame); match episode.calls { 0 => { let Ok(abi::Call::Write(write)) = decoded else { park(); }; if write.fd() != 3 || write.address() != 0x8000_1020 || write.bytes() != 8 { park(); } abi::AbiResult::Err(abi::Errno::BadFd) } 1 => { if frame.x[0] != 1 || frame.x[1] != u64::MAX || decoded != Err(abi::Errno::Fault) { park(); } abi::AbiResult::Err(abi::Errno::Fault) } 2 => { let Ok(abi::Call::Write(write)) = decoded else { park(); }; if write.fd() != 1 || write.address() != 0x8000_1020 || write.bytes() != 8 || episode.write_budget != 0 || unsafe { read_volatile((launch.data_frame + 32) as *const u64) } != 0 { park(); } // The bounded diagnostic service refuses preparation before // any copy or output while its retained budget is exhausted. abi::AbiResult::Err(abi::Errno::NoMem) } _ => park(), } }; if table.snapshot() != resources_before || table.current_launch(episode.pid) != Ok(launch) { park(); } frame.x[0] = result.encode(); episode.calls += 1; write_line("TURKOS/OS/K1135-TRACE: RETURN"); 0 } #[unsafe(no_mangle)] unsafe extern "C" fn __os_k1135_el0_process_body( table: *mut u8, pid: *const u8, kernel_root: u64, ) -> u64 { 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(); } let result = (|| -> Result<(), &'static str> { let launch = unsafe { &*table_ptr }.current_launch(pid) .map_err(|_| "el0-launch-owner")?; write_line("TURKOS/OS/K1135-TRACE: LANDED"); if launch.kernel_root != kernel_root || launch.user_asid == 0 || launch.user_root == kernel_root || launch.user_root == 0 { return Err("el0-launch-root"); } let old_vbar: u64; unsafe { asm!("mrs {vbar}, VBAR_EL1", vbar=out(reg) old_vbar, options(nomem, nostack, preserves_flags)); } let mut episode = OsK1135El0Episode {table, pid, launch, calls: 0, write_budget: 0, old_vbar}; let user_ttbr = launch.user_root | ((launch.user_asid as u64) << 48); unsafe { write_volatile(core::ptr::addr_of_mut!(OS_K1135_KERNEL_ROOT), kernel_root); write_volatile(core::ptr::addr_of_mut!(OS_K1135_USER_TTBR), user_ttbr); write_volatile(core::ptr::addr_of_mut!(OS_K1135_TRAP_TTBR), 0); write_volatile(core::ptr::addr_of_mut!(OS_K1135_KERNEL_FRAME), 0); write_volatile(core::ptr::addr_of_mut!(OS_K1135_ACTIVE), (&mut episode as *mut OsK1135El0Episode) as u64); } unsafe extern "C" { fn __os_k1135_enter_el0(user_ttbr: u64, pc: u64, sp: u64, spsr: u64); } unsafe { __os_k1135_enter_el0(user_ttbr, launch.user_pc, launch.user_sp, launch.user_spsr); } write_line("TURKOS/OS/K1135-TRACE: KERNEL-RESUME"); 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_K1135_ACTIVE), 0); write_volatile(core::ptr::addr_of_mut!(OS_K1135_KERNEL_ROOT), 0); write_volatile(core::ptr::addr_of_mut!(OS_K1135_USER_TTBR), 0); write_volatile(core::ptr::addr_of_mut!(OS_K1135_TRAP_TTBR), 0); write_volatile(core::ptr::addr_of_mut!(OS_K1135_KERNEL_FRAME), 0); } if episode.calls != 5 || os_k1120_registers().ttbr != kernel_root || unsafe { &*table_ptr }.current_launch(pid) != Ok(launch) { return Err("el0-completion-owner"); } Ok(()) })(); if unsafe { (&mut *table_ptr).release_actual_current_to_ready() }.is_err() { park(); } match result { Ok(()) => 0, Err(error) => { unsafe { write_volatile(core::ptr::addr_of_mut!(OS_K1135_EL0_ERROR), Some(error)); } 1 } } } #[inline(never)] fn os_k1135_el0_probe( memory: &mut OsK660Memory, tables: &mmu::Tables, ) -> Result<(), &'static str> { 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(|_| "el0-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 + 131072 - 16, spsel: registers.spsel }; let gate = unsafe { guest::Gate::new(&hardware, binding) } .map_err(|_| "el0-primary-gate")?; let authority = guest::AuthorityCell::new(memory.allocator.os_authority_mut()); let store = guest::FrameStore::new(0x1136, &authority, &gate) .map_err(|_| "el0-frame-store")?; let trusted = unsafe { TrustedImage::from_kernel(&OS_K1135_USER_ELF, OS_K1135_USER_ELF.len()) } .map_err(|_| "el0-trusted-image")?; let recipe = Recipe::new(trusted, &[b"init"], &[]) .map_err(|_| "el0-image-recipe")?; let image = OsK1120PreparedImage(recipe); let config = spaces::Configuration::from_registers(5, registers.tcr) .map_err(|_| "el0-space-config")?; let table_ptr = os_k1105_install_table(&gate, &authority, &store, &image, config)?; let table = unsafe { &mut *table_ptr }; let request = process::Spawn { handles: 3, code_entry: guest::CODE, user_stack_top: guest::STACK_TOP }; let reservation = table.begin(request).map_err(|_| "el0-begin")?; let prepared = table.prepare(reservation).map_err(|_| "el0-prepare")?; let pid = table.publish(prepared).map_err(|_| "el0-publish")?; write_line("TURKOS/OS/K1135-TRACE: PUBLISHED"); let (_, stack_top) = table.landing_stack(pid).map_err(|_| "el0-landing-stack")?; unsafe extern "C" { fn __os_k1135_enter_el0_process_stack( table: *mut u8, pid: *const u8, stack_top: u64, kernel_root: u64) -> u64; } let status = unsafe { __os_k1135_enter_el0_process_stack( table_ptr.cast(), (&pid as *const process::ProcessId).cast(), stack_top, tables.root) }; if status != 0 { return Err(unsafe { read_volatile(core::ptr::addr_of!(OS_K1135_EL0_ERROR)) } .unwrap_or("el0-process-body")); } table.terminate_child(pid, 0).map_err(|_| "el0-terminate")?; if table.wait_child(pid) != Ok(0) || table.snapshot() != process::Snapshot::default() { return Err("el0-reap"); } let backend = os_k1105_finish_table(table_ptr)?; let inventory = backend.inventory().map_err(|_| "el0-owner-inventory")?; if inventory != [0, 0, 0, before.live_pages] { return Err("el0-owner-leak"); } drop(backend); if gate.faulted() || authority.observe(&gate, |allocator| allocator.audit()) .map_err(|_| "el0-after-gate")? .map_err(|_| "el0-after-inventory")? != before { return Err("el0-physical-rollback"); } write_line("TURKOS/OS/K1135-EL0: FIVE-SVC=OK EBADF=OK EFAULT=OK ENOMEM=OK WRAPPER=TAGGED ERET=4 OWNER=RELEASED"); write_line("TURKOS/OS/K1135: PASS"); Ok(()) }