第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 条评论
登录 后参与评论

相关文章

来自专栏向治洪

dex分包方案

当一个app的功能越来越复杂,代码量越来越多,也许有一天便会突然遇到下列现象: 1. 生成的apk在2.3以前的机器无法安装,提示INSTALL_FAILE...

1915
来自专栏技术博文

浅谈开启magic_quotes_gpc后的sql注入攻与防

通过启用php.ini配置文件中的相关选项,就可以将大部分想利用SQL注入漏洞的骇客拒绝于门外。        开启magic_quotes_gpc=on之后,...

3475
来自专栏雨尘分享

2018 - iOS 面试题汇总一般面试题BAT面试题

1.1K3
来自专栏我的博客

TP入门第七天

Trace信息无法显示,因为信息需要显示在body体内 1、创建数据 我们在php的action里面当然也可以使用$_POST以及$_GET获取变量,而TP提供...

2754
来自专栏塔奇克马敲代码

C++中输出流的刷新问题和 endl和 \n的区别

1576
来自专栏Python小屋

使用with关键字让你的Python代码更加Pythonic

首先解释一下上一篇文章Python科学计算扩展库numpy中的广播运算中最后的小题目,该题目答案是一个元组(True, 5),原因在于Python中的等号=虽然...

3428
来自专栏Flutter知识集

Flutter与Native通信 - PlatformChannel源码分析

Flutter是一个跨平台的方案,在UI、触控及基本的网络请求上已经基本做到平台无关,但是在某些平台特性的功能上,还是必须要对不同的平台做处理。这就涉及到与Na...

1560
来自专栏数据之美

关于 MySQL UTF8 编码下生僻字符插入失败/假死问题的分析

1、问题:mysql 遇到某些中文插入异常 最近有同学反馈了这样一个问题: ? 上述语句在脚本中 load 入库的时候会 hang 住,web 前端、命令行操作...

3029
来自专栏noteless

javaweb请求编码 url编码 响应编码 乱码问题 post编码 get请求编码 中文乱码问题 GET POST参数乱码问题 url乱码问题 get post请求乱码 字符编码

然后使用      65------>$ 另外一种解码方式解读,显然A就变成了$,这不就是乱码了么

803
来自专栏Java帮帮-微信公众号-技术文章全总结

springmvc学习第二天

Springmvc第二天 回顾第一天课程内容: 1.JAVAEE体系结构 2.什么是springmvc? * mvc设计模式 * springmvc框架原理 3...

3158

扫码关注云+社区