summaryrefslogtreecommitdiff
path: root/cmd/sbc_harness
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/sbc_harness')
-rw-r--r--cmd/sbc_harness/CMakeLists.txt84
-rw-r--r--cmd/sbc_harness/config/config.h114
-rw-r--r--cmd/sbc_harness/config/tusb_config.h129
-rw-r--r--cmd/sbc_harness/fs_harness_flash_bin.c312
-rw-r--r--cmd/sbc_harness/fs_harness_flash_bin.h30
-rw-r--r--cmd/sbc_harness/fs_harness_uptime_txt.c156
-rw-r--r--cmd/sbc_harness/fs_harness_uptime_txt.h19
-rw-r--r--cmd/sbc_harness/main.c253
-rw-r--r--cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS.md29
l---------cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/agpl-3.0.txt1
l---------cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/newlib.txt1
l---------cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/pico-sdk.bsd3.txt1
l---------cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/printf.mit.txt1
l---------cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/tinyusb.mit.txt1
-rw-r--r--cmd/sbc_harness/static/Documentation/harness_flash_bin.txt33
-rw-r--r--cmd/sbc_harness/static/Documentation/harness_rom_bin.txt41
-rw-r--r--cmd/sbc_harness/static/Documentation/harness_uptime_txt.txt17
-rw-r--r--cmd/sbc_harness/tusb_log.c15
-rw-r--r--cmd/sbc_harness/usb_keyboard.c117
-rw-r--r--cmd/sbc_harness/usb_keyboard.h20
20 files changed, 0 insertions, 1374 deletions
diff --git a/cmd/sbc_harness/CMakeLists.txt b/cmd/sbc_harness/CMakeLists.txt
deleted file mode 100644
index 6e722d7..0000000
--- a/cmd/sbc_harness/CMakeLists.txt
+++ /dev/null
@@ -1,84 +0,0 @@
-# cmd/sbc_harness/CMakeLists.txt - Build script for main sbc_harness.uf2 firmware file
-#
-# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-if (PICO_PLATFORM STREQUAL "rp2040")
-
-# Compile ######################################################################
-
-add_library(sbc_harness_objs OBJECT
- main.c
- usb_keyboard.c
- tusb_log.c
-
- fs_harness_flash_bin.c
- fs_harness_uptime_txt.c
-)
-target_include_directories(sbc_harness_objs PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config)
-target_include_directories(sbc_harness_objs PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
-target_include_directories(sbc_harness_objs PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
-target_link_libraries(sbc_harness_objs
- pico_runtime
- pico_stdio_uart
-
- hardware_flash
- hardware_watchdog
-
- libmisc
- libfmt
- libusb
- libdhcp
- libhw_cr
- lib9p_srv
- lib9p_util
-)
-pico_minimize_runtime(sbc_harness_objs
- INCLUDE PRINTF PRINTF_MINIMAL PRINTF_LONG_LONG PRINTF_PTRDIFF_T
-)
-target_compile_definitions(sbc_harness_objs PRIVATE
- #PICO_USE_FASTEST_SUPPORTED_CLOCK=1
-
- # Calculated by `./3rd-party/pico-sdk/src/rp2_common/hardware_clocks/scripts/vcocalc.py --cmake-only 170`
- PLL_SYS_REFDIV=2
- PLL_SYS_VCO_FREQ_HZ=1530000000
- PLL_SYS_POSTDIV1=3
- PLL_SYS_POSTDIV2=3
- SYS_CLK_HZ=170000000
-)
-
-suppress_tinyusb_warnings()
-
-# Analyze the stack ############################################################
-
-add_stack_analysis(sbc_harness_stack.c sbc_harness_objs)
-
-# Link #########################################################################
-
-add_executable(sbc_harness)
-target_sources(sbc_harness PRIVATE
- sbc_harness_stack.c
- "$<TARGET_OBJECTS:sbc_harness_objs>"
-)
-target_link_libraries(sbc_harness
- pico_standard_link
-)
-target_link_options(sbc_harness PRIVATE "$<TARGET_PROPERTY:sbc_harness_objs,LINK_OPTIONS>")
-pico_add_extra_outputs(sbc_harness) # create .map/.bin/.hex/.uf2 files in addition to .elf
-pico_set_program_url(sbc_harness "https://git.lukeshu.com/sbc-harness")
-
-# Embed ########################################################################
-
-target_embed_sources(sbc_harness_objs sbc_harness static.h
- static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS.md
- static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/agpl-3.0.txt
- static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/pico-sdk.bsd3.txt
- static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/printf.mit.txt
- static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/tinyusb.mit.txt
- static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/newlib.txt
- static/Documentation/harness_rom_bin.txt
- static/Documentation/harness_flash_bin.txt
- static/Documentation/harness_uptime_txt.txt
-)
-
-endif()
diff --git a/cmd/sbc_harness/config/config.h b/cmd/sbc_harness/config/config.h
deleted file mode 100644
index 5367dbe..0000000
--- a/cmd/sbc_harness/config/config.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/* config.h - Compile-time configuration for sbc_harness
- *
- * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#ifndef _CONFIG_H_
-#define _CONFIG_H_
-
-#include <stddef.h> /* for size_t */
-
-#define CONFIG_FLASH_DEBUG 1
-
-#define _CONFIG_9P_MAX_CONNS 3 /* FIXME: bump this back up to 8 */
-#define _CONFIG_9P_MAX_REQS (2*_CONFIG_9P_MAX_CONNS)
-
-/* RP2040 *********************************************************************/
-
-#define CONFIG_RP2040_SPI_DEBUG 1 /* bool */
-
-/* W5500 **********************************************************************/
-
-/**
- * When allocating an arbitrary local port, what range should it be
- * allocated from?
- *
- * These are the default values of the Linux kernel's
- * net.ipv4.ip_local_port_range, so I figure they're probably good
- * values to use.
- */
-#define CONFIG_W5500_LOCAL_PORT_MIN 32768
-#define CONFIG_W5500_LOCAL_PORT_MAX 60999
-
-#define CONFIG_W5500_VALIDATE_SPI 1 /* bool */
-#define CONFIG_W5500_DEBUG 0 /* bool */
-#define CONFIG_W5500_LL_DEBUG 0 /* bool */
-
-/* 9P *************************************************************************/
-
-#define CONFIG_9P_MAX_ERR_SIZE 128 /* 128 is what Plan 9 4e uses */
-
-/**
- * This max-msg-size is sized so that a Twrite message can return
- * 8KiB of data.
- *
- * This is the same as the default in Plan 9 4e's lib9p; it has the
- * comment that "24" is "ample room for Twrite/Rread header
- * (iounit)". In fact, the Twrite header is only 23 bytes
- * ("size[4] Twrite[1] tag[2] fid[4] offset[8] count[4]") and the
- * Rread header is even shorter at 11 bytes ("size[4] Rread[1]
- * tag[2] count[4]"), so "24" appears to be the size of the Twrite
- * header rounded up to a nice round number.
- *
- * In older versions of 9P ("9P1"), the max message size was
- * defined as part of the protocol specification rather than
- * negotiated. In Plan 9 1e it was (8*1024)+128, and was bumped to
- * (8*1024)+160 in 2e and 3e.
- */
-#define CONFIG_9P_SRV_MAX_MSG_SIZE ((4*1024)+24)
-/**
- * Maximum host-data-structure size. A message may be larger in
- * unmarshaled-host-structures than marshaled-net-bytes due to (1)
- * struct padding, (2) array pointers.
- */
-#define CONFIG_9P_SRV_MAX_HOSTMSG_SIZE CONFIG_9P_SRV_MAX_MSG_SIZE+16
-
-#define CONFIG_9P_ENABLE_9P2000 1 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_e 0 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_L 0 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_p9p 0 /* bool */
-
-/* DHCP ***********************************************************************/
-
-#define CONFIG_DHCP_CAN_RECV_UNICAST_IP_WITHOUT_IP 0 /* bool */
-#define CONFIG_DHCP_DEBUG 1 /* bool */
-#define CONFIG_DHCP_OPT_SIZE 312 /* minimum of 312 */
-#define CONFIG_DHCP_SELECTING_NS (5*NS_PER_S)
-
-/* USB KEYBOARD ***************************************************************/
-
-/**
- * Which USB port to use for the Root Hub.
- *
- * The RP2040 only has 1 port, so it's gotta be port #0.
- */
-#define CONFIG_USB_COMMON_RHPORT 0
-
-#define CONFIG_USB_COMMON_DEBUG 1 /* bool */
-
-/* COROUTINE ******************************************************************/
-
-extern const size_t CONFIG_COROUTINE_STACK_SIZE_dhcp_cr;
-extern const size_t CONFIG_COROUTINE_STACK_SIZE_init_cr;
-extern const size_t CONFIG_COROUTINE_STACK_SIZE_read9p_cr;
-extern const size_t CONFIG_COROUTINE_STACK_SIZE_write9p_cr;
-extern const size_t CONFIG_COROUTINE_STACK_SIZE_usb_common_cr;
-extern const size_t CONFIG_COROUTINE_STACK_SIZE_usb_keyboard_cr;
-extern const size_t CONFIG_COROUTINE_STACK_SIZE_w5500_irq_cr;
-#define CONFIG_COROUTINE_NAME_LEN 16
-#define CONFIG_COROUTINE_MEASURE_STACK 1 /* bool */
-#define CONFIG_COROUTINE_PROTECT_STACK 1 /* bool */
-#define CONFIG_COROUTINE_DEBUG 0 /* bool */
-#define CONFIG_COROUTINE_VALGRIND 0 /* bool */
-#define CONFIG_COROUTINE_GDB 1 /* bool */
-
-#define CONFIG_COROUTINE_NUM ( \
- 1 /* usb_common */ + \
- 1 /* usb_keyboard */ + \
- 1 /* W5500 irq handler */ + \
- _CONFIG_9P_MAX_CONNS /* 9P accept()+read() */ + \
- _CONFIG_9P_MAX_REQS /* 9P work+write() */ )
-
-#endif /* _CONFIG_H_ */
diff --git a/cmd/sbc_harness/config/tusb_config.h b/cmd/sbc_harness/config/tusb_config.h
deleted file mode 100644
index 0a6d3e4..0000000
--- a/cmd/sbc_harness/config/tusb_config.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/* tusb_config.h - Compile-time configuration for the TinyUSB library
- *
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- *
- * SPDX-License-Identifier: MIT
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 Ha Thach (tinyusb.org)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#ifndef _TUSB_CONFIG_H_
-#define _TUSB_CONFIG_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//--------------------------------------------------------------------
-// Override the default definition of TU_ASSERT() to use our logging
-//--------------------------------------------------------------------
-
-// "magically" select between the 1-arg and 2-args variants, inject a
-// stringified version of `_cond`.
-//
-// Note: Use GNU-C `, ##__VA_ARGS__`, not standard C `__VA_OPT__(,)
-// __VA_ARGS__`; because __VA_OPT__ doesn't handle present-but-empty
-// arguments the way that we need.
-#define TU_ASSERT(_cond, ...) \
- _GET_3RD_ARG(_cond, ##__VA_ARGS__, \
- _LIBMISC_TU_ASSERT_2ARGS, _LIBMISC_TU_ASSERT_1ARGS, _dummy) \
- (_cond, #_cond, ##__VA_ARGS__)
-
-#define _LIBMISC_TU_ASSERT_1ARGS(_cond, _cond_str) \
- _LIBMISC_TU_ASSERT_2ARGS(_cond, _cond_str, false)
-
-#define _LIBMISC_TU_ASSERT_2ARGS(_cond, _cond_str, _ret) \
- do { \
- if ( !(_cond) ) { \
- _libmisc_tu_mess_failed(_cond_str, \
- __FILE__, __LINE__, __func__); \
- TU_BREAKPOINT(); \
- return _ret; \
- } \
- } while(0)
-
-void _libmisc_tu_mess_failed(const char *expr,
- const char *file, unsigned int line, const char *func);
-
-//--------------------------------------------------------------------
-// Configuration: common
-//--------------------------------------------------------------------
-
-// defined by compiler flags
-#ifndef CFG_TUSB_MCU
-#error CFG_TUSB_MCU must be defined
-#endif
-
-// Conditional because it might be defined with `-D` on the command
-// line if `cmake -DCMAKE_BUILD_TYPE=Debug`.
-#ifndef CFG_TUSB_DEBUG
-#define CFG_TUSB_DEBUG 0
-#endif
-
-// USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
-// Tinyusb use follows macros to declare transferring memory so that they can be put
-// into those specific section.
-// e.g
-// - CFG_TUSB_MEM SECTION : [[gnu::section(".usb_ram")]]
-// - CFG_TUSB_MEM_ALIGN : [[gnu::aligned(4)]]
-#define CFG_TUSB_MEM_SECTION /* blank */
-#define CFG_TUSB_MEM_ALIGN [[gnu::aligned(4)]]
-
-#define CFG_TUD_ENABLED 1
-#define CFG_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
-
-//--------------------------------------------------------------------
-// Configuration: TinyUSB Device (TUD)
-//--------------------------------------------------------------------
-
-// control endpoint max packet size (only 8, 16, 32, or 64 are valid)
-#define CFG_TUD_ENDPOINT0_SIZE 64
-
-// Which of TinyUSB's built-in class drivers to enable.
-//
-// If a class takes an int, that's the maximum number of interfaces of
-// that type that may be listed in the same configuration descriptor.
-#define CFG_TUD_CDC 0 // int : Communications Device Class (e.g. ttyUSB) https://www.usb.org/sites/default/files/CDC1.2_WMC1.1_012011.zip
-#define CFG_TUD_MSC 0 // bool: Mass Storage Class https://www.usb.org/sites/default/files/Mass_Storage_Specification_Overview_v1.4_2-19-2010.pdf
-#define CFG_TUD_HID 1 // int : Human Interface Device https://www.usb.org/sites/default/files/hid1_11.pdf
-#define CFG_TUD_AUDIO 0 // int : Audio https://www.usb.org/sites/default/files/audio10.pdf
-#define CFG_TUD_VIDEO 0 // int : Video https://www.usb.org/sites/default/files/USB_Video_Class_1_5.zip
-#define CFG_TUD_MIDI 0 // int : Musical Instrument Digital Interface https://www.usb.org/sites/default/files/USB%20MIDI%20v2_0.pdf
-#define CFG_TUD_VENDOR 0 // int : ???
-#define CFG_TUD_USBTMC 0 // bool: Test & Measurement Class https://www.usb.org/sites/default/files/USBTMC_1_006a.zip
-#define CFG_TUD_DFU_RUNTIME 0 // bool: Device Firmware Upgrade https://www.usb.org/sites/default/files/DFU_1.1.pdf
-#define CFG_TUD_DFU 0 // bool: Device Firmware Upgrade https://www.usb.org/sites/default/files/DFU_1.1.pdf
-#define CFG_TUD_ECM_RNDIS 0 // bool: net
-#define CFG_TUD_NCM 0 // bool: net
-#define CFG_TUD_BTH 0 // bool: Bluetooth
-
-// HID buffer size Should be sufficient to hold ID (if any) + Data
-#define CFG_TUD_HID_EP_BUFSIZE 8
-
-//--------------------------------------------------------------------
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _TUSB_CONFIG_H_ */
diff --git a/cmd/sbc_harness/fs_harness_flash_bin.c b/cmd/sbc_harness/fs_harness_flash_bin.c
deleted file mode 100644
index bc3d061..0000000
--- a/cmd/sbc_harness/fs_harness_flash_bin.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/* sbc_harness/fs_harness_flash_bin.c - 9P access to flash storage
- *
- * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#include <string.h>
-
-#include <hardware/flash.h>
-#include <hardware/watchdog.h>
-
-#define LOG_NAME FLASH
-#include <libmisc/log.h>
-
-#include <util9p/static.h>
-
-#define IMPLEMENTATION_FOR_FS_HARNESS_FLASH_BIN YES
-#include "fs_harness_flash_bin.h"
-
-LO_IMPLEMENTATION_C(lib9p_srv_file, struct flash_file, flash_file, static);
-
-LO_IMPLEMENTATION_H(lib9p_srv_fio, struct flash_file, flash_file);
-LO_IMPLEMENTATION_C(lib9p_srv_fio, struct flash_file, flash_file, static);
-
-#define DATA_START ((const char *)(XIP_NOALLOC_BASE))
-#define DATA_SIZE PICO_FLASH_SIZE_BYTES
-#define DATA_HSIZE (DATA_SIZE/2)
-static_assert(DATA_SIZE % FLASH_SECTOR_SIZE == 0);
-static_assert(DATA_HSIZE % FLASH_SECTOR_SIZE == 0);
-
-/* There are some memcpy()s (and memcmp()s?) in here that can (and
- * arguably should) be replaced with SSI DMA. */
-
-/* ab_flash_* (mid-level utilities for our A/B write scheme) ******************/
-
-/**
- * Copy the upper half of flash to the lower half of flash, then reboot.
- *
- * @param buf : a scratch buffer that is at least FLASH_SECTOR_SIZE
- */
-[[noreturn]] static void __no_inline_not_in_flash_func(ab_flash_finalize)(uint8_t *buf) {
- assert(buf);
-
- infof("copying upper flash to lower flash...");
-
- cr_save_and_disable_interrupts();
-
- for (size_t off = 0; off < DATA_HSIZE; off += FLASH_SECTOR_SIZE) {
- memcpy(buf, DATA_START+DATA_HSIZE+off, FLASH_SECTOR_SIZE);
- if (memcmp(DATA_START+off, buf, FLASH_SECTOR_SIZE) == 0)
- continue;
- flash_range_erase(off, FLASH_SECTOR_SIZE);
- flash_range_program(off, buf, FLASH_SECTOR_SIZE);
- }
-
- infof("rebooting...");
-
- watchdog_reboot(0, 0, 300);
-
- for (;;)
- asm volatile ("nop");
-}
-
-/**
- * Set the upper half of flash to all zero bytes.
- *
- * @param buf : a scratch buffer that is at least FLASH_SECTOR_SIZE
- */
-static void ab_flash_initialize_zero(uint8_t *buf) {
- assert(buf);
-
- memset(buf, 0, FLASH_SECTOR_SIZE);
-
- infof("zeroing upper flash...");
- for (size_t off = DATA_HSIZE; off < DATA_SIZE; off += FLASH_SECTOR_SIZE) {
- if (memcmp(buf, DATA_START+off, FLASH_SECTOR_SIZE) == 0)
- continue;
- bool saved = cr_save_and_disable_interrupts();
- /* No need to `flash_range_erase()`; the way the flash
- * works is that _erase() sets all bits to 1, and
- * _program() sets some bits to 0. If we don't need
- * any bits to be 1, then we can skip the
- * _erase(). */
- flash_range_program(off, buf, FLASH_SECTOR_SIZE);
- cr_restore_interrupts(saved);
- }
- debugf("... zeroed");
-}
-
-/**
- * Copy the lower half of flash to the upper half of flash.
- *
- * @param buf : a scratch buffer that is at least FLASH_SECTOR_SIZE
- */
-static void ab_flash_initialize(uint8_t *buf) {
- assert(buf);
-
- infof("initializing upper flash...");
- for (size_t off = 0; off < DATA_HSIZE; off += FLASH_SECTOR_SIZE) {
- memcpy(buf, DATA_START+off, FLASH_SECTOR_SIZE);
- if (memcmp(buf, DATA_START+DATA_HSIZE+off, FLASH_SECTOR_SIZE) == 0)
- continue;
- bool saved = cr_save_and_disable_interrupts();
- flash_range_erase(DATA_HSIZE+off, FLASH_SECTOR_SIZE);
- flash_range_program(DATA_HSIZE+off, buf, FLASH_SECTOR_SIZE);
- cr_restore_interrupts(saved);
- }
- debugf("... initialized");
-}
-
-/**
- * Write `dat` to flash sector `pos`+(DATA_SIZE/2) (i.e. `pos` is a
- * sector in the lower half, but this function writes to the upper
- * half).
- *
- * @param pos : start-position of the sector to write to, must be in the upper half of the flash
- * @param dat : the FLASH_SECTOR_SIZE bytes to write
- */
-static void ab_flash_write_sector(size_t pos, uint8_t *dat) {
- assert(pos < DATA_HSIZE);
- assert(pos % FLASH_SECTOR_SIZE == 0);
- assert(dat);
-
- pos += DATA_HSIZE;
-
- infof("write flash sector @ %zu...", pos);
- if (memcmp(dat, DATA_START+pos, FLASH_SECTOR_SIZE) != 0) {
- bool saved = cr_save_and_disable_interrupts();
- flash_range_erase(pos, FLASH_SECTOR_SIZE);
- flash_range_program(pos, dat, FLASH_SECTOR_SIZE);
- cr_restore_interrupts(saved);
- }
- debugf("... written");
-}
-
-/* srv_file *******************************************************************/
-
-static void flash_file_free(struct flash_file *self) {
- assert(self);
-}
-static struct lib9p_qid flash_file_qid(struct flash_file *self) {
- assert(self);
-
- return (struct lib9p_qid){
- .type = LIB9P_QT_FILE|LIB9P_QT_EXCL,
- .vers = 1,
- .path = self->pathnum,
- };
-}
-
-static struct lib9p_stat flash_file_stat(struct flash_file *self, struct lib9p_srv_ctx *ctx) {
- assert(self);
- assert(ctx);
-
- return (struct lib9p_stat){
- .kern_type = 0,
- .kern_dev = 0,
- .file_qid = flash_file_qid(self),
- .file_mode = LIB9P_DM_EXCL|0666,
- .file_atime = UTIL9P_ATIME,
- .file_mtime = UTIL9P_MTIME,
- .file_size = DATA_SIZE,
- .file_name = lib9p_str(self->name),
- .file_owner_uid = lib9p_str("root"),
- .file_owner_gid = lib9p_str("root"),
- .file_last_modified_uid = lib9p_str("root"),
- .file_extension = lib9p_str(NULL),
- .file_owner_n_uid = 0,
- .file_owner_n_gid = 0,
- .file_last_modified_n_uid = 0,
- };
-}
-static void flash_file_wstat(struct flash_file *self, struct lib9p_srv_ctx *ctx,
- struct lib9p_stat) {
- assert(self);
- assert(ctx);
-
- lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem");
-}
-static void flash_file_remove(struct flash_file *self, struct lib9p_srv_ctx *ctx) {
- assert(self);
- assert(ctx);
-
- lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem");
-}
-
-LIB9P_SRV_NOTDIR(struct flash_file, flash_file);
-
-static lo_interface lib9p_srv_fio flash_file_fopen(struct flash_file *self, struct lib9p_srv_ctx *ctx,
- bool rd, bool wr, bool trunc) {
- assert(self);
- assert(ctx);
-
- if (rd) {
- self->rbuf.ok = false;
- }
-
- if (wr) {
- if (trunc) {
- ab_flash_initialize_zero(self->wbuf.dat);
- self->written = true;
- } else {
- ab_flash_initialize(self->wbuf.dat);
- self->written = false;
- }
- self->wbuf.ok = false;
- }
-
- return lo_box_flash_file_as_lib9p_srv_fio(self);
-}
-
-/* srv_fio ********************************************************************/
-
-static uint32_t flash_file_iounit(struct flash_file *self) {
- assert(self);
- return FLASH_SECTOR_SIZE;
-}
-
-static void flash_file_iofree(struct flash_file *self) {
- assert(self);
-
- if (self->wbuf.ok)
- ab_flash_write_sector(self->wbuf.pos, self->wbuf.dat);
-
- if (self->written)
- ab_flash_finalize(self->wbuf.dat);
-}
-
-static void flash_file_pread(struct flash_file *self, struct lib9p_srv_ctx *ctx,
- uint32_t byte_count, uint64_t byte_offset,
- struct iovec *ret) {
- assert(self);
- assert(ctx);
- assert(ret);
-
- if (byte_offset > DATA_SIZE) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EINVAL, "offset is past the chip size");
- return;
- }
-
- /* Assume that somewhere down the line the iovec we return
- * will be passed to DMA. We don't want the DMA engine to hit
- * (slow) XIP (for instance, this can cause reads/writes to
- * the SSP to get out of sync with eachother), so copy the
- * data to a buffer in (fast) RAM first. It's lame that the
- * DMA engine can only have a DREQ on one side of the channel.
- */
- if (byte_offset == DATA_SIZE) {
- *ret = (struct iovec){
- .iov_len = 0,
- };
- return;
- }
- size_t sector_base = LM_ROUND_DOWN(byte_offset, FLASH_SECTOR_SIZE);
- if (byte_offset + byte_count > sector_base + FLASH_SECTOR_SIZE)
- byte_count = (sector_base + FLASH_SECTOR_SIZE) - byte_offset;
- assert(byte_offset + byte_count <= DATA_SIZE);
-
- if (!self->rbuf.ok || self->rbuf.pos != sector_base) {
- self->rbuf.ok = true;
- self->rbuf.pos = sector_base;
- memcpy(self->rbuf.dat, DATA_START+sector_base, FLASH_SECTOR_SIZE);
- }
-
- *ret = (struct iovec){
- .iov_base = &self->rbuf.dat[byte_offset-sector_base],
- .iov_len = byte_count,
- };
-}
-
-/* TODO: Short/corrupt writes are dangerous. This should either (1)
- * check a checksum, (2) use uf2 instead of verbatim data, or (3) use
- * ihex instead of verbatim data. */
-static uint32_t flash_file_pwrite(struct flash_file *self, struct lib9p_srv_ctx *ctx,
- void *buf,
- uint32_t byte_count,
- uint64_t byte_offset) {
- assert(self);
- assert(ctx);
-
- if (byte_offset > DATA_HSIZE) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EINVAL, "offset is past half the chip size");
- return 0;
- }
- if (byte_count == 0)
- return 0;
- if (byte_offset == DATA_HSIZE) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EINVAL, "offset is at half the chip size");
- return 0;
- }
-
- size_t sector_base = LM_ROUND_DOWN(byte_offset, FLASH_SECTOR_SIZE);
- if (byte_offset + byte_count > sector_base + FLASH_SECTOR_SIZE)
- byte_count = (sector_base + FLASH_SECTOR_SIZE) - byte_offset;
- assert(byte_offset + byte_count < DATA_HSIZE);
-
- if (self->wbuf.ok && self->wbuf.pos != sector_base)
- ab_flash_write_sector(self->wbuf.pos, self->wbuf.dat);
- if (!self->wbuf.ok || self->wbuf.pos != sector_base) {
- self->wbuf.ok = true;
- self->wbuf.pos = sector_base;
- if (byte_count != FLASH_SECTOR_SIZE)
- memcpy(self->wbuf.dat, DATA_START+DATA_HSIZE+sector_base, FLASH_SECTOR_SIZE);
- }
- memcpy(&self->wbuf.dat[byte_offset-sector_base], buf, byte_count);
-
- self->written = true;
- return byte_count;
-}
diff --git a/cmd/sbc_harness/fs_harness_flash_bin.h b/cmd/sbc_harness/fs_harness_flash_bin.h
deleted file mode 100644
index 36382be..0000000
--- a/cmd/sbc_harness/fs_harness_flash_bin.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* sbc_harness/fs_harness_flash_bin.h - 9P access to flash storage
- *
- * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#ifndef _SBC_HARNESS_FS_HARNESS_FLASH_BIN_H_
-#define _SBC_HARNESS_FS_HARNESS_FLASH_BIN_H_
-
-#include <hardware/flash.h> /* for FLASH_SECTOR_SIZE */
-
-#include <lib9p/srv.h>
-
-struct flash_file {
- char *name;
- uint64_t pathnum;
-
- BEGIN_PRIVATE(FS_HARNESS_FLASH_BIN);
- bool written;
- struct {
- bool ok;
- size_t pos;
- uint8_t dat[FLASH_SECTOR_SIZE];
- } wbuf, rbuf;
- END_PRIVATE(FS_HARNESS_FLASH_BIN);
-};
-LO_IMPLEMENTATION_H(lib9p_srv_file, struct flash_file, flash_file);
-#define lo_box_flash_file_as_lib9p_srv_file(obj) util9p_box(flash_file, obj)
-
-#endif /* _SBC_HARNESS_FS_HARNESS_FLASH_BIN_H_ */
diff --git a/cmd/sbc_harness/fs_harness_uptime_txt.c b/cmd/sbc_harness/fs_harness_uptime_txt.c
deleted file mode 100644
index 1425bf9..0000000
--- a/cmd/sbc_harness/fs_harness_uptime_txt.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/* sbc_harness/fs_harness_uptime_txt.c - 9P access to harness uptime
- *
- * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#include <stdio.h> /* for snprintf() */
-#include <stdlib.h> /* for malloc(), free() */
-
-#include <libhw/generic/alarmclock.h>
-#include <util9p/static.h>
-
-#include "fs_harness_uptime_txt.h"
-
-LO_IMPLEMENTATION_C(lib9p_srv_file, struct uptime_file, uptime_file, static);
-
-struct uptime_fio {
- struct uptime_file *parent;
- size_t buf_len;
- char buf[24]; /* len(str(UINT64_MAX)+"ns\n\0") */
-};
-
-LO_IMPLEMENTATION_H(lib9p_srv_fio, struct uptime_fio, uptime_fio);
-LO_IMPLEMENTATION_C(lib9p_srv_fio, struct uptime_fio, uptime_fio, static);
-
-/* srv_file *******************************************************************/
-
-static void uptime_file_free(struct uptime_file *self) {
- assert(self);
-}
-static struct lib9p_qid uptime_file_qid(struct uptime_file *self) {
- assert(self);
-
- return (struct lib9p_qid){
- .type = LIB9P_QT_FILE,
- .vers = 1,
- .path = self->pathnum,
- };
-}
-
-static struct lib9p_stat uptime_file_stat(struct uptime_file *self, struct lib9p_srv_ctx *ctx) {
- assert(self);
- assert(ctx);
-
- uint64_t now = LO_CALL(bootclock, get_time_ns);
- uint64_t size = 0;
- while (now) {
- size++;
- now /= 10;
- }
- if (!size)
- size++;
- size += 3;
-
- return (struct lib9p_stat){
- .kern_type = 0,
- .kern_dev = 0,
- .file_qid = uptime_file_qid(self),
- .file_mode = 0444,
- .file_atime = UTIL9P_ATIME,
- .file_mtime = UTIL9P_MTIME,
- .file_size = size,
- .file_name = lib9p_str(self->name),
- .file_owner_uid = lib9p_str("root"),
- .file_owner_gid = lib9p_str("root"),
- .file_last_modified_uid = lib9p_str("root"),
- .file_extension = lib9p_str(NULL),
- .file_owner_n_uid = 0,
- .file_owner_n_gid = 0,
- .file_last_modified_n_uid = 0,
- };
-}
-static void uptime_file_wstat(struct uptime_file *self, struct lib9p_srv_ctx *ctx,
- struct lib9p_stat) {
- assert(self);
- assert(ctx);
-
- lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem");
-}
-static void uptime_file_remove(struct uptime_file *self, struct lib9p_srv_ctx *ctx) {
- assert(self);
- assert(ctx);
-
- lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem");
-}
-
-LIB9P_SRV_NOTDIR(struct uptime_file, uptime_file);
-
-static lo_interface lib9p_srv_fio uptime_file_fopen(struct uptime_file *self, struct lib9p_srv_ctx *ctx,
- bool LM_UNUSED(rd), bool LM_UNUSED(wr), bool LM_UNUSED(trunc)) {
- assert(self);
- assert(ctx);
-
- struct uptime_fio *ret = malloc(sizeof(struct uptime_fio));
- ret->parent = self;
- ret->buf_len = 0;
-
- return lo_box_uptime_fio_as_lib9p_srv_fio(ret);
-}
-
-/* srv_fio ********************************************************************/
-
-static uint32_t uptime_fio_iounit(struct uptime_fio *self) {
- assert(self);
- return sizeof(self->buf)-1;
-}
-
-static void uptime_fio_iofree(struct uptime_fio *self) {
- assert(self);
- free(self);
-}
-
-static struct lib9p_qid uptime_fio_qid(struct uptime_fio *self) {
- assert(self);
- assert(self->parent);
- return uptime_file_qid(self->parent);
-}
-
-static void uptime_fio_pread(struct uptime_fio *self, struct lib9p_srv_ctx *ctx,
- uint32_t byte_count, uint64_t byte_offset,
- struct iovec *ret) {
- assert(self);
- assert(ctx);
- assert(ret);
-
- if (byte_offset == 0 || self->buf_len == 0) {
- uint64_t now = LO_CALL(bootclock, get_time_ns);
- self->buf_len = snprintf(self->buf, sizeof(self->buf), "%"PRIu64"ns\n", now);
- }
-
- if (byte_offset > (uint64_t)self->buf_len) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EINVAL, "offset is past end-of-file length");
- return;
- }
-
- size_t beg_off = (size_t)byte_offset;
- size_t end_off = beg_off + (size_t)byte_count;
- if (end_off > self->buf_len)
- end_off = self->buf_len;
- *ret = (struct iovec){
- .iov_base = &self->buf[beg_off],
- .iov_len = end_off-beg_off,
- };
-}
-
-static uint32_t uptime_fio_pwrite(struct uptime_fio *self, struct lib9p_srv_ctx *ctx,
- void *LM_UNUSED(buf),
- uint32_t LM_UNUSED(byte_count),
- uint64_t LM_UNUSED(byte_offset)) {
- assert(self);
- assert(ctx);
-
- lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem");
- return 0;
-}
diff --git a/cmd/sbc_harness/fs_harness_uptime_txt.h b/cmd/sbc_harness/fs_harness_uptime_txt.h
deleted file mode 100644
index 7bf2945..0000000
--- a/cmd/sbc_harness/fs_harness_uptime_txt.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* sbc_harness/fs_harness_uptime_txt.h - 9P access to harness uptime
- *
- * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#ifndef _SBC_HARNESS_FS_HARNESS_UPTIME_TXT_H_
-#define _SBC_HARNESS_FS_HARNESS_UPTIME_TXT_H_
-
-#include <lib9p/srv.h>
-
-struct uptime_file {
- char *name;
- uint64_t pathnum;
-};
-LO_IMPLEMENTATION_H(lib9p_srv_file, struct uptime_file, uptime_file);
-#define lo_box_uptime_file_as_lib9p_srv_file(obj) util9p_box(uptime_file, obj)
-
-#endif /* _SBC_HARNESS_FS_HARNESS_UPTIME_TXT_H_ */
diff --git a/cmd/sbc_harness/main.c b/cmd/sbc_harness/main.c
deleted file mode 100644
index 5630e83..0000000
--- a/cmd/sbc_harness/main.c
+++ /dev/null
@@ -1,253 +0,0 @@
-/* sbc_harness/main.c - Main entry point and event loop for sbc-harness
- *
- * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-/* libc */
-#include <string.h> /* libc: for strlen() */
-
-/* pico-sdk */
-#include <pico/stdio_uart.h> /* pico-sdk:pico_stdio_uart: for stdio_uart_init() */
-#include <hardware/flash.h> /* pico-sdk:hardware_flash: for flash_get_unique_id() */
-
-/* our OS */
-#include <libcr/coroutine.h>
-#include <libhw/generic/alarmclock.h> /* so we can set `bootclock` */
-#include <libhw/rp2040_hwspi.h>
-#include <libhw/rp2040_hwtimer.h>
-#include <libhw/w5500.h>
-
-/* our application libraries */
-#include <libdhcp/client.h>
-#include <libusb/usb_common.h>
-#include <lib9p/srv.h>
-#include <util9p/static.h>
-
-/* our utility libraries */
-#include <libmisc/hash.h>
-#define LOG_NAME MAIN
-#include <libmisc/log.h>
-
-/* local headers */
-#include "usb_keyboard.h"
-#include "static.h"
-#include "fs_harness_flash_bin.h"
-#include "fs_harness_uptime_txt.h"
-
-/* configuration **************************************************************/
-
-#include "config.h"
-
-#ifndef _CONFIG_9P_MAX_CONNS
- #error config.h must define _CONFIG_9P_MAX_CONNS
-#endif
-#ifndef _CONFIG_9P_MAX_REQS
- #error config.h must define _CONFIG_9P_MAX_REQS
-#endif
-
-/* file tree ******************************************************************/
-
-enum { PATH_BASE = __COUNTER__ };
-#define PATH_COUNTER __COUNTER__ - PATH_BASE
-
-#define STATIC_FILE(STRNAME, ...) UTIL9P_STATIC_FILE(PATH_COUNTER, STRNAME, __VA_ARGS__)
-#define STATIC_DIR(STRNAME, ...) UTIL9P_STATIC_DIR(PATH_COUNTER, STRNAME, __VA_ARGS__)
-
-#define API_FILE(STRNAME, SYMNAME, ...) \
- lo_box_##SYMNAME##_file_as_lib9p_srv_file(&((struct SYMNAME##_file){ \
- .name = STRNAME, \
- .pathnum = PATH_COUNTER \
- __VA_OPT__(,) __VA_ARGS__ \
- }))
-
-struct lib9p_srv_file root =
- STATIC_DIR("",
- STATIC_DIR("Documentation",
- STATIC_FILE("YOUR_RIGHTS_AND_OBLIGATIONS.md",
- .data_start = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_md_start,
- .data_end = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_md_end),
- STATIC_DIR("YOUR_RIGHTS_AND_OBLIGATIONS",
- STATIC_FILE("agpl-3.0.txt",
- .data_start = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_agpl_3_0_txt_start,
- .data_end = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_agpl_3_0_txt_end),
- STATIC_FILE("pico-sdk.bsd3.txt",
- .data_start = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_pico_sdk_bsd3_txt_start,
- .data_end = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_pico_sdk_bsd3_txt_end),
- STATIC_FILE("printf.mit.txt",
- .data_start = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_printf_mit_txt_start,
- .data_end = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_printf_mit_txt_end),
- STATIC_FILE("tinyusb.mit.txt",
- .data_start = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_tinyusb_mit_txt_start,
- .data_end = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_tinyusb_mit_txt_end),
- STATIC_FILE("newlib.txt",
- .data_start = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_newlib_txt_start,
- .data_end = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_newlib_txt_end),
- ),
- STATIC_FILE("harness_rom_bin.txt",
- .data_start = _binary_static_Documentation_harness_rom_bin_txt_start,
- .data_end = _binary_static_Documentation_harness_rom_bin_txt_end),
- STATIC_FILE("harness_flash_bin.txt",
- .data_start = _binary_static_Documentation_harness_flash_bin_txt_start,
- .data_end = _binary_static_Documentation_harness_flash_bin_txt_end),
- STATIC_FILE("harness_uptime_txt.txt",
- .data_start = _binary_static_Documentation_harness_uptime_txt_txt_start,
- .data_end = _binary_static_Documentation_harness_uptime_txt_txt_end),
- ),
- STATIC_DIR("harness",
- STATIC_FILE("rom.bin",
- .data_start = (void*)0x00000000,
- .data_size = 16*1024),
- API_FILE("flash.bin",
- flash),
- API_FILE("uptime.txt",
- uptime),
- // TODO: system.log
- // TODO: proc.txt
- // TODO: cpuinfo.txt
- // TODO: ctl
- ),
- STATIC_DIR("dut",
- // TODO: hdmi.nut
- // TODO: uart.txt
- // TODO: usb-keyboard.txt
- ),
- );
-
-static lo_interface lib9p_srv_file get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) {
- return root;
-}
-
-/* Code ***********************************************************************/
-
-/*
-static COROUTINE hello_world_cr(void *_chan) {
- const char *msg = "Hello world!\n";
- usb_keyboard_rpc_t *chan = _chan;
- cr_begin();
-
- for (size_t i = 0;; i = (i+1) % strlen(msg)) {
- int result = usb_keyboard_rpc_send_req(chan, (uint32_t)msg[i]);
- if (result < 1) {
- errorf("error sending rune U+%d", (uint32_t)msg[i]);
- break;
- }
- }
-
- cr_end();
-}
-*/
-
-struct {
- struct rp2040_hwspi dev_spi;
- struct w5500 dev_w5500;
- usb_keyboard_rpc_t keyboard_chan;
- uint16_t usb_serial[sizeof(uint64_t)*2]; /* UTF-16 */
- struct lib9p_srv srv;
-} globals;
-
-static COROUTINE dhcp_cr(void *) {
- cr_begin();
-
- dhcp_client_main(lo_box_w5500_if_as_net_iface(&globals.dev_w5500), "harness");
-
- cr_end();
-}
-
-static COROUTINE read9p_cr(void *) {
- cr_begin();
-
- lo_interface net_iface iface = lo_box_w5500_if_as_net_iface(&globals.dev_w5500);
- lo_interface net_stream_listener listener = LO_CALL(iface, tcp_listen, LIB9P_DEFAULT_PORT_9FS);
-
- lib9p_srv_accept_and_read_loop(&globals.srv, listener);
-
- cr_end();
-}
-
-static COROUTINE write9p_cr(void *) {
- cr_begin();
-
- lib9p_srv_worker_loop(&globals.srv);
-
- cr_end();
-}
-
-const char *const hexdig = "0123456789ABCDEF";
-static_assert(_CONFIG_9P_MAX_REQS <= 16);
-
-COROUTINE init_cr(void *) {
- cr_begin();
-
- /* NOR flash chips have a (bog-?)standard "RUID" "Read Unique
- * ID" instruction; use our flash chip's unique ID as the
- * basis for our serial numbers. */
- uint64_t flash_id64;
- static_assert(sizeof(flash_id64) == FLASH_UNIQUE_ID_SIZE_BYTES);
- flash_get_unique_id((uint8_t *)&flash_id64);
- uint32_t flash_id32 = hash(&flash_id64, sizeof(flash_id64));
- static_assert(sizeof(flash_id32) == sizeof(hash(NULL, 0)));
- uint8_t flash_id24[3] = {
- (uint8_t)((flash_id32 >> 16) & 0xFF),
- (uint8_t)((flash_id32 >> 8) & 0xFF),
- (uint8_t)((flash_id32 >> 0) & 0xFF),
- };
-
- rp2040_hwspi_init(&globals.dev_spi, "W5500", RP2040_HWSPI_0,
- SPI_MODE_0, /* the W5500 supports mode 0 or mode 3 */
- 42500000, /* min(w5500, hwspi); w5500=80MHz; hwspi=42.5MHz, see rp2040_hwspi.h for a comment about why this is so low */
- 30, /* W5500 datasheet says min(T_CS = SCSn High Time) = 30ns */
- 0, /* bogus write write data when doing a read */
- 16, /* PIN_MISO */
- 19, /* PIN_MOSI */
- 18, /* PIN_CLK */
- 17, /* PIN_CS */
- 0, 1, 2, 3); /* DMA channels */
- w5500_init(&globals.dev_w5500, "W5500",
- lo_box_rp2040_hwspi_as_spi(&globals.dev_spi),
- 21, /* PIN_INTR */
- 20, /* PIN_RESET */
- ((struct net_eth_addr){{
- /* vendor ID: "Wiznet" */
- 0x00, 0x08, 0xDC,
- /* serial number */
- flash_id24[0], flash_id24[1], flash_id24[2],
- }}));
-
- static_assert(sizeof(flash_id64)*2 == LM_ARRAY_LEN(globals.usb_serial));
- for (size_t i = 0; i < LM_ARRAY_LEN(globals.usb_serial); i++)
- globals.usb_serial[i] = hexdig[(flash_id64 >> ((sizeof(flash_id64)*8)-((i+1)*4))) & 0xF];
- usb_common_earlyinit(globals.usb_serial, sizeof(globals.usb_serial));
- usb_keyboard_init();
- usb_common_lateinit();
-
- globals.keyboard_chan = (usb_keyboard_rpc_t){0};
-
- globals.srv.rootdir = get_root;
-
- /* set up coroutines **************************************************/
- coroutine_add("usb_common", usb_common_cr, NULL);
- coroutine_add("usb_keyboard", usb_keyboard_cr, &globals.keyboard_chan);
- //coroutine_add("hello_world", hello_world_cr, &globals.keyboard_chan);
- coroutine_add("dhcp", dhcp_cr, NULL);
- for (int i = 0; i < _CONFIG_9P_MAX_CONNS; i++) {
- char name[] = {'r', 'e', 'a', 'd', '-', hexdig[i], '\0'};
- coroutine_add(name, read9p_cr, NULL);
- }
- for (int i = 0; i < _CONFIG_9P_MAX_REQS; i++) {
- char name[] = {'w', 'r', 'i', 't', 'e', '-', hexdig[i], '\0'};
- coroutine_add(name, write9p_cr, NULL);
- }
-
- cr_exit();
-}
-
-int main() {
- bootclock = rp2040_hwtimer(0);
- stdio_uart_init();
- /* char *hdr = "=" * (80-strlen("info : MAIN: ")); */
- infof("===================================================================");
- coroutine_add("init", init_cr, NULL);
- coroutine_main();
- assert_notreached("all coroutines exited");
-}
diff --git a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS.md b/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS.md
deleted file mode 100644
index b3fc12e..0000000
--- a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS.md
+++ /dev/null
@@ -1,29 +0,0 @@
-<!--
- Documentation/YOUR_RIGHTS_AND_OBLIGATIONS.md - Overview of your
- rights and obligations with regard to the SBC-Harness firmware
-
- Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- SPDX-License-Identifier: AGPL-3.0-or-later
--->
-
-The firmware running on the SBC-Harness is Free Software -- if you
-have access to this file, then you have the freedom to use, study,
-share, and improve the firmware; as long as you follow a few
-conditions that basically amount to "paying it forward".
-
-The precise terms of your rights and obligations are given in the
-files in the `YOUR_RIGHTS_AND_OBLIGATIONS/` directory. You must obey
-each of the files in that directory when distributing
-verbatim-or-modified copies of the firmware:
-
- - `agpl-3.0.txt`: The firmware is as-a-whole licensed to you under
- the terms of the GNU Affero General Public License (GNU AGPL) as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version. This is the main
- document that protects your rights and defines your obligations.
-
- - other files: The firmware makes use of other code that is under
- various other licenses. When taken with the AGPL, they amount to
- requiring that you pass along the copyright and license text in
- those files when you distribute verbatim-or-modified copies of the
- firmware.
diff --git a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/agpl-3.0.txt b/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/agpl-3.0.txt
deleted file mode 120000
index 8a9b6f3..0000000
--- a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/agpl-3.0.txt
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../COPYING.txt \ No newline at end of file
diff --git a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/newlib.txt b/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/newlib.txt
deleted file mode 120000
index 5c5939c..0000000
--- a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/newlib.txt
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../3rd-party/COPYING.newlib.txt \ No newline at end of file
diff --git a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/pico-sdk.bsd3.txt b/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/pico-sdk.bsd3.txt
deleted file mode 120000
index 52c4374..0000000
--- a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/pico-sdk.bsd3.txt
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../3rd-party/pico-sdk/LICENSE.TXT \ No newline at end of file
diff --git a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/printf.mit.txt b/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/printf.mit.txt
deleted file mode 120000
index 5a6e342..0000000
--- a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/printf.mit.txt
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../3rd-party/pico-sdk/src/rp2_common/pico_printf/LICENSE \ No newline at end of file
diff --git a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/tinyusb.mit.txt b/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/tinyusb.mit.txt
deleted file mode 120000
index 22a67cf..0000000
--- a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/tinyusb.mit.txt
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../3rd-party/pico-sdk/lib/tinyusb/LICENSE \ No newline at end of file
diff --git a/cmd/sbc_harness/static/Documentation/harness_flash_bin.txt b/cmd/sbc_harness/static/Documentation/harness_flash_bin.txt
deleted file mode 100644
index 115f2ee..0000000
--- a/cmd/sbc_harness/static/Documentation/harness_flash_bin.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-NAME
- /harness/flash.bin
-
-DESCRIPTION
- Access to the flash storage chip (where the harness firmware
- is stored).
-
- Any number of readers may read the flash contents.
-
- Only one writer can have the file open at a time; once the
- file is closed, the harness reboots into the new firmware.
- Writes to the top half of the chip will fail.
-
-BUGS
- - The size of the chip is configured at compile-time. If the
- firmware is loaded onto hardware with a larger flash chip
- than it was compiled for, then the upper part of the chip
- will not be accessible with this file. If the firmware is
- loaded onto hardware with a smaller flash chip than it was
- compiled for, then accessing the missing upper part of the
- chip will crash.
-
- - When writing to the flash using this file, only half of the
- chip capacity is usable; the top half and bottom half are
- mirrors of each-other. This is to avoid the firmware
- crashing as its program text is overwritten; the firmware is
- executing out of the bottom half, and writing to the top
- half; once the file is closed, a minimal in-RAM function
- copies the top half to the bottom half and reboots.
-
-AUTHOR
- Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/cmd/sbc_harness/static/Documentation/harness_rom_bin.txt b/cmd/sbc_harness/static/Documentation/harness_rom_bin.txt
deleted file mode 100644
index 63fd0a3..0000000
--- a/cmd/sbc_harness/static/Documentation/harness_rom_bin.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-NAME
- /harness/rom.bin
-
-DESCRIPTION
- Read access to the RP2040 CPU's ROM. This contains code that
- initializes the chip to load the main firmware from the
- external flash chip, provides a failsafe USB-programmable
- mode, and provides a few functions that the main firmware can
- call to.
-
-BUGS
- This ROM is programmed into the chip at the factory; revising
- it means issuing a new revison of the RP2040 CPU. So while
- the source code to the ROM is freely available to be used,
- studied, and shared; one cannot install modified versions onto
- the CPU.
-
-HISTORY
- - RP2040 B0 : chips manufactured before September 2020 or so
- - RP2040 B1 : chips manufactured after September 2020 or so
- - Released to the public January 2021; chance whether you get
- a B0 or a B1 chip.
- - RP2040 B2 : released September 2021
-
- Printed on the physical CPU is a label that indicates which
- revision it is. For example:
-
- RP2-B2 21/24
-
- indicates that it is the "B2" revision (and was manufactured
- the 21st week (late May) of 2024).
-
-SEE ALSO
- - /harness/cpuinfo.txt can report which CPU version you have.
-
- - The source code to each ROM revision is published at
- https://github.com/raspberrypi/pico-bootrom-rp2040
-
-AUTHOR
- Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/cmd/sbc_harness/static/Documentation/harness_uptime_txt.txt b/cmd/sbc_harness/static/Documentation/harness_uptime_txt.txt
deleted file mode 100644
index 1ab86f7..0000000
--- a/cmd/sbc_harness/static/Documentation/harness_uptime_txt.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-NAME
- /harness/uptime.txt
-
-DESCRIPTION
- Reading this file gives a text string of the format
- `sprintf("%uns\n", uptime_ns)` indicating the harness's uptime
- in an integer number of nanoseconds.
-
-BUGS
- Using nanoseconds gives the illusion of more precision than
- there actually is; the harness' clock only has microsecond
- resolution; the last 3 digits of the returned nanosecond count
- will always be 0.
-
-AUTHOR
- Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/cmd/sbc_harness/tusb_log.c b/cmd/sbc_harness/tusb_log.c
deleted file mode 100644
index 4c6b7df..0000000
--- a/cmd/sbc_harness/tusb_log.c
+++ /dev/null
@@ -1,15 +0,0 @@
-/* sbc_harness/tusb_log.c - Logger for tusb_config.h
- *
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#define LOG_NAME TINY_USB
-#include <libmisc/log.h>
-
-void _libmisc_tu_mess_failed(const char *expr,
- const char *file, unsigned int line, const char *func) {
- errorf("%s:%u:%s(): assertion \"%s\" failed",
- file, line, func,
- expr);
-}
diff --git a/cmd/sbc_harness/usb_keyboard.c b/cmd/sbc_harness/usb_keyboard.c
deleted file mode 100644
index 7dd8a24..0000000
--- a/cmd/sbc_harness/usb_keyboard.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/* sbc_harness/usb_keyboard.c - Implementation of a USB keyboard device
- *
- * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#include <tusb.h>
-
-#include <libusb/tusb_helpers.h> /* for TUD_ENDPOINT_IN */
-#include <libusb/usb_common.h>
-#include <libmisc/macro.h>
-
-#include "usb_keyboard.h"
-
-/**
- * A USB-HID "Report Descriptor" (see USB-HID 1.11 §6.2.2 "Report
- * Descriptor") describing a keyboard.
- */
-static uint8_t const hid_report_descriptor_keyboard[] = { TUD_HID_REPORT_DESC_KEYBOARD() };
-
-static uint8_t kbd_ifc = 0;
-
-void usb_keyboard_init() {
- if (kbd_ifc)
- return;
-
- kbd_ifc = usb_add_interface(cfgnum_std, TUD_HID_DESC_LEN, (uint8_t[]){
- /* USB-HID input-only descriptor for inclusion in the config descriptor; consisting of 3 parts:
- * 1. an interface descriptor (USB 2.0 §9.6.5 "Interface"),
- * 2. a class-specific (class=HID) descriptor of type HID (USB-HID 1.11 §6.2.1 "HID Descriptor"),
- * 3. an endpoint descriptor for inputs (USB 2.0 §9.6.6 "Endpoint").
- * The TUD_HID_DESCRIPTOR() macro takes care of this for us. */
- TUD_HID_DESCRIPTOR(
- 0, /* interface : bInterfaceNumber ; Number of this interface (0-indexed) */
- STRID_KBD_IFC, /* interface : iInterface ; Index of string descriptor describing this interface */
- HID_ITF_PROTOCOL_KEYBOARD, /* interface : bInterfaceProtocol ; see USB-HID 1.11 §4.3 "Protocols" */
- sizeof(hid_report_descriptor_keyboard), /* hid : wDescriptorLength ; Total size of report descriptor */
- TUD_ENDPOINT_IN | 1, /* endpoint : bEndpointAddress ; Direction | endpoint number (arbitrary?) */
- CFG_TUD_HID_EP_BUFSIZE, /* endpoint : wMaxPacketSize ; Maximum packet size this endpoint is capable of sending or receiving */
- 10), /* endpoint : bInterval ; poll interval (in milliseconds?) */
- });
-}
-
-static uint8_t ascii2keycode[128][2] = { HID_ASCII_TO_KEYCODE };
-
-COROUTINE usb_keyboard_cr(void *_chan) {
- usb_keyboard_rpc_t *chan = _chan;
- cr_begin();
-
- uint8_t report_id = 0;
- uint8_t modifier = 0;
- uint8_t keycodes[6] = {0};
- for (;;) {
- while (!tud_hid_n_ready(kbd_ifc))
- cr_yield();
-
- if (cr_rpc_can_recv_req(chan)) {
- usb_keyboard_rpc_req_t req = cr_rpc_recv_req(chan);
- uint32_t rune = req.req;
-
- modifier = ascii2keycode[rune][0] ? KEYBOARD_MODIFIER_LEFTSHIFT : 0;
- keycodes[0] = ascii2keycode[rune][1];
- tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes);
-
- while (!tud_hid_n_ready(kbd_ifc))
- cr_yield();
-
- modifier = 0;
- keycodes[0] = 0;
- tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes);
-
- cr_rpc_send_resp(req, 1);
- } else {
- modifier = 0;
- keycodes[0] = 0;
- tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes);
- }
- }
-
- cr_end();
-}
-
-/**
- * Return a pointer to the HID "Report Descriptor" (see USB-HID 1.11
- * §6.2.2 "Report Descriptor") for the given index.
- */
-uint8_t const *tud_hid_descriptor_report_cb(uint8_t index) {
- static uint8_t const *reports[] = {
- hid_report_descriptor_keyboard,
- };
- if (index >= TU_ARRAY_SIZE(reports))
- return NULL;
- return reports[index];
-}
-
-uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
-{
- // TODO not implemented
- (void) instance;
- (void) report_id;
- (void) report_type;
- (void) buffer;
- (void) reqlen;
-
- return 0;
-}
-
-// Invoked when received SET_REPORT control request or
-// received data on OUT endpoint ( Report ID = 0, Type = 0 )
-void tud_hid_set_report_cb(uint8_t LM_UNUSED(instance),
- uint8_t LM_UNUSED(report_id),
- hid_report_type_t LM_UNUSED(report_type),
- uint8_t const *LM_UNUSED(buffer),
- uint16_t LM_UNUSED(bufsize))
-{
- // TODO not implemented
-}
diff --git a/cmd/sbc_harness/usb_keyboard.h b/cmd/sbc_harness/usb_keyboard.h
deleted file mode 100644
index cf8483b..0000000
--- a/cmd/sbc_harness/usb_keyboard.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* sbc_harness/usb_keyboard.h - Implementation of a USB keyboard device
- *
- * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#ifndef _SBC_HARNESS_USB_KEYBOARD_H_
-#define _SBC_HARNESS_USB_KEYBOARD_H_
-
-#include <stdint.h> /* for uint32_t */
-
-#include <libcr/coroutine.h> /* for COROUTINE */
-#include <libcr_ipc/rpc.h> /* for CR_RPC_DECLARE */
-
-CR_RPC_DECLARE(usb_keyboard_rpc, uint32_t, int);
-
-void usb_keyboard_init(void);
-COROUTINE usb_keyboard_cr(void *arg);
-
-#endif /* _SBC_HARNESS_USB_KEYBOARD_H_ */