Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/sio-notify-lifetime.yml
Original file line number Diff line number Diff line change
@@ -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
90 changes: 90 additions & 0 deletions ci/test_sio_notify_lifetime.py
Original file line number Diff line number Diff line change
@@ -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 <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
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')
Loading