ASELSANMicrokernel
S339 · SOURCE-BOUND GATE EVIDENCE

S339 · User-first-kernel-entry production writer guard integration

production acquire → S247 guard modülü → Operations-bound focused test Bu sayfa yalnız S339 kapısına aittir; komşu kapıların kaynakları bu kabulün içine katılmaz.

S339Production writer guardOperations id exactsource SHA exacttest target exact

operation: g8l-s339-user-first-kernel-entry-writer-guard-integration-partial

production · S247 guard · focused test · Operations · 4 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 öğesiL6365–L6540
kernel/src/task/scheduler.rs::user_first_kernel_entry

/// User task'ler için **ilk giriş** noktası.
/// `context_switch + ret` ile buraya geliyoruz, sonra direkt EL0'a eret yapıyoruz.
/// Bu, trampoline + extra fonksiyon katmanlarını büyük ölçüde azaltır.
#[no_mangle]
pub extern "C" fn user_first_kernel_entry() -> ! {
    crate::kprintln!("[M4.3-DEBUG] >>> Entered user_first_kernel_entry (EN SADE YOL - bypass)");

    #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
    let s339_irq_guard = crate::arch::aarch64::IrqGuard::new();
    #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
    let s339_writer_access = crate::g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s339_user_first_kernel_entry_writer_guard_integration::acquire_s339_production_scheduler_writer_access()
        .unwrap_or_else(|error| {
            panic!(
                "S339 user-first-kernel-entry scheduler writer guard failed closed: {:?}",
                error
            )
        });

    unsafe {
        let sched = &mut *core::ptr::addr_of_mut!(SCHEDULER);

        if let Some(curr) = &mut sched.current_task {
            if !curr.is_user {
                panic!("[M4.3] user_first_kernel_entry: not a user task");
            }

            crate::kprintln!(
                "[M4.3-DEBUG] user_first_kernel_entry (SADE) → '{}' (ELR=0x{:x})",
                curr.name,
                curr.saved_user_elr
            );

            if curr.name.contains("elf") {
                crate::kprintln!(
                    ">>> [M8-ELF] Task '{}' is about to enter EL0 with its own AddressSpace (root=0x{:x})",
                    curr.name, curr.page_table_root.as_u64()
                );
            }

            // M8.2 — TTBR0 switch for tasks with their own AddressSpace
            // S339 already owns the whole-scheduler writer. The historical
            // helper would acquire the S265 reader again, so the RPi5 path
            // supplies its exact old-ASID scalar to the non-nesting S334
            // architecture helper instead.
            #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
            let old_asid = curr.asid;
            #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
            let maybe_switch_to_task_address_space = |task: &Task| {
                prepare_task_for_context_switch_from_s334_snapshot(task, old_asid);
            };
            maybe_switch_to_task_address_space(curr);

            #[cfg(not(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5")))]
            {
                // =====================================================
                // ÇOK GÜÇLÜ STACK AYARI (ilk giriş için kritik)
                // =====================================================
                core::arch::asm!(
                    // Stack pointer’ı 16-byte align et
                    "mov x9, sp",
                    "and x9, x9, #~15",
                    "mov sp, x9",
                    // 128 byte’lık çok güçlü frame kur (daha fazla güvenlik alanı)
                    "sub sp, sp, #128",
                    "stp x29, x30, [sp, #112]",
                    "stp x27, x28, [sp, #96]",
                    "stp x25, x26, [sp, #80]",
                    "mov x29, sp",
                    options(nostack, preserves_flags)
                );

                // Frame'i stack'e kopyala (güvenli base register için)
                let mut local: [u64; 31] = [0; 31];
                local[..30].copy_from_slice(&curr.saved_user_gprs[..30]);
                local[30] = curr.saved_user_gprs[30]; // lr (x30)

                let fptr = local.as_ptr() as u64;

                core::arch::asm!(
                    "mov x16, {fptr}",

                    "msr sp_el0, {sp}",
                    "msr elr_el1, {elr}",
                    "msr spsr_el1, {spsr}",

                    "ldp x0,  x1,  [x16, #0]",
                    "ldp x2,  x3,  [x16, #16]",
                    "ldp x4,  x5,  [x16, #32]",
                    "ldp x6,  x7,  [x16, #48]",
                    "ldp x8,  x9,  [x16, #64]",
                    "ldp x10, x11, [x16, #80]",
                    "ldp x12, x13, [x16, #96]",
                    "ldp x14, x15, [x16, #112]",
                    // x16/x17 (IP0/IP1) USER tarafından yüklenmez — base'i koruyoruz.
                    // Skip [x16, #128] (x16/x17 slot).
                    "ldp x18, x19, [x16, #144]",
                    "ldp x20, x21, [x16, #160]",
                    "ldp x22, x23, [x16, #176]",
                    "ldp x24, x25, [x16, #192]",
                    "ldp x26, x27, [x16, #208]",
                    "ldp x28, x29, [x16, #224]",
                    "ldr x30,      [x16, #240]",

                    "eret",

                    fptr = in(reg) fptr,
                    sp   = in(reg) curr.user_sp,
                    elr  = in(reg) curr.saved_user_elr,
                    spsr = in(reg) curr.saved_user_spsr,
                    options(noreturn)
                );
            }

            #[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
            {
                // Copy every scheduler-owned value before releasing the writer.
                let mut local: [u64; 31] = [0; 31];
                local[..30].copy_from_slice(&curr.saved_user_gprs[..30]);
                local[30] = curr.saved_user_gprs[30]; // lr (x30)
                let fptr = local.as_ptr() as u64;
                let user_sp = curr.user_sp;
                let saved_user_elr = curr.saved_user_elr;
                let saved_user_spsr = curr.saved_user_spsr;

                drop(s339_writer_access);
                drop(s339_irq_guard);

                // One terminal assembly block loads all Rust operands before
                // changing SP. x16 remains the GPR-frame base; x17 carries the
                // owned user SP until SP_EL0 is written. Historical x16/x17
                // user restore skipping is preserved.
                core::arch::asm!(
                    "mov x9, sp",
                    "and x9, x9, #~15",
                    "mov sp, x9",
                    "sub sp, sp, #128",
                    "stp x29, x30, [sp, #112]",
                    "stp x27, x28, [sp, #96]",
                    "stp x25, x26, [sp, #80]",
                    "mov x29, sp",

                    "msr sp_el0, x17",
                    "msr elr_el1, x14",
                    "msr spsr_el1, x15",

                    "ldp x0,  x1,  [x16, #0]",
                    "ldp x2,  x3,  [x16, #16]",
                    "ldp x4,  x5,  [x16, #32]",
                    "ldp x6,  x7,  [x16, #48]",
                    "ldp x8,  x9,  [x16, #64]",
                    "ldp x10, x11, [x16, #80]",
                    "ldp x12, x13, [x16, #96]",
                    "ldp x14, x15, [x16, #112]",
                    // x16/x17 (IP0/IP1) USER tarafından yüklenmez — base'i koruyoruz.
                    // Skip [x16, #128] (x16/x17 slot).
                    "ldp x18, x19, [x16, #144]",
                    "ldp x20, x21, [x16, #160]",
                    "ldp x22, x23, [x16, #176]",
                    "ldp x24, x25, [x16, #192]",
                    "ldp x26, x27, [x16, #208]",
                    "ldp x28, x29, [x16, #224]",
                    "ldr x30,      [x16, #240]",
                    "eret",
                    in("x16") fptr,
                    in("x17") user_sp,
                    in("x14") saved_user_elr,
                    in("x15") saved_user_spsr,
                    options(noreturn)
                );
            }
        } else {
            panic!("[M4.3] user_first_kernel_entry: no current task");
        }
    }
}
snippet sha256: 6f85e35aa8bbfile sha256: 838dd474448c
02 · Ortak exclusion üyeliği

S247 production writer guard

tam Rust öğesiL163–L175
kernel/src/g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s339_user_first_kernel_entry_writer_guard_integration.rs::acquire_s339_production_scheduler_writer_access

#[cfg(all(target_arch = "aarch64", target_os = "none", feature = "board-rpi5"))]
pub fn acquire_s339_production_scheduler_writer_access(
) -> Result<G8lS339ProductionSchedulerWriterAccess, 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(G8lS339ProductionSchedulerWriterAccess { _access: access })
}
snippet sha256: d0611cd67abafile sha256: 8a07a73a3fcc
03 · Doğrulayan test kodu

Operations komutuna bağlı focused test

tam Rust öğesiL229–L246
simulation/tests/g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s339_user_first_kernel_entry_writer_guard_integration.rs::target_function_contains_one_scheduler_alias_and_one_s339_guard

#[test]
fn target_function_contains_one_scheduler_alias_and_one_s339_guard() {
    let target = user_first_kernel_entry_boundary();
    assert_eq!(target.matches("addr_of_mut!(SCHEDULER)").count(), 1);
    assert_eq!(
        target
            .matches("acquire_s339_production_scheduler_writer_access()")
            .count(),
        1
    );
    assert_eq!(
        target
            .matches("if let Some(curr) = &mut sched.current_task")
            .count(),
        1
    );
}
snippet sha256: 8da008275a71file sha256: 849e3cd3e98a
04 · Kapı kimlik kaydı

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

tam Operations kaydıL13979–L14056
website/src/lib/operations.ts::g8l-s339-user-first-kernel-entry-writer-guard-integration-partial
  {
    id: "g8l-s339-user-first-kernel-entry-writer-guard-integration-partial",
    date: "2026-08-27",
    sequence: 339,
    status: "passed",
    umbrella_status: "partial",
    title: "S339 · User-first-kernel-entry production writer guard integration",
    summary:
      "S339, user_first_kernel_entry içindeki tek mutable SCHEDULER yolunu IRQ-masked CPU0 sınırında S338 ve 44 production reader'ın kullandığı aynı S247 state word'e bağlar. Current user task'ın old-ASID değeri writer altında owned scalar'a alınır; address-space hazırlığı nested S265 reader açmadan tamamlanır ve ELR/SPSR/SP ile 31 GPR owned frame'e kopyalanır. Writer lease bırakılır, IRQ state restore edilir ve yalnız sonra terminal stack/eret assembly başlar. Guarded writer 12/69, açık writer 57 ve provider authority 0'dır. Production entry wiring=1 olsa da dolaylı context_switch+ret sınırı nedeniyle direct callsite=0 ve supported-profile runtime gözlemi=0'dır; downstream task_exit writer'ı S340 için açıktır.",
    evidence: [
      "Focused user-first-kernel-entry writer-integration kapısı 30/30 PASS verdi; tarihsel S301 15/15 ve bir önceki S338 27/27 regresyonları ayrıca geçti.",
      "Aynı S247 state word üzerinde CPU0-only writer membership, non-CPU0 pre-commit rejection, reader→writer ve writer→reader exclusion, exact-once commit/error release ve S338→S339 token monotonluğu doğrulandı.",
      "Production kaynak sırası debug marker → IRQ guard → acquire_s339 writer → tek mutable alias/current-user-task doğrulaması → owned old-ASID → nested-reader içermeyen address-space hazırlığı → ELR/SPSR/SP/[u64;31] owned snapshot → writer drop → IRQ restore → terminal stack/eret olarak kilitlendi.",
      "Terminal assembly bütün Rust operandlarını SP mutation'dan önce x16/x17/x14/x15'e alır; tarihsel 128-byte frame ile x16/x17 user restore atlaması korunur. Writer lease veya IRQ guard eret sınırını geçmez.",
      "Non-user ve missing-current-task exact fail-closed panic metinleri ile RPi5 dışı tarihsel S301 restore şekli korunur. Önceki S338 first-ERET writer sınırı ayrı kalır.",
      "Fonksiyon production task-entry hedefi olarak bir kez kurulur; direct source callsite yoktur. Bu entry wiring kanıtıdır, QEMU/RPi supported-profile invocation veya cihaz gözlemi değildir.",
      "QEMU, RPi4, RPi5 ve RPi5+SMP AArch64 compile profilleri fresh ve izole target dizinlerinde 4/4 exit 0 verdi; zero-warning iddiası yoktur.",
      "S238–S339 dependency matrisi iki bağımsız seri koşuda 103 grup / 1575/1575 PASS verdi; normalize çıktılar aynı fdf80b31…c9bd SHA-256 ile byte-eşittir.",
      "Exact yedi tarihsel G8h assertion adı dışlanıp --test-threads=1 kabulü kullanıldığında tam workspace 301 sonuç grubu / 3403 PASS / 0 fail / 7 filtered verdi; 66756 B log a1c5ad69…da30'dur.",
      "Filtresiz workspace yalnız frozen S96 source-identity reddinde exit 101 verdi; 61977 B log 59f3341d…2b95'tir ve global workspace GREEN iddia edilmez.",
      "make verify-qemu ortak regresyonu strict ELF W^X 31/31, S130–S154, IPC 20/20, scheduler SEC5 ve kernel fault 0 ile PASS verdi. Bu S339 runtime invocation kanıtı değildir.",
      "Website 526/526 test ile PASS; lint, boş çıktılı TypeScript kontrolü ve 23/23 static route ayrıca geçti. Cloudflare Pages production/main ilk S339 içerik yayını 151b2c25 ile tamamlandı; cache-busted custom-domain /operations/ ve /timeline/ HTTP 200 döndü ve yerel out ile byte-exact eşleşti.",
      "Timeline 178 bağımsız gate-policy kartı taşır; S339, S338, S337, S325, S324 ve S323 kartları ayrı ayrı tam birer kez bulunur. S325–S339 kartları en az 1055 karakterdir ve birleşik gate-policy kutusu yoktur.",
      "S245 request ve S244 admission dokunulmadan kalır; production provider authority=0, whole-scheduler exclusion=false ve toplam 57 production writer açık kalır.",
      "Fiziksel/device işlem yapılmadı: physical/device operations=0 ve RUNBOOK_EXECUTED_IN_S339=NO.",
    ],
    commands: [
      "cargo test -p aselsan_microkernel_simulation --test g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s339_user_first_kernel_entry_writer_guard_integration -- --nocapture",
      "cargo check -p aselsan_kernel --target aarch64-unknown-none --no-default-features --features board-rpi5",
      "cargo check -p aselsan_kernel --target aarch64-unknown-none --no-default-features --features board-rpi5,smp",
      "cargo test --workspace --quiet -- --test-threads=1 [seven exact historical --skip filters]",
      "make verify-qemu",
      "npm run deploy",
    ],
    terminalSessions: [
      {
        id: "g8l-s339-user-first-kernel-entry-writer-guard-integration",
        title: "G8l S339 user-first-kernel-entry writer guard integration",
        commandLines: [
          "cargo test -p aselsan_microkernel_simulation --test g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s339_user_first_kernel_entry_writer_guard_integration -- --nocapture",
        ],
        outputLines: [
          "test result: ok; S339 focused 1 group / 30 passed; 0 failed",
          "shared S247 gate: 44 guarded readers + 12/69 guarded writers; 57 writers open",
          "owned old-ASID/no nested S265 reader; writer drop < IRQ restore < terminal stack/eret",
          "production entry wiring=1; direct callsite=0; supported-profile runtime observations=0",
        ],
        exitCode: 0,
        outputMode: "complete",
      },
      {
        id: "g8l-s339-operations-timeline-production-publication",
        title: "S339 Operations/Timeline production publication",
        commandLines: [
          "npm run deploy",
          "curl --cache-busted https://aselsan.kerege.net/{operations,timeline}/ and compare with local out",
        ],
        outputLines: [
          "Cloudflare Pages production/main initial content deployment: 151b2c25",
          "custom domain: operations HTTP 200 / timeline HTTP 200; both byte-exact with local out",
          "timeline gate-policy cards=178; S339=1; S338=1; S337=1; S325=1; S324=1; S323=1; combined gate-policy box absent",
          "S324 policy chars=1573; S325-S339 minimum policy chars=1055",
          "direct immutable pages.dev fetch: curl exit 28 / HTTP 000 connection timeout; direct-host equality not claimed",
        ],
        exitCode: 0,
        outputMode: "complete",
      },
    ],
    terminalSessionsNote:
      "S339 on ikinci production writer'ın kaynak entegrasyonudur. Production entry target source-wired olsa da direct callsite veya supported-profile runtime/cihaz gözlemi yoktur; global exclusion ya da provider authority oluşmadı.",
    limitations: [
      "57 production writer aynı shared gate dışında kaldığı için whole-scheduler exclusion ve provider authority açık kalır.",
      "Production entry wiring=1'dir; direct callsite=0 ve supported-profile runtime invocation/observation kanıtı yoktur.",
      "Downstream task_exit writer entegrasyonu S340 için açık bırakılmıştır.",
      "Default-parallel PTY determinism S331'den açık taşınır; kayıtlı seri kabul matrisi kullanılır.",
      "Transient-contention liveness/soak, Generic SMP ve fiziksel RPi kabulü açık kalır.",
    ],
  },
snippet sha256: 4fec12a4ece4file sha256: 9726dbf00f84
Focused test komutu
cargo test -p aselsan_microkernel_simulation --test g8l_target_dispatch_scheduler_owner_scheduler_mutation_production_migration_lifecycle_s339_user_first_kernel_entry_writer_guard_integration -- --test-threads=1
proof: docs/M8.1-RPi5-G8l-S339-User-First-Kernel-Entry-Writer-Guard-Integration-Proof.md
Registry schema v5 · generator website/scripts/generate-code-gates.mjs · Tam SHA-256: 91d38c7b6222f0b4c117be786454853543da55a160e543d9b951057cc20dcc06