第2阶段——编写uboot之硬件初始化和制作链接脚本lds(1)

目标:

第一阶段:

1.关看门狗
2.设置时钟
3.初始化SDRAM (初始化寄存器以及清除bss段)
4.重定位 (将nand/nor中代码COPY到链接地址上,需要初始化nandflash,读flash)

5.执行main 

进入第二阶段:

6.写main函数,在main()中设置要传给内核的参数,然后跳转内核基地址处

7.制作uboot.lds链接脚本


 

编写步骤:

1.创建个名为"my_bootloader"根目录,方便编写uboot


2.新建my_bootloader/si目录,创建source insight工程


2.1 新建my_bootloader/start.S (后缀名必须是大写的S,或者后面编译会报错)

编写start.S (第一阶段初始硬件文件):
start.s任务:
1.关看门狗
2.设置时钟
3.初始化SDRAM
4.重定位(把bootloader本身的代码从flash复制到它的链接地址(c函数编写),然后清空bss段(c函数编写))
5.执行main

/*  看门狗寄存器            */
#define WTCON      0x53000000

/*  2.时钟寄存器            */
#define CLKDIVN    0x4C000014        //设置FCLK,HCLK,PCLK比例
#define MPLLCON   0x4C000004          //设置FCLK频率
#define S3C2440_MPLL_200MHZ     ((0x5c<<12)|(0x01<<4)|(0x02))  //设置FCLK=200MHZ
#define S3C2440_MPLL_400MHZ     ((0x5c<<12)|(0x01<<4)|(0x01))  //设置FCLK=400MHZ

/*  3.bank寄存器       */
#define BWSCON      0x48000000

.text                                /*设置代码段*/
.global   _start                  /*定义全局变量,要被连接脚本用到*/
_start:                           /*_start跳转到这里实现硬件初始化*/

    /*  1.关看门狗            */
       ldr r0,=WTCON
       mov r1,#0
       str r1,[r0]
       
    /*	2.设置时钟(必须设为异步总线模式)  */
       
       ldr r0,=CLKDIVN
       mov r1,#3                                  /*FCLK:HCLK:PCLK=1:2:4*/ 
       str r1,[r0]        
       mrc	p15, 0, r1, c1, c0                 /* 读出控制寄存器 */	
       orr	 r1, r1, #0xc0000000   		 /* 设置为“asynchronous bus mode” */
       mcr	  p15, 0, r1, c1, c0, 0 	        /* 写入控制寄存器 */       
       ldr r0,=MPLLCON
       ldr r1,=S3C2440_MPLL_200MHZ      //使用复杂的数不能用mov,需要用ldr
       str r1,[r0]
       
    /*  3.初始化SDRAM       */
       ldr r0,=BWSCON                   //r0=SDRAM寄存器基地址
       adr r1,SDRAM_CONFIG           //使用adr相对跳转,因为SDRAM未初始化
       add r2,r0,#(13*4)               //r2等于 SDRAM尾地址+4

0:
       ldr r3,[r1],#4                      //r3=r1里的	内容, &r1+=4;
       str r3,[r0],#4                      //*r0=r3,&r0+=4
       cmp r0,r2
       bne 0b                               //(ne:no equal   b:bank)   若r0!=r2,跳转到后面的0处

 /*  4.重定位 				*/
        ldr sp,=0x34000000                     //64Msdram,所以设置栈SP=0x34000000,避免堆栈溢出
        mov r0,#0                           //r0->src
	ldr r1,=_start                     //r1->dest
	ldr r2,=__bss_start            //r2->len->__bss_start-_start
	sub r2,r2,r1
	bl copy_code_to_sdram          //复制代码到SDRAM连接地址dest上
	bl clear_bss                         //清除bss段 
	
   /*  5.执行main				 */
        ldr lr,=halt                         //执行一个子程序调用返回时,需要先将返回地址赋给lr链接寄存器
        ldr pc,=main                              //初始化SDRAM后,可以使用pc 绝对跳转到SDRAM地址上
        mov pc,lr                             //若main函数跳出后,使PC等于lr链接寄存器,避免程序跑飞 

halt:	                                //死循环,避免跑飞
	 b halt               

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

3 新建my_bootloader/init.c,用于重定位,bss段清除,初始化NandFlash等

在重定位函数中的nand驱动在(入口:http://www.cnblogs.com/lifexy/p/7097695.html)里详细介绍了,这里就不描述了.

3.1编写copy_code_tosdram() 重定位函数

void copy_code_to_sdram(unsigned char *src,unsigned char *dest,unsigned int len)			//复制代码到SDRAM连接地址dest上
{
      unsigned int i;
        /*判断nor启动还是nand启动*/
	if(is_boot_from_norflash())                 //nor启动,直接复制
	{
              for(i=0;i<len;i++)
              {
               dest[i]=src[i];
              }
	}
	else
	{
       nand_init();
	    
	nand_read((unsigned int)src,dest,len);
       
	}
} 

3.2编写isBootFramNorFlash()函数,来判断nand启动还是nor启动

/*判断nor启动还是nand启动*/
unsigned char is_boot_from_norflash(void)
{
         volatile unsigned int *p=(volatile unsigned int *)0;
	 unsigned int i;
	 i=*p;
	 *p=0x12345678;
	 if(*p==0x12345678)    //nand
	 {
	 *p=i;
	 return 0;
	 }
	 else                    //nor
	 {
        *p=i;
	 return 1;
	 }

3.3编写clear_bss()函数

void clear_bss(void)  //清除BSS段
{
  extern int __bss_start,__bss_end;
  int  *p=&__bss_start;
  for( ;p<&__bss_end;p++)
  {
  *p=0;
  }
}

4编写连接脚本uboot.lds (参考硬件实验里的uart.lds和u-boot-1.1.6里的u-boot.lds)

SECTIONS {
    . = 0x33f80000; //0地址里存放0X33F80000
    . = ALIGN(4);

    .text : { *(.text) }
    . = ALIGN(4);

    .rodata : {	*(.rodata)	}
    . = ALIGN(4);

    .data : {	*(.data)	}
    . = ALIGN(4);

    __bss_start = .; 
    .bss : { *(.bss) *(COMMON) }
    __bss_end = .;
}

其中0x33f80000就是链接地址首地址,共512K空间存放bootloader
定义__bss_start和__bss_end符号,是用来程序开始之前将这些未定义的变量清0,节省内存
且bss_start-0x33f80000就等于代码的大小(copy_code_tosdram函数中len值)

 

posted @ 2017-08-10 09:31  诺谦  阅读(1791)  评论(0编辑  收藏  举报