Linux和Uboot下eMMC boot分区读写
关键词:eMMC boot、PARTITION_CONFIG、force_ro等。
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 > /sys/block/mmcblk0boot1/force_ro
关闭写:
echo > /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 (mmc_add_disk(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 =force_ro_show;
md->force_ro.store =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, );
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= count= seek= && sync
dd: writing '/dev/mmcblk0boot1': Operation not permitted
+ records in
+ records out
然后打开force_ro=0:
echo > /sys/block/mmcblk0boot1/force_ro && echo updt | dd of=/dev/mmcblk0boot1 bs= count= seek= && sync
通过hexdump验证一下:
hexdump -v -n -s /dev/mmcblk0boot1
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();
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, , MMC_PART_BOOT2, );------------------------------------------切换到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 * ); /* FIXME */ if(*(unsigned int *)addr == BOOTMODE_UPDATE_MAGIC)
{
ret = BOOTMODE_UPDATE;
}
else
{
ret = BOOTMODE_NORMAL;
} #if 0
for(int i = ; i < /; i++)
printf("%08x %08x %08x %08x\n", *((int *)addr+i*), *((int *)addr+i*+), *((int *)addr+i*+), *((int *)addr+i*+));
#endif
/* Switch to original partition. */
blk_select_hwpart_devnum(IF_TYPE_MMC, curr_device, original_part);----------------------切换到默认分区。 free(addr); return ret;
}
至此可以在Linux和Uboot下对boot分区进行操作,进行bootloader烧写或者进行重要数据更新。
Linux和Uboot下eMMC boot分区读写的更多相关文章
- uboot下emmc内容烧写(拷贝)步骤
一.目的:嵌入式开发板,通过emmc上的内核文件加载启动linux操作系统,以及存放其他程序文件.需要将所需文件先写入emmc中. 二.总体步骤是:uboot启动后,进入linux下,将emmc分区并 ...
- 解决Ubuntu 16.04下提示boot分区空间不足的办法
原文地址: http://www.jb51.net/article/106976.htm https://www.linuxidc.com/Linux/2015-09/123227.htm 因为lin ...
- eMMC之分区管理、总线协议和工作模式【转】
本文转载自:https://blog.csdn.net/u013686019/article/details/66472291 一.eMMC 简介 eMMC 是 embedded MultiMedia ...
- 关于ubuntu系统boot分区空间不足而又无法卸载旧内核的解决方法
2016年09月03日 14:16:45 萧氏一郎 阅读数:7802 标签: ubuntuboot分区清理更多 个人分类: linux 版权声明:本文为本猿原创文章,转载务必注明出处,多谢. ht ...
- Linux下的磁盘分区和逻辑卷
一.硬盘接口类型 硬盘的接口主要有IDE.SATA.SCSI .SAS和光纤通道等五种类型.其中IDE和SATA接口硬盘多用于家用产品中,也有部分应用于服务器,SATA是一种新生的硬盘接口类型,已经取 ...
- linux下硬盘的分区:
提到硬盘的分区,以前就是很乱,有什么主分区/扩展分区/逻辑分区等;它们有什么区别呢?现在简单的了解一下: 由于在MBR的主引导记录中的分区表里面最多只能记录4个分区记录,这个不够用啊,为了解决这个问题 ...
- linux系统下重要的分区及其作用
下面列出来的是linux系统下重要的分区及其作用/bin :bin是binary的缩写;/boot :存放启动Linux时使用的一些核心文件;/root :root(超级管理员)的用户主目录;/sbi ...
- linux下磁盘进行分区、文件系统创建、挂载和卸载
任务的原因:由于,刚购买来的服务器需要将磁盘挂载到操作系统上,为了挂载磁盘首先要对磁盘进行分区,然后进行文件系统的创建,最后将磁盘挂载到操作系统上的某个目录. MBR(Master Boot Reco ...
- linux下磁盘进行分区、文件系统创建、挂载和卸载(转)
任务的原因:由于,刚购买来的服务器需要将磁盘挂载到操作系统上,为了挂载磁盘首先要对磁盘进行分区,然后进行文件系统的创建,最后将磁盘挂载到操作系统上的某个目录. MBR(Master Boot Reco ...
随机推荐
- 基于 Nginx 的 HTTPS 性能优化实践
前言 分享一个卓见云的较多客户遇到HTTPS优化案例. 随着相关浏览器对HTTP协议的“不安全”.红色页面警告等严格措施的出台,以及向 iOS 应用的 ATS 要求和微信.支付宝小程序强制 HTTPS ...
- linux 制作不用密碼可立即登入的 ssh 用戶
机器环境: 192.167.33.48 clent 用户:server 192.167.33.47 server 用户:server 1.客户端 生成密钥 ssh-keygen 2. 查看密钥文件权限 ...
- Docker系列06—基于容器制作镜像并上传到Docker Registry
本文收录在容器技术学习系列文章总目录 1.制作镜像 1.1 镜像的生成途径 基于容器制作 dockerfile,docker build 本篇主要详细讲解基于容器制作镜像:基于dockerfile 制 ...
- 批处理启动vm虚拟机服务 vm12启动无界面启动vm虚拟机系统 windows上如何操作服务 sc net启动关闭服务
windows(win10)批处理脚本 打开vm虚拟机的服务,并且开启无界面虚拟机 @echo off net start "vds" net start "VMAuth ...
- WPF TabControl Unload俩次的解决方案
WPF中,有些控件会多次触发Unload,有点莫名其妙~ Unload的多次触发 TabControl的内容,我是这么设置的: 在TabItem的CacheSettingView中,监听Loaded/ ...
- 微信小程序支付接入注意点
一.微信支付后台服务器部署 服务器采用ubuntu16.04 + php7.0 + apache2.0. 微信支付后台服务使用了curl 和 samplexml ,因此php.ini配置中必须开启这两 ...
- mysql 随机数 rand使用
生成随机数 生成0-3的随机数 SELECT RAND() * 最大不会超过3, SELECT FLOOR(RAND() * ) 上面生成整数的值是0,1,2,3生成的随机整数是1,2,3的话,语句如 ...
- git合并两个不同的仓库
目前开发是2个仓库,线上仓库online_a(对应的branch分支为online),测试环境online_b(对应的branch分支为demo),测试环境需要时刻保持onine_a上的最新稳定稳定代 ...
- Python 100例(001)
#!/usr/bin/env python # coding:utf-8 '''有四个数字:1.2.3.4,能组成多少个互不相同且无重复数字的三位数?各是多少?''' n = 1 num = [4, ...
- C# 消息队列-MSMQ
MQ是一种消息中间件技术,所以它能够支持多种类型的语言开发,同时也是跨平台的通信机制,也就是说MQ支持将信息转化为XML或者JSon等类型的数据存储到消息队列中,然后可以使用不同的语言来处理消息队列中 ...