基本指令含义

.globl _start

.globl指示告诉汇编器,_start这个符号要被链接器用到,所以要在目标文件的符号表中标记它是一个全局符号

b,bl

b是不带返回的跳转  bl带返回的跳转

.word

插入一个32-bit的数据队列。(与armasm中的DCD功能相同)

芯片到uboot启动流程 :ROM → MLO(SPL)→ uboot.img

启动脚本:/u-boot2011.09/arch/arm/cpu/armv7/omap-common/u-boot_spl.lds

MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\

LENGTH = CONFIG_SPL_MAX_SIZE }

MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \

LENGTH = CONFIG_SPL_BSS_MAX_SIZE }

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

OUTPUT_ARCH(arm)

ENTRY(_start)

SECTIONS

{

.text      :

{

__start = .;

  arch/arm/cpu/armv7/start.o(.text)    //入口函数

  *(.text*)

} >.sram

. = ALIGN(4);

.rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram

. = ALIGN(4);

.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram

. = ALIGN(4);

__image_copy_end = .;

_end = .;

.bss :

{

. = ALIGN(4);

__bss_start = .;

*(.bss*)

. = ALIGN(4);

__bss_end__ = .;

} >.sdram

}

分析文件arch/arm/cpu/armv7/start.S

1. 保存启动参数  arch/arm/cpu/armv7/ti81xx/lowlevel_init.S

bl  save_boot_params

简化代码:

save_boot_params:

#ifdef CONFIG_SPL_BUILD

ldrr4, =ti81xx_boot_device

ldrr5, [r0, #BOOT_DEVICE_OFFSET]

andr5, r5, #BOOT_DEVICE_MASK

strr5, [r4]

#endif

bxlr

2. cpu初始化   cpu_init_crit  

首先设置cpu工作模,把cpu的状态类型为SVC,然后执行cpu_init_crit关闭mmu缓存,接着跳转到arch/arm/cpu/armv7/ti81xx/lowlevel_init.S  的lowlevel_init中,

lowlevel_init 主要调用 board\aplex\ecm_5206\evm.c  s_init 函数

void s_init(void)

{

l2_cache_enable();       //二级缓存

__raw_writel(0xAAAA, WDT_WSPR);

while(__raw_readl(WDT_WWPS) != 0x0);

__raw_writel(0x5555, WDT_WSPR);

while(__raw_readl(WDT_WWPS) != 0x0);

pll_init();             //设置时钟

u32 regVal;

u32 uart_base = DEFAULT_UART_BASE;

enable_uart0_pin_mux();   //使能串口0

if (board_id == IA_BOARD) {

uart_base = UART3_BASE;

}

regVal = __raw_readl(uart_base + UART_SYSCFG_OFFSET);

regVal |= UART_RESET;    //直接操作寄存器

__raw_writel(regVal, (uart_base + UART_SYSCFG_OFFSET) );

while ((__raw_readl(uart_base + UART_SYSSTS_OFFSET) &

UART_CLK_RUNNING_MASK) != UART_CLK_RUNNING_MASK);

/* Disable smart idle */

regVal = __raw_readl((uart_base + UART_SYSCFG_OFFSET));

regVal |= UART_SMART_IDLE_EN;

__raw_writel(regVal, (uart_base + UART_SYSCFG_OFFSET));

init_timer();                //实际上是timer2

preloader_console_init();   //控制台初始化

config_am335x_ddr();        //配置DDR

}

即:

1)使能二级缓存  l2_cache_enable();

2)关闭看门狗    __raw_writel(0x5555, WDT_WSPR);

3)设置外设时钟  pll_init()

PATH: board\aplex\ecm_5206中

mpu_pll_config(MPUPLL_M_720);

core_pll_config();

per_pll_config();

ddr_pll_config();

interface_clocks_enable();

power_domain_transition_enable();

per_clocks_enable();

使能RTC rtc32k_enable()  /board/ti/am335x/evm.c

使能32K实时时钟时钟,准确是应该是32.768K

static void rtc32k_enable(void)

{

__raw_writel(0x83e70b13, (AM335X_RTC_BASE + RTC_KICK0_REG));

__raw_writel(0x95a4f1e0, (AM335X_RTC_BASE + RTC_KICK1_REG));

__raw_writel(0x48, (AM335X_RTC_BASE + RTC_OSC_REG));

}

4)使能串口 UART0

配置串口,主要用于打印中断,也可以配置UART3

if (board_id == IA_BOARD) {

uart_base = UART3_BASE;

}

6)初始化定时器Timer2 init_timer();

7)初始化控制台 preloader_console_init()

简化代码为: 实际上是串口配置  修改这里 可以修改串口控制台应该

/* This requires UART clocks to be enabled */

void preloader_console_init(void)

{

const char *u_boot_rev = U_BOOT_VERSION;

char rev_string_buffer[50];

gd = &gdata;

gd->bd = &bdata;

gd->flags |= GD_FLG_RELOC;

gd->baudrate = CONFIG_BAUDRATE;        //串口波特率设置

serial_init();  //串口初始化

u_boot_rev = &u_boot_rev[7];

omap_rev_string(rev_string_buffer);

}

8)配置DDR  config_am335x_ddr(void)

简化代码:

static void config_am335x_ddr(void)  //ddr2初始化

{

int data_macro_0 = 0;

int data_macro_1 = 1;

enable_ddr_clocks();

config_vtp();

Cmd_Macro_Config();

Data_Macro_Config(data_macro_0);

Data_Macro_Config(data_macro_1);

__raw_writel(PHY_RANK0_DELAY, DATA0_RANK0_DELAYS_0);

__raw_writel(PHY_RANK0_DELAY, DATA1_RANK0_DELAYS_0);

__raw_writel(DDR_IOCTRL_VALUE, DDR_CMD0_IOCTRL);

__raw_writel(DDR_IOCTRL_VALUE, DDR_CMD1_IOCTRL);

__raw_writel(DDR_IOCTRL_VALUE, DDR_CMD2_IOCTRL);

__raw_writel(DDR_IOCTRL_VALUE, DDR_DATA0_IOCTRL);

__raw_writel(DDR_IOCTRL_VALUE, DDR_DATA1_IOCTRL);

__raw_writel(__raw_readl(DDR_IO_CTRL) & 0xefffffff, DDR_IO_CTRL);

__raw_writel(__raw_readl(DDR_CKE_CTRL) | 0x00000001, DDR_CKE_CTRL);

config_emif_ddr2();

}

到这里,整个cpu已经初始化完成,执行完成s_init之后返回到strt.S中,可以进行一些启动操作  比如配置状态灯等

3.板级操作初始化  include/configs/ecm_5206.h

返回start.S,执行

call_board_init_f:

ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)

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

ldr r0,=0x00000000

bl  board_init_f    //有返回的跳转到  board_init_f

1) 设置 internal RAM 内存空间的栈指针

2)接着跳转到/arch/arm/cpu/armv7/omap-common/spl.c 中

执行 C代码  board_init_f(ulong dummy),跳转到spl第二阶段

void board_init_f(ulong dummy)

{

debug(">>board_init_f()\n");

//重新指定

relocate_code(CONFIG_SPL_STACK, &gdata, CONFIG_SPL_TEXT_BASE);

}

4.代码重定位

1)stack_setup

2)copy_loop

3)clear_bss

5.返回转到spl第二阶段 ,调用函数 board_init_r   

路径: /arch/arm/cpu/armv7/omap-common/spl.

简化代码为:

void board_init_r(gd_t *id, ulong dummy)

{

u32 boot_device;

timer_init();

i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);

spl_board_init();

boot_device = omap_boot_device();  获取启动选择

switch (boot_device) {

case BOOT_DEVICE_MMC1:

case BOOT_DEVICE_MMC2:

spl_mmc_load_image();   //EMMC启动

break;

case BOOT_DEVICE_NAND:

spl_nand_load_image();  //SD卡

break;

case BOOT_DEVICE_UART:

spl_ymodem_load_image(); //串口

break;

default: hang();

break;

}

jump_to_image_no_args();

}

流程概括为:

1)初始化定时器  timer_init();

2)i2c配置 i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);

3)spl板级初始化 spl_board_init();

4)按照启动方式 加载 image jump_....

4)加载并跳转到img  代码也在 /arch/arm/cpu/armv7/omap-common/spl.c中

简化代码为:

static void jump_to_image_no_args(void)

{

typedef void (*image_entry_noargs_t)(void)__attribute__ ((noreturn));

image_entry_noargs_t image_entry =

(image_entry_noargs_t) spl_image.entry_point;

int *p = 0x80000000;

*p = omap_boot_device();

image_entry();        //跳转到image中

}

 board_init_r 中完成 MLO(SPI)阶段的所有初始化,并跳转到 uboot.img 阶段

----------------------------uboot.img--------------------------------

6.uboot.img   arch/arm/lib/board.c

在spl执行第一和第二阶段结束后,已经初始化运行平台,并根据boot_device选择方式加载了image,

image主要功能,加载kernel

接下来就是程序重新返回运行start.o,跳转回到board_init_f()

简化代码为:

void board_init_f(ulong bootflag)

{

bd_t *bd;

init_fnc_t **init_fnc_ptr;

gd_t *id;

ulong addr, addr_sp;

gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);

__asm__ __volatile__("": : :"memory");

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

gd->mon_len = _bss_end_ofs;

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

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

hang ();

}

}

gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;

addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;

addr -= (LOGBUFF_RESERVE);

i = getenv_r("pram", (char *)tmp, sizeof(tmp));

reg = (i > 0) ? simple_strtoul((const char *)tmp, NULL, 10) :

CONFIG_PRAM;

addr -= (reg << 10); /* size is in kB */

addr -= (4096 * 4);

addr &= ~(0x10000 - 1);

gd->tlb_addr = addr;

/* round down to next 4 kB limit */

addr &= ~(4096 - 1);

gd->fb_base = CONFIG_FB_ADDR;

#else

addr = lcd_setmem(addr);

gd->fb_base = addr;

addr -= gd->mon_len;

addr &= ~(4096 - 1);

addr_sp = addr - TOTAL_MALLOC_LEN;

addr_sp -= sizeof (bd_t);

bd = (bd_t *) addr_sp;

gd->bd = bd;

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

addr_sp -= sizeof (gd_t);

id = (gd_t *) addr_sp;

gd->irq_sp = addr_sp;

addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);

addr_sp -= 12;

addr_sp &= ~0x07;

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

gd->irq_sp = addr_sp;

post_bootmode_init();

post_run(NULL, POST_ROM | post_bootmode_get(0));

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

dram_init_banksize();

display_dram_config();

gd->relocaddr = addr;

gd->start_addr_sp = addr_sp;

gd->reloc_off = addr - _TEXT_BASE;

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

relocate_code(addr_sp, id, addr);

}

在 uboot.img 运行过程中,有两个非常重要的结构体:gd_t 和 bd_t 。

其中 gd_t :

global_data 数据结构的定义

位于:/arch/arm/include/asm/global_data.h 中。

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

其中 bd_t :

bd_info 数据结构的定义

位于:/arch/arm/include/asm/u-boot.h 中。

其成员是开发板的相关参数。

Image重要结构体头文件        include/image.h

typedef struct bootm_headers {  //boot头结构

image_header_t *legacy_hdr_os; /* image header pointer */

image_header_t legacy_hdr_os_copy; /* header copy */ ulong legacy_hdr_valid;

……

}

typedef struct image_header {  //image 头结构体

……

__be32 ih_size; /* Image Data Size */

__be32 ih_load; /* Data Load Address

……

}

1. 启动脚本开始分析image  u-boot2011.09/include/configs/ am335x_evm.h.20160426

#define CONFIG_BOOTCOMMAND \

"if mmc rescan; then " \                           #如果是SD/MMC加载

"echo SD/MMC found on device ${mmc_dev};" \    # - - - @0

"if run loadbootenv; then " \                   #加载loadbootenv - - - @1

"echo Loaded environment from ${bootenv};" \  #从bootenv加载- - - @2

"run importbootenv;" \   #运行  importbootenv

"fi;" \

"if test -n ${uenvcmd}; then " \

"echo Running uenvcmd ...;" \

"run uenvcmd;" \        #运行  uenvcmd

"fi;" \

"if run mmc_load_image; then " \

"run mmc_args;" \       #运行  mmc_args

"bootm ${kloadaddr};" \   #加载kloadaddr - - - - - @3

"fi;" \

"fi;" \

"run nand_boot;" \

@0

l "mmc_dev=0\0" \      #给mmc_dev赋值

"mmc_root=/dev/ram rw \0" \

"nand_root=ubi0:rootfs rw ubi.mtd=7,2048\0" \

"spi_root=/dev/mtdblock4 rw\0" \

@1 @2

l "bootenv=uEnv.txt\0" \

"loadbootenv=fatload mmc ${mmc_dev} ${loadaddr} ${bootenv}\0" \

"importbootenv=echo Importing environment from mmc ...; " \

"env import -t ${loadaddr} ${filesize}\0" \

"mmc_load_image=fatload mmc ${mmc_dev} ${kloadaddr} ${bootfile};" \

"fatload mmc ${mmc_dev} ${rdloadaddr} ${ramdisk}\0" \

@3

#define CONFIG_EXTRA_ENV_SETTINGS \

"bootfile=uImage\0" \

"ramdisk=ramdisk.gz\0" \

"loadaddr=0x82000000\0" \

"kloadaddr=0x80007fc0\0" \

u-boot,imagekernel 的加载函数

入口

1. common/cmd_botm,c

static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])

{

……

bootm_start_lmb();

//获取内核

os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,&images, &images.os.image_start, &images.os.image_len);

……

if (((images.os.type == IH_TYPE_KERNEL) ||

(images.os.type == IH_TYPE_MULTI)) &&

(images.os.os == IH_OS_LINUX)) {            //使用IH_OS_LINUX

ret = boot_get_ramdisk (argc, argv, &images, IH_INITRD_ARCH,

&images.rd_start, &images.rd_end);

……

}

}

在 common/Cmd_bootms中,定义了IH_OS_LINUX ,并赋值为do_bootm_linux  这是最后跳转进入kernel的接口

static boot_os_fn *boot_os[] = {

#ifdef CONFIG_BOOTM_LINUX

[IH_OS_LINUX] = do_bootm_linux,

……

};

即:从这里跳转进入do_bootm_linux

2. arch/arm/lib/bootm.c

代码如下:arch/arm/lib/bootm.c

int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)

{

bd_t *bd = gd->bd;

char *s;

int machid = bd->bi_arch_number;

void (*kernel_entry)(int zero, int arch, uint params);

#ifdef CONFIG_CMDLINE_TAG

char *commandline = getenv ("bootargs");

#endif

show_boot_progress (15);

kernel_entry = (void (*)(int, int, uint))images->ep;

setup_start_tag (bd);

setup_serial_tag (¶ms);

announce_and_cleanup();

kernel_entry(0, machid, bd->bi_boot_params);   //进入内核  不返回

}

参考文献:http://blog.chinaunix.net/uid-28458801-id-3486399.html

am335x uboot启动流程分析的更多相关文章

  1. u-boot启动流程分析(2)_板级(board)部分

    转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global dat ...

  2. imx6 uboot启动流程分析

    参考http://blog.csdn.net/skyflying2012/article/details/25804209 这里以imx6平台为例,分析uboot启动流程对于任何程序,入口函数是在链接 ...

  3. Uboot启动流程分析(三)

    1.前言 在前面的文章Uboot启动流程分析(二)中,链接如下: https://www.cnblogs.com/Cqlismy/p/12002764.html 已经对_main函数的整个大体调用流程 ...

  4. Uboot启动流程分析(二)

    1.前言 在前面的文章Uboot启动流程分析(一)中,链接如下: https://www.cnblogs.com/Cqlismy/p/12000889.html 已经简单地分析了low_level_i ...

  5. Uboot启动流程分析(一)

    1.前言 Linux系统的启动需要一个bootloader程序,该bootloader程序会先初始化DDR等外设,然后将Linux内核从flash中拷贝到DDR中,最后启动Linux内核,uboot的 ...

  6. 嵌入式Linux驱动学习之路(五)u-boot启动流程分析

    这里说的u-boot启动流程,值得是从上电开机执行u-boot,到u-boot,到u-boot加载操作系统的过程.这一过程可以分为两个过程,各个阶段的功能如下. 第一阶段的功能: 硬件设备初始化. 加 ...

  7. u-boot启动流程分析(1)_平台相关部分

    转自:http://www.wowotech.net/u-boot/boot_flow_1.html 1. 前言 本文将结合u-boot的“board—>machine—>arch—> ...

  8. Uboot启动流程分析(转载)

    最近一段时间一直在做uboot移植相关的工作,需要将uboot-2016-7移植到单位设计的ARMv7的处理器上.正好元旦放假三天闲来无事,有段完整的时间来整理下最近的工作成果.之前在学习uboot时 ...

  9. U-BOOT启动流程分析--start.s(二)

    一.概述 u-boot的启动流程: 从文件层面上看主要流程是在两个文件中:cpu/arm920t/start.s,lib_arm/board.c, 先来分析start.s    在flash中执行的引 ...

随机推荐

  1. 白盒测试实践项目(day1)

    由于近期各种考试逼近,我们小组白盒测试实践项目进度有些慢,在任务决定后的两天里,我们小组各个成员的进度完成不一. 胡俊辉熟悉了怎么使用Junit对部分代码的测试,初步掌握了Junit的简单使用. 汪鸿 ...

  2. 两款JSON类库Jackson与JSON-lib的性能对比(新增第三款测试)

    本篇文章主要介绍了"两款JSON类库Jackson与JSON-lib的性能对比(新增第三款测试)",主要涉及到两款JSON类库Jackson与JSON-lib的性能对比(新增第三款 ...

  3. 【转】Java虚拟机详解----常用JVM配置参数

    原文地址:http://www.cnblogs.com/smyhvae/p/4736162.html 本文主要内容: Trace跟踪参数 堆的分配参数 栈的分配参数 零.在IDE的后台打印GC日志: ...

  4. HDU 6005 Pandaland (Dijkstra)

    题意:给定一个图,找出一个最小环. 析:暴力枚举每一条,然后把边设置为最大值,以后就不用改回来了,然后跑一遍最短路,跑 n 次就好. 代码如下: #pragma comment(linker, &qu ...

  5. CodeForces 877E Danil and a Part-time Job(dfs序+线段树)

    Danil decided to earn some money, so he had found a part-time job. The interview have went well, so ...

  6. java动态代理类

    很有意思的一个东西,在java.lang.reflect包下 示例代码 package com.guangshan.test.proxy; import java.lang.reflect.Invoc ...

  7. MVC4 路由解析 同名Controller的解决方案

    通常我们在MVC中通过Area建立子站的时候会有 controller名称重复的情况,这是后如何区分路由优先级, 我们知道 在Route对象中存在RouteValueDictionary 类型的Dat ...

  8. [Mac][转] ports命令

    [Mac][转] ports命令 安装路径:/opt/local/lib/ 常用命令 port -d selfupdate #升级macport, 如同:cd /usr/ports && ...

  9. Partition--分区切换

    现有数据表[dbo].[staging_TB1_20131018-104722]和分区表[dbo].[TB1],需要将分区表和数据表中做数据交换 CREATE TABLE [dbo].[staging ...

  10. AgentJob--修改操作系统时间对Job的影响

    场景:有一个数据库作业每10分钟运行一次,在系统管理员修改操作系统时间后,作业长时间未运行. 分析:作业最后一次运行时间是 10:20,按照作业的计划,下一次的运行时间为 10:30,而系统管理员修改 ...