VoCore2: Force Write to Read-Only MTD Partition

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