博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux和Uboot下eMMC boot分区读写
阅读量:4285 次
发布时间:2019-05-27

本文共 5058 字,大约阅读时间需要 16 分钟。

1. eMMC的分区

大部分eMMC都有类似如下的分区,其中BOOT、RPMB和UDA一般是默认存在的,gpp分区需要手动创建。

BOOT主要是为了支持从eMMC启动系统而设计的;RPMB即Replay Protected Memory Block简称,通常用来保存安全线管的数据;GPP主要用于存储系统或者用户数据。

UDA通常会进行再分区,然后根据不同目的存放相关数据,或者格式化成不同文件系统。

2. Linux下读写boot分区

因为boot分区中一般存放的是bootloader或者相关配置参数,这些参数一般是不允许修改的,所以默认情况下是能读boot分区,不能写。

2.1 使能读写

如果需要些则需要,修改/sys/block/mmcblk0boot1/force_ro。

使能写:

echo 0 > /sys/block/mmcblk0boot1/force_ro

关闭写:

echo 1 > /sys/block/mmcblk0boot1/force_ro

在重启之后,force_ro会恢复为1。

2.2 内核force_ro实现

下面来看看force_ro是如何起作用的?

eMMC在被初始化的时候,调用mmc_blk_probe(),这里面会在每个设备下创建force_ro sysfs节点。

复制代码

static int mmc_blk_probe(struct mmc_card *card){...    if ((md))        goto out;...}static int mmc_add_disk(struct mmc_blk_data *md){    int ret;    struct mmc_card *card = md->queue.card;    device_add_disk(md->parent, md->disk);    md->force_ro.show =;    md->force_ro.store =;----------------------------------------------设置分区是否只读,0可读写;1只读。    sysfs_attr_init(&md->force_ro.attr);    md->force_ro.attr.name = "force_ro";    md->force_ro.attr.mode = S_IRUGO | S_IWUSR;    ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);    if (ret)        goto force_ro_fail;    if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&         card->ext_csd.boot_ro_lockable) {        umode_t mode;        if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)            mode = S_IRUGO;        else            mode = S_IRUGO | S_IWUSR;        md->power_ro_lock.show = power_ro_lock_show;        md->power_ro_lock.store = power_ro_lock_store;        sysfs_attr_init(&md->power_ro_lock.attr);        md->power_ro_lock.attr.mode = mode;        md->power_ro_lock.attr.name =                    "ro_lock_until_next_power_on";        ret = device_create_file(disk_to_dev(md->disk),                &md->power_ro_lock);        if (ret)            goto power_ro_lock_fail;    }    return ret;power_ro_lock_fail:    device_remove_file(disk_to_dev(md->disk), &md->force_ro);force_ro_fail:    del_gendisk(md->disk);    return ret;}static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,                 char *buf){    int ret;    struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));    ret = snprintf(buf, PAGE_SIZE, "%d\n",               get_disk_ro(dev_to_disk(dev)) ^               md->read_only);    mmc_blk_put(md);    return ret;}static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,                  const char *buf, size_t count){    int ret;    char *end;    struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));    unsigned long set = simple_strtoul(buf, &end, 0);    if (end == buf) {        ret = -EINVAL;        goto out;    }    set_disk_ro(dev_to_disk(dev), set || md->read_only);    ret = count;out:    mmc_blk_put(md);    return ret;}

复制代码

2.3 读写boot分区操作

在force_ro为1的情况下,写boot分区返回Operation not permitted。

echo updt | dd of=/dev/mmcblk0boot1 bs=4 count=1 seek=0 && syncdd: writing '/dev/mmcblk0boot1': Operation not permitted1+0 records in0+0 records out

然后打开force_ro=0:

echo 0 > /sys/block/mmcblk0boot1/force_ro && echo updt | dd of=/dev/mmcblk0boot1 bs=4 count=1 seek=0 && sync

通过hexdump验证一下:

hexdump -v -n 4 -s 0 /dev/mmcblk0boot10000000 7075 7464                              0000004

3. uboot下读写boot分区

uboot下操作boot分区需要打开CONFIG_SUPPORT_EMMC_BOOT。

在Linux下/dev/mmcblk0boot1就表示切换到boot分区了,在uboot下需要先切换到boot分区。

3.1 PARTITION_CONFIG寄存器

由于默认分区是UDA,而eMMC每个分区都是独立编址的。所以要使用boot分区需要切换分区。

PARTITION_CONFIG寄存器,通过EXT_CSD_PART_CONF命令来设置。

根据下面的寄存解释,BOOT_ACK设置为0x0,;BOOT_PARTITION_ENABLE设置为0x2;PARTITION_ACCESS设置为0x2。

3.2 读取boot分区

uboot中读取boot分区,首先需要将分区切换到boot分区,然后读写分区,最后将分区切换回原来分区。

复制代码

static int do_mmc_bootmode(cmd_tbl_t *cmdtp, int flag,            int argc, char * const argv[]){    struct mmc *mmc;    int ret = BOOTMODE_NORMAL;    u32 blk, cnt, n;    void *addr;    char original_part;    addr = (void *)malloc(512);    blk = BOOTMODE_BLK_NUM;    cnt = BOOTMODE_BLK_COUNT;    mmc = init_mmc_device(curr_device, false);    if (!mmc)    {        free(addr);        return CMD_RET_FAILURE;    }    /* Switch to the Boot 2 partition */    original_part = mmc->block_dev.hwpart;    blk_select_hwpart_devnum(IF_TYPE_MMC, curr_device, MMC_PART_BOOT2);    mmc_set_part_conf(mmc, 0, MMC_PART_BOOT2, 2);------------------------------------------切换到eMMC boot1分区。    n = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, addr);----------------------------------读取一个block。    if(n != cnt)    {        free(addr);        return CMD_RET_FAILURE;    }    /* flush cache after read */    flush_cache((ulong)addr, cnt * 512); /* FIXME */    if(*(unsigned int *)addr == BOOTMODE_UPDATE_MAGIC)    {        ret = BOOTMODE_UPDATE;    }    else    {        ret = BOOTMODE_NORMAL;    }#if 0    for(int i = 0; i < 512/16; i++)        printf("%08x %08x %08x %08x\n", *((int *)addr+i*4), *((int *)addr+i*4+1), *((int *)addr+i*4+2), *((int *)addr+i*4+3));#endif    /* Switch to original partition. */    blk_select_hwpart_devnum(IF_TYPE_MMC, curr_device, original_part);----------------------切换到默认分区。    free(addr);    return ret;}

复制代码

至此可以在Linux和Uboot下对boot分区进行操作,进行bootloader烧写或者进行重要数据更新。

你可能感兴趣的文章
狂神说java,html5基础知识讲解全总结
查看>>
Mac idea 替换快捷键
查看>>
CSS3 position sticky固定定位失败的原因
查看>>
狂神说Java CSS3讲解综合代码
查看>>
springboot-mybaits 的mapper文件中使用insert into xx values(xxx) on duplicate key update
查看>>
python-day2 python的基本语法(注释,运算符,数据类型,在python中,定义变量时,不需要指定变量的类型的)
查看>>
Springboot-data-es 自动创建mapping(mapping的数据结构为空)以及自动添加新字段(生成mapping的数据结构)
查看>>
数据分析-day04-pandas-dataFrame中查询数据与修改赋值修改语句(r=df[df["z"]==6] & df["z"]=6)
查看>>
数据分析-day06-pandas-dataFrame案例分析1(方法一):获取title字段中包含物流运输业名称作为分类,统计各个分类的条数
查看>>
数据分析-day06-pandas-dataFrame案例分析1(方法二):获取title字段中包含物流运输业名称作为分类,统计各个分类的条数,
查看>>
数据分析-day06-pandas-dataFrame案例分析4:使用PeriodIndex将离散组成pandas的时间序列,然后统计不同时间段,两个地方的pm值走势
查看>>
static synchronized方法和synchronized方法的区别和联系-2(class锁和对象锁,不同锁,混合访问时)
查看>>
spring cloud 自定义ribbon实现负载均衡(二) 解决自定义ribbon和springboot启动类放在同一包下
查看>>
重要重要》》》》》springcloud fegin的基本使用,实现consumer通过fegin访问provider!!!!!
查看>>
spring cloud 远程仓库配置文件(yml或properties)中有server.port参数就无法访问,这是一个大坑吗?
查看>>
es 2.3.3 向es添加数据报NoNodeAvailableException[None of the configured nodes are available
查看>>
springboot 的@RequestBody JSONObject 与@RequestBody Object 的区别
查看>>
springboot pom文件设置<packaging>pom</packaging> 对于application.yml无法加载读取的问题
查看>>
springboot加载resouce下面的静态文件,templates目录的访问,以及经过controller后跳转页面问题
查看>>
shiro的通过md5+salt+hash散列进行注册操作
查看>>