ASELSANMicrokernel
S157 · SOURCE-BOUND GATE EVIDENCE

G8i: per-CPU IRQ stack ve exception context ownership model

Operations --test hedefi → test hedefiyle aynı adlı uygulama/model modülü → kaynak kesiti Bu sayfa yalnız S157 kapısına aittir; komşu kapıların kaynakları bu kabulün içine katılmaz.

S157Focused kod testiOperations id exactsource SHA exacttest target exact

operation: g8i-per-cpu-irq-stack-context-model-partial

uygulama/model · focused test · Operations · 3 exact excerpt

sequence-bound=true · implementation-bound=false
01 · Testin bağlı olduğu uygulama/model kodu

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

tam Rust öğesiL1–L129
simulation/src/g8i_exception_stack.rs::IRQ_STACK_DEPTH
//! G8i bounded per-CPU IRQ-stack and exception-context ownership model.
//!
//! This is the next source/model slice after the S156 dormant runtime.  It
//! keeps exception frames on fixed per-CPU stacks, requires the exact CPU
//! owner for every mutation, and makes overflow/stale return fail closed.  It
//! does not wire production AArch64 exception assembly or a live scheduler.

use crate::g8i_runqueue::{ExceptionFrame, MAX_CPUS};

pub const IRQ_STACK_DEPTH: usize = 4;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ExceptionStackError {
    InvalidCpu,
    ForeignMutation,
    StackFull,
    StackEmpty,
    OwnerMismatch,
    TaskAlreadyStackedOnAnotherCpu,
    NestedTaskMismatch,
    GenerationNotMonotonic,
}

pub struct PerCpuExceptionStackModel {
    stacks: [[Option<ExceptionFrame>; IRQ_STACK_DEPTH]; MAX_CPUS],
    last_generation: [u64; MAX_CPUS],
}

impl PerCpuExceptionStackModel {
    pub const fn new() -> Self {
        Self {
            stacks: [[None; IRQ_STACK_DEPTH]; MAX_CPUS],
            last_generation: [0; MAX_CPUS],
        }
    }

    fn valid_cpu(cpu: usize) -> Result<(), ExceptionStackError> {
        if cpu < MAX_CPUS {
            Ok(())
        } else {
            Err(ExceptionStackError::InvalidCpu)
        }
    }

    fn task_stack_owner(&self, task_id: u64) -> Option<usize> {
        self.stacks.iter().enumerate().find_map(|(cpu, stack)| {
            stack
                .iter()
                .flatten()
                .any(|frame| frame.task_id == task_id)
                .then_some(cpu)
        })
    }

    pub fn enter(
        &mut self,
        caller_cpu: usize,
        frame: ExceptionFrame,
    ) -> Result<(), ExceptionStackError> {
        Self::valid_cpu(caller_cpu)?;
        Self::valid_cpu(frame.owner_cpu)?;
        if caller_cpu != frame.owner_cpu {
            return Err(ExceptionStackError::ForeignMutation);
        }
        if self
            .task_stack_owner(frame.task_id)
            .is_some_and(|owner_cpu| owner_cpu != caller_cpu)
        {
            return Err(ExceptionStackError::TaskAlreadyStackedOnAnotherCpu);
        }
        if self.stacks[caller_cpu]
            .iter()
            .flatten()
            .next()
            .is_some_and(|active| active.task_id != frame.task_id)
        {
            return Err(ExceptionStackError::NestedTaskMismatch);
        }
        if frame.generation <= self.last_generation[caller_cpu] {
            return Err(ExceptionStackError::GenerationNotMonotonic);
        }
        let slot = self.stacks[caller_cpu]
            .iter_mut()
            .find(|entry| entry.is_none())
            .ok_or(ExceptionStackError::StackFull)?;
        *slot = Some(frame);
        self.last_generation[caller_cpu] = frame.generation;
        Ok(())
    }

    pub fn leave(
        &mut self,
        caller_cpu: usize,
        expected: ExceptionFrame,
    ) -> Result<(), ExceptionStackError> {
        Self::valid_cpu(caller_cpu)?;
        if expected.owner_cpu != caller_cpu {
            return Err(ExceptionStackError::OwnerMismatch);
        }
        let top = self.stacks[caller_cpu]
            .iter_mut()
            .rev()
            .find(|entry| entry.is_some())
            .ok_or(ExceptionStackError::StackEmpty)?;
        if *top != Some(expected) {
            return Err(ExceptionStackError::OwnerMismatch);
        }
        *top = None;
        Ok(())
    }

    pub fn depth(&self, cpu: usize) -> Result<usize, ExceptionStackError> {
        Self::valid_cpu(cpu)?;
        Ok(self.stacks[cpu]
            .iter()
            .filter(|entry| entry.is_some())
            .count())
    }

    pub fn peek(&self, cpu: usize) -> Result<Option<ExceptionFrame>, ExceptionStackError> {
        Self::valid_cpu(cpu)?;
        Ok(self.stacks[cpu].iter().rev().find_map(|entry| *entry))
    }

    pub fn last_generation(&self, cpu: usize) -> Result<u64, ExceptionStackError> {
        Self::valid_cpu(cpu)?;
        Ok(self.last_generation[cpu])
    }
}
snippet sha256: 733922b46956file sha256: fd60a4fa153a
02 · Doğrulayan test kodu

Operations komutuna bağlı focused test

tam Rust öğesiL102–L114
simulation/tests/g8i_exception_stack.rs::stale_generation_is_rejected_without_mutation

#[test]
fn stale_generation_is_rejected_without_mutation() {
    let mut stacks = PerCpuExceptionStackModel::new();
    stacks.enter(0, frame(0, 51, 7)).unwrap();
    assert_eq!(
        stacks.enter(0, frame(0, 51, 7)),
        Err(ExceptionStackError::GenerationNotMonotonic)
    );
    assert_eq!(stacks.depth(0), Ok(1));
    assert_eq!(stacks.peek(0), Ok(Some(frame(0, 51, 7))));
    assert_eq!(stacks.last_generation(0), Ok(7));
}
snippet sha256: f13096b14c4cfile sha256: ee8a9bdd0ff3
03 · Kapı kimlik kaydı

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

tam Operations kaydıL23690–L23730
website/src/lib/operations.ts::g8i-per-cpu-irq-stack-context-model-partial
  {
    id: "g8i-per-cpu-irq-stack-context-model-partial",
    date: "2026-08-24",
    sequence: 157,
    status: "passed",
    umbrella_status: "partial",
    title: "G8i: per-CPU IRQ stack ve exception context ownership model",
    summary:
      "S157, S156 dormant runtime modelinin açık bıraktığı per-CPU IRQ stack sınırını bounded host model olarak kapattı: dört CPU, IRQ_STACK_DEPTH=4, exact owner push/pop, same-task nested LIFO, cross-CPU duplicate-task reddi, stale generation, foreign mutation, transactional overflow ve boş/invalid dönüş fail-closed kuralları 8/8 geçti. Production exception assembly, context switch, QEMU ve fiziksel runtime açılmadı.",
    evidence: [
      "g8i_exception_stack: 8/8 PASS; dört bağımsız stack, exact owner, foreign mutation reddi ve owner doğrulamalı return geçti.",
      "Nested frame LIFO döndü; kapasite taşması mevcut frame'leri kaybetmeden reddedildi; stale generation ve invalid/empty dönüşler mutasyonsuz fail-closed kaldı.",
      "Aynı task iki CPU IRQ stack'inde bulunamıyor; nested frame farklı task kimliği taşıyamıyor ve non-top return stack'i değiştirmeden reddediliyor.",
      "Overflow denemesindeki yüksek generation commit edilmedi; top pop sonrası sıradaki monoton generation kabul edilerek sayaç transaction'ı doğrulandı.",
      "Kalıcı kapsam: `docs/M8.1-RPi5-G8i-PerCpu-IRQ-Stack-Context-Proof.md`.",
      "S157 fiziksel/device operasyonu yapmadı: physical/device operations=0 ve RUNBOOK_EXECUTED_IN_S157=NO.",
    ],
    commands: [
      "cargo test -p aselsan_microkernel_simulation --test g8i_exception_stack -- --test-threads=1",
    ],
    terminalSessions: [
      {
        id: "s157-g8i-irq-stack-context-model",
        title: "G8i per-CPU IRQ stack/context host model kapısı",
        commandLines: [
          "cargo test -p aselsan_microkernel_simulation --test g8i_exception_stack -- --test-threads=1",
        ],
        outputLines: ["running 8 tests", "test result: ok. 8 passed; 0 failed"],
        exitCode: 0,
        outputMode: "selected",
      },
    ],
    terminalSessionsNote:
      "S157 yalnız bounded host/model stack sözleşmesidir; production AArch64 exception assembly, scheduler/context switch, QEMU, fiziksel RPi ve generic SMP runtime sonucu değildir.",
    limitations: [
      "Gerçek per-CPU IRQ stack allocation, exception trampoline ve context switch production path'e bağlanmadı.",
      "G8j shared-root/ASID0 migration, G8k ASID/TLB shootdown, QEMU ve fiziksel runtime sonraki kapılardır.",
      "Generic SMP arbitration, CPU2/CPU3, hotplug, long soak ve signed product budgets kapsam dışıdır.",
      "Fiziksel/device operations=0; RUNBOOK_EXECUTED_IN_S157=NO.",
    ],
  },
snippet sha256: 826cdbfa756dfile sha256: 9726dbf00f84
Focused test komutu
cargo test -p aselsan_microkernel_simulation --test g8i_exception_stack -- --test-threads=1
Registry schema v5 · generator website/scripts/generate-code-gates.mjs · Tam SHA-256: 3050638b71a684d8f8f947a8a6faa237a17fa8db5dc0db04fb207b668b462af9