U-boot-2014.04移植到MINI2440(11) 第二启动阶段分析

发布者:brian808090最新更新时间:2022-06-21 来源: eefocus关键字:U-boot  移植到  MINI2440 手机看文章 扫描二维码
随时随地手机看文章

回顾一下u-boot启动其一阶段做了哪些事:


第一:设置CPU为SVC模式


第二:关闭看门狗


第三:关中断和子中断


第四:设置时钟


第五:MMU关闭,清除cache和TLB,使能地址对齐检查等


第六:初始化SDRAM


       在我前面的分析里,第一阶段的最后,通过bl _main,跳到了arch/arm/lib/crt0.S里面去了,从这里开始时第二阶段的入口,下面从这里开始分析。


       文件:crt0.S


       先看看该文件对_main的描述,在第18行,有一个_main execution sequence is:下面有五步,其实就是对_main的执行流程的一个介绍,我翻译一下:


       1.设置初始环境准备调用board_init_f()。提供一个堆栈或者地址来存储全局数据结构gd。


       2.调用board_init_f()。该函数是为了准备执行的硬件环境,因为RAM可能还不能使用,board_init_f()必须使用当前的GD来存储必须在稍后的阶段传递的任何数据。这些数据包括搬迁目的地,未来堆栈,以及未来GD位置。


       3.设置中间环境。使用board_init_f()在RAM中分配空间给gd和堆栈,但是bss和非常量数据仍然无法使用。


       4.调用重定向代码。此功能重新定位U-Boot从当前位置到由board_init_f计算的重定向后的地址。


       5.建立最终环境调用board_init_r()。包括在RAM中对BSS清零,初始化变量和堆栈,gd保留通过board_init_f()设定的值。


       6.跳转到board_init_r()执行。


函数:_main


       ENTRY(_main)


 


/*


 * Set up initial C runtime environment andcall board_init_f(0).


 */


 


#ifdefined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)


       ldr   sp,=(CONFIG_SPL_STACK)


#else


       ldr   sp,=(CONFIG_SYS_INIT_SP_ADDR)


#endif


       bic  sp,sp, #7      /* 8-byte alignment for ABI compliance*/


       sub  sp,sp, #GD_SIZE     /* allocate one GD aboveSP */


       bic  sp,sp, #7      /* 8-byte alignment for ABIcompliance */


       mov       r9,sp            /* GD is above SP */


       初始化栈指针,为board_init_f准备调用环境。最后r9寄存器中的地址就是gd结构体的首地址。


       #if 1


       __TEXT_BASE:


       .word CONFIG_SYS_TEXT_BASE


       mov r0, #0


       ldr r1, __TEXT_BASE


       ldr r2, __TEXT_BASE


       ldr r3, =__bss_end


       sub r2, r3, r2


       bl copy_code_to_sdram


       bl clear_bss


       ldr pc, =call_board_init_f


       .word的意思是在__TEXT_BASE地址处放置CONFIG_SYS_TEXT_BASE的值,还有一种就是.globl,这是告诉编译器紧跟着后面的的符号要被编译器用到。


       给r0清零,r1和r2都给__TEXT_BASE地址,r3给bss段的结束地址。结束地址和TEXT_BASE的差值给r2,然后跳转到copy_code_to_sdram,切过去:


       void copy_code_to_sdram(unsigned char*src, unsigned char *dest, unsigned int len)


{


int i = 0;


/* 如果是 NOR 启动 */


       if (isBootFromNorFlash())


       {


       while (i < len)


              {


                     dest[i] = src[i];


              i++;


              }


       }


else


       {


       nand_init_b();


       nand_read_b((unsigned int)src, dest,len);


       }


}


先判断是从nand还是从nor启动,然后将代码拷贝到sdram中去。接着,请bss段,然后ldr pc, =call_board_init_f,跳转到


call_board_init_f:


       mov r0, #0


       bl board_init_f


函数:board_init_f


       gd->mon_len = (ulong)&__bss_end -(ulong)_start;


指定代码的大小,为bss段的尾地址减去_start地址。


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


              if ((*init_fnc_ptr)() != 0) {


                     hang ();


              }


       }


遍历了init_sequence中的函数,init_sequence函数如下:


init_fnc_t *init_sequence[]= {


       arch_cpu_init,            /* basic arch cpu dependent setup */


       mark_bootstage,


#ifdefCONFIG_OF_CONTROL


       fdtdec_check_fdt,


#endif


#ifdefined(CONFIG_BOARD_EARLY_INIT_F)


       board_early_init_f,


#endif


       timer_init,            /* initialize timer */


#ifdef CONFIG_BOARD_POSTCLK_INIT


       board_postclk_init,


#endif


#ifdefCONFIG_FSL_ESDHC


       get_clocks,


#endif


       env_init,              /*initialize environment */


       init_baudrate,             /* initialze baudrate settings */


       serial_init,            /* serial communications setup */


       console_init_f,           /* stage 1 init of console */


       display_banner,          /* say that we are here */


       print_cpuinfo,            /* display cpu info (and speed) */


#ifdefined(CONFIG_DISPLAY_BOARDINFO)


       checkboard,         /* display board info */


#endif


#ifdefined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)


       init_func_i2c,


#endif


       dram_init,            /* configure available RAM banks */


       NULL,


};


这里有很多重要的初始化函数,例如init_baudrate,serial_init,,console_init_f,等等,就不一一切过去看了,只要知道每个函数名是干嘛的就可以了。


addr = CONFIG_SYS_SDRAM_BASE +get_effective_memsize();


这里地址等于BASE+有效地址,也就是整个sdram的可用部分。在下面:


#if !(defined(CONFIG_SYS_ICACHE_OFF) &&defined(CONFIG_SYS_DCACHE_OFF))


       /* reserveTLB table */


       gd->arch.tlb_size= PGTABLE_SIZE;


       addr -=gd->arch.tlb_size;


 


       /* rounddown to next 64 kB limit */


       addr&= ~(0x10000 - 1);


 


       gd->arch.tlb_addr= addr;


       debug("TLBtable from %08lx to %08lxn", addr, addr + gd->arch.tlb_size);


#endif


 


       /* rounddown to next 4 kB limit */


       addr&= ~(4096 - 1);


       debug("Topof RAM usable for U-Boot at: %08lxn", addr);


这里是说如果没有定义关闭icache以及dcache关闭,就把PGTABLE_SIZE给gd,同时addr要减去gd这部分的大小,最后addr的值其实就是tlb的地址,并且要4Kb对齐。


addr=CONFIG_SYS_TEXT_BASE;


这里的CONFIG_SYS_TEXT_BASE;代码u-boot代码在内存中的起始地址。


addr_sp = addr - TOTAL_MALLOC_LEN;


       debug("Reserving %dk for malloc()at: %08lxn",


                     TOTAL_MALLOC_LEN >>10, addr_sp);


       /*


        *(permanently) allocate a Board Info struct


        *and a permanent copy of the "global" data


        */


       addr_sp -= sizeof (bd_t);


       bd = (bd_t *) addr_sp;


       gd->bd = bd;


       debug("Reserving %zu Bytes for BoardInfo at: %08lxn",


                     sizeof (bd_t), addr_sp);


#ifdef CONFIG_MACH_TYPE


       gd->bd->bi_arch_number= CONFIG_MACH_TYPE; /* board id for Linux */


#endif


 


       addr_sp-= sizeof (gd_t);


       id= (gd_t *) addr_sp;


       debug("Reserving%zu Bytes for Global Data at: %08lxn",


                     sizeof(gd_t), addr_sp);


 


首先预留malloclen,一般为0x400000,为bd,gd做一个永久的拷贝,因为这时候环境已经准备的差不多了。留出了全局信息bd_t结构体的空间,首地址存在gd->bd。留出gd_t结构体的空间。首地址存在id中。将此地址保存在gd->irq_sp中作为异常栈指针。


addr_sp += 128;  /*leave 32 words for abort-stack   */


       gd->irq_sp= addr_sp;


这里是为异常留的堆栈部分。


gd->bd->bi_baudrate = gd->baudrate;


       /* Ram istboard specific, so move it to board code ... */


       dram_init_banksize();


       display_dram_config();     /* and display it */


首先将gd->baudrate赋给gd->bd->bi_baudrate,然后对板上的BANKS进行一个初始化。


gd->relocaddr = addr;


       gd->start_addr_sp = addr_sp;


       gd->reloc_off = addr - (ulong)&_start;


       debug("relocation Offset is:%08lxn", gd->reloc_off);


       if (new_fdt) {


              memcpy(new_fdt, gd->fdt_blob,fdt_size);


              gd->fdt_blob = new_fdt;


       }


       memcpy(id, (void *)gd, sizeof(gd_t));


       return (unsigned int)id;


       三个地址的幅值,主要是重定向的起始结束以及sp的起始地址。最后将gd结构体拷贝到新的地址上。board_init_f结束。


       ldr sp, [r9, #GD_START_ADDR_SP] /* sp =gd->start_addr_sp */


       bic sp, sp, #7 /* 8-byte alignment forABI compliance */


       ldr r9, [r9, #GD_BD] /* r9 = gd->bd */


       sub r9, r9, #GD_SIZE /* new GD is belowbd */


       ldr r1, __TEXT_BASE


       bl board_init_r


       执行这一段,更新sp,更新gd地址,跳转到board_init_r。


函数:board_init_r


       void board_init_r(gd_t *id, ulongdest_addr)


{


       ulong malloc_start;


#if!defined(CONFIG_SYS_NO_FLASH)


       ulong flash_size;


#endif


 


       gd->flags |= GD_FLG_RELOC;   /* tell others: relocation done */


       bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R,"board_init_r");


 


       monitor_flash_len =(ulong)&__rel_dyn_end - (ulong)_start;

[1] [2]
关键字:U-boot  移植到  MINI2440 引用地址:U-boot-2014.04移植到MINI2440(11) 第二启动阶段分析

上一篇:U-boot-2014.04移植到MINI2440(9) nor flash启动和nand flash 启动
下一篇:U-boot-2014.04移植到MINI2440(10) 移植nand flash保存环境变量、添加分区

推荐阅读最新更新时间:2024-11-10 09:18

【重温经典】mini2440驱动程序之LED驱动(基于Linux-2.6.32.2)
一、LED资源介绍 1、LED对应的GPIO(已上拉) LED1 nLED1 GPB5 LED2 nLED2 GPB6 LED3 nLED3 GPB7 LED4 nLED4 GPB8 2、硬件电路 二、驱动代码(mini2440_leds.c) 以混杂设备注册,主要实现了ioctl接口,应用程序操作时,只需要打开这个设备文件,然后发一个ioctl的命令就会进入到内核空间,接着调用该驱动的ioctl函数来设置相应的状态。 (1)、设置GPIO为输出模式 for (i = 0; i 4; i++) { s3c2410_gpio_cfgpin(led_table ,
[单片机]
【重温经典】<font color='red'>mini2440</font>驱动程序之LED驱动(基于Linux-2.6.32.2)
06-S3C2440学习之移植2012u-bootS3C2440(移植过程二)支持NAND启动
说明: 原来的代码在链接时加了 -pie 选项, 使得u-boot.bin里多了 *(.rel*) , *(.dynsym) (*(.rel*) , *(.dynsym)这些地址信息用于实现UBOOT可以被拷贝到任何地方,更新地址信息),但使得程序非常大,结构复杂,不利于从NAND启动(重定位之前的启动代码应该少于4K)。所提去掉了pie功能。 (1)使用一下之前写的init.c 拷贝到2440单板下: 修改init内容为: /* NAND FLASH控制器 */ #define NFCONF (*((volatile unsigned long *)0x4E000000)) #define
[单片机]
06-S3C2440学习之<font color='red'>移植</font>2012u-boot<font color='red'>到</font>S3C2440(<font color='red'>移植</font>过程二)支持NAND<font color='red'>启动</font>
一起学mini2440裸机开发(九)--ARM中断控制系统
ARM处理器程序的执行流程种类 ●正常执行:每执行一条ARM指令,程序计数器PC的值自动加4。这一过程描述了应用程序顺序执行的状态。 ●跳转执行:通过B、BL跳转执行,实现程序在一定范围内的跳转执行。这一过程描述了ARM处理器程序执行过程中的过程调用。 ●中断处理:在应用程序执行过程中,发生中断后,ARM处理器在执行完当前指令后,跳转到上述中断对应的中断处理程序处去执行,执行完中断处理程序后,再返回到发生中断的指令的下一条执行处接着执行。这一过程描述了ARM处理器对异常中断的响应情况。 S3C2440中断系统概述 在ARM处理器运行过程中,需要与系统的各类外部设备进行通信,包括发出控制信息、读取外部设备的状态信
[单片机]
一起学<font color='red'>mini2440</font>裸机开发(九)--ARM中断控制系统
STM32F103R8T6系统移植STM32F103RCT6
1 由于工作需要原来的STM32F103R8T6需要升级到RCT6由此也需要把软件系统移植到RCT6但是移植过来的时候由于r8的定时只有T1--T4 ,RC有6个定时器所以遇到自己认为很奇怪的问题。 问题1 代码移植过来后发现有些定时器根本不工作,时钟也使能啦,定时器也配置啦,根本找不到什么问题,被逼的没办法啦。后来就更新ST公司给的配置文件。 原来工程配置文件需要更新为下面这两个配置文件 新更新的文件
[单片机]
STM32F103R8T6系统<font color='red'>移植</font><font color='red'>到</font>STM32F103RCT6
u-boot移植(九)---代码修改---NAND
一、NAND原理      NAND 无地址空间,地址和数据的发送都依赖于LDATA 这一串数据总线。      不看随机页编程,看到从高位到低位的页,总共分为64个页面,每个页的组成是2K + 64 个byte,一个块的大小是(128K + 4K)byte,64页组成一块。 1.1 NAND Flash的编址   nand flash的的页的大小是(2048 + 64)byte,64这个数据是不参与编址的。   访问 nand flash: 发出命令:读、写、擦除 发出地址 传输数据   命令设置如下:    1.2 nand flash的访问      可以看看上面的模式选择,然后对应引脚进行操作,就
[单片机]
<font color='red'>u-boot</font><font color='red'>移植</font>(九)---代码修改---NAND
移植 libxml2-2.9.4 arm
一、环境介绍 1.1 宿主机 Ubuntu 1404 32 位 1.2 嵌入式平台 ATMEL AT91SAM9X25 1.3 交叉工具链 arm-none-linux-gnueabi libxml2-2.9.4移植所需源码包下载地址 二、交叉编译 2.1 先编译 libxml2-2.9.4 依赖的模块 2.1.1 libicobv tar xvf libiconv-1.15.tar.gz cd libiconv-1.15/ ./configure --prefix=$PWD/tmp --host=arm-none-linux-gnueabi --build=i686-linux make V=s make in
[单片机]
uCosII移植STM32触发中断、任务切换的汇编学习
STM32汇编关键字含义: IMPORT OSxx ;//IMPORT声明了OSxx在外文件定义 EXPORT OSxx ;//EXPORT声明OSxx可以被外文件使用,相当于全局性声明 LDR R0,=label ;//这是ARM的RISC指令下一个用于内存和CPU寄存器交换数据的指令,用法比较复杂。具体百度。 ;//这里的含义就是把label的地址值赋值给R0,和 LDR R0,label 不同,没有'='的是取其地址的值传递给R0 ;// LDR R0,label ;//取label其地址的值传递给R0 LDR?R0,0x12345678 ;//就是把0x12345678这个地址中的值存放到r0
[单片机]
【GD32 MCU 移植教程】6、从GD32F1x0和GD32F3x0移植GD32E230
1.简介 GD32E230 系列是 GD 最新推出的 Cortex_M23 系列产品,该系列资源上与既有的 GD32F1x0以及 GD32F3x0 兼容度非常高。由于 GD32E230 系列主打低功耗和低成本,所以在存量客户中可能会有越来越多的客户会有从 GD32F1x0 和 GD32F3x0 移植到 GD32E230 系列的需求,本文档专门针对既有的 GD32F1x0 和 GD32F3x0 代码如何移植到 GD32E230 做一个详细的介绍; 2.硬件资源对比 1. TSSOP20 和 QFN28PIN 的封装兼容,但 E230 系列 PA9、PA10 可以映射为 PA11、PA12; 2. LQFP32、QFN32 封
[单片机]
【GD32 MCU <font color='red'>移植</font>教程】6、从GD32F1x0和GD32F3x0<font color='red'>移植</font><font color='red'>到</font>GD32E230
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved