IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> imx6ull u-boot启动流程分析 -> 正文阅读

[嵌入式]imx6ull u-boot启动流程分析

一、程序入口

程序的链接由链接脚本决定的,所以可以通过u-boot.lds 来找到uboot的入口。
在这里插入图片描述

从上图可以看出入口为_start,该标签在vector.S中(\arch\arm\lib\vectors.S)

        .macro ARM_VECTORS
	b	reset
	ldr	pc, _undefined_instruction
	ldr	pc, _software_interrupt
	ldr	pc, _prefetch_abort
	ldr	pc, _data_abort
	ldr	pc, _not_used
	ldr	pc, _irq
	ldr	pc, _fiq
	.endm
	
.globl _start
.section ".vectors", "ax"
_start:
	ARM_VECTORS
    .globl	_undefined_instruction
    .globl	_software_interrupt
    .globl	_prefetch_abort
    .globl	_data_abort
    .globl	_not_used
    .globl	_irq
    .globl	_fiq
_undefined_instruction:	.word undefined_instruction
_software_interrupt:	.word software_interrupt
_prefetch_abort:	.word prefetch_abort
_data_abort:		.word data_abort
_not_used:		.word not_used
_irq:			.word irq
_fiq:			.word fiq
.balignl 16,0xdeadbeef

所以,设备一上电开始执行reset函数。

reset:
	/* Allow the board to save important registers */
	b	save_boot_params
save_boot_params_ret:
	//disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,except if in HYP mode already
	mrs	r0, cpsr
	and	r1, r0, #0x1f		@ mask mode bits
	teq	r1, #0x1a		@ test for HYP mode
	bicne	r0, r0, #0x1f		@ clear all mode bits
	orrne	r0, r0, #0x13		@ set SVC mode
	orr	r0, r0, #0xc0		@ disable FIQ and IRQ
	msr	cpsr,r0
	#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
	/* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */
	mrc	p15, 0, r0, c1, c0, 0	@ Read CP15 SCTLR Register
	bic	r0, #CR_V		@ V = 0
	mcr	p15, 0, r0, c1, c0, 0	@ Write CP15 SCTLR Register
	/* Set vector address in CP15 VBAR register */
	ldr	r0, =_start
	mcr	p15, 0, r0, c12, c0, 0	@Set VBAR
#endif

	/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
	bl	cpu_init_cp15
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
	bl	cpu_init_crit
#endif
#endif
	bl	_main

save_boot_params 没干啥事,直接跳转到save_boot_params_ret。然后关FIQ、IRQ中断,并且设置cpu到SVC32模式。设置中断向量地址寄存器的值为_start地址。

cpu_init_cp15主要设置CP15寄存器,涉及cache、MMU、TLBS。

cpu_init_crit :直接调用lowlevel_init

.pushsection .text.lowlevel_init, "ax"
WEAK(lowlevel_init)
	//Setup a temporary stack. Global data is not available yet.
	ldr	sp, =CONFIG_SYS_INIT_SP_ADDR  //SP=0x0091ff00
	bic	sp, sp, #7 /* 8-byte alignment for ABI compliance */
	
    //Set up global data for boards that still need it. This will be removed soon.
	sub	sp, sp, #GD_SIZE  //DEFINE(GD_SIZE, sizeof(struct global_data)); 256个字节
	bic	sp, sp, #7
	mov	r9, sp
	
	//Save the old lr(passed in ip) and the current lr to stack
	push	{ip, lr}

	 /* Call the very early init function. This should do only the absolute bare minimum to get started. It 			should not:- set up DRAM  - use global_data  - clear BSS  - try to start a console
	 * For boards with SPL this should be empty since SPL can do all of this init in the SPL board_init_f()       function which is called immediately after this.*/
	bl	s_init //最早的初始化,对于mx6ull是个空函数。
	pop	{ip, pc}
ENDPROC(lowlevel_init)

_main 重点函数:

ENTRY(_main)
	//Set up initial C runtime environment and call board_init_f(0).
	ldr	r0, =(CONFIG_SYS_INIT_SP_ADDR)  //0x0091ff00
	bic	r0, r0, #7	/* 8-byte alignment for ABI compliance */
	mov	sp, r0
	bl	board_init_f_alloc_reserve  //保留SYS_MALLOC_F_LEN 和GDsize空间
	mov	sp, r0
	/* set up gd here, outside any C code */
	mov	r9, r0
	bl	board_init_f_init_reserve // global_data 清零,设置gd->malloc_base

	mov	r0, #0
	bl	board_init_f

//Set up intermediate environment (new sp and gd) and call relocate_code(addr_moni). Trick here is that we'll return
//'here' but relocated.

	ldr	r0, [r9, #GD_START_ADDR_SP]	/* sp = gd->start_addr_sp */
	bic	r0, r0, #7	/* 8-byte alignment for ABI compliance */
	mov	sp, r0
	ldr	r9, [r9, #GD_BD]		/* r9 = gd->bd */
	sub	r9, r9, #GD_SIZE		/* new GD is below bd */

	adr	lr, here
	ldr	r0, [r9, #GD_RELOC_OFF]		/* r0 = gd->reloc_off */
	add	lr, lr, r0

	ldr	r0, [r9, #GD_RELOCADDR]		/* r0 = gd->relocaddr */
	b	relocate_code
here:
	bl	relocate_vectors
	bl	c_runtime_cpu_setup	/关I-cache */
//清bss段
	ldr	r0, =__bss_start	/* this is auto-relocated! */
	ldr	r3, =__bss_end		/* this is auto-relocated! */
	mov	r1, #0x00000000		/* prepare zero to clear BSS */
	subs	r2, r3, r0		/* r2 = memset len */
	bl	memset

	bl coloured_LED_init  //空函数
	bl red_led_on         //空函数

	/* call board_init_r(gd_t *id, ulong dest_addr) */
	mov     r0, r9                  /* gd_t */
	ldr	r1, [r9, #GD_RELOCADDR]	/* dest_addr */
	ldr	pc, =board_init_r	/* this is auto-relocated! */
	
ENDPROC(_main)

board_init_f:调用一系列 initcall_run_list(init_sequence_f)如下:

setup_mon_len:设置uboot镜像大小gd->mon_len

fdtdec_setup:设置 gd->fdt_blob

__weak void *board_fdt_blob_setup(void)
{
	void *fdt_blob = NULL;
	/* FDT is at end of image */
	fdt_blob = (ulong *)&_end;
	return fdt_blob;
}
设置dtb地址为&_end
gd->fdt_blob = board_fdt_blob_setup();
/* Allow the early environment to override the fdt address */
gd->fdt_blob = (void *)env_get_ulong("fdtcontroladdr", 16,(uintptr_t)gd->fdt_blob);
return fdtdec_prepare_fdt();
fdtdec_prepare_fdt():校验dtb的头部信息。

trace_early_init: 设置早期的缓冲区

initf_malloc: 设置gd->malloc_limit= SYS_MALLOC_F_LEN和 gd->malloc_ptr=0

log_init:如果有LOG_DRIVER创建log_device

initf_bootstage:空函数。

initf_console_record:空函数

arch_cpu_init: basic arch cpu dependent setup

mach_cpu_init:空函数

initf_dm:驱动模型 非dtb的初始化

initf_dm(void)
	--->dm_init_and_scan(true);
{
	ret = dm_init(IS_ENABLED(CONFIG_OF_LIVE));
	{
		INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST);//#define DM_UCLASS_ROOT_NON_CONST  (((gd_t *)gd)->uclass_root)
		ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
		{
			struct driver *drv;
			//在.u_boot_list_2_driver_1r段中查找info->name的struct drive
			drv = lists_driver_lookup_name(info->name);
			#if CONFIG_IS_ENABLED(OF_PLATDATA) //使用dtb则要设置平台数据大小
 			platdata_size = info->platdata_size;
			#endif
			return device_bind_common(parent, drv, info->name, (void *)info->platdata, 0, ofnode_null(), platdata_size,devp);
		}
		ret = device_probe(DM_ROOT_NON_CONST); //#define DM_ROOT_NON_CONST (((gd_t *)gd)->dm_root)
	}
	ret = dm_scan_platdata(pre_reloc_only);
	ret = dm_extended_scan_fdt(gd->fdt_blob, pre_reloc_only);
	ret = dm_scan_other(pre_reloc_only);
}

arch_cpu_init_dm:空函数

board_early_init_f:setup_iomux_uart

get_clocks:获取gd->arch.sdhc_clk

timer_init: 初始化A7内核定时器,为uboot提供时间基准

int timer_init(void)
{
	struct sctr_regs *sctr = (struct sctr_regs *)SCTR_BASE_ADDR;
	unsigned long val, freq;
	freq = CONFIG_SC_TIMER_CLK;
	asm volatile("mcr p15, 0, %0, c14, c0, 0" : : "r" (freq));
	writel(freq, &sctr->cntfid0);
	/* Enable system counter */
	val = readl(&sctr->cntcr);
	val &= ~(SC_CNTCR_FREQ0 | SC_CNTCR_FREQ1);
	val |= SC_CNTCR_FREQ0 | SC_CNTCR_ENABLE | SC_CNTCR_HDBG;
	writel(val, &sctr->cntcr);
	gd->arch.tbl = 0;
	gd->arch.tbu = 0;
	return 0;
}

board_postclk_init:设置ldo 电压

env_init: 获取 gd->env_addr 、gd->env_valid

init_baud_rate:从环境变量中获取波特率并设置到gd->baudrate。

console_init_f:stage 1 init of console

display_options:打印版本相关内容

display_text_info:打印U-Boot code的 bss_start、bss_end

print_cpuinfo: 打印cpu相关信息

show_board_info:获取dtb文件model属性的值,打印Model: Freescale i.MX6 ULL 14x14 EVK Board Board: MX6ULL 14x14 EVK

init_func_i2c:iic相关初始化

init_func_spi:spi相关初始化

announce_dram_init: puts("DRAM: ");

dram_init: gd->ram_size = imx_ddr_size();

setup_dest_addr:设置gd->ram_size=0x20000000 gd->ram_top= 0x80000000+ gd->ram_size =A0000000 gd->relocaddr = gd->ram_top

reserve_round_4k: gd->relocaddr &= ~(4096 - 1); 4k对齐

reserve_mmu:设置:gd->arch.tlb_size=0x4000;gd->relocaddr -= gd->arch.tlb_size; gd->relocaddr &= ~(0x10000 - 1); gd->arch.tlb_addr = gd->relocaddr=9fff0000;

reserve_video:该版本未使用

reserve_trace:该版本未使用

reserve_uboot: gd->relocaddr -= gd->mon_len; gd->relocaddr &= ~(4096 - 1); gd->start_addr_sp = gd->relocaddr=9ff24000;

reserve_malloc: gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN =9ef22000;

reserve_board: gd->start_addr_sp -= sizeof(bd_t)=9ef21fb0; gd->bd = (bd_t *)map_sysmem(gd->start_addr_sp, sizeof(bd_t));

setup_machine:新框架已经废弃

reserve_global_data:gd->start_addr_sp -= sizeof(gd_t)=9ef21eb0; gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t));

reserve_fdt: gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32)=0x39200;

	gd->start_addr_sp -= gd->fdt_size =9ef18590;
	gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);

reserve_bootstage:该版本未使用

reserve_arch:该版本未使用

reserve_stacks:做gd->start_addr_sp 16字节对齐,然后留出16字节给abor-stack;得到gd->start_addr_sp=9ef33530

dram_init_banksize:

gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
gd->bd->bi_dram[0].size = get_effective_memsize();

show_dram_config: 打印RAM 配置 和DRAM大小,日志如下:

RAM Configuration:
Bank #0: 80000000 512 MiB

DRAM:  512 MiB

display_new_sp: 打印gd->start_addr_sp :9ef18570

INIT_FUNC_WATCHDOG_RESET 复位看门狗

reloc_fdt:重定位fdt

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

reloc_bootstage:该版本未使用

setup_reloc:设置gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE= 18724000; 拷贝gd 到gd->new_gd

relocate_code :

拷贝代码到gd->relocaddr 处, 同时需要将记录相对位置调用关系的__rel_dyn段里面的内容加上gd->reloc_off写到gd->relocaddr 处,防止代码位置变动了,不能正确调用函数、全局变量等。

relocate_vectors:

将新的中断向量表地址写到vbar寄存器里面即可

ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr /
mcr p15, 0, r0, c12, c0, 0 /
Set VBAR */

c_runtime_cpu_setup: 关闭 I-cache

board_init_r:函数调用init_sequence_r里面每个函数。

initr_trace: 空函数

initr_reloc:标记重定位完成 gd->flags |= GD_FLG_RELOC | GD_FLG_FULL_MALLOC_INIT;

initr_caches: 使能caches

initr_reloc_global_data:

monitor_flash_len = _end - __image_copy_start;
efi_runtime_relocate(gd->relocaddr, NULL);

initr_barrier:空函数

initr_malloc:初始化malloc区域,malloc区域为紧挨着镜像文件下面malloc_start = gd->relocaddr - TOTAL_MALLOC_LEN; mem_malloc_init((ulong)map_sysmem(malloc_start, TOTAL_MALLOC_LEN), TOTAL_MALLOC_LEN);

log_init:日志相关初始化。

initr_bootstage:空函数

initr_console_record :空函数

bootstage_relocate:空函数

initr_dm: dm相关初始化

board_init:板级初始化,包括 74XX 芯片,I2C、FEC、USB 和 QSPI 等

/* Address of boot parameters */
gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1);
setup_fec(CONFIG_FEC_ENET_DEV);
board_qspi_init();
setup_gpmi_nand();
return 0;

efi_memory_init:内存相关初始化

stdio_init_tables:stdio初始化

initr_serial:串口初始化

initr_announce: debug(“Now running in RAM - U-Boot at: %08lx\n”, gd->relocaddr);

INIT_FUNC_WATCHDOG_RESET:看门狗复位

power_init_board:初始化电源芯片

initr_mmc:emmc初始化

initr_env:初始化环境变量

initr_secondary_cpu:初始化其他cpu核。

stdio_add_devices:各种输入输出设备的初始化。

initr_jumptable:gd->jt = malloc(sizeof(struct jt_funcs));

console_init_r:fully init console as a device

show_board_info:

model = fdt_getprop(gd->fdt_blob, 0, "model", NULL);
printf("Model: %s\n", model);
return checkboard();

interrupt_init:初始化中断

initr_enable_interrupts:使能中断

timer_init:时钟初始化

initr_ethaddr:初始化网络地址,也就是获取 MAC 地址。读取环境变量“ethaddr”的值。

board_late_init:,板子后续初始化,

initr_fastboot_setup:

initr_net:初始化eth 复位phy

initr_check_fastboot

run_main_loop:

uboot 启动以后会进入 3 秒倒计时,如果在 3 秒倒计时结束之前按下按下回车键,那么就

会进入 uboot 的命令模式,如果倒计时结束以后都没有按下回车键,那么就会自动启动 Linux 内

核 , 这 个 功 能 就 是 由 run_main_loop 函 数 来 完 成 的 。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-03 12:04:50  更:2021-09-03 12:05:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/29 9:15:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计