Repository navigation
Add remote write head #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
c868b30
b9dd92c
1c0651d
d40f619
420dd75
d1b6810
5e44128
520a9cd
68db822
85d0ad0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| *.o | ||
| flswh-* | ||
| stubs/*.so_stub.so* |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| FROM fedora:latest | ||
|
|
||
| # gcc: native compiler (runs the native test; system headers) | ||
| # gcc-aarch64-linux-gnu: cross compiler (provides aarch64-linux-gnu-gcc) | ||
| # binutils-aarch64-linux-gnu: GNU ld (provides aarch64-linux-gnu-ld) | ||
| # python3: runs stubs/so_stub.py; make: the build itself | ||
| RUN dnf install -y gcc gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu python3 make \ | ||
| && dnf clean all | ||
|
|
||
| # The Makefile and so_stub.py hardcode the QNX-style tool name; map it | ||
| # to Fedora's. (ld.lld is already named correctly by the lld package.) | ||
| RUN ln -s /usr/bin/aarch64-linux-gnu-gcc /usr/local/bin/aarch64-elf-gcc |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| # fls-wh — a block-device write head, built for a QNX aarch64 target. | ||
| # | ||
| # Built from: | ||
| # - this source (fls-wh.c, start.S) | ||
| # - standard C/POSIX headers (include/) | ||
| # - a minimal JSON symbol manifest (stubs/*.min.json) <- source of truth | ||
| # - open tooling: aarch64-elf-gcc (GCC) + ld.lld (LLVM) + stubs/so_stub.py | ||
| # | ||
| # The stub .so files are build artifacts (gitignored). At runtime, the | ||
| # target's dynamic linker resolves the SONAME (libc.so.5) to the library | ||
| # present on the system. | ||
| # | ||
| # Container build: `make container-build` builds the Containerfile with | ||
| # podman and runs the whole build inside it (fedora + cross toolchain). | ||
| # | ||
| # `make help` prints this file's `##`-annotated targets, grouped by | ||
| # `##@` section headers. | ||
|
|
||
| CC := aarch64-elf-gcc | ||
| LD := ld.lld | ||
| CFLAGS := -I include | ||
| LDFLAGS := -dynamic-linker /usr/lib/ldqnx-64.so.2 | ||
| STUBDIR := stubs | ||
|
|
||
| CONTAINER ?= podman | ||
| IMAGE ?= fls-wh-builder | ||
|
|
||
| # host arch/os for the native binary name (flswh-<arch>-<os>) | ||
| UNAME_M := $(shell uname -m) | ||
| UNAME_S := $(shell uname -s) | ||
| NATIVE_ARCH := $(if $(filter arm64,$(UNAME_M)),aarch64,$(UNAME_M)) | ||
| NATIVE_OS := $(if $(filter Darwin,$(UNAME_S)),darwin,$(if $(filter Linux,$(UNAME_S)),linux,$(UNAME_S))) | ||
| NATIVE_BIN := flswh-$(NATIVE_ARCH)-$(NATIVE_OS) | ||
|
|
||
| .PHONY: all clean stubs native container container-build test help | ||
|
|
||
| ##@ build | ||
| all: flswh-aarch64-qnx7 ## build fls-wh for QNX aarch64 (default) | ||
|
|
||
| flswh-aarch64-qnx7: fls-wh.o start.o stubs ## link the QNX aarch64 binary | ||
| $(LD) -o $@ fls-wh.o start.o -L$(STUBDIR) -l:libc.min.so_stub.so $(LDFLAGS) | ||
|
|
||
| native: $(NATIVE_BIN) ## build fls-wh for the host (system compiler, no stubs) | ||
|
|
||
| $(NATIVE_BIN): fls-wh.c | ||
| cc -O2 $< -o $@ | ||
|
|
||
| # build the minimal stub .so from the minimal JSON (artifacts, gitignored) | ||
| stubs: ## build the stub .so files from the JSON manifests | ||
| python3 stubs/so_stub.py $(STUBDIR)/libc.min.json -o $(STUBDIR)/libc.min.so_stub.so | ||
|
|
||
| fls-wh.o: fls-wh.c | ||
| $(CC) $(CFLAGS) -c $< -o $@ | ||
|
|
||
| start.o: start.S | ||
| $(CC) -c $< -o $@ | ||
|
|
||
| clean: ## remove all build artifacts | ||
| rm -f flswh-* fls-wh.o start.o $(STUBDIR)/*.so_stub.so* | ||
|
|
||
| ##@ test | ||
| test: ## native test: build with the system compiler, run, assert | ||
| python3 test.py | ||
|
|
||
| ##@ container (podman) | ||
| container: ## build the fedora container image | ||
| $(CONTAINER) build -t $(IMAGE) . | ||
|
|
||
| container-build: container ## build fls-wh inside the container (GNU ld) | ||
| $(CONTAINER) run --rm -v $(PWD):/src -w /src $(IMAGE) make \ | ||
| LD=aarch64-linux-gnu-ld STUB_LD=aarch64-linux-gnu-ld | ||
|
|
||
| help: ## show this help | ||
| @awk 'BEGIN {FS = ":.*##"} \ | ||
| /^##@/ { printf "\n\033[1;33m%s\033[0m\n", substr($$0, 5) } \ | ||
| /^[a-zA-Z0-9_-]+:.*##/ { printf " \033[36m%-18s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| # fls-wh — the remote write head | ||
|
|
||
| `fls-wh` is a small C program that runs on a remote system (QNX today; | ||
| extensible to others, e.g. a U-Boot command talking over the network) and | ||
| writes framed commands to a raw block device (e.g. `/dev/emmc0`). It is the | ||
| remote counterpart of the local writer in `src/fls/block_writer.rs` (which | ||
| uses `O_DIRECT` on Linux/macOS). QNX has no `O_DIRECT`, so durability comes | ||
| from an explicit `SYNC` (`fdatasync`; `fsync` on macOS, which has no | ||
| `fdatasync`). | ||
|
|
||
| ## Usage | ||
|
|
||
| ``` | ||
| ./flswh-<arch>-<os> <device> | ||
| ``` | ||
|
|
||
| Opens `<device>` (`O_RDWR`), reports its size (`READY`), then reads framed | ||
| commands from stdin and writes them to the device, emitting framed records to | ||
| stdout. Intended to be driven by a remote client (e.g. over SSH). QUIT or | ||
| EOF exits. | ||
| Device I/O errors are reported (`ERR`) and processing continues. | ||
|
|
||
| ## Protocol | ||
|
|
||
| Frame (both directions): `[magic:4][opcode:1][payload_len:u32 LE][payload]`, | ||
| little-endian throughout. The magic (`FLSW`) is a sync header: the reader | ||
| scans for it to resync after any corruption. | ||
|
|
||
| | | opcode | | opcode | | ||
| |---|---|---|---| | ||
| | **Requests** | `DATA 0x01` `SKIP 0x02` `SEEK 0x03` `SYNC 0x04` `QUIT 0x05` `READ 0x06` `ZERO 0x09` `SIZE 0x0a` | **Responses** | `READY 0x81` `OK 0x82` `PROG 0x83` `ERR 0x84` `DONE 0x85` `READ_DATA 0x86` `SIZE 0x89` | | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SKIP can droppped, no?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. true, because I designed it independently of the fls integration I probably added unnecessary stuff like this |
||
| | **Reserved** | `AUTH 0x07` `HELLO 0x08` | | `AUTH_RESULT 0x87` `HELLO 0x88` | | ||
|
|
||
| The `READY` payload is `version:u8 + size:u64` (total device bytes, measured | ||
| at open); the protocol version is currently 1. `DATA` is | ||
| `size:u32 + content + crc:u32` (CRC32-IEEE); | ||
| `READ` is `len:u64` (reads from the current offset, advances it, capped at | ||
| 1 MiB) and returns `READ_DATA` with the bytes. `ZERO` is `len:u64` — writes | ||
| that many zeros from the current offset and advances it, sending only the 8 | ||
| length bytes over the wire (for filling regions without transferring bytes). | ||
|
|
||
| `SIZE` has no request payload and returns `SIZE 0x89` with `size:u64` (the | ||
| same total device bytes measured at open), without changing the cursor. If | ||
| the size could not be determined, it returns `ERR` with the original errno; | ||
| the startup `READY` uses zero for unknown size. | ||
| Before writing an image, the client can use `READY` or `SIZE` to check | ||
| `image_size <= device_size - write_offset` after checking that | ||
| `write_offset <= device_size`. For sparse images, compare the expanded size. | ||
|
|
||
| ## Build | ||
|
|
||
| Binaries are named `flswh-<arch>-<os>` (matching the `fls` artifact scheme): | ||
|
|
||
| - **QNX aarch64** (cross): `make` (or `make -C remote` from the repo root) → `flswh-aarch64-qnx7`. Needs an aarch64 cross gcc toolchain (the Makefile's `aarch64-elf-gcc` + `ld.lld` names map to any gcc cross toolchain; `make container-build` uses Fedora's in a container). | ||
| - **Native** (host, incl. macOS): `make native` → `flswh-<arch>-<os>` (e.g. `flswh-aarch64-darwin`, `flswh-x86_64-linux`). Uses the system compiler and system headers, no stubs. | ||
|
|
||
| ## Test | ||
|
|
||
| `python3 test.py` — builds the source with the system compiler, drives it with | ||
| a framed command script against a temp file, and asserts the records and bytes. | ||
Uh oh!
There was an error while loading. Please reload this page.