自己写bootloader笔记6---boot.c分析(u-boot向内核传递参数及跳转到内核)

时间:2021-07-19 16:52:27
#include "setup.h"


extern void uart0_init(void);
extern void nand_read(unsigned int addr, unsigned char *buf, unsigned int len);
extern void puts(char *str);
extern void puthex(unsigned int val);


u-boot 传参数给内核分析参考http://blog.csdn.net/qingkongyeyue/article/details/52312095

//定义tag结构体
static struct tag *params;

//开始标志函数
void setup_start_tag(void)
{
params = (struct tag *)0x30000100;


params->hdr.tag = ATAG_CORE;
params->hdr.size = tag_size (tag_core);


params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;


params = tag_next (params);
}

//内存相关标志函数
void setup_memory_tags(void)
{
params->hdr.tag = ATAG_MEM;
params->hdr.size = tag_size (tag_mem32);

params->u.mem.start = 0x30000000;
params->u.mem.size  = 64*1024*1024;

params = tag_next (params);
}

//获取字符串大小函数
int strlen(char *str)
{

int i = 0;

//循环取字符,直到最后一个

while (str[i])
{
i++;
}
return i;
}

//字符串拷贝函数
void strcpy(char *dest, char *src)

{

//循环拷贝直到出现结束字符

while ((*dest++ = *src++) != '\0');
}

//命令行参数相关标志

void setup_commandline_tag(char *cmdline)
{
int len = strlen(cmdline) + 1;

params->hdr.tag  = ATAG_CMDLINE;
params->hdr.size = (sizeof (struct tag_header) + len + 3) >> 2;


strcpy (params->u.cmdline.cmdline, cmdline);


params = tag_next (params);
}

//结束标志函数
void setup_end_tag(void)
{
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;
}



//主函数
int main(void)

{

//定义函数指针theKernel

void (*theKernel)(int zero, int arch, unsigned int params);
volatile unsigned int *p = (volatile unsigned int *)0x30008000;


/* 0. 帮内核设置串口: 内核启动的开始部分会从串口打印一些信息,但是内核一开始没有初始化串口 */
uart0_init();

/* 1. 从NAND FLASH里把内核读入内存 */

puts("Copy kernel from nand\n\r");

//bootloader不支持烧写,使用u-boot烧写,uImage=64字节的头部+zImage(真正的内核),从下面可以看出uImage存在0x60000,zImage存在0x60000+64

自己写bootloader笔记6---boot.c分析(u-boot向内核传递参数及跳转到内核)

真正的内核源地址0x60000+64,目的地址0x30008000,内核大小0x200000(2M)

nand_read(0x60000+64, (unsigned char *)0x30008000, 0x200000);
puthex(0x1234ABCD);
puts("\n\r");
puthex(*p);
puts("\n\r");


/* 2. 设置参数 */

puts("Set boot params\n\r");

//表参数设置的开始

setup_start_tag();

//告诉内核,内存有多大

setup_memory_tags();

//命令行参数 root=/dev/mtdblock3表示根文件系统在哪里 init=/linuxrc console=ttySAC0表示内核启动时,内核的打印信息从哪个串口打印出来

setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");

//表参数设置的结束

setup_end_tag();


/* 3. 跳转执行 */

puts("Boot kernel\n\r");

//函数指针指向0x30008000

theKernel = (void (*)(int, int, unsigned int))0x30008000;

第一个参数是0,第二个参数是机器ID(板子属于哪一类)(参考u-boot程序),第3个参数是存放传给内核的参数的位置0x30000100

theKernel(0, 362, 0x30000100);  
/* 
*  mov r0, #0
*  ldr r1, =362

*  ldr r2, =0x30000100

跳过去执行内核,因为函数指针指向0x30008000。内核代码肯定会解析机器ID这个参数,并把传给内核的参数的位置0x30000100记下来,以后去这个地址读出保存的参数

*  mov pc, #0x30008000 
*/


puts("Error!\n\r");
/* 如果一切正常, 不会执行到这里 */


return -1;
}