Skip to content
Merged
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: 11 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,13 @@ UCI (`cfg/c64-https-uci.cfg`, W1 hot/cold split — the reference):
at $BA00 so sqtab lands at $BC00
(LIB_SHARED_SQTAB_BASE, asserted
post-link)
$C000-$DFFF OVERLAY_FILE_PAD zero-pad; runtime TCP ring at $C000
$C000-$CFFF (no region) TCP ring by equate; not in the PRG,
except comb's COLD_IMAGE (cold bank)
— the PRG ends $BFFF; comb with the
cold bank (COLD_BANK=1) ends $CFFF
$D000-$DFFF I/O never in the PRG: a KERNAL LOAD would
store into the registers (#288,
`tools/test_prg_io_range.py`)

ip65 (`cfg/c64-https-ip65.cfg`):

Expand Down Expand Up @@ -844,9 +850,10 @@ is LibreSSL and cannot serve this client) and `--selftest` proves the path
with `openssl s_client -ciphersuites TLS_CHACHA20_POLY1305_SHA256`.

`make package-verify` rebuilds and compares **PRG** hashes, reads each PRG
back out of its .d64 with `c1541`, boots each image in VICE
(`-trapdevice8 +drive8truedrive`, or the load never finishes), and runs the
listener selftest. A failed variant yields a partial release with an
back out of its .d64 with `c1541`, boots each image in VICE through a
real serial LOAD under true drive emulation (#288 — a poll that halts the
6510 between reads must `resume()` AFTER reading, or the load "never
finishes"), and runs the listener selftest. A failed variant yields a partial release with an
`!! INCOMPLETE RELEASE !!` MANIFEST block, and the gate cannot pass
vacuously (zero checks = fail; any `SKIP_*` = `PARTIAL VERIFICATION`).

Expand Down
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,11 @@ $(PRG): $(PRG_DEPS)
@grep -q '^al C:BC00 \.sqtab_lo' $(LABELS) || \
{ echo 'ERROR: sqtab_lo is not at $$BC00 — TABLES_BSS layout drifted; realign LIB_SHARED_SQTAB_BASE in tools/integration/build_x25519.sh and build_nistcurves_p256.sh'; \
grep ' \.sqtab_lo$$' $(LABELS); exit 1; }
@la=$$(od -An -tu1 -N2 $@ | awk 'NR==1 {print $$1 + 256 * $$2}'); \
end=$$(( la + $$(wc -c < $@) - 3 )); \
if [ $$end -ge 53248 ] && [ $$la -le 57343 ]; then \
echo "ERROR: $@ loads $$(printf '$$%04X-$$%04X' $$la $$end), into the I/O page at \$$D000-\$$DFFF: a KERNAL LOAD would store into the chip registers (#288, tools/check_prg_io_range.py)"; \
rm -f $@; exit 1; fi
ifeq ($(TRUST_RELEASE)$(TRUST_BUNDLE),11)
@python3 tools/check_release_key.py $@ || { rm -f $@; exit 1; }
endif
Expand Down
24 changes: 14 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,8 +346,10 @@ $A000-$BFFF CRYPTO_COLD_SHADOW 8 KB BSS (same tenants as ip65, less
cert_buf — which sits in CRYPTO_OVERLAY
under UCI, at 2,048 B against ip65's
1,536 B)
$C000-$DFFF OVERLAY_FILE_PAD zero-pad in the PRG; at runtime the
4 KB TCP_BUF ring lives at $C000
$C000-$CFFF (no region) the 4 KB TCP ring, by equate; not in
the PRG, except uci-comb's cold-code
image, which boot stashes to the REU
$D000-$DFFF I/O never in the PRG (#288)
```

`CRYPTO_OVERLAY` is not empty in any shipped UCI image — it holds the
Expand All @@ -369,9 +371,11 @@ one pool and moving segments between them creates nothing. `uci-onchip` is the
roomy one, and only because it ships neither the comb tables nor the comb
rodata; `uci-comb`'s `CRYPTO_OVERLAY` tail is small.

**PRG size is not a headroom gauge.** Both UCI products are 62,977 B and both
ip65 profiles are 47,105 B, because the ld65 configs mark the inter-region
gaps `fill = yes` so load addresses stay right. Re-measure from the map.
**PRG size is not a headroom gauge.** Every image ending at $BFFF is
47,105 B (both ip65 profiles, `uci-onchip`) and `uci-comb`, whose cold-code
image runs to $CFFF, is 51,201 B, because the ld65 configs mark the
inter-region gaps `fill = yes` so load addresses stay right. Re-measure from
the map.

No segment may cross $A000: boot zeroes $A000-$BFFF as BSS, so anything
executable there would be wiped on first call.
Expand Down Expand Up @@ -495,17 +499,17 @@ it is supposed to detect.
## Project Status

Current status of the three shipped products (re-measured at the
`libs/nistcurves` v0.14.0 pin with cc65 from Homebrew; `make clean` before each, then `stat` the PRG and
`libs/nistcurves` v0.15.0 pin with cc65 from Homebrew; `make clean` before each, then `stat` the PRG and
`grep -c '^al ' build/labels.txt`):

| product | PRG | labels |
|---|---:|---:|
| `c64-https-ip65-onchip` | 47,105 B | 2,395 |
| `c64-https-uci-onchip` | 62,977 B | 2,726 |
| `c64-https-uci-comb` | 62,977 B | 2,859 |
| `c64-https-ip65-onchip` | 47,105 B | 2,420 |
| `c64-https-uci-onchip` | 47,105 B | 2,939 |
| `c64-https-uci-comb` | 51,201 B | 3,181 |

The unshipped default profiles land on the same two PRG sizes (47,105 B /
62,977 B) with fewer labels, which is the point: **the PRG size is not a
51,201 B) with fewer labels, which is the point: **the PRG size is not a
code-size measurement and not a headroom gauge.** Much of each image is
deliberate zero fill, because the ld65 configs mark the inter-region gaps
`fill = yes` so the load addresses stay right. Two different builds sharing a
Expand Down
43 changes: 16 additions & 27 deletions cfg/c64-https-uci-onchip-cold.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# run there, one at a time. (P256_SCRATCH_UNION sits there too; a cold
# group never calls ecdsa_verify — the Makefile refuses TRUST_BUNDLE=1
# here, and src/net/uci/trust_bundle.s asserts it.)
# * COLD_IMAGE ($C000-$CFFF, the head of the old OVERLAY_FILE_PAD) is
# * COLD_IMAGE ($C000-$CFFF, the PRG's last file-backed area) is
# where the PRG carries them, back to back; boot stashes it into the
# REU before anything touches the TCP ring that shares the range.
# * TARGET_PROMPT_CODE (+ TRUST_BUNDLE_CODE) + COLD_TAIL_UI, and
Expand Down Expand Up @@ -92,10 +92,10 @@
# $01=$36; the large zero-init BSS —
# BSS / CRYPTO_BSS / BSS_TAIL, and
# TABLES_BSS pinned at $BA00)
# $C000-$DFFF : OVERLAY_FILE_PAD (zero-pad; tcp_recv_buf's 4 KB ring
# lives at $C000 inside this range, by
# equate — the separate TCP_BUF region
# was removed in Phase 3)
# $C000-$CFFF : TCP ring (tcp_recv_buf, 4 KB, by equate in
# src/constants.inc; RAM, no region)
# $D000-$DFFF : I/O (never in the PRG: a KERNAL LOAD
# would write the registers, #288)
#
# The W1 hot/cold split below DID happen: the note that used to stand here
# saying the bumped library "does not fit that partition" described an
Expand Down Expand Up @@ -234,34 +234,23 @@ MEMORY {
# asserted equal to tls_rec_buf in src/crypto/x25519_tables.s.
X25519_SCRATCH: start = $A000, size = $0224, type = rw, define = yes;

# File-backed zero pad from $C000. It was added (Phase 3) so the P-384
# curve blob, the next region, landed at $E000; P-384 is retired and
# that region is gone, but the pad stays: removing it changes what a
# PRG load writes over $C000-$DFFF, which is its own change. $C000-$CFFF is TCP_BUF
# at runtime (RAM, populated by ip65/UCI rx callback after net
# init); the zero-fill PRG-load write is harmless because TCP_BUF
# is zero-initialised at first use anyway. $D000-$DFFF is I/O on
# a real C64 + 1541 the PRG load WOULD momentarily corrupt VIC /
# SID / CIA registers; production targets are VICE warp + U64
# fastload, both of which inject bytes directly to RAM and bypass
# CPU I/O writes during PRG load.
# Cold bank: the PRG's copy of the cold groups (src/net/uci/cold_bank.s),
# back to back; boot stashes it into the REU. The head of what was
# OVERLAY_FILE_PAD, and of the TCP ring's range.
# back to back; boot stashes it into the REU before the first connect
# reuses the range as the TCP ring.
COLD_IMAGE: start = $C000, size = $1000, file = %O, define = yes, fill = yes, fillval = $00;
OVERLAY_FILE_PAD: start = $D000, size = $1000, file = %O, define = yes, fill = yes, fillval = $00;
# Where each cold group runs: cert_buf, pinned below. Not file-backed.
COLD_RUN_UI: start = $4200, size = $0800, type = rw, define = yes;
COLD_RUN_TRUST: start = $4200, size = $0800, type = rw, define = yes;

# NOTE: the historical TCP_BUF MEMORY region at $C000-$CFFF was
# removed in Phase 3 -- the actual TCP rx ring is just the
# `tcp_recv_buf = $c000` equate in src/constants.inc and the bytes
# at runtime live inside OVERLAY_FILE_PAD's address range. PRG
# load zeros the ring; the rx callback overwrites it after net
# init. The optional TCP_RECV_BUF segment was also dropped from
# SEGMENTS below (no .s file references the segment name; the
# buffer is addressed via the equate, not via a segment label).
# The PRG ends at $CFFF, COLD_IMAGE's last byte (#288).
# Nothing above it is file-backed. A zero pad used to run on to $DFFF
# (it put the retired P-384 curve blob at $E000), so a KERNAL LOAD
# wrote zeros into the VIC/SID/CIA registers at $D000-$DFFF;
# tools/test_prg_io_range.py fails if a PRG reaches $D000 again.
# The TCP rx ring is the `tcp_recv_buf = $c000` equate in
# src/constants.inc, not a region: net_tcp_connect empties it
# (head = tail = 0) and nothing reads a byte net_poll did not write,
# so what the load left there never mattered.
}

# --- Region occupancy -------------------------------------------------------
Expand Down
38 changes: 13 additions & 25 deletions cfg/c64-https-uci-onchip.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@
# $01=$36; the large zero-init BSS —
# BSS / CRYPTO_BSS / BSS_TAIL, and
# TABLES_BSS pinned at $BA00)
# $C000-$DFFF : OVERLAY_FILE_PAD (zero-pad; tcp_recv_buf's 4 KB ring
# lives at $C000 inside this range, by
# equate — the separate TCP_BUF region
# was removed in Phase 3)
# $C000-$CFFF : TCP ring (tcp_recv_buf, 4 KB, by equate in
# src/constants.inc; RAM, no region)
# $D000-$DFFF : I/O (never in the PRG: a KERNAL LOAD
# would write the registers, #288)
#
# The W1 hot/cold split below DID happen: the note that used to stand here
# saying the bumped library "does not fit that partition" described an
Expand Down Expand Up @@ -213,27 +213,15 @@ MEMORY {
# asserted equal to tls_rec_buf in src/crypto/x25519_tables.s.
X25519_SCRATCH: start = $A000, size = $0224, type = rw, define = yes;

# File-backed zero pad from $C000. It was added (Phase 3) so the P-384
# curve blob, the next region, landed at $E000; P-384 is retired and
# that region is gone, but the pad stays: removing it changes what a
# PRG load writes over $C000-$DFFF, which is its own change. $C000-$CFFF is TCP_BUF
# at runtime (RAM, populated by ip65/UCI rx callback after net
# init); the zero-fill PRG-load write is harmless because TCP_BUF
# is zero-initialised at first use anyway. $D000-$DFFF is I/O on
# a real C64 + 1541 the PRG load WOULD momentarily corrupt VIC /
# SID / CIA registers; production targets are VICE warp + U64
# fastload, both of which inject bytes directly to RAM and bypass
# CPU I/O writes during PRG load.
OVERLAY_FILE_PAD: start = $C000, size = $2000, file = %O, define = yes, fill = yes, fillval = $00;

# NOTE: the historical TCP_BUF MEMORY region at $C000-$CFFF was
# removed in Phase 3 -- the actual TCP rx ring is just the
# `tcp_recv_buf = $c000` equate in src/constants.inc and the bytes
# at runtime live inside OVERLAY_FILE_PAD's address range. PRG
# load zeros the ring; the rx callback overwrites it after net
# init. The optional TCP_RECV_BUF segment was also dropped from
# SEGMENTS below (no .s file references the segment name; the
# buffer is addressed via the equate, not via a segment label).
# The PRG ends at $BFFF, CRYPTO_COLD_SHADOW's last byte (#288).
# Nothing above it is file-backed. A zero pad used to run on to $DFFF
# (it put the retired P-384 curve blob at $E000), so a KERNAL LOAD
# wrote zeros into the VIC/SID/CIA registers at $D000-$DFFF;
# tools/test_prg_io_range.py fails if a PRG reaches $D000 again.
# The TCP rx ring is the `tcp_recv_buf = $c000` equate in
# src/constants.inc, not a region: net_tcp_connect empties it
# (head = tail = 0) and nothing reads a byte net_poll did not write,
# so what the load left there never mattered.
}

# --- Region occupancy -------------------------------------------------------
Expand Down
39 changes: 13 additions & 26 deletions cfg/c64-https-uci.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,10 @@
# $01=$36; the large zero-init BSS —
# BSS / CRYPTO_BSS / BSS_TAIL, and
# TABLES_BSS pinned at $BA00)
# $C000-$DFFF : OVERLAY_FILE_PAD (zero-pad; tcp_recv_buf's 4 KB ring
# lives at $C000 inside this range, by
# equate — the separate TCP_BUF region
# was removed in Phase 3, see the note
# in the MEMORY block)
# $C000-$CFFF : TCP ring (tcp_recv_buf, 4 KB, by equate in
# src/constants.inc; RAM, no region)
# $D000-$DFFF : I/O (never in the PRG: a KERNAL LOAD
# would write the registers, #288)
#
# The W1 hot/cold split below DID happen: the note that used to stand here
# saying the bumped library "does not fit that partition" described an
Expand Down Expand Up @@ -169,27 +168,15 @@ MEMORY {
# asserted equal to tls_rec_buf in src/crypto/x25519_tables.s.
X25519_SCRATCH: start = $A000, size = $0224, type = rw, define = yes;

# File-backed zero pad from $C000. It was added (Phase 3) so the P-384
# curve blob, the next region, landed at $E000; P-384 is retired and
# that region is gone, but the pad stays: removing it changes what a
# PRG load writes over $C000-$DFFF, which is its own change. $C000-$CFFF is TCP_BUF
# at runtime (RAM, populated by ip65/UCI rx callback after net
# init); the zero-fill PRG-load write is harmless because TCP_BUF
# is zero-initialised at first use anyway. $D000-$DFFF is I/O on
# a real C64 + 1541 the PRG load WOULD momentarily corrupt VIC /
# SID / CIA registers; production targets are VICE warp + U64
# fastload, both of which inject bytes directly to RAM and bypass
# CPU I/O writes during PRG load.
OVERLAY_FILE_PAD: start = $C000, size = $2000, file = %O, define = yes, fill = yes, fillval = $00;

# NOTE: the historical TCP_BUF MEMORY region at $C000-$CFFF was
# removed in Phase 3 -- the actual TCP rx ring is just the
# `tcp_recv_buf = $c000` equate in src/constants.inc and the bytes
# at runtime live inside OVERLAY_FILE_PAD's address range. PRG
# load zeros the ring; the rx callback overwrites it after net
# init. The optional TCP_RECV_BUF segment was also dropped from
# SEGMENTS below (no .s file references the segment name; the
# buffer is addressed via the equate, not via a segment label).
# The PRG ends at $BFFF, CRYPTO_COLD_SHADOW's last byte (#288).
# Nothing above it is file-backed. A zero pad used to run on to $DFFF
# (it put the retired P-384 curve blob at $E000), so a KERNAL LOAD
# wrote zeros into the VIC/SID/CIA registers at $D000-$DFFF;
# tools/test_prg_io_range.py fails if a PRG reaches $D000 again.
# The TCP rx ring is the `tcp_recv_buf = $c000` equate in
# src/constants.inc, not a region: net_tcp_connect empties it
# (head = tail = 0) and nothing reads a byte net_poll did not write,
# so what the load left there never mattered.
}

# --- Region occupancy -------------------------------------------------------
Expand Down
Loading