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 @@ -1623,6 +1623,21 @@ struct Application {
uartPutDec(UInt64(kernel_genet34_restore()))
uartPuts("\n")

// Runtime V139: PWM GPIO12 ALT0 pin-mux. UART token only.
// Fail-closed FSEL readback. No output claim. No boot event emit.
// No EL0 enter after GENET.
uartPuts("runtime v139: PWM pin-mux\n")
let pwm3_ok_boot = kernel_pwm3_selftest()
uartPuts("pwm3 ok=")
uartPutDec(UInt64(pwm3_ok_boot))
uartPuts(" version=139 pin=")
uartPutDec(UInt64(kernel_pwm3_pin()))
uartPuts(" alt=")
uartPutDec(UInt64(kernel_pwm3_alt()))
uartPuts(" restore=")
uartPutDec(UInt64(kernel_pwm3_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"
"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"

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

func printPwm3() {
_ = kernel_pwm3_selftest()
uartPuts("pwm3 ok=")
uartPutDec(UInt64(kernel_pwm3_ok()))
uartPuts(" version=139 pin=")
uartPutDec(UInt64(kernel_pwm3_pin()))
uartPuts(" alt=")
uartPutDec(UInt64(kernel_pwm3_alt()))
uartPuts(" restore=")
uartPutDec(UInt64(kernel_pwm3_restore()))
uartPuts("\n")
}

func printPoolName(_ pool: UInt32) {
var i: UInt32 = 0
let n = kernel_pool_name_len(pool)
Expand Down Expand Up @@ -4091,6 +4104,8 @@ func dispatchShellCommand(_ commandStart: UInt32, _ commandLen: UInt32, _ reques
printGenet33()
} else if shellBufferSliceEquals(commandStart, commandLen, "genet34") {
printGenet34()
} else if shellBufferSliceEquals(commandStart, commandLen, "pwm3") {
printPwm3()
} 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 @@ -1605,6 +1605,13 @@ int kernel_pwm2_ok(void);
unsigned int kernel_pwm2_clk(void);
unsigned int kernel_pwm2_en(void);

// V139: PWM GPIO12 ALT0 pin-mux after GENET. Fail-closed FSEL. No EL0.
int kernel_pwm3_selftest(void);
int kernel_pwm3_ok(void);
unsigned int kernel_pwm3_pin(void);
unsigned int kernel_pwm3_alt(void);
unsigned int kernel_pwm3_restore(void);

// V82: one bounded BSC1 write to a vacant address. Honest nack=1. No boot emit.
int kernel_i2c2_selftest(void);
int kernel_i2c2_ok(void);
Expand Down
83 changes: 83 additions & 0 deletions Sources/Support/kernel_pwm3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Runtime V139: BCM2711 PWM GPIO12 ALT0 pin-mux after GENET.
// Fail-closed GPFSEL1 readback of ALT0, then leftover restore.
// UART GPIO14/15 FSEL bits must stay unchanged. No PUP/PDN writes
// (do not touch REG0). No PWM CTL/DAT (V93 already poked those).
// No output claim. No EL0 enter (I-abort esr=0xbf000002 elr=0x100002000
// after GENET DMA). No boot event emit.

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

#define GPIO_BASE 0xFE200000UL
#define G32(off) (*(volatile uint32_t *)(GPIO_BASE + (unsigned long)(off)))

#define GPFSEL1 0x04U /* GPIO10..19 */

#define PWM3_PIN 12U
#define PWM3_FSEL_SHIFT 6U /* (12-10)*3 */
#define FSEL_MASK 7U
#define FSEL_INPUT 0U
#define FSEL_ALT0 4U
#define UART_FSEL_MASK (0x3FU << 12) /* GPIO14+15 in GPFSEL1 */

static int pwm3_probed;
static int pwm3_ok_val;
static unsigned int pwm3_pin_val;
static unsigned int pwm3_alt_val;
static unsigned int pwm3_restore_val;

int kernel_pwm3_selftest(void) {
if (pwm3_probed) return pwm3_ok_val;
pwm3_probed = 1;
pwm3_ok_val = 0;
pwm3_pin_val = PWM3_PIN;
pwm3_alt_val = 0;
pwm3_restore_val = 0;

if (kernel_pwm2_selftest() == 0) return 0;

unsigned int saved = G32(GPFSEL1);
if (saved == 0xFFFFFFFFU) return 0;

unsigned int uart_bits = saved & UART_FSEL_MASK;
unsigned int fsel12 = (saved >> PWM3_FSEL_SHIFT) & FSEL_MASK;

/* Non-vacuous: if leftover is already ALT0, prove the field can move. */
if (fsel12 == FSEL_ALT0) {
unsigned int tmp = saved & ~(FSEL_MASK << PWM3_FSEL_SHIFT);
tmp |= (FSEL_INPUT << PWM3_FSEL_SHIFT);
G32(GPFSEL1) = tmp;
unsigned int rb = G32(GPFSEL1);
if (((rb >> PWM3_FSEL_SHIFT) & FSEL_MASK) != FSEL_INPUT ||
(rb & UART_FSEL_MASK) != uart_bits) {
G32(GPFSEL1) = saved;
return 0;
}
}

unsigned int cur = G32(GPFSEL1);
unsigned int next = cur;
next &= ~(FSEL_MASK << PWM3_FSEL_SHIFT);
next |= (FSEL_ALT0 << PWM3_FSEL_SHIFT);
G32(GPFSEL1) = next;

unsigned int muxed = G32(GPFSEL1);
if (((muxed >> PWM3_FSEL_SHIFT) & FSEL_MASK) == FSEL_ALT0 &&
(muxed & UART_FSEL_MASK) == uart_bits) {
pwm3_alt_val = 1;
}

G32(GPFSEL1) = saved;
if (G32(GPFSEL1) == saved) pwm3_restore_val = 1;

if (pwm3_alt_val == 1U && pwm3_restore_val == 1U) {
pwm3_ok_val = 1;
return 1;
}
return 0;
}

int kernel_pwm3_ok(void) { return pwm3_ok_val; }
unsigned int kernel_pwm3_pin(void) { return pwm3_pin_val; }
unsigned int kernel_pwm3_alt(void) { return pwm3_alt_val; }
unsigned int kernel_pwm3_restore(void) { return pwm3_restore_val; }
1 change: 1 addition & 0 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ Turn the static identity-map MMU into a real virtual-memory system and run code
- [x] V91 GPIO42 output + GPLEV readback after GENET (`gpio2 ok=1 version=91 pin=42 set=1 clr=1`). Kernel ACT LED; restore FSEL; no jumper; no EL0.
- [x] V92 system timer C1 match after GENET (`stimer2 ok=1 version=92 chan=1 match=1`). ARM C1 only; no C0/C2 writes; park after match; no EL0.
- [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] 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 @@ -491,6 +491,8 @@ PY
&& printf '%s' "$serial_delta" | grep -qa "genet33 ok=1 version=137 rflush=" \
&& printf '%s' "$serial_delta" | grep -qa "runtime v138: GENET EXT OOB" \
&& printf '%s' "$serial_delta" | grep -qa "genet34 ok=1 version=138 oob=" \
&& printf '%s' "$serial_delta" | grep -qa "runtime v139: PWM pin-mux" \
&& printf '%s' "$serial_delta" | grep -qa "pwm3 ok=1 version=139 pin=12 alt=" \
&& 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 @@ -810,6 +812,8 @@ PY
probe_shell "genet33" "^genet33 ok=1 version=137 rflush="
# V138: EXT RGMII OOB_DISABLE writeback. No DMA. No EL0.
probe_shell "genet34" "^genet34 ok=1 version=138 oob="
# V139: PWM GPIO12 ALT0 pin-mux. Fail-closed FSEL. No EL0.
probe_shell "pwm3" "^pwm3 ok=1 version=139 pin=12 alt="
# 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 @@ -351,6 +351,8 @@ while [ "$SECONDS" -lt "$deadline" ]; do
&& printf '%s' "$serial_delta" | grep -q "genet33 ok=1 version=137 rflush=" \
&& printf '%s' "$serial_delta" | grep -q "runtime v138: GENET EXT OOB" \
&& printf '%s' "$serial_delta" | grep -q "genet34 ok=1 version=138 oob=" \
&& printf '%s' "$serial_delta" | grep -q "runtime v139: PWM pin-mux" \
&& printf '%s' "$serial_delta" | grep -q "pwm3 ok=1 version=139 pin=12 alt=" \
&& 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
76 changes: 76 additions & 0 deletions tests/test_runtime_pwm3_v139_contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"""EPIC G V139: PWM GPIO12 ALT0 pin-mux after GENET. Fail-closed FSEL. No EL0."""

import pathlib


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


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


def test_pwm3_pin_mux_fail_closed_without_el0() -> None:
load = read_repo("Sources/Support/kernel_pwm3.c")
pwm_ro = read_repo("Sources/Support/kernel_pwm.c")
pwm2 = read_repo("Sources/Support/kernel_pwm2.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 "0xFE200000" in load
assert "GPFSEL1" in load
assert "12U" in load or "GPIO12" in load
assert "ALT0" in load
assert "kernel_pwm2_selftest" in load
assert "int kernel_pwm3_selftest(void);" in support
assert "unsigned int kernel_pwm3_pin(void);" in support
assert "unsigned int kernel_pwm3_alt(void);" in support
assert "unsigned int kernel_pwm3_restore(void);" in support
assert 'uartPuts("runtime v139: PWM pin-mux\\n")' in app
assert 'uartPuts("pwm3 ok=")' in app
assert "kernel_event_emit(KERNEL_EVENT_KIND_SELFTEST, 139" not in app
assert "func printPwm3()" in shell
assert 'shellBufferSliceEquals(commandStart, commandLen, "pwm3")' in shell
assert ",genet34,pwm3" in shell
assert 'grep -qa "pwm3 ok=1 version=139 pin=12 alt="' in iterate
assert 'probe_shell "pwm3" "^pwm3 ok=1 version=139 pin=12 alt="' in iterate
assert 'grep -q "pwm3 ok=1 version=139 pin=12 alt="' in doctor
assert "V139 PWM GPIO12 ALT0 pin-mux" in roadmap
assert "kernel_pwm3_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
# Fail-closed FSEL readback; no output claim; UART 14/15 pulls untouched.
assert "GPFSEL1" in load
assert "PUP_PDN" not in load
assert "0xE4" not in load
assert "GPSET" not in load
assert "GPCLR" not in load
assert "PWM_CTL" not in load
assert "PWM_DAT1" not in load
assert "0xFE20C800" 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 "G32(PWM0_BASE, PWM_CTL) =" not in pwm_ro
assert "GPFSEL" not in pwm2
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_pwm3_selftest" in after