写一个简单的BootLoader(三)——boot.c分析笔记

这个简单的BootLoader一共有三个源文件,分别是start.S、init.c、boot.c,前两个的作用已经在前两篇文章中分析过了,主要起到初始化硬件的作用。那么自然地,BootLoader的另外一个重要作用——启动内核,就需要由boot.c来完成了。

这个文件是用于启动内核的,主要有四个步骤:
1. 帮内核设置串口:
2. 从NAND FLASH里把内核读入内存
3. 设置参数
4. 跳转执行

设置参数是最复杂的一部分内容:

setup_start_tag等函数的具体操作,可以直接从U-Boot中拷贝过来。setup.h拷贝过来之后稍作写修改即可使用,tag等结构体也是在setup.h中定义的。(使用SourceInsight查找)


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


static struct tag *params;

void setup_start_tag(void)
{
    params = (struct tag *)0x30000100;

    params->hdr.tag = ATAG_CORE;//tag结构体中有一个tag_header类型的hdr结构体,成员
    params->hdr.size = tag_size (tag_core);//就是tag和size

    params->u.core.flags = 0;//tag最后被命名为u
    params->u.core.pagesize = 0;
    params->u.core.rootdev = 0;

    params = tag_next (params);//以上设置完成之后,params跳到下一个tag
    //#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size)),
    //所以就可以指向下一个tag的内存空间
}

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;//内存大小64M

    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;//之所以>>2是因为size
    //都是以4字节为单位的
    //像4取整应该是+3,u-boot中的代码用的是+1+4,他说不好,然而这好像一个样

    strcpy (params->u.cmdline.cmdline, cmdline);//把命令拷贝到字符存放区

    params = tag_next (params);
}

void setup_end_tag(void)
{
    params->hdr.tag = ATAG_NONE;//结束就很简单,两个0就可以了
    params->hdr.size = 0;
}


int main(void)
{
    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");
    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();
    setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
    setup_end_tag();

    /* 3. 跳转执行 */
    puts("Boot kernel\n\r");
    theKernel = (void (*)(int, int, unsigned int))0x30008000;
    theKernel(0, 362, 0x30000100);  
    /* 
     *  mov r0, #0
     *  ldr r1, =362//机器ID
     *  ldr r2, =0x30000100//参数的位置
     *  mov pc, #0x30008000 //内核的位置
     */

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

    return -1;
}


你可能感兴趣的:(BootLoader)