自制简易BootLoader思路分析及实现

3 篇文章 0 订阅
3 篇文章 0 订阅

1,BootLoader功能分析:BootLoader最终要达到的目标是把Linux内核引导起来(相当于用户空间的Shell程序启动用户进程,但是Shell不仅仅具有启动用户进程的作用)
为了实现这个最终的目标,BootLoader具有以下必须的功能(以U-Boot为例);
Step-1:
1),设置CPU;
2),关闭Watchdog;
3),设置Clock;
4),屏蔽所有的Interrupt;
5),初始化SDRAM;
6),初始化nandflash(如果u-boot代码在nandflash上);
7);重定位BootLoader的代码到SDRAM;
8);设置栈(C语言函数调用需要先设置栈,栈要在SDRAM初始化之后设置);
9),清BSS段;
10),进入BootLoader的Step-2阶段启动内核;

Step-2:
11),设置BootLoader要传递给内核的参数;
12),从Nor 或 Nand flash 上复制内核代码到SDRAM的0x30007FC0的地方(这个地址不是固定的,可以任意指定,只要不破坏u-boot使用的内存空间,u-boot会根据uImage的Header中的Load Addr判断内核是否装载到Load Addr的地址处,Load Addr在u-boot中默认为0x30007FC0,如果不在,u-boot会移动内核代码到改地址处);
13),跳转到uImage的Header中Entry Point指定的入口地址处开始执行内核代码(内核执行后,u-boot不在执行);

在第二阶段中还可以包括一些辅助开发的功能(不分先后次序):
14),Nor 或者 Nand flash烧写功能;
15),USB初始化;
16),UART串口初始化;
17),网络功能初始化;

2,自制BootLoader思路:
实现上述必须功能;
以S3C2440平台为例;
硬件参数查S3C2440 Datasheet;
内存布局以及内核参数传递参考u-boot.1.1.6版本代码;
总体功能实现(start.S , init.c , boot.c , u-boot.lds , Makefile 附件会提供完整源码):

1,第一阶段的实现:
设置CPU为管理模式;

    mrs r0,cpsr
    bic r0,r0,#0x1f
    orr r0,r0,#0xd3
    msr cpsr,r0

开启CPU的I-Cache,经测试开启之前和开启之后复制内核代码时间缩短8s;

    mrc p15, 0, r1, c1, c0, 0
    orr r1,r1,#0x1000
    mcr p15, 0, r1, c1, c0, 0

关闭Watchdog;

    ldr r0,=0x53000000
    mov r1,#0
    str r1,[r0]

屏蔽所有中断;

    ldr r0,=0x4A000008
    ldr r1,=0xFFFFFFFF
    str r1,[r0]
   ldr r1,=0x3FF
   ldr r0,=0x4A00001C
   str r1,[r0]

初始化时钟;

    1,设置 FCLK:HCLK:PCLK=1:2:4
    ldr r0,=0x4C000014
    mov r1,#0x3
    str r1,[r0]

2,设置总线模式为异步模式(手册中要求);

   mrc p15, 0, r1, c1, c0, 0
    orr r1, r1, #0xc0000000
    mcr p15, 0, r1, c1, c0, 0

3,设置MPLL寄存器,将12M晶振频率变为200M;

    ldr r0,=0x4c000004
    ldr r2,=0x0005c012
    str r2,[r0]

初始化内存;

    ldr r0,=SDRDATA
    ldr r1,=_text_start
    sub r0,r0,r1          @data address for initing sdram  start;
    add r2,r0,#13*4       @data address end;
    ldr r1,=0x48000000    @sdram control registers address start;

0: 循环设置内存控制器13个寄存器的值;

    ldr r3,[r0],#4
    str r3,[r1],#4
    cmp r0,r2
    bne 0b

设置栈,后面的初始化由C语言来完成所以需要设置栈;

    ldr sp,=0x34000000

初始化Nand Flash控制器;

    bl nand_init

重定位u-boot代码;

    bl copy_to_sdram

进入u-boot第二阶段准备启动内核;

    ldr lr,=halt
    ldr pc,=main
@   bl main             @jump to step 2 for starting linux kernel; 

halt:
    bl halt

设置内存控制器寄存器时使用的值;

.align 4
SDRDATA:
    .long 0x32333330
    .long 0x00002a60
    .long 0x00002a60
    .long 0x00002a60
    .long 0x00002a60
    .long 0x00002a60
    .long 0x00002a60
    .long 0x00018001
    .long 0x00018001
    .long 0x008404f5
    .long 0x000000b1
    .long 0x00000020
    .long 0x00000020

第二阶段主要介绍传递给内核的参数设置部分(参考u-boot源码中的struct tag结构体):
参数的内存分布如图:
这里写图片描述

最重要的几个参数设置如下

/* 起始tag设置  */
static unsigned long  * setup_start_tag (unsigned long *params)
{
    *params     = 0x5;                   //start tag的大小,以4字节对齐;
    *(params+1) = ATAG_CORE;  //start tag的name标示;
    *(params+2) = 0;
    *(params+3) = 0;
    *(params+4) = 0;
    return (params+5);
}
/* 内存tag设置 */
static unsigned long * setup_memory_tags (unsigned long *params)
{
    *params      = 4;
    *(params+1)  = ATAG_MEM;
    *(params+2)  = 0x4000000;   //内存空间大小;
    *(params+3)  = 0x30000000; //内存起始地址;
    return (params+4);
}
/* 命令行tag设置 */
static  unsigned long * setup_commandline_tag (unsigned long *params,char *commandline)
{
    int len,slen=strlen(commandline);   //命令行参数长度
    char *tmp;
    len     = (8+slen+4)>>2;                 //命令行参数tag的总大小,4字节对齐;
    *params = len;
    *(params+1)     = ATAG_CMDLINE;
    tmp = (char *)(params+2);
    strcpy(tmp,commandline);           //将命令行参数内容放入tag内存空间;
    *(tmp+slen)='\0';                    
   return params+len;
}
/* 结束tag设置 */
static void setup_end_tag (unsigned long *params)
{
    *params   = 0x0;
    *(params+1) = ATAG_NONE;
}

完整源代码下载地址
start.S 第一阶段启动实现;
init.c 主要硬件初始化及相关操作实现(串口 , Nand Flash);
boot.c 从Nand Flash的Kernel分区(0x60040–不包括uImage的header部分所以0x60000需要加上64字节)中复制Kernel代码到SDRAM的0x30008000的地址处,设置传递给内核的参数,参数存放在内存的0x30000100地址处,然后启动内核;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值