From 9fde94d068f87b34e0bc6bfa48388d89bb54f1e4 Mon Sep 17 00:00:00 2001 From: salmonik Date: Mon, 3 Aug 2026 02:23:35 +0200 Subject: v0.5.8: heap-free QR encoder + crash-dump QR on framebuffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Real hardware has no serial console, so a kernel crash only leaves a frozen screen. Every dump_lines() report now also renders the crash text as a scannable QR below the white-on-red band (photograph the screen instead of relaying text). - rsnix/src/qr.rs: from-scratch no_std/no_alloc byte-mode QR encoder (EC-L, v1..v40, .bss statics only — safe on the fault path): RS over GF(256), codeword interleave, zigzag placement, 8 masks with N1-N4 penalty auto-selection, format/version info. - gop.rs: dump_qr() joins dump lines into a static buffer, truncates with '...' at the v40-L capacity, encodes, and renders centered black-on-white with a 4-module quiet zone. - tools/qrcheck: host harness (embedds qr.rs) + qrcheck.py cross-check against segno's placement primitives. Verified bit-exact: 12 versions x 8 masks forced, plus auto-mask choice matches segno's penalty evaluation. Caught 3 encoder bugs (multi-block interleave offsets, transposed version info, mask eval ordering). - QEMU e2e: page-fault dump screendump decodes via zbarimg, content matches the serial log line-for-line. - test-msg.sh and test-fault.sh both PASS; debug+release 0 warnings. --- tools/qrcheck/.gitignore | 1 + tools/qrcheck/Cargo.lock | 7 ++++++ tools/qrcheck/Cargo.toml | 13 +++++++++++ tools/qrcheck/src/main.rs | 58 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 tools/qrcheck/.gitignore create mode 100644 tools/qrcheck/Cargo.lock create mode 100644 tools/qrcheck/Cargo.toml create mode 100644 tools/qrcheck/src/main.rs (limited to 'tools/qrcheck') diff --git a/tools/qrcheck/.gitignore b/tools/qrcheck/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/tools/qrcheck/.gitignore @@ -0,0 +1 @@ +/target diff --git a/tools/qrcheck/Cargo.lock b/tools/qrcheck/Cargo.lock new file mode 100644 index 0000000..141dd97 --- /dev/null +++ b/tools/qrcheck/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "qrcheck" +version = "0.1.0" diff --git a/tools/qrcheck/Cargo.toml b/tools/qrcheck/Cargo.toml new file mode 100644 index 0000000..4d4487c --- /dev/null +++ b/tools/qrcheck/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "qrcheck" +version = "0.1.0" +edition = "2024" + +[[bin]] +name = "qrcheck" +path = "src/main.rs" + +[profile.release] +panic = "abort" + +[workspace] diff --git a/tools/qrcheck/src/main.rs b/tools/qrcheck/src/main.rs new file mode 100644 index 0000000..d294485 --- /dev/null +++ b/tools/qrcheck/src/main.rs @@ -0,0 +1,58 @@ +//! Host-side cross-check tool for the kernel QR encoder. +//! +//! Usage: `qrcheck TEXT [VERSION] [MASK]` +//! - with VERSION+MASK: force both and dump the matrix (compared against +//! segno by `tools/qrcheck.py`); +//! - with neither: auto-pick version and best mask, print `v m`. +//! +//! Output: first line `v m`, then one line per matrix row of +//! `#` (dark) / `.` (light). +#![allow(static_mut_refs)] + +#[path = "../../../rsnix/src/qr.rs"] +mod qr; + +fn main() { + let args: Vec = std::env::args().collect(); + if args.get(1).map(String::as_str) == Some("--raw") { + let text = args.get(2).map(String::as_str).unwrap_or("hello"); + let version: usize = args.get(3).and_then(|s| s.parse().ok()).unwrap_or(0); + let v = if version > 0 { + qr::encode_at(text.as_bytes(), version, Some(0)) + } else { + qr::encode(text.as_bytes()) + }; + if v == 0 { + eprintln!("FAIL"); + std::process::exit(1); + } + for b in qr::codeword_stream() { + print!("{:02x}", b); + } + println!(); + return; + } + let text = args.get(1).map(String::as_str).unwrap_or("hello world"); + let version: usize = args.get(2).and_then(|s| s.parse().ok()).unwrap_or(0); + let mask: Option = args.get(3).and_then(|s| s.parse().ok()); + + let v = if version > 0 { + qr::encode_at(text.as_bytes(), version, mask) + } else { + qr::encode(text.as_bytes()) + }; + if v == 0 { + eprintln!("FAIL: cannot encode {} bytes at v{}", text.len(), version); + std::process::exit(1); + } + let size = qr::size(); + let m = if let Some(m) = mask { m } else { qr::last_mask() }; + println!("v{} m{}", v, m); + for y in 0..size { + let mut row = String::with_capacity(size); + for x in 0..size { + row.push(if qr::module(x, y) { '#' } else { '.' }); + } + println!("{}", row); + } +} -- cgit v1.2.3