# 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):

```bash
# 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

```bash
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

```bashsudo mmc bootpart enable 7 1 /dev/mmcblk0

## Step 4: Write Bootloader to User Data Area

First, find the bootloader files. They may already exist on your running system:

```bash
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:

```bash
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:

```bash
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:**

```bash
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

```bash
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

```bash
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

```bash
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:

```bash
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

```bash
sudo umount /mnt/root_opios/boot
sudo umount /mnt/root_opios
sudo sync
sudo poweroff
```

Remove SD card. Power on. Expected behavior:

1. Orange Pi logo appears (u-boot running)
2. Boot menu shows (from extlinux.conf)
3. 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`