MnemOS for the Allwinner D1
This directory contains MnemOS platform support for the Allwinner D1 RISC-V SoC.
src/: The top-level crate that produces MnemOS binaries for the Allwinner D1.
mnemos-config] configurations for supported D1 single-board computers.
d1-core/: Core MnemOS implementation for the Allwinner D1. This is factored out into a separate crate so that it can be built without
forced-target="riscv64imac-unknown-none-elf"(unlike the top-level
mnemos-d1crate), so that unit tests for the platform implementation can be run on development host targets.
mnemos-config] type definition crate for the Allwinner D1.
Getting started with MnemOS on the D1
This crate contains a separate Cargo bin target for each supported D1 board.
These bin targets depend on the
mnemos-d1 crate for the majority of the
platform implementation, and configure the D1's I/O pins based on how those pins
are mapped to pins on the board. The following bin targets are currently
The simplest way to build a MnemOS image for an Allwinner D1 board is to use the
just build-d1 Just recipe.
Running Just recipes requires Just to be installed. See https://just.systems for details on using Just.
just build-d1 recipe takes an optional argument to select which bin target
is built; by default, the
mq-pro bin target is selected. For example:
$ just build-d1 # builds MnemOS for the MangoPi MQ Pro $ just build-d1 mq-pro # also builds MnemOS for the MQ Pro $ just build-d1 lichee-rv # builds MnemOS for the Lichee RV
Alternatively, Allwinner D1 images can be built manually using Cargo. To build using Cargo, run the following commands:
# set which board binary to build $ export BOARD="mq-pro" # or "lichee-rv" # build the MnemOS binary for that board $ cargo build -p mnemos-d1 --board $BOARD --release # produce a binary that can be flashed to the board $ cargo objcopy -p mnemos-d1 --bin $BOARD -- release \ -O binary target/riscv64imac-unknown-none-elf/mnemos-$BOARD.bin
cargo-binutilsmust be installed in order to use
cargo objcopy. The
just build-d1recipe will prompt to install it automatically.
just flash-d1 recipe will build MnemOS and then flash it to your D1 board.
build-d1, this recipe takes an optional argument to
select which board target to build, and defaults to building for the MQ Pro if
none is provided.
For example, running
just flash-d1 mq-pro should print output like this:
$ just flash-d1 mq-pro Found cargo objcopy Compiling mnemos-d1 v0.1.0 (/home/eliza/Code/mnemos/platforms/allwinner-d1/boards) Finished release [optimized] target(s) in 2.66s Finished release [optimized] target(s) in 0.07s xfel ddr d1 xfel write 0x40000000 platforms/allwinner-d1/boards/target/riscv64imac-unknown-none-elf/mnemos-mq-pro.bin 100% [================================================] 241.281 KB, 450.510 KB/s xfel exec 0x40000000
When flashing the MangoPi MQ Pro using
just flash-d1, ensure that the USB cable is plugged in to the USB-C port on the board labeled as "OTG" on the silkscreen, not the one labeled as "HOST".
Once a board has been successfully flashed, attempting to flash it again using
xfel may fail. This can be fixed by unplugging the USB cable from the board
and then plugging it back in.
In order to use the
just flash-d1 recipe, the
cargo-binutils Cargo plugin
is required. If it is not found, the
flash-d1 recipe will prompt the user to
llvm-tools-preview Rustup component is a dependency of
It should be automatically installed by the
rust-toolchain.toml file in this
repo, but can be manually installed by running
$ rustup component add llvm-tools-preview.
xfel is necessary to actually flash the board. Instructions for
xfel from source for Linux, MacOS, and Windows can be found
xfel binaries for Windows are available
In addition to the official distribution channels, I (Eliza) have written a Nix derivation for
xfel. Eventually, I'd like to upstream this to Nixpkgs, but it can currently be used as a git dependency. Note that when using this,
xfel's udev rules must be added to the system's udev rules; see here for an example.
On reset, the D1 executes its internal Boot ROM (
BROM), which either loads
a first stage bootloader or enters FEL mode.
- Do some initial setup of the clocks
- Check the FEL pin: if it is low (connected to GND), it will enter FEL mode
- Check the SD card (SMHC0) and connected SPI flash for a valid eGON header
- Fall back to FEL mode if no valid header is found
You can find additional info about
BROM and FEL on the linux-sunxi wiki.
In short, in FEL mode the D1 will present itself as a USB device and allow
(using a custom protocol) things like reading data, writing data and starting
Different tools like
xfel have been developed that speak
this protocol and implement functionality like initializing DRAM
(by loading code that does this into SRAM and then executing it).
However, this is all volatile, so these actions have to be repeated on reset.
To have a persistent boot, we can use one of the media that is probed
BROM for an eGON header: the SD card or SPI flash
(if you have this on your board).
On this persistent medium, a first stage bootloader needs to be present,
preceded by a valid eGON header.
BROM will then load it into SRAM and execute it.
This bootloader has to, at a minimum, initialize DRAM and load either a second stage bootloader or the actual application (in our case MnemOS) into DRAM so it can transfer control of execution to it.
The initialization code for the DDR3 RAM is somewhat of a black box. It is hard to determine who was first in reverse-engineering the necessary Allwinner blobs, but one candidate is this, which served as a basis for the original SPL work by smaeul. This is now deprecated, as it is included in smaeul's u-boot fork, which will hopefully be merged upstream one day.
SD card layout
The linux-sunxi wiki has some more information on the required layout of the SD card. The eGON header with first stage bootloader has to be located at an offset of either 8KB or 128KB, in order to leave some space for a partition table (so you can have, e.g., a FAT filesystem on your SD card at the same time).
To prepare your SD card, you can do the following (where
sdX is the SD card):
sudo dd if=first-stage-boot.bin of=/dev/sdX bs=1024 seek=8 conv=sync sudo dd if=mnemos.bin of=/dev/sdX bs=1024 seek=40 conv=sync
MnemOS currently does not have its own first stage bootloader, but it is possible to adapt the oreboot bt0 for this role.