加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

启动的流程

发布时间:2020-12-15 07:15:22 所属栏目:百科 来源:网络整理
导读:先分析一下u-boot启动的两个阶段,分别对应start.S和board.c这两个文件。带着两个目的:一是分析一下启动的流程,二是熟悉一下汇编。 ??? 转载请注明出处,有误的地方请指正。源码基于u-boot1.1.4版本。 ??? 先看board/smsk2410/u-boot.lds这个链接脚本,可

先分析一下u-boot启动的两个阶段,分别对应start.S和board.c这两个文件。带着两个目的:一是分析一下启动的流程,二是熟悉一下汇编。

??? 转载请注明出处,有误的地方请指正。源码基于u-boot1.1.4版本。
??? 先看board/smsk2410/u-boot.lds这个链接脚本,可以知道目标程序的各部分链接顺序。

OUTPUT_FORMAT("elf32-littlearm",?)
/*OUTPUT_FORMAT"elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
????.?=?0x00000000;?/*指定可执行image文件的全局入口点,通常这个地址都放在ROM(flash)0x0位置。必须使编译器知道这个地址,通常都是修改此处来完成/

????=?ALIGN(4;
????.text?:
????{
?????cpu/arm920t/start.o?(.text)
?????)
????}

????.rodata?:?{?.rodata)?}

????.data?.data.got?.got.;
????__u_boot_cmd_start?.u_boot_cmd?.u_boot_cmd)?}
????__u_boot_cmd_end?;

????;
????__bss_start?.bss?.bss)?}
????_end?;
}

??? 第一个要链接的是cpu/arm920t/start.o,那么U-Boot的入口指令一定位于这个程序中。下面详细分析一下程序跳转和函数的调用关系以及函数实现。
1.Stage1:cpu/arm920t/start.S
??? 这个汇编程序是U-Boot的入口程序,开头就是复位向量的代码。

U-Boot启动代码流程图

_start:?b reset //复位向量?;;设置异常向量表
???????ldr pc?_software_interrupt
???????ldr pc?_data_abort
???????ldr pc?_irq //中断向量
???????ldr pc*?the actual reset code?/
reset:?//复位启动子程序
???????/*?设置CPU为SVC32模式?/
???????mrs r0r0#0x1f?;位清除,将某些位的值置0:r0?=?r0?AND?(?!0x1f)
???????orr r0#0xd3?;逻辑或,将r0与立即数进行逻辑或,放在r0中(第一个)
???????msr cpsr*?关闭看门狗?/
?/*?turn off the watchdog?/
#if?defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /*?Interupt-Controller base addresses?/
# define CLKDIVN 0x14800014 /*?clock divisor register?/
#elif defined(CONFIG_S3C2410)
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 //
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /endif

#)?||?defined)
????ldr r0=pWTCON
????mov?r1str?r1[r0]
/*?禁止所有中断和设置CPU频率?/
????/*
?????*?mask?all IRQs by setting all bits?in?the INTMR?-?default
?????/
????=INTMSK
????]
#?)
????ldr r1=0x3ff
????ldr r0=INTSUBMSK
????endif

????/*?FCLK:HCLK:PCLK?=?1:2:4?/?;FCLK用于CPU,HCLK用于AHB,PCLK用于APB
????/*?default FCLK is 120 MHz?!?/
????ldr r0=CLKDIVN?;根据硬件手册来设置CLKDIVN寄存器
????;用户手册的推荐值
????]
#endif?/*?CONFIG_S3C2400?|?CONFIG_S3C2410?/


/*?这些初始化代码在系统重起的时候执行,运行时热复位从RAM中启动不执行?*?we do sys-critical inits only at rebootnot?when booting from?
?????/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
????bl?cpu_init_crit?;跳转去初始化CPU
#endif
#ifdef CONFIG_INIT_CRITICAL 原文中的,估计是1.1.16版本的
;?bl?cpu_init_crit
#endif

/*?CPU和RAM两个关键的初始化子程序?/
/*?初始化CPU?/
cpu_init_crit:
????/*?flush v4 I/D caches 设置CP15
?????mov?r0?0?c7*?flush v3/v4 cache?;使I/D cache失效:将寄存器r0的数据传送到协处理器p15的c7中。C7寄存器位对应cp15中的cache控制寄存器
????mcr p15*?flush v4 TLB?;使TLB操作寄存器失效:将r0数据送到cp15的c8、c7中。C8对应TLB操作寄存器

????/*?disable MMU stuff?and?caches 禁止MMU和caches
?????/
????mrc p15?c0;先把c1和c0寄存器的各位置0(r0?=?0)
????bic r0?9:8?--V-?-RS?2:0?(B-CAM;这里我本来有个疑问:为什么要分开设置。因为arm汇编要求的立即数格式所决定的
????orr r0?(AAlign?;上一条已经设置bit1为0,这一条又设置为1??
????orr r0(I)?I-Cache
????mcr p15;用上面(见下面)设定的r0的值设置c1??(cache类型寄存器)和c0(control字寄存器),以下为c0的位定义
;bit8:?0?=?Disable System protection
;bit9=?Disable ROM protection
;bit0=?MMU disabled
;bit1=?Fault checking disabled 禁止纠错
;bit2=?Data cache disabled
;bit7=?Little-endian operation
;bit12:?1?=?Instruction cache enabled


????/*?配置内存区控制寄存器 ??有待分析,是1.4版本的
?????*?before relocating*?because memory timing is board-dependend*?find a lowlevel_init.S?in?your board directory.
?????mov?ipbl?lowlevel_init?;位于board/smdk2410/lowlevel_init.S:用于完成芯片存储器的初始化,执行完成后返回
????mov?lrip
????mov?pc:?/*?把U-Boot重新定位到RAM?/
???????adr r0*?r0是代码的当前位置?;adr伪指令,汇编器自动通过当前PC的值算出 如果执行到_start时PC的值,放到r0中:
当此段在flash中执行时r0?=?_start?=?0;当此段在RAM中执行时_start?=?_TEXT_BASE(在board/smdk2410/config.mk中指定的值为0x33F80000,即u-boot在把代码拷贝到RAM中去执行的代码段的开始)
???????ldr r1*?测试判断是从Flash启动,还是RAM?;此句执行的结果r1始终是0x33FF80000,因为此值是又编译器指定的(ads中设置,或-D设置编译器参数)
???????cmp?r0*?比较r0和r1,调试的时候不要执行重定位?/
???????beq stack_setup /*?如果r0等于r1,跳过重定位代码?/
???????/*?准备重新定位代码?;以上确定了复位启动代码是在flash中执行的(是系统重启,而不是软复位),就需要把代码拷贝到RAM中去执行,以下为计算即将拷贝的代码的长度
???????ldr r2;前面定义了,就是_start
???????ldr r3;所谓bss段,就是未被初始化的静态变量存放的地方,这个地址是如何的出来的?根据board/smsk2410/u-boot.lds内容?
???????sub?r2?r2 /*?r2 得到armboot的大小?/
???????add?r2*?r2 得到要复制代码的末尾地址?/
copy_loop*?重新定位代码?;开始循环拷贝启动的代码到RAM中
???????ldmia {r3-r10} /*从源地址]复制?;r0指向_start=0)
???????stmia {r3*?复制到目的地址[r1]?;r1指向_TEXT_BASE=0x33F80000*?复制数据块直到源数据末尾地址[r2/
???????ble copy_loop
?;这里附上u-boot各存储区域的映射图,从网上找的,这下对于这几个地址的位置就一目了然了!

?

/* 初始化堆栈等 */
stack_setup:
???????ldr r0,_TEXT_BASE /* 上面是128 KiB重定位的u-boot */
???????sub r0,r0,#CFG_MALLOC_LEN /* 向下是内存分配空间 */????
???????sub r0,#CFG_GBL_DATA_SIZE /* 然后是bdinfo结构体地址空间 */
#ifdef CONFIG_USE_IRQ
???????sub r0,#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif????????;;这些宏定义在/include/configs/smdk2410.h中:
#define CFG_MALLOC_LEN????(CFG_ENV_SIZE + 128*1024)????????;;64K+128K=0xC0
#define CFG_ENV_SIZE????0x10000????????/* Total Size of Environment Sector 64k*/
#define CONFIG_STACKSIZE????(128*1024)????/* regular stack 128k */
#define CFG_GBL_DATA_SIZE???? 128????/* size in bytes reserved for initial data */
用0x33F8000 – 0xC0 – 0x80得到_TEXT_BASE向下(低地址)的堆栈指针sp的起点地址
???????sub sp,#12 /* 为abort-stack预留3个字 */????;;得到最终sp指针初始值
clear_bss:
???????ldr r0,_bss_start /* 找到bss段起始地址 */
???????ldr r1,_bss_end /* bss段末尾地址 */
???????mov r2,#0x00000000 /* 清零 */
clbss_l:str r2,[r0] /* bss段地址空间清零循环... */
???????add r0,#4
???????cmp r0,r1
???????bne clbss_l
???????/* 跳转到start_armboot函数入口,_start_armboot字保存函数入口指针 */
???????ldr pc,_start_armboot
_start_armboot: .word start_armboot ;;start_armboot函数在lib_arm/board.c中实现
?
2.Stage2:lib_arm/board.c
??? 此文件是u-boot Stage2部分,入口为Stage1最后调用的start_armboot函数。注意上面最后ldr到pc的是_start_armboot这个地址,而非start_armboot变量。
??? start_armboot是U-Boot执行的第一个C语言函数,完成系统初始化工作,进入主循环,处理用户输入的命令。
?

void?start_armboot?void)
{
???????DECLARE_GLOBAL_DATA_PTR;
//此宏定义了一个gd_t类型的指针 *gd,并指名用r8寄存器来存储:

#define?DECLARE_GLOBAL_DATA_PTR?register?volatile?gd_t?*gd?asm?"r8")
???????ulong size;
???????init_fnc_t?*init_fnc_ptr;
???????char?*s;
???????/* Pointer is writable since we allocated a register for it ????上面那个宏的作用*/
???????gd?(gd_t(_armboot_start?-?CFG_MALLOC_LEN?sizeof// 此C语句引用的是start.S中的地址标号_armboot_start,但是得到的却是其中所指的变量_start的值(在RAM中,_start = 0x33F80000)。????Ps:????_armboot_start:????.word _start

//gd是全局变量,位置在堆栈区以下(低地址):

typedef?struct?global_data?{
????bd_t?*bdunsigned?long?flagslong?baudratelong?have_console/* serial_init() was called */
????long?reloc_off/* Relocation Offset */????????//此变量有什么用?

????long?env_addr/* Address of Environment struct */
????long?env_valid/* Checksum of Environment valid? */
????long?fb_base/* base address of frame buffer */
ifdef?CONFIG_VFD
????char?vfd_type/* display type */
endif
if?0
????long?cpu_clk/* CPU clock in Hz! */
????long?bus_clklong?ram_size/* RAM size */
????long?reset_status/* reset status register at boot */
endif
????void?*jt/* jump table */
}?gd_t/* compiler optimization barrier needed for GCC >= 3.4 */
???????__asm__?__volatile__"":?:"memory"memset?)gdsizeof?;
???????gd>bd?(bd_tchar)gd?;????//得到bd的起点

???????(gd>bd;
???????monitor_flash_len?=?_bss_start?-?_armboot_start/* 顺序执行init_sequence数组中的初始化函数 */
???????for?(init_fnc_ptr?=?init_sequence;?++init_fnc_ptr{
??????????????if?!{
??????????????????????hang?;
??????????????}
???????}
???????/*配置可用的Flash */
???????size?=?flash_init?;????????//初始化Nor flash的函数,函数实现在下面

???????display_flash_config?(size//打印到控制台:Flash: 512 kB

???????/* _armboot_start 在u-boot.lds链接脚本中定义 */
???????mem_malloc_init?-?CFG_MALLOC_LEN//将CFG_MALLOC_LEN区域用memset函数清零(直接往目的地址写0)

???????/* 配置环境变量,重新定位 */
???????env_relocate?//刚才的初始化函数中有一个是env_init(),根据CRC校验来初始化gd->env_addr变量(自己设定的还是初始值),此函数是作用是将环境变量值从某个flash和RAM之间的拷贝。下图描述了ENV的初始化过程:

?

/* 从环境变量中获取IP地址,放到全局变量gd中 */
???????gd>bi_ip_addr?=?getenv_IPaddr?"ipaddr"/* 以太网接口MAC 地址,放到全局变量gd中,实现过程有待研究*/
??????????{
????????int?i;
????????ulong reg;
????????*e;
????????uchar tmp[64];

????????i?=?getenv_r?"ethaddr"(tmp;
????????s?(i?>?0??tmp?:?NULL;

????????(reg?;?reg?<?6+reg{
????????????gd>bi_enetaddr[reg=?s???simple_strtoul?(s&e:?0;
????????????)
????????????????s???e?+?1?:?e}
????}
???????devices_init?/* 获取列表中的设备 */
???????jumptable_init?;
???????console_init_r?/* 完整地初始化控制台设备 */
???????enable_interrupts?/* 使能例外处理 */
???????/* 通过环境变量初始化 */
???????(s?=?getenv?"loadaddr"{
???????????????load_addr?=?simple_strtoul?}
//以上几个初始化函数有待研究

???????/* main_loop()总是试图自动启动,循环不断执行 */
???????{
???????????????main_loop?/* 主循环函数处理执行用户命令 -- common/main.c */
???????/* NOTREACHED - no way out of command loop except booting */
}

??? 以上总体的浏览了u-boot的启动过程,搞的比较乱,以后有空再修改整理一下,有几个地方还有待弄清,还有Stage2中的多个初始化函数,待续。。。


原文地址http://blog.chinaunix.net/space.php?uid=10696433&do=blog&id=2935725

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读