Skip to content

dmflash: the internal flash as a block device - #1

Merged
JohnAmadis merged 3 commits into
mainfrom
feat/initial-driver
Oct 28, 2026
Merged

JohnAmadis merged 3 commits into
mainfrom
feat/initial-driver

Conversation

@JaxCalder

@JaxCalder JaxCalder commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Driver of the internal flash as a DMOD block device (/dev/dmflashx/<section>: read, write, erase by sector, DMDRVI_IOCTL_BLOCK_*, two DMFLASH_IOCTL_*). The node is the only interface: no API to open the flash by hand, dmdevfs makes it from the .ini file. Meant for what has to live in the internal flash and change: a second firmware bank, a bootloader update, a small file system (dmlittlefs).
  • Everything hardware independent is in the core: the sector table, the exposed region, alignment and padding of a write to the programming step, reading back what was written, the block device. The port is four functions: open, close, erase(sector, address, size), program(address, data, size).
  • stm32_common implements them for every STM32F4 and F7 (same flash interface); stm32f4/port.c and stm32f7/port.c are lifecycle plus the reset of the flash accelerator (the one thing that differs: ICRST/DCRST vs ARTRST).
  • The chip is a string, not code: layout=4x32k,1x128k,3x256k in an .ini (configs/mcu/<mcu>.ini, configs/board/<board>/flash.ini; dmflash.dmr installs configs/). A part with another sector layout needs a file, not a port. Included: STM32F746NG, STM32F407VG, boards STM32F746G-DISCO and STM32F4-DISCOVERY (a read/write region after the firmware).
  • Several nodes on one controller: a file of several sections ([fs], [bank_a], [bank_b], ...) makes a node of each; a node reaches only its own region. They share the port and one lock, must agree on the chip and must not overlap.
  • Safe by default: mode=ro; a region is whole sectors you name; a write never erases by itself and is read back (-EIO over data that was not erased).
  • x86_64 port = a flash in RAM (erased bytes 0xFF, a program step can only clear bits) for the tests; CI builds it and runs the 16 steps with ctest, and builds the F4 and F7 ports.
  • tools/flashtest: on-board test of the node (saves and restores the last sector of the region).

Tested

  • Host: 22/22 steps through the dmdrvi functions of the module (what dmdevfs calls, with an .ini built in the test) against the flash in RAM; F4 and F7 build.
  • STM32F746G-DISCO (docs/validation/stm32f746g-disco.txt): flashtest /dev/dmflashx/flash on sectors 6 and 7 (2 x 256 kB): 0 failed steps, 5.5 s with a 256 kB save and restore; the rest of the system (carhmi, ...) kept running. Also two nodes (bank_a, bank_b) on sectors 6 and 7, each passing flashtest.

Not done / notes

  • The STM32F4 port was not run on hardware (same code, only the accelerator reset differs).
  • program_bits other than 32 and parts with two banks (bank 2 sector numbers in FLASH_CR) are not handled / tried; see docs/configuration.md.
  • Erasing or programming stops the CPU while it fetches from the flash (up to a second for 256 kB on an F7).
  • The sectors 6 and 7 of the DISCO were not blank (leftovers of an earlier, bigger firmware image); the board flash.ini region starts after the current ~400 kB image, so the firmware must not grow into it.

🤖 Generated with Claude Code

JaxCalder and others added 3 commits October 27, 2026 10:35
The core does everything that does not depend on the hardware: the sector
table (a layout string from an .ini file, 4x32k,1x128k,3x256k), the exposed
region (whole sectors, read only by default), alignment and padding of a write
to the programming step, reading back what was written, erasing by sector,
the dmdrvi block device (/dev/dmflashx/<section>, BLOCK_GET_INFO / _ERASE and
two dmflash ioctls). The port is four functions: open, close, erase a sector,
program aligned bytes.

stm32_common implements them for every STM32F4 and F7 (the flash interface is
the same); src/port/stm32f4 and stm32f7 are lifecycle and the reset of the
flash accelerator, the one thing that differs. A chip with another sector
layout needs an .ini file (configs/mcu, configs/board), not a port. The
x86_64 port is a flash in RAM for the tests (16 steps of the core), and
tools/flashtest tests the node on the board.

Validated on an STM32F746G-DISCO (docs/validation). The STM32F4 port builds
and shares the code; it was not run on hardware.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The flash is configured by dmdevfs from an .ini file; nobody should open it by
hand, so the module has no API of its own any more (dmflash_create and the rest
are internal functions of dmflash_core.c). What stays public: the ioctls of the
node and the sector / region info (dmflash_ioctl.h), the port and the mock of
the host port.

The dmdrvi functions dmdevfs calls are the only file with the registration
enabled (dmflash.c); the tests do what dmdevfs does - build the .ini, call
those functions - against the flash in RAM (18 steps). base in the .ini is
parsed as an address (a host pointer does not fit in 32 bits).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A file of several sections (fs, bank_a, bank_b, ...) makes a node of each, and a
node reaches only its own region. The controller is one: the nodes share the
port (the first opens it, the last closes it) and one lock, have to agree on the
chip (base, layout, program_bits, timeout_ms) and must not overlap, else the
node is not created. The port stays a singleton - it does not know about nodes.

Tests: nodes with separate regions, overlapping / different chip refused, the
text of a board file with two sections, active sections as dmdevfs sets them
(22 steps). On an STM32F746G-DISCO two nodes on sectors 6 and 7 pass flashtest.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@JohnAmadis
JohnAmadis merged commit 026e5e7 into main Oct 28, 2026
5 checks passed
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.

2 participants