自己写bootloader------编写第2阶段

我们的bootloader要实现以下功能,

  • 初始化硬件:关看门狗,设置时钟,设置SDRAM,初始化nand falsh,
  • 如果bootloader比较大,要把它重定位到SDRAM。
  • 把内核从nandflash读到SDRAM
  • 设置"要传给内核的参数"
  • 跳转到内核

在第一阶段我们实现了初始化以及重定位,并且封装了nandread函数,接下来实现后面三项功能,我们将新建一个boot.c,在里面的main函数中实现这三个功能。

1 从nandflash里把内核读入内存

那么我们从哪个地址开始读,读到哪里,读多大,我们在开发板的uboot命令行用mtd命令看一下,得到

 我们可以看到kernal存在0x0060000这个地方,还有一个问题就是我们烧写的内核是uImage,uImage=64字节的头部 + zImage。我们的uImage存在0x0060000这里,那么我们的zImage存在0x0060000 + 64这里。

那么读到哪里呢,我们再uboot里面用boot命令启动看一下,得到

 可以看到内核是放到内存的30008000这里,于是我们用如下代码将内核从nandflash读到SDRAM里面。

nand_read(0x60000+64, (unsigned char *)0x30008000, 0x200000);

2 设置参数

我们的uboot要告诉内核我们的内存有多大,告诉内核启动的命令行参数,这些参数都是通过tag进行传递的,就是在某一块内存上保存着这些参数,然后内核直接去这个内存读取参数,我们一共需要四个tag

	/* 2. 设置参数 */
	puts("Set boot params\n\r");
	setup_start_tag();
	setup_memory_tags();
	setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
	setup_end_tag();
  • setup_start_tag()表示设置参数开始的地方,
  • setup_memory_tags()高速内核我们的内存有多大;
  • setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");命令行参数tag
  • setup_end_tag();表示参数结束的地方。

2.1 setup_start_tag()

我们首先看一下uboot的start_tag是怎么写的,

 这里面有一个参数param,我们看一下param的定义

 那我们在自己的bootloader里面也定义这么一个结构体,其中的tag是这么一个结构体

 tag结构体是在uboot的setup.h里面声明的,我们直接把这个setup.h复制过来用,然后这个setup.h里面的u32 u16 u8没有定义,我们在里面定义一下。

然后我们开始写setup_start_tag,我们直接把uboot里面的setup_start_tag函数复制过来,

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);
}

经过setup_start_tag之后得到

其中params = tag_next (params);的意思是指向下一个tag,这个宏定义是当前tag+size也就是指向了下一个tag。  ​​​​​

 2.2 setup_memory_tag

我们同样模仿uboot里面的写法,我们先看一下uboot里面的

 我们的内存起始地址是0x30000000,大小是64M,因此得到

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);
}

2.3 setup_commandline_tag

视频到24分钟了。

3 跳转

我们参考uboot的代码,uboot启动主要执行bootm命令

于是我们去uboot代码中搜一下bootm这个命令,在cmd_bootm.c这个文件中的do_bootm函数,在do_bootm这个函数中调用了do_bootm_linux函数,在这里面定义了一个函数指针,

我们也仿照着定义一个函数指针,

void (*theKernel)(int zero, int arch, unsigned int params);

猜你喜欢

转载自blog.csdn.net/u013171226/article/details/123607387