How to update bootloader uboot

i have HH41V router which has: QCA9531-MIPS-24Kc_AP143

it uses: : U-Boot 1.1.4-g85be9953-dirty

i have build ther newer version of ubbot:

git clone --depth 1 https://source.denx.de/u-boot/u-boot.git

export SDK_ROOT=".../openwrt-sdk-25.12.5-ath79-generic"
export STAGING_DIR="$SDK_ROOT/staging_dir/toolchain-mips_24kc_gcc-14.3.0_musl"
export HOST_STAGING_DIR="$SDK_ROOT/staging_dir/host"
export PATH="$STAGING_DIR/bin:/usr/bin:$PATH"
export CROSS_COMPILE="mips-openwrt-linux-musl-"
export ARCH=mips
make ap143_defconfig

cp u-boot.bin backup/u-boot-new.bin
dd if=/dev/zero bs=1 count=262144 of=backup/u-boot-new-padded.bin
dd if=backup/u-boot-new.bin of=backup/u-boot-new-padded.bin conv=notrunc

now when i try to flash it does not give me the permission:

root@OpenWrt:~# fw_setenv bootdelay 0 && dd if=/tmp/u-boot-new-padded.bin of=/dev/mtd0 bs=1k 2>&1 && fw_setenv bootdela
y 2 && reboot -f
dd: can't open '/dev/mtd0': Permission denied
root@OpenWrt:~# fw_setenv bootdelay 0 && dd if=/tmp/u-boot-new-padded.bin of=/dev/mtd0 bs=1 count=262144 conv=notrunc 2
>&1 && fw_setenv bootdelay 2
dd: can't open '/dev/mtd0': Permission denied
root@OpenWrt:~# fw_setenv bootdelay 0 && dd if=/tmp/u-boot-new-padded.bin of=/dev/mtdblock0 bs=4k 2>&1 && fw_setenv boo
tdelay 2
dd: error writing '/dev/mtdblock0': Operation not permitted
1+0 records in
0+0 records out
root@OpenWrt:~# 

how to bypass this writing restriction?

Typically the write-protection is defined in the partition table embedded in the firmware, usually nowadays via DTS.
Example: Writable u-boot partition (Ralink MT7268 Soc) - #5 by drbrains

You can removed it by

  • compiling a firmware that removes the write protection from DTS for that mtd area
  • using the kmod-mtd-rw kernel module to remove the write protection.
    • apk add it, and then load it to the kernel (note: requires an explicit add-on to the command. see below)
      apk update
      apk add kmod-mtd-rw
      insmod mtd-rw i_want_a_brick=1
    • compiling a personal firmware with that kmod built-in. Still need to be loaded explicitly. (If you are running a private self-compiled firmware, you may not be able to download kmod from the OpenWrt download repos)

Be aware are i_want_a_brick is to be taken literally, you must have out-of-circuit means of recovery (reflashing the flash chip externally). The installed OEM u-boot isn't just an old (vanilla-) upstream u-boot, but usually (read, always) heavily modified, predating DTS usage - there is no guarantee at all that your device will boot afterwards. So have full backups (of everything, including u-boot!, u-boot-env, ART!!, among others!!), soldering equipment and means to reflash the flash chip externally (e.g. spi-nor writer) ath your disposal, should that become necessary (it will!).

thank you.

should i erase the bootloader flash first then flash the new one like this:

flash_erase /dev/mtd0 0 0

dd if=/tmp/u-boot-new-padded.bin of=/dev/mtd0 bs=1k

or i can flash it directly?

Depending on the structure, mtd0 could be the whole flash... Erasing that is likely not wanted.

You haven't given any details about your device's mtd structure, so no advice coming...

The more "normal" way might be to just "mtd write" directly, especially if there is a clearly defined u-boot mtd partition.
https://openwrt.org/docs/techref/mtd

In general, like slh says above, flashing the bootloader is really risky.
Try to avoid it, if possible.
What is your actual goal/benefit that you are seeking here?

Ps. hard to believe that a fresh copy of upstream u-boot would work ok. If you have no knowledge about the changes that OEM has likely done to the currently running u-boot, you are on shaky ground.

i just want to take thee full control of this device, and i like that all firmwares in it are updates and opensource.

the other goal is to learn updating the bootloader in this deice since i find it easier because the soc is already supported in uboot, i have another router (P298 N13 ooredoo R291) that has a modified uboot which i very limited: no tftp no ethernet which make the device very easy to brick without any easy rescue option.

Out of curiosity I just googled the dev.
lu=tftp 0x80060000 ${dir}u-boot.bin&&erase 0x9f000000 +$filesize&&cp.b $fileaddr 0x9f000000 $filesize
Indicates you can load uboot actually into RAM for testing before flashing it.
EDIT: Ofc I dont know if this is really possible bc. the command "lu" would write the loaded uboot. But maybe there is a command to load the tftp pushed image actually? At least you would not need OpenWrt to write the image.

you mean hh41v?

loading the uboot into ram can be done from openwrt ssh or from uart console?

For u-boot console you'll need a serial connection and then you can do something like below provided stock u-boot has commands 'tftpboot' and 'go'. You might need to change load address etc.

#chain-load u-boot

setenv ipaddr 192.168.1.1; setenv serverip 192.168.1.254; tftpboot 0x80200000 u-boot.bin && go 0x80200000

or

#upgrade u-boot

setenv ipaddr 192.168.1.1; setenv serverip 192.168.1.254; tftpboot 0x85000000 u-boot.bin
mtdparts default
sf probe && sf erase u-boot 0x40000 && sf write 0x85000000 u-boot ${filesize}

y, i was just curios if it is worth to mess around with uboot.

y, i thought so bc. if there is a command to load it into a RAM address you could potentially load it after from this address. @sandberg answered this question kindly.

It's not always as simple as just loading u-boot into memory and then running it from there.

The reason for this is that quite often, u-boot executes memory initialisation code that would wipe out the RAM that holds the code that is currently executing. You can build a custom u-boot without the memory initialisation step, then "chain load" the new u-boot from the old one to test functionality other than the lowest level init code (e.g. ethernet drivers, etc), but that is still no guarantee that the lowest level initialisation code is good.

As other posters have indicated, make sure you have backups of the entire flash, as well as a mechanism to restore the backup to the flash chip if your custom u-boot fails to work as expected.

Thank you for elaborating more on this topic. I knew that chainloading is a major hurdle to make this working resp. the installed bootloader must support chainloading. I forgot to mention it bc. my knowledge regarding uboot is outdated and sketchy. I dont deal with uboot regulary. But I thought it is worth to try to find out before trying to flash uboot.

The installed bootloader doesn't need explicit support for chainloading. As far as it is concerned the new u-boot is a payload to execute, just like a kernel. It is the new U-Boot that needs to be configured to assume initialised RAM, and not re-initialise it.

It used to be called CONFIG_SKIP_LOWLEVEL_INIT, but that seems to be deprecated nowadays. i.e. actual code blocks guarded by this option are very limited. Not 100% sure what has replaced it. Possibly driver model tags.

Ty, again for slapping this right into my face. It's actually very valueable for the threadstarter and me. But it tells me also its much more complex then I initially thought bc. if I understand this correctly (I could be totally wrong again) the "chainloaded" bootloader has to be aware what is already initialized by the "initial" bootloader bc. this could conflict with what the "new" chainloaded bootloader is actually trying/want to do. A nightmare. oO

Yes. In theory, the new u-boot may encounter peripherals that are in an unexpected state. e.g the Ethernet driver has brought up the interface to transfer the payload, but has not reset it to "power on" defaults. If the driver in the new payload doesn't know how to initialise it in that state, there could be problems. This is obviously just an example to illustrate the point, I know nothing about Ethernet drivers.