[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>
#elseb	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_el3orr	x0, x0, #0xf			/* SCR_EL3.NS|IRQ|FIQ|EA */msr	scr_el3, x0msr	cptr_el3, xzr			/* Enable FP/SIMD */b	0f	/*設置完上述相關寄存器,跳出*/
2:	msr	vbar_el2, x0	/*el2*/mov	x0, #0x33ffmsr	cptr_el2, x0			/* Enable FP/SIMD */b	0f
1:	msr	vbar_el1, x0	/*el1*/mov	x0, #3 << 20msr	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_coderelocation_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], #8cmp	x0, x1b.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 = 0gd->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_CONTROLfdtdec_setup, /*設置dtb的地址gd->fdt_blob*/
#endif
#ifdef CONFIG_TRACE_EARLYtrace_early_init,
#endifinitf_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,
#endifarch_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,
#endifenv_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,
#endifINIT_FUNC_WATCHDOG_INIT
#if defined(CONFIG_MISC_INIT_F)misc_init_f,
#endifINIT_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,
#endifannounce_dram_init,dram_init,		/* configure available RAM banks */
#ifdef CONFIG_POSTpost_init_f,
#endifINIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_SYS_DRAM_TEST)testdram,
#endif /* CONFIG_SYS_DRAM_TEST */INIT_FUNC_WATCHDOG_RESET#ifdef CONFIG_POSTinit_post,
#endifINIT_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_PRAMreserve_pram,
#endifreserve_round_4k,  //內存4K對齊
#ifdef CONFIG_ARMreserve_mmu,
#endifreserve_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_RESETsetup_board_part2,
#endifdisplay_new_sp,
#ifdef CONFIG_OF_BOARD_FIXUPfix_fdt,
#endifINIT_FUNC_WATCHDOG_RESETreloc_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,
#endifNULL,
};

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地址指向}
#endifreturn 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_gdtick_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_coderelocation_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, spstr	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_loopstr	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, #0xffffffffcmp	x1, #R_AARCH64_RELATIVEbne	fixnext/* relative fix: store addend plus offset at dest location */add	x0, x0, x9add	x4, x4, x9str	x4, [x0]
fixnext:cmp	x2, x3b.lo	fixlooprelocate_done:switch_el x1, 3f, 2f, 1fbl	hang
3:	mrs	x0, sctlr_el3b	0f
2:	mrs	x0, sctlr_el2b	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],#32ret
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], #8cmp	x0, x1b.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_ARMinitr_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.*/
#endifinitr_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_DMinitr_dm,  //初始化dm驅動框架
#endif
#if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || defined(CONFIG_RISCV)board_init,	/* Setup chipselects */  //全志平臺相關的初始化,如CPU/axp Power/rtc/dma等
#endifstdio_init_tables,  //stdio相關的配置initr_serial,  //串口驅動初始化initr_announce,  //打印說明當前uboot是運行在ram中
#ifdef CONFIG_SUNXI_LEDCinitr_ledc,  // led demo
#endifpower_init_board,  //空實現
#ifdef CONFIG_MMCinitr_mmc, //初始化mmc設備驅動,空實現
#endifinitr_secondary_cpu,  //初始化第二個cpu,一般uboot都是只運行在cpu0上,這里空實現stdio_add_devices,  //注冊標準輸入輸出的各種函數,如puts/gets/tstcinitr_jumptable,  //初始化函數跳轉表,例如上面的stdio的這些函數console_init_r,		/* fully init console as a device */  //初始化終端輸出,可以是串口或者lcd,并映射stdout/stdin/stderrinterrupt_init,  //空實現
#ifdef CONFIG_ARMinitr_enable_interrupts,  //空實現
#endif
#ifdef CONFIG_SUNXI_FAST_BURN_KEYsunxi_fast_burn_key,  //快速燒key相關功能
#endif
#ifdef CONFIG_ARCH_SUNXIinitr_sunxi_plat, //初始化flash相關
#endifboard_env_late_init,  //獲取pmu bootreason和keybox初始化
#ifdef CONFIG_ARCH_SUNXIsunxi_burn_key,  //燒key功能
#endifrun_main_loop,  //進入主循環,引導內核或者進入cli
};

因為uboot相當于重新運行了,所以init_sequence_r中首先需要做各種初始化,最后進入引導linux內核啟動流程或者進入cli_loop循壞中。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/35990.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/35990.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/35990.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring Boot中的異步編程技巧

Spring Boot中的異步編程技巧 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01;今天我們將探討在Spring Boot應用程序中如何使用異步編程技巧&#xff0c;以提升性…

LeetCode題練習與總結:單詞拆分--139

一、題目描述 給你一個字符串 s 和一個字符串列表 wordDict 作為字典。如果可以利用字典中出現的一個或多個單詞拼接出 s 則返回 true。 注意&#xff1a;不要求字典中出現的單詞全部都使用&#xff0c;并且字典中的單詞可以重復使用。 示例 1&#xff1a; 輸入: s "l…

vant組件 頂部下拉刷新和頁面底部下拉獲取數據+頂部搜索框

1.html部分&#xff08;頂部tab切換無&#xff0c;只有主體list部分&#xff09; <div class"yd" ><!-- yd端 --><!-- 搜索框 --><van-searchv-model"ydsearchvalue"show-actionplaceholder"請輸入搜索關鍵詞"search"…

JavaEE之HTTP協議(1)_HTTP基礎知識,HTTP 請求、響應格式,方法,狀態碼

一、HTTP協議 1.1 基本概念: HTTP全稱超文本傳輸協議&#xff0c;是一種無狀態的、應用層的協議&#xff0c;它基于請求/響應模型。客戶端&#xff08;通常是Web瀏覽器&#xff09;通過發送HTTP請求到服務器來獲取或發送信息&#xff0c;服務器則返回HTTP響應作為回應。HTTP協…

shell (三)shell腳本

SHELL腳本 編程語言的分類 解釋型語言&#xff1a;shell&#xff0c;Python&#xff0c;需要解析器 編譯型語言&#xff1a;C語言&#xff0c;C&#xff0c;需要編譯器 shell腳本 操作系統的結構 shell&#xff08;貝殼&#xff09; 應用層 app&#xff0c;代碼 應用層需要通…

2024年軟件測試面試題大全【答案+文檔】

&#x1f345; 視頻學習&#xff1a;文末有免費的配套視頻可觀看 &#x1f345; 點擊文末小卡片&#xff0c;免費獲取軟件測試全套資料&#xff0c;資料在手&#xff0c;漲薪更快 一、面試基礎題 簡述測試流程&#xff1a; 1、閱讀相關技術文檔&#xff08;如產品PRD、UI設計…

1、線性回歸模型

1、主要解決問題類型 1.1 預測分析(Prediction) 線性回歸可以用來預測一個變量(通常稱為因變量或響應變量)的值,基于一個或多個輸入變量(自變量或預測變量)。例如,根據房屋的面積、位置等因素預測房價。 1.2 異常檢測(Outlier Detection) 線性回歸可以幫助識別數…

鴻蒙開發系統基礎能力:【@ohos.systemTime (設置系統時間)】

設置系統時間 本模塊用來設置、獲取當前系統時間&#xff0c;設置、獲取當前系統日期和設置、獲取當前系統時區。 說明&#xff1a; 本模塊首批接口從API version 7開始支持。后續版本的新增接口&#xff0c;采用上角標單獨標記接口的起始版本。 導入模塊 import systemTime …

沙盒在數據防泄密領域意義

在信息化快速發展的今天&#xff0c;數據已成為企業最寶貴的資產之一。然而&#xff0c;數據泄密事件頻發&#xff0c;給企業的安全和發展帶來了巨大威脅。SDC沙盒防泄密系統&#xff0c;作為一種創新的數據防泄密解決方案&#xff0c;正逐漸在數據防泄密領域發揮著越來越重要的…

理解和使用JavaScript的閉包

閉包 在前端開發中&#xff0c;JavaScript是一種非常重要的編程語言。它的靈活性和強大功能使得開發者可以創建豐富的用戶體驗。然而&#xff0c;JavaScript中有些概念對于初學者來說可能比較難以理解&#xff0c;閉包就是其中之一。本文將深入探討JavaScript中的閉包&#xf…

安裝zabbix時報錯Could not resolve host: mirrors.huaweicloud.com;Unknown error解決辦法

目錄 1、問題原因 2、解決辦法 3、知識拓展 DNS的區別 DNS配置文件解析 域名解析過程 4、書籍推薦 當安裝Zabbix server&#xff0c;Web前端&#xff0c;agent時出現&#xff1a; [rootsc-zabbix-server ~]# yum install zabbix-server-mysql zabbix-agent安裝過程中會出…

Python3極簡教程(一小時學完)上

開始 Python 之旅 本教程基于 Python for you and me 教程翻譯制作&#xff0c;其中參考了 Python tutorial 和 _The Python Standard Library_&#xff0c;并對原教程的內容進行了改進與補充。 相關鏈接地址如下&#xff1a; _Python tutorial_&#xff1a;Python 入門指南…

數字孿生流域:定義、組成等

數字孿生流域&#xff1a;定義、組成等 1 數字孿生流域&#xff08;Digital Twin Basin/Watershed&#xff09;總則1.1 定義1.2 適用范圍1.3 建設目標1.4 建設原則 2 數字孿生流域框架與組成2.1 數字孿生流域框架2.2 數字孿生流域組成2.2.1 數字孿生平臺2.2.2 信息化基礎設施 3…

類的裝飾器

1 使用類定義裝飾器 class Person(object):def __init__(self):self._age 0propertydef age(self):return self._ageage.setterdef age(self,newValue):print(觸發了嗎)self._age newValuep Person() print(p.age) # 0 p.age 20 print(p.age) # 20 2 類屬性 class Pe…

JavaScript學習筆記(二)

12、數字 常規用法和java的用法相似&#xff0c;就不再做詳細的記錄, JavaScript 數字 以下只記錄特殊用法&#xff1a; 12.1 數字字符串運算 在所有數字運算中&#xff0c;JavaScript 會嘗試將字符串轉換為數字&#xff1a; var x "100"; var y "10"…

探索QCS6490目標檢測AI應用開發(一):Yolov8n模型轉換及量化

目標檢測&#xff08;Object Detection&#xff09;是計算機視覺領域的核心任務之一&#xff0c;它旨在識別圖像中的物體并確定其位置&#xff0c;在本期的文章中&#xff0c;我們用一個端到端的目標檢測AI應用為例子。介紹如何在QCS6490 Ubuntu系統上實現一個目標檢測應用開發…

第 5 章理解 ScrollView 并構建 Carousel UI

通過上一章的學習,我相信你現在應該明白如何使用堆棧構建復雜的 UI。當然,在你掌握 SwiftUI 之前,你還需要大量的練習。因此,在深入研究 ScrollView 以使視圖可滾動之前,讓我們先以一個挑戰開始本章。你的任務是創建一個類似于圖 1 所示的卡片視圖。 …

如何遷移R包

遷移R包涉及將一個或多個R包從一個系統轉移到另一個系統。以下是遷移R包的詳細步驟&#xff1a; 1. 確定要遷移的R包 首先&#xff0c;列出你在當前系統中安裝的所有R包&#xff0c;或僅列出你需要遷移的R包。你可以使用以下代碼列出所有安裝的R包&#xff1a; installed_pa…

swp添加池子addLiquidity失敗

案發現場 首次添加交易對、一直失敗、但是也沒提示具體的原因。到這一步就沒了、由下圖可知、也沒看到log、由此可見第一步就失敗了。 解決方案 一、添加 工廠KywFactory 添加如下 bytes32 public constant INIT_CODE_PAIR_HASH keccak256(abi.encodePacked(type(KywPair…

移植對話框MFC

VC版 MFC程序對話框資源移植 以下均拷貝自上面&#xff0c;僅用來記錄 &#xff08;部分有刪除&#xff09; 法1&#xff1a; Eg&#xff1a;將B工程調試好的對話框移植到A工程中 1.資源移植 1.1 在2017打開B工程,在工作區Resource標簽頁中選中Dialog文件夾下的資源文件,按…