写BootLoader

第一节:最简单的BootLoader编写步骤

一、 Boot Loader的概念和功能

1、嵌入式Linux软件结构与分布:在一般情况下嵌入式Linux系统中的软件主要分为以下及部分:

(1)引导加载程序:其中包括内部ROM中的固化启动代码和Boot Loader两部分。
内部固化ROM:是厂家在芯片生产时候固化的,作用基本上是引导Boot Loader。
Boot Loader:引导内核启动

(2)Linux kernel 和drivers。

(3)文件系统。包括根文件系统和建立于Flash内存设备之上的文件系统(EXT4、UBI、CRAMFS等等)。它是提供管理系统的各种配置文件以及系统执行用户应用程序的良好运行环境的载体。

(4)应用程序。用户自定义的应用程序,存放于文件系统之中。
在Flash 存储器中,他们的 一般分布如下:
图:1-1

但是以上只是大部分情况下的分布,也有一些可能根文件系统是initramfs,被一起压缩到了内核映像里,或者没有Bootloader参数区,等等。

第一部分问答:

1、BootLoader的目标是干什么?
答:启动内核

2、那么内核在什么地方?
答:内核在flash上

那么写BootLoader第一步:从flash上把内核读到内存

由第一步可见,BootLoader需要对flash进行操作
3、从flash上把内核读到内存需要具备哪些条件?
答:a.能操作flash;
b.既然需要读到内存中,那么就需要初始化内存(内核是要放到SDRAM中 ,因为nand flash比较小,不能直接烧写内核,SDRAM这种内存需要先初始化);
c.开发板上电时有自己的运行频率(例如:三星2440一上电运行的频率是12MHZ)如果我们想让它运行的快一点,就需要初始化时钟;
d.还有一些其它的例如关闭看门狗等。之所以关闭看门狗是因为开发板一上电看门狗就打开,如果不关掉一到看门狗设置的时间就会重新复位开发板
e.如果BootLoader比较大怎么办?把BootLoader重定位到SDRAM
f.如果内核是放在nand flash的话,需要初始化nand flash
g.必须禁止中断(IRQs和FIQs)?为中断提供服务通常是OS设备驱动程序的责任,因此在 Boot Loader 的执行全过程中可以不必响应任何中断。中断屏蔽可以通过写CPU的中断屏蔽寄存器或状态寄存器(比如 ARM 的 CPSR 寄存器)来完成。

第二部分问答:
4、在第一部分中已经将内核读到了内存,那么怎么去启动内核?直接跳到内核的地址里面去就可以了吗?

5、在启动内核之前我想给它传一些参数,比如说,告诉内核我的内存有多大,你应该去哪里找这个根文件系统,等等等等。。。。。传参数?怎么传?
答:1、首先设置参数(在某个约定的地址存入一些参数、设置好一些参数)
2、跳转执行内核

代码部分:
首先写一个start.S

图:1-1

#define S3C2440_MPLL_200MHZ     ((0x5c<<12)|(0x01<<4)|(0x02))   /*设置200MHZ*/
#define MEM_CTL_BASE   0x48000000
.text   //.text:表示代码段
.global _start  //.global _start:表示一个全局的标识   
_start:

/* 1.关看门狗 */ i 
    ldr r0, =0x53000000 /*0x53000000看门狗的地址,如果一个数比较复杂,不能用立即数表示,我们就用伪汇编*/
    mov r1, #0
    str r1, [r0]            /*把0存到r0这个地址去*/

/* 2.设置时钟 */
    ldr r0, =0x4c00014      /*0x4c00014时钟地址*/
    mov r1, #0x03           /*0x03分频系数,FCLK:HCLK:PCLK=1:2:4,HDIVN=1,PDIVN=1*/
    str r1, [r0]

    /*数据手册要求,当FCLK不等于HCLK时,cpu的总线模式应该从“fast bus mode”变为“asynchronous bus mode”*/
    mrc p15, 0, r1, c1, c0, 0       /*读出控制寄存器*/
    orr r1, r1, #0xc000000          /*设置为“asynchronous bus mode”*/
    mcr p15, 0, r1, c1, c0, 0       /*写入控制寄存器*/

    /*设置MPLLCON=S3C2440_MPLL_200MHZ*/
    ldr r0, =0x4c00004
    ldr r1, =S3C2440_MPLL_200MHZ
    str r1, [r0]

/* 3.初始化SDRAM */
    /*SDRAM控制寄存器的起始地址*/
   ldr r0, =MEM_CTL_BASE   
    /*(sdram_config)的当前地址*/
    adr r1, sdram_config 
    /*r3=r0+52,之所以为13,是因为有13个控制寄存器*/
    /*每个长度为4,所以为13*4*/
    add r3, r0, #(13*4)    


    1:
        /*将r1的值加载到r2,同时r1加4。取出寄存器将要被设置的值*/
        ldr r2, [r1], #4    
        /*将r2的值存储到r0,同时r0加4。将要设置的值赋给对应的寄存器*/
        str r2, [r0], #4    
        /*如果r0小于r3,那么就跳回到标签1处*/
        cmp r0, r3          
        /*b是back的意思,结束之后,SDRAM的所有寄存器就都设置好了*/
        bne 1b              

 /*注:为了完成比较复杂的工作,不能仅仅使用汇编代码。我们需要使用C语言来编写一些功能,在使用C语言代码之前一定要设置栈。
*/
    /*2440的SDRAM大小为64M,并且起始地址为0x30000000。
    这里指向最高的内存,因为栈是由高向低地址走的(下文)。
    这里0x04000000为64M(每个地址对应一个字节)
    所以设为0x30000000+0x04000000*/
    ldr sp, =0x34000000 


    bl nand_init    
    /*跳转到C语言程序中的NAND FLASH初始化函数*/



/* 4.重定位 :把BootLoader本身的代码从flash复制到它的链接地址去:他的链接地址是什么?*/
    bl copy_code_to_sdram  //相对跳转到copy_code_to_sdram


/* 5.执行main */
     /*怎么执行的main函数?相对跳转?用bl main ?*/
/*要把这些数据读出来,存到SDRAM:reg:0x48000000*/
 sdram_config:
    .long 0x22011110     //BWSCON
    .long 0x00000700     //BANKCON0
    .long 0x00000700     //BANKCON1
    .long 0x00000700     //BANKCON2
    .long 0x00000700     //BANKCON3  
    .long 0x00000700     //BANKCON4
    .long 0x00000700     //BANKCON5
    .long 0x00018005     //BANKCON6
    .long 0x00018005     //BANKCON7
    .long 0x008C04F4     //REFRESH
    .long 0x000000B1     //BANKSIZE
    .long 0x00000030     //MRSRB6
    .long 0x00000030     //MRSRB7
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章