基本指令含义

.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. dbcp的销毁

    使用commons-dbcp-1.2.2.jar的DataSource,发现每次动态编译后连接池中的连接不会释放,新的连接池建立有mssql多出一组连接,只有重新启动tomcat或weblogic才可 ...

  2. Android 热修复技术中的CLASS_ISPREVERIFIED问题

    一.前言 上一篇博客中,我们通过介绍dex分包原理引出了Android的热补丁技术,而现在我们将解决两个问题. 1. 怎么将修复后的Bug类打包成dex 2. 怎么将外部的dex插入到ClassLoa ...

  3. DRBD 数据镜像软件

    1>DRBD介绍 1>数据镜像软件DRBD介绍  分布式块设备复制(Distributed Relicated Block Deivce,DRBD),是一种基于软件.基于网络的块复制存储解 ...

  4. 4、Semantic-UI之图标的使用

    4.1 图标的使用   在Semantic-UI中定义了很多的图标样式,这些图标样式可以通过官网查看名称(官网中名称首字母都是大写的,但是在实际使用中全部都是小写使用的): 实例:图标样式 定义基础图 ...

  5. Exception has been thrown by the target of an invocation

    I'd suggest checking for an inner exception. If there isn't one, check your logs for the exception t ...

  6. Backup--压缩备份和数据库压缩

    1> 即使数据库启用了页压缩或行压缩,压缩备份也可以有效减小备份的大小,压缩备份的压缩效率取决于表中的数据类型 2> 数据库压缩有利于降低备份时间(因为数据库变小) 3> 对已启用压 ...

  7. 零散知识点总结(持续更新……)

        这篇博客用于记录平时学习中遇到的零散的知识点,它们不适于单独写一篇长博客,在这里记录下来一是为了增强记忆,二是为了方便复习总结.这篇博客会持续更新... 一.JS数据类型及类型判断 1. JS ...

  8. 阿里云PolarDB及其共享存储PolarFS技术实现分析(上)

    PolarDB是阿里云基于MySQL推出的云原生数据库(Cloud Native Database)产品,通过将数据库中计算和存储分离,多个计算节点访问同一份存储数据的方式来解决目前MySQL数据库存 ...

  9. [HNOI2010] 合唱队

    题目链接:https://www.luogu.org/problemnew/show/P3205 一个区间DP的题目. 设计状态为:\(dp1[i][j]\)表示当前区间为\([i,j]\),而且最后 ...

  10. C#中List调用库函数sort进行升序排序

    private void button1_Click(object sender, EventArgs e) { List<int> demo2 = new List<int> ...