第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值)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Linux驱动

makefile使用.lds链接脚本以及 $@ ,$^, $,< 解析

先来分析一个简单的.lds链接脚本 例1,假如现在有head.c init.c nand.c main.c这4个文件: 1.1 首先创建链接脚本nand.lds...

20110
来自专栏python读书笔记

python 数据分析基础 day6-xlrd,xlwt读写单个excel

今天的内容为使用xlrd和xlwt这两个模块来读取单个excel文件, 思路和读取csv文件大致相同,分别设置输入和输出的excel文件对象,然后遍历输入对象...

3257
来自专栏C/C++基础

Makefile教程

Makefile定义了软件开发过程中,项目工程编译链、链接的方法和规则。 由IDE自动生成或者开发者手动书写。 Unix(MAC OS、Solaris)和Lin...

1092
来自专栏蓝天

C++资源编译工具,用于将任何格式的文件编译成C++代码

resource_maker.zip          linux自带了一个名叫xxd的工具,带参数-i运行时,效果类似,如:xxd -i /bin/ls。 ...

611
来自专栏坚毅的PHP

my python FAQ

python编码规范 http://google-styleguide.googlecode.com/svn/trunk/pyguide.html 判断对象是否...

3247
来自专栏北京马哥教育

大神带你 20 分钟学会 Ansible !

2532
来自专栏CaiRui

Shell-2-命令之乐

1.cat (1)基本用法 [root@cai tmp]# cat 1.txt 2.txt this is a test1 this is a test 2...

1985
来自专栏北京马哥教育

初学python的30个操作难点汇总(新手必看篇)

初学Python的人总会遇到这样或者那样的问题,在我学习Python的这段时间我总结了自己的29个问题,具体如下: 1 在cmd下 盘与盘之间的切换 直接 D...

3207
来自专栏武军超python专栏

2018年8月29日学习mysql数据库的笔记

今天遇到的新单词: manual n手工的 correspond v符合一致 reject v拒绝 exist  v存在 solid adj固体的 ...

1185
来自专栏软件测试经验与教训

Python学习笔记(15)- os\\os.path 操作文件

3136

扫码关注云+社区