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
16 changes: 16 additions & 0 deletions Sources/Application/Application.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1668,6 +1668,22 @@ struct Application {
uartPutDec(UInt64(kernel_pwm4_restore()))
uartPuts("\n")

// Runtime V142: PCM/I2S clock + CS enable. UART token only.
// Fail-closed CM_PCM + PCM_CS EN readback + leftover restore.
// No pin-mux. No FIFO. No output claim. No boot event emit.
// No EL0 enter after GENET.
uartPuts("runtime v142: PCM enable\n")
let pcm_ok_boot = kernel_pcm_selftest()
uartPuts("pcm ok=")
uartPutDec(UInt64(pcm_ok_boot))
uartPuts(" version=142 clk=")
uartPutDec(UInt64(kernel_pcm_clk()))
uartPuts(" en=")
uartPutDec(UInt64(kernel_pcm_en()))
uartPuts(" restore=")
uartPutDec(UInt64(kernel_pcm_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,pwm4"
"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,pcm"

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

func printPcm() {
_ = kernel_pcm_selftest()
uartPuts("pcm ok=")
uartPutDec(UInt64(kernel_pcm_ok()))
uartPuts(" version=142 clk=")
uartPutDec(UInt64(kernel_pcm_clk()))
uartPuts(" en=")
uartPutDec(UInt64(kernel_pcm_en()))
uartPuts(" restore=")
uartPutDec(UInt64(kernel_pcm_restore()))
uartPuts("\n")
}

func printPoolName(_ pool: UInt32) {
var i: UInt32 = 0
let n = kernel_pool_name_len(pool)
Expand Down Expand Up @@ -4136,6 +4149,8 @@ func dispatchShellCommand(_ commandStart: UInt32, _ commandLen: UInt32, _ reques
printGpio4()
} else if shellBufferSliceEquals(commandStart, commandLen, "pwm4") {
printPwm4()
} else if shellBufferSliceEquals(commandStart, commandLen, "pcm") {
printPcm()
} 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 @@ -1640,6 +1640,13 @@ unsigned int kernel_pwm4_pwm1(void);
unsigned int kernel_pwm4_en(void);
unsigned int kernel_pwm4_restore(void);

// V142: PCM/I2S clock + CS enable after GENET. Fail-closed readback. No EL0.
int kernel_pcm_selftest(void);
int kernel_pcm_ok(void);
unsigned int kernel_pcm_clk(void);
unsigned int kernel_pcm_en(void);
unsigned int kernel_pcm_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
114 changes: 114 additions & 0 deletions Sources/Support/kernel_pcm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Runtime V142: BCM2711 PCM/I2S clock + CS enable after GENET.
// New unused block (0xFE203000). Fail-closed CM_PCM OSC + PCM_CS EN
// write+readback + leftover restore. TXON/RXON/DMAEN stay clear.
// No pin-mux. No FIFO. No output/audio claim.
// Does not write PWM or GPIO event-detect registers.
// No EL0 enter (I-abort esr=0xbf000002 elr=0x100002000 after GENET DMA).
// No boot event emit.

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

#define PCM_BASE 0xFE203000UL
#define CM_PCMCTL 0xFE101098UL
#define CM_PCMDIV 0xFE10109CUL

#define G32(off) (*(volatile uint32_t *)(PCM_BASE + (unsigned long)(off)))
#define CM32(addr) (*(volatile uint32_t *)(addr))

#define PCM_CS 0x00U

#define PCM_CS_EN (1U << 0)
#define PCM_CS_RXON (1U << 1)
#define PCM_CS_TXON (1U << 2)
#define PCM_CS_DMAEN (1U << 9)
/* Programmable leftover: EN/RXON/TXON/DMAEN. RXD/TXW/SYNC status is live. */
#define PCM_CS_PROG (PCM_CS_EN | PCM_CS_RXON | PCM_CS_TXON | PCM_CS_DMAEN)

#define CM_PASSWD 0x5A000000U
#define CM_SRC_OSC 1U
#define CM_ENAB (1U << 4)
#define CM_BUSY (1U << 7)
#define CM_SRC_MASK 0x0FU
#define CM_PROG (CM_ENAB | CM_SRC_MASK)

#define PCM_DIVI 50U
#define PCM_WAIT_TICKS 108000UL /* ~2ms @ 54MHz CNTPCT */

static int pcm_probed;
static int pcm_ok_val;
static unsigned int pcm_clk_val;
static unsigned int pcm_en_val;
static unsigned int pcm_restore_val;

static int pcm_wait_busy(unsigned int want) {
unsigned long start = read_cntpct();
while ((read_cntpct() - start) < PCM_WAIT_TICKS) {
unsigned int ctl = CM32(CM_PCMCTL);
if (ctl == 0xFFFFFFFFU) return 0;
if (want) {
if ((ctl & CM_BUSY) != 0U) return 1;
} else if ((ctl & CM_BUSY) == 0U) {
return 1;
}
}
return 0;
}

int kernel_pcm_selftest(void) {
if (pcm_probed) return pcm_ok_val;
pcm_probed = 1;
pcm_ok_val = 0;
pcm_clk_val = 0;
pcm_en_val = 0;
pcm_restore_val = 0;

unsigned int saved_cm_ctl = CM32(CM_PCMCTL);
unsigned int saved_cm_div = CM32(CM_PCMDIV);
unsigned int saved_cs = G32(PCM_CS);
if (saved_cm_ctl == 0xFFFFFFFFU || saved_cm_div == 0xFFFFFFFFU || saved_cs == 0xFFFFFFFFU) {
return 0;
}

CM32(CM_PCMCTL) = CM_PASSWD | (saved_cm_ctl & 0x0FU);
if (pcm_wait_busy(0) == 0) {
CM32(CM_PCMCTL) = CM_PASSWD | (saved_cm_ctl & 0xFFU);
return 0;
}

CM32(CM_PCMDIV) = CM_PASSWD | (PCM_DIVI << 12);
CM32(CM_PCMCTL) = CM_PASSWD | CM_ENAB | CM_SRC_OSC;
if (pcm_wait_busy(1) != 0) pcm_clk_val = 1;

if (pcm_clk_val == 1U) {
unsigned int want = (saved_cs | PCM_CS_EN) & ~(PCM_CS_RXON | PCM_CS_TXON | PCM_CS_DMAEN);
G32(PCM_CS) = want;
unsigned int cs = G32(PCM_CS);
if ((cs & PCM_CS_EN) != 0U && (cs & (PCM_CS_RXON | PCM_CS_TXON | PCM_CS_DMAEN)) == 0U) {
pcm_en_val = 1;
}
}

G32(PCM_CS) = saved_cs;
CM32(CM_PCMCTL) = CM_PASSWD | (saved_cm_ctl & 0x0FU);
(void)pcm_wait_busy(0);
CM32(CM_PCMDIV) = CM_PASSWD | (saved_cm_div & 0x00FFFFFFU);
CM32(CM_PCMCTL) = CM_PASSWD | (saved_cm_ctl & 0xFFU);

if ((G32(PCM_CS) & PCM_CS_PROG) == (saved_cs & PCM_CS_PROG) &&
(CM32(CM_PCMCTL) & CM_PROG) == (saved_cm_ctl & CM_PROG) &&
(CM32(CM_PCMDIV) & 0x00FFFFFFU) == (saved_cm_div & 0x00FFFFFFU)) {
pcm_restore_val = 1;
}

if (pcm_clk_val == 1U && pcm_en_val == 1U && pcm_restore_val == 1U) {
pcm_ok_val = 1;
return 1;
}
return 0;
}

int kernel_pcm_ok(void) { return pcm_ok_val; }
unsigned int kernel_pcm_clk(void) { return pcm_clk_val; }
unsigned int kernel_pcm_en(void) { return pcm_en_val; }
unsigned int kernel_pcm_restore(void) { return pcm_restore_val; }
1 change: 1 addition & 0 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ Turn the static identity-map MMU into a real virtual-memory system and run code
- [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] V142 PCM/I2S enable after GENET (`pcm ok=1 version=142 clk=1 en=1 restore=1`). Fail-closed `CM_PCM` OSC + `PCM_CS` EN write+readback + leftover restore; no pin-mux; no TX/RX/FIFO; no output/audio 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 @@ -497,6 +497,8 @@ PY
&& 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 "runtime v142: PCM enable" \
&& printf '%s' "$serial_delta" | grep -qa "pcm ok=1 version=142 clk=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 @@ -822,6 +824,8 @@ PY
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="
# V142: PCM/I2S clock + CS enable. Fail-closed readback. No EL0.
probe_shell "pcm" "^pcm ok=1 version=142 clk=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 @@ -357,6 +357,8 @@ while [ "$SECONDS" -lt "$deadline" ]; do
&& 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 "runtime v142: PCM enable" \
&& printf '%s' "$serial_delta" | grep -q "pcm ok=1 version=142 clk=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
81 changes: 81 additions & 0 deletions tests/test_runtime_pcm_v142_contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"""EPIC G V142: PCM/I2S clock+enable 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_pcm_enable_fail_closed_without_el0() -> None:
load = read_repo("Sources/Support/kernel_pcm.c")
pwm2 = read_repo("Sources/Support/kernel_pwm2.c")
pwm4 = read_repo("Sources/Support/kernel_pwm4.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 "0xFE203000" in load
assert "0xFE101098" in load
assert "PCM_CS" in load
assert "PCM_CS_EN" in load
assert "CM_PCMCTL" in load
assert "int kernel_pcm_selftest(void);" in support
assert "unsigned int kernel_pcm_clk(void);" in support
assert "unsigned int kernel_pcm_en(void);" in support
assert "unsigned int kernel_pcm_restore(void);" in support
assert 'uartPuts("runtime v142: PCM enable\\n")' in app
assert 'uartPuts("pcm ok=")' in app
assert "kernel_event_emit(KERNEL_EVENT_KIND_SELFTEST, 142" not in app
assert "func printPcm()" in shell
assert 'shellBufferSliceEquals(commandStart, commandLen, "pcm")' in shell
assert ",pwm4,pcm" in shell
assert 'grep -qa "pcm ok=1 version=142 clk=1 en="' in iterate
assert 'probe_shell "pcm" "^pcm ok=1 version=142 clk=1 en="' in iterate
assert 'grep -q "pcm ok=1 version=142 clk=1 en="' in doctor
assert "V142 PCM/I2S enable" in roadmap
assert "kernel_pcm_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
# New unused PCM block, not a PWM-DAT / edge / ALT0 / SPI0-TA clone.
assert "0xFE20C000" not in load
assert "0xFE20C800" not in load
assert "PWM_DAT1" 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 "PCM_CS_TXON" in load
assert "PCM_CS_RXON" in load
assert "0xFE203000" not in pwm2
assert "0xFE203000" not in pwm4
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_pcm_selftest" in after
assert "kernel_spi3_selftest" not in after