03Uboot移植分析.docx

上传人:b****5 文档编号:6887155 上传时间:2023-01-12 格式:DOCX 页数:35 大小:778.89KB
下载 相关 举报
03Uboot移植分析.docx_第1页
第1页 / 共35页
03Uboot移植分析.docx_第2页
第2页 / 共35页
03Uboot移植分析.docx_第3页
第3页 / 共35页
03Uboot移植分析.docx_第4页
第4页 / 共35页
03Uboot移植分析.docx_第5页
第5页 / 共35页
点击查看更多>>
下载资源
资源描述

03Uboot移植分析.docx

《03Uboot移植分析.docx》由会员分享,可在线阅读,更多相关《03Uboot移植分析.docx(35页珍藏版)》请在冰豆网上搜索。

03Uboot移植分析.docx

03Uboot移植分析

U-boot分析与移植

(1)----bootloader分析

一、BootLoader概念

就是在操作系统内核运行之前运行的一段小程序。

通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境,他就是所谓的引导加载程序(BootLoader)。

嵌入式软件在Flash存储器中的分布图

 

二、为什么需要BootLoader?

BootLoader的终极任务是引导操作系统,所谓引导操作系统,就是启动内核,在启动内核之前所需要的环境(如初始化sdram,设置cpu模式等,下面会介绍)都是由BootLoader来完成的。

试想一下,如果你要启动内核,让内核在内存上跑,但连sdram都没有初始化,这显然不行。

在s3c2440中,系统在上电或复位时通常都从地址0x00000000处开始执行,而在这个地址处安排的通常就是系统的BootLoader程序。

在x86的PC机上,BootLoader=BIOS+GRUB/LILO。

三、BootLoader的选择

有些人误认为BootLoader=U-Boot,其实BootLoader只是所有引导加载程序中的一个总称。

四、启动过程

  S3C2440支持两种方式的启动:

NorFlash启动和NandFlash启动。

NorFlash和NandFlash都是非易失性存储器,NorFlash的特点是芯片内执行和不能直接写操作,程序可以直接在其中运行,而不必将程序读取到RAM中运行。

NorFlash虽然具有这个优点,但是它的性价比远低于NandFlash,因而很多系统采用NandFlash启动。

NandFlash的特点是采用非线性存储模式,程序无法在其中运行,它只能作为程序或数据的存储载体,存储在其中的程序只能先拷贝到RAM中才能运行。

 从NorFlash启动时,与nGCS0相连的NorFlash就被映射到nGCS0片选的空间,其地址被映射为0x00000000;从NandFlash启动时,S3C2440芯片内部自带的一块容量为4K的被称为“Steppingstone”(“起步阶石”)的BootSRAM被映射到nGCS0片选的空间,其地址被映射为0x00000000。

当系统上电或复位时,程序会从0地址处开始执行,因此我们编写的启动代码要确保存储在0地址处。

   当启动方式为NorFlash启动时,没有额外需要考虑的问题,因为这种情况下程序在系统启动前就存储在NorFlash中,我们只要保证将启动代码保存在NorFlash开始的位置即可,系统上电或复位时,0地址处的启动代码就会被执行。

 在启动方式为NandFlash启动的情况下,系统启动前所有的程序存储在NandFlash中,系统的启动过程稍微有点复杂:

系统上电或复位时,0地址处为S3C2440内部自带的BootSRAM,启动前里面没有任何存储内容,启动后S3C2440先通过硬件机制将NandFlash前4K的内容拷贝至其中,然后再运行里面的程序(从0地址处)。

这种情况下我们需要保证将启动代码保存在NandFlash开始的位置,并且启动代码的大小要小于4K。

这就是我们的裸机程序为什么在nandflash能跑的原因。

 我们用的bootloader一般大于4k,所以,我们把用汇编编写的在sram里面执行的过程称为stage1,实现最关键的初始化后,把bootloader代码从nandflash拷贝到sdram里。

此时在sdram里实现stage2,做更具体的初始化,最后启动内核,这个阶段一般用c语言来编写。

 

BootLoader的stage1通常包括以下步骤(以执行的先后顺序):

∙硬件设备初始化(关看门狗,关中断,设置cpu时钟,初始化sdram,关闭CPU内部指令/数据cache)。

∙为加载BootLoader的stage2准备RAM空间。

∙拷贝BootLoader的stage2到RAM空间中。

∙设置好堆栈。

∙跳转到stage2的C入口点。

BootLoader的stage2通常包括以下步骤(以执行的先后顺序):

∙初始化本阶段要使用到的硬件设备。

∙检测系统内存映射(memorymap)。

∙将kernel映像和根文件系统映像从flash上读到RAM空间中。

∙为内核设置启动参数。

∙调用内核。

U-boot分析与移植

(2)----U-bootstage1分析

我们要生成u-boot.bin文件,它首先依赖于很多.o文件和.lds链接脚本文件

我们只要找到对应的.lds链接脚本文件就可以分析u-boot的启动流程。

1、打开u-boot-1.1.6\u-boot-1.1.6\board\smdk2410\

打开链接脚本boot.lds看看:

OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm","elf32-littlearm")

/*OUTPUT_FORMAT("elf32-arm","elf32-arm","elf32-arm")*/

OUTPUT_ARCH(arm)

ENTRY(_start)

SECTIONS

{

 .=0x00000000;

 .=ALIGN(4);

 .text     :

 {

  cpu/arm920t/start.o (.text)

  *(.text)

 }

1)可以看见入口函数是_start

2)这个start代码放在cpu/arm920t/,就是start.S生成的start.o 

 

 2、打开u-boot-1.1.6\cpu\arm920t\start.S

.globl_start

_start:

 b      reset

 ldr pc,_undefined_instruction

......

 一开始跳到reset

reset:

设置CPUSVC32模式:

 /*

 *setthecputoSVC32mode

 */

mrs r0,cpsr

 bic r0,r0,#0x1f  /*clear0atlow5bit*/

 orr r0,r0,#0xd3 /*set11010011*/

                           /*closeirq,fiq,atarmstate,atsupervisormode*/

 msr cpsr,r0     /*writecpsr*/

IF为1,关闭FIQ,IRQ

T为0,ARM模式

M[4:

0]=10011,管理模式

 

关闭看门狗:

 

向pWTCON全写0

#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)

 ldr    r0,=pWTCON

 mov    r1,#0x0 

 str    r1,[r0]

 

关闭所有中断:

但默认已经是关闭的

INTMSK写1,屏蔽对应的中断(默认1)

INTSUBMSK写1,屏蔽对应的二级中断(默认1)

 /*

 *maskallIRQsbysettingallbitsintheINTMR-default

 */

 mov r1,#0xffffffff

 ldr r0,=INTMSK

 str r1,[r0]

#ifdefined(CONFIG_S3C2410)

 ldr r1,=0x3ff

 ldr r0,=INTSUBMSK

 str r1,[r0]

#endif

 设置时钟分频比:

/*FCLK:

HCLK:

PCLK=1:

2:

4*/

 /*defaultFCLKis120MHz!

*/

 ldr r0,=CLKDIVN

 mov r1,#3

 str r1,[r0]

接着跳入cpu系统初始化:

#ifndefCONFIG_SKIP_LOWLEVEL_INIT

 bl cpu_init_crit

#endif

在里面再跳入sdram初始化:

bl lowlevel_init

拷贝代码到SDRAM:

十分遗憾,这是给NOR FLASH用的

首先判断_start当前第一条代码位置,如果是在内存中,就不用代码重定位了

#ifndefCONFIG_SKIP_RELOCATE_UBOOT

relocate:

    /*relocateU-BoottoRAM    */

 adr r0,_start  /*r0<-currentpositionofcode  */

 ldr r1,_TEXT_BASE  /*testifwerunfromflashorRAM*/

 cmp    r0,r1                 /*don'trelocduringdebug        */

 beq    stack_setup

 ldr r2,_armboot_start

 ldr r3,_bss_start

 sub r2,r3,r2  /*r2<-sizeofarmboot           */

 add r2,r0,r2  /*r2<-sourceendaddress        */

copy_loop:

 ldmia r0!

{r3-r10}  /*copyfromsourceaddress[r0]   */

 stmia r1!

{r3-r10}  /*copyto  targetaddress[r1]   */

 cmp r0,r2   /*untilsourceendaddreee[r2]   */

 ble copy_loop

#endif /*CONFIG_SKIP_RELOCATE_UBOOT*/

设置堆栈:

stack_setup:

 ldr r0,_TEXT_BASE  /*upper128KiB:

relocateduboot  */

 sub r0,r0,#CFG_MALLOC_LEN /*mallocarea                     */

 sub r0,r0,#CFG_GBL_DATA_SIZE/*bdinfo                       */

还有设置中断stack

......

清bss段:

Bss段用来存放未初始化的全局变量和静态变量,在有操作系统的c编译器里默认为0.

但移植u-boot时,所有堆栈,清bss段都是人手设置,我们定义了一个bss段,把这个区域写0,

以后我们c函数运行时,就默认0了。

clear_bss:

 ldr r0,_bss_start  /*findstartofbsssegment       */

 ldr r1,_bss_end  /*stophere                       */

 mov r2,#0x00000000  /*clear                           */

clbss_l:

str r2,[r0]  /*clearloop...                   */

 add r0,r0,#4

 cmp r0,r1

 ble clbss_l

 

跳到c函数入口:

 ldr pc,_start_armboot

_start_armboot:

 .wordstart_armboot

第一阶段基本完成

ldr绝对跳转到_start_armboot函数入口

U-boot分析与移植(3)----U-bootstage2分析.

一来到voidstart_armboot(void)函数,马上出现两个很重要的数据结构gd_t和bd_t

1、gd_t :

 global data数据结构定义,位于文件 include/asm-arm/global_data.h。

其成员主要是一些全局的系统初始化参数。

[cpp]viewplaincopyprint?

1.typedef struct  global_data {  

2.    bd_t        *bd;      // struct board_info

宋体;">指针,保存板子信息  

3.    unsigned long   flags;     // 

宋体;">指示标志,如设备已经初始化标志等  

4.    unsigned long   baudrate;  

5.    unsigned long   have_console;   /* serial_init() was called */  

6.    unsigned long   reloc_off;  /* Relocation Offset */  

7.    unsigned long   env_addr;   /* Address  of Environment struct 环境参数地址*/  

8.    unsigned long   env_valid;  /* Checksum of Environment valid?

 */  

9.    unsigned long   fb_base;    /* base address of frame buffer */  

10.#ifdef CONFIG_VFD  

11.    unsigned char   vfd_type;   /* display type */  

12.#endif  

13.#if 0  

14.    unsigned long   cpu_clk;    /* CPU clock in Hz!

     */  

15.    unsigned long   bus_clk;  

16.    unsigned long   ram_size;   /* RAM size */  

17.    unsigned long   reset_status;   /* reset status register at boot */  

18.#endif  

19.    void        **jt;       /* jump table */  

20.} gd_t;  

2.、bd_t :

board info数据结构定义,位于文件 include/asm-arm/u-boot.h。

保存板子参数。

[cpp]viewplaincopyprint?

1.typedef struct bd_info {  

2.    int         bi_baudrate;    /* serial console baudrate */  

3.    unsigned long   bi_ip_addr; /* IP Address */  

4.    unsigned char   bi_enetaddr[6]; /* Ethernet adress */  

5.    struct environment_s           *bi_env;  

6.    ulong           bi_arch_number; /* unique id for this board  

宋体;">板子

Times New Roman;">ID

宋体;">号*/  

7.    ulong           bi_boot_params; /* where this board expects params */  

8.    struct              /* RAM configuration */  

9.    {  

10.    ulong start;  

11.    ulong size;  

12.    }           bi_dram[CONFIG_NR_DRAM_BANKS];  

13.#ifdef CONFIG_HAS_ETH1  

14.    /* second onboard ethernet port */  

15.    unsigned char   bi_enet1addr[6];  

16.#endif  

17.} bd_t;  

分配一个存储全局数据的区域,地址给指针gd

[cpp]viewplaincopyprint?

1.gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));  

清0并分配空间

[cpp]viewplaincopyprint?

1.memset ((void*)gd, 0, sizeof (gd_t));    

在gd前面的位置给 gd->bd赋值地址

[cpp]viewplaincopyprint?

1.gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));  

清0并分配空间

[cpp]viewplaincopyprint?

1.memset (gd->bd, 0, sizeof (bd_t));  

执行一系列初始化函数

[cpp]viewplaincopyprint?

1.for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {  

2.  if ((*init_fnc_ptr)() !

= 0) {  

3.   hang ();  

4.  }  

5. }  

假如函数指针指向的函数返回值不为0,那么在hang()里就会死循环,初始化失败

[cpp]viewplaincopyprint?

1.void hang (void)  

2.{  

3. puts ("### ERROR ### Please RESET the board ###\n");  

4. for (;;);  

5.}  

函数列表如下:

每个初始化函数正常情况下返回值是0

[cpp]viewplaincopyprint?

1.init_fnc_t *init_sequence[] = {  

2. cpu_init,  /* 初始化irq/fiq模式的栈*/  

3. board_init, /* 设置系统时钟*/  

4. interrupt_init, /*初始化定时器*/  

5. env_init,  /* 检查flash上的环境参数是否有效*/  

6. init_baudrate, /* 初始化波特率*/  

7. serial_init, /* 初始化串口*/  

8. console_init_f, /*初始化串口控制台*/  

9. display_banner, /* say that we are here */  

接着进行一些NORFLASH,LCD,串口,控制台,sd卡,网卡等初始化,不一一列举了。

终于来到重要的时刻了--#

进入一个死循环

[cpp]viewplaincopyprint?

1.for (;;)  

2.{  

3. main_loop ();  

4.}  

继续跟踪

发现在bootdelay时间内按下键进入命令行,用run_command来解析命令

[cpp]viewplaincopyprint?

1.#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)  

2.    s = getenv ("bootdelay");  

3.    bootdelay = s ?

 (int)simple_strtol(s, NULL, 10) :

 CONFIG_BOOTDELAY;  

4.  

5.    debug ("### main_loop entered:

 bootdelay=%d\n\n", bootdelay);  

如果CONFIG_BOOTDELAY已经定义,用s得到环境变量bootdelay,然后倒数启动内核

[cpp]viewplaincopyprint?

1.#ifdef CONFIG_BOOTCOUNT_LIMIT  

2.    if (bootlimit && (bootcount > bootlimit)) {  

3.        printf ("Warning:

 Bootlimit (%u) exceeded. Using altbootcmd.\n",  

4.                (unsigned)bootlimit);  

5.        s = getenv ("altbootcmd");  

6.    }  

7.    else  

8.#endif /* CONFIG_BOOTCOUNT_LIMIT */  

9.        s = getenv ("bootcmd");  

CONFIG_BOOTCOUNT_LIMIT是设置u-boot启动次数的限制

最后s=getenv("bootcmd");获得启动参数

[cpp]viewplaincopyprint?

1.run_command (s, 0);  

启动命令解析

在run_command函数里最终执行命令

[cpp]viewplaincopyprint?

1./* OK - call function to do the command */  

2.if ((cmdtp->cmd) (cmdtp, flag, argc, argv) !

= 0) {  

3. rc = -1;  

4.}  

这是一个命令结构体,原型如下:

[cpp]viewplaincopyprint?

1.struct cmd_tbl_s {  

2.    char        *name;      /* Comma

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 法律文书 > 调解书

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1