第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值)
人间有真情,人间有真爱。