9.2 KiB
eMMC Multi-Boot Setup — Orange Pi 3B
Status: Revised 2026-06-02. Replaces earlier version that used the eMMC hardware boot partition — that approach failed because the SPL cannot find u-boot.itb on a 4MB boot partition (it looks at sector 16384, which is past the end).
This version uses the by-the-book Rockchip user-area boot method.
Boot Architecture
Rockchip Standard Boot Layout (eMMC/SD user data area)
Sector 0: Protective MBR
Sectors 1-33: GPT header + partition entries
Sectors 34-63: gap (unused)
Sectors 64-683: idbloader.img (620 sectors / 317KB — RKNS magic at sector 0x40)
Sectors 684-16383: free gap (~8MB)
Sectors 16384-19400: u-boot.itb (3017 sectors / 1.5MB)
Sectors 19401-32767: free gap (~6.5MB)
Sector 32768+: User partitions (first partition starts here, at 16MB alignment)
Source: https://opensource.rock-chips.com/wiki_Boot_option
Boot Flow
BootROM → SPI (erased, skip) → microSD (if inserted, skip) → eMMC user area
→ scans sectors 64, 1088, 2112, 3136, 4160 for "RKNS" magic
→ loads idbloader (SPL + DDR init)
→ SPL loads u-boot.itb from sector 16384 of same device
→ u-boot reads extlinux.conf from /boot partition
→ shows boot menu → loads kernel
Key difference from v1: The BootROM scans the user data area of the eMMC (mmcblk0), not the hardware boot partition (mmcblk0boot0). The eMMC's PARTITION_CONFIG register must be set to boot from user area (0x78), not boot0 partition (0x48).
Why the first approach failed
The hardware boot partition (mmcblk0boot0) is only 4MB (8192 sectors). The SPL binary (idbloader) is configured to find u-boot.itb at sector 16384 of the same device. On the boot partition, sector 16384 doesn't exist — it's past the 8192-sector boundary. The BootROM successfully loaded idbloader, but SPL immediately failed when it tried to read u-boot.itb from an out-of-bounds sector.
Partition Layout
mmcblk0 (233GB eMMC — user data area)
└── mmcblk0
├── mmcblk0p1 FAT32 1GB /boot (starts at sector 32768)
├── mmcblk0p2 ext4 85GB root_opios (Orange Pi OS Arch)
├── mmcblk0p3 ext4 85GB root_armbian (Armbian)
└── mmcblk0p4 ext4 ~84GB root_nixos (NixOS)
All data below sector 32768 is reserved for the bootloader chain (idbloader + u-boot.itb). Do not create partitions there.
Step 1: Switch to User-Area Boot and Verify
This step is critical. The eMMC's PARTITION_CONFIG must be set for user-area boot. Run from a booted Orange Pi OS (either SD card or existing eMMC install):
# Switch to user-area boot with BOOT_ACK enabled
sudo mmc bootpart enable 7 1 /dev/mmcblk0
# Verify
sudo mmc extcsd read /dev/mmcblk0 | grep PARTITION_CONFIG
Expected: PARTITION_CONFIG: 0x78 (bits [5:3] = 111 = user area, bit 6 = BOOT_ACK enabled).
This only needs to be done once. The eMMC retains this setting across power cycles.
Step 2: Wipe and Repartition
sudo sgdisk --zap-all /dev/mmcblk0
sudo blkdiscard /dev/mmcblk0 # optional
sudo gdisk /dev/mmcblk0
In gdisk interactive mode — note the explicit start sector for p1:
o (new GPT)
n 1 32768 +1G ef00 name=boot
n 2 default +85G 8300 name=root_opios
n 3 default +85G 8300 name=root_armbian
n 4 default default 8300 name=root_nixos
w (write, confirm 'y')
p1 starts at sector 32768 (16MB boundary), leaving the entire 0-32767 area for the bootloader. p2/3/4 use default start sectors — gdisk automatically calculates them from the preceding partition's end.
Step 3: Create Filesystems
sudo mkfs.vfat -F 32 -n BOOT /dev/mmcblk0p1
sudo mkfs.ext4 -L root_opios /dev/mmcblk0p2
sudo mkfs.ext4 -L root_armbian /dev/mmcblk0p3
sudo mkfs.ext4 -L root_nixos /dev/mmcblk0p4
Order doesn't matter here — the bootloader sectors (64-683 and 16384-19400) are in the gap between GPT and p1 (which starts at sector 32768). mkfs only touches the partition itself, not the gap. But writing the bootloader first and verifying it's there before moving on makes debugging easier.
Step 4: Write Bootloader to User Data Area
First, find the bootloader files. They may already exist on your running system:
find / -name "idbloader.img" -o -name "u-boot.itb" 2>/dev/null
If found (e.g. at /boot/idbloader.img and /boot/u-boot.itb), use them directly. If not, extract from the SD card — the idbloader starts at sector 64 (skip the GPT header) and u-boot.itb at sector 16384:
sudo dd if=/dev/mmcblk1 of=idbloader.img bs=512 skip=64 count=16320
sudo dd if=/dev/mmcblk1 of=u-boot.itb bs=512 skip=16384 count=8192
Write both to the eMMC user data area at Rockchip-standard offsets. Write to /dev/mmcblk0 (the raw eMMC device), not a partition:
sudo dd if=idbloader.img of=/dev/mmcblk0 bs=512 seek=64
sudo dd if=u-boot.itb of=/dev/mmcblk0 bs=512 seek=16384
sudo sync
Verify the write:
sudo hexdump -C /dev/mmcblk0 -n 16 -s $((64*512))
Should show 52 4b 4e 53 ("RKNS") — the Rockchip boot header magic. That confirms the BootROM will find it.
Why skip=64 on the SD card extraction: The SD card has a GPT at sectors 0-33. idbloader starts at sector 64 (0x40). Without skip=64, the extracted image includes GPT garbage at the beginning.
Why seek=64 and seek=16384: These are the Rockchip-standard offsets where the BootROM and SPL expect to find the bootloader stages. They work for both SD card and eMMC user data area.
Step 5: Mount and Clone the Rootfs
sudo mkdir -p /mnt/root_opios
sudo mount /dev/mmcblk0p2 /mnt/root_opios
sudo mkdir -p /mnt/root_opios/boot
sudo mount /dev/mmcblk0p1 /mnt/root_opios/boot
sudo rsync -axHAWX --info=progress2 / /mnt/root_opios/
sudo rsync -aHAWX /boot/ /mnt/root_opios/boot/
The second rsync is needed because /boot is a separate filesystem on the SD card — -x (first rsync) deliberately avoids crossing filesystem boundaries.
Step 6: Update fstab
sudo blkid /dev/mmcblk0p1 /dev/mmcblk0p2
Edit /mnt/root_opios/etc/fstab. Replace old SD card references with the new eMMC partition UUIDs:
UUID=<boot-UUID> /boot vfat defaults,noatime 0 2
UUID=<root_opios-UUID> / ext4 defaults,noatime 0 1
Remove any old SD card entries (typically referencing /dev/mmcblk1 or the SD card's UUID).
Step 7: Write extlinux.conf
uname -r
find /mnt/root_opios/boot -name "*.dtb" | grep orangepi-3b
Rather than writing from scratch, copy and modify the SD card's working config:
sudo cp /boot/extlinux/extlinux.conf /mnt/root_opios/boot/extlinux/extlinux.conf
sudo nano /mnt/root_opios/boot/extlinux/extlinux.conf
Replace the UUID in the APPEND root=UUID=... line with root_opios's UUID. Keep everything else (DTB path, console args) as-is — these are known to work with this hardware.
Step 8: Test
sudo umount /mnt/root_opios/boot
sudo umount /mnt/root_opios
sudo sync
sudo poweroff
Remove SD card. Power on. Expected behavior:
- Orange Pi logo appears (u-boot running)
- Boot menu shows (from extlinux.conf)
- Orange Pi OS boots from eMMC
If it doesn't boot, see troubleshooting below.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| u-boot logo, then blank screen | EDID/HDMI handshake | Add video=HDMI-A-1:1920x1080@60e to APPEND line |
| "No bootable device" or no logo | Bootloader not found | Verify PARTITION_CONFIG=0x78 (step 1). Verify idbloader was written to /dev/mmcblk0 at seek=64: hexdump -C /dev/mmcblk0 -n 512 -s $((64*512)) should show "RKNS" |
| "Can't find u-boot.itb" | SPL loaded idbloader but can't find u-boot | Verify u-boot.itb at seek=16384: hexdump -C /dev/mmcblk0 -n 16 -s $((16384*512)) — should show valid header, not zeros |
| Kernel panic: can't find root | Wrong UUID in extlinux.conf | Boot from SD, mount eMMC, fix UUID in /boot/extlinux/extlinux.conf |
| Nothing on screen at all | Power? HDMI connection? | Check USB-C power, HDMI cable, try different monitor |
| Boots only when SD inserted | SD card takes priority | Boot flow checks SD first. Remove SD card for eMMC-only test |
Later: Install Armbian and NixOS
To be documented — Armbian rootfs goes into root_armbian, kernel+DTB added to shared /boot, next LABEL added to extlinux.conf.
NixOS rootfs goes into root_nixos. Likely the trickiest since NixOS generates its own /boot structure.
References
- Rockchip boot option: https://opensource.rock-chips.com/wiki_Boot_option
- Rockchip standard partition layout: https://opensource.rock-chips.com/wiki_Partitions
- U-boot extlinux format: https://docs.u-boot.org/en/stable/develop/distro.html
- PINE64 RK3399 boot sequence (same BootROM search pattern): https://wiki.pine64.org/wiki/RK3399_boot_sequence
- Gentoo wiki — first partition at sector 32768: https://wiki.gentoo.org/wiki/User:Brendlefly62/Rockchip_RK3588S_Rock_5c/Build-Install-U-Boot
- Khadas forum — confirming 32768 offset: https://forum.khadas.com/t/edge-v-domain-emmc-what-is-the-right-offset-for-creating-a-new-partition/4921
- eMMC boot partition docs (linux-sunxi): https://linux-sunxi.org/Bootable_eMMC
- OPi 3B bring-up:
docs/initial-bringup.md - Storage architecture:
docs/storage-architecture.md