Skip to content

Add firmware 3.25.1.1 support#50

Open
CedricYauLBD wants to merge 10 commits intotimower:masterfrom
CedricYauLBD:feat/firmware-3.25-support
Open

Add firmware 3.25.1.1 support#50
CedricYauLBD wants to merge 10 commits intotimower:masterfrom
CedricYauLBD:feat/firmware-3.25-support

Conversation

@CedricYauLBD
Copy link
Copy Markdown

Summary

  • Adds support for reMarkable 2 firmware 3.25.1.1, where EPFramebufferSwtcon was moved from libqsgepaper.so into xochitl (statically linked)
  • The server uses the LD_PRELOAD path (ServerLib.cpp) since dlopen(libqsgepaper.so) no longer finds the SWTCON implementation
  • Adds robust ELF PT_NOTE parsing for build-id discovery in Version.cpp, replacing the hardcoded address (backward compatible with older firmware)

What changed in firmware 3.25

In 3.20-3.23, EPFramebufferSwtcon lived in libqsgepaper.so and the server could dlopen/dlsym the update functions. In 3.25, these are statically linked into xochitl. libqsgepaper.so now only contains EPFramebufferDesktop (a software renderer).

The 3.25 build ID is intentionally not mapped for libqsgepaper.so in Version.cpp so that ServerExe falls through to the LD_PRELOAD path.

Files

File Change
libs/rm2fb/Versions/Version3.25.cpp New — hooks malloc/calloc/mmap during init, redirects gray buffer to shared memory, drives display via lock → actualUpdate → processAndSignal
libs/rm2fb/Versions/Version.cpp Added 3.25 xochitl build ID + ELF PT_NOTE parsing (fallback to legacy 0x10180 for older firmware)
libs/rm2fb/Versions/Version.h Declared version_3_25_0
libs/rm2fb/PreloadHooks.h Added Mmap to HOOKS(X) macro
libs/rm2fb/CMakeLists.txt Added Version3.25.cpp to build
CLAUDE.md Reproduction instructions

Test plan

  • rm2fb server starts without crashes on firmware 3.25.1.1
  • "SWTCON initalized!" appears in server logs
  • Gray buffer successfully redirected to shared memory
  • yaft terminal renders on e-ink screen
  • Type Folio keyboard input works
  • SSH connections work from yaft (dbclient)
  • LCDIF interrupt count increases with each screen update (verified ~50-90 interrupts per refresh)
  • Exiting yaft and restarting xochitl restores normal UI
  • Older firmware versions still work (unchanged code paths, only additive changes)

Build

nix build .#dev-cross

Cross-compiled on aarch64-darwin, deployed via SCP + patchelf.

CedricYauLBD and others added 10 commits March 3, 2026 03:26
EPFramebufferSwtcon moved from libqsgepaper.so into xochitl in firmware
3.25, breaking the dlopen/dlsym server path. This adds LD_PRELOAD-based
support that hooks into xochitl's statically-linked SWTCON functions.

Changes:
- Version3.25.cpp: new implementation using malloc/calloc/mmap hooks to
  redirect the gray buffer to shared memory, then lock → actualUpdate →
  processAndSignal to drive the framegen thread
- Version.cpp: added 3.25 build ID mapping + robust ELF PT_NOTE parsing
  for build-id discovery (replaces hardcoded address, backward compatible)
- PreloadHooks.h: added Mmap to the HOOKS(X) macro
- CLAUDE.md: reproduction instructions for future contributors

Tested on reMarkable 2 with firmware 3.25.1.1 using yaft terminal
emulator with Type Folio keyboard.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Covers SSH access, terminal usage, build/deploy, remote screen
verification, debugging, architecture, and address discovery for
future firmware versions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Restores the detailed RE narrative: how addresses were discovered,
buffer redirections, update mechanism, ELF build ID parsing,
failed approaches, and the terminal helper script.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rasterize 9,944 glyphs (regular + bold) from JetBrains Mono Nerd Font
using a new Python generator script. Covers ASCII, Latin, Greek,
Cyrillic, box drawing, block elements, Powerline, and ~5,900 Nerd Font
dev icons (Seti-UI, Devicons, Font Awesome, Codicons, etc.).

Box drawing characters are post-processed to extend lines to cell edges
for seamless connections across terminal cells.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add keyhotd, a keyboard hotkey daemon that listens for Ctrl+Alt+T on the
Type Folio to launch the terminal directly from xochitl. Runs as a systemd
service, passively monitors input without grabbing, and guards against
double-launch.

Also includes yaft glyph regeneration with JetBrains Mono Nerd Font,
dirty line tracking improvements, and test infrastructure updates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Skip e-ink updates for cells that haven't actually changed. tmux and
Claude Code TUI frequently repaint unchanged content (status bars,
static text), causing unnecessary full-screen e-ink flashes.

- Add cells_equal() for field-by-field cell comparison (fast path
  skips pixmap[] unless has_pixmap is set)
- Guard erase_cell, set_cell, copy_cell with comparison checks
- Make erase_display shouldClear conditional on actual changes
- Scope server-side RGB565→Y8/ARGB32 conversion to dirty rect only
  (was converting all 2.6M pixels per doUpdate call)
- Send single bounding-box doUpdate per frame instead of per-line
- Fix existing dirty tracking tests for new skip-unchanged semantics
- Add 6 new tests for redundant-write skipping

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server: when GrayReady flag is set, skip redundant gray buffer write
and only convert RGB565→ARGB32 (~30% per-pixel savings). The Y8→ARGB32
fast path was investigated but doesn't work due to canvas rotation
mismatch between the unrotated gray buffer and rotated RGB565 layout.

yaft: replace per-chunk setState with a 32ms debounce timer. Terminal
output is parsed immediately but draws are batched, limiting panel
refreshes to ~30/sec. This is the biggest performance win — each e-ink
refresh costs 50-250ms, so batching rapid output (e.g. ls, cat) into
fewer refreshes saves far more time than pixel conversion optimizations.

Infrastructure: add GrayReady=8 UpdateFlag, getGrayCanvas(), expanded
shared memory mmap for Y8 buffer, and canvasOffset() helper.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…low commands

Document actualUpdate's ARGB32 dependency, canvas rotation mismatch,
GrayReady fast path behavior, e-ink refresh batching strategy, quick
build-deploy-test cycle, screenshot script usage, WiFi fallback note,
and expanded files-modified table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@LeviEdwards
Copy link
Copy Markdown

This worked great for me! I mean Claude did all the work, but i've got Claude Code running on my RM2 now, version 3.25.1.1 ... Thank you!!

@timower timower self-requested a review March 23, 2026 14:19
@timower
Copy link
Copy Markdown
Owner

timower commented Mar 23, 2026

Nice, I do see some changes that are not related to 3.25 support.
Could you separate out the yaft specific stuff?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants