IMX6Solo启动流程 外传-新建一条Uboot命令
来源:互联网 发布:js点击空白处触发事件 编辑:程序博客网 时间:2024/05/16 15:01
写在前头
*.版权声明:本篇文章为原创,可随意转载,转载请注明出处,谢谢!另我创建一个QQ群82642304,欢迎加入!
*.目的:整理一下RIotBoard开发板的启动流程,对自己的所学做一个整理总结,本系列Uboot代码基于2009.08版。
*.备注:整个系列只是对我所学进行总结,记录我认为是关键的点,另我能力有限,难免出现疏漏错误,如果读者有发现请多指正,以免我误导他人!
原理
在《IMX6Solo启动流程-从Uboot到kernel 上》中我们讲到了Uboot命令是通过宏U_BOOT_CMD来定义的.所以新建一条命令实际上就是定义一个宏的过程.
在新建一条命令之前,我们先要区分一下新建的命令是属于通用的还是专用的,所谓通用就是你的命令与具体的硬件无关,例如tftp命令,bootm命令等,专用的就是你的命令只能在你的硬件上面跑.
Uboot的命令一般在两个地方定义,一个是common目录下,在这里面定义的一般都是通用的命令,另外一个就是在board/xxx目录下,定义的就是专用的,当然这不是强制要求,只是一个建议,这样定义命令能够让逻辑分开.
我在每次更新Uboot或者内核的时候都要执行
tftp u-boot.bin
mmc dev 3
mmc erase 0 400
mmc write ${loadaddr} 0 400
对于我这种懒人来说,复制粘帖这几行都是一件繁琐的事情.所以就想新建一条命令,能够一条命令执行以上四个步骤.
在RIotBoard开发板上,存储设备是emmc,即port 3,下载烧写地址和长度都是固定的,所以这是一条专用的命令.当然你也可以将这些数据以参数的形式传给命令,将命令拓展成通用的.其实都一样.
首先在board/freescale/mx6q_riot/目录下新建cmd_update.c,定义命令
U_BOOT_CMD( uduboot, 2, 1, do_uduboot, "download uboot from tftp,then update it", "uduboot [uboot file name]");U_BOOT_CMD( udkernel, 2, 1, do_udkernel, "download kernel from tftp,then update it", "udkernel [kernel file name]");
然后实现函数do_uduboot和do_uduboot.接下来修改board/freescale/mx6q_riot/Makefile,将cmd_update.c编译进去.
COBJS := $(BOARD).o cmd_update.o
在COBJS中增加 cmd_update.o
重新编译Uboot并下载烧写,在Uboot的命令交互模式下就可以看到新加两条命令uduboot和udkernel.
另:使用tftp需要配置Uboot的环境变量ipaddr和serverip,每次烧写Uboot,之前配置的环境变量值都会被恢复默认值,所以可以通过修改ipaddr和serverip的默认值,后续烧写Uboot就无需修改IP地址.
源码
#include <common.h>#include <command.h>#include <asm/io.h>#include <mmc.h>#include <net.h>#include <malloc.h>#define UBOOT_FILE_OFFSET 1024#define MMC_PAGE_SIZE 512extern ulong TftpRRQTimeoutMSecs;extern int TftpRRQTimeoutCountMax;extern ulong load_addr;extern enum boot_device get_boot_device(void);extern int get_mmc_env_devno(void);/* follow function copy from $(TOPDIR)/common/update.c */static int update_load(char *filename, ulong msec_max, int cnt_max, ulong addr){ int size, rv; ulong saved_timeout_msecs; int saved_timeout_count; char *saved_netretry, *saved_bootfile; rv = 0; /* save used globals and env variable */ saved_timeout_msecs = TftpRRQTimeoutMSecs; saved_timeout_count = TftpRRQTimeoutCountMax; saved_netretry = strdup(getenv("netretry")); saved_bootfile = strdup(BootFile); /* set timeouts for auto-update */ TftpRRQTimeoutMSecs = msec_max; TftpRRQTimeoutCountMax = cnt_max; /* we don't want to retry the connection if errors occur */ setenv("netretry", "no"); /* download the update file */ load_addr = addr; copy_filename(BootFile, filename, sizeof(BootFile)); size = NetLoop(TFTP); if (size < 0) rv = 1; else if (size > 0) flush_cache(addr, size); /* restore changed globals and env variable */ TftpRRQTimeoutMSecs = saved_timeout_msecs; TftpRRQTimeoutCountMax = saved_timeout_count; setenv("netretry", saved_netretry); if (saved_netretry != NULL) free(saved_netretry); if (saved_bootfile != NULL) { copy_filename(BootFile, saved_bootfile, sizeof(BootFile)); free(saved_bootfile); } return rv;}int DownloadAndUpdate(char * filename,unsigned int maxsize, unsigned int startblk,unsigned int fileoffset){ char * serverIP = getenv("serverip"); struct mmc * mmc = NULL; block_dev_desc_t * mmc_dev = NULL; char * s; ulong addr; uint boot_devno; unsigned int filesize; unsigned int block; if (NULL == serverIP) { printf("error: not found tftp server IP\n"); return -1; } /* get load address of downloaded update file */ if ((s = getenv("loadaddr")) != NULL){ addr = simple_strtoul(s, NULL, 16); }else{ printf("error: not found $(loadaddr)\n"); return -1; } if (MMC_BOOT != get_boot_device()) { printf("error: only support MMC boot dev\n"); return -1; } printf("download %s from %s\n",filename,serverIP); if(update_load(filename,100,10,addr)){ printf("error: download failure\n"); return -1; }else if (NULL == (s = getenv("filesize"))) { printf("error: download failure,not found $(filesize)\n"); return -1; }else{ filesize = simple_strtol(s,NULL,16); if (filesize < maxsize) { printf("download success,file length %d(0x%x)\n", filesize, filesize); }else{ printf("error: download failure,$(filesize) bigger then 1M\n"); return -1; } } block = (filesize + MMC_PAGE_SIZE - 1)/MMC_PAGE_SIZE; boot_devno = readl(SRC_BASE_ADDR + 0x4); /* BOOT_CFG2[3] and BOOT_CFG2[4] */ boot_devno = (boot_devno & 0x00001800) >> 11; if (boot_devno >= CONFIG_SYS_FSL_USDHC_NUM) { printf("error: not such mmc dev %d\n",boot_devno); return -1; }else{ printf("boot dev is MMC%d\n",boot_devno); } if(NULL == (mmc = find_mmc_device(boot_devno))){ printf("Can't find mmc devno %d\n",boot_devno); return -1; } mmc_init(mmc); if (NULL == (mmc_dev = mmc_get_dev(boot_devno))) { printf("mmc init failure %d\n",boot_devno); return -1; } if (block != mmc_dev->block_erase(boot_devno,startblk,block)) { printf("error: erase %d,%d failure\n",startblk,block); return -1; }else{ printf("erase %d,%d\n",startblk,block); } if (block != mmc_dev->block_write(boot_devno,startblk,block,(void *)(addr + fileoffset))) { printf("error: write %d,%d failure\n",startblk,block); return -1; }else{ printf("write %d,%d,0x%x\n",startblk,block,addr + fileoffset); } printf("update %s success\n",filename); return 0; }int do_uduboot ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){ char * filename = "u-boot.bin"; if (argc > 1) { filename = argv[1]; } return DownloadAndUpdate(filename,0x100000,UBOOT_FILE_OFFSET/MMC_PAGE_SIZE,UBOOT_FILE_OFFSET);};int do_udkernel ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){ char * filename = "uImage"; if (argc > 1) { filename = argv[1]; } return DownloadAndUpdate(filename,0x800000,0x800,0);};U_BOOT_CMD( uduboot, 2, 1, do_uduboot, "download uboot from tftp,then update it", "uduboot [uboot file name]");U_BOOT_CMD( udkernel, 2, 1, do_udkernel, "download kernel from tftp,then update it", "udkernel [kernel file name]");
总结
只要了解U_BOOT_CMD宏的原理之后,新建一条命令就十分简单。
另:上述的功能也可以通过将多条命令用分号隔开,保存到一个环境变量中,然后通过run命令来执行,达到一样的效果。类似bootcmd的做法,这里就不再赘述.
参考
暂无
- IMX6Solo启动流程 外传-新建一条Uboot命令
- IMX6Solo启动流程-从上电到Uboot
- IMX6Solo启动流程-从Uboot到kernel 上
- IMX6Solo启动流程-从Uboot到kernel 中
- IMX6Solo启动流程-从Uboot到kernel 下
- IMX6Solo启动流程-Linux 内核启动 一
- IMX6Solo启动流程-Linux 内核启动 二
- IMX6Solo启动流程-Linux 内核启动 三
- IMX6Solo启动流程-Linux 内核启动 四
- IMX6Solo启动流程-Linux 内核启动 五
- IMX6Solo启动流程-Linux 内核启动 六
- IMX6Solo启动流程-Linux 内核启动 七
- laravel新建一条命令
- uboot启动流程
- uboot启动流程
- uboot 启动流程分析
- Uboot 启动流程简介
- Uboot启动流程分析
- statement 、prepareStatement的用法和解释
- spring schedule定时任务
- notification的简单使用
- Item 22:数据成员应声明为私有 Effective C++笔记
- 初探Qt Opengl【1】
- IMX6Solo启动流程 外传-新建一条Uboot命令
- 三种排序方式
- !Important的使用及测试
- @media css样式
- 1094. The Largest Generation (25)
- Copy + Paste (Clipboard) Issues / Not Working?
- 无线路由器QoS设置——连接数限制
- IOS第三方代码收集
- 可以接收链路层MAC帧的原始套接字