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

// Runtime V144: GPCLK0 clock enable. UART token only.
// Fail-closed CM_GP0 OSC+ENAB + leftover restore.
// No pin-mux. No output claim. No UART2. No BSC0. No SPI0 TA.
// No boot event emit. No EL0 enter after GENET.
uartPuts("runtime v144: GPCLK probe\n")
let gpclk_ok_boot = kernel_gpclk_selftest()
uartPuts("gpclk ok=")
uartPutDec(UInt64(gpclk_ok_boot))
uartPuts(" version=144 clk=")
uartPutDec(UInt64(kernel_gpclk_clk()))
uartPuts(" restore=")
uartPutDec(UInt64(kernel_gpclk_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
15 changes: 14 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,pcm,auxspi1"
"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,auxspi1,gpclk"

func printShellReady() {
uartPuts("shell ready \(SHELL_COMMAND_LIST)\n")
Expand Down Expand Up @@ -3138,6 +3138,17 @@ func printAuxspi1() {
uartPuts("\n")
}

func printGpclk() {
_ = kernel_gpclk_selftest()
uartPuts("gpclk ok=")
uartPutDec(UInt64(kernel_gpclk_ok()))
uartPuts(" version=144 clk=")
uartPutDec(UInt64(kernel_gpclk_clk()))
uartPuts(" restore=")
uartPutDec(UInt64(kernel_gpclk_restore()))
uartPuts("\n")
}

func printPoolName(_ pool: UInt32) {
var i: UInt32 = 0
let n = kernel_pool_name_len(pool)
Expand Down Expand Up @@ -4164,6 +4175,8 @@ func dispatchShellCommand(_ commandStart: UInt32, _ commandLen: UInt32, _ reques
printPcm()
} else if shellBufferSliceEquals(commandStart, commandLen, "auxspi1") {
printAuxspi1()
} else if shellBufferSliceEquals(commandStart, commandLen, "gpclk") {
printGpclk()
} else if shellBufferSliceEquals(commandStart, commandLen, "pools") {
printPools()
} else if shellBufferSliceEquals(commandStart, commandLen, "poolcheck") {
Expand Down
6 changes: 6 additions & 0 deletions Sources/Support/include/Support.h
Original file line number Diff line number Diff line change
Expand Up @@ -1653,6 +1653,12 @@ int kernel_auxspi1_ok(void);
unsigned int kernel_auxspi1_en(void);
unsigned int kernel_auxspi1_restore(void);

// V144: GPCLK0 enable after GENET. Fail-closed CM_GP0 readback. No EL0.
int kernel_gpclk_selftest(void);
int kernel_gpclk_ok(void);
unsigned int kernel_gpclk_clk(void);
unsigned int kernel_gpclk_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
88 changes: 88 additions & 0 deletions Sources/Support/kernel_gpclk.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Runtime V144: BCM2711 GPCLK0 clock enable after GENET.
// New unused CM block (CM_GP0 0xFE101070). Fail-closed OSC+ENAB
// write+readback + leftover restore. No pin-mux. No output claim.
// UART2 after GENET hung AXI/UART — do not retry UART2-5.
// Do not probe BSC0 after GENET (AXI hang, UART dies).
// Do not assert SPI0 TA after GENET (hung boot).
// No EL0 enter (I-abort esr=0xbf000002 elr=0x100002000 after GENET DMA).
// No boot event emit.

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

#define CM_GP0CTL 0xFE101070UL
#define CM_GP0DIV 0xFE101074UL
#define CM32(addr) (*(volatile uint32_t *)(addr))

#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 GPCLK_DIVI 50U
#define GPCLK_WAIT_TICKS 108000UL /* ~2ms @ 54MHz CNTPCT */

static int gpclk_probed;
static int gpclk_ok_val;
static unsigned int gpclk_clk_val;
static unsigned int gpclk_restore_val;

static int gpclk_wait_busy(unsigned int want) {
unsigned long start = read_cntpct();
while ((read_cntpct() - start) < GPCLK_WAIT_TICKS) {
unsigned int ctl = CM32(CM_GP0CTL);
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_gpclk_selftest(void) {
if (gpclk_probed) return gpclk_ok_val;
gpclk_probed = 1;
gpclk_ok_val = 0;
gpclk_clk_val = 0;
gpclk_restore_val = 0;

unsigned int saved_cm_ctl = CM32(CM_GP0CTL);
unsigned int saved_cm_div = CM32(CM_GP0DIV);
if (saved_cm_ctl == 0xFFFFFFFFU || saved_cm_div == 0xFFFFFFFFU) {
return 0;
}

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

CM32(CM_GP0DIV) = CM_PASSWD | (GPCLK_DIVI << 12);
CM32(CM_GP0CTL) = CM_PASSWD | CM_ENAB | CM_SRC_OSC;
if (gpclk_wait_busy(1) != 0) gpclk_clk_val = 1;

CM32(CM_GP0CTL) = CM_PASSWD | (saved_cm_ctl & 0x0FU);
(void)gpclk_wait_busy(0);
CM32(CM_GP0DIV) = CM_PASSWD | (saved_cm_div & 0x00FFFFFFU);
CM32(CM_GP0CTL) = CM_PASSWD | (saved_cm_ctl & 0xFFU);

if ((CM32(CM_GP0CTL) & CM_PROG) == (saved_cm_ctl & CM_PROG) &&
(CM32(CM_GP0DIV) & 0x00FFFFFFU) == (saved_cm_div & 0x00FFFFFFU)) {
gpclk_restore_val = 1;
}

if (gpclk_clk_val == 1U && gpclk_restore_val == 1U) {
gpclk_ok_val = 1;
return 1;
}
return 0;
}

int kernel_gpclk_ok(void) { return gpclk_ok_val; }
unsigned int kernel_gpclk_clk(void) { return gpclk_clk_val; }
unsigned int kernel_gpclk_restore(void) { return gpclk_restore_val; }
1 change: 1 addition & 0 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ Turn the static identity-map MMU into a real virtual-memory system and run code
- [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] V143 AUX SPI1 enable after GENET (`auxspi1 ok=1 version=143 en=1 restore=1`). Fail-closed `AUXENB` SPI1 bit + leftover restore; no pin-mux; no transfer; no mini-UART change. BSC0 `0xFE205000` after GENET hung AXI/UART — do not retry. No EL0.
- [x] V144 GPCLK0 enable after GENET (`gpclk ok=1 version=144 clk=1 restore=1`). Fail-closed `CM_GP0CTL` OSC+ENAB write+readback + leftover restore; no pin-mux; no output claim. UART2 `0xFE201400` after GENET hung AXI/UART — do not retry UART2–5. 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 @@ -501,6 +501,8 @@ PY
&& printf '%s' "$serial_delta" | grep -qa "pcm ok=1 version=142 clk=1 en=" \
&& printf '%s' "$serial_delta" | grep -qa "runtime v143: AUX SPI1 probe" \
&& printf '%s' "$serial_delta" | grep -qa "auxspi1 ok=1 version=143 en=" \
&& printf '%s' "$serial_delta" | grep -qa "runtime v144: GPCLK probe" \
&& printf '%s' "$serial_delta" | grep -qa "gpclk ok=1 version=144 clk=" \
&& 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 @@ -830,6 +832,8 @@ PY
probe_shell "pcm" "^pcm ok=1 version=142 clk=1 en="
# V143: AUX SPI1 enable. Fail-closed AUXENB readback. No EL0.
probe_shell "auxspi1" "^auxspi1 ok=1 version=143 en="
# V144: GPCLK0 clock enable. Fail-closed CM_GP0 readback. No EL0.
probe_shell "gpclk" "^gpclk ok=1 version=144 clk="
# 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 @@ -361,6 +361,8 @@ while [ "$SECONDS" -lt "$deadline" ]; do
&& printf '%s' "$serial_delta" | grep -q "pcm ok=1 version=142 clk=1 en=" \
&& printf '%s' "$serial_delta" | grep -q "runtime v143: AUX SPI1 probe" \
&& printf '%s' "$serial_delta" | grep -q "auxspi1 ok=1 version=143 en=" \
&& printf '%s' "$serial_delta" | grep -q "runtime v144: GPCLK probe" \
&& printf '%s' "$serial_delta" | grep -q "gpclk ok=1 version=144 clk=" \
&& 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
89 changes: 89 additions & 0 deletions tests/test_runtime_gpclk_v144_contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"""EPIC G V144: GPCLK0 enable after GENET. Fail-closed CM_GP0 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_gpclk_enable_fail_closed_without_el0() -> None:
load = read_repo("Sources/Support/kernel_gpclk.c")
aux = read_repo("Sources/Support/kernel_auxspi1.c")
pcm = read_repo("Sources/Support/kernel_pcm.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 "0xFE101070" in load
assert "0xFE101074" in load
assert "CM_GP0CTL" in load
assert "CM_ENAB" in load
assert "int kernel_gpclk_selftest(void);" in support
assert "unsigned int kernel_gpclk_clk(void);" in support
assert "unsigned int kernel_gpclk_restore(void);" in support
assert 'uartPuts("runtime v144: GPCLK probe\\n")' in app
assert 'uartPuts("gpclk ok=")' in app
assert "kernel_event_emit(KERNEL_EVENT_KIND_SELFTEST, 144" not in app
assert "func printGpclk()" in shell
assert 'shellBufferSliceEquals(commandStart, commandLen, "gpclk")' in shell
assert ",auxspi1,gpclk" in shell
assert 'grep -qa "gpclk ok=1 version=144 clk="' in iterate
assert 'probe_shell "gpclk" "^gpclk ok=1 version=144 clk="' in iterate
assert 'grep -q "gpclk ok=1 version=144 clk="' in doctor
assert "V144 GPCLK0 enable" in roadmap
assert "kernel_gpclk_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 GPCLK0 CM block. Do not retry UART2-5 / BSC0 / SPI0 TA.
assert "0xFE201400" not in load
assert "0xFE201000" not in load
assert "0xFE205000" not in load
assert "0xFE804000" not in load
assert "0xFE203000" not in load
assert "0xFE20C000" not in load
assert "0xFE20C800" not in load
assert "0xFE215000" not in load
assert "UARTCR" not in load
assert "PCM_CS" not in load
assert "AUXENB" 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 "RBUF_HFB_EN" not in load
assert "0xFE101070" not in aux
assert "0xFE101070" not in pcm
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_gpclk_selftest" in after
assert "kernel_uart2_selftest" not in after
assert "kernel_bsc0_selftest" not in after
assert "kernel_spi3_selftest" not in after