Boot fails with self-build u-boot

(Frank W.) #21

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

(Alexey Loukianov) #22

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.

(Frank W.) #23

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

(Alexey Loukianov) #24

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:

root@lx2bpir2:/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.

(Frank W.) #25

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 to not overwrite saveenv-position (prevent saveenv overwrite uboot). Original partition scheme starts with first partition at 100 mb…

(Alexey Loukianov) #26

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



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))"

UBOOT_OFFSET=320       # 320KB


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_ENV_OFFSET      0xF3800

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

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_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

(Frank W.) #27

you can use my uboots bootdevice-detection like this:

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

(Alexey Loukianov) #28

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.

(Frank W.) #29

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