mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-10-29 17:54:14 +08:00
* stp: select the root port by cost and block redundant links * stp: move the protocol to BANK4 and keep the command line in BANK2 * stp: implement the RSTP state machines of 802.1D-2004 clause 17 * stp: counters, more settings and a fuller Spanning Tree page * stp: make a link aggregation group one port of the RSTP tree * web: serve the Spanning Tree JSON from BANK4 as well Kept in BANK1, the larger Spanning Tree page would leave under 1 kB there for the rest of the web server and every page still to come, so send_stp() and send_stp_counters() move to httpd/page_stp.c in BANK4 with the protocol, as banked calls, with their own copies of the few output helpers and of the JSON header, so nothing in BANK4 calls into BANK1 directly or hands it a pointer into its code space. BANK4 takes the free flash between BANK3 and the web files. KP_9000_6XHML_X2: BANK1 44336, BANK2 36969, BANK3 11942, BANK4 20965 bytes of 49152.
Host unit-test harness
Compile and test individual firmware translation units on the build host with
gcc + AddressSanitizer + UBSan — no SDCC, no flashing, no hardware. This is
the fast inner loop for the logic-level bugs in ../../NOTES/08-findings.md
(parser, line editor, HTTP header, DHCP): edit → make → see red/green in
seconds instead of a minutes-long flash-and-reboot cycle.
Run
cd test
make # build + run all tests (ASan/UBSan on)
make clean
Exit status is non-zero if any check fails, a sanitizer trips, or the watchdog fires — so it drops straight into CI.
How it works
sdcc_shim.h(force-included) erases SDCC 8051 keywords (__xdata,__code,__banked, …) so firmware sources compile under host gcc. It changes no logic — the code under test is byte-for-byte the firmware source.hw_mock.c/hw_mock.hsimulate the ASIC edge: a flat register file behindreg_read/reg_writeand theSFR_DATA_*registers, with a table engine that performs a VLAN or L2 operation the momentTBL_CTRLis written, fetches a MIB counter onSTAT_GETand drops entries onL2_TBL_FLUSH_CTRL. Nothing ever reports busy, so a polling loop runs once. The header states the VLAN and L2 entry layouts independently of the firmware, so a test can hold whatrtl837x_port.cwrites against whatpage_impl.creads.env_tables.ccarries the globals and leaf calls those two modules link against;stub/stands in for the two headers only a firmware build generates, so the harness needs no SDCC build first.support.c/support.hmock the hardware edges: the 16-byte serial ring (sbuf), the command/history buffers, and the character-output sink (write_charetc.). Buffers are sized exactly as on target, so ASan redzones catch the same off-by-one overflows the 8051 hits.- Builds define
RTLP_HOST_TEST, which hides the firmware's libc-named prototypes (memset/strlen/…) inrtl837x_common.hso they don't clash with glibc. Argument order matches libc, so on-host callers transparently use the C library. This guard is compiled out of normal firmware builds — zero on-target effect. - A SIGALRM watchdog (
watchdog_arm) turns an infinite-loop bug into a fast test failure instead of a hung runner.
Current coverage
| Test binary | TU under test | Findings exercised |
|---|---|---|
test_cmd_editor |
cmd_editor.c |
C4 — full-line hang + cmd_buffer 1-byte overflow; basic entry & backspace regressions |
test_port_tables |
rtl837x_port.c |
VLAN entry layout and round trip, PVID register sharing, static multicast and management entries, per-port flush, trunk membership and hash seed |
test_page_json |
httpd/page_impl.c + rtl837x_port.c |
/vlan.json, /vlanlist, /l2.json (walk, wrap marker, paging inside outbuf), 64-bit counters in /status.json and /counters.json |
test_httpd_tx |
httpd/httpd.c + uip/uip.c |
a GET of a static file against a client that moves its receive window: ACK accounting, continuation chunks out of flash, retransmission |
test_lacp |
rtl837x_lacp.c |
state machines against a simulated 802.3ad partner: convergence, mis-cabling, expiry, re-election, two groups, delivery by trap |
Adding a test for another module
- Write
test_<module>.cwithmain()driving the module's entry points andCHECK(cond, msg)assertions. - Add any missing mocked symbols to
support.c(only what the linker asks for). - Add a target in the
Makefilelistingtest_<module>.c support.c ../<module>.c. - If the module calls a firmware libc-name (
memcpy/strcpy/…), it will use the C library on host (compatible arg order); provide afw_*-style mock only if the semantics differ in a way the test cares about.
Good next targets (pure logic, high finding density): cmd_parser.c (C6/C8),
the HTTP header parser in httpd/httpd.c (S1), dhcp.c (S5).