ASELSANMicrokernel
S379 · SOURCE-BOUND GATE EVIDENCE

S379 · EL0 IPC call-timeout production writer guard integration

tam syscall Rust öğesi + exact acquire→handoff odağı → tam scheduler release/rejoin Rust öğesi → S247 guard modülü → Operations-bound focused test Bu sayfa yalnız S379 kapısına aittir; komşu kapıların kaynakları bu kabulün içine katılmaz.

S379Production writer guardOperations id exactsource SHA exacttest target exact

operation: g8l-s379-el0-ipc-call-timeout-writer-guard-integration-partial

production · S247 guard · focused test · Operations · 5 exact excerpt

sequence-bound=true · implementation-bound=true
01 · Test edilen uygulama/model kodu

Kapının yürüttüğü gerçek kaynak

tam Rust öğesiL293–L408kapı odağı L362–L385
kernel/src/arch/aarch64/exceptions.rs::handle_ipc_call_timeout
Tam kapsayıcı Rust öğesi gösterilir; vurgulu blok yalnız S379 exact production writer üyeliği sınırıdır. Komşu kod, guard kapsamı iddiası değildir.

/// S144 opt-in deadline-bearing CALL. Keeping this separate from the frozen
/// SYS_IPC_CALL arm ensures legacy callers never expose an unspecified x6 as
/// timeout policy.
fn handle_ipc_call_timeout(ctx: &mut ExceptionContext, user_sp: u64) {
    let target_id = ctx.gpr[0];
    let label = ctx.gpr[1];
    let mr0 = ctx.gpr[2];
    let mr1 = ctx.gpr[3];
    let mr2 = ctx.gpr[4];
    let mr3 = ctx.gpr[5];
    let timeout_ticks = ctx.gpr[6];
    let now_tick = TICKS.load(Ordering::Acquire);
    if crate::ipc_wait::TickDeadline::try_after(now_tick, timeout_ticks).is_err() {
        set_ipc_error(ctx, IpcError::InvalidDeadline);
        return;
    }

    let current_id = crate::task::current_task_id().unwrap_or(0);
    kprintln!(
        "[K2-S144] SYS_IPC_CALL_TIMEOUT task={} target={} timeout_ticks={} now={}",
        current_id,
        target_id,
        timeout_ticks,
        now_tick,
    );

    let target_is_normal = crate::ui::capability::ENDPOINT_REGISTRY
        .lock()
        .iter()
        .any(|endpoint| endpoint.id == target_id && !endpoint.is_reply_cap);
    if !target_is_normal {
        set_ipc_error(ctx, IpcError::InvalidCapability);
        return;
    }

    let endpoint_cap = crate::task::current_task_cnode()
        .and_then(|cnode| cnode.lookup_capability_by_id(target_id).copied())
        .filter(|capability| {
            capability.kind == crate::ui::capability::CapabilityKind::Endpoint
                && capability
                    .rights
                    .contains(crate::ui::capability::CapabilityRights::ENDPOINT_SEND)
        });
    let Some(endpoint_cap) = endpoint_cap else {
        set_ipc_error(ctx, IpcError::InvalidCapability);
        return;
    };

    let msg = crate::ui::capability::IpcMessage {
        label,
        badge: current_id,
        data: [mr0, mr1, mr2, mr3],
    };
    let reply_cap = match crate::ui::mint_reply_endpoint_for_call(current_id, target_id) {
        Ok(capability) => capability,
        Err(error) => {
            kprintln!(
                "[K2-S144] timeout reply mint rejected task={}: {}",
                current_id,
                error
            );
            set_ipc_error(ctx, IpcError::InvalidCapability);
            return;
        }
    };

    #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
    let s379_irq_guard = crate::arch::aarch64::IrqGuard::new();
    #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
    let s379_writer_access = crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s379_el0_ipc_call_timeout_writer_guard_integration::acquire_s379_production_scheduler_writer_access()
        .unwrap_or_else(|error| {
            panic!(
                "S379 EL0 IPC call-timeout scheduler writer guard failed closed: {:?}",
                error
            )
        });

    let commit = unsafe {
        let scheduler = &mut *core::ptr::addr_of_mut!(crate::task::scheduler::SCHEDULER);
        #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
        let commit = scheduler.ipc_call_timeout_commit_and_park(
            ctx,
            user_sp,
            target_id,
            endpoint_cap.generation,
            reply_cap.id,
            reply_cap.generation,
            msg,
            now_tick,
            timeout_ticks,
            s379_irq_guard,
            s379_writer_access,
        );
        #[cfg(not(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5")))]
        let commit = scheduler.ipc_call_timeout_commit_and_park(
            ctx,
            user_sp,
            target_id,
            endpoint_cap.generation,
            reply_cap.id,
            reply_cap.generation,
            msg,
            now_tick,
            timeout_ticks,
        );
        commit
    };
    if let Err(error) = commit {
        let _ = crate::ui::capability::discard_unpublished_reply_endpoint(
            reply_cap.id,
            Some(current_id),
        );
        set_ipc_error(ctx, error);
    }
}
snippet sha256: ebfed35940f7file sha256: 6f3a4c8dbf40focus sha256: 533f21fe7705
02 · Devredilen production üyeliği

Context-switch bırakma ve resume yeniden-katılım kodu

tam Rust öğesiL446–L3588
kernel/src/task/scheduler.rs::ipc_call_timeout_commit_and_park

impl Scheduler {
    pub const fn new() -> Self {
        Self {
            ready_queue: BinaryHeap::new(),
            current_task: None,
            retired_task: None,
            deferred_current_runtime_oom: None,
            ticks_until_preempt: 0,
            min_vruntime: 0,
            ipc_blocked_tasks: spin::Mutex::new(Vec::new()),
        }
    }

    /// Reap the task retired by an earlier context switch.
    ///
    /// User roots remain paired with their non-zero ASID lease until this
    /// later-stack reaper drops the complete page-table owner. The ASID is
    /// returned only after those resources are gone.
    fn reap_retired_task(&mut self) {
        let Some(mut task) = self.retired_task.take() else {
            return;
        };

        let deferred_match = self
            .deferred_current_runtime_oom
            .as_ref()
            .filter(|carrier| carrier.witness.is_none())
            .is_some_and(|carrier| {
                task.id == carrier.binding.task_id
                    && task.runtime_allocation_domain() == Some(carrier.binding.domain)
            });
        if deferred_match {
            let mut carrier = self
                .deferred_current_runtime_oom
                .take()
                .expect("deferred current OOM carrier disappeared");
            let witness = reap_detached_runtime_oom_task(
                task,
                carrier.binding.domain,
                carrier.ipc_lifecycle_closed,
            );
            carrier.witness = Some(witness);
            self.deferred_current_runtime_oom = Some(carrier);
            return;
        }

        if task.is_user && (task.asid == 0 || !task.address_space_quiesced) {
            crate::kprintln!(
                "[K1-LIFECYCLE] quarantine task #{} '{}' without complete address-space quiescence (asid={}); resources intentionally retained",
                task.id,
                task.name,
                task.asid
            );
            core::mem::forget(task);
            return;
        }

        crate::kprintln!(
            "[K1-LIFECYCLE] reaping task #{} '{}' on a later task stack",
            task.id,
            task.name
        );
        unsafe {
            task.release_owned_page_table_root();
        }
        task.owned_user_page_tables.take();
        match crate::mm::address_space::reclaim_owned_user_frames(
            &mut task.owned_user_frames,
            &mut task.runtime_user_frames,
        ) {
            Ok(Some(report)) if report.returned_to_baseline() => crate::kprintln!(
                "[K1-RUNTIME-ELF-RECLAIM] task={} frames={} free={}->{} active_allocations={}->{} BASELINE=PASS",
                task.id,
                report.released_frames,
                report.baseline_free_frames,
                report.observed_free_frames,
                report.baseline_active_allocations,
                report.observed_active_allocations,
            ),
            Ok(Some(report)) if report.exactly_reconciled() => crate::kprintln!(
                "[K1-RUNTIME-ELF-RECLAIM] task={} frames={} free={}->{} active_allocations={}->{} RECONCILED=PASS BASELINE=CONCURRENT",
                task.id,
                report.released_frames,
                report.reclaim_started_free_frames,
                report.observed_free_frames,
                report.reclaim_started_active_allocations,
                report.observed_active_allocations,
            ),
            Ok(Some(_)) => unreachable!("RuntimePmm reclaimer returned an unaudited delta"),
            Ok(None) => {}
            Err(error) => {
                crate::kprintln!(
                    "[K1-RUNTIME-ELF-RECLAIM] task={} BASELINE=FAIL error={:?}; ASID and remaining resources quarantined",
                    task.id,
                    error
                );
                core::mem::forget(task);
                return;
            }
        }

        // Root/intermediate storage is unreachable and the prior TLBI is
        // complete. Only now may a fresh address space acquire this ASID.
        let retired_asid = task.asid;
        if retired_asid != 0 {
            if let Err(error) = crate::mm::address_space::free_asid(retired_asid) {
                crate::kprintln!(
                    "[K1-ASID] final reaper release failed asid={} error={:?}; identifier remains quarantined",
                    retired_asid,
                    error
                );
                core::mem::forget(task);
                return;
            }
            task.asid = 0;
        }
        // `Task` drop now releases its owned kernel/user stack allocations.
        // Raw ELF user stacks have no `OwnedStackAllocation` and are not
        // reconstructed as a Box.
        drop(task);
    }

    /// CFS tarzı weight hesabı (düşük priority = daha yüksek weight = daha yavaş vruntime artışı)
    fn weight_of(priority: u8) -> u64 {
        match priority {
            0 => 1024, // En yüksek öncelik
            1 => 820,
            2 => 655,
            3 => 524,
            4 => 419,
            5 => 335,
            6 => 268,
            7 => 215,
            _ => 128,
        }
    }

    /// Scheduler içinde vruntime güncelleme (CFS-lite)
    fn update_vruntime(&mut self, task: &mut Task, delta_exec: u64) {
        let weight = Self::weight_of(task.priority);
        let delta = delta_exec * 1024 / weight.max(1);

        task.vruntime = task.vruntime.wrapping_add(delta);

        // min_vruntime'ı güncelle (CFS'te scheduler bunu takip eder)
        if task.vruntime < self.min_vruntime {
            self.min_vruntime = task.vruntime;
        }
    }

    /// Builds a complete task without exposing it through a scheduler
    /// container. S354 and S355 use this with an owned S255 vruntime snapshot
    /// so all fallible user/kernel preparation finishes before the respective
    /// publication writer. The old unguarded `Scheduler::spawn` publication
    /// path no longer exists.
    fn build_unpublished_task(
        name: &str,
        kernel_entry: extern "C" fn() -> !,
        stack_size: usize,
        priority: u8,
        time_slice: u32,
        is_user: bool,
        user_entry: Option<extern "C" fn() -> !>,
        initial_user_arg0: u64,
        initial_vruntime: u64,
    ) -> Result<(Task, JoinHandle), TaskSpawnError> {
        const GUARD_SIZE: usize = 0x1000;
        let validated_user_entry = if is_user {
            Some(user_entry.ok_or(TaskSpawnError::MissingUserEntry)?)
        } else {
            None
        };
        let total_user_stack_alloc = if is_user {
            Some(
                stack_size
                    .checked_add(GUARD_SIZE)
                    .ok_or(TaskSpawnError::StackSizeOverflow)?,
            )
        } else {
            None
        };

        // Task ids are authority principals. Reserve one before ASIDs, page
        // tables, or stacks so permanent id exhaustion has no side effects.
        // A later spawn failure may consume an id, but ids are never reused.
        let id = TASK_ID_ALLOCATOR
            .try_allocate()
            .map_err(|_| TaskSpawnError::TaskIdExhausted)?;

        // === M8.2+M7.4 fix (18-agent audit): page_table_root policy ===
        // Kernel tasks share the live ROOT_PAGE_TABLE and never own or switch
        // to a private root. The recorded value must nevertheless be its real
        // address: framebuffer grants query this metadata and mutate the
        // returned table. The old 0x4020_0000 placeholder points into the heap
        // on current links and corrupts/walks allocator metadata as PTEs.
        let kernel_root = unsafe {
            let root = crate::arch::aarch64::mmu::get_kernel_root_table() as *mut _ as u64;
            crate::mm::PhysAddr::new(root)
        };
        let (new_root, new_asid) = if is_user {
            // Reserve the scarce identifier before any root or stack Box.
            // Exhaustion is returned to the user-task caller without mutation.
            let a = crate::mm::address_space::try_allocate_asid().map_err(TaskSpawnError::Asid)?;
            let r = crate::mm::allocate_page_table_root();
            (r, a)
        } else {
            (kernel_root, 0u16)
        };

        let kernel_stack_allocation = OwnedStackAllocation::new(stack_size);
        let stack_top = unsafe { kernel_stack_allocation.top() };
        let finished = Arc::new(AtomicBool::new(false));

        // M5.5 (Audit #18) — EL0 stack + guard yalnız user task için gerekir.
        // Kernel task'e ikinci, hiç kullanılmayan bir stack ayırmak hem heap'i
        // tüketiyor hem de sahipliği kaybolan gereksiz bir allocation yaratıyordu.
        let user_stack_allocation = total_user_stack_alloc.map(OwnedStackAllocation::new);
        let (user_stack_ptr, usable_stack_bottom) = if let Some(owner) = &user_stack_allocation {
            let user_stack_ptr = owner.base();
            let usable_stack_bottom = unsafe { user_stack_ptr.add(GUARD_SIZE) };

            // Guard sayfasının üstüne canary yaz (ileride overflow kontrolü).
            unsafe {
                core::ptr::write_volatile(
                    user_stack_ptr.add(GUARD_SIZE - 8) as *mut u64,
                    0xDEAD_BEEF_C0FFEE00,
                );
            }
            (user_stack_ptr, usable_stack_bottom)
        } else {
            (core::ptr::null_mut(), core::ptr::null_mut())
        };

        // Sadece user task için per-task root mapping kur.
        if is_user {
            unsafe {
                let root_table = crate::arch::aarch64::mmu::get_page_table_from_root(new_root);

                // Düşük RAM + heap bölgesi (kernel tarafı NORMAL — kernel kodu için exec).
                crate::arch::aarch64::mmu::map_range_4k_to_root(
                    root_table,
                    crate::mm::VirtAddr::new(0x4000_0000),
                    crate::mm::PhysAddr::new(0x4000_0000),
                    0x0800_0000,
                    crate::mm::paging::PageTableFlags::NORMAL,
                );

                // UART
                crate::arch::aarch64::mmu::map_range_4k_to_root(
                    root_table,
                    crate::mm::VirtAddr::new(0x0900_0000),
                    crate::mm::PhysAddr::new(0x0900_0000),
                    0x0020_0000,
                    crate::mm::paging::PageTableFlags::DEVICE,
                );

                // GIC
                crate::arch::aarch64::mmu::map_range_4k_to_root(
                    root_table,
                    crate::mm::VirtAddr::new(0x0800_0000),
                    crate::mm::PhysAddr::new(0x0800_0000),
                    0x0020_0000,
                    crate::mm::paging::PageTableFlags::DEVICE,
                );

                // M5.5+M7.4 fix: User stack USER_NORMAL override.
                // Heap NORMAL kalır (kernel isolation), sadece user stack range'i
                // USER_NORMAL ile EL0'a açılır. Guard page (alt 4K) MAP EDİLMEZ →
                // translation fault overflow yakalar (Strategy A — Linux/seL4 patterni).
                //
                // KRİTİK: Box::into_raw u8 alignment'lı bir pointer döner (4K aligned değil).
                // map_range_4k_to_root 4K page boundary bekler — unaligned adresleri
                // atlar (page'leri map etmez) → user EL0 stack write'da perm fault.
                // Bu yüzden adresi 4K'ya yuvarla (aşağı → start, yukarı → end).
                let usable_stack_phys = usable_stack_bottom as u64;
                let aligned_start = usable_stack_phys & !0xFFF; // round down
                let aligned_end = (usable_stack_phys + stack_size as u64 + 0xFFF) & !0xFFF;
                let aligned_size = aligned_end - aligned_start;
                crate::arch::aarch64::mmu::map_range_4k_to_root(
                    root_table,
                    crate::mm::VirtAddr::new(aligned_start),
                    crate::mm::PhysAddr::new(aligned_start),
                    aligned_size,
                    crate::mm::paging::PageTableFlags::USER_NORMAL,
                );
                crate::kprintln!(
                    "[M5.5+M7.4] user '{}' root=0x{:x} asid={} stack USER_NORMAL [0x{:x}..0x{:x}] (size=0x{:x}, requested phys=0x{:x})",
                    name, new_root.as_u64(), new_asid, aligned_start, aligned_end, aligned_size, usable_stack_phys
                );
            }
        }

        let mut task = Task {
            id,
            name: String::from(name),
            state: TaskState::Ready,
            context: TaskContext::default(),
            priority,
            time_slice,
            default_time_slice: time_slice,
            vruntime: initial_vruntime,
            finished: finished.clone(),
            kernel_stack_allocation: Some(kernel_stack_allocation),
            user_stack_allocation,

            user_stack_bottom: usable_stack_bottom,
            user_stack_size: if is_user { stack_size } else { 0 },
            // M5.5: yalnız user task'te guard sayfası ayrılır.
            stack_guard_page: if is_user { Some(user_stack_ptr) } else { None },

            // M4.3
            is_user,
            user_sp: 0,
            saved_user_elr: 0,
            saved_user_spsr: 0,
            saved_user_gprs: {
                let mut registers = [0; 31];
                if is_user {
                    registers[0] = initial_user_arg0;
                }
                registers
            },

            // Kernel task = live shared kernel root/asid=0; user task = unique owned root + ASID.
            page_table_root: new_root,
            owns_page_table_root: is_user,
            owned_user_page_tables: None,
            owned_user_frames: alloc::vec::Vec::new(),
            runtime_user_frames: None,
            asid: new_asid,
            #[cfg(feature = "board-rpi5")]
            g8l_current_task_owner: crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_current_task::G8lSchedulerCurrentTaskOwnerSlot::new(),
            address_space_quiesced: !is_user,

            // M5: Her task kendi CNode'unu alır (boş başlar)
            cnode: crate::ui::capability::CNode::new(),
        };

        // Kernel context'i her zaman trampoline veya normal entry'ye işaret eder
        // User task'ler için ilk girişe özel kurulum kullanıyoruz
        unsafe {
            if is_user {
                task.context = TaskContext::new_for_user_first_entry(stack_top);
            } else {
                task.context = TaskContext::new(kernel_entry, stack_top);
            }
        }

        // User task ise initial EL0 frame'i hemen hazırla
        if let Some(entry) = validated_user_entry {
            // Stack top = usable_bottom + size (guard hariç)
            task.user_sp = usable_stack_bottom as u64 + stack_size as u64; // stack top (büyüme aşağı)
            task.saved_user_elr = entry as u64;
            task.saved_user_spsr = 0; // EL0t
                                      // GPR'ler sıfır kalır, sadece PC ve SP önemli
        }

        let handle = JoinHandle {
            finished,
            task_id: id,
        };
        Ok((task, handle))
    }

    /// Build a kernel-task skeleton without publishing it in any scheduler
    /// container. The raw-ELF path consumes this value, installs the complete
    /// user address-space state, and performs exactly one final ready-queue
    /// push. No CPU can therefore observe a placeholder entry/root/ASID.
    fn build_unpublished_kernel_task(
        name: &str,
        kernel_entry: extern "C" fn() -> !,
        stack_size: usize,
        priority: u8,
        time_slice: u32,
        initial_vruntime: u64,
    ) -> Result<Box<Task>, &'static str> {
        let id = TASK_ID_ALLOCATOR
            .try_allocate()
            .map_err(|_| "task id space exhausted")?;
        let kernel_root = {
            let root =
                unsafe { crate::arch::aarch64::mmu::get_kernel_root_table() } as *mut _ as u64;
            crate::mm::PhysAddr::new(root)
        };
        let kernel_stack_allocation = OwnedStackAllocation::new(stack_size);
        let stack_top = unsafe { kernel_stack_allocation.top() };
        let mut task = Box::new(Task {
            id,
            name: String::from(name),
            state: TaskState::Ready,
            context: TaskContext::default(),
            priority,
            time_slice,
            default_time_slice: time_slice,
            vruntime: initial_vruntime,
            finished: Arc::new(AtomicBool::new(false)),
            kernel_stack_allocation: Some(kernel_stack_allocation),
            user_stack_allocation: None,
            user_stack_bottom: core::ptr::null_mut(),
            user_stack_size: 0,
            stack_guard_page: None,
            is_user: false,
            user_sp: 0,
            saved_user_elr: 0,
            saved_user_spsr: 0,
            saved_user_gprs: [0; 31],
            page_table_root: kernel_root,
            owns_page_table_root: false,
            owned_user_page_tables: None,
            owned_user_frames: alloc::vec::Vec::new(),
            runtime_user_frames: None,
            asid: 0,
            #[cfg(feature = "board-rpi5")]
            g8l_current_task_owner: crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_current_task::G8lSchedulerCurrentTaskOwnerSlot::new(),
            address_space_quiesced: true,
            cnode: crate::ui::capability::CNode::new(),
        });
        task.context = unsafe { TaskContext::new(kernel_entry, stack_top) };
        Ok(task)
    }

    /// Mevcut task'i kuyruğa geri koyar ve en yüksek öncelikli (en düşük vruntime) task'i seçer.
    ///
    /// NOT: Şu anda kullanılmıyor (`yield_now` aynı işi inline yapıyor).
    /// İleride farklı bir API (örn. IRQ-driven preemption) lazım olursa bu
    /// fonksiyon kullanılabilir.
    #[allow(dead_code)]
    pub unsafe fn schedule(&mut self) -> Option<(*mut TaskContext, *mut TaskContext)> {
        if let Some(mut curr) = self.current_task.take() {
            curr.state = TaskState::Ready;
            if curr.time_slice == 0 {
                curr.time_slice = curr.default_time_slice;
            }
            self.ready_queue.push(PriorityTask::new(curr));
        }

        // min_vruntime'ı güncelle (daha adil seçim için)
        self.recalculate_min_vruntime();

        if let Some(prio_next) = self.ready_queue.pop() {
            let mut next = prio_next.task;
            next.state = TaskState::Running;
            let new_ctx = &mut next.context as *mut TaskContext;

            self.current_task = Some(next);
            self.ticks_until_preempt = self.current_task.as_ref().unwrap().time_slice;

            Some((core::ptr::null_mut(), new_ctx))
        } else {
            None
        }
    }

    /// Timer her tick'te çağrılır.
    /// Time slice bitince preemption tetikler + vruntime ve aging uygular.
    pub unsafe fn tick(&mut self) -> bool {
        static TICK_COUNTER: AtomicU64 = AtomicU64::new(0);
        let n = TICK_COUNTER.fetch_add(1, Ordering::Relaxed) + 1;

        // Aging + min_vruntime + normalizasyon (her 50 tick'te bir)
        if n % 50 == 0 {
            self.apply_aging();
            self.recalculate_min_vruntime();
            self.normalize_vruntime();
        }

        if let Some(curr) = &mut self.current_task {
            if curr.time_slice > 0 {
                curr.time_slice -= 1;
            }

            // Vruntime'ı da tick bazında hafifçe artır
            let weight = Self::weight_of(curr.priority);
            curr.vruntime = curr.vruntime.wrapping_add(1 * 1024 / weight.max(1));
            if curr.vruntime < self.min_vruntime {
                self.min_vruntime = curr.vruntime;
            }

            if curr.time_slice == 0 {
                return true; // preemption gerekli
            }
        }
        false
    }

    /// Aging mekanizması:
    /// Uzun süredir bekleyen task'lerin vruntime'ını azaltarak önlerine geçmelerini sağlar.
    /// Bu sayede düşük öncelikli task'ler bile zamanla CPU alabilir.
    fn apply_aging(&mut self) {
        let mut temp = Vec::new();
        while let Some(mut ptask) = self.ready_queue.pop() {
            // min_vruntime'tan çok geride kalanlara daha fazla bonus veriyoruz
            let bonus = if ptask.task.vruntime + 50 < self.min_vruntime {
                12
            } else {
                6
            };
            ptask.task.vruntime = ptask.task.vruntime.saturating_sub(bonus);
            temp.push(ptask);
        }
        for p in temp {
            self.ready_queue.push(p);
        }
    }

    /// Mevcut task'in context pointer'ını döner (güvenli kullanım için)
    pub fn current_context_ptr(&self) -> Option<*mut TaskContext> {
        self.current_task
            .as_ref()
            .map(|t| &t.context as *const _ as *mut TaskContext)
    }

    /// Mevcut çalışan task'in ID'sini döndürür.
    pub fn current_task_id(&self) -> Option<u64> {
        self.current_task.as_ref().map(|t| t.id)
    }

    /// S211 producer-side observation of the real scheduler current task.
    /// The target adapter holds a local IRQ guard while calling this method;
    /// cross-CPU exclusion against legacy scheduler accesses remains open.
    #[cfg(feature = "board-rpi5")]
    pub(crate) fn observe_g8l_current_task(
        &self,
    ) -> Option<
        crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_current_task::G8lObservedCurrentTask,
    >{
        self.current_task.as_ref().map(|task| {
            crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_current_task::G8lObservedCurrentTask {
                task_id: task.id,
                running: task.state == TaskState::Running,
                el0: task.is_user,
                asid: task.asid,
                root: task.page_table_root.as_u64(),
            }
        })
    }

    #[cfg(feature = "board-rpi5")]
    pub(crate) fn commit_g8l_current_task_owner(
        &mut self,
        runtime: &crate::g8l_runtime_contract::G8lRuntimeAuthority,
        authority: &crate::g8l_target_dispatch_scheduler_owner::G8lSchedulerOwnerAuthority,
        bridge: &crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_guarded_ack::G8lSchedulerMutationProductionGuardedAckBridge<'_>,
    ) -> Result<
        crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_current_task::G8lSchedulerCurrentTaskOwnerCommitReceipt,
        crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_current_task::G8lSchedulerCurrentTaskOwnerCommitError,
    >{
        let task = self.current_task.as_mut().ok_or(
            crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_current_task::G8lSchedulerCurrentTaskOwnerCommitError::MissingCurrentTask,
        )?;
        let observed = crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_current_task::G8lObservedCurrentTask {
            task_id: task.id,
            running: task.state == TaskState::Running,
            el0: task.is_user,
            asid: task.asid,
            root: task.page_table_root.as_u64(),
        };
        task.g8l_current_task_owner
            .commit_from_guarded_bridge(runtime, authority, bridge, observed)
    }

    #[cfg(feature = "board-rpi5")]
    pub(crate) fn rollback_g8l_current_task_owner(
        &mut self,
        receipt: crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_current_task::G8lSchedulerCurrentTaskOwnerCommitReceipt,
    ) -> Result<
        (),
        crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_current_task::G8lSchedulerCurrentTaskOwnerCommitError,
    >{
        let task = self.current_task.as_mut().ok_or(
            crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_current_task::G8lSchedulerCurrentTaskOwnerCommitError::MissingCurrentTask,
        )?;
        if task.id != receipt.task_id {
            return Err(crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_current_task::G8lSchedulerCurrentTaskOwnerCommitError::TaskMismatch);
        }
        task.g8l_current_task_owner.rollback_exact(receipt)
    }

    fn record_runtime_oom_binding(
        task: &Task,
        location: RuntimeOomTaskLocation,
        domain: crate::mm::AllocationDomain,
        expected_frames: usize,
        binding: &mut Option<RuntimeOomTaskBinding>,
    ) -> Result<(), RuntimeOomTaskExecutionError> {
        if task.runtime_allocation_domain() != Some(domain) {
            return Ok(());
        }
        if binding.is_some() {
            return Err(RuntimeOomTaskExecutionError::AmbiguousDomainBinding);
        }
        let Some(ledger) = task.runtime_user_frames.as_ref() else {
            return Err(RuntimeOomTaskExecutionError::InvalidTaskBinding);
        };
        let expected_state = match location {
            RuntimeOomTaskLocation::Current => task.state == TaskState::Running,
            RuntimeOomTaskLocation::Ready => task.state == TaskState::Ready,
            RuntimeOomTaskLocation::Blocked => matches!(
                task.state,
                TaskState::Blocked
                    | TaskState::BlockedOnIpc { .. }
                    | TaskState::BlockedOnNotification { .. }
            ),
            RuntimeOomTaskLocation::Retired => task.state == TaskState::Dead,
        };
        if !task.is_user
            || task.asid == 0
            || task.address_space_quiesced
            || task.owns_page_table_root
            || task.owned_user_page_tables.is_none()
            || ledger.frame_count() != expected_frames
            || task.owned_user_frames.len() != expected_frames
            || !ledger.physical_frames_match(&task.owned_user_frames)
            || !expected_state
        {
            return Err(RuntimeOomTaskExecutionError::InvalidTaskBinding);
        }
        *binding = Some(RuntimeOomTaskBinding {
            task_id: task.id,
            domain,
            location,
            asid: task.asid,
            frame_count: expected_frames,
        });
        Ok(())
    }

    /// Allocation-free audit of every persistent scheduler container. A
    /// domain must bind one strict RuntimePmm ELF task and the ticket's frame
    /// count must equal that task's complete leaf ledger.
    fn audit_runtime_oom_task_binding(
        &self,
        preflight: crate::mm::RuntimeOomTeardownPreflight,
    ) -> Result<RuntimeOomTaskBinding, RuntimeOomTaskExecutionError> {
        let expected_frames = usize::try_from(preflight.expected_reclaimable_frames)
            .map_err(|_| RuntimeOomTaskExecutionError::InvalidTaskBinding)?;
        let mut binding = None;
        if let Some(task) = self.current_task.as_deref() {
            Self::record_runtime_oom_binding(
                task,
                RuntimeOomTaskLocation::Current,
                preflight.domain,
                expected_frames,
                &mut binding,
            )?;
        }
        for priority_task in self.ready_queue.iter() {
            Self::record_runtime_oom_binding(
                &priority_task.task,
                RuntimeOomTaskLocation::Ready,
                preflight.domain,
                expected_frames,
                &mut binding,
            )?;
        }
        {
            let blocked = self.ipc_blocked_tasks.lock();
            for task in blocked.iter() {
                Self::record_runtime_oom_binding(
                    task,
                    RuntimeOomTaskLocation::Blocked,
                    preflight.domain,
                    expected_frames,
                    &mut binding,
                )?;
            }
        }
        if let Some(task) = self.retired_task.as_deref() {
            Self::record_runtime_oom_binding(
                task,
                RuntimeOomTaskLocation::Retired,
                preflight.domain,
                expected_frames,
                &mut binding,
            )?;
        }

        binding.ok_or(RuntimeOomTaskExecutionError::DomainNotBound)
    }

    fn preflight_runtime_oom_task(
        &self,
        preflight: crate::mm::RuntimeOomTeardownPreflight,
    ) -> Result<RuntimeOomTaskBinding, RuntimeOomTaskExecutionError> {
        let binding = self.audit_runtime_oom_task_binding(preflight)?;
        match binding.location {
            RuntimeOomTaskLocation::Current => {
                Err(RuntimeOomTaskExecutionError::CurrentTaskRequiresDeferredExit)
            }
            RuntimeOomTaskLocation::Retired => {
                Err(RuntimeOomTaskExecutionError::RetiredTaskQuarantined)
            }
            RuntimeOomTaskLocation::Ready | RuntimeOomTaskLocation::Blocked => Ok(binding),
        }
    }

    /// Detach the exact preflighted non-current task without allocating. The
    /// ready heap is rebuilt in-place from its existing Vec allocation.
    fn take_runtime_oom_task(&mut self, binding: RuntimeOomTaskBinding) -> Option<Box<Task>> {
        let mut ready = core::mem::take(&mut self.ready_queue).into_vec();
        let ready_match = ready.iter().position(|priority_task| {
            priority_task.task.id == binding.task_id
                && priority_task.task.runtime_allocation_domain() == Some(binding.domain)
        });
        let selected = ready_match.map(|index| ready.swap_remove(index).task);
        self.ready_queue = BinaryHeap::from(ready);
        if selected.is_some() {
            return selected;
        }

        let mut blocked = self.ipc_blocked_tasks.lock();
        let blocked_match = blocked.iter().position(|task| {
            task.id == binding.task_id && task.runtime_allocation_domain() == Some(binding.domain)
        });
        blocked_match.map(|index| blocked.swap_remove(index))
    }

    pub(crate) fn capability_for_task(
        &self,
        task_id: u64,
        cap_id: crate::ui::capability::CapId,
    ) -> Option<crate::ui::capability::Capability> {
        if let Some(capability) = self
            .current_task
            .as_ref()
            .filter(|task| task.id == task_id)
            .and_then(|task| task.cnode.lookup_capability_by_id(cap_id))
            .copied()
        {
            return Some(capability);
        }

        if let Some(capability) = self
            .ipc_blocked_tasks
            .lock()
            .iter()
            .find(|task| task.id == task_id)
            .and_then(|task| task.cnode.lookup_capability_by_id(cap_id))
            .copied()
        {
            return Some(capability);
        }

        if let Some(capability) = self
            .ready_queue
            .iter()
            .find(|priority_task| priority_task.task.id == task_id)
            .and_then(|priority_task| priority_task.task.cnode.lookup_capability_by_id(cap_id))
            .copied()
        {
            return Some(capability);
        }

        self.retired_task
            .as_ref()
            .filter(|task| task.id == task_id)
            .and_then(|task| task.cnode.lookup_capability_by_id(cap_id))
            .copied()
    }

    pub(crate) fn notification_holder_count(
        &self,
        notification_id: crate::ui::capability::CapId,
    ) -> usize {
        let holds = |task: &Task| {
            task.cnode
                .lookup_capability_by_id(notification_id)
                .is_some_and(|capability| {
                    capability.kind == crate::ui::capability::CapabilityKind::Notification
                })
        };
        let mut count = usize::from(self.current_task.as_deref().is_some_and(holds));
        count += self
            .ready_queue
            .iter()
            .filter(|task| holds(&task.task))
            .count();
        count += self
            .ipc_blocked_tasks
            .lock()
            .iter()
            .filter(|task| holds(task))
            .count();
        count += usize::from(self.retired_task.as_deref().is_some_and(holds));
        count
    }

    fn notification_holder_for_task(
        task: &Task,
        notification_id: crate::ui::capability::CapId,
        object_owner: u64,
    ) -> Result<Option<crate::ui::capability::Capability>, EndpointHolderPurgeError> {
        use crate::ui::capability::{CapabilityKind, CapabilityRights};

        let Some(capability) = task.cnode.lookup_capability_by_id(notification_id).copied() else {
            return Ok(None);
        };
        let is_object_owner = object_owner != 0 && task.id == object_owner;
        let expected_parent = if is_object_owner {
            None
        } else {
            Some(notification_id)
        };
        let notification_rights = capability.rights.intersect(CapabilityRights::FULL);
        if capability.id != notification_id
            || capability.owner != task.id
            || capability.kind != CapabilityKind::Notification
            || capability.parent != expected_parent
            || capability.rights == CapabilityRights::NONE
            || notification_rights != capability.rights
            || (is_object_owner
                && !capability
                    .rights
                    .contains(CapabilityRights::NOTIFICATION_REVOKE))
            || !task.cnode.can_revoke_capability_exact(&capability)
        {
            return Err(EndpointHolderPurgeError::MalformedAuthority);
        }
        Ok(Some(capability))
    }

    fn audit_notification_holder_task(
        task: &Task,
        notification_id: crate::ui::capability::CapId,
        object_owner: u64,
        container: TaskContainer,
        summary: &mut EndpointHolderPurgeSummary,
    ) -> Result<(), EndpointHolderPurgeError> {
        if Self::notification_holder_for_task(task, notification_id, object_owner)?.is_some() {
            summary.record(container)?;
        }
        Ok(())
    }

    /// Generation-aware audit of every persistent notification holder. The
    /// caller owns `IPC_TRANSACTION_LOCK`, so the matching purge observes the
    /// same CNode graph.
    pub(crate) fn preflight_notification_holder_purge(
        &self,
        notification_id: crate::ui::capability::CapId,
        object_owner: u64,
    ) -> Result<EndpointHolderPurgeSummary, EndpointHolderPurgeError> {
        let mut summary = EndpointHolderPurgeSummary::default();
        if let Some(task) = self.current_task.as_deref() {
            Self::audit_notification_holder_task(
                task,
                notification_id,
                object_owner,
                TaskContainer::Current,
                &mut summary,
            )?;
        }
        for task in self.ready_queue.iter() {
            Self::audit_notification_holder_task(
                &task.task,
                notification_id,
                object_owner,
                TaskContainer::Ready,
                &mut summary,
            )?;
        }
        for task in self.ipc_blocked_tasks.lock().iter() {
            Self::audit_notification_holder_task(
                task,
                notification_id,
                object_owner,
                TaskContainer::Blocked,
                &mut summary,
            )?;
        }
        if let Some(task) = self.retired_task.as_deref() {
            Self::audit_notification_holder_task(
                task,
                notification_id,
                object_owner,
                TaskContainer::Retired,
                &mut summary,
            )?;
        }
        if object_owner != 0 && summary.total == 0 {
            return Err(EndpointHolderPurgeError::MalformedAuthority);
        }
        Ok(summary)
    }

    fn purge_notification_holder_from_task(
        task: &mut Task,
        notification_id: crate::ui::capability::CapId,
        object_owner: u64,
        container: TaskContainer,
        summary: &mut EndpointHolderPurgeSummary,
    ) {
        let capability = Self::notification_holder_for_task(task, notification_id, object_owner)
            .expect("preflighted notification holder became malformed");
        let Some(capability) = capability else {
            return;
        };
        assert_eq!(
            task.cnode.revoke_capability_exact(&capability),
            Some(capability),
            "preflighted notification holder exact revoke failed"
        );
        summary
            .record(container)
            .expect("notification holder count overflowed during commit");
    }

    /// Allocation-free exact purge paired with
    /// `preflight_notification_holder_purge`.
    pub(crate) fn purge_notification_holders_exact(
        &mut self,
        notification_id: crate::ui::capability::CapId,
        object_owner: u64,
    ) -> EndpointHolderPurgeSummary {
        let expected = self
            .preflight_notification_holder_purge(notification_id, object_owner)
            .expect("notification holder graph changed after teardown preflight");
        let mut removed = EndpointHolderPurgeSummary::default();

        if let Some(task) = self.current_task.as_deref_mut() {
            Self::purge_notification_holder_from_task(
                task,
                notification_id,
                object_owner,
                TaskContainer::Current,
                &mut removed,
            );
        }
        let ready = core::mem::take(&mut self.ready_queue);
        let mut ready_tasks = ready.into_vec();
        for task in ready_tasks.iter_mut() {
            Self::purge_notification_holder_from_task(
                &mut task.task,
                notification_id,
                object_owner,
                TaskContainer::Ready,
                &mut removed,
            );
        }
        self.ready_queue = BinaryHeap::from(ready_tasks);
        for task in self.ipc_blocked_tasks.lock().iter_mut() {
            Self::purge_notification_holder_from_task(
                task,
                notification_id,
                object_owner,
                TaskContainer::Blocked,
                &mut removed,
            );
        }
        if let Some(task) = self.retired_task.as_deref_mut() {
            Self::purge_notification_holder_from_task(
                task,
                notification_id,
                object_owner,
                TaskContainer::Retired,
                &mut removed,
            );
        }
        assert_eq!(
            removed, expected,
            "notification holder purge differed from exact preflight"
        );
        removed
    }

    fn endpoint_holder_for_task(
        task: &Task,
        endpoint_id: crate::ui::capability::CapId,
        object_owner: u64,
    ) -> Result<Option<crate::ui::capability::Capability>, EndpointHolderPurgeError> {
        use crate::ui::capability::{CapabilityKind, CapabilityRights};

        let Some(capability) = task.cnode.lookup_capability_by_id(endpoint_id).copied() else {
            return Ok(None);
        };
        let is_object_owner = object_owner != 0 && task.id == object_owner;
        let expected_parent = if is_object_owner {
            None
        } else {
            Some(endpoint_id)
        };
        let endpoint_rights = capability.rights.intersect(CapabilityRights::FULL);
        if capability.id != endpoint_id
            || capability.owner != task.id
            || capability.kind != CapabilityKind::Endpoint
            || capability.parent != expected_parent
            || capability.rights == CapabilityRights::NONE
            || endpoint_rights != capability.rights
            || (is_object_owner
                && !capability
                    .rights
                    .contains(CapabilityRights::ENDPOINT_REVOKE))
            || !task.cnode.can_revoke_capability_exact(&capability)
        {
            return Err(EndpointHolderPurgeError::MalformedAuthority);
        }
        Ok(Some(capability))
    }

    fn audit_endpoint_holder_task(
        task: &Task,
        endpoint_id: crate::ui::capability::CapId,
        object_owner: u64,
        container: TaskContainer,
        summary: &mut EndpointHolderPurgeSummary,
    ) -> Result<(), EndpointHolderPurgeError> {
        if Self::endpoint_holder_for_task(task, endpoint_id, object_owner)?.is_some() {
            summary.record(container)?;
        }
        Ok(())
    }

    /// Allocation-free, generation-aware audit of every scheduler-owned task
    /// CNode that can outlive the current instruction. The caller holds the
    /// global IPC transaction lock, so this snapshot remains stable through
    /// the matching purge.
    pub(crate) fn preflight_endpoint_holder_purge(
        &self,
        endpoint_id: crate::ui::capability::CapId,
        object_owner: u64,
    ) -> Result<EndpointHolderPurgeSummary, EndpointHolderPurgeError> {
        let mut summary = EndpointHolderPurgeSummary::default();
        if let Some(task) = self.current_task.as_deref() {
            Self::audit_endpoint_holder_task(
                task,
                endpoint_id,
                object_owner,
                TaskContainer::Current,
                &mut summary,
            )?;
        }
        for task in self.ready_queue.iter() {
            Self::audit_endpoint_holder_task(
                &task.task,
                endpoint_id,
                object_owner,
                TaskContainer::Ready,
                &mut summary,
            )?;
        }
        for task in self.ipc_blocked_tasks.lock().iter() {
            Self::audit_endpoint_holder_task(
                task,
                endpoint_id,
                object_owner,
                TaskContainer::Blocked,
                &mut summary,
            )?;
        }
        if let Some(task) = self.retired_task.as_deref() {
            Self::audit_endpoint_holder_task(
                task,
                endpoint_id,
                object_owner,
                TaskContainer::Retired,
                &mut summary,
            )?;
        }
        if object_owner != 0 && summary.total == 0 {
            return Err(EndpointHolderPurgeError::MalformedAuthority);
        }
        Ok(summary)
    }

    fn purge_endpoint_holder_from_task(
        task: &mut Task,
        endpoint_id: crate::ui::capability::CapId,
        object_owner: u64,
        container: TaskContainer,
        summary: &mut EndpointHolderPurgeSummary,
    ) {
        let capability = Self::endpoint_holder_for_task(task, endpoint_id, object_owner)
            .expect("preflighted endpoint holder became malformed inside one IPC transaction");
        let Some(capability) = capability else {
            return;
        };
        assert_eq!(
            task.cnode.revoke_capability_exact(&capability),
            Some(capability),
            "preflighted endpoint holder exact revoke failed"
        );
        summary
            .record(container)
            .expect("preflighted endpoint holder count overflowed during commit");
    }

    /// Commit the exact holder snapshot without allocating. BinaryHeap is
    /// converted into and rebuilt from its existing Vec allocation in place;
    /// CNode changes cannot affect heap ordering.
    pub(crate) fn purge_endpoint_holders_exact(
        &mut self,
        endpoint_id: crate::ui::capability::CapId,
        object_owner: u64,
    ) -> EndpointHolderPurgeSummary {
        let expected = self
            .preflight_endpoint_holder_purge(endpoint_id, object_owner)
            .expect("endpoint holder graph changed after teardown preflight");
        let mut removed = EndpointHolderPurgeSummary::default();

        if let Some(task) = self.current_task.as_deref_mut() {
            Self::purge_endpoint_holder_from_task(
                task,
                endpoint_id,
                object_owner,
                TaskContainer::Current,
                &mut removed,
            );
        }

        let ready = core::mem::take(&mut self.ready_queue);
        let mut ready_tasks = ready.into_vec();
        for task in ready_tasks.iter_mut() {
            Self::purge_endpoint_holder_from_task(
                &mut task.task,
                endpoint_id,
                object_owner,
                TaskContainer::Ready,
                &mut removed,
            );
        }
        self.ready_queue = BinaryHeap::from(ready_tasks);

        for task in self.ipc_blocked_tasks.lock().iter_mut() {
            Self::purge_endpoint_holder_from_task(
                task,
                endpoint_id,
                object_owner,
                TaskContainer::Blocked,
                &mut removed,
            );
        }
        if let Some(task) = self.retired_task.as_deref_mut() {
            Self::purge_endpoint_holder_from_task(
                task,
                endpoint_id,
                object_owner,
                TaskContainer::Retired,
                &mut removed,
            );
        }
        assert_eq!(
            removed, expected,
            "endpoint holder purge differed from its exact preflight"
        );
        removed
    }

    /// Belirli bir task'in page table root'unu döndürür (M4.4 büyük adım için).
    pub fn get_task_page_table_root(&self, task_id: u64) -> Option<crate::mm::PhysAddr> {
        // Basit lineer arama (demo için yeterli)
        if let Some(ref curr) = self.current_task {
            if curr.id == task_id {
                return Some(curr.page_table_root);
            }
        }
        for ptask in self.ready_queue.iter() {
            if ptask.task.id == task_id {
                return Some(ptask.task.page_table_root);
            }
        }
        for task in self.ipc_blocked_tasks.lock().iter() {
            if task.id == task_id {
                return Some(task.page_table_root);
            }
        }
        None
    }

    /// M5 — Belirli bir task'in CNode'una capability ekler (cross-task grant için kritik).
    /// Hem current_task hem ready_queue içindeki task'leri tarar.
    pub fn insert_cap_for_task(
        &mut self,
        task_id: u64,
        cap: crate::ui::capability::Capability,
    ) -> Result<(usize, u64), &'static str> {
        if let Some(ref mut curr) = self.current_task {
            if curr.id == task_id {
                return curr.cnode.insert(cap);
            }
        }

        let mut temp: alloc::vec::Vec<PriorityTask> = alloc::vec::Vec::new();
        let mut result: Result<(usize, u64), &'static str> = Err("Task not found");

        while let Some(mut pt) = self.ready_queue.pop() {
            if pt.task.id == task_id {
                result = pt.task.cnode.insert(cap);
                temp.push(pt);
                break;
            } else {
                temp.push(pt);
            }
        }

        for p in temp {
            self.ready_queue.push(p);
        }

        result
    }

    /// Private id-only CNode removal. Public callers must pass through the
    /// global wrapper, which rejects endpoint identities in favor of typed
    /// grant/object APIs.
    fn revoke_cap_for_task(
        &mut self,
        task_id: u64,
        cap_id: crate::ui::capability::CapId,
    ) -> Option<usize> {
        self.remove_cap_by_id(task_id, cap_id)
    }

    /// CNode seviyesinde id bazlı güçlü revoke (generation bump dahil)
    fn remove_cap_by_id(
        &mut self,
        task_id: u64,
        cap_id: crate::ui::capability::CapId,
    ) -> Option<usize> {
        if let Some(ref mut curr) = self.current_task {
            if curr.id == task_id {
                if curr.cnode.revoke_capability(cap_id).is_some() {
                    return Some(0);
                }
            }
        }

        // Reply owners normally wait outside the ready queue. Search this
        // fixed authority location before the heap fallback so reply consume
        // and endpoint teardown do not allocate a temporary queue at OOM.
        let mut blocked = self.ipc_blocked_tasks.lock();
        for task in blocked.iter_mut() {
            if task.id == task_id && task.cnode.revoke_capability(cap_id).is_some() {
                return Some(0);
            }
        }
        drop(blocked);

        let mut temp: alloc::vec::Vec<PriorityTask> = alloc::vec::Vec::new();
        let mut found: Option<usize> = None;

        while let Some(mut pt) = self.ready_queue.pop() {
            if pt.task.id == task_id {
                if pt.task.cnode.revoke_capability(cap_id).is_some() {
                    found = Some(0);
                }
                temp.push(pt);
                break;
            } else {
                temp.push(pt);
            }
        }

        for p in temp {
            self.ready_queue.push(p);
        }

        if found.is_some() {
            return found;
        }

        None
    }

    /// Allocation-free removal of one complete CNode authority tuple.  This
    /// is used by typed endpoint/reply teardown where id-only revocation would
    /// let a stale capability delete a newer generation.
    pub(crate) fn revoke_cap_for_task_exact(
        &mut self,
        expected: &crate::ui::capability::Capability,
    ) -> bool {
        let task_id = expected.owner;
        if let Some(task) = self
            .current_task
            .as_deref_mut()
            .filter(|task| task.id == task_id)
        {
            return task.cnode.revoke_capability_exact(expected).is_some();
        }

        {
            let mut blocked = self.ipc_blocked_tasks.lock();
            if let Some(task) = blocked.iter_mut().find(|task| task.id == task_id) {
                return task.cnode.revoke_capability_exact(expected).is_some();
            }
        }

        let ready = core::mem::take(&mut self.ready_queue);
        let mut ready_tasks = ready.into_vec();
        let removed = ready_tasks
            .iter_mut()
            .find(|task| task.task.id == task_id)
            .map_or(false, |task| {
                task.task.cnode.revoke_capability_exact(expected).is_some()
            });
        self.ready_queue = BinaryHeap::from(ready_tasks);
        if removed {
            return true;
        }

        self.retired_task
            .as_deref_mut()
            .filter(|task| task.id == task_id)
            .map_or(false, |task| {
                task.cnode.revoke_capability_exact(expected).is_some()
            })
    }

    // =================================================================
    // M6.2 — IPC Blocking / Waking (İskelet)
    // =================================================================

    fn save_current_ipc_context(&mut self, ctx: &ExceptionContext, user_sp: u64) {
        if let Some(current) = &mut self.current_task {
            current.is_user = true;
            current.user_sp = user_sp;
            current.saved_user_elr = ctx.elr_el1;
            current.saved_user_spsr = ctx.spsr_el1;
            current.saved_user_gprs[..30].copy_from_slice(&ctx.gpr);
            current.saved_user_gprs[30] = ctx.lr;
        }
    }

    /// Copy the wake result back into the still-live exception frame whose
    /// kernel continuation was saved by `switch_after_ipc_park`.
    fn restore_current_ipc_context(&self, ctx: &mut ExceptionContext) {
        let current = self
            .current_task
            .as_ref()
            .expect("IPC continuation resumed without its current task");
        assert!(
            current.is_user && current.state == TaskState::Running,
            "IPC continuation resumed outside a running EL0 task"
        );
        ctx.gpr.copy_from_slice(&current.saved_user_gprs[..30]);
        ctx.lr = current.saved_user_gprs[30];
        ctx.elr_el1 = current.saved_user_elr;
        ctx.spsr_el1 = current.saved_user_spsr;
    }

    fn current_endpoint_authority_is_live(
        &self,
        task_id: u64,
        endpoint_id: crate::ui::capability::CapId,
        expected_generation: u64,
        required_right: crate::ui::capability::CapabilityRights,
    ) -> bool {
        self.current_task
            .as_ref()
            .filter(|task| task.id == task_id)
            .and_then(|task| task.cnode.lookup_capability_by_id(endpoint_id))
            .map_or(false, |capability| {
                capability.generation == expected_generation
                    && capability.owner == task_id
                    && capability.kind == crate::ui::capability::CapabilityKind::Endpoint
                    && capability.rights.contains(required_right)
            })
    }

    fn current_notification_authority_is_live(
        &self,
        task_id: u64,
        notification_id: crate::ui::capability::CapId,
        expected_generation: u64,
        required_right: crate::ui::capability::CapabilityRights,
    ) -> bool {
        self.current_task
            .as_ref()
            .filter(|task| task.id == task_id)
            .and_then(|task| task.cnode.lookup_capability_by_id(notification_id))
            .is_some_and(|capability| {
                capability.generation == expected_generation
                    && capability.owner == task_id
                    && capability.kind == crate::ui::capability::CapabilityKind::Notification
                    && capability.rights.contains(required_right)
            })
    }

    fn write_ipc_delivery(
        task: &mut Task,
        message: crate::ui::capability::IpcMessage,
        reply_cap_id: u64,
    ) {
        task.saved_user_gprs[0] = crate::ipc::IpcError::Ok.as_u64();
        task.saved_user_gprs[1] = message.label;
        task.saved_user_gprs[2] = message.badge;
        task.saved_user_gprs[3] = message.data[0];
        task.saved_user_gprs[4] = message.data[1];
        task.saved_user_gprs[5] = message.data[2];
        task.saved_user_gprs[6] = message.data[3];
        task.saved_user_gprs[7] = reply_cap_id;
    }

    /// A registered rendezvous receiver may be legacy (no deadline record) or
    /// S145 timed. Any record for that task must be the exact receiver waiter;
    /// another kind/generation is an authority-graph mismatch, not a hint to
    /// deliver anyway.
    fn exact_receive_deadline_for_waiter<const N: usize>(
        deadlines: &crate::ipc_deadline::IpcCallDeadlineRegistry<N>,
        receiver: crate::ipc_rendezvous::ReceiverWaiter,
        endpoint_id: crate::ui::capability::CapId,
    ) -> Result<Option<crate::ipc_wait::WaitRecord>, crate::ipc::IpcError> {
        let record = deadlines.task_snapshot(receiver.task_id());
        if record.is_some_and(|record| {
            record.kind().tag() != crate::ipc_wait::WaitKindTag::Receive
                || record.kind().object_id() != endpoint_id
                || record.kind().object_generation() != receiver.cap_generation()
                || record.kind().reply_cap_id().is_some()
        }) {
            return Err(crate::ipc::IpcError::InvalidCapability);
        }
        Ok(record)
    }

    fn retire_receive_deadline_after_delivery<const N: usize>(
        deadlines: &mut crate::ipc_deadline::IpcCallDeadlineRegistry<N>,
        record: Option<crate::ipc_wait::WaitRecord>,
    ) {
        if let Some(record) = record {
            deadlines
                .complete_delivery_exact(record)
                .expect("CALL delivered but exact RECV deadline did not retire");
        }
    }

    fn switch_after_ipc_park_with_membership_handoff<BeforeSwitch, AfterResume>(
        &mut self,
        parked_context: *mut TaskContext,
        before_switch: BeforeSwitch,
        after_resume: AfterResume,
    ) where
        BeforeSwitch: FnOnce(),
        AfterResume: FnOnce(&mut Self),
    {
        let Some(priority_task) = self.ready_queue.pop() else {
            panic!("transactional IPC parked the current task without a runnable successor");
        };
        let mut next = priority_task.task;
        next.state = TaskState::Running;
        let new_context = &mut next.context as *mut TaskContext;
        let next_slice = next.default_time_slice;

        // IPC blocking is a real scheduler transition, so it must install the
        // next task's TTBR0/ASID just like yield_now does. The context saved by
        // context_switch belongs to the parked Box<Task>; a stack-local dummy
        // loses the live syscall continuation and can resume a stale frame.
        unsafe {
            prepare_task_for_context_switch(&next);
        }
        self.current_task = Some(next);
        self.ticks_until_preempt = next_slice;

        // A gate lease belongs to the task executing this continuation. It
        // must not remain live while the selected task runs. S373 uses these
        // callbacks to release immediately before the machine switch and to
        // rejoin before reading the wake payload when this continuation later
        // resumes. Other IPC paths retain the legacy no-op wrapper below.
        before_switch();
        unsafe {
            crate::arch::aarch64::context_switch(parked_context, new_context);
        }
        after_resume(self);
    }

    fn switch_after_ipc_park(&mut self, parked_context: *mut TaskContext) {
        self.switch_after_ipc_park_with_membership_handoff(parked_context, || {}, |_| {});
    }

    /// Atomically publishes a CALL and parks its caller under one lock order:
    /// IPC transaction -> global endpoint table -> global blocked-task set.
    /// The caller is in the reply wait set before a receiver becomes runnable.
    pub fn ipc_call_commit_and_park(
        &mut self,
        ctx: &mut ExceptionContext,
        user_sp: u64,
        target_endpoint: crate::ui::capability::CapId,
        expected_generation: u64,
        reply_cap_id: crate::ui::capability::CapId,
        message: crate::ui::capability::IpcMessage,
        #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
        s374_irq_guard: crate::arch::aarch64::IrqGuard,
        #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
        s374_writer_access: crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s374_el0_ipc_call_writer_guard_integration::G8lS374ProductionSchedulerWriterAccess,
    ) -> Result<(), crate::ipc::IpcError> {
        use crate::ipc_rendezvous::{CallError, CallOutcome, FinishOutcome};

        #[cfg(not(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5")))]
        let _irq_guard = crate::arch::aarch64::IrqGuard::new();
        let transaction = IPC_TRANSACTION_LOCK.lock();
        let mut deadlines = crate::ipc::IPC_CALL_DEADLINES.lock();
        let caller_task = self
            .current_task
            .as_ref()
            .map(|task| task.id)
            .filter(|task_id| *task_id != 0)
            .ok_or(crate::ipc::IpcError::InvalidCapability)?;
        if !self.current_endpoint_authority_is_live(
            caller_task,
            target_endpoint,
            expected_generation,
            crate::ui::capability::CapabilityRights::ENDPOINT_SEND,
        ) {
            return Err(crate::ipc::IpcError::InvalidCapability);
        }

        let mut endpoints = crate::ui::capability::ENDPOINT_REGISTRY.lock();
        let target_index = endpoints
            .iter()
            .position(|endpoint| endpoint.id == target_endpoint && !endpoint.is_reply_cap)
            .ok_or(crate::ipc::IpcError::InvalidCapability)?;
        let reply_is_linked = endpoints.iter().any(|endpoint| {
            endpoint.id == reply_cap_id
                && endpoint.is_reply_cap
                && endpoint.owner == caller_task
                && endpoint.reply_target == Some(target_endpoint)
        });
        if !reply_is_linked {
            return Err(crate::ipc::IpcError::InvalidCapability);
        }

        let waiting_receiver = endpoints[target_index].rendezvous.waiting_receiver();
        if waiting_receiver.is_none() && self.ready_queue.is_empty() {
            return Err(crate::ipc::IpcError::NoReceiver);
        }
        if waiting_receiver.is_some() {
            self.ready_queue
                .try_reserve(1)
                .map_err(|_| crate::ipc::IpcError::NoReceiver)?;
        }
        self.save_current_ipc_context(ctx, user_sp);

        let mut blocked = self.ipc_blocked_tasks.lock();
        blocked
            .try_reserve(1)
            .map_err(|_| crate::ipc::IpcError::NoReceiver)?;
        let receiver_deadline = if let Some(receiver) = waiting_receiver {
            let receiver_task = blocked.iter().find(|task| {
                task.id == receiver.task_id()
                    && matches!(
                        task.state,
                        TaskState::BlockedOnIpc {
                            endpoint_id,
                            is_call: false,
                        } if endpoint_id == target_endpoint
                    )
            });
            let receiver_authority_is_live = receiver_task
                .and_then(|task| task.cnode.lookup_capability_by_id(target_endpoint))
                .map_or(false, |capability| {
                    capability.generation == receiver.cap_generation()
                        && capability.owner == receiver.task_id()
                        && capability.kind == crate::ui::capability::CapabilityKind::Endpoint
                        && capability
                            .rights
                            .contains(crate::ui::capability::CapabilityRights::ENDPOINT_RECV)
                });
            if receiver.wait_token() != target_endpoint || !receiver_authority_is_live {
                return Err(crate::ipc::IpcError::InvalidCapability);
            }
            Self::exact_receive_deadline_for_waiter(&deadlines, receiver, target_endpoint)?
        } else {
            None
        };

        let outcome = endpoints[target_index]
            .rendezvous
            .call(caller_task, reply_cap_id, message)
            .map_err(|error| match error {
                CallError::QueueFull | CallError::ReplyTableFull => crate::ipc::IpcError::QueueFull,
                _ => crate::ipc::IpcError::InvalidCapability,
            })?;
        match endpoints[target_index]
            .rendezvous
            .finish_call_park(caller_task, reply_cap_id)
        {
            Ok(FinishOutcome::Park) => {}
            Ok(FinishOutcome::Ready(_)) | Ok(FinishOutcome::Cancelled) | Err(_) => {
                // CALL, finish and scheduler publication are serialized by
                // IPC_TRANSACTION_LOCK.  No REPLY/revoke transition can run
                // between `call` and this point, so any non-Park result means
                // the model and scheduler have already diverged. Returning a
                // recoverable syscall error here would strand a published
                // request/reply record; fail-stop before making it worse.
                panic!("CALL rendezvous changed inside one IPC transaction")
            }
        }

        let mut caller = self
            .current_task
            .take()
            .expect("preflighted CALL current task disappeared");
        caller.state = TaskState::BlockedOnIpc {
            endpoint_id: reply_cap_id,
            is_call: true,
        };
        // Moving the Box through the blocked/ready/current containers does not
        // move its Task pointee, so this exact SAVE target stays valid until
        // the caller is scheduled and resumes this syscall continuation.
        let caller_context = &mut caller.context as *mut TaskContext;
        blocked.push(caller);

        match outcome {
            CallOutcome::Queued => {}
            CallOutcome::Deliver {
                receiver_task,
                receiver_wait_token,
                request,
                ..
            } => {
                if receiver_wait_token != target_endpoint {
                    panic!("rendezvous receiver wait-token changed during CALL commit");
                }
                let receiver_position = blocked
                    .iter()
                    .position(|task| {
                        task.id == receiver_task
                            && matches!(
                                task.state,
                                TaskState::BlockedOnIpc { endpoint_id, .. }
                                    if endpoint_id == target_endpoint
                            )
                    })
                    .expect("preflighted rendezvous receiver disappeared");
                let mut receiver = blocked.remove(receiver_position);
                Self::retire_receive_deadline_after_delivery(&mut deadlines, receiver_deadline);
                Self::write_ipc_delivery(&mut receiver, request, reply_cap_id);
                receiver.state = TaskState::Ready;
                self.ready_queue.push(PriorityTask::new(receiver));
            }
        }

        drop(blocked);
        drop(endpoints);
        drop(deadlines);
        drop(transaction);
        #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
        self.switch_after_ipc_park_with_membership_handoff(
            caller_context,
            || {
                drop(s374_writer_access);
                drop(s374_irq_guard);
            },
            |scheduler| {
                let s374_resume_irq_guard = crate::arch::aarch64::IrqGuard::new();
                let s374_resume_writer_access = crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s374_el0_ipc_call_writer_guard_integration::acquire_s374_production_scheduler_writer_access()
                    .unwrap_or_else(|error| {
                        panic!(
                            "S374 resumed normal EL0 IPC-call scheduler writer guard failed closed: {:?}",
                            error
                        )
                    });
                scheduler.restore_current_ipc_context(ctx);
                drop(s374_resume_writer_access);
                drop(s374_resume_irq_guard);
            },
        );
        #[cfg(not(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5")))]
        {
            self.switch_after_ipc_park(caller_context);
            self.restore_current_ipc_context(ctx);
        }
        Ok(())
    }

    /// S144 deadline-bearing CALL. This is deliberately a distinct ABI path:
    /// legacy SYS_IPC_CALL never interprets an unspecified x6 register. The
    /// fixed wait record is armed under `IPC_TRANSACTION_LOCK` before the
    /// rendezvous request becomes visible, and every fallible allocation or
    /// authority check precedes that publication point.
    #[allow(clippy::too_many_arguments)]
    pub fn ipc_call_timeout_commit_and_park(
        &mut self,
        ctx: &mut ExceptionContext,
        user_sp: u64,
        target_endpoint: crate::ui::capability::CapId,
        expected_generation: u64,
        reply_cap_id: crate::ui::capability::CapId,
        reply_generation: u64,
        message: crate::ui::capability::IpcMessage,
        now_tick: u64,
        timeout_ticks: u64,
        #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
        s379_irq_guard: crate::arch::aarch64::IrqGuard,
        #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
        s379_writer_access: crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s379_el0_ipc_call_timeout_writer_guard_integration::G8lS379ProductionSchedulerWriterAccess,
    ) -> Result<(), crate::ipc::IpcError> {
        use crate::ipc_deadline::IpcCallDeadlineRegistryError;
        use crate::ipc_rendezvous::{CallError, CallOutcome, FinishOutcome};
        use crate::ipc_wait::WaitError;

        #[cfg(not(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5")))]
        let _irq_guard = crate::arch::aarch64::IrqGuard::new();
        let transaction = IPC_TRANSACTION_LOCK.lock();
        let caller_task = self
            .current_task
            .as_ref()
            .map(|task| task.id)
            .filter(|task_id| *task_id != 0)
            .ok_or(crate::ipc::IpcError::InvalidCapability)?;
        if !self.current_endpoint_authority_is_live(
            caller_task,
            target_endpoint,
            expected_generation,
            crate::ui::capability::CapabilityRights::ENDPOINT_SEND,
        ) {
            return Err(crate::ipc::IpcError::InvalidCapability);
        }

        let reply_authority_is_live = self
            .current_task
            .as_ref()
            .and_then(|task| task.cnode.lookup_capability_by_id(reply_cap_id))
            .is_some_and(|capability| {
                capability.id == reply_cap_id
                    && capability.owner == caller_task
                    && capability.generation == reply_generation
                    && capability.kind == crate::ui::capability::CapabilityKind::Endpoint
                    && capability.parent.is_none()
            });
        if !reply_authority_is_live {
            return Err(crate::ipc::IpcError::InvalidCapability);
        }

        // Global lock order for every deadline race is:
        // IPC transaction -> deadline registry -> endpoint/provenance ->
        // scheduler blocked set. Timer and REPLY follow the same order.
        let mut deadlines = crate::ipc::IPC_CALL_DEADLINES.lock();
        let mut endpoints = crate::ui::capability::ENDPOINT_REGISTRY.lock();
        let target_index = endpoints
            .iter()
            .position(|endpoint| endpoint.id == target_endpoint && !endpoint.is_reply_cap)
            .ok_or(crate::ipc::IpcError::InvalidCapability)?;
        let reply_is_linked = endpoints.iter().any(|endpoint| {
            endpoint.id == reply_cap_id
                && endpoint.is_reply_cap
                && endpoint.owner == caller_task
                && endpoint.reply_target == Some(target_endpoint)
        });
        if !reply_is_linked {
            return Err(crate::ipc::IpcError::InvalidCapability);
        }

        let waiting_receiver = endpoints[target_index].rendezvous.waiting_receiver();
        if waiting_receiver.is_none() && self.ready_queue.is_empty() {
            return Err(crate::ipc::IpcError::NoReceiver);
        }
        if waiting_receiver.is_some() {
            self.ready_queue
                .try_reserve(1)
                .map_err(|_| crate::ipc::IpcError::NoReceiver)?;
        }
        self.save_current_ipc_context(ctx, user_sp);

        let mut blocked = self.ipc_blocked_tasks.lock();
        blocked
            .try_reserve(1)
            .map_err(|_| crate::ipc::IpcError::NoReceiver)?;
        let receiver_deadline = if let Some(receiver) = waiting_receiver {
            let receiver_task = blocked.iter().find(|task| {
                task.id == receiver.task_id()
                    && matches!(
                        task.state,
                        TaskState::BlockedOnIpc {
                            endpoint_id,
                            is_call: false,
                        } if endpoint_id == target_endpoint
                    )
            });
            let receiver_authority_is_live = receiver_task
                .and_then(|task| task.cnode.lookup_capability_by_id(target_endpoint))
                .is_some_and(|capability| {
                    capability.generation == receiver.cap_generation()
                        && capability.owner == receiver.task_id()
                        && capability.kind == crate::ui::capability::CapabilityKind::Endpoint
                        && capability
                            .rights
                            .contains(crate::ui::capability::CapabilityRights::ENDPOINT_RECV)
                });
            if receiver.wait_token() != target_endpoint || !receiver_authority_is_live {
                return Err(crate::ipc::IpcError::InvalidCapability);
            }
            Self::exact_receive_deadline_for_waiter(&deadlines, receiver, target_endpoint)?
        } else {
            None
        };

        let deadline_record = deadlines
            .register_call(
                caller_task,
                target_endpoint,
                expected_generation,
                reply_cap_id,
                reply_generation,
                now_tick,
                timeout_ticks,
            )
            .map_err(|error| match error {
                IpcCallDeadlineRegistryError::Wait(WaitError::TableFull) => {
                    crate::ipc::IpcError::QueueFull
                }
                IpcCallDeadlineRegistryError::Wait(
                    WaitError::DeadlineNotFuture | WaitError::DeadlineTooFar,
                )
                | IpcCallDeadlineRegistryError::WaitEpochExhausted => {
                    crate::ipc::IpcError::InvalidDeadline
                }
                IpcCallDeadlineRegistryError::Wait(_) => crate::ipc::IpcError::InvalidCapability,
            })?;

        let outcome =
            match endpoints[target_index]
                .rendezvous
                .call(caller_task, reply_cap_id, message)
            {
                Ok(outcome) => outcome,
                Err(error) => {
                    deadlines
                        .cancel_exact(deadline_record)
                        .expect("failed CALL publication must roll back its exact deadline");
                    return Err(match error {
                        CallError::QueueFull | CallError::ReplyTableFull => {
                            crate::ipc::IpcError::QueueFull
                        }
                        _ => crate::ipc::IpcError::InvalidCapability,
                    });
                }
            };
        match endpoints[target_index]
            .rendezvous
            .finish_call_park(caller_task, reply_cap_id)
        {
            Ok(FinishOutcome::Park) => {}
            Ok(FinishOutcome::Ready(_)) | Ok(FinishOutcome::Cancelled) | Err(_) => {
                panic!("deadline CALL rendezvous changed inside one IPC transaction")
            }
        }

        let mut caller = self
            .current_task
            .take()
            .expect("preflighted deadline CALL current task disappeared");
        caller.state = TaskState::BlockedOnIpc {
            endpoint_id: reply_cap_id,
            is_call: true,
        };
        let caller_context = &mut caller.context as *mut TaskContext;
        blocked.push(caller);

        match outcome {
            CallOutcome::Queued => {}
            CallOutcome::Deliver {
                receiver_task,
                receiver_wait_token,
                request,
                ..
            } => {
                if receiver_wait_token != target_endpoint {
                    panic!("deadline CALL receiver wait-token changed during commit");
                }
                let receiver_position = blocked
                    .iter()
                    .position(|task| {
                        task.id == receiver_task
                            && matches!(
                                task.state,
                                TaskState::BlockedOnIpc { endpoint_id, .. }
                                    if endpoint_id == target_endpoint
                            )
                    })
                    .expect("preflighted deadline receiver disappeared");
                let mut receiver = blocked.remove(receiver_position);
                Self::retire_receive_deadline_after_delivery(&mut deadlines, receiver_deadline);
                Self::write_ipc_delivery(&mut receiver, request, reply_cap_id);
                receiver.state = TaskState::Ready;
                self.ready_queue.push(PriorityTask::new(receiver));
            }
        }

        drop(blocked);
        drop(endpoints);
        drop(deadlines);
        drop(transaction);
        #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
        self.switch_after_ipc_park_with_membership_handoff(
            caller_context,
            || {
                drop(s379_writer_access);
                drop(s379_irq_guard);
            },
            |scheduler| {
                let s379_resume_irq_guard = crate::arch::aarch64::IrqGuard::new();
                let s379_resume_writer_access = crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s379_el0_ipc_call_timeout_writer_guard_integration::acquire_s379_production_scheduler_writer_access()
                    .unwrap_or_else(|error| {
                        panic!(
                            "S379 resumed EL0 IPC call-timeout scheduler writer guard failed closed: {:?}",
                            error
                        )
                    });
                scheduler.restore_current_ipc_context(ctx);
                drop(s379_resume_writer_access);
                drop(s379_resume_irq_guard);
            },
        );
        #[cfg(not(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5")))]
        {
            self.switch_after_ipc_park(caller_context);
            self.restore_current_ipc_context(ctx);
        }
        Ok(())
    }

    /// Publish one synchronous kernel-supervisor request through the same
    /// bounded endpoint rendezvous used by EL0 CALL, then block the current
    /// kernel task until an ordinary EL0 REPLY wakes it.  This is not an
    /// ambient kernel message queue: the current task must own a live SEND
    /// capability, the reply object is one-shot, and every transition remains
    /// under the production IPC transaction/registry/scheduler lock order.
    pub fn ipc_kernel_call_and_wait(
        &mut self,
        target_endpoint: crate::ui::capability::CapId,
        expected_generation: u64,
        reply_cap_id: crate::ui::capability::CapId,
        message: crate::ui::capability::IpcMessage,
    ) -> Result<crate::ui::capability::IpcMessage, crate::ipc::IpcError> {
        use crate::ipc_rendezvous::{CallError, CallOutcome, FinishOutcome};

        let _irq_guard = crate::arch::aarch64::IrqGuard::new();
        let transaction = IPC_TRANSACTION_LOCK.lock();
        let mut deadlines = crate::ipc::IPC_CALL_DEADLINES.lock();
        let caller_task = self
            .current_task
            .as_ref()
            .filter(|task| !task.is_user)
            .map(|task| task.id)
            .filter(|task_id| *task_id != 0)
            .ok_or(crate::ipc::IpcError::InvalidCapability)?;
        if !self.current_endpoint_authority_is_live(
            caller_task,
            target_endpoint,
            expected_generation,
            crate::ui::capability::CapabilityRights::ENDPOINT_SEND,
        ) {
            return Err(crate::ipc::IpcError::InvalidCapability);
        }

        let mut endpoints = crate::ui::capability::ENDPOINT_REGISTRY.lock();
        let target_index = endpoints
            .iter()
            .position(|endpoint| endpoint.id == target_endpoint && !endpoint.is_reply_cap)
            .ok_or(crate::ipc::IpcError::InvalidCapability)?;
        let reply_is_linked = endpoints.iter().any(|endpoint| {
            endpoint.id == reply_cap_id
                && endpoint.is_reply_cap
                && endpoint.owner == caller_task
                && endpoint.reply_target == Some(target_endpoint)
        });
        if !reply_is_linked {
            return Err(crate::ipc::IpcError::InvalidCapability);
        }

        let waiting_receiver = endpoints[target_index].rendezvous.waiting_receiver();
        if waiting_receiver.is_none() && self.ready_queue.is_empty() {
            return Err(crate::ipc::IpcError::NoReceiver);
        }
        if waiting_receiver.is_some() {
            self.ready_queue
                .try_reserve(1)
                .map_err(|_| crate::ipc::IpcError::NoReceiver)?;
        }
        let mut blocked = self.ipc_blocked_tasks.lock();
        blocked
            .try_reserve(1)
            .map_err(|_| crate::ipc::IpcError::NoReceiver)?;
        let receiver_deadline = if let Some(receiver) = waiting_receiver {
            let receiver_authority_is_live = blocked
                .iter()
                .find(|task| {
                    task.id == receiver.task_id()
                        && matches!(
                            task.state,
                            TaskState::BlockedOnIpc {
                                endpoint_id,
                                is_call: false,
                            } if endpoint_id == target_endpoint
                        )
                })
                .and_then(|task| task.cnode.lookup_capability_by_id(target_endpoint))
                .map_or(false, |capability| {
                    capability.generation == receiver.cap_generation()
                        && capability.owner == receiver.task_id()
                        && capability.kind == crate::ui::capability::CapabilityKind::Endpoint
                        && capability
                            .rights
                            .contains(crate::ui::capability::CapabilityRights::ENDPOINT_RECV)
                });
            if receiver.wait_token() != target_endpoint || !receiver_authority_is_live {
                return Err(crate::ipc::IpcError::InvalidCapability);
            }
            Self::exact_receive_deadline_for_waiter(&deadlines, receiver, target_endpoint)?
        } else {
            None
        };

        let outcome = endpoints[target_index]
            .rendezvous
            .call(caller_task, reply_cap_id, message)
            .map_err(|error| match error {
                CallError::QueueFull | CallError::ReplyTableFull => crate::ipc::IpcError::QueueFull,
                _ => crate::ipc::IpcError::InvalidCapability,
            })?;
        if !matches!(
            endpoints[target_index]
                .rendezvous
                .finish_call_park(caller_task, reply_cap_id),
            Ok(FinishOutcome::Park)
        ) {
            panic!("kernel CALL rendezvous changed inside one IPC transaction");
        }

        let mut caller = self
            .current_task
            .take()
            .expect("preflighted kernel CALL current task disappeared");
        caller.state = TaskState::BlockedOnIpc {
            endpoint_id: reply_cap_id,
            is_call: true,
        };
        let caller_context = &mut caller.context as *mut TaskContext;
        blocked.push(caller);

        match outcome {
            CallOutcome::Queued => {}
            CallOutcome::Deliver {
                receiver_task,
                receiver_wait_token,
                request,
                ..
            } => {
                if receiver_wait_token != target_endpoint {
                    panic!("kernel CALL receiver wait-token changed during commit");
                }
                let receiver_position = blocked
                    .iter()
                    .position(|task| {
                        task.id == receiver_task
                            && matches!(
                                task.state,
                                TaskState::BlockedOnIpc { endpoint_id, .. }
                                    if endpoint_id == target_endpoint
                            )
                    })
                    .expect("preflighted kernel CALL receiver disappeared");
                let mut receiver = blocked.remove(receiver_position);
                Self::retire_receive_deadline_after_delivery(&mut deadlines, receiver_deadline);
                Self::write_ipc_delivery(&mut receiver, request, reply_cap_id);
                receiver.state = TaskState::Ready;
                self.ready_queue.push(PriorityTask::new(receiver));
            }
        }

        drop(blocked);
        drop(endpoints);
        drop(deadlines);
        drop(transaction);
        self.switch_after_ipc_park(caller_context);

        let caller = self
            .current_task
            .as_ref()
            .filter(|task| task.id == caller_task && !task.is_user)
            .expect("kernel CALL continuation resumed under another task");
        if caller.saved_user_gprs[0] != crate::ipc::IpcError::Ok.as_u64()
            || caller.saved_user_gprs[7] != 0
        {
            return Err(crate::ipc::IpcError::InvalidCapability);
        }
        Ok(crate::ui::capability::IpcMessage {
            label: caller.saved_user_gprs[1],
            badge: caller.saved_user_gprs[2],
            data: [
                caller.saved_user_gprs[3],
                caller.saved_user_gprs[4],
                caller.saved_user_gprs[5],
                caller.saved_user_gprs[6],
            ],
        })
    }

    /// Atomically performs RECV's FIFO-pop-or-waiter-registration decision.
    /// `Some` is an immediate queued delivery; `None` means the task was
    /// parked and a context switch was initiated.
    pub fn ipc_recv_or_park(
        &mut self,
        ctx: &mut ExceptionContext,
        user_sp: u64,
        endpoint_id: crate::ui::capability::CapId,
        expected_generation: u64,
        #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
        s373_irq_guard: crate::arch::aarch64::IrqGuard,
        #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
        s373_writer_access: crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s373_el0_ipc_receive_writer_guard_integration::G8lS373ProductionSchedulerWriterAccess,
    ) -> Result<Option<crate::ui::capability::IpcEnvelope>, crate::ipc::IpcError> {
        use crate::ipc_rendezvous::{ReceiverWaiter, RecvOutcome};

        #[cfg(not(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5")))]
        let _irq_guard = crate::arch::aarch64::IrqGuard::new();
        let transaction = IPC_TRANSACTION_LOCK.lock();
        let receiver_task = self
            .current_task
            .as_ref()
            .map(|task| task.id)
            .filter(|task_id| *task_id != 0)
            .ok_or(crate::ipc::IpcError::InvalidCapability)?;
        if !self.current_endpoint_authority_is_live(
            receiver_task,
            endpoint_id,
            expected_generation,
            crate::ui::capability::CapabilityRights::ENDPOINT_RECV,
        ) {
            return Err(crate::ipc::IpcError::InvalidCapability);
        }
        let waiter =
            ReceiverWaiter::new_with_generation(receiver_task, endpoint_id, expected_generation)
                .map_err(|_| crate::ipc::IpcError::InvalidCapability)?;

        let mut endpoints = crate::ui::capability::ENDPOINT_REGISTRY.lock();
        let target = endpoints
            .iter_mut()
            .find(|endpoint| endpoint.id == endpoint_id && !endpoint.is_reply_cap)
            .ok_or(crate::ipc::IpcError::InvalidCapability)?;

        let will_park = target.rendezvous.queued_len() == 0;
        if will_park && self.ready_queue.is_empty() {
            return Err(crate::ipc::IpcError::NoReceiver);
        }
        if will_park {
            self.save_current_ipc_context(ctx, user_sp);
        }
        // Only the waiter-registration branch needs blocked-set capacity.
        // Reserving on an immediate FIFO delivery could spuriously reject a
        // receive under allocator pressure even though it does not allocate.
        let mut blocked = if will_park {
            let mut blocked = self.ipc_blocked_tasks.lock();
            blocked
                .try_reserve(1)
                .map_err(|_| crate::ipc::IpcError::NoReceiver)?;
            Some(blocked)
        } else {
            None
        };

        match target
            .rendezvous
            .recv(waiter)
            .map_err(|_| crate::ipc::IpcError::InvalidCapability)?
        {
            RecvOutcome::Deliver {
                request,
                reply_token,
                ..
            } => {
                drop(blocked);
                drop(endpoints);
                drop(transaction);
                Ok(Some(crate::ui::capability::IpcEnvelope {
                    message: request,
                    reply_cap_id: reply_token,
                }))
            }
            RecvOutcome::Registered => {
                let mut blocked_guard = blocked
                    .take()
                    .expect("RECV registered without preflighted blocked capacity");
                let mut receiver = self
                    .current_task
                    .take()
                    .expect("preflighted RECV current task disappeared");
                receiver.state = TaskState::BlockedOnIpc {
                    endpoint_id,
                    is_call: false,
                };
                let receiver_context = &mut receiver.context as *mut TaskContext;
                blocked_guard.push(receiver);
                drop(blocked_guard);
                drop(blocked);
                drop(endpoints);
                drop(transaction);
                #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
                self.switch_after_ipc_park_with_membership_handoff(
                    receiver_context,
                    || {
                        drop(s373_writer_access);
                        drop(s373_irq_guard);
                    },
                    |scheduler| {
                        let s373_resume_irq_guard = crate::arch::aarch64::IrqGuard::new();
                        let s373_resume_writer_access = crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s373_el0_ipc_receive_writer_guard_integration::acquire_s373_production_scheduler_writer_access()
                            .unwrap_or_else(|error| {
                                panic!(
                                    "S373 resumed EL0 IPC-receive scheduler writer guard failed closed: {:?}",
                                    error
                                )
                            });
                        scheduler.restore_current_ipc_context(ctx);
                        drop(s373_resume_writer_access);
                        drop(s373_resume_irq_guard);
                    },
                );
                #[cfg(not(all(
                    target_arch = "aarch64",
                    target_os = "none",
                    feature = "board-rpi5"
                )))]
                {
                    self.switch_after_ipc_park(receiver_context);
                    self.restore_current_ipc_context(ctx);
                }
                Ok(None)
            }
        }
    }

    /// S145 opt-in deadline-bearing RECV. The legacy syscall above remains
    /// byte-for-byte policy compatible and never interprets x6. Only an empty
    /// endpoint arms a wait record; a queued FIFO message is returned with
    /// `IMMEDIATE_DELIVERY_DEADLINE=UNARMED`.
    pub fn ipc_recv_timeout_or_park(
        &mut self,
        ctx: &mut ExceptionContext,
        user_sp: u64,
        endpoint_id: crate::ui::capability::CapId,
        expected_generation: u64,
        now_tick: u64,
        timeout_ticks: u64,
        #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
        s378_irq_guard: crate::arch::aarch64::IrqGuard,
        #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
        s378_writer_access: crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s378_el0_ipc_receive_timeout_writer_guard_integration::G8lS378ProductionSchedulerWriterAccess,
    ) -> Result<Option<crate::ui::capability::IpcEnvelope>, crate::ipc::IpcError> {
        use crate::ipc_deadline::IpcCallDeadlineRegistryError;
        use crate::ipc_rendezvous::{ReceiverWaiter, RecvOutcome};
        use crate::ipc_wait::WaitError;

        #[cfg(not(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5")))]
        let _irq_guard = crate::arch::aarch64::IrqGuard::new();
        let transaction = IPC_TRANSACTION_LOCK.lock();
        let receiver_task = self
            .current_task
            .as_ref()
            .map(|task| task.id)
            .filter(|task_id| *task_id != 0)
            .ok_or(crate::ipc::IpcError::InvalidCapability)?;
        if !self.current_endpoint_authority_is_live(
            receiver_task,
            endpoint_id,
            expected_generation,
            crate::ui::capability::CapabilityRights::ENDPOINT_RECV,
        ) {
            return Err(crate::ipc::IpcError::InvalidCapability);
        }
        let waiter =
            ReceiverWaiter::new_with_generation(receiver_task, endpoint_id, expected_generation)
                .map_err(|_| crate::ipc::IpcError::InvalidCapability)?;

        // Shared CALL/RECV arbitration order: transaction -> deadline table ->
        // endpoint -> blocked scheduler set.
        let mut deadlines = crate::ipc::IPC_CALL_DEADLINES.lock();
        let mut endpoints = crate::ui::capability::ENDPOINT_REGISTRY.lock();
        let target_index = endpoints
            .iter()
            .position(|endpoint| endpoint.id == endpoint_id && !endpoint.is_reply_cap)
            .ok_or(crate::ipc::IpcError::InvalidCapability)?;
        let will_park = endpoints[target_index].rendezvous.queued_len() == 0;
        if will_park && self.ready_queue.is_empty() {
            return Err(crate::ipc::IpcError::NoReceiver);
        }

        let mut blocked = if will_park {
            self.save_current_ipc_context(ctx, user_sp);
            let mut blocked = self.ipc_blocked_tasks.lock();
            blocked
                .try_reserve(1)
                .map_err(|_| crate::ipc::IpcError::NoReceiver)?;
            Some(blocked)
        } else {
            None
        };

        if !will_park {
            // S145 acceptance marker: IMMEDIATE_DELIVERY_DEADLINE=UNARMED.
            let outcome = endpoints[target_index]
                .rendezvous
                .recv(waiter)
                .map_err(|_| crate::ipc::IpcError::InvalidCapability)?;
            let RecvOutcome::Deliver {
                request,
                reply_token,
                ..
            } = outcome
            else {
                panic!("non-empty endpoint registered a timed RECV waiter")
            };
            drop(blocked);
            drop(endpoints);
            drop(deadlines);
            drop(transaction);
            return Ok(Some(crate::ui::capability::IpcEnvelope {
                message: request,
                reply_cap_id: reply_token,
            }));
        }

        let deadline_record = deadlines
            .register_receive(
                receiver_task,
                endpoint_id,
                expected_generation,
                now_tick,
                timeout_ticks,
            )
            .map_err(|error| match error {
                IpcCallDeadlineRegistryError::Wait(WaitError::TableFull) => {
                    crate::ipc::IpcError::QueueFull
                }
                IpcCallDeadlineRegistryError::Wait(
                    WaitError::DeadlineNotFuture | WaitError::DeadlineTooFar,
                )
                | IpcCallDeadlineRegistryError::WaitEpochExhausted => {
                    crate::ipc::IpcError::InvalidDeadline
                }
                IpcCallDeadlineRegistryError::Wait(_) => crate::ipc::IpcError::InvalidCapability,
            })?;

        let outcome = endpoints[target_index].rendezvous.recv(waiter);
        match outcome {
            Ok(RecvOutcome::Registered) => {}
            Ok(RecvOutcome::Deliver { .. }) | Err(_) => {
                deadlines
                    .cancel_exact(deadline_record)
                    .expect("failed RECV publication must roll back its exact deadline");
                return Err(crate::ipc::IpcError::InvalidCapability);
            }
        }

        let mut blocked_guard = blocked
            .take()
            .expect("timed RECV registered without blocked capacity");
        let mut receiver = self
            .current_task
            .take()
            .expect("preflighted timed RECV current task disappeared");
        receiver.state = TaskState::BlockedOnIpc {
            endpoint_id,
            is_call: false,
        };
        let receiver_context = &mut receiver.context as *mut TaskContext;
        blocked_guard.push(receiver);
        drop(blocked_guard);
        drop(blocked);
        drop(endpoints);
        drop(deadlines);
        drop(transaction);
        #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
        self.switch_after_ipc_park_with_membership_handoff(
            receiver_context,
            || {
                drop(s378_writer_access);
                drop(s378_irq_guard);
            },
            |scheduler| {
                let s378_resume_irq_guard = crate::arch::aarch64::IrqGuard::new();
                let s378_resume_writer_access = crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s378_el0_ipc_receive_timeout_writer_guard_integration::acquire_s378_production_scheduler_writer_access()
                    .unwrap_or_else(|error| {
                        panic!(
                            "S378 resumed EL0 IPC receive-timeout scheduler writer guard failed closed: {:?}",
                            error
                        )
                    });
                scheduler.restore_current_ipc_context(ctx);
                drop(s378_resume_writer_access);
                drop(s378_resume_irq_guard);
            },
        );
        #[cfg(not(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5")))]
        {
            self.switch_after_ipc_park(receiver_context);
            self.restore_current_ipc_context(ctx);
        }
        Ok(None)
    }

    /// S146 timed notification wait. Matching bits already pending are
    /// consumed immediately without a deadline record. Otherwise the shared
    /// deadline is published before the exact object waiter.
    pub fn notification_wait_timeout_or_park(
        &mut self,
        ctx: &mut ExceptionContext,
        user_sp: u64,
        notification_id: crate::ui::capability::CapId,
        expected_generation: u64,
        mask: u64,
        now_tick: u64,
        timeout_ticks: u64,
        #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
        s377_irq_guard: crate::arch::aarch64::IrqGuard,
        #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
        s377_writer_access: crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s377_el0_notification_wait_timeout_writer_guard_integration::G8lS377ProductionSchedulerWriterAccess,
    ) -> Result<Option<u64>, crate::ipc::IpcError> {
        use crate::ipc_deadline::IpcCallDeadlineRegistryError;
        use crate::ipc_notification::{NotificationWaitOutcome, NotificationWaiter};
        use crate::ipc_wait::WaitError;

        #[cfg(not(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5")))]
        let _irq_guard = crate::arch::aarch64::IrqGuard::new();
        let transaction = IPC_TRANSACTION_LOCK.lock();
        let waiter_task = self
            .current_task
            .as_ref()
            .map(|task| task.id)
            .filter(|task_id| *task_id != 0)
            .ok_or(crate::ipc::IpcError::InvalidCapability)?;
        if !self.current_notification_authority_is_live(
            waiter_task,
            notification_id,
            expected_generation,
            crate::ui::capability::CapabilityRights::NOTIFICATION_WAIT,
        ) {
            return Err(crate::ipc::IpcError::InvalidCapability);
        }
        let waiter = NotificationWaiter::try_new(waiter_task, expected_generation, mask)
            .map_err(|_| crate::ipc::IpcError::InvalidCapability)?;

        let mut deadlines = crate::ipc::IPC_CALL_DEADLINES.lock();
        let mut notifications = crate::ui::capability::NOTIFICATION_REGISTRY.lock();
        let target_index = notifications
            .iter()
            .position(|object| object.id() == notification_id)
            .ok_or(crate::ipc::IpcError::InvalidCapability)?;
        let immediate = notifications[target_index].pending() & mask;
        if immediate != 0 {
            // S146 acceptance marker: IMMEDIATE_NOTIFICATION_DEADLINE=UNARMED.
            let outcome = notifications[target_index]
                .wait(waiter)
                .map_err(|_| crate::ipc::IpcError::InvalidCapability)?;
            let NotificationWaitOutcome::Immediate { observed } = outcome else {
                panic!("ready notification bits published a waiter")
            };
            drop(notifications);
            drop(deadlines);
            drop(transaction);
            return Ok(Some(observed));
        }
        if self.ready_queue.is_empty() {
            return Err(crate::ipc::IpcError::NoReceiver);
        }
        self.save_current_ipc_context(ctx, user_sp);
        let mut blocked = self.ipc_blocked_tasks.lock();
        blocked
            .try_reserve(1)
            .map_err(|_| crate::ipc::IpcError::NoReceiver)?;

        // NOTIFICATION_WAIT_ARM_BEFORE_WAITER: timer authority exists before
        // the object can expose a parked waiter to a signal producer.
        let deadline_record = deadlines
            .register_notification(
                waiter_task,
                notification_id,
                expected_generation,
                mask,
                now_tick,
                timeout_ticks,
            )
            .map_err(|error| match error {
                IpcCallDeadlineRegistryError::Wait(WaitError::TableFull) => {
                    crate::ipc::IpcError::QueueFull
                }
                IpcCallDeadlineRegistryError::Wait(
                    WaitError::DeadlineNotFuture | WaitError::DeadlineTooFar,
                )
                | IpcCallDeadlineRegistryError::WaitEpochExhausted => {
                    crate::ipc::IpcError::InvalidDeadline
                }
                IpcCallDeadlineRegistryError::Wait(_) => crate::ipc::IpcError::InvalidCapability,
            })?;
        match notifications[target_index].wait(waiter) {
            Ok(NotificationWaitOutcome::Registered) => {}
            Ok(NotificationWaitOutcome::Immediate { .. }) | Err(_) => {
                deadlines
                    .cancel_exact(deadline_record)
                    .expect("failed notification waiter publication lost its deadline rollback");
                return Err(crate::ipc::IpcError::InvalidCapability);
            }
        }

        let mut task = self
            .current_task
            .take()
            .expect("preflighted notification waiter task disappeared");
        task.state = TaskState::BlockedOnNotification { notification_id };
        let parked_context = &mut task.context as *mut TaskContext;
        blocked.push(task);
        drop(blocked);
        drop(notifications);
        drop(deadlines);
        drop(transaction);
        #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
        self.switch_after_ipc_park_with_membership_handoff(
            parked_context,
            || {
                drop(s377_writer_access);
                drop(s377_irq_guard);
            },
            |scheduler| {
                let s377_resume_irq_guard = crate::arch::aarch64::IrqGuard::new();
                let s377_resume_writer_access = crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s377_el0_notification_wait_timeout_writer_guard_integration::acquire_s377_production_scheduler_writer_access()
                    .unwrap_or_else(|error| {
                        panic!(
                            "S377 resumed EL0 notification-wait scheduler writer guard failed closed: {:?}",
                            error
                        )
                    });
                scheduler.restore_current_ipc_context(ctx);
                drop(s377_resume_writer_access);
                drop(s377_resume_irq_guard);
            },
        );
        #[cfg(not(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5")))]
        {
            self.switch_after_ipc_park(parked_context);
            self.restore_current_ipc_context(ctx);
        }
        Ok(None)
    }

    /// OR one signal into a coalescing notification. A matching waiter is
    /// validated across object, shared deadline, CNode and scheduler state
    /// before the allocation-free signal/wake commit.
    pub fn notification_signal(
        &mut self,
        notification_id: crate::ui::capability::CapId,
        expected_generation: u64,
        bits: u64,
    ) -> Result<crate::ipc_notification::NotificationSignalOutcome, crate::ipc::IpcError> {
        use crate::ipc_notification::NotificationSignalOutcome;

        let _irq_guard = crate::arch::aarch64::IrqGuard::new();
        let _transaction = IPC_TRANSACTION_LOCK.lock();
        let signaler_task = self
            .current_task
            .as_ref()
            .map(|task| task.id)
            .filter(|task_id| *task_id != 0)
            .ok_or(crate::ipc::IpcError::InvalidCapability)?;
        if bits == 0
            || !self.current_notification_authority_is_live(
                signaler_task,
                notification_id,
                expected_generation,
                crate::ui::capability::CapabilityRights::NOTIFICATION_SIGNAL,
            )
        {
            return Err(crate::ipc::IpcError::InvalidCapability);
        }

        let mut deadlines = crate::ipc::IPC_CALL_DEADLINES.lock();
        let mut notifications = crate::ui::capability::NOTIFICATION_REGISTRY.lock();
        let target_index = notifications
            .iter()
            .position(|object| object.id() == notification_id)
            .ok_or(crate::ipc::IpcError::InvalidCapability)?;
        let waiter = notifications[target_index].waiter_snapshot();
        let will_wake = waiter.is_some_and(|waiter| {
            (notifications[target_index].pending() | bits) & waiter.mask() != 0
        });
        if !will_wake {
            return notifications[target_index]
                .signal(bits)
                .map_err(|_| crate::ipc::IpcError::InvalidCapability);
        }

        let waiter = waiter.expect("will_wake without a notification waiter");
        let deadline_record = deadlines
            .task_snapshot(waiter.task_id())
            .filter(|record| {
                record.kind().tag() == crate::ipc_wait::WaitKindTag::Notification
                    && record.kind().object_id() == notification_id
                    && record.kind().object_generation() == waiter.capability_generation()
                    && record.kind().notification_mask() == Some(waiter.mask())
            })
            .ok_or(crate::ipc::IpcError::InvalidCapability)?;
        let mut blocked = self.ipc_blocked_tasks.lock();
        let task_position = blocked
            .iter()
            .position(|task| {
                task.id == waiter.task_id()
                    && matches!(
                        task.state,
                        TaskState::BlockedOnNotification {
                            notification_id: blocked_id,
                        } if blocked_id == notification_id
                    )
                    && task
                        .cnode
                        .lookup_capability_by_id(notification_id)
                        .is_some_and(|capability| {
                            capability.kind == crate::ui::capability::CapabilityKind::Notification
                                && capability.generation == waiter.capability_generation()
                                && capability.rights.contains(
                                    crate::ui::capability::CapabilityRights::NOTIFICATION_WAIT,
                                )
                        })
            })
            .ok_or(crate::ipc::IpcError::InvalidCapability)?;
        if !self.ipc_wake_capacity_available(1) {
            return Err(crate::ipc::IpcError::NoReceiver);
        }

        let outcome = notifications[target_index]
            .signal(bits)
            .map_err(|_| crate::ipc::IpcError::InvalidCapability)?;
        let NotificationSignalOutcome::Wake {
            waiter: committed_waiter,
            observed,
            ..
        } = outcome
        else {
            panic!("preflighted matching notification did not wake")
        };
        assert_eq!(committed_waiter, waiter);
        let mut task = blocked.remove(task_position);
        task.saved_user_gprs[0] = crate::ipc::IpcError::Ok.as_u64();
        task.saved_user_gprs[1] = observed;
        for register in &mut task.saved_user_gprs[2..=7] {
            *register = 0;
        }
        task.state = TaskState::Ready;
        self.ready_queue.push(PriorityTask::new(task));
        deadlines
            .complete_delivery_exact(deadline_record)
            .expect("matching notification signal lost exact deadline retirement");
        Ok(outcome)
    }

    /// Commits a one-shot reply only after proving the caller is already in
    /// the global blocked set. The reply object is removed after the response
    /// is copied and the caller becomes runnable.
    pub fn ipc_reply_commit(
        &mut self,
        reply_cap_id: crate::ui::capability::CapId,
        message: crate::ui::capability::IpcMessage,
    ) -> crate::ipc::IpcError {
        use crate::ipc_rendezvous::ReplyOutcome;

        let _irq_guard = crate::arch::aarch64::IrqGuard::new();
        let transaction = IPC_TRANSACTION_LOCK.lock();
        let mut deadlines = crate::ipc::IPC_CALL_DEADLINES.lock();
        let Some(responder_task) = self
            .current_task
            .as_ref()
            .map(|task| task.id)
            .filter(|task_id| *task_id != 0)
        else {
            return crate::ipc::IpcError::InvalidCapability;
        };
        // Match lifecycle/mint lock order: IPC transaction -> capability
        // provenance -> endpoint registry -> blocked scheduler set.
        let mut capability_store = crate::ui::capability::get_capability_store();
        let mut endpoints = crate::ui::capability::ENDPOINT_REGISTRY.lock();
        let Some(reply_index) = endpoints
            .iter()
            .position(|endpoint| endpoint.id == reply_cap_id && endpoint.is_reply_cap)
        else {
            return crate::ipc::IpcError::InvalidCapability;
        };
        let caller_task = endpoints[reply_index].owner;
        let Some(target_endpoint) = endpoints[reply_index].reply_target else {
            return crate::ipc::IpcError::InvalidCapability;
        };
        let Some(target_index) = endpoints
            .iter()
            .position(|endpoint| endpoint.id == target_endpoint && !endpoint.is_reply_cap)
        else {
            return crate::ipc::IpcError::InvalidCapability;
        };

        let mut blocked = self.ipc_blocked_tasks.lock();
        let Some(caller_position) = blocked.iter().position(|task| {
            task.id == caller_task
                && matches!(
                    task.state,
                    TaskState::BlockedOnIpc {
                        endpoint_id,
                        is_call: true,
                    } if endpoint_id == reply_cap_id
                )
        }) else {
            return crate::ipc::IpcError::InvalidCapability;
        };
        let reply_authority = blocked[caller_position]
            .cnode
            .lookup_capability_by_id(reply_cap_id)
            .copied()
            .filter(|capability| {
                capability.owner == caller_task
                    && capability.kind == crate::ui::capability::CapabilityKind::Endpoint
                    && capability.parent.is_none()
            });
        let Some(reply_authority) = reply_authority else {
            return crate::ipc::IpcError::InvalidCapability;
        };
        let deadline_record = deadlines.reply_snapshot(reply_cap_id);
        if deadline_record.is_some_and(|record| {
            record.key().task_id() != caller_task
                || record.kind().tag() != crate::ipc_wait::WaitKindTag::Call
                || record.kind().object_id() != target_endpoint
                || record.kind().reply_cap_id() != Some(reply_cap_id)
                || record.kind().reply_generation() != Some(reply_authority.generation)
        }) {
            return crate::ipc::IpcError::InvalidCapability;
        }
        if self.ready_queue.try_reserve(1).is_err() {
            return crate::ipc::IpcError::NoReceiver;
        }

        match endpoints[target_index]
            .rendezvous
            .reply(responder_task, reply_cap_id, message)
        {
            Ok(ReplyOutcome::Wake {
                caller_task: model_caller,
                payload,
                ..
            }) => {
                if model_caller != caller_task {
                    panic!("reply model caller differs from blocked caller");
                }
                let retire_witness = endpoints[target_index]
                    .rendezvous
                    .retire(caller_task, reply_cap_id)
                    .expect("consumed reply record must retire exactly once");
                assert_eq!(retire_witness.caller_task(), caller_task);
                assert_eq!(retire_witness.reply_token(), reply_cap_id);
                let mut caller = blocked.remove(caller_position);
                assert_eq!(
                    caller.cnode.revoke_capability_exact(&reply_authority),
                    Some(reply_authority),
                    "retired reply exact caller CNode revoke failed"
                );
                Self::write_ipc_delivery(&mut caller, payload, 0);
                caller.state = TaskState::Ready;
                self.ready_queue.push(PriorityTask::new(caller));
                let removed_reply = endpoints.remove(reply_index);
                assert_eq!(removed_reply.id, retire_witness.reply_token());
                assert_eq!(removed_reply.owner, retire_witness.caller_task());
                assert_eq!(removed_reply.reply_target, Some(target_endpoint));
                if let Some(record) = deadline_record {
                    deadlines
                        .complete_reply_exact(record)
                        .expect("ordinary REPLY committed but exact deadline did not retire");
                }
            }
            Ok(ReplyOutcome::StoredBeforePark) => {
                // The blocked-set proof above and the model's `parked` bit
                // must agree under the transaction lock. A recoverable error
                // would leave a Replied record with a permanently parked
                // caller, so treat disagreement as an integrity failure.
                panic!("blocked caller has an unparked reply record")
            }
            Err(_) => return crate::ipc::IpcError::InvalidCapability,
        }

        drop(blocked);
        drop(endpoints);
        assert_eq!(
            capability_store.revoke_endpoint_provenance(reply_cap_id, Some(responder_task)),
            1,
            "retired reply must have exactly one provenance record"
        );
        drop(capability_store);
        drop(deadlines);
        drop(transaction);
        crate::ipc::IpcError::Ok
    }

    /// M7.5 — Revoke edildiğinde bloke task'leri uyandır
    ///
    /// NOTE (M6/M7 Multi-core hazırlığı):
    /// ipc_blocked_tasks şu anda Scheduler'ın içinde (tek global).
    /// Gerçek SMP'de ya:
    ///   - Scheduler'ın tamamını spin::Mutex ile sarmak, veya
    ///   - Per-CPU blocked list + cross-CPU IPI ile wake.
    ///
    /// Şu an için ENDPOINT_REGISTRY'nin yaptığı gibi .lock() ile korunması önerilir.
    pub(crate) fn try_reserve_ipc_wake_capacity(&mut self, additional: usize) -> bool {
        self.ready_queue.try_reserve(additional).is_ok()
    }

    /// Timer IRQ preflight must never allocate. All scheduler-created tasks
    /// have already occupied the ready heap once, so a parked task can return
    /// only when an existing slot is available. A false result leaves every
    /// IPC/deadline object untouched for fail-closed handling.
    pub(crate) fn ipc_wake_capacity_available(&self, additional: usize) -> bool {
        self.ready_queue
            .capacity()
            .saturating_sub(self.ready_queue.len())
            >= additional
    }

    /// Commit the scheduler half of one already-preflighted timeout. The
    /// caller is selected by task id + reply object and its exact CNode
    /// generation is retired before it becomes runnable with TimedOut.
    pub(crate) fn wake_timed_out_ipc_caller_exact(
        &mut self,
        caller_task: u64,
        reply_authority: crate::ui::capability::Capability,
    ) {
        assert!(
            self.ipc_wake_capacity_available(1),
            "timed CALL wake lost preflighted ready capacity"
        );
        let mut blocked = self.ipc_blocked_tasks.lock();
        let caller_position = blocked
            .iter()
            .position(|task| {
                task.id == caller_task
                    && matches!(
                        task.state,
                        TaskState::BlockedOnIpc {
                            endpoint_id,
                            is_call: true,
                        } if endpoint_id == reply_authority.id
                    )
                    && task.cnode.can_revoke_capability_exact(&reply_authority)
            })
            .expect("preflighted timed CALL caller disappeared");
        let mut caller = blocked.remove(caller_position);
        assert_eq!(
            caller.cnode.revoke_capability_exact(&reply_authority),
            Some(reply_authority),
            "timed CALL exact reply CNode revoke failed"
        );
        caller.saved_user_gprs[0] = crate::ipc::IpcError::TimedOut.as_u64();
        for register in &mut caller.saved_user_gprs[1..=7] {
            *register = 0;
        }
        caller.state = TaskState::Ready;
        self.ready_queue.push(PriorityTask::new(caller));
    }

    /// Wake one exact timed RECV without consuming its endpoint capability.
    /// The timer-side graph preflight already removed the rendezvous waiter;
    /// this commits only the allocation-free scheduler half.
    pub(crate) fn wake_timed_out_ipc_receiver_exact(
        &mut self,
        receiver_task: u64,
        endpoint_authority: crate::ui::capability::Capability,
    ) {
        assert!(
            self.ipc_wake_capacity_available(1),
            "timed RECV wake lost preflighted ready capacity"
        );
        let mut blocked = self.ipc_blocked_tasks.lock();
        let receiver_position = blocked
            .iter()
            .position(|task| {
                task.id == receiver_task
                    && matches!(
                        task.state,
                        TaskState::BlockedOnIpc {
                            endpoint_id,
                            is_call: false,
                        } if endpoint_id == endpoint_authority.id
                    )
                    && task
                        .cnode
                        .lookup_capability_by_id(endpoint_authority.id)
                        .copied()
                        == Some(endpoint_authority)
            })
            .expect("preflighted timed RECV receiver disappeared");
        let mut receiver = blocked.remove(receiver_position);
        receiver.saved_user_gprs[0] = crate::ipc::IpcError::TimedOut.as_u64();
        for register in &mut receiver.saved_user_gprs[1..=7] {
            *register = 0;
        }
        receiver.state = TaskState::Ready;
        self.ready_queue.push(PriorityTask::new(receiver));
    }

    pub(crate) fn notification_blocked_task_count_on(
        &self,
        task_id: u64,
        notification_id: crate::ui::capability::CapId,
    ) -> usize {
        self.ipc_blocked_tasks
            .lock()
            .iter()
            .filter(|task| {
                task.id == task_id
                    && matches!(
                        task.state,
                        TaskState::BlockedOnNotification {
                            notification_id: blocked_id,
                        } if blocked_id == notification_id
                    )
            })
            .count()
    }

    pub(crate) fn notification_blocked_count_on(
        &self,
        notification_id: crate::ui::capability::CapId,
    ) -> usize {
        self.ipc_blocked_tasks
            .lock()
            .iter()
            .filter(|task| {
                matches!(
                    task.state,
                    TaskState::BlockedOnNotification { notification_id: blocked_id }
                        if blocked_id == notification_id
                )
            })
            .count()
    }

    /// Wake one waiter whose notification authority was revoked after wait
    /// admission. Holder removal may already have committed, so identity is
    /// proven by task/object/state under the same IPC transaction rather than
    /// by re-reading the deleted CNode slot.
    pub(crate) fn wake_revoked_notification_exact(
        &mut self,
        waiter_task: u64,
        notification_id: crate::ui::capability::CapId,
    ) {
        assert!(
            self.ipc_wake_capacity_available(1),
            "revoked notification wake lost preflighted ready capacity"
        );
        let mut blocked = self.ipc_blocked_tasks.lock();
        let task_position = blocked
            .iter()
            .position(|task| {
                task.id == waiter_task
                    && matches!(
                        task.state,
                        TaskState::BlockedOnNotification { notification_id: blocked_id }
                            if blocked_id == notification_id
                    )
            })
            .expect("preflighted revoked notification waiter disappeared");
        let mut task = blocked.remove(task_position);
        task.saved_user_gprs[0] = crate::ipc::IpcError::InvalidCapability.as_u64();
        for register in &mut task.saved_user_gprs[1..=7] {
            *register = 0;
        }
        task.state = TaskState::Ready;
        self.ready_queue.push(PriorityTask::new(task));
    }

    pub(crate) fn wake_timed_out_notification_exact(
        &mut self,
        waiter_task: u64,
        notification_authority: crate::ui::capability::Capability,
    ) {
        assert!(
            self.ipc_wake_capacity_available(1),
            "timed notification wake lost preflighted ready capacity"
        );
        let mut blocked = self.ipc_blocked_tasks.lock();
        let task_position = blocked
            .iter()
            .position(|task| {
                task.id == waiter_task
                    && matches!(
                        task.state,
                        TaskState::BlockedOnNotification { notification_id }
                            if notification_id == notification_authority.id
                    )
                    && task
                        .cnode
                        .lookup_capability_by_id(notification_authority.id)
                        .copied()
                        == Some(notification_authority)
            })
            .expect("preflighted timed notification waiter disappeared");
        let mut task = blocked.remove(task_position);
        task.saved_user_gprs[0] = crate::ipc::IpcError::TimedOut.as_u64();
        for register in &mut task.saved_user_gprs[1..=7] {
            *register = 0;
        }
        task.state = TaskState::Ready;
        self.ready_queue.push(PriorityTask::new(task));
    }

    /// Allocation-free lifecycle audit: a parked rendezvous identity must map
    /// to exactly one scheduler waiter before cancellation is committed.
    pub(crate) fn ipc_blocked_count_on(&self, endpoint_id: crate::ui::capability::CapId) -> usize {
        self.ipc_blocked_tasks
            .lock()
            .iter()
            .filter(|task| {
                matches!(
                    task.state,
                    TaskState::BlockedOnIpc {
                        endpoint_id: blocked_endpoint,
                        ..
                    } if blocked_endpoint == endpoint_id
                )
            })
            .count()
    }

    pub(crate) fn ipc_blocked_task_count_on(
        &self,
        task_id: u64,
        endpoint_id: crate::ui::capability::CapId,
        is_call: bool,
    ) -> usize {
        self.ipc_blocked_tasks
            .lock()
            .iter()
            .filter(|task| {
                task.id == task_id
                    && matches!(
                        task.state,
                        TaskState::BlockedOnIpc {
                            endpoint_id: blocked_endpoint,
                            is_call: blocked_is_call,
                        } if blocked_endpoint == endpoint_id && blocked_is_call == is_call
                    )
            })
            .count()
    }

    pub fn wake_tasks_on_revoked_endpoint(&mut self, endpoint_id: crate::ui::capability::CapId) {
        // Multi-core safe: PerCpu üzerinden kilitle
        let mut deadlines = crate::ipc::IPC_CALL_DEADLINES.lock();
        let mut blocked_list = self.ipc_blocked_tasks.lock();

        let mut i = 0;
        while i < blocked_list.len() {
            let should_wake = matches!(
                blocked_list[i].state,
                TaskState::BlockedOnIpc { endpoint_id: eid, .. } if eid == endpoint_id
            );

            if should_wake {
                let mut task = blocked_list.remove(i);
                let task_asid = task.asid; // ASID'i kaydet (invalidate için)
                let is_call = matches!(task.state, TaskState::BlockedOnIpc { is_call: true, .. });
                if let Some(record) = deadlines.task_snapshot(task.id) {
                    match (is_call, record.kind().tag()) {
                        (true, crate::ipc_wait::WaitKindTag::Call) => assert_eq!(
                            record.kind().reply_cap_id(),
                            Some(endpoint_id),
                            "peer-close wake selected a different deadline reply"
                        ),
                        (false, crate::ipc_wait::WaitKindTag::Receive) => assert_eq!(
                            record.kind().object_id(),
                            endpoint_id,
                            "peer-close wake selected a different deadline endpoint"
                        ),
                        _ => panic!("peer-close wake selected a different IPC wait kind"),
                    }
                    deadlines
                        .complete_peer_closed_exact(record)
                        .expect("peer-close IPC wake lost its exact deadline record");
                }
                drop(blocked_list);

                // M7 audit fix #10 + M8.2 ASID invalidate
                task.saved_user_gprs[0] = crate::ipc::IpcError::InvalidCapability.as_u64();
                for slot in &mut task.saved_user_gprs[1..=7] {
                    *slot = 0;
                }
                task.state = TaskState::Ready;

                // Revoke sonrası ilgili ASID'in TLB girdilerini temizle (M8.2)
                if task_asid != 0 {
                    unsafe {
                        crate::arch::aarch64::mmu::invalidate_asid(task_asid);
                    }
                }

                let task_id = task.id;
                self.ready_queue.push(PriorityTask::new(task));
                crate::kprintln!(
                    "[M7.5] Revoke nedeniyle task#{} uyandırıldı (ASID={} invalidate edildi)",
                    task_id,
                    task_asid
                );

                blocked_list = self.ipc_blocked_tasks.lock();
            } else {
                i += 1;
            }
        }
    }

    // Restored minimal versions of previously removed methods to make build pass
    fn recalculate_min_vruntime(&mut self) {
        // TODO: implement properly later
    }

    fn normalize_vruntime(&mut self) {
        // TODO: implement properly later
    }

    pub fn current_vruntime() -> u64 {
        #[cfg(feature = "board-rpi5")]
        let _s255_scheduler_read_access = crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s254_vruntime_read_access_guard_expansion::acquire_s255_production_scheduler_read_access()
            .unwrap_or_else(|error| {
                panic!(
                    "S255 current-vruntime scheduler read access failed closed: {:?}",
                    error
                )
            });
        unsafe {
            let sched = &*core::ptr::addr_of!(SCHEDULER);
            sched.current_task.as_ref().map_or(0, |t| t.vruntime)
        }
    }

    pub fn min_vruntime() -> u64 {
        #[cfg(feature = "board-rpi5")]
        let _s255_scheduler_read_access = crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s254_vruntime_read_access_guard_expansion::acquire_s255_production_scheduler_read_access()
            .unwrap_or_else(|error| {
                panic!(
                    "S255 min-vruntime scheduler read access failed closed: {:?}",
                    error
                )
            });
        unsafe {
            let sched = &*core::ptr::addr_of!(SCHEDULER);
            sched.min_vruntime
        }
    }

    pub fn try_wake_tasks_waiting_on(&mut self, _endpoint_id: crate::ui::capability::CapId) {
        // TODO
    }
}
snippet sha256: fc5979057655file sha256: 838dd474448c
03 · Ortak exclusion üyeliği

S247 production writer guard

tam Rust öğesiL212–L224
kernel/src/g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s379_el0_ipc_call_timeout_writer_guard_integration.rs::acquire_s379_production_scheduler_writer_access

#[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
pub fn acquire_s379_production_scheduler_writer_access(
) -> Result<G8lS379ProductionSchedulerWriterAccess, G8lS247WholeSchedulerAccessError> {
    let caller_cpu =
        crate::percpu::try_current_cpu_id().ok_or(G8lS247WholeSchedulerAccessError::InvalidCpu)?;
    if caller_cpu != crate::g8l_runtime_contract::CPU0 {
        return Err(G8lS247WholeSchedulerAccessError::InvalidCpu);
    }
    let access = crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s246_whole_scheduler_read_access_guard::S247_PRODUCTION_WHOLE_SCHEDULER_ACCESS_GATE
        .try_acquire_exclusive_for_valid_cpu(caller_cpu)?;
    Ok(G8lS379ProductionSchedulerWriterAccess { _access: access })
}
snippet sha256: ffd9f040ef78file sha256: 8dba899b7461
04 · Doğrulayan test kodu

Operations komutuna bağlı focused test

tam Rust öğesiL377–L386
simulation/tests/g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s379_el0_ipc_call_timeout_writer_guard_integration.rs::call_timeout_handler_has_exactly_one_initial_s379_acquire

#[test]
fn call_timeout_handler_has_exactly_one_initial_s379_acquire() {
    assert_eq!(
        call_timeout_handler()
            .matches("acquire_s379_production_scheduler_writer_access")
            .count(),
        1
    );
}
snippet sha256: 502a326d60fffile sha256: bf967009d799
05 · Kapı kimlik kaydı

Operations sıra, kimlik ve başlık bağı

tam Operations kaydıL8917–L9098
website/src/lib/operations.ts::g8l-s379-el0-ipc-call-timeout-writer-guard-integration-partial
  {
    id: "g8l-s379-el0-ipc-call-timeout-writer-guard-integration-partial",
    date: "2026-08-29",
    sequence: 379,
    status: "passed",
    umbrella_status: "partial",
    title: "S379 · EL0 IPC call-timeout production writer guard integration",
    summary:
      "S379, handle_ipc_call_timeout içindeki exact scheduler.ipc_call_timeout_commit_and_park(...) mutable scheduler sınırını S378 ve 44 production reader'ın kullandığı aynı statik S247 state word'e bağlar. Target/message/timeout/current-tick snapshot'ları, relative deadline, current-task identity, normal Endpoint şekli, current CNode Endpoint + ENDPOINT_SEND authority, immutable IpcMessage ve caller-owned linked one-shot reply-cap writer'dan önce tamamlanır. RPi5 bare-metal kesişiminde dedicated IRQ guard kurulur; gerçek per-CPU kimliğiyle yalnız CPU0 için S379 exclusive writer alınır ve exact tek mutable SCHEDULER aliası üzerinden IRQ/writer değerleri scheduler'a by-value aktarılır. Scheduler live SEND authority, exact reply generation/linkage, optional receiver authority/deadline ve bütün park kapasitelerini transaction altında yeniden doğrular. CALL deadline rendezvous'tan önce kaydedilir; publish hatasında exact cancel_exact rollback yapılır. Parked yol CALL/Blocked/optional receiver wake publication'ını membership altında tamamlar; writer ve IRQ gerçek context_switch'ten hemen önce bırakılır. Resume continuation önce yeni IRQ sonra yeni S379 writer ile durable reply/cancel/timeout payload okunmadan yeniden katılır. Tarihsel S309 audit'i, S374 normal CALL membership'i ve S378 timed receive membership'i ayrı kalır. Guarded writer 52/69, açık writer 17, provider authority 0, whole-scheduler exclusion false ve supported-profile runtime observation=0'dır. S380 QEMU S139 exact-ACK sıradaki ayrı kapıdır.",
    evidence: [
      "İlk focused komut ayrı S379 module/source registration ve production boundary henüz yokken compile RED verdi; S379 S378 kartına topluca eklenmedi.",
      "İlk RED exit 101 verdi; log 1262 B / 3653f9215e68af31a992e45496b5d4bfb0c6ab2623ede33104769ab2b5f69a35 SHA-256 ve artifact /tmp/aselsanos-s379-focused.vlbC35/initial-red.log'dur.",
      "Sözleşme 55 bağımsız assertion'a genişletildi. İlk geniş koşu 54/55 PASS verdi; tek RED dokümantasyonda gerçek ENDPOINT_SEND sabitinin exact yazılmamasıydı.",
      "Üretim authority sabiti veya kod davranışı gevşetilmedi; yalnız source-contract metni exact ENDPOINT_SEND adıyla düzeltildi.",
      "Final rustfmt-sonrası focused koşu 55/55 PASS / 0 fail verdi; log 4229 B / 2351cb3b0445279634f9b32d7e8c2464ddbcb007f2d7091adebabc90ac074429 SHA-256'dır.",
      "S379 modülü S378 typed preflight outcome'unu yeniden doğrular; inherited 44 reader + 51 guarded writer + 18 open writer snapshot'ı saparsa InventoryDrift ile fail-closed kapanır.",
      "S379 başarı outcome'u FiftySecondWriterGuardedAwaitingRemaining'dir ve exact 44 guarded reader + 52/69 guarded writer + 17 open writer envanterini sabitler.",
      "Production wrapper exact target_arch=aarch64, target_os=none, feature=board-rpi5 cfg kesişimindedir; host executor production runtime observation diye sunulmaz.",
      "acquire_s379_production_scheduler_writer_access gerçek try_current_cpu_id sonucunu kullanır; caller-supplied production CPU parametresi yoktur ve CPU0 dışı InvalidCpu verir.",
      "Writer lease S247_PRODUCTION_WHOLE_SCHEDULER_ACCESS_GATE üzerinde try_acquire_exclusive_for_valid_cpu ile alınır; yeni static veya ayrı model gate yaratılmaz.",
      "Host executor callback'i exact bir kez çağırır; canlı reader/writer callback'ten önce ExclusiveBusy üretir, CPU1–CPU_MAX InvalidCpu verir ve callback error RAII lease'i bırakır.",
      "S378 ve S379 token'ları aynı shared gate üzerinde monotonic ve distinct'tir; iki kapı tek transaction, dispatcher veya Kod kartı değildir.",
      "Exact production giriş sınırı arch/aarch64/exceptions.rs içindeki handle_ipc_call_timeout fonksiyonudur; S379 diğer IPC syscall branch'lerini coverage'a katmaz.",
      "target_task_id, label, badge, data0, data1, timeout_ticks ve now_tick immutable owned scalar olarak writer edinilmeden önce alınır.",
      "TickDeadline::try_after taşması InvalidDeadline ve terminal return ile IRQ/writer acquisition'dan önce kapanır; shared gate veya scheduler graph değişmez.",
      "current_task_id writer öncesinde caller_task scalar'ına çevrilir; mutable scheduler aliasından identity reader türetilmez.",
      "Target endpoint exact normal/non-reply object olmalıdır; missing veya reply endpoint writer membership'i açmaz.",
      "Current CNode lookup exact target için CapabilityKind::Endpoint, object generation ve CapabilityRights::ENDPOINT_SEND üçlüsünü writer öncesinde doğrular.",
      "Authority yoksa InvalidCapability terminal sonucu S379 IRQ/writer acquisition'dan önce üretilir; stale veya foreign SEND grant writer'ı açmaz.",
      "IpcMessage dört immutable payload alanıyla writer öncesinde kurulur; scheduler aliası message snapshot üretmek için kullanılmaz.",
      "Linked one-shot reply-cap mint writer öncesindedir; mint başarısızlığı writer membership'i açmadan exact error döndürür.",
      "Dedicated s379_irq_guard mutable scheduler aliasından önce local interrupt re-entry'yi kapatır; s379_writer_access IRQ guard'dan sonra ve alias kurulmadan önce alınır.",
      "handle_ipc_call_timeout production cfg yolunda exact bir acquire_s379_production_scheduler_writer_access, bir mutable SCHEDULER aliası ve bir ipc_call_timeout_commit_and_park forward'ı vardır.",
      "Production forward original dokuz çekirdek argümanı ve ardından s379_irq_guard/s379_writer_access değerlerini by-value taşır.",
      "Non-RPi5 fallback exact tarihsel dokuz çekirdek argümanı korur ve guard değerleri taşımaz; S309 regresyonu iki cfg forward'ını ayrı doğrular.",
      "Scheduler ipc_call_timeout_commit_and_park production imzası S379 IrqGuard ve G8lS379ProductionSchedulerWriterAccess değerlerini by-value alır; caller bunları yeniden kullanamaz.",
      "Scheduler mevcut IPC_TRANSACTION_LOCK → deadline table → endpoint registry → blocked scheduler set kilit sırasını korur; S379 alternatif exclusion alanı eklemez.",
      "Current caller task nonzero ve canlı olmalıdır; current_endpoint_authority_is_live exact endpoint id/generation ve ENDPOINT_SEND right'ını transaction altında yeniden doğrular.",
      "Caller CNode'daki reply capability exact minted reply id/generation ve caller ownership ile yeniden doğrulanır; stale/replaced reply park publication'ını açmaz.",
      "Endpoint normal/non-reply şekli ve linked reply relation transaction altında yeniden doğrulanır; reply endpoint CALL hedefi olamaz.",
      "Optional waiting receiver varsa exact receiver authority, endpoint generation ve compatible deadline identity publication öncesinde doğrulanır.",
      "Ready queue, blocked-task collection, endpoint rendezvous ve deadline capacity kontrolleri ilk mutation'dan önce tamamlanır; NoReceiver/QueueFull kısmi CALL bırakmaz.",
      "Exact CALL deadline rendezvous publication'ından önce register edilir; deadline identity caller/reply/endpoint bağı taşır.",
      "Rendezvous publication başarısız olursa aynı deadline_record cancel_exact ile geri alınır; orphan timeout kaydı bırakılmaz.",
      "finish_call_park, caller BlockedOnIpc state'i ve optional receiver delivery/wake aynı scheduler transaction'ında ve S379 writer membership canlıyken tamamlanır.",
      "switch_after_ipc_park_with_membership_handoff pre-switch closure'ı gerçek machine context_switch çağrısına bitişiktir; yorum veya model switch release kanıtı sayılmaz.",
      "Pre-switch closure exact drop(s379_writer_access) ardından drop(s379_irq_guard) taşır; global writer başka task çalışırken pinlenmez.",
      "Post-resume closure önce yeni IrqGuard, sonra acquire_s379_production_scheduler_writer_access ile yeni membership alır; eski token across-switch taşınmaz.",
      "Durable reply, cancellation veya timeout payload scheduler.restore_current_ipc_context(ctx) ile yalnız resume üyeliğine yeniden katıldıktan sonra okunur.",
      "Post-resume exact writer→IRQ drop sırası terminal result projection ve unpublished-reply cleanup'tan önce tamamlanır.",
      "Immediate ve pre-publication error yolları ordinary RAII release kullanır; parked yol explicit release/switch/rejoin kullanır. İki yaşam döngüsü sahte long-lived token değildir.",
      "Tarihsel S309 writer-authority audit modelidir; canlı S379 membership'i S309 sequence kimliğini veya o kapının 69-open-writer snapshot'ını değiştirmez.",
      "S374 normal non-timeout CALL ayrı handler branch'i ve S374 token'ı kullanır; S379 timeout CALL yaşam döngüsü S374 coverage'ına katılmaz.",
      "S378 timed receive ayrı endpoint right, waiter ve membership taşır; call-timeout branch'inde S378 acquire yoktur.",
      "CPU1 coverage service timer zincirinde S378'den sonra ve S242 sender service'ten önce çalışır; pending S245 view yalnız inspect edilir, request take edilmez ve writer acquire yoktur.",
      "Seçili regresyonun ilk tarihsel S309 koşusu 14/15 PASS / 1 fail verdi; tek RED karşılıklı dışlayan cfg forward'larını kaynakta tek call sayan eski assertion'dı.",
      "S309 ortak dokuz argüman sözleşmesi korunarak production + S379 guards ve fallback guardsız forward ayrı ayrı sabitlendi; audit kapsamı gevşetilmedi.",
      "S378 komşu testi call-timeout branch'inde yalnız distinct S379 membership bulunduğunu ve CPU1 service sırasının S377 < S378 < S379 < S242 olduğunu doğrular.",
      "Final seçili regresyon S284, S309, S361, S374, S378, S379 ve ipc_call_deadline_runtime ile 7 grup / 267/267 PASS / 0 fail verdi.",
      "Selected final log 28654 B / b8f310b8d3b8d5c7ad6e14ae978444fe12819bda2b7c930cf39b32ac4e7ffc06 SHA-256; artifact /tmp/aselsanos-s379-selected.2ulF0x'tir.",
      "S238–S379 dependency listesi 143 gruptur. İki bağımsız seri koşunun her biri 3364/3364 PASS / 0 fail verdi.",
      "İki kanonik dependency özeti 23607 B ve 581e8a91e32eeabdef630a520f333e6c07a3d73f533874f7fdc5db909b154bcb SHA-256 ile byte-eşittir; artifact /tmp/aselsanos-s379-dependency.AX1VA9'dur.",
      "Exact yedi frozen G8h assertion dışındaki seri workspace 342 sonuç grubu / 5234 PASS / 0 fail / 7 filtered verdi.",
      "Filtered workspace log 521495 B / c27535a942fb363df459b61d1931405cae3b9ca0e83541b5d11f0d8cc602c1da; summary 32372 B / 5962221e14673b735de44029ad6f85582975adb82a9f7bbac647402b636a84e7 SHA-256'dır.",
      "Filtresiz workspace exit 101 ile yalnız frozen S96 wiring_does_not_mutate_timer_gic_boot_or_expand_runtime_scope reddinde durdu: 295 grup / 4979 PASS / 1 fail; global workspace GREEN iddia edilmez.",
      "Filtresiz log 489846 B / 37af40d611eaa1fe0d8245b24d030cd97ffda970ec0c9bba2d553461f03e723e; summary 27953 B / 80db6be4ee03d78cbbeed73b2ad7e779cb9fd1e8d273720a0c910e918e21eabf SHA-256 ve artifact /tmp/aselsanos-s379-workspace.S8lM3W'dir.",
      "Fresh izole AArch64 profilleri 4/4 exit 0 verdi. board-qemu log 112254 B / 9c35031cf4e0b4e45a3a1f1ba3b11248ff44937f1594aaaf82f8b0a88a1e5892, 293 warning header; ELF 16813080 B / c293d4bdc03d1faaaf9ad9b1f20ee129c2eaacd2c8f522a2c60094d912a1b740'dır.",
      "board-rpi4 log 150942 B / 145e6e18e6fe7f6bae21217a09db8f8afbdce42b8f877c56338bf84047479aee, 391 warning header; ELF 11925456 B / 0f18cb9c37741dcb1364e25b9ddb4bae783f2f81a7c981b518ced61534027614'dür.",
      "board-rpi5 log 626487 B / 2d93faf040e820221b445b234c2bc38e816bf6893a0a36b2dd954a6717b6a0ad, 1426 warning header; ELF 15138928 B / 1e582418ef3009836651988897e27dc0a0a1efa9c9b067da79794e06d5923aa4'dür.",
      "board-rpi5+smp log 626385 B / 4a1f846711c3d0449d4202a4bddacb4798269f5720669af97e0642d73a50d954, 1426 warning header; ELF 15122328 B / d6ccb7bf95fde4b8a9635677fd4a62c475957902d0d288bf93724b0bef94d29f'dir. Zero-warning iddiası yoktur.",
      "CARGO_INCREMENTAL=0 make verify-qemu exit 0 verdi. 116354 B log / 383138b6654b591787942e52fddfa45eef15fb293eccb3bf1b5326eaadb69c46 SHA-256 ile W^X 31/31, S130–S154+S271, RuntimePmm, EL0x4096, IPC reply 20/20 ve scheduler SEC5 PASS'tir.",
      "Ortak board-qemu regresyonu RPi5-only S379 production wrapper invocation kanıtı değildir; supported-profile runtime observations=0 kalır.",
      "Yeni modül/test scoped rustfmt ve cargo fmt --all -- --check exit 0 verdi; global Rust format kapısı PASS'tir.",
      "Source-bound Kod hedefi S1–S379 379/379 ayrı kapı, pre-S328 S1–S327 327/327, missing=none ve duplicate=0'dır. S379 kartı S309/S374/S378/S380 kartlarıyla birleştirilmez.",
      "S379 Code kartı tam handle_ipc_call_timeout öğesi içinde exact preflight→IRQ→writer→single alias→by-value handoff odağını ve ayrı tam ipc_call_timeout_commit_and_park rollback→park→release→switch→rejoin→restore yaşam döngüsünü yayımlar.",
      "Ayrı S379 guard modülü, focused test, proof ve exact Operations object'i kendi source excerpt'leriyle yayımlanır; her excerpt repository path, satır aralığı, file SHA-256 ve snippet SHA-256 taşır.",
      "S1–S327 tarihsel kapılar Operations sequence kimliğiyle 327/327 ayrı kart olarak korunur; S328 öncesi kayıtlar generic placeholder içinde birleştirilmez veya S328 kartına eklenmez.",
      "İlk source-bound registry S1–S379 aralığında 379/379 unique kapı, 1084 exact excerpt, pre-S328 S1–S327 327/327, missing=none ve duplicate=0 üretti. JSON 8273442 B / bb2f2d244639c62f1a3d0836cce2b5135bfc4ccd7118c442a9c5d55434b0d0f7 SHA-256; registry content SHA-256 85ea1b822490ac399ed78e40801a6ac94a1f9532e45e6e17be2a79ceab8a4220'dır.",
      "Website kabulü 674/674 PASS, lint PASS, boş çıktılı TypeScript exit 0 ve 24/24 static page verdi; export 201 dosya, Timeline 218 ayrı gate-policy kartı ve S379 core policy 13970 karakter / 14509 UTF-8 byte'tır.",
      "Website test logu 62594 B / 0f3f64905d965a8ad4ff4578463acb4c76b71b75c8744d5da6bc5cc5ac492d3d; lint logu 218 B / 79c084453e339ceb2efe76ed96d1d68be8ac51442957a7a048fd17dba3067ba2; build logu 1213 B / 445c5b75fe653e8bc8098c36aa747fef0082072a17dd06d12aa32030065fa01d SHA-256'dır.",
      "Production/main deployment 5a6973d6-bf9c-44fb-9131-d01a0d650cc5 ile 116 uploaded + 84 existing = 200 asset yayımlandı; deploy logu 1714 B / ec1654e74caac4ccb13ce673c22b9beb82a39a8aaf1bed9404c0528720c15462 SHA-256'dır.",
      "Cache-busted custom-domain /code/, /operations/, /timeline/ ve /yol-haritasi/ HTTP 200 ve deploy-sonrası yerel out'a raw byte-exact PASS verdi. /code/ 23372606 B / e30f7f385dcd7b9692fefc2e2de479aab8a14e9f3bf14065c4c6b75d58f43fc7; /operations/ 13610973 B / 4da1d42475f3373e1b85817bbc51f2f10933f36e2ed5bf59153f444421ee8346; /timeline/ 5468862 B / 9aa2432c38aa0169c0111d533c998d4f9f35c8fc9c72619e3c9f17f333a33e65; /yol-haritasi/ 5468610 B / 1875bd48d13fe37175eeb9956e2cabb7d3c439ddecf23ac82ec9bb89800671f3 SHA-256'dır.",
      "Canlı /code no-transform header'ı taşır; literal kart sayımı total=379, unique=379, min=S1, max=S379, pre-S328=327, missing=none, duplicate=0, S1=1, S327=1, S328=1, S378=1 ve S379=1 verdi. Canlı Timeline policy kartı 218'dir.",
      "İlk publication artifact dizini /tmp/aselsanos-s379-web-initial.IQ46DY'dir. Immutable 5a6973d6 hostname probe'u curl exit 28 / HTTP 000 verdi; custom-domain PASS bunun yerine geçirilmez. Evidence-sync deployment ölçülmüş ilk snapshot'ı yayımlar ve self-reference üretmemek için kendi kimliğini bu snapshot metnine geri yazmaz.",
      "S379 sırasında güç, SD kart, Mac kart erişimi, UART capture, raw validation, archive veya promotion yapılmadı: physical/device operations=0 ve RUNBOOK_EXECUTED_IN_S379=NO.",
      "S379 bazlı bağlayıcı olmayan planlama görünümü R1 S379–S409, R2 S434–S484, R3 S563+, kaba S539–S589 ve risk paylı merkez yaklaşık S564'tür; ürün veya sıra taahhüdü değildir.",
    ],
    commands: [
      "cargo test -p aselsan_microkernel_simulation --test g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s379_el0_ipc_call_timeout_writer_guard_integration -- --test-threads=1",
      "run S284, S309, S361, S374, S378, S379 and ipc_call_deadline_runtime serially",
      "run four fresh isolated AArch64 profiles; run S238-S379 dependency list twice; run filtered and unfiltered serial workspace audits; CARGO_INCREMENTAL=0 make verify-qemu",
      "python3 scripts/render-project-status.py --write && python3 scripts/render-project-status.py --check; cargo test -p aselsan_microkernel_simulation --test project_status_manifest -- --test-threads=1",
      "npm run code:generate && npm test && npm run lint && npx tsc --noEmit && npm run build",
      "npm run deploy; cache-busted curl + cmp for /code/, /operations/, /timeline/ and /yol-haritasi/",
    ],
    terminalSessions: [
      {
        id: "g8l-s379-focused-source-contract",
        title: "S379 focused IPC call-timeout writer membership",
        commandLines: [
          "cargo test -p aselsan_microkernel_simulation --test g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s379_el0_ipc_call_timeout_writer_guard_integration -- --test-threads=1",
        ],
        outputLines: [
          "initial result: compile RED; separate S379 module/source registration and production boundary absent",
          "first expanded result: 54/55 PASS; exact ENDPOINT_SEND documentation assertion RED",
          "final result: ok; S379 focused 1 group / 55 passed / 0 failed",
          "shared S247 gate: 44 guarded readers + 52/69 guarded writers; 17 writers open",
          "inputs/deadline/identity/endpoint/SEND/message/reply mint < IRQ < writer < deadline/CALL/park < release < switch < rejoin < durable restore",
          "direct production caller paths=1; context-switch handoff=1; post-resume rejoin=1; runtime observations=0; provider authority=0",
        ],
        exitCode: 0,
        outputMode: "complete",
      },
      {
        id: "g8l-s379-selected-regression",
        title: "S379 selected CALL authority/handoff/deadline regression",
        commandLines: [
          "run S284, S309, S361, S374, S378, S379 and ipc_call_deadline_runtime serially",
        ],
        outputLines: [
          "initial historical result: S309 14/15; cfg-call-count source assertion RED",
          "S309 aligned to two exact cfg forwards while preserving the common nine-argument and authority contract",
          "S378 aligned to require distinct S379 membership without changing the S378 inventory snapshot",
          "final result: 7 groups / 267 passed / 0 failed",
          "final log 28654 bytes; SHA-256 b8f310b8d3b8d5c7ad6e14ae978444fe12819bda2b7c930cf39b32ac4e7ffc06",
        ],
        exitCode: 0,
        outputMode: "complete",
      },
      {
        id: "g8l-s379-full-acceptance",
        title: "S379 four-profile, dependency, workspace and QEMU acceptance",
        commandLines: [
          "run four fresh isolated AArch64 profile builds with CARGO_INCREMENTAL=0",
          "run S238-S379 dependency list twice and compare canonical summaries",
          "run filtered and unfiltered serial workspace audits",
          "CARGO_INCREMENTAL=0 make verify-qemu",
        ],
        outputLines: [
          "four AArch64 profiles: 4/4 exit 0; individual log/ELF byte and SHA-256 identities recorded",
          "dependency: 143 groups / 3364/3364 twice; 23607-byte canonical summaries byte-equal",
          "filtered workspace: 342 groups / 5234 PASS / 0 fail / 7 frozen filtered",
          "unfiltered workspace: exit 101; 295 groups / 4979 PASS / 1 frozen S96 failure; global GREEN=false",
          "QEMU: W^X 31/31 + S130-S154/S271 + RuntimePmm + EL0x4096 + IPC 20/20 + scheduler SEC5 PASS",
          "QEMU common regression is not an S379 RPi5 runtime observation",
        ],
        exitCode: 0,
        outputMode: "complete",
      },
      {
        id: "g8l-s379-production-publication",
        title: "S379 source-code registry and production publication",
        commandLines: [
          "npm run code:generate && npm test && npm run lint && npx tsc --noEmit && npm run build",
          "npm run deploy",
          "cache-busted curl + raw cmp for /code/, /operations/, /timeline/ and /yol-haritasi/",
        ],
        outputLines: [
          "source registry: S1-S379 379/379 unique gates; 1084 exact excerpts; pre-S328 S1-S327 327/327; missing=none; duplicate=0",
          "S379 code layers: complete handle_ipc_call_timeout + exact guard handoff focus + complete scheduler park/resume lifecycle + S247 guard + focused test + proof + Operations object",
          "website: 674/674 PASS; lint PASS; TypeScript empty; static pages 24/24; files 201; Timeline cards 218",
          "deployment 5a6973d6-bf9c-44fb-9131-d01a0d650cc5; 116 uploaded + 84 existing = 200 assets",
          "custom-domain four routes HTTP 200 and raw byte-exact; /code no-transform; live code 379/379; pre-S328 327/327; missing=none; duplicate=0; S379=1",
          "immutable hostname curl exit 28 / HTTP 000; custom-domain result remains the publication authority",
        ],
        exitCode: 0,
        outputMode: "complete",
      },
    ],
    terminalSessionsNote:
      "TAM ÇIKTI kayıtları S379 focused 55/55, seçili 7 grup / 267 PASS, iki kez 143 grup / 3364 PASS, filtreli workspace 342 grup / 5234 PASS, filtresiz yalnız frozen-S96 RED, dört AArch64 profil 4/4, ortak QEMU kabulü ve production publication'ı ayrı oturumlar halinde taşır. /code S1–S379 aralığını 379 ayrı source-bound kart olarak yayımlar; özellikle S1–S327 tarihsel kapsam 327/327 tekildir. Dört custom-domain rota HTTP 200/raw byte-exact, missing=none, duplicate=0 ve S379=1'dir; S380 ayrı ve açık kalır.",
    limitations: [
      "S379 yalnız EL0 IPC call-timeout mutable scheduler sınırını kapatır; S380 QEMU S139 exact-ACK ve kalan 17 writer açıktır.",
      "Production provider authority=0, whole-scheduler exclusion=false ve S244 admission publication yoktur.",
      "Supported-profile S379 writer runtime invocation gözlenmedi; QEMU ortak regresyonu bunun yerine geçirilmez.",
      "Park/resume source, host model ve AArch64 compile ile doğrulandı; transient contention liveness/soak ve default-parallel PTY determinism ürün kabulü değildir.",
      "Generic SMP cross-CPU scheduler ownership, CPU2/CPU3, migration, load balancing, hotplug ve cross-CPU ASID/TLB arbitration açıktır.",
      "Filtresiz workspace frozen S96 source assertion'ı nedeniyle global GREEN değildir.",
      "Fiziksel RPi latency/power/thermal, UART/raw ve product threshold kabulü yapılmadı; RUNBOOK_EXECUTED_IN_S379=NO.",
      "R1/R2/R3 sıra görünümü bağlayıcı olmayan planlama projeksiyonudur; ürün teslim taahhüdü değildir.",
    ],
  },
snippet sha256: 63e451348e24file sha256: 9726dbf00f84
Focused test komutu
cargo test -p aselsan_microkernel_simulation --test g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s379_el0_ipc_call_timeout_writer_guard_integration -- --test-threads=1
proof: docs/M8.1-RPi5-G8l-S379-EL0-IPC-Call-Timeout-Writer-Guard-Integration-Proof.md
Registry schema v5 · generator website/scripts/generate-code-gates.mjs · Tam SHA-256: 91d38c7b6222f0b4c117be786454853543da55a160e543d9b951057cc20dcc06