[A133]uboot启动流程

[A133]uboot启动流程

hongxi.zhu 2024-6-21

1. 第一阶段

lds描述

u-boot.lds中能找到程序的汇编入口ENTRY(_start)

brandy/brandy-2.0/u-boot-2018/u-boot.lds

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
...

ENTRY(_start)的实现在start.S中,根据平台架构, 有对应的实现,当前平台是armv8

_start

brandy/brandy-2.0/u-boot-2018/arch/arm/cpu/armv8/start.S

.globl	_start
_start:
#if defined(LINUX_KERNEL_IMAGE_HEADER)
#include <asm/boot0-linux-kernel-header.h>
#elif defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK)
/*
 * Various SoCs need something special and SoC-specific up front in
 * order to boot, allow them to set that in their boot0.h file and then
 * use it here.
 */
#include <asm/arch/boot0.h>
#else
	b	reset  /* 跳转到reset块 */
#endif

reset

brandy/brandy-2.0/u-boot-2018/arch/arm/cpu/armv8/start.S

reset:
	/* Allow the board to save important registers */
	b	save_boot_params  /*空实现,并跳转回save_boot_params_ret*/
.globl	save_boot_params_ret
save_boot_params_ret:

	/*
	 * Could be EL3/EL2/EL1, Initial State:
	 * Little Endian, MMU Disabled, i/dCache Disabled
	 */
	adr	x0, vectors 	/*将异常向量表基地址写到x0*/
	switch_el x1, 3f, 2f, 1f	/*根据异常等级选择el3/el2/el1情况处理*/
3:	msr	vbar_el3, x0  /*el3*/
	mrs	x0, scr_el3
	orr	x0, x0, #0xf			/* SCR_EL3.NS|IRQ|FIQ|EA */
	msr	scr_el3, x0
	msr	cptr_el3, xzr			/* Enable FP/SIMD */
	b	0f	/*设置完上述相关寄存器,跳出*/
2:	msr	vbar_el2, x0	/*el2*/
	mov	x0, #0x33ff
	msr	cptr_el2, x0			/* Enable FP/SIMD */
	b	0f
1:	msr	vbar_el1, x0	/*el1*/
	mov	x0, #3 << 20
	msr	cpacr_el1, x0			/* Enable FP/SIMD */
0:  /* 空执行,相当于跳出 */


	/* Apply ARM core specific erratas */
	bl	apply_core_errata  /*arm核的特殊配置*/

	/*
	 * Cache/BPB/TLB Invalidate
	 * i-cache is invalidated before enabled in icache_enable()
	 * tlb is invalidated before mmu is enabled in dcache_enable()
	 * d-cache is invalidated before enabled in dcache_enable()
	 */

	/* Processor specific initialization */
	bl	lowlevel_init  /* A133看起来没做啥事情 */

master_cpu:
	bl	_main  /*跳转到_main*/

_main

brandy/brandy-2.0/u-boot-2018/arch/arm/lib/crt0_64.S

ENTRY(_main)

/*
 * Set up initial C runtime environment and call board_init_f(0).
 */
 	/*清除x0寄存器的最低四位(#0xf即二进制1111)并赋值给sp栈指针, x0寄存器的值是调用方传递*/
	bic	sp, x0, #0xf	/* 16-byte alignment for ABI compliance */
	mov	x0, sp		/*将栈指针sp的值写入x0寄存器作为下一条bl命令的参数,这个参数就是global区域的顶部地址top*/
	bl	board_init_f_alloc_reserve		/*跳转到C中的board_init_f_alloc_reserve,给全局gd变量分配内存*/
	mov	sp, x0		/*上面的bl命令执行后,它的返回值存放在x0中,将这个新的栈指针值赋值给sp指针*/
	/* set up gd here, outside any C code */
	mov	x18, x0		/*x18寄存器用作全局数据(Global Data, gd)的指针,上面board_init_f_alloc_reserve的返回值就是需要设置的gd的指针地址*/
	bl	board_init_f_init_reserve	/*跳转到C中的board_init_f_init_reserve, 初始化gd变量的内容为0,并确定后续分配的gd变量内容偏移基地址*/

	mov	x0, #0		/*x0清零,下一个bl命令传入参数值为0*/
	bl	board_init_f		/*跳转到C中的board_init_f初始化一些早期硬件,并为重定位准备*/

#if !defined(CONFIG_SPL_BUILD)
/*
 * 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	x0, [x18, #GD_START_ADDR_SP]	/* x0 <- gd->start_addr_sp */
	bic	sp, x0, #0xf	/* 16-byte alignment for ABI compliance */
	ldr	x18, [x18, #GD_NEW_GD]		/* x18 <- gd->new_gd */

	adr	lr, relocation_return

	/* Add in link-vs-relocation offset */
	ldr	x9, [x18, #GD_RELOC_OFF]	/* x9 <- gd->reloc_off */
	add	lr, lr, x9	/* new return address after relocation */
	ldr	x0, [x18, #GD_RELOCADDR]	/* x0 <- gd->relocaddr */
	b	relocate_code

relocation_return:

/*
 * Set up final (full) environment
 */
	bl	c_runtime_cpu_setup		/* still call old routine */
#endif /* !CONFIG_SPL_BUILD */

/*
 * Clear BSS section
 */
	ldr	x0, =__bss_start		/* this is auto-relocated! */
	ldr	x1, =__bss_end			/* this is auto-relocated! */
clear_loop:
	str	xzr, [x0], #8
	cmp	x0, x1
	b.lo	clear_loop

	/* call board_init_r(gd_t *id, ulong dest_addr) */
	mov	x0, x18				/* gd_t */
	ldr	x1, [x18, #GD_RELOCADDR]	/* dest_addr */
	b	board_init_r			/* PC relative jump */

	/* NOTREACHED - board_init_r() does not return */

ENDPROC(_main)
board_init_f_alloc_reserve

brandy/brandy-2.0/u-boot-2018/common/init/board_init.c

ulong board_init_f_alloc_reserve(ulong top)
{
	...
	/* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
 	// 从global区域分配一块大小为struct global_data大小的16字节对齐的内存存放全局的global_data变量
    // top就是x0寄存器传入的值(具体值需要调试才知道)
	top = rounddown(top-sizeof(struct global_data), 16);

	return top;
}
board_init_f_init_reserve

brandy/brandy-2.0/u-boot-2018/common/init/board_init.c

void board_init_f_init_reserve(ulong base)
{
	struct global_data *gd_ptr;

	/*
	 * clear GD entirely and set it up.
	 * Use gd_ptr, as gd may not be properly set yet.
	 */

	gd_ptr = (struct global_data *)base;  // 拿到寄存器x18里存的gd变量内存地址
	/* zero the area */
	memset(gd_ptr, '\0', sizeof(*gd));  //将这块内存数据,初始化为0
	/* set GD unless architecture did it already */
	...
	/* next alloc will be higher by one GD plus 16-byte alignment */
	base += roundup(sizeof(struct global_data), 16);  //内存向上对齐16字节,这个地址就是gd变量后续分配内容的偏移基地址

	/*
	 * record early malloc arena start.
	 * Use gd as it is now properly set for all architectures.
	 */

	...
}
board_init_f

brandy/brandy-2.0/u-boot-2018/common/board_f.c

void board_init_f(ulong boot_flags)
{
	gd->flags = boot_flags; // 这里汇编传入的x0是0,所以boot_flags = 0
	gd->have_console = 0;

    //执行init_sequence_f数组中的每一个函数指针,会依次初始化cpu/dm/外设总线/串口/optee/等
	if (initcall_run_list(init_sequence_f))
		hang();
}

init_sequence_f数组中特别注意的是下面的函数,将接下来的链接重定位息息相关:

static const init_fnc_t init_sequence_f[] = {
	setup_mon_len, /*设置内存区域长度 gd->mon_len = __bss_end - __image_copy_start;*/
#ifdef CONFIG_OF_CONTROL
	fdtdec_setup, /*设置dtb的地址gd->fdt_blob*/
#endif
#ifdef CONFIG_TRACE_EARLY
	trace_early_init,
#endif
	initf_malloc,  //看起来这里并没有实现f_malloc的区域,也许别的地方实现了
	log_init,
	initf_bootstage,	/* uses its own timer, so does not need DM */
	initf_console_record,
#if defined(CONFIG_HAVE_FSP)
	arch_fsp_init,
#endif
	arch_cpu_init,		/* basic arch cpu dependent setup */
	mach_cpu_init,		/* SoC/machine dependent CPU setup */
	initf_dm,
	arch_cpu_init_dm,
#if defined(CONFIG_BOARD_EARLY_INIT_F)
	board_early_init_f,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_SYS_FSL_CLK) || defined(CONFIG_M68K)
	/* get CPU and bus clocks according to the environment variable */
	get_clocks,		/* get CPU and bus clocks (etc.) */
#endif
#if !defined(CONFIG_M68K)
	timer_init,		/* initialize timer */
#endif
#if defined(CONFIG_BOARD_POSTCLK_INIT)
	board_postclk_init,
#endif
	env_init,		/* initialize environment */  //初始化env驱动
	init_baud_rate,		/* initialze baudrate settings */  //从env读取出设置的串口波特率
	serial_init,		/* serial communications setup */  //初始化串口
	console_init_f,		/* stage 1 init of console */  //从uboot的设备树中获取调试等级debug_mode等
	display_options,	/* say that we are here */  //"打印 U-Boot 2018.07 (xxxx) Allwinner Technology"
	display_text_info,	/* show debugging info if required *///打印bss段的内存起止地址(未初始化全局变量数据段)、text段内存起始地址(代码段)
#if defined(CONFIG_PPC) || defined(CONFIG_SH) || defined(CONFIG_X86)
	checkcpu,
#endif
#if defined(CONFIG_DISPLAY_CPUINFO)
	print_cpuinfo,		/* display cpu info (and speed) */
#endif
#if defined(CONFIG_DTB_RESELECT)
	embedded_dtb_select,
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
	show_board_info,
#endif
	INIT_FUNC_WATCHDOG_INIT
#if defined(CONFIG_MISC_INIT_F)
	misc_init_f,
#endif
	INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_SYS_I2C)
	init_func_i2c,
#endif

#if defined(CONFIG_VID) && !defined(CONFIG_SPL)
	init_func_vid,
#endif
#if defined(CONFIG_HARD_SPI)
	init_func_spi,
#endif
#if defined(CONFIG_OPTEE25)
	smc_init,
#endif

	announce_dram_init,
	dram_init,		/* configure available RAM banks */
#ifdef CONFIG_POST
	post_init_f,
#endif
	INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_SYS_DRAM_TEST)
	testdram,
#endif /* CONFIG_SYS_DRAM_TEST */
	INIT_FUNC_WATCHDOG_RESET

#ifdef CONFIG_POST
	init_post,
#endif
	INIT_FUNC_WATCHDOG_RESET
	/*
	 * Now that we have DRAM mapped and working, we can
	 * relocate the code and continue running from DRAM.
	 *
	 * Reserve memory at end of RAM for (top down in that order):
	 *  - area that won't get touched by U-Boot and Linux (optional)
	 *  - kernel log buffer
	 *  - protected RAM
	 *  - LCD framebuffer
	 *  - monitor code
	 *  - board info struct
	 */
	setup_dest_addr,  //获取内存区域的top地址
#ifdef CONFIG_PRAM
	reserve_pram,
#endif
	reserve_round_4k,  //内存4K对齐
#ifdef CONFIG_ARM
	reserve_mmu,
#endif
	reserve_video,
	reserve_trace,
	reserve_uboot,
	reserve_malloc,
	reserve_board,
	setup_machine,
	reserve_global_data,
	reserve_fdt,
	reserve_bootstage,
	reserve_arch,
	reserve_stacks,
	dram_init_banksize,
	show_dram_config,
#if defined(CONFIG_M68K) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || \
	defined(CONFIG_SH)
	setup_board_part1,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
	INIT_FUNC_WATCHDOG_RESET
	setup_board_part2,
#endif
	display_new_sp,
#ifdef CONFIG_OF_BOARD_FIXUP
	fix_fdt,
#endif
	INIT_FUNC_WATCHDOG_RESET
	reloc_fdt,
	reloc_bootstage,
	setup_reloc,
#if defined(CONFIG_X86) || defined(CONFIG_ARC)
	copy_uboot_to_ram,
	do_elf_reloc_fixups,
	clear_bss,
#endif
#if defined(CONFIG_XTENSA)
	clear_bss,
#endif
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
		!CONFIG_IS_ENABLED(X86_64)
	jump_to_copy,
#endif
	NULL,
};

init_sequence_f数组中特别注意的是下面的函数,将接下来的链接重定位内存结构息息相关

	setup_dest_addr,  //获取内存区域的top地址
	reserve_round_4k,  //内存4K对齐
	reserve_mmu,  //在内存中为MMU TLB页表分配16KB内存
	reserve_video,  //fb相关,这里空实现
	reserve_uboot,  //在内存中为U-Boot text, data & bss段分配790KB内存
	reserve_malloc,  //在内存中为malloc区域预留500MB内存
	reserve_board,  //在内存中为board info预留96 Byte内存
	reserve_global_data,    // 在内存中为global_data预留336 Byte内存
	reserve_fdt,  // 在内存中为fdt 设备树预留149KB内存
	reserve_stacks,  // 为栈空间预留空间(IRQ stack和stack)。sp指针指向的base地址
	dram_init_banksize,  //空实现

相关打印

Ram size: 40000000  // 1GB
Ram top: 80000000  //高地址
TLB table from 7fff0000 to 7fff4000
Reserving 790k for U-Boot at: 7ff2a000
Reserving 512128k for malloc() at: 60b0a000
Reserving 96 Bytes for Board Info at: 60b09fa0
Reserving 336 Bytes for Global Data at: 60b09e50
Reserving 153216 Bytes for FDT at: 60ae47d0
Reserving 8192 Bytes for IRQ stack at: 60ae27c0
New Stack Pointer is: 60ae27b0
[01.588]Relocation Offset is: 35f2a000
Relocating to 7ff2a000, new gd at 60b09e50, sp at 60ae27b0

为即将重定位做的内存分配,此时结构如下

在这里插入图片描述

reloc_fdt

重定位设备树文件

brandy/brandy-2.0/u-boot-2018/common/board_f.c

static int reloc_fdt(void)
{
#ifndef CONFIG_OF_EMBED
	,..
	if (gd->new_fdt) {  //前面的reserved fdt就分配了内存区域
		memcpy(gd->new_fdt, gd->fdt_blob, gd->fdt_size);  //将fdt文件拷贝到内存的新地址中
		gd->fdt_blob = gd->new_fdt;  //修改gd中fdt地址指向
	}
#endif

	return 0;
}
setup_reloc

重定位uboot text&bss&data段到内存中的新地址

brandy/brandy-2.0/u-boot-2018/common/board_f.c

static int setup_reloc(void)
{
	//gd->relocaddr就是前面内存模型中给uboot分配的空间的基地址
    //__image_copy_start是lds文件中描述拷贝uboot的起始地址
	gd->reloc_off = gd->relocaddr - (unsigned long)__image_copy_start;  //重新设置gd中uboot重定位地址偏移

	memcpy(gd->new_gd, (char *)gd, sizeof(gd_t));  //将gd从flash中拷贝内存中的global data区域, 后续都使用new_gd

	tick_printf("Relocation Offset is: %08lx\n", gd->reloc_off);
	debug("Relocating to %08lx, new gd at %08lx, sp at %08lx\n",
	      gd->relocaddr, (ulong)map_to_sysmem(gd->new_gd),
	      gd->start_addr_sp);

	return 0;
}

到这里重定位的准备工作都做完了,board_init_f函数执行结束并返回到_main汇编标签往下执行

/*
 * 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	x0, [x18, #GD_START_ADDR_SP]	/* x0 <- gd->start_addr_sp */
	bic	sp, x0, #0xf	/* 16-byte alignment for ABI compliance */
	ldr	x18, [x18, #GD_NEW_GD]		/* x18 <- gd->new_gd */

	adr	lr, relocation_return

	/* Add in link-vs-relocation offset */
	ldr	x9, [x18, #GD_RELOC_OFF]	/* x9 <- gd->reloc_off */
	add	lr, lr, x9	/* new return address after relocation */
	ldr	x0, [x18, #GD_RELOCADDR]	/* x0 <- gd->relocaddr */
	b	relocate_code

relocation_return:

逐行解析:

ldr	x0, [x18, #GD_START_ADDR_SP]	/* x0 <- gd->start_addr_sp */

使用ARM64的ldr指令从寄存器x18指向的结构体中加载GD_START_ADDR_SP偏移量处的值到寄存器x0。实际上x18是gd的指针。

GD_START_ADDR_SP从下面的汇编到C的map可知是gd->start_addr_sp

a133_linux/brandy/brandy-2.0/u-boot-2018/lib/asm-offsets.c

DEFINE(GD_START_ADDR_SP, offsetof(struct global_data, start_addr_sp));
bic	sp, x0, #0xf	/* 16-byte alignment for ABI compliance */

bic(位清除)指令将x0(即gd->start_addr_sp)的低4位清零,以确保栈指针(sp)是16字节对齐的。这是为了满足ABI的要求

ldr	x18, [x18, #GD_NEW_GD]		/* x18 <- gd->new_gd */

更新x18寄存器,使其指向gd->new_gd。代码重定位后,全局描述符的gd变量指向需要改变

adr	lr, relocation_return

使用adr(地址寄存器)指令获取relocation_return标签的当前地址,并将其存储在链接寄存器(lr)中。这将是代码重定位后的返回地址。

ldr	x9, [x18, #GD_RELOC_OFF]	/* x9 <- gd->reloc_off */

gd(new_gd)结构体中加载GD_RELOC_OFF(可能是重定位偏移量)到x9

add	lr, lr, x9	/* new return address after relocation */

x9(重定位偏移量)加到lr寄存器中,以得到重定位后的最终返回地址

ldr	x0, [x18, #GD_RELOCADDR]	/* x0 <- gd->relocaddr */

gd(new_gd)结构体中加载GD_RELOCADDRx0

b	relocate_code

跳转到relocate_code标签执行,传入的参数为GD_RELOCADDR

relocate_code

/*
 * void relocate_code (addr_moni)
 *
 * This function relocates the monitor code.
 * x0 holds the destination address.
 */
ENTRY(relocate_code)
	stp	x29, x30, [sp, #-32]!	/* create a stack frame */
	mov	x29, sp
	str	x0, [sp, #16]
	/*
	 * Copy u-boot from flash to RAM
	 */
	adr	x1, __image_copy_start	/* x1 <- Run &__image_copy_start */
	subs	x9, x0, x1		/* x8 <- Run to copy offset */
	b.eq	relocate_done		/* skip relocation */
	/*
	 * Don't ldr x1, __image_copy_start here, since if the code is already
	 * running at an address other than it was linked to, that instruction
	 * will load the relocated value of __image_copy_start. To
	 * correctly apply relocations, we need to know the linked value.
	 *
	 * Linked &__image_copy_start, which we know was at
	 * CONFIG_SYS_TEXT_BASE, which is stored in _TEXT_BASE, as a non-
	 * relocated value, since it isn't a symbol reference.
	 */
	ldr	x1, _TEXT_BASE		/* x1 <- Linked &__image_copy_start */
	subs	x9, x0, x1		/* x9 <- Link to copy offset */

	adr	x1, __image_copy_start	/* x1 <- Run &__image_copy_start */
	adr	x2, __image_copy_end	/* x2 <- Run &__image_copy_end */
copy_loop:
	ldp	x10, x11, [x1], #16	/* copy from source address [x1] */
	stp	x10, x11, [x0], #16	/* copy to   target address [x0] */
	cmp	x1, x2			/* until source end address [x2] */
	b.lo	copy_loop
	str	x0, [sp, #24]

	/*
	 * Fix .rela.dyn relocations
	 */
	adr	x2, __rel_dyn_start	/* x2 <- Run &__rel_dyn_start */
	adr	x3, __rel_dyn_end	/* x3 <- Run &__rel_dyn_end */
fixloop:
	ldp	x0, x1, [x2], #16	/* (x0,x1) <- (SRC location, fixup) */
	ldr	x4, [x2], #8		/* x4 <- addend */
	and	x1, x1, #0xffffffff
	cmp	x1, #R_AARCH64_RELATIVE
	bne	fixnext

	/* relative fix: store addend plus offset at dest location */
	add	x0, x0, x9
	add	x4, x4, x9
	str	x4, [x0]
fixnext:
	cmp	x2, x3
	b.lo	fixloop

relocate_done:
	switch_el x1, 3f, 2f, 1f
	bl	hang
3:	mrs	x0, sctlr_el3
	b	0f
2:	mrs	x0, sctlr_el2
	b	0f
1:	mrs	x0, sctlr_el1
0:	tbz	w0, #2, 5f	/* skip flushing cache if disabled */
	tbz	w0, #12, 4f	/* skip invalidating i-cache if disabled */
	ic	iallu		/* i-cache invalidate all */
	isb	sy
4:	ldp	x0, x1, [sp, #16]
	bl	__asm_flush_dcache_range
5:	ldp	x29, x30, [sp],#32
	ret
ENDPROC(relocate_code)

这个的内容比较繁杂涉及复杂的栈操作和链接操作,主要做了两件事:

  • 拷贝flash上面的uboot代码段到内存中
  • 重置链接中的.rela.dyn内容(与重定位相关)

完成重定位后,返回到_main中,进入uboot第二阶段

2. 第二阶段

relocation_return:

/*
 * Set up final (full) environment
 */
	bl	c_runtime_cpu_setup		/* still call old routine */  /*重定向向量表基址寄存器*/
#endif /* !CONFIG_SPL_BUILD */

/*
 * Clear BSS section  重定向后需要清除bss段内容,为接下来运行重定向的uboot做准备
 */
	ldr	x0, =__bss_start		/* this is auto-relocated! */
	ldr	x1, =__bss_end			/* this is auto-relocated! */
clear_loop:
	str	xzr, [x0], #8
	cmp	x0, x1
	b.lo	clear_loop

	/* call board_init_r(gd_t *id, ulong dest_addr) */
	mov	x0, x18				/* gd_t */  /*传递新的gd的地址*/
	ldr	x1, [x18, #GD_RELOCADDR]	/* dest_addr */  /*gd->relocaddr就是重定向后,uboot在内存上运行的入口地址*/
	b	board_init_r			/* PC relative jump */  /*入口函数就是board_init_r函数,且不再返回*/

	/* NOTREACHED - board_init_r() does not return */

ENDPROC(_main)
board_init_r

brandy/brandy-2.0/u-boot-2018/common/board_r.c

void board_init_r(gd_t *new_gd, ulong dest_addr)
{
	gd->flags &= ~GD_FLG_LOG_READY;

	if (initcall_run_list(init_sequence_r))
		hang();

	/* NOTREACHED - run_main_loop() does not return */
	hang();
}
static init_fnc_t init_sequence_r[] = {
	initr_trace,
	initr_reloc,  // 更新fdt的地址到env fdtaddr字段中
	/* TODO: could x86/PPC have this also perhaps? */
#ifdef CONFIG_ARM
	initr_caches,  //配置cpu smp和使能icache和dcache
	/* Note: For Freescale LS2 SoCs, new MMU table is created in DDR.
	 *	 A temporary mapping of IFC high region is since removed,
	 *	 so environmental variables in NOR flash is not available
	 *	 until board_init() is called below to remap IFC to high
	 *	 region.
	 */
#endif
	initr_reloc_global_data,  //更新gd中一些地址偏移,A133这里基本空实现
	initr_barrier,  //空实现
	initr_malloc,  //初始化malloc区域
	log_init,
	initr_bootstage,	/* Needs malloc() but has its own timer */
	initr_console_record,  //空实现
	bootstage_relocate,
#ifdef CONFIG_DM
	initr_dm,  //初始化dm驱动框架
#endif
#if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || defined(CONFIG_RISCV)
	board_init,	/* Setup chipselects */  //全志平台相关的初始化,如CPU/axp Power/rtc/dma等
#endif

	stdio_init_tables,  //stdio相关的配置
	initr_serial,  //串口驱动初始化
	initr_announce,  //打印说明当前uboot是运行在ram中
#ifdef CONFIG_SUNXI_LEDC
	initr_ledc,  // led demo
#endif
	power_init_board,  //空实现
#ifdef CONFIG_MMC
	initr_mmc, //初始化mmc设备驱动,空实现
#endif
	initr_secondary_cpu,  //初始化第二个cpu,一般uboot都是只运行在cpu0上,这里空实现
	stdio_add_devices,  //注册标准输入输出的各种函数,如puts/gets/tstc
	initr_jumptable,  //初始化函数跳转表,例如上面的stdio的这些函数
	console_init_r,		/* fully init console as a device */  //初始化终端输出,可以是串口或者lcd,并映射stdout/stdin/stderr
	interrupt_init,  //空实现
#ifdef CONFIG_ARM
	initr_enable_interrupts,  //空实现
#endif
#ifdef CONFIG_SUNXI_FAST_BURN_KEY
	sunxi_fast_burn_key,  //快速烧key相关功能
#endif
#ifdef CONFIG_ARCH_SUNXI
	  initr_sunxi_plat, //初始化flash相关
#endif
	board_env_late_init,  //获取pmu bootreason和keybox初始化
#ifdef CONFIG_ARCH_SUNXI
	sunxi_burn_key,  //烧key功能
#endif

	run_main_loop,  //进入主循环,引导内核或者进入cli
};

因为uboot相当于重新运行了,所以init_sequence_r中首先需要做各种初始化,最后进入引导linux内核启动流程或者进入cli_loop循坏中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/745309.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AU音频重新混合音频,在 Adobe Audition 中无缝延长背景音乐,无缝缩短BGM

导入音频&#xff0c;选中音频&#xff0c;并且点 New Multitrack Session 的图标 设计文件名和存储路径&#xff0c;然后点 OK 点 Essential Sound 面板点 Music &#xff08;如果没有这个面板 点菜单栏 Windows > Essential Sound 调出来&#xff09; 点 Duration 展…

西门子PLC数据 转 CCLink IE Field Basic项目案例

1 案例说明 设置网关采集西门子PLC数据把采集的数据转成CCLink IE Field Basic协议转发给其他系统。 2 VFBOX网关工作原理 VFBOX网关是协议转换网关&#xff0c;是把一种协议转换成另外一种协议。网关可以采集西门子&#xff0c;欧姆龙&#xff0c;三菱&#xff0c;AB PLC&am…

星戈瑞DSPE-FITC在细胞标记中的应用

细胞标记是生物医学研究中的一项基本技术&#xff0c;它允许研究者追踪和观察细胞的行为、分布以及与周围环境的相互作用。在众多的细胞标记方法中&#xff0c;DSPE-FITC因其独特的性质和应用范围而受关注。 DSPE-FITC的基本性质 DSPE-FITC是由二硬脂酰磷脂酰乙醇胺&#xff0…

海云安参编《数字安全蓝皮书 》正式发布并入选《2024中国数字安全新质百强》荣膺“先行者”

近日&#xff0c;国内数字化产业第三方调研与咨询机构数世咨询正式发布了《2024中国数字安全新质百强》&#xff08;以下简称百强报告&#xff09;。海云安凭借在开发安全领域的技术创新力及市场影响力入选百强报告“新质百强先行者” 本次报告&#xff0c;数世咨询经过对国内8…

文心一言使用笔记

目录 让文心一言提炼已有的内容&#xff0c;模仿给出的案例写一段宣传稿方法例子 发现写出的内容有瑕疵&#xff0c;如何微调&#xff1f;比如文心一言介绍的领导不全如何让文心一言检查语法和表达问题&#xff1f; 如何让文心一言将每个片段用一两句话总结&#xff1f;为了防止…

冰淇淋PDF编辑器,轻量,无需安装,打开即用

​IceCream PDF Editor (冰淇淋PDF编辑器) 是一款简单实用的PDF文件编辑工具。功能包括&#xff1a;编辑文本、注释添加、页面管理、PDF文件保护等&#xff1b;操作简单&#xff0c;功能强大&#xff0c;使用户能够轻松编辑和修改PDF文件。 软件链接&#xff1a;轻量&#xff…

华为OD机试【高矮个子排队】(java)(100分)

1、题目描述 现在有一队小朋友&#xff0c;他们高矮不同&#xff0c;我们以正整数数组表示这一队小朋友的身高&#xff0c;如数组{5,3,1,2,3}。 我们现在希望小朋友排队&#xff0c;以“高”“矮”“高”“矮”顺序排列&#xff0c;每一个“高”位置的小朋友要比相邻的位置高或…

Ollama模型部署工具在Linux平台的部署

1.新建普通用户dmx&#xff08;可选&#xff09; [rootnode3 ~]$ useradd dmx2.切换普通用户dmx环境(可选) [dmxnode3 ~]$ su - dmx3.下载ollama-linux-amd64服务 下载ollama-linux-amd64到 ~/server目录&#xff0c;并将ollama-linux-amd64服务重命名为ollamaEED curl -L …

【仿真】UR机器人手眼标定与实时视觉追踪(单目)

这段代码实现了一个机器人视觉引导系统,主要功能包括: 连接仿真环境,控制UR机器人。相机标定: 使用棋盘格图案进行相机内参标定通过移动机器人采集多组图像使用calibrateCamera函数计算相机内参 手眼标定: 采集机器人末端位姿和对应的棋盘格图像使用calibrateHandEye函数计算相…

Percona Toolkit 神器全攻略(配置类)

Percona Toolkit 神器全攻略&#xff08;配置类&#xff09; Percona Toolkit 神器全攻略系列共八篇&#xff0c;前文回顾&#xff1a; 前文回顾Percona Toolkit 神器全攻略Percona Toolkit 神器全攻略&#xff08;实用类&#xff09; 全文约定&#xff1a;$为命令提示符、gr…

51-61 CVPR 2024 最佳论文 | Rich Human Feedback for Text-to-Image Generation

23年12月&#xff0c;加州大学圣地亚哥、谷歌研究院、南加州大学、剑桥大学联合发布Rich Human Feedback for Text-to-Image Generation论文。 作者受大模型中RLHF技术的启发&#xff0c;用人类反馈来改进Stable Diffusion等文生图模型&#xff0c;提出了先进的RichHF-18K数据…

批归一化(Batch Normalization)和层归一化(Layer Normalization)的作用

在深度学习领域&#xff0c;归一化技术被广泛用于加速神经网络的训练速度并提高其稳定性。本文将介绍两种常见的归一化方法&#xff1a;批归一化&#xff08;Batch Normalization, BN&#xff09;和层归一化&#xff08;Layer Normalization, LN&#xff09;&#xff0c;并通过…

在虚拟机中安装centos系统,及通过安装包安装jdk1.8,mysql5.7,redis7.2

在虚拟机中安装centos系统&#xff0c;及通过安装包安装jdk1.8,mysql5.7,redis7.2 第一章 CentOS7的下载1.1.使用阿里云开源镜像站下载。 第二章 CentOS7的配置2.1.通过VMware 创建一个CentOS7虚拟机2.1.1.打开软件&#xff0c;点击如箭头所示按钮&#xff0c;创建虚拟机2.1.2.…

【建设方案】智慧园区大数据云平台建设方案(DOC原件)

大数据云平台建设技术要点主要包括以下几个方面&#xff1a; 云计算平台选择&#xff1a;选择安全性高、效率性强、成本可控的云计算平台&#xff0c;如阿里云、腾讯云等&#xff0c;确保大数据处理的基础环境稳定可靠。 数据存储与管理&#xff1a;利用Hadoop、HBase等分布式…

全球最快的 JSON 文件查询工具

本文字数&#xff1a;1684&#xff1b;估计阅读时间&#xff1a;5分钟 审校&#xff1a;庄晓东&#xff08;魏庄&#xff09; 本文在公众号【ClickHouseInc】首发 介绍 在 ClickHouse&#xff0c;我们热衷于基准测试和性能优化。所以当我第一次看到 Hacker News 上那篇“查询大…

aspectj:AOP编程备忘录-切面定义的注意事项

AOP编程时定义切面时需要注意的事 Around 以Around注解拦截构造方法(Constructor)时切面定义只能用call方式而不能是execution&#xff0c;否则 ProceedingJoinPoint.proceed()返回的是null&#xff0c;得不到构造的实例。 execution execution切入点要修改对象内部&#x…

惊!两个样本的简单分组实验登上了园艺学顶级期刊

在真核细胞中&#xff0c;基因组DNA被包装成高度组织化的核蛋白复合体&#xff0c;称为染色质。染色质的基本单元是核小体&#xff0c;它由一个核心组蛋白八聚体&#xff08;组蛋白H2A、H2B、H3和H4各两个&#xff09;组成&#xff0c;其周围缠绕着大约146个碱基对的DNA。这些组…

汇编语言作业(九)

目录 一、实验目的 二、实验内容 三&#xff0e;实验步骤以及结果 1. 从键盘缓冲区中接受一个英文字符串&#xff08;长度<50), 如“AB123cdE*87fGabFZ”&#xff0c;要求将其大写转小写&#xff0c;小写转大写后存入以result地址开始的缓冲区中&#xff0c;并输出。 2…

无线WiFi毫米波雷达传感器成品,智能照明人体感应开关,飞睿智能点亮智慧生活

在智能科技飞速发展的今天&#xff0c;我们的生活正被各种智能设备所包围&#xff0c;其中智能照明作为智能家居的重要组成部分&#xff0c;正逐渐改变着我们的生活方式。而在这背后&#xff0c;有一个默默工作的“小助手”——飞睿智能毫米波雷达传感器&#xff0c;它就像智能…

kettle创建资源库无法登录问题

问题&#xff1a;You dont seem to be getting a connection to the server. Please check the path youre using and make sure the server is up and running. 1. 删除资源库 2.删除数据库中R_开头的表 3.重新创建资源库连接&#xff0c;查看是否成功产生表 4.创建成功&…