第2阶段——编写uboot之启动内核和制作Makefile(2)
目标:
1 添加头文件setup.h和serial.h
2 写main函数
2.1 帮内核设置串口0, (内核启动会打印出启动信息)
2.2把内核读入到SDRAM
2.3设置参数(参考u-boot-1.1.6 /lib_arm/armlinux.C中do_bootm_linux()函数)
2.4跳转运行内核(参考u-boot-1.1.6/lib_arm/armlinux.C中do_bootm_linux()函数)
3 写tag参数函数
3.1 setup_start_tag (void);
3.2 setup_memory_tags(void);
3.3 setup_commandline_tag (char *cmdline);
3.4 setup_end_tag (void);
4 写makefile文件
1 添加头文件setup.h和serial.h
1.1 将lcd裸板程序中串口uart0初始化文件serial.c复制到my_bootloader目录中.并修改serial.c
1.2 因为TAG结构体定义是存在u-boot-1.1.6/include/asm-arm/setup.h中,所以设置TAG参数需要用到这个文件,将setup.h复制到my_bootloader目录中.
1.2.1 修改setup.h文件
删除以下不需要的代码:
- #define __tag __attribute__((unused, __section__(".taglist")))
- #define __tagtable(tag, fn) \
- static struct tagtable __tagtable_##fn __tag = { tag, fn }
- #define tag_member_present(tag,member) \
- ((unsigned long)(&((struct tag *)0L)->member + ) \
- <= (tag)->hdr.size * )
添加以下代码:
- #define u32 unsigned long
- #define u16 unsigned int
- #define u8 unsigned char
2. 新建my_bootloader/boor.c,用于存放main函数(main:由start.S跳转过来的).
main函数代码如下:
- void main(void)
- {
- void (*theKernel)(int zero, int arch, unsigned int params);
- /*定义一个函数指针theKernel,其中第一个参数zero:0 */
- /* arch:机器ID ,由于芯片类型很多,内核为了辨别芯片而定义的机器ID,其中2440芯片的ID号是362,*/
- /* params :tag参数位置,这里我们的tag起始地址=0x30000100*/
- /*1 初 始 化 串 口 0 , 使 内 核 能 打 印 信 息 */
- uart0_init(); //调用serial.h头文件里的uart0_init()
- puts(“uart0 init OK\r\n”); //打印uart0初始化
- /*2从 nand flash 里 把 内 核 复 制 到 SDRAM 中 */
- puts(“copy kernel from nand\r\n”); //打印内核复制
- nand_read((0x60000+),0X30008000,0X200000); //烧写2MB,多烧写点避免出错
- /*
- 0x60000+64:表示内核在nand(存储)地址上位置,
- 0X30008000:内核在sdram(运行)地址上位置
- 0X200000:内核长度2MB
- 因为Flash上存的内核格式是:uImage(64B头部(header) + 真正的内核 )
- 在uboot界面中输入mtd命令可以看到:
- kernel分区位于 nand的0X00060000~0x00260000
- 所以在nand中真正的内核地址=0x60000+64,
- 在uboot界面中输入boot命令可以看到:
- Data Size: 1848656 Bytes =1.8 MB
- Load Address: 30008000
- 所以内核目的地址=0X30008000
- 长度=1.8MB
- */
- /*3 设 置 T A G 参 数 */
- puts(“set boot params\r\n”); //打印设置参数信息
- setup_start_tag (void); //在0X30000100地址保存start_tag数据,
- setup_memory_tags (void); //保存memory_tag数据,让内核知道内存多大
- setup_commandline_tag (“boottargs=noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0”);
- /*保存命令行bootargs参数,让内核知道根文件系统位置在/dev/mtdblock3,指定开机运行第一个脚本/linuxrc,指定打印串口0*/
- setup_end_tag (void); //初始化tag结构体结束
- /* 4 跳 转 执 行 */
- puts(“boot kernel\r\n”); //打印启动内核
- theKernel = (void (*)(int, int, unsigend int))0x30008000;
- // 设置theKernel地址=0x30008000,用于后面启动内核
- theKernel(,,0x300000100); //362:机器ID, 0x300000100: params(tag)地址
- /*传递参数跳转执行到0x30008000启动内核, */
- /*相当于: mov r0,#0 */
- /*ldr r1,=362 */
- /*ldr r2,= 0x300000100 */
- /*mov pc,#0x30008000 */
- puts(“kernel ERROR\r\n”); //打印内核启动出错
- }
3.创建TAG参数函数(使main函数调用)
设置tag参数函数代码如下
- #include “setup.h”
- static struct tag *params; //定义个tag结构体变量params指针
- setup_start_tag (void) //开始tag
- {
- params = (struct tag *) 0x30000100; //tag起始地址等于0X30000100
- params->hdr.tag = ATAG_CORE; //头部常量tag=0x54410001
- params->hdr.size = tag_size (tag_core); //size=5,
- params->u.core.flags = ;
- params->u.core.pagesize = ;
- params->u.core.rootdev = ;
params = tag_next (params); //parmas=( struct tag *)((u32 *)parmas+ params->hdr.size)- }
- // setup_start_tag (bd)保存tag参数如下:
- setup_memory_tags (void) //内存tag
- {
- int i;
- params->hdr.tag = ATAG_MEM; //头部常量tag=0x54410002
- params->hdr.size = tag_size (tag_mem32); //size=4
- params->u.mem.start = 0x30000000; //SDRAM起始地址
- params->u.mem.size = 0x4000000; //SDRAM内存大小64M
- params = tag_next (params); //指向下个tag
- }
- // setup_memory_tag s(bd)保存tag参数如下:
- int strlen(char *str) //uboot不依赖任何库,所以需要自己写strlen函数
- {
- int i=;
- while(str[i])
- {
- i++;
- }
- return i;
- }
- void strcpy(char *dest, char *src)
- {
- while((*dest++=*src++)!=’\’&&*dest!=’\’);
- }
- setup_commandline_tag (char *cmdline) //命令行tag
- /**cmdline :指向命令行参数 */
- /*一般为:“boottargs=noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0” */
- {
- int len=strlen(cmdline)+; //计算cmdline长度,并加上结束符
- params->hdr.tag = ATAG_CMDLINE; //头部常量tag=0x54410009
- params->hdr.size =(sizeof (struct tag_header) +len+) >> ; /*size=(字符串长度+头部长度) >>2 */
- /*“+3”表示:按4字节对齐,比如当总长度=(1,2,3,4)时,size=(总长度+3)>>2=1,实现4字节对齐 */
- strcpy (params->u.cmdline.cmdline, cmdline); //复制形参字符串到params->u.cmdline.cmdline
- params = tag_next (params); //执行下个tag
- }
- setup_end_tag (void) //结束tag
- {
- params->hdr.tag = ;
- params->hdr.size = ;
- }
4 写makefile文件
4.1 首先将lcd裸板程序里的makefile复制到my_bootloader目录中,并修改.
备注:在makefile中‘=’与‘:=’的区别:
‘=’:无关位置的等于(比如:”x=a y=$(x) x=b”,那么y的值永远等于最后的值,等于 b ,而不是a)
‘:=’:有关位置的等于(比如:”x:=a y:=$(x) x:=b”,那么y的值取决于当时位置的值,等于 a ,而不是b)
代码如下:
- CC = arm-linux-gcc //定义CC变量=arm-linux-gcc,简化书写,编译命令,(*.C,*.S)文件生成*.O文件
- LD = arm-linux-ld //连接命令,将多个*.O文件生成 boot.elf
- AR = arm-linux-ar //库管理命令,这里没有用到
- OBJCOPY = arm-linux-objcopy //复制/格式转换命令, boot.elf生成boot.dis
- OBJDUMP = arm-linux-objdump //反汇编命令,boot.bin生成boot.dis
- CFLAGS := -Wall -O2 //GCC编译参数,-Wall:显示所有错误和警告, -O2:采用2级编译优化
- CPPFLAGS := -nostdinc -fno-builtin
- //添加头文件参数,-nostdinc忽略缺省目录, -fno-builtin不连接系统标准启动文件和标准库文件(表示不用自带的strlen()等库函数)
- objs := start.o init.o boot.o //定义objs变量,包含生成boot.bin目标文件需要的依赖文件
- boot.bin: $(objs) //执行生成目标文件,首先是先满足objs所有依赖文件都拥有,才执行
- ${LD} -Tuboot.lds -o boot_elf $^
- ${OBJCOPY} -O binary -S boot_elf $@
- ${OBJDUMP} -D -m arm boot_elf > boot.dis
- %.o:%.c //%通配符。生成xxx.o文件先要找到xxx.c文件
- ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $< //-c编译不连接。$@表示目标文件 $<表示第一个依赖文件
- %.o:%.S
- ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
- clean:
- rm -f *.bin *.elf *.dis *.o
第2阶段——编写uboot之启动内核和制作Makefile(2)的更多相关文章
- 第2阶段——编写uboot之硬件初始化和制作链接脚本lds(1)
目标: 1.关看门狗 2.设置时钟 3.初始化SDRAM (初始化寄存器以及清除bss段) 4.重定位 (将nand/nor中代码COPY到链接地址上,需要初始化nandflash,读flash) 5 ...
- uboot如何启动内核
2.7.1.uboot和内核到底是什么 2.7.1.1.uboot是一个裸机程序 (1)uboot的本质就是一个复杂点的裸机程序.和我们在ARM裸机全集中学习的每一个裸机程序并没有本质区别. 2.7. ...
- 第2阶段——编写uboot之编译测试以及改进(3)
编译测试: 1.将写好的uboot复制到linux下面 2.make编译,然后将错误的地方修改,生成boot.bin (编译出错的解决方案:http://www.cnblogs.com/lifexy/ ...
- UBOOT启动内核过程
1.摘要 (1).启动4步骤第一步:将内核搬移到DDR中第二步:校验内核格式.CRC等第三步:准备传参第四步:跳转执行内核(2).涉及到的主要函数是:do_bootm和do_bootm_linux(3 ...
- uboot学习之五-----uboot如何启动Linux内核
uboot和内核到底是什么?uboot实质就是一个复杂的裸机程序:uboot可以被配置也可以做移植: 操作系统内核本身就是一个裸机程序,和我们学的uboot和其他裸机程序没有本质的区别:区别就是我们操 ...
- u-boot向linux内核传递启动参数(详细)
U-BOOT 在启动内核时,会向内核传递一些参数.BootLoader 可以通过两种方法传递参数给内核,一种是旧的参数结构方式(parameter_struct),主要是 2.6 之前的内核使用的方式 ...
- uboot代码2:stage2代码,启动内核
一.uboot最终目的: 1.读出内核 do_nand read kernel { flash上存的内核:uImage = 头部 + 真正的内核; } 2.启动内核. do_bootm_linux { ...
- u-boot向linux内核传递启动参数
U-BOOT 在启动内核时,会向内核传递一些参数.BootLoader 可以通过两种方法传递参数给内核,一种是旧的参数结构方式(parameter_struct),主要是 2.6 之前的内核使用的方式 ...
- linux的几个内核镜像格式Image 和 u-boot启动内核和文件系统时的一些环境变量的设置
关于编译powerpc linux的几个Image参考原文 http://blog.sina.com.cn/s/blog_86a30b0c0100wfzt.html 转载▼ PowerPC架构 L ...
随机推荐
- RF+Appium框架自动化测试系列一之(Mac下Appium环境搭建)万事开头难
消失了3个月,有一段时间没来园子更新博客了,各位看官见谅哈哈,消失是因为刚换了工作环境没外网,好多笔记没能及时的记录分享,以后有时间慢慢补上吧,这段时间主要接触了移动端app的自动化测试,公司为了快速 ...
- 最短路和次短路问题,dijkstra算法
/* *题目大意: *在一个有向图中,求从s到t两个点之间的最短路和比最短路长1的次短路的条数之和; * *算法思想: *用A*求第K短路,目测会超时,直接在dijkstra算法上求次短路; ...
- 纯JavaScript实现异步Ajax的基本原理
Ajax实际就是XMLHttpRequest对象和DOM.(X)HTML和CSS的简称,用于概括异步加载页面内容的技术. Ajax实例 HTML代码如下,包含一个h5标题和一个按钮: JS代码如下 ...
- C语言内存申请与使用
1. 使用malloc申请一块空间,模拟KV存储的一个节点存储数据信息. #include<stdio.h> #include <unistd.h> #include < ...
- python 在大文件里面删除某一行,比较有效率的方法
用 python 处理一个文本时,想要删除其中中某一行,常规的思路是先把文件读入内存,在内存中修改后再写入源文件. 但如果要处理一个很大的文本,比如GB级别的文本时,这种方法不仅需要占用很大内存,而且 ...
- 前端布局之Flex语法
前端布局一直是CSS的一个重点应用,然而基于盒子模型的传统布局方案,依赖display + position + float 属性,对于某些特殊的布局非常不方便,比如:垂直居中就不容易实现.针对这一情 ...
- 2017多校第9场 HDU 6169 Senior PanⅡ 数论,DP,爆搜
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6169 题意:给了区间L,R,求[L,R]区间所有满足其最小质数因子为k的数的和. 解法: 我看了这篇b ...
- Vim入门基础
公司新员工学习有用到,Vim官网的手册又太大而全,而网上各方资料要么不全面,要么不够基础.在网上搜集各方资料,按照自己的框架整理一份Vim入门基础教程,分享出来.特点是偏向基础,但对入门者来说足够全面 ...
- Java中构造方法跟普通方法的区别?
构造方法与普通方法的调用时机不同. 首先在一个类中可以定义构造方法与普通方法两种类型的方法,但是这两种方法在调用时有明显的区别. 1.构造方法是在实例化新对象(new)的时候只调用一次 2.普通方法是 ...
- Thinkphp报错 -- “_STORAGE_WRITE_ERROR_”
磁盘满了 没有写入权限 解决方法: chmod -R 777 Runtime目录路径