ASELSANMicrokernel
S408 · SOURCE-BOUND GATE EVIDENCE

S408 · Live offer SGI sender

tam S408 implementation modülü → Operations --test hedefi ile bağlı tam focused test → ayrı Operations kaydı Bu sayfa yalnız S408 kapısına aittir; komşu kapıların kaynakları bu kabulün içine katılmaz.

S408Focused kod testiOperations id exactsource SHA exacttest target exact

operation: g8l-s408-live-offer-sgi-sender-partial

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

sequence-bound=true · implementation-bound=true
01 · Yürütme / doğrulama kodu

Kapının gerçek repository sözleşmesi

tam dosyaL1–L359
kernel/src/g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s408_live_offer_sgi_sender.rs::S408 live offer sgi sender implementation
#![allow(unexpected_cfgs)]

//! S408 dedicated SGI3 sender for a live S407 exclusion offer.
//!
//! SGI1 belongs to G8d/G8e and SGI2 to S240. S408 reserves dedicated SGI3,
//! prepares CPU0 during boot, and permits send only while the S407 wrapper is
//! live. IRQ validation/EOI, admission, and physical observation remain open.

use crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s407_live_exclusion_offer_publication::{
    G8lS407OfferedScopedProviderAuthority, S407_DIRECT_SCHEDULER_ACCESS_SITES,
    S407_PRODUCTION_GUARDED_DIRECT_ACCESS_SITES, S407_SOURCE_AUDIT_UNITS,
    S407_SOURCE_MODEL_COVERED_DIRECT_ACCESS_SITES, S407_UNROUTED_DIRECT_ACCESS_SITES,
};
#[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
use crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s407_live_exclusion_offer_publication::G8lS407ProductionOfferedScopedProviderAuthority;

pub const S408_SOURCE_AUDIT_UNITS: usize = S407_SOURCE_AUDIT_UNITS;
pub const S408_DIRECT_SCHEDULER_ACCESS_SITES: usize = S407_DIRECT_SCHEDULER_ACCESS_SITES;
pub const S408_SOURCE_MODEL_COVERED_DIRECT_ACCESS_SITES: usize =
    S407_SOURCE_MODEL_COVERED_DIRECT_ACCESS_SITES;
pub const S408_PRODUCTION_GUARDED_DIRECT_ACCESS_SITES: usize =
    S407_PRODUCTION_GUARDED_DIRECT_ACCESS_SITES;
pub const S408_UNROUTED_DIRECT_ACCESS_SITES: usize = S407_UNROUTED_DIRECT_ACCESS_SITES;
pub const S408_SGI_INTID: u32 = 3;
pub const S408_SOURCE_CPU1: usize = 1;
pub const S408_TARGET_CPU0: usize = 0;
pub const S408_TARGET_LIST_CPU0: u8 = 0x01;
pub const S408_EXPECTED_ENABLE: u32 = 1u32 << S408_SGI_INTID;
pub const S408_EXPECTED_COMMAND: u32 = ((S408_TARGET_LIST_CPU0 as u32) << 16) | S408_SGI_INTID;
pub const S408_EXPECTED_RAW_ACK: u32 = ((S408_SOURCE_CPU1 as u32) << 10) | S408_SGI_INTID;
pub const S408_PRODUCTION_RECEIVER_PREPARE_CALLSITES: usize = 1;
pub const S408_PRODUCTION_SENDER_INVOCATION_CALLSITES: usize = 0;
pub const S408_IRQ_DELIVERY_COMPLETE: bool = false;
pub const S408_END_TO_END_EXCLUSION_ADMISSION_COMPLETE: bool = false;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS408LiveOfferSgiPhase {
    Idle,
    ReceiverReady,
    Sent,
    Failed,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum G8lS408LiveOfferSgiError {
    InvalidPhase,
    WrongReceiverCpu,
    WrongSenderCpu,
    WrongExpectedSourceCpu,
    SgiNotEnabled,
    WrongTargetList,
    PendingSourceNotClear,
    OfferNotLive,
    OfferBindingDrift,
    WrongCommand,
    SendReceiptNotDrained,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G8lS408LiveOfferSgiSendReceipt {
    command: u32,
    attempt_id: u64,
    provider_request_id: u64,
    exclusive_token: u64,
}

impl G8lS408LiveOfferSgiSendReceipt {
    pub const fn command(&self) -> u32 {
        self.command
    }
    pub const fn attempt_id(&self) -> u64 {
        self.attempt_id
    }
    pub const fn provider_request_id(&self) -> u64 {
        self.provider_request_id
    }
    pub const fn exclusive_token(&self) -> u64 {
        self.exclusive_token
    }
    pub const fn offer_was_live_at_send(&self) -> bool {
        true
    }
}

#[derive(Debug)]
pub struct G8lS408LiveOfferSgiSenderState {
    phase: G8lS408LiveOfferSgiPhase,
    command: u32,
}

impl G8lS408LiveOfferSgiSenderState {
    pub const fn new() -> Self {
        Self {
            phase: G8lS408LiveOfferSgiPhase::Idle,
            command: 0,
        }
    }

    pub const fn phase(&self) -> G8lS408LiveOfferSgiPhase {
        self.phase
    }

    pub fn prepare_receiver(
        &mut self,
        receiver_cpu: usize,
        expected_source_cpu: usize,
        enabled: u32,
        target_list: u8,
        pending_sources: u8,
    ) -> Result<(), G8lS408LiveOfferSgiError> {
        if self.phase != G8lS408LiveOfferSgiPhase::Idle {
            return Err(G8lS408LiveOfferSgiError::InvalidPhase);
        }
        if receiver_cpu != S408_TARGET_CPU0 {
            return Err(G8lS408LiveOfferSgiError::WrongReceiverCpu);
        }
        if expected_source_cpu != S408_SOURCE_CPU1 {
            return Err(G8lS408LiveOfferSgiError::WrongExpectedSourceCpu);
        }
        if enabled != S408_EXPECTED_ENABLE {
            return Err(G8lS408LiveOfferSgiError::SgiNotEnabled);
        }
        if target_list != S408_TARGET_LIST_CPU0 {
            return Err(G8lS408LiveOfferSgiError::WrongTargetList);
        }
        if pending_sources & (1u8 << S408_SOURCE_CPU1) != 0 {
            return Err(G8lS408LiveOfferSgiError::PendingSourceNotClear);
        }
        self.phase = G8lS408LiveOfferSgiPhase::ReceiverReady;
        Ok(())
    }

    fn begin_send(
        &mut self,
        sender_cpu: usize,
        attempt_id: u64,
        provider_request_id: u64,
        exclusive_token: u64,
        command: u32,
    ) -> Result<G8lS408LiveOfferSgiSendReceipt, G8lS408LiveOfferSgiError> {
        if self.phase != G8lS408LiveOfferSgiPhase::ReceiverReady {
            return Err(G8lS408LiveOfferSgiError::InvalidPhase);
        }
        if sender_cpu != S408_SOURCE_CPU1 {
            self.phase = G8lS408LiveOfferSgiPhase::Failed;
            return Err(G8lS408LiveOfferSgiError::WrongSenderCpu);
        }
        if attempt_id == 0 || provider_request_id == 0 || exclusive_token == 0 {
            self.phase = G8lS408LiveOfferSgiPhase::Failed;
            return Err(G8lS408LiveOfferSgiError::OfferBindingDrift);
        }
        if command != S408_EXPECTED_COMMAND {
            self.phase = G8lS408LiveOfferSgiPhase::Failed;
            return Err(G8lS408LiveOfferSgiError::WrongCommand);
        }
        self.command = command;
        self.phase = G8lS408LiveOfferSgiPhase::Sent;
        Ok(G8lS408LiveOfferSgiSendReceipt {
            command,
            attempt_id,
            provider_request_id,
            exclusive_token,
        })
    }

    #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
    fn fail_terminal(&mut self) {
        self.phase = G8lS408LiveOfferSgiPhase::Failed;
    }

    pub fn rearm_after_drained_attempt(
        &mut self,
        send_receipt_pending: bool,
    ) -> Result<(), G8lS408LiveOfferSgiError> {
        if send_receipt_pending {
            return Err(G8lS408LiveOfferSgiError::SendReceiptNotDrained);
        }
        match self.phase {
            G8lS408LiveOfferSgiPhase::ReceiverReady => Ok(()),
            G8lS408LiveOfferSgiPhase::Sent | G8lS408LiveOfferSgiPhase::Failed => {
                self.command = 0;
                self.phase = G8lS408LiveOfferSgiPhase::ReceiverReady;
                Ok(())
            }
            G8lS408LiveOfferSgiPhase::Idle => Err(G8lS408LiveOfferSgiError::InvalidPhase),
        }
    }
}

impl Default for G8lS408LiveOfferSgiSenderState {
    fn default() -> Self {
        Self::new()
    }
}

pub fn service_s408_model_live_offer_sgi_send(
    sender: &mut G8lS408LiveOfferSgiSenderState,
    caller_cpu: usize,
    offered: &G8lS407OfferedScopedProviderAuthority<'_, '_>,
) -> Result<G8lS408LiveOfferSgiSendReceipt, G8lS408LiveOfferSgiError> {
    if !offered.offer_pending()
        || !offered.is_provider_authority()
        || !offered.whole_scheduler_exclusion_proven()
    {
        return Err(G8lS408LiveOfferSgiError::OfferNotLive);
    }
    let offer = offered.offer();
    if offer.source_cpu != S408_SOURCE_CPU1
        || offer.target_cpu != S408_TARGET_CPU0
        || !offer.requires_live_gate_match
        || offer.is_authority
        || offer.whole_scheduler_exclusion_proven
    {
        return Err(G8lS408LiveOfferSgiError::OfferBindingDrift);
    }
    sender.begin_send(
        caller_cpu,
        offer.attempt_id,
        offer.provider_request_id,
        offer.exclusive_token,
        S408_EXPECTED_COMMAND,
    )
}

#[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
static S408_PRODUCTION_SGI_SENDER: spin::Mutex<G8lS408LiveOfferSgiSenderState> =
    spin::Mutex::new(G8lS408LiveOfferSgiSenderState::new());

#[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
static S408_PRODUCTION_SEND_RECEIPT: spin::Mutex<Option<G8lS408LiveOfferSgiSendReceipt>> =
    spin::Mutex::new(None);

#[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
#[derive(Debug)]
pub enum G8lS408ProductionSgiError {
    WrongCpu,
    State(G8lS408LiveOfferSgiError),
    Gic(&'static str),
    CommandReadbackMismatch,
    SendReceiptPending,
}

#[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
pub fn prepare_s408_live_offer_sgi_receiver_on_cpu0() -> Result<(), G8lS408ProductionSgiError> {
    use crate::g8l_runtime_contract::CPU0;
    if crate::percpu::try_current_cpu_id() != Some(CPU0) {
        return Err(G8lS408ProductionSgiError::WrongCpu);
    }
    let _irq_guard = crate::arch::aarch64::IrqGuard::new();
    let gic_state = crate::arch::aarch64::gic::rpi5_g8d_init_secondary_sgi(
        S408_SGI_INTID,
        S408_SOURCE_CPU1 as u32,
    )
    .map_err(G8lS408ProductionSgiError::Gic)?;
    S408_PRODUCTION_SGI_SENDER
        .lock()
        .prepare_receiver(
            CPU0,
            S408_SOURCE_CPU1,
            gic_state.enabled,
            gic_state.target_list,
            gic_state.pending_sources,
        )
        .map_err(G8lS408ProductionSgiError::State)
}

#[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
pub fn send_s408_live_offer_sgi_from_cpu1(
    offered: &G8lS407ProductionOfferedScopedProviderAuthority,
) -> Result<u32, G8lS408ProductionSgiError> {
    use crate::g8l_runtime_contract::CPU1;
    if crate::percpu::try_current_cpu_id() != Some(CPU1) {
        return Err(G8lS408ProductionSgiError::WrongCpu);
    }
    if !offered.offer_pending()
        || !offered.is_provider_authority()
        || !offered.whole_scheduler_exclusion_proven()
    {
        return Err(G8lS408ProductionSgiError::State(
            G8lS408LiveOfferSgiError::OfferNotLive,
        ));
    }
    let offer = offered.offer();
    let receipt = S408_PRODUCTION_SGI_SENDER
        .lock()
        .begin_send(
            CPU1,
            offer.attempt_id,
            offer.provider_request_id,
            offer.exclusive_token,
            S408_EXPECTED_COMMAND,
        )
        .map_err(G8lS408ProductionSgiError::State)?;
    {
        let mut slot = S408_PRODUCTION_SEND_RECEIPT.lock();
        if slot.is_some() {
            return Err(G8lS408ProductionSgiError::SendReceiptPending);
        }
        *slot = Some(receipt);
    }
    let command =
        match crate::arch::aarch64::gic::rpi5_g8d_send_sgi(S408_SGI_INTID, S408_TARGET_LIST_CPU0) {
            Ok(command) => command,
            Err(error) => {
                S408_PRODUCTION_SEND_RECEIPT.lock().take();
                S408_PRODUCTION_SGI_SENDER.lock().fail_terminal();
                return Err(G8lS408ProductionSgiError::Gic(error));
            }
        };
    if command != S408_EXPECTED_COMMAND {
        S408_PRODUCTION_SEND_RECEIPT.lock().take();
        S408_PRODUCTION_SGI_SENDER.lock().fail_terminal();
        return Err(G8lS408ProductionSgiError::CommandReadbackMismatch);
    }
    Ok(command)
}

#[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
pub fn take_s408_live_offer_sgi_send_receipt_on_cpu0(
) -> Result<Option<G8lS408LiveOfferSgiSendReceipt>, G8lS408ProductionSgiError> {
    use crate::g8l_runtime_contract::CPU0;
    if crate::percpu::try_current_cpu_id() != Some(CPU0) {
        return Err(G8lS408ProductionSgiError::WrongCpu);
    }
    Ok(S408_PRODUCTION_SEND_RECEIPT.lock().take())
}

#[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
pub fn s408_production_send_receipt_pending_on_cpu1() -> Result<bool, G8lS408ProductionSgiError> {
    use crate::g8l_runtime_contract::CPU1;
    if crate::percpu::try_current_cpu_id() != Some(CPU1) {
        return Err(G8lS408ProductionSgiError::WrongCpu);
    }
    Ok(S408_PRODUCTION_SEND_RECEIPT.lock().is_some())
}

#[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
pub fn s408_production_sender_phase_on_cpu1(
) -> Result<G8lS408LiveOfferSgiPhase, G8lS408ProductionSgiError> {
    use crate::g8l_runtime_contract::CPU1;
    if crate::percpu::try_current_cpu_id() != Some(CPU1) {
        return Err(G8lS408ProductionSgiError::WrongCpu);
    }
    Ok(S408_PRODUCTION_SGI_SENDER.lock().phase())
}

#[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
pub fn rearm_s408_live_offer_sgi_sender_on_cpu1() -> Result<(), G8lS408ProductionSgiError> {
    use crate::g8l_runtime_contract::CPU1;
    if crate::percpu::try_current_cpu_id() != Some(CPU1) {
        return Err(G8lS408ProductionSgiError::WrongCpu);
    }
    let pending = S408_PRODUCTION_SEND_RECEIPT.lock().is_some();
    S408_PRODUCTION_SGI_SENDER
        .lock()
        .rearm_after_drained_attempt(pending)
        .map_err(G8lS408ProductionSgiError::State)
}
snippet sha256: fe0632ee5590file sha256: fe0632ee5590
02 · Doğrulayan test kodu

Operations komutuna bağlı focused test

tam dosyaL1–L321
simulation/tests/g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s408_live_offer_sgi_sender.rs::S408 live offer sgi sender focused tests
#![recursion_limit = "256"]

use aselsan_microkernel_simulation::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s244_whole_scheduler_exclusion_admission_request::{
    service_s245_exclusion_admission_request, G8lS245ExclusionAdmissionRequestOutcome,
    G8lS245WholeSchedulerExclusionAdmissionRequestState, S245_SOURCE_CPU0, S245_TARGET_CPU1,
};
use aselsan_microkernel_simulation::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s246_whole_scheduler_read_access_guard::G8lS247WholeSchedulerAccessGate;
use aselsan_microkernel_simulation::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s402_provider_invocation_observation_publication::{
    service_s402_model_provider_invocation_observation_publication,
    G8lS402ProviderInvocationObservationState,
};
use aselsan_microkernel_simulation::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s404_scoped_authority_request_publication::{
    service_s404_model_scoped_authority_request_publication,
    G8lS404ScopedAuthorityRequestState,
};
use aselsan_microkernel_simulation::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s407_live_exclusion_offer_publication::{
    try_publish_s407_model_live_exclusion_offer, G8lS407LiveExclusionOfferState,
    S407_DIRECT_SCHEDULER_ACCESS_SITES, S407_PRODUCTION_GUARDED_DIRECT_ACCESS_SITES,
    S407_SOURCE_AUDIT_UNITS, S407_SOURCE_MODEL_COVERED_DIRECT_ACCESS_SITES,
    S407_UNROUTED_DIRECT_ACCESS_SITES,
};
use aselsan_microkernel_simulation::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s408_live_offer_sgi_sender::*;

fn paired_states() -> (
    G8lS247WholeSchedulerAccessGate,
    G8lS245WholeSchedulerExclusionAdmissionRequestState,
    G8lS404ScopedAuthorityRequestState,
) {
    let gate = G8lS247WholeSchedulerAccessGate::new();
    let mut providers = G8lS245WholeSchedulerExclusionAdmissionRequestState::new();
    service_s245_exclusion_admission_request(&mut providers, S245_SOURCE_CPU0, true, true).unwrap();
    let mut observations = G8lS402ProviderInvocationObservationState::new();
    service_s402_model_provider_invocation_observation_publication(
        &mut observations,
        &gate,
        &mut providers,
        S245_TARGET_CPU1,
    )
    .unwrap();
    let mut scoped = G8lS404ScopedAuthorityRequestState::new();
    service_s404_model_scoped_authority_request_publication(
        &mut scoped,
        &mut observations,
        S245_SOURCE_CPU0,
    )
    .unwrap();
    assert_eq!(
        service_s245_exclusion_admission_request(&mut providers, S245_SOURCE_CPU0, true, true),
        Ok(G8lS245ExclusionAdmissionRequestOutcome::RequestPublished(2))
    );
    (gate, providers, scoped)
}

fn module_source() -> &'static str {
    include_str!("../../kernel/src/g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s408_live_offer_sgi_sender.rs")
}

fn kernel_main_source() -> &'static str {
    include_str!("../../kernel/src/main.rs")
}

fn exception_source() -> &'static str {
    include_str!("../../kernel/src/arch/aarch64/exceptions.rs")
}

fn simulation_lib_source() -> &'static str {
    include_str!("../src/lib.rs")
}

#[test]
fn constants_assign_dedicated_sgi3_without_promoting_delivery() {
    assert_eq!(S408_SOURCE_AUDIT_UNITS, 7);
    assert_eq!(S408_DIRECT_SCHEDULER_ACCESS_SITES, 113);
    assert_eq!(S408_SOURCE_MODEL_COVERED_DIRECT_ACCESS_SITES, 113);
    assert_eq!(S408_PRODUCTION_GUARDED_DIRECT_ACCESS_SITES, 113);
    assert_eq!(S408_UNROUTED_DIRECT_ACCESS_SITES, 0);
    assert_eq!(S408_SGI_INTID, 3);
    assert_eq!(S408_SOURCE_CPU1, 1);
    assert_eq!(S408_TARGET_CPU0, 0);
    assert_eq!(S408_TARGET_LIST_CPU0, 0x01);
    assert_eq!(S408_EXPECTED_COMMAND, 0x0001_0003);
    assert_eq!(S408_EXPECTED_RAW_ACK, 0x0000_0403);
    assert_eq!(S408_PRODUCTION_RECEIVER_PREPARE_CALLSITES, 1);
    assert_eq!(S408_PRODUCTION_SENDER_INVOCATION_CALLSITES, 0);
    assert!(!S408_IRQ_DELIVERY_COMPLETE);
    assert!(!S408_END_TO_END_EXCLUSION_ADMISSION_COMPLETE);
}

#[test]
fn s407_is_the_exact_live_offer_predecessor() {
    assert_eq!(S408_SOURCE_AUDIT_UNITS, S407_SOURCE_AUDIT_UNITS);
    assert_eq!(
        S408_DIRECT_SCHEDULER_ACCESS_SITES,
        S407_DIRECT_SCHEDULER_ACCESS_SITES
    );
    assert_eq!(
        S408_SOURCE_MODEL_COVERED_DIRECT_ACCESS_SITES,
        S407_SOURCE_MODEL_COVERED_DIRECT_ACCESS_SITES
    );
    assert_eq!(
        S408_PRODUCTION_GUARDED_DIRECT_ACCESS_SITES,
        S407_PRODUCTION_GUARDED_DIRECT_ACCESS_SITES
    );
    assert_eq!(
        S408_UNROUTED_DIRECT_ACCESS_SITES,
        S407_UNROUTED_DIRECT_ACCESS_SITES
    );
}

#[test]
fn exact_receiver_prepare_then_live_offer_send_records_sgi3_command() {
    let (gate, mut providers, mut scoped) = paired_states();
    let mut offers = G8lS407LiveExclusionOfferState::new();
    let offered = try_publish_s407_model_live_exclusion_offer(
        &mut offers,
        &gate,
        &mut providers,
        &mut scoped,
        S245_TARGET_CPU1,
    )
    .unwrap()
    .unwrap();
    let mut sender = G8lS408LiveOfferSgiSenderState::new();
    sender
        .prepare_receiver(
            S408_TARGET_CPU0,
            S408_SOURCE_CPU1,
            S408_EXPECTED_ENABLE,
            S408_TARGET_LIST_CPU0,
            0,
        )
        .unwrap();
    let receipt =
        service_s408_model_live_offer_sgi_send(&mut sender, S408_SOURCE_CPU1, &offered).unwrap();
    assert_eq!(receipt.command(), S408_EXPECTED_COMMAND);
    assert_eq!(receipt.attempt_id(), 1);
    assert_eq!(receipt.provider_request_id(), 2);
    assert_eq!(receipt.exclusive_token(), 2);
    assert!(receipt.offer_was_live_at_send());
    assert_eq!(sender.phase(), G8lS408LiveOfferSgiPhase::Sent);
    assert!(offered.offer_pending());
    assert_eq!(gate.active_exclusive_token(), Some(2));
}

#[test]
fn send_before_receiver_prepare_fails_closed_without_releasing_offer() {
    let (gate, mut providers, mut scoped) = paired_states();
    let mut offers = G8lS407LiveExclusionOfferState::new();
    let offered = try_publish_s407_model_live_exclusion_offer(
        &mut offers,
        &gate,
        &mut providers,
        &mut scoped,
        S245_TARGET_CPU1,
    )
    .unwrap()
    .unwrap();
    let mut sender = G8lS408LiveOfferSgiSenderState::new();
    assert_eq!(
        service_s408_model_live_offer_sgi_send(&mut sender, S408_SOURCE_CPU1, &offered),
        Err(G8lS408LiveOfferSgiError::InvalidPhase)
    );
    assert!(offered.offer_pending());
    assert_eq!(gate.active_exclusive_token(), Some(2));
}

#[test]
fn wrong_sender_cpu_fails_closed_with_offer_still_live() {
    let (gate, mut providers, mut scoped) = paired_states();
    let mut offers = G8lS407LiveExclusionOfferState::new();
    let offered = try_publish_s407_model_live_exclusion_offer(
        &mut offers,
        &gate,
        &mut providers,
        &mut scoped,
        S245_TARGET_CPU1,
    )
    .unwrap()
    .unwrap();
    let mut sender = G8lS408LiveOfferSgiSenderState::new();
    sender
        .prepare_receiver(0, 1, S408_EXPECTED_ENABLE, 1, 0)
        .unwrap();
    assert_eq!(
        service_s408_model_live_offer_sgi_send(&mut sender, S408_TARGET_CPU0, &offered),
        Err(G8lS408LiveOfferSgiError::WrongSenderCpu)
    );
    assert!(offered.offer_pending());
    assert_eq!(gate.active_exclusive_token(), Some(2));
}

#[test]
fn receiver_prepare_rejects_wrong_enable_target_and_pending_source() {
    for (enabled, target_list, pending, expected) in [
        (0, 1, 0, G8lS408LiveOfferSgiError::SgiNotEnabled),
        (
            S408_EXPECTED_ENABLE,
            2,
            0,
            G8lS408LiveOfferSgiError::WrongTargetList,
        ),
        (
            S408_EXPECTED_ENABLE,
            1,
            1 << S408_SOURCE_CPU1,
            G8lS408LiveOfferSgiError::PendingSourceNotClear,
        ),
    ] {
        let mut sender = G8lS408LiveOfferSgiSenderState::new();
        assert_eq!(
            sender.prepare_receiver(0, 1, enabled, target_list, pending),
            Err(expected)
        );
    }
}

#[test]
fn duplicate_send_is_rejected_and_does_not_duplicate_command() {
    let (gate, mut providers, mut scoped) = paired_states();
    let mut offers = G8lS407LiveExclusionOfferState::new();
    let offered = try_publish_s407_model_live_exclusion_offer(
        &mut offers,
        &gate,
        &mut providers,
        &mut scoped,
        S245_TARGET_CPU1,
    )
    .unwrap()
    .unwrap();
    let mut sender = G8lS408LiveOfferSgiSenderState::new();
    sender
        .prepare_receiver(0, 1, S408_EXPECTED_ENABLE, 1, 0)
        .unwrap();
    service_s408_model_live_offer_sgi_send(&mut sender, 1, &offered).unwrap();
    assert_eq!(
        service_s408_model_live_offer_sgi_send(&mut sender, 1, &offered),
        Err(G8lS408LiveOfferSgiError::InvalidPhase)
    );
}

#[test]
fn model_send_requires_live_wrapper_before_transitioning_to_sent() {
    let source = module_source();
    let start = source
        .find("pub fn service_s408_model_live_offer_sgi_send")
        .unwrap();
    let function = &source[start..];
    let live = function.find("offered.offer_pending()").unwrap();
    let authority = function.find("offered.is_provider_authority()").unwrap();
    let send = function.find("sender.begin_send(").unwrap();
    assert!(live < send && authority < send);
}

#[test]
fn boot_prepares_sgi3_after_sgi2_and_before_timer_init() {
    let source = kernel_main_source();
    let s240 = source
        .find("prepare_s179_notification_sgi_receiver_on_cpu0")
        .unwrap();
    let s408 = source
        .find("prepare_s408_live_offer_sgi_receiver_on_cpu0")
        .unwrap();
    let timer = source[s408..]
        .find("timer::init_checked()")
        .map(|offset| offset + s408)
        .unwrap();
    assert!(s240 < s408 && s408 < timer);
}

#[test]
fn production_sender_uses_exact_gic_sgi3_and_live_wrapper_reference() {
    let source = module_source();
    let start = source.find("send_s408_live_offer_sgi_from_cpu1").unwrap();
    let function = &source[start..];
    assert!(function.contains("&G8lS407ProductionOfferedScopedProviderAuthority"));
    assert!(function.contains("rpi5_g8d_send_sgi(S408_SGI_INTID, S408_TARGET_LIST_CPU0)"));
    assert!(function.contains("offered.offer_pending()"));
}

#[test]
fn production_sender_is_exposed_but_not_invoked_and_s409_owns_sgi3_delivery() {
    assert!(!exception_source().contains("send_s408_live_offer_sgi_from_cpu1"));
    assert!(exception_source().contains("try_handle_s409_live_offer_sgi_on_cpu0"));
    assert_eq!(S408_PRODUCTION_SENDER_INVOCATION_CALLSITES, 0);
    assert!(!S408_IRQ_DELIVERY_COMPLETE);
}

#[test]
fn sgi3_is_distinct_from_historical_sgi1_and_s240_sgi2() {
    assert_ne!(S408_SGI_INTID, 1);
    assert_ne!(S408_SGI_INTID, 2);
    assert!(module_source().contains("dedicated SGI3"));
}

#[test]
fn s408_does_not_publish_admission_or_release_live_authority() {
    let source = module_source();
    for forbidden in [
        "publish_s244",
        "service_s243_deferred_authority_receipt_join",
        "offered.release()",
        "addr_of!(",
        "addr_of_mut!(",
    ] {
        assert!(
            !source.contains(forbidden),
            "forbidden promotion: {forbidden}"
        );
    }
}

#[test]
fn s408_and_its_exact_s409_delivery_are_registered_separately() {
    let s408 = "g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s408_live_offer_sgi_sender";
    let s409 = "g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s409_live_offer_sgi_delivery";
    assert!(kernel_main_source().contains(&format!("mod {s408};")));
    assert!(simulation_lib_source().contains(&format!("pub mod {s408};")));
    assert!(kernel_main_source().contains(&format!("mod {s409};")));
    assert!(simulation_lib_source().contains(&format!("pub mod {s409};")));
}
snippet sha256: caa620e65d52file sha256: caa620e65d52
03 · Kapı kimlik kaydı

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

tam Operations kaydıL219–L235
website/src/lib/operations.ts::g8l-s408-live-offer-sgi-sender-partial
  {
    id: "g8l-s408-live-offer-sgi-sender-partial",
    sequence: 408,
    slug: "live_offer_sgi_sender",
    title: "Live offer SGI sender",
    focusedTests: 14,
    sourceBytes: 13057,
    sourceSha256:
      "fe0632ee55901d6b216292423242f55f6fb145ffd27ebbe3b9db2e4a88ce0d6a",
    testBytes: 12065,
    testSha256:
      "caa620e65d52add7768541fc581c6904ad64d13494a50e717b6a6b5fadf4500a",
    acceptance:
      "SGI3 için CPU1→CPU0 exact target-list, enable, command ve raw-ACK sözleşmesi; prepare/send/receipt/rearm state machine'i ile source-bound kurulur.",
    retainedBoundary:
      "Receiver prepare callsite vardır; sender invocation ve IRQ delivery henüz tamamlanmış sayılmaz.",
  },
snippet sha256: d916699e33e5file sha256: 9726dbf00f84
Focused test komutu
CARGO_INCREMENTAL=0 cargo test -p aselsan_microkernel_simulation --test g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s408_live_offer_sgi_sender -- --test-threads=1
proof: docs/M8.1-RPi5-G8l-S408-Live-Offer-SGI-Sender-Proof.md
Registry schema v5 · generator website/scripts/generate-code-gates.mjs · Tam SHA-256: 3050638b71a684d8f8f947a8a6faa237a17fa8db5dc0db04fb207b668b462af9