When I make a test jig for a project, I need to write new uboot to cover old one. Normally I will use uboot UART to update uboot partition, that is the fastest way, we do not have to wait Linux system ready, but it has a failure rate because UART is not very stable.
Currently I need to login to Linux and run test application. I do not have to upload from UART anymore, but same time, I just found u-boot partition is default read-only. This is locked in VOCORE2.dts at compile stage to avoid user erase uboot by mistake. If we need to overwrite u-boot, we can not modify it directly but have to upgrade the firmware who has a writeable u-boot partition.
If I upgrade the firmware, it will take too much time, at least 2 minutes…not acceptable for mass production. For that reason, I am thinking, is that possible we hack the kernel and remove the READ-ONLY tag from mtd partition without do change to firmware?
Lucky, that is possible, and pretty simple to do.
mtd driver has a structure named mtd_info to store every detail of a mtd partition. It is using a flag named MTD_WRITEABLE to determine whether a mtd partition is readonly or not.
Reference: linux-4.14/drivers/mtd/ofpart.c
if (of_get_property(pp, "read-only", &len))
parts[i].mask_flags |= MTD_WRITEABLE;
Now, just need to find a way add that MTD_WRITEABLE flag to mtd partition.
We can not do it in user mode, because kernel mode memory is protected. So I write a small driver for it.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
int w2uboot_init(void)
{
struct mtd_info *mtd;
mtd = get_mtd_device_nm("u-boot");
mtd->flags |= MTD_WRITEABLE;
printk(KERN_INFO "unlock u-boot, now it is writeable\n");
return 0;
}
void w2uboot_exit(void)
{
}
module_init(w2uboot_init);
module_exit(w2uboot_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Qin Wei");
Compile and insert this module to kernel. Magically, the u-boot is unlocked. Now we can use mtd -e u-boot write uboot.bin u-boot write to uboot partition.
To compile the code(save as w2uboot.c), try this way in same folder:
echo 'obj-m=w2uboot.o' > Makefile
make -C [path to linux]/linux-4.14.195 M=$(PWD) CROSS_COMPILE=mipsel-openwrt-linux- ARCH=mips