Boot fails with self-build u-boot

Yes, u-boot-tools are installed

Wouldn’t that write u-boot to the integrated emmc? This is not what I’m trying to achieve. I want to build u-boot from the repository on my own and load it to the SD card. Then boot the bananpi from the self-compiled u-boot.

I didn’t try to write anything to the emmc yet. So I’m pretty sure it should be empty. Just to really make sure I zeroed (dd if=/dev/zero ..) the sd card and turned on the bpi-r2. Nothing happened. I think the emmc is empty.

@frank-w I see in your post “How to extend the uboot menu” that apparently you can compile and use your own uboot. Could you please post every step (from cloning the git repository, until insterting the SD card into the bpi-r2) here?

basicly there are no more steps as described in my wiki

  • git clone https://github.com/frank-w/BPI-R2-4.4.git
  • cd BPI-R2-4.4
  • ./build.sh => 1
  • gunzip SD/100MB/BPI-R2-720P-2k.img.gz
  • sudo dd if=SD/100MB/BPI-R2-720P-2k.img of=/dev/sdb bs=1k seek=2 count=1022
  • sync + umount automounted partitions
  • remove card and insert in r2
  • boot r2

i looked into how the BPI-R2-720P-2k.img was created…preloader is included on sdcard preloader (preloader_iotg7623Np1_emmc.bin) is at 0x800 and uboot (uboot.bin) on 0x50000 (you can dd an 1MB-image from your card and look with bless or similar hexeditor)

i don’t know if there must be an partition defined…if you use an empty card…you can use my partition-scheme to test it out: http://www.fw-web.de/dokuwiki/doku.php?id=en:bpi-r2:storage#manual_copy_of_os

Since it was still not working I changed my plans. I took my old clamshell pc, installed linux, and did all your steps and it worked :ok_man: I just hadded to add the section from 0-2k from the ubuntu image, in order to be able to boot. I guess there is some kind of preloader on it to initialize the CPU and the memory.

dd if=ubuntu.img bs=1k count=2 of=/dev/sdb

I attached the part that I used for the sd card (0-2k). Do you have any idea what this is?

I still have no idea what went wrong in my previous tries. I’m still investigating and if I find something I will report it.

header_0-2k.img (2 KB)

maybe the first 512kB are needed to boot see https://en.wikipedia.org/wiki/Master_boot_record

the first 10 bytes containing a magic string “SDMMC_BOOT” followed by 10Bytes (00 00 01 00 00 00 00 02 00 00) i don’t know (maybe position of preloader/uboot to jump to) followed by many FF (fill-bytes??). On byte 440 (1b8h) there is the “32-bit disk signature” followed by 0000h (for rw-state). After that Partition-Table starts (MBR 4x16byte) followed by MBR end-marker 55AAh

so i assume that it is enough copy the first 20 bytes to get SDcard to boot (partitiontable should not be involved in boot-process before uboot).

also some infos about that area of the sd/emmc: Boot process\FreeBSD porting

i have wrote down the steps after creating bootable emmc with only these steps, but emmc has bootloader in separate partition (boot0-block) so maybe in SD-Card there is more needed. in my image i used original image with erased partitions.

btw. preloader is before uboot >=2k

Unfortunately it is not. There are 32 bytes after the MBR (starting at 0x200) that are required for booting. Let’s refer to it as BRLYT

$ dd if=2017-09-04-ubuntu-16.04-mate-desktop-bpi-r2-sd-emmc-v1.2.0.img bs=1 skip=512 count=32 | xxd
32+0 records in
32+0 records out
32 bytes copied, 0.000135552 s, 236 kB/s
00000000: 4252 4c59 5400 0000 0100 0000 0008 0000  BRLYT...........
00000010: 0008 0000 4242 4242 0800 0100 0008 0000  ....BBBB........
00000020: 0008 0000 0100 0000 0000 0000 0000 0000  ................

Putting only those 3 parts (SDMMC_BOOT, BRLYT, uBoot) to the SD card is sufficient to make it boot. There is no need for a partition table.

# copy SDMMC_BOOT
$ dd of=/dev/sdb bs=1 count=20 if=2017-09-04-ubuntu-16.04-mate-desktop-bpi-r2-sd-emmc-v1.2.0.img 
# copy BRLYT
$ dd of=/dev/sdb bs=1 seek=512 skip=512 count=48 if=2017-09-04-ubuntu-16.04-mate-desktop-bpi-r2-sd-emmc-v1.2.0.img 
# copy uboot
$ dd of=/dev/sdb bs=1k seek=2 count=1022 if=./SD/100MB/BPI-R2-720P-2k.img

Indeed those are fill-bytes. I replaced them with 0x00 and it’s still loading uboot.

I can also confirm, that the partition table is not part of the boot process. My SD has no partition table on (i zeroed everythin) and it is still loading uboot.

Questions that are still open for me:

  1. What do the bytes from 0-20 (SDMMC) do?
  2. What is the BRLYT part?
  3. Where are the addresses stored to jump from the preloader (SDMMC) to BRLYT and from BRLYT to 0x800 (uBoot)?
1 Like

Seems that the 10 bytes after sdmmc_boot pointing to brlyt 0x200 and brlyt to preloader at 0x800+2k (also 0x800). Preloader loads uboot at 0x50000+2k

Spent quite a lot of time today debugging why my BPiR2 refuses to boot from SD card if this card has some partitions defined in MBR. Turned out that board seems to ignore SD card in case any entry in partition table is marked as “active” (also known as “boot” flag). In my case I was generating SD card image template using OpenWRT’s ptgen utility which by default sets first primary partition as “active”. Quick fix using fdisk and viola - board is able to boot from this SD card.

You have installed openwrt to an sd with partitiontable? Is openwrt also on a partition or outside?

It is a bit more flexible. Right now I’m running openwrt on eMMC with partitions but it works the same way for SD card. Partitions look like this:

[email protected]:/etc# block info
/dev/mmcblk0p1: UUID="047A-02BF" LABEL="NO NAME" VERSION="FAT16" MOUNT="/boot" TYPE="vfat"
/dev/mmcblk0p2: UUID="57f8f4bc-abf4-655f-bf67-946fc0f9f25b" VERSION="1.0" MOUNT="/" TYPE="ext4"
/dev/sda1: UUID="7ebdbb13-3c7b-e844-1f52-049f80e63836" LABEL="OpenWrt:r1" TYPE="linux_raid_member"
/dev/sdb1: UUID="7ebdbb13-3c7b-e844-1f52-049f80e63836" LABEL="OpenWrt:r1" TYPE="linux_raid_member"
/dev/md127: UUID="1bb2dfe2-8158-4833-9dff-9260b998716d" LABEL="owrt-raid1" VERSION="1.0" MOUNT="/mnt/storage" TYPE="ext4"

Kernel and uEnv.txt reside on /dev/mmcblk0p1 vfat partition (mounted as /boot in openwrt), rootfs is ext4 on /dev/mmcblk0p2. uUnv.txt had been modified a bit compared from your variant so it detects if the system had been booted from eMMD or SD and then it boots the kernel and rootfs from the same device. Original logic in your uEnv.txt was to check if the first partition on SD is a valid FAT filesystem and boot from it even if preloader/u-boot were booted from eMMC. It resulted in nasty behavior for the case when openwrt is installed on eMMC and hardware boot switch is set to eMMC. For such case if an SD card is inserted into the slot and have got valid FAT filesystem on the first partition then u-boot will try to boot from this SD card - which is not what I want. Instead I had implemented two bootmenu options allowing user to select what bootdevice to use.

Ah, and another change is to move u-boot saveenv target offset to be less than 1MB - default partition scheme for modern linux is the first partition to start at 1MB so if u-boot is compiled to saveenv to the first megabyte the first time saveenv is used would result in data corruption on the first partition. Good offset to store saveenv is 950k from the start of the disk: it is far enough to provide plenty room for u-boot itself (950k-320k=630k available for u-boot binary) and leaves 50k for environment storage - which is also more than enough.

Back to openwrt changes:

  • Had hacked in the support for built-in openwrt’s sysupgrade functionality to allow for easy system upgrades by end-user. It is a “classic openwrt sysupgrade.bin-style” system upgrade: put all known conffiles + all files listed by end-user as “save at sysupgrade” into a tarball, flash the preloader, u-boot, kernel (vfat partition containing kernel and uEnv.txt for our case) and filesystem with new ones coming from sysupgrade file, put saved configs tarball to the root of the rootfs and reboot. Pre-init script will find tarball on the first boot and restore all configuration files to original places.
  • Currently I’m considering implementing another way of sysupgrading system that is available in openwrt - through sysupgrade.tar. This upgrade style works a bit differently as it only allows for updating kernel and rootfs - which might be great for people who don’t want to update preloader/u-boot and loose uEnv.txt local changes each time they to a sysupgrade. Shouldn’t be that hard to implement but it is time to spend and I’ve got a lot of other things to fix that seem to be more important than this.
  • Had properly integrated DTS fixes into the openwrt’s kernel patch/build system (fix for second gmac, fix for memory to be 2GB instead of 1GB, add pcie entries). No more ugly “copy dts/dtsi to this directory after executing make target/linux/{clean,prepare}”.
  • Had created new uboot-mediatek package using openwrt’s u-boot building infrastructure coupled with u-boot patches from your u-boot 2019.01 repo.
  • What is left to implement is an auto-download functionality for preloader binary. What @Jackzeng had done in latest Openwrt 2018.06.2 based image is an ugly hack: he had put preloader binary files directly into the git repo at staging_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/image/. It is not upstreamable but it’s not the worst thing here. Main fault with this approach is the fact that staging_dir image target folder gets emptied on make clean. I.e. execute make clean once and get the sudden and surprising build failure on following make target/install. There are several ways to re-implement this properly but fist thing I need is an “official vendor source” for preloader which I can rely on to put the download URL into makefile. I believe you’ve seen my question on this matter in u-boot thread but it looks like vendor representatives have next to none incentive to provide me with an answer :frowning: .

Nevertheless my end-goal for this project it to try to upstream at least some of these changes into openwrt main tree so it would be less hassle for me in future to maintain my own fork.

how have you done this? Using my getbootdev-function? afair the uboot-cmd is not in actual uboot because i don’t have pushed this part to upstream,only the saveenv-mapping.

I have adapted the original behaviour (and the offset of 1MB) to be compatible to official images. I don’t know atm how bis my current uboot-binary is,but there is a check in build.sh to not overwrite saveenv-position (prevent saveenv overwrite uboot). Original partition scheme starts with first partition at 100 mb…

https://www.fw-web.de/dokuwiki/doku.php?id=en:bpi-r2:storage

I do not stick with original partition scheme and prefer to keep limitations to the bare minimum possible. As had been figured out in this thread minimal requirements for board to boot from SD are:

  1. SDBOOT 20 byte signature at offset 0.
  2. BRLYT 32 byte signature at offset 512 (1 sector).
  3. Preloader binary at offset 2048 (2k == 4 sectors).
  4. U-boot raw binary at offset 327680 (320k = 640 sectors).
  5. Only MS-DOS MBR-style partition table label is allowed.
  6. No active partitions are allowed.

So my script to create bootable SD is like this:

#!/usr/bin/env bash
#
# Copyright (C) 2013-2019 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#

set -ex
[ $# -eq 7 ] || {
    echo "SYNTAX: $0 <file> <preloader image> <u-boot image> <bootfs image> <rootfs image> <bootfs size> <rootfs size>"
    exit 1
}

OUTPUT="$1"
PRELOADER="$2"
UBOOT="$3"
BOOTFS="$4"
ROOTFS="$5"
BOOTFSSIZE="$6"
ROOTFSSIZE="$7"

head=4
sect=63

set `ptgen -o $OUTPUT -h $head -s $sect -l 1024 -t c -p ${BOOTFSSIZE}M -t 83 -p ${ROOTFSSIZE}M -a 0`

BOOT_OFFSET="$(($1 / 512))"
BOOT_SIZE="$(($2 / 512))"
ROOTFS_OFFSET="$(($3 / 512))"
ROOTFS_SIZE="$(($4 / 512))"

PRELOADER_OFFSET=2     # 2KB
UBOOT_OFFSET=320       # 320KB

SDMMC_BOOT="SDMMC_BOOT\x00\x00\x01\x00\x00\x00\x00\x02\x00\x00"
BRLYT="\
BRLYT\x00\x00\x00\x01\x00\x00\x00\x00\x08\x00\x00\
\x00\x08\x00\x00\x42\x42\x42\x42\x08\x00\x01\x00\x00\x08\x00\x00\
\x00\x08\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"

echo -en "${SDMMC_BOOT}" | dd bs=1 of="${OUTPUT}" seek=0   conv=notrunc
echo -en "${BRLYT}"      | dd bs=1 of="${OUTPUT}" seek=512 conv=notrunc

dd bs=1024 if="${PRELOADER}" of="${OUTPUT}" seek="${PRELOADER_OFFSET}" conv=notrunc
dd bs=1024 if="${UBOOT}"     of="${OUTPUT}" seek="${UBOOT_OFFSET}"     conv=notrunc
dd bs=512  if="${BOOTFS}"    of="${OUTPUT}" seek="${BOOT_OFFSET}"      conv=notrunc
dd bs=512  if="${ROOTFS}"    of="${OUTPUT}" seek="${ROOTFS_OFFSET}"    conv=notrunc

Having u-boot sitting at 320k offset and knowing that u-boot binary is about 300k in size (as of 2019.01 version built from your repo) leaves us with a relatively safe assumption that we may place the start of the first partition at 1MB offset - and it so happens that this offset is a default offset for modern linux-world partitioning tools like fdisk or parted. So I have this patch applied:

diff --git a/include/configs/mt7623.h b/include/configs/mt7623.h
index ba763501..fb6ac073 100644
--- a/include/configs/mt7623.h
+++ b/include/configs/mt7623.h
@@ -53,4 +53,7 @@
 #define CONFIG_EXTRA_ENV_SETTINGS      \
        FDT_HIGH

+#define CONFIG_SYS_MMC_ENV_DEV 0
+#define CONFIG_ENV_OFFSET      0xF3800
+
 #endif

Regarding boot detection logic, here is how I’ve done it:

roottmpl=${rootdev} rootfstype=ext4 rootwait
prepsetroot=setenv setroot setenv root ${roottmpl}

buildargs=setenv bootargs "console=${console} root=${root} ${bootopts} ${graphic}"
checkbootedfrom=if itest.l *81dffff0 == 434d4d65 ; then setenv bootedfrom eMMC; else setenv bootedfrom SD; fi;

checksd=fatinfo ${device} 1:1
selectmmc=run useemmc; if test "${bootedfrom}" == "eMMC"; then echo "Booted from eMMC, using eMMC"; else run selectsd; fi;
selectsd=if run checksd; then echo "Booted from SD, pt#1 FAT OK, use SD"; run usesd; else echo "Booted from SD, pr#1 is not FAT, fall back to eMMC"; fi;
usesd=setenv partition 1:1; setenv rootdev /dev/mmcblk1p2;
useemmc=setenv partition 0:1; setenv rootdev /dev/mmcblk0p2;

newboot=run prepsetroot; run setroot;run buildargs;printenv bootargs;fatload ${device} ${partition} ${loadaddr} ${kernel}; bootm

#bootmenu
boot0=run lskernel;run askkernel;if printenv kernelinput ;then setenv kernel ${kernelinput};run lsdtb;run askdtb;if printenv dtbinput ;then setenv fdt ${dtbinput};fi; run newboot2; fi;
boot1=run newboot;

bootmenu_default=2
bootmenu_0=1. Enter kernel-name to boot from SD/EMMC.=run boot0
bootmenu_1=2. Boot kernel from TFTP.=run bootnet
bootmenu_2=3. Boot from SD/EMMC (auto select).=run boot1
bootmenu_3=4. Boot from eMMC.=run useemmc; run boot1
bootmenu_4=5. Boot from SD.=run usesd; run boot1
1 Like

you can use my uboots bootdevice-detection like this:

as you see there i also tried setting an environment-variable :slight_smile:

This code is not in 2019-01-bri-r2 branch I was basing my work on. FWIS it is in bpi-r2_v5 branch. Anyway I prefer to have direct comparison like “if itest.l *81dffff0 == 434d4d65 ; ...” in uEnv rather than relying on custom command in u-boot that is not available in upstream version. It is just more portable this way - one less patch to care about when porting to more recent version.

right, i have not put this part to upstream (and inside newer branches), because i did not need this before…it was only a test for me :slight_smile:

the other code testing for emmc-string in Memory was from me, but currently only used for determining device for saveenv

Frank, I’m wondering about the magic behind the address 0x81DFFFF0 that you use to determine if it was eMMC or SD card the device had booted from. Looks like this detection is not that reliable:

[Dram_Buffer] MAX_TEE_DRAM_SIZE: 0
Boot from eMMC!!
[PLFM] Init Boot Device: OK(0)

...

 bootloader load uboot ,the address of uboot is 81E00000
[PART]partition name UBOOT
[PART]partition start block 0x200
[PART]partition size 0x80000
[PART]partition blks 0x400
[PART]partition flags 0x0
[PART]partition name 0x8
[bean] part->startblk(0x200) bdev->blksz(0x200) part->part_id(8) hdr(0xFFB50000)
[BlkDev.c 101 ]partition block size 0x200 ,blks:0xE90000
[BlkDev.c 101 ]partition block erase size 0x200

[PART] load "UBOOT" from 0x0000000000050000 (dev) to 0x81E00000 (mem) [SUCCESS]
[PART] load speed: 10462KB/s, 300000 bytes, 28ms
[BT_SD_PG] device info 0x8590 0x8A00 0xCB01 0x102

...

[PLFM] boot reason: 0
[PLFM] boot mode: 0
[PLFM] META COM0: 0
[PLFM] <0xFFB7CC10>: 0x0
[PLFM] boot time: 2013ms
[PLFM] DDR reserve mode: enable = 0, success = 0

[BLDR] jump to 0x81E00000
[BLDR] <0x81E00000>=0xEA0000B8
[BLDR] <0x81E00004>=0xE59FF014


U-Boot 2019.01 (Jan 30 2019 - 12:21:02 +0000)

CPU:   MediaTek MT7623 E3
DRAM:  2 GiB
MMC:   [email protected]: 0, [email protected]: 1
Loading Environment from MMC... Boot From SD(id:1)

MMC: no card present

As you can see here I boot the board from the eMMC but u-boot thinks that is was booted from SD - and that’s because of this:

BPI-R2> md 0x81DFFFF0
81dffff0: ffffffff ffffffff ffffffff ffffffff    ................

It is not the first time I see it fail. Sometimes I was getting “eMMC” at this offset even when I was booting from SD. That’s why I’m wondering about the “detection magic” - what was the reasoning behind using this offset as an information source?

I took the offset from jackzengs implementation

But simplyfied the code to make it compatible with upstream uboot. In my tests i got the right value,but you need a powercycle to boot from the other device…on reboot it remembers bootdevice…

I don’t know a better way…also i know no way to get boot-switch position and cannot test it. maybe this is for bootswitch, but i have no such board: https://github.com/BPI-SINOVOIP/BPI-R2-bsp/commit/2bf5f720c99db45ee551176a4f2a44f622fcf8a9

maybe this is interferring with your board, have you tested with switch on SD?

Uh oh, it looks like a hackish hack. g_mmc_devid is an extern that is defined in common/env_mmc.c (which is patched in “Save uboot envs to where it boot from” change) so it is initialized to 0 if at 0x81DFFFF0 there’s a “eMMC” or to 1 if not. And the “hackish” I mean that this change hardcodes dev to always be 0 or 1 no matter what was the actual device number passed to the mmc command. I.e. this change breaks mmc command in unobvious way and makes either SD card or eMMC unavailable from u-boot,

As for boot switch “detection” - my experiments with different preloaders seem to show that the contents of the memory at address 0x81DFFFF0 is set to “eMMC” by some versions of preloaders to indicate that u-boot is loaded from the eMMC. It has no direct relation to the position of the boot switch. If a preloader of such kind is written to the SD card you still would be getting “eMMC” at memory 0x81DFFFF0 despite the fact that boot switch is set to SD and preloader was loader from this SD card. We need something else to detect the real position of the boot switch. I may speculate here that probably boot switch is connected to some gpio line on the MT7623n and the state of this line is used by the in-chip hardcoded firmware “pre-pre-loader” to determine if attempt to boot from SD card should be skipped or not. If that’s the case than in theory we may read the state of this gpio line and get our answer. But this is a speculation and more info from vendor (or further investigation) is needed to be able to solve this.

P.S. Or there’s an easiest fix (from my PoV): vendor might provide us with yet another preloader binary that always loads u-boot from SD card and always set memory at address 0x81DFFFF0 to some predefined value like "SD ". Such preloader coupled with already available preloader that always loads u-boot from eMMC and always put “eMMC” to that memory address would allow us to reliably determine the source u-boot was loaded from which is sufficient for our needs. The only rule to follow then would be to place “SD card always” preloader to SD cards and “eMMC always” preloader to eMMC and that will seal the deal.

1 Like

thank you for your investigation. I have a board without this switch but maybe here the gpio-line is soldered to sd-position.

In my tests my detection works…have i used differen preloaders?

afair i used debian-image to create my own (erased boot/root-partitions and leave preloader,other bootheaders,uboot). On emmc i used BPI-R2-EMMC-boot0-DDR1600-0k-0905.img.gz which should not set emmc-string based on your findings.

Btw. Read out switch does not represent boot-device…if switch is on SD and no (bootable) sd is inserted r2 will boot from emmc and your gpio-state shows wrong position

That’s worrying. I will try to re-test with this preloader this evening - it might be me messing something up while testing.