From a59d7057dd693e80dde6b38b29c254332bf7ad3b Mon Sep 17 00:00:00 2001 From: Stuart Fraser <60394096+stuart902@users.noreply.github.com> Date: Tue, 3 Nov 2026 07:57:14 -0400 Subject: [PATCH] ci: compile pinned SmartIO notifier fix for both page sizes Build the SmartIO core and DMA consumer objects with each Orchard ARM64 configuration and run the captured-callback retirement harness. Keep the exact kernel SHA and source receipt with the object artifacts. This is test-only wiring, not a boot image or hardware qualification. Assisted-by: OpenAI --- .github/workflows/sio-notify-lifetime.yml | 63 ++++++++++++++++ ci/test_sio_notify_lifetime.py | 90 +++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 .github/workflows/sio-notify-lifetime.yml create mode 100644 ci/test_sio_notify_lifetime.py diff --git a/.github/workflows/sio-notify-lifetime.yml b/.github/workflows/sio-notify-lifetime.yml new file mode 100644 index 00000000..123231d0 --- /dev/null +++ b/.github/workflows/sio-notify-lifetime.yml @@ -0,0 +1,63 @@ +name: SmartIO notifier lifetime checks +on: + push: + branches: [ci/sio-notify-lifetime-nov3] +permissions: + contents: read +jobs: + compile: + runs-on: ubuntu-24.04-arm + container: debian:bookworm + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + pages: [4k, 16k] + defaults: + run: + shell: bash + steps: + - run: apt-get update && apt-get install -y git ca-certificates python3 + - uses: actions/checkout@v4 + with: + persist-credentials: false + - uses: actions/checkout@v4 + with: + repository: stuart902/linux + ref: 9e6c464782046a73095e32590f6f55c88feb232f + path: linux-draft + persist-credentials: false + - name: Verify pinned source + run: | + test "$(git -C linux-draft rev-parse HEAD)" = 9e6c464782046a73095e32590f6f55c88feb232f + test -z "$(git -C linux-draft status --porcelain)" + mkdir -p out + git -C linux-draft rev-parse HEAD > out/linux-source-commit.txt + - name: Install Orchard kernel toolchain + run: bash kernel/install-toolchain + - name: Compile SmartIO core and DMA consumer + run: | + build="$PWD/out/build" + make -C linux-draft O="$build" LLVM=-19 ARCH=arm64 orchard_apple${{ matrix.pages }}_defconfig + make -C linux-draft O="$build" LLVM=-19 ARCH=arm64 -j"$(nproc)" prepare modules_prepare + make -C linux-draft O="$build" LLVM=-19 ARCH=arm64 -j"$(nproc)" drivers/soc/apple/apple-sio-core.o drivers/dma/apple-sio-dma.o + cp "$build/.config" out/kernel.config + cp "$build/drivers/soc/apple/apple-sio-core.o" "$build/drivers/dma/apple-sio-dma.o" out/ + dpkg-query -W > out/toolchain-packages.lock + test -z "$(git -C linux-draft status --porcelain)" + (cd out && sha256sum *.o kernel.config linux-source-commit.txt > SHA256SUMS) + - name: Exercise captured IRQ callback retirement + env: + CC: cc -fsanitize=address,undefined -fno-omit-frame-pointer + run: python3 ci/test_sio_notify_lifetime.py linux-draft + - uses: actions/upload-artifact@v4 + with: + name: sio-notify-9e6c464-compile-${{ matrix.pages }} + path: | + out/*.o + out/kernel.config + out/linux-source-commit.txt + out/toolchain-packages.lock + out/SHA256SUMS + if-no-files-found: error + retention-days: 7 diff --git a/ci/test_sio_notify_lifetime.py b/ci/test_sio_notify_lifetime.py new file mode 100644 index 00000000..6e0695df --- /dev/null +++ b/ci/test_sio_notify_lifetime.py @@ -0,0 +1,90 @@ +"""Run actual notifier replacement against a captured-IRQ callback model. + +Usage: python3 kernel/tests/test_sio_notify_lifetime.py PREPARED_KERNEL_SOURCE +Requires a host C11 compiler (CC, default cc). No device or MMIO access. +""" +import argparse +import os +from pathlib import Path +import shlex +import subprocess +import tempfile + +parser = argparse.ArgumentParser(description=__doc__) +parser.add_argument('source', type=Path) +args = parser.parse_args() +text = (args.source / 'drivers/soc/apple/apple-sio-core.c').read_text() +start = text.index('void apple_sio_set_notify(') +end = text.index('EXPORT_SYMBOL_GPL(apple_sio_set_notify)', start) +function = text[start:end] +prelude = r''' +#include +#include +#include +#include +typedef uint8_t u8; +typedef void (*apple_sio_notify_t)(void *, uint64_t); +#define APPLE_SIO_MAX_ENDPOINTS 0x82 +struct apple_sio { + int pending, irq; + bool irq_requested; + struct { apple_sio_notify_t fn; void *data; } notify[APPLE_SIO_MAX_ENDPOINTS]; +}; +static bool locked; +static unsigned int waits, callbacks, may_sleep; +static apple_sio_notify_t captured; +static void *captured_data; +static struct apple_sio *current; +static apple_sio_notify_t expected_fn; +static void *expected_data; +struct context { bool alive; }; +static void callback(void *data, uint64_t message) { + struct context *c=data; + (void)message; + assert(c->alive); callbacks++; +} +#define xa_lock_irqsave(p,f) do { (void)(p); (f)=0; assert(!locked); locked=true; } while (0) +#define xa_unlock_irqrestore(p,f) do { (void)(p); (void)(f); assert(locked); locked=false; } while (0) +static __attribute__((unused)) void might_sleep(void) { may_sleep++; } +static __attribute__((unused)) void synchronize_irq(int irq) { + (void)irq; assert(!locked); waits++; + assert(current->notify[0x5b].fn == expected_fn); + assert(current->notify[0x5b].data == expected_data); + if (captured) { captured(captured_data,0); captured=NULL; } +} +''' +main = r''' +int main(void) { + struct apple_sio sio={.irq_requested=true}; + struct context old={.alive=true}, next={.alive=true}; + current=&sio; expected_fn=callback; expected_data=&old; + apple_sio_set_notify(&sio,0x5b,callback,&old); + captured=sio.notify[0x5b].fn; captured_data=sio.notify[0x5b].data; + expected_data=&next; + apple_sio_set_notify(&sio,0x5b,callback,&next); + assert(callbacks==1 && !captured); old.alive=false; + captured=sio.notify[0x5b].fn; captured_data=sio.notify[0x5b].data; + expected_fn=NULL; expected_data=NULL; + apple_sio_set_notify(&sio,0x5b,NULL,NULL); + assert(callbacks==2 && !captured); next.alive=false; + assert(!sio.notify[0x5b].fn && !sio.notify[0x5b].data); + assert(waits==3); + sio.irq_requested=false; + expected_fn=NULL; expected_data=NULL; + apple_sio_set_notify(&sio,0x5b,NULL,NULL); + apple_sio_set_notify(&sio,0xff,NULL,NULL); + assert(waits==3 && may_sleep==5); + return 0; +} +''' +compiler = shlex.split(os.environ.get('CC', 'cc')) +if not compiler: + parser.error('CC must name a host C compiler') +with tempfile.TemporaryDirectory(prefix='sio-notify-test-') as temp: + source = Path(temp) / 'test.c' + binary = Path(temp) / 'test' + source.write_text(prelude + function + main) + subprocess.run(compiler + ['-std=c11', '-Wall', '-Wextra', '-Werror', + str(source), '-o', str(binary)], check=True) + subprocess.run([str(binary)], check=True, timeout=5) +print('PASS: registration, replacement, removal, absent IRQ, invalid endpoint')