Skip to content
Open
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
15 changes: 15 additions & 0 deletions Sources/Application/Application.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1653,6 +1653,21 @@ struct Application {
uartPutDec(UInt64(kernel_gpio4_restore()))
uartPuts("\n")

// Runtime V141: PWM1 channel-1 program. UART token only.
// Fail-closed PWM1 readback + leftover restore. No pin-mux.
// No output claim. No boot event emit. No EL0 enter after GENET.
uartPuts("runtime v141: PWM1 program\n")
let pwm4_ok_boot = kernel_pwm4_selftest()
uartPuts("pwm4 ok=")
uartPutDec(UInt64(pwm4_ok_boot))
uartPuts(" version=141 pwm1=")
uartPutDec(UInt64(kernel_pwm4_pwm1()))
uartPuts(" en=")
uartPutDec(UInt64(kernel_pwm4_en()))
uartPuts(" restore=")
uartPutDec(UInt64(kernel_pwm4_restore()))
uartPuts("\n")

kernel_event_emit(KERNEL_EVENT_KIND_SELFTEST, 22, UInt(kernel_pool_selftest()), UInt(kernel_pool_count()))
kernel_event_emit(KERNEL_EVENT_KIND_SELFTEST, 23, UInt(heap_fragmentation_selftest()), UInt(kernel_pool_pressure_selftest()))
kernel_event_emit(KERNEL_EVENT_KIND_SELFTEST, 24, UInt(kernel_driver_registry_selftest()), UInt(kernel_driver_count()))
Expand Down
17 changes: 16 additions & 1 deletion Sources/Application/UARTShell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func uartPutShellBufferSlice(_ start: UInt32, _ len: UInt32) {
}

let SHELL_COMMAND_LIST =
"commands=help,protocol,status,heap,queues,tasks,tasks2,kobjects,drivers,drivercheck,mailboxes,sendtest,supervisor,health,handlecheck,capcheck,events,runtime,agent,certificate,sched,sched2,sched3,sched4,sched5,sched6,sched7,sched8,sched9,sched10,sched11,sched12,cores,locks,runqueues,diag,irqs,timers,memcheck,faults,retained,retained-clear,memmap,mmu,pools,poolcheck,heapfrag,poolstats,frames,heapcheck,framecheck,stress,frameprobe,bootcert,canceltest,taskcheck,channeltest,bootcheck,soak,heap-invalid-free-test,heap-double-free-test,panic-test,fault-test,reboot,vmm,asplit,el0,syscall,uaccess,usermode,process,loader,multiprocess,sdhci,card,block,fat32,mailbox,framebuf,console,pcie,vl805,xhci,genet,genet2,genet3,genet4,gpio,genet5,genet6,genet7,genet8,genet9,genet10,genet11,genet12,i2c,pwm,i2c2,spi2,stimer,sdload,sdls,sdfile,sdovl,sdovf,sdiss,gpio2,stimer2,pwm2,gpio3,stimer3,mboxt,mboxc,wdog2,mboxv,rng,dma2,sdwr,sdmk,sdrd,sdst,sdscr,sdss,sdbus,sdmb,sdsw,sdmw,sdbc,sdfi,sdfb,sdfm,sdrm,genet13,genet14,genet15,genet16,genet17,genet18,genet19,genet20,genet21,genet22,genet23,genet24,genet25,genet26,genet27,genet28,genet29,genet30,genet31,genet32,genet33,genet34,pwm3,gpio4"
"commands=help,protocol,status,heap,queues,tasks,tasks2,kobjects,drivers,drivercheck,mailboxes,sendtest,supervisor,health,handlecheck,capcheck,events,runtime,agent,certificate,sched,sched2,sched3,sched4,sched5,sched6,sched7,sched8,sched9,sched10,sched11,sched12,cores,locks,runqueues,diag,irqs,timers,memcheck,faults,retained,retained-clear,memmap,mmu,pools,poolcheck,heapfrag,poolstats,frames,heapcheck,framecheck,stress,frameprobe,bootcert,canceltest,taskcheck,channeltest,bootcheck,soak,heap-invalid-free-test,heap-double-free-test,panic-test,fault-test,reboot,vmm,asplit,el0,syscall,uaccess,usermode,process,loader,multiprocess,sdhci,card,block,fat32,mailbox,framebuf,console,pcie,vl805,xhci,genet,genet2,genet3,genet4,gpio,genet5,genet6,genet7,genet8,genet9,genet10,genet11,genet12,i2c,pwm,i2c2,spi2,stimer,sdload,sdls,sdfile,sdovl,sdovf,sdiss,gpio2,stimer2,pwm2,gpio3,stimer3,mboxt,mboxc,wdog2,mboxv,rng,dma2,sdwr,sdmk,sdrd,sdst,sdscr,sdss,sdbus,sdmb,sdsw,sdmw,sdbc,sdfi,sdfb,sdfm,sdrm,genet13,genet14,genet15,genet16,genet17,genet18,genet19,genet20,genet21,genet22,genet23,genet24,genet25,genet26,genet27,genet28,genet29,genet30,genet31,genet32,genet33,genet34,pwm3,gpio4,pwm4"

func printShellReady() {
uartPuts("shell ready \(SHELL_COMMAND_LIST)\n")
Expand Down Expand Up @@ -3101,6 +3101,19 @@ func printGpio4() {
uartPuts("\n")
}

func printPwm4() {
_ = kernel_pwm4_selftest()
uartPuts("pwm4 ok=")
uartPutDec(UInt64(kernel_pwm4_ok()))
uartPuts(" version=141 pwm1=")
uartPutDec(UInt64(kernel_pwm4_pwm1()))
uartPuts(" en=")
uartPutDec(UInt64(kernel_pwm4_en()))
uartPuts(" restore=")
uartPutDec(UInt64(kernel_pwm4_restore()))
uartPuts("\n")
}

func printPoolName(_ pool: UInt32) {
var i: UInt32 = 0
let n = kernel_pool_name_len(pool)
Expand Down Expand Up @@ -4121,6 +4134,8 @@ func dispatchShellCommand(_ commandStart: UInt32, _ commandLen: UInt32, _ reques
printPwm3()
} else if shellBufferSliceEquals(commandStart, commandLen, "gpio4") {
printGpio4()
} else if shellBufferSliceEquals(commandStart, commandLen, "pwm4") {
printPwm4()
} else if shellBufferSliceEquals(commandStart, commandLen, "pools") {
printPools()
} else if shellBufferSliceEquals(commandStart, commandLen, "poolcheck") {
Expand Down
7 changes: 7 additions & 0 deletions Sources/Support/include/Support.h
Original file line number Diff line number Diff line change
Expand Up @@ -1633,6 +1633,13 @@ unsigned int kernel_spi2_done(void);
unsigned int kernel_spi2_loop(void);
unsigned int kernel_spi2_rx(void);

// V141: PWM1 channel-1 program after GENET. Fail-closed readback. No EL0.
int kernel_pwm4_selftest(void);
int kernel_pwm4_ok(void);
unsigned int kernel_pwm4_pwm1(void);
unsigned int kernel_pwm4_en(void);
unsigned int kernel_pwm4_restore(void);

// V84: system timer CLO/CHI + four compare slots. Read-only. No boot emit.
int kernel_stimer_selftest(void);
int kernel_stimer_ok(void);
Expand Down
76 changes: 76 additions & 0 deletions Sources/Support/kernel_pwm4.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Runtime V141: BCM2711 PWM1 channel-1 program after GENET.
// Fail-closed RNG1/DAT1/PWEN1 write+readback on the second PWM block
// (0xFE20C800). Leftover restore. No pin-mux. No output/audio claim.
// No PWM0 writes (V93). No CM_PWM (V93 restored leftover).
// No EL0 enter (I-abort esr=0xbf000002 elr=0x100002000 after GENET DMA).
// No boot event emit.

#include "Support.h"
#include <stdint.h>

#define PWM1_BASE 0xFE20C800UL
#define G32(off) (*(volatile uint32_t *)(PWM1_BASE + (unsigned long)(off)))

#define PWM_CTL 0x00U
#define PWM_RNG1 0x10U
#define PWM_DAT1 0x14U

#define PWM_PWEN1 (1U << 0)
#define PWM_MSEN1 (1U << 7)

#define PWM4_RNG 32U
#define PWM4_DAT 8U

static int pwm4_probed;
static int pwm4_ok_val;
static unsigned int pwm4_pwm1_val;
static unsigned int pwm4_en_val;
static unsigned int pwm4_restore_val;

int kernel_pwm4_selftest(void) {
if (pwm4_probed) return pwm4_ok_val;
pwm4_probed = 1;
pwm4_ok_val = 0;
pwm4_pwm1_val = 0;
pwm4_en_val = 0;
pwm4_restore_val = 0;

if (kernel_pwm3_selftest() == 0) return 0;

unsigned int saved_ctl = G32(PWM_CTL);
unsigned int saved_rng = G32(PWM_RNG1);
unsigned int saved_dat = G32(PWM_DAT1);
if (saved_ctl == 0xFFFFFFFFU || saved_rng == 0xFFFFFFFFU || saved_dat == 0xFFFFFFFFU) {
return 0;
}
pwm4_pwm1_val = 1;

G32(PWM_RNG1) = PWM4_RNG;
G32(PWM_DAT1) = PWM4_DAT;
G32(PWM_CTL) = (saved_ctl & ~PWM_PWEN1) | PWM_PWEN1 | PWM_MSEN1;

unsigned int ctl = G32(PWM_CTL);
unsigned int rng = G32(PWM_RNG1);
unsigned int dat = G32(PWM_DAT1);
if ((ctl & PWM_PWEN1) != 0U && rng == PWM4_RNG && dat == PWM4_DAT) {
pwm4_en_val = 1;
}

G32(PWM_CTL) = saved_ctl;
G32(PWM_RNG1) = saved_rng;
G32(PWM_DAT1) = saved_dat;
if (G32(PWM_CTL) == saved_ctl && G32(PWM_RNG1) == saved_rng && G32(PWM_DAT1) == saved_dat) {
pwm4_restore_val = 1;
}

if (pwm4_pwm1_val == 1U && pwm4_en_val == 1U && pwm4_restore_val == 1U) {
pwm4_ok_val = 1;
return 1;
}
return 0;
}

int kernel_pwm4_ok(void) { return pwm4_ok_val; }
unsigned int kernel_pwm4_pwm1(void) { return pwm4_pwm1_val; }
unsigned int kernel_pwm4_en(void) { return pwm4_en_val; }
unsigned int kernel_pwm4_restore(void) { return pwm4_restore_val; }
1 change: 1 addition & 0 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ Turn the static identity-map MMU into a real virtual-memory system and run code
- [x] V93 PWM clock enable + CTL poke after GENET (`pwm2 ok=1 version=93 clk=1 en=1`). CM_PWM OSC + PWM0 PWEN1 readback; restore; no pin-mux; no output claim; no EL0.
- [x] V139 PWM GPIO12 ALT0 pin-mux after GENET (`pwm3 ok=1 version=139 pin=12 alt=1 restore=1`). Fail-closed `GPFSEL1` ALT0 readback + leftover restore; UART GPIO14/15 FSEL bits unchanged; no pull writes; no output claim; no EL0.
- [x] V140 GPIO42 rising-edge detect after GENET (`gpio4 ok=1 version=140 pin=42 rise=1 restore=1`). Fail-closed `GPREN1`/`GPEDS1` after a SET edge; leftover restore; no UART; no ALT0; no EL0.
- [x] V141 PWM1 channel-1 program after GENET (`pwm4 ok=1 version=141 pwm1=1 en=1 restore=1`). Fail-closed `PWM1` RNG1/DAT1/PWEN1 write+readback + leftover restore; no pin-mux; no output claim; no EL0.
- [x] V94 GPIO26 PUP_PDN write+readback after GENET (`gpio3 ok=1 version=94 pin=26 up=1 dn=1`). REG1 only; restore; no UART; no EL0.
- [x] V95 system timer C3 match after GENET (`stimer3 ok=1 version=95 chan=3 match=1`). ARM C3 only; no C0/C1/C2 writes; park after match; no EL0.
- [x] V96 mailbox GET_TEMPERATURE after GENET (`mboxt ok=1 version=96 temp=`). Millidegrees; fail-closed range; no EL0.
Expand Down
4 changes: 4 additions & 0 deletions scripts/netboot/net-iterate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,8 @@ PY
&& printf '%s' "$serial_delta" | grep -qa "pwm3 ok=1 version=139 pin=12 alt=" \
&& printf '%s' "$serial_delta" | grep -qa "runtime v140: GPIO rising-edge detect" \
&& printf '%s' "$serial_delta" | grep -qa "gpio4 ok=1 version=140 pin=42 rise=" \
&& printf '%s' "$serial_delta" | grep -qa "runtime v141: PWM1 program" \
&& printf '%s' "$serial_delta" | grep -qa "pwm4 ok=1 version=141 pwm1=1 en=" \
&& printf '%s' "$serial_delta" | grep -qa "vmmcheck ok=1" \
&& printf '%s' "$serial_delta" | grep -qa "asplit ok=1 version=46" \
&& printf '%s' "$serial_delta" | grep -qa "el0 ok=1 version=47" \
Expand Down Expand Up @@ -818,6 +820,8 @@ PY
probe_shell "pwm3" "^pwm3 ok=1 version=139 pin=12 alt="
# V140: GPIO42 rising-edge detect. Fail-closed GPEDS. No EL0.
probe_shell "gpio4" "^gpio4 ok=1 version=140 pin=42 rise="
# V141: PWM1 channel-1 program. Fail-closed readback. No EL0.
probe_shell "pwm4" "^pwm4 ok=1 version=141 pwm1=1 en="
# probe shell: req-status
probe_shell "req id=25 cmd=status" "^resp id=25 ok=1 cmd=status end"
# probe shell: canceltest
Expand Down
2 changes: 2 additions & 0 deletions scripts/netboot/netboot-doctor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,8 @@ while [ "$SECONDS" -lt "$deadline" ]; do
&& printf '%s' "$serial_delta" | grep -q "pwm3 ok=1 version=139 pin=12 alt=" \
&& printf '%s' "$serial_delta" | grep -q "runtime v140: GPIO rising-edge detect" \
&& printf '%s' "$serial_delta" | grep -q "gpio4 ok=1 version=140 pin=42 rise=" \
&& printf '%s' "$serial_delta" | grep -q "runtime v141: PWM1 program" \
&& printf '%s' "$serial_delta" | grep -q "pwm4 ok=1 version=141 pwm1=1 en=" \
&& printf '%s' "$serial_delta" | grep -q "vmmcheck ok=1" \
&& printf '%s' "$serial_delta" | grep -q "asplit ok=1 version=46" \
&& printf '%s' "$serial_delta" | grep -q "el0 ok=1 version=47" \
Expand Down
77 changes: 77 additions & 0 deletions tests/test_runtime_pwm4_v141_contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""EPIC G V141: PWM1 channel-1 program after GENET. Fail-closed readback. No EL0."""

import pathlib


ROOT = pathlib.Path(__file__).resolve().parents[1]


def read_repo(path: str) -> str:
return (ROOT / path).read_text()


def test_pwm4_pwm1_program_fail_closed_without_el0() -> None:
load = read_repo("Sources/Support/kernel_pwm4.c")
pwm2 = read_repo("Sources/Support/kernel_pwm2.c")
pwm3 = read_repo("Sources/Support/kernel_pwm3.c")
support = read_repo("Sources/Support/include/Support.h")
app = read_repo("Sources/Application/Application.swift")
shell = read_repo("Sources/Application/UARTShell.swift")
iterate = read_repo("scripts/netboot/net-iterate.sh")
doctor = read_repo("scripts/netboot/netboot-doctor.sh")
scheduler = read_repo("Sources/Support/kernel_scheduler.c")
roadmap = read_repo("docs/ROADMAP.md")

assert "0xFE20C800" in load
assert "PWM_RNG1" in load
assert "PWM_DAT1" in load
assert "PWM_PWEN1" in load
assert "kernel_pwm3_selftest" in load
assert "int kernel_pwm4_selftest(void);" in support
assert "unsigned int kernel_pwm4_pwm1(void);" in support
assert "unsigned int kernel_pwm4_en(void);" in support
assert "unsigned int kernel_pwm4_restore(void);" in support
assert 'uartPuts("runtime v141: PWM1 program\\n")' in app
assert 'uartPuts("pwm4 ok=")' in app
assert "kernel_event_emit(KERNEL_EVENT_KIND_SELFTEST, 141" not in app
assert "func printPwm4()" in shell
assert 'shellBufferSliceEquals(commandStart, commandLen, "pwm4")' in shell
assert ",gpio4,pwm4" in shell
assert 'grep -qa "pwm4 ok=1 version=141 pwm1=1 en="' in iterate
assert 'probe_shell "pwm4" "^pwm4 ok=1 version=141 pwm1=1 en="' in iterate
assert 'grep -q "pwm4 ok=1 version=141 pwm1=1 en="' in doctor
assert "V141 PWM1 channel-1 program" in roadmap
assert "kernel_pwm4_selftest" not in scheduler
assert "alloc_dma" not in load
assert "kernel_event_emit" not in load
assert "kernel_enter_el0_and_wait" not in load
assert "0xbf000002" in load
assert "watchdog_reset_now" not in load
# Second PWM block, not another PWM0 / pin-mux / edge / SPI-TA clone.
assert "0xFE20C000" not in load
assert "GPREN" not in load
assert "GPEDS" not in load
assert "GPFSEL" not in load
assert "ALT0" not in load
assert "SPI_CS_TA" not in load
assert "0xFE204000" not in load
assert "PUP_PDN" not in load
assert "RBUF_64B_EN" not in load
assert "DMA_TX_DO_CSUM" not in load
assert "CMD_LCL_LOOP_EN" not in load
assert "EXT_RGMII_OOB_CTRL" not in load
assert "0xFE20C800" not in pwm2
assert "PWM1_BASE" not in pwm3
assert "ping -c 2" in iterate
assert "SOCK_STREAM" in iterate
assert "sched12" in iterate


def test_no_boot_el0_enter_after_genet12() -> None:
"""sys_socket after GENET DMA I-aborted; do not ship a second boot EL0 enter."""
app = read_repo("Sources/Application/Application.swift")
after = app.split("kernel_genet12_selftest", 1)[1]
assert "kernel_enter_el0_and_wait" not in after
assert "kernel_socket_selftest" not in after
assert "kernel_pwm4_selftest" in after
assert "kernel_spi3_selftest" not in after