diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-07-10 11:31:46 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-07-10 11:31:46 +0800 |
| commit | e90b72ec3082588b296956730bd2930cf8d5d671 (patch) | |
| tree | 36ff6916af9b4176ea5a9662219d11e721f0b691 /test/test_smp.cc | |
| parent | 1767d390fbf3d0c65389de46caf0b6d43ef3b6ad (diff) | |
| download | lume-e90b72ec3082588b296956730bd2930cf8d5d671.tar.gz lume-e90b72ec3082588b296956730bd2930cf8d5d671.tar.xz | |
refactor: promote new architecture to repository root
Archive the deprecated implementation under lume-legacy, make the new kernel the default root-level build, and update repository entry points without changing kernel behavior.
Diffstat (limited to 'test/test_smp.cc')
| -rw-r--r-- | test/test_smp.cc | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/test/test_smp.cc b/test/test_smp.cc new file mode 100644 index 0000000..f934526 --- /dev/null +++ b/test/test_smp.cc @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2026 Richard Qin */ + +/* + * test_smp.cc — Post-SMP boot tests + * + * These tests run after all APs are online. They verify: + * 1. IPI delivery — BSP sends IPI to each AP, AP increments counter. + * 2. Task migration — a task moves from one runqueue to another. + * 3. TLB shootdown IPI — cross-CPU flush. + * + * Called from the init thread (PID 1) context, NOT from the pre-SMP + * self-test suite. + */ + +#include <lume/selftest.h> +#include <lume/smp.h> +#include <lume/sched.h> +#include <lume/atomic.h> +#include <lume/config.h> +#include <arch/cpu.h> + +/* Shared counter incremented by APs when they receive an IPI */ +static lume::atomic<uint32> g_ipi_ack_count{0}; + +/* ------------------------------------------------------------------ */ +/* IPI delivery test */ +/* ------------------------------------------------------------------ */ + +void selftest_ipi_delivery() +{ + st_begin("smp: IPI delivery to all APs"); + + /* Reset counter */ + g_ipi_ack_count.store(0, __ATOMIC_RELAXED); + + uint32 bsp = static_cast<uint32>(arch::cpu::id()); + uint32 num_cpus = 4; /* TODO: derive from FDT */ + + /* Build mask of all APs */ + uint64 ap_mask = 0; + uint32 expected = 0; + for (uint32 i = 0; i < num_cpus; i++) { + if (i == bsp) continue; + ap_mask |= (1ULL << i); + expected++; + } + + /* Send reschedule IPI to all APs */ + smp_send_ipi(ap_mask, IPI_RESCHEDULE); + + /* Wait a short while for APs to process the interrupt. + * APs are in wfi (idle loop), so they'll wake immediately + * on interrupt delivery. We just need to give them time + * to run the handler. */ + for (volatile int i = 0; i < 100000; i++) { + /* spin-wait */ + } + + /* We can't directly check that IPI was received because + * IPI_RESCHEDULE just sets need_resched — no ack. + * Instead verify no crash occurred and the IPI infrastructure + * didn't deadlock. This is a liveness test. */ + + st_pass(); +} + +/* ------------------------------------------------------------------ */ +/* IPI halt test (send to self, skip) */ +/* ------------------------------------------------------------------ */ + +void selftest_ipi_self_skip() +{ + st_begin("smp: IPI reason bitmask accumulation"); + + uint32 cpu = static_cast<uint32>(arch::cpu::id()); + + /* Manually set multiple reasons atomically */ + g_ipi_data[cpu].pending.store(0, __ATOMIC_RELAXED); + g_ipi_data[cpu].pending.fetch_or(IPI_RESCHEDULE, __ATOMIC_RELEASE); + g_ipi_data[cpu].pending.fetch_or(IPI_TLB_SHOOTDOWN, __ATOMIC_RELEASE); + + uint32 val = g_ipi_data[cpu].pending.load(__ATOMIC_ACQUIRE); + ST_ASSERT_EQ(val, IPI_RESCHEDULE | IPI_TLB_SHOOTDOWN); + + /* Clean up */ + g_ipi_data[cpu].pending.store(0, __ATOMIC_RELAXED); + + st_pass(); +} + +/* ------------------------------------------------------------------ */ +/* TLB shootdown IPI test */ +/* ------------------------------------------------------------------ */ + +void selftest_tlb_shootdown() +{ + st_begin("smp: TLB shootdown IPI (cross-CPU flush)"); + + uint32 bsp = static_cast<uint32>(arch::cpu::id()); + uint32 num_cpus = 4; + + /* Build AP mask */ + uint64 ap_mask = 0; + for (uint32 i = 0; i < num_cpus; i++) { + if (i == bsp) continue; + ap_mask |= (1ULL << i); + } + + /* Set TLB range on each AP's IpiData */ + for (uint32 i = 0; i < num_cpus; i++) { + if (i == bsp) continue; + g_ipi_data[i].tlb_start = 0; + g_ipi_data[i].tlb_end = 0; /* 0,0 = full flush */ + } + + /* Send TLB shootdown */ + smp_send_ipi(ap_mask, IPI_TLB_SHOOTDOWN); + + /* Wait for APs to process */ + for (volatile int i = 0; i < 100000; i++) {} + + /* If we got here without panic, TLB shootdown succeeded */ + st_pass(); +} + +/* ------------------------------------------------------------------ */ +/* Public entry point */ +/* ------------------------------------------------------------------ */ + +void selftest_smp() +{ + selftest_ipi_delivery(); + selftest_ipi_self_skip(); + selftest_tlb_shootdown(); +} |
