Repository navigation
ci(baremetal): Cortex-M7 smoke and size budget gate (#447 Phase 5) - #455
Merged
Merged
Conversation
- .github/workflows/baremetal.yml (ubuntu-24.04: gcc-arm-none-eabi 13.2, newlib 4.4, qemu-user 8.2) runs `make baremetal-size-gate` on every PR and push: the three smoke firmware (in-memory dispatch with and without an RTC, and the lwIP adapter over loopback) under qemu-arm, then the budget check. ELFs, maps and logs are uploaded as an artifact. - baremetal-smoke keeps each run's output in .baremetal-build/<fw>.log and still fails on the first failing firmware. - scripts/ci/baremetal_size_gate.py measures flash (code, rodata, exidx, init arrays, .data load image), static RAM (.data + .bss, not the linker heap region) and the heap/stack high-water marks the firmware report, against scripts/ci/baremetal-budget.txt. A budgeted value the run did not report fails rather than passing. - Budgets sit about 10% above values measured with both gcc 13.2 (the CI toolchain) and 14.2, which agree within 0.6%.
gg582
added a commit
that referenced
this pull request
Oct 27, 2026
…458) * ci(baremetal): Cortex-M7 smoke and size budget gate (#447 Phase 5) (#455) - .github/workflows/baremetal.yml (ubuntu-24.04: gcc-arm-none-eabi 13.2, newlib 4.4, qemu-user 8.2) runs `make baremetal-size-gate` on every PR and push: the three smoke firmware (in-memory dispatch with and without an RTC, and the lwIP adapter over loopback) under qemu-arm, then the budget check. ELFs, maps and logs are uploaded as an artifact. - baremetal-smoke keeps each run's output in .baremetal-build/<fw>.log and still fails on the first failing firmware. - scripts/ci/baremetal_size_gate.py measures flash (code, rodata, exidx, init arrays, .data load image), static RAM (.data + .bss, not the linker heap region) and the heap/stack high-water marks the firmware report, against scripts/ci/baremetal-budget.txt. A budgeted value the run did not report fails rather than passing. - Budgets sit about 10% above values measured with both gcc 13.2 (the CI toolchain) and 14.2, which agree within 0.6%. (cherry picked from commit 35ed9a0) * feat(port): HTTPS over the lwIP adapter with mbedTLS 3.6 (#447 Phase 4) (#457) lwIP's altcp_tls_mbedtls only supports mbedTLS 2.x (in 2.2.1 and on master), so the adapter drives mbedTLS 3.6 itself. - cwist_lwip_tls_create()/destroy() build a server context (certificate chain, key, CTR_DRBG, ssl config); cwist_lwip_config.tls turns HTTPS on for a listener. TLS code compiles with -DCWIST_LWIP_TLS; without it, create returns NULL and a listener asked for TLS fails instead of serving plaintext. - The DRBG is seeded only from cwist_port_entropy(): a failing hook makes create fail, and a failing reseed fails the handshake. - Per connection: an mbedtls_ssl_context with BIOs over the pcb. Received ciphertext queues (bounded, refused back to lwIP when full) and is decrypted into the same rx/framing path as plaintext; responses go through mbedtls_ssl_write and are copied into lwIP, so tx is freed as soon as mbedTLS has taken it. The next pipelined request is picked up from tcp_sent, as on the plaintext path. 100 Continue goes through the record layer. Connection: close sends close_notify. A failed handshake aborts the connection. - tests/lwip/cwist_test_mbedtls_config.h: TLS 1.2 server profile (ECDHE-ECDSA P-256, AES-128-GCM, SHA-256; 16 KB in / 4 KB out records). tests/lwip/tls_client.{c,h}: mbedTLS client over a loopback pcb. tests/lwip/test_tls_cert.h: test-only self-signed P-256 credentials. - tests/test_lwip_tls.c (make test): verified handshake, keep-alive and pipelining in one session, 100-continue with a split body, 40 KB response, 413, close_notify, plaintext client on the TLS port, and context creation failures. Under CWIST_TLS=mbedtls it links the vendored mbedTLS libcwist already uses. - tests/baremetal/hello_tls.c joins baremetal-smoke and the size gate: Cortex-M7 flash 137 KB, heap high-water 106.6 KB with both sessions, ~50 KB held by server + client sessions after the handshake. (cherry picked from commit eb537f9)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 5 of the bare-metal STM32 epic (#447): CI for the bare-metal build. Until now
make baremetal-smokeran only locally, so a change to hosted code could break the Cortex-M build unnoticed.What runs
.github/workflows/baremetal.ymlrunsmake baremetal-size-gateon every PR and push to main/dev:libcwist_baremetal.awitharm-none-eabi-gccfor Cortex-M7.qemu-arm -cpu cortex-m7with semihosting output:hello: in-memory dispatch, no RTC, so no Date headerhello-rtc: the same with an RTC, so Date is presenthello-lwip: the lwIP adapter over lwIP's loopback netifscripts/ci/baremetal-budget.txt:.dataload image.data+.bss, not counting the linker's.heapregionELFs, linker maps and run logs are uploaded as the
baremetal-firmwareartifact, so a size regression can be read from the map. The runner is pinned toubuntu-24.04(gcc 13.2 / newlib 4.4 / qemu 8.2), so the toolchain and the sizes do not move under the budget.The workflow checks out top-level submodules only and installs no host libraries. Nothing vendored is built: the build reads headers from boringssl and lsquic (for the Makefile feature probe) and sources from cjson, libttak and lwip.
Budgets
Set about 10% above the measured values and rounded to KiB. I measured with both the CI toolchain (gcc 13.2, extracted from the noble packages) and gcc 14.2; the results agree within 0.6%.
(measured / budget, bytes, gcc 13.2)
hello-lwip's static RAM comes mostly from the testlwipopts.h(24 KBMEM_SIZEand a 16-entry pbuf pool), not from CWIST. When growth is intended, the limit is raised in the same PR, with a reason.Changes
Makefile:baremetal-smokesaves each run's output to.baremetal-build/<fw>.log, and still stops at the first failing firmware with its log printed.baremetal-size-gatetarget.scripts/ci/baremetal_size_gate.pyand its unit testscripts/ci/test_baremetal_size_gate.py. The test is picked up by the existingscripts/ciunittest discovery. If the budget has a value for a metric the run did not report, the gate fails instead of passing silently.Local verification
make -j16. PASS.FAIL hello stack: 8352 bytes > budget 8000 (+352)).PKG_CONFIG=false. PASS.check_test_wiring,check_api_baselineandcheck_env_knobsall OK.Refs #447