uboot流程——uboot启动流程

2024-08-30 17:38
文章标签 uboot 流程 启动

本文主要是介绍uboot流程——uboot启动流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

[uboot] (第五章)uboot流程——uboot启动流程

以下例子都以project X项目tiny210(s5pv210平台,armv7架构)为例

[uboot] uboot流程系列: 
[project X] tiny210(s5pv210)上电启动流程(BL0-BL2) 
[project X] tiny210(s5pv210)从存储设备加载代码到DDR 
[uboot] (第一章)uboot流程——概述 
[uboot] (第二章)uboot流程——uboot-spl编译流程 
[uboot] (第三章)uboot流程——uboot-spl代码流程 
[uboot] (第四章)uboot流程——uboot编译流程 
[uboot] (番外篇)global_data介绍 
[uboot] (番外篇)uboot relocation介绍

建议先看《[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)》,根据例子了解一下上电之后的BL0\BL1\BL2阶段,以及各个阶段的运行位置,功能。 
建议可以和《[uboot] (番外篇)global_data介绍》和《[uboot] (番外篇)uboot relocation介绍》结合起来看。

=================================================================================

一、uboot说明

1、uboot要做的事情

CPU初始刚上电的状态。需要小心的设置好很多状态,包括cpu状态、中断状态、MMU状态等等。其次,就是要根据硬件资源进行板级的初始化,代码重定向等等。最后,就是进入命令行状态,等待处理命令。 
在armv7架构的uboot,主要需要做如下事情

  • arch级的初始化

    • 关闭中断,设置svc模式
    • 禁用MMU、TLB
    • 关键寄存器的设置,包括时钟、看门狗的寄存器
  • 板级的初始化

    • 堆栈环境的设置
    • 代码重定向之前的板级初始化,包括串口、定时器、环境变量、I2C\SPI等等的初始化
    • 进行代码重定向
    • 代码重定向之后的板级初始化,包括板级代码中定义的初始化操作、emmc、nand flash、网络、中断等等的初始化。
    • 进入命令行状态,等待终端输入命令以及对命令进行处理

上述工作,也就是uboot流程的核心。

2、疑问

  • 在前面的文章中虽然已经说明了,在spl的阶段中已经对arch级进行了初始化了,为什么uboot里面还要对arch再初始化一遍? 
    回答:spl对于启动uboot来说并不是必须的,在某些情况下,上电之后uboot可能在ROM上或者flash上开始执行而并没有使用spl。这些都是取决于平台的启动机制。因此uboot并不会考虑spl是否已经对arch进行了初始化操作,uboot会完整的做一遍初始化动作,以保证cpu处于所要求的状态下。

  • 和spl在启动过程的差异在哪里? 
    回答:以tiny210而言,前期arch的初始化流程基本上是一致的,出现本质区别的是在board_init_f开始的。

    • spl的board_init_f是由board自己实现相应的功能,例如tiny210则是在board/samsung/tiny210/board.c中。其主要实现了复制uboot到ddr中,并且跳转到uboot的对应位置上。一般spl在这里就可以完成自己的工作了。
    • uboot的board_init_f是在common下实现的,其主要实现uboot relocate前的板级初始化以及relocate的区域规划,其还需要往下走其他初始化流程。

3、代码入口

project-X/u-boot/arch/arm/cpu/u-boot.lds

ENTRY(_start)
  • 1

所以uboot-spl的代码入口函数是_start 
对应于路径project-X/u-boot/arch/arm/lib/vector.S的_start,后续就是从这个函数开始分析。

二、代码整体流程

1、首先看一下主枝干的流程(包含了arch级的初始化)

在arch级初始化是和spl完全一致的 
_start———–>reset————–>关闭中断 
………………………………| 
………………………………———->cpu_init_cp15———–>关闭MMU,TLB 
………………………………| 
………………………………———->cpu_init_crit————->lowlevel_init————->关键寄存器的配置和初始化 
………………………………| 
………………………………———->_main————–>进入板级初始化,具体看下面

2、板级初始化的流程

_main————–>board_init_f_alloc_reserve —————>堆栈、GD、early malloc空间的分配 
…………| 
…………————->board_init_f_init_reserve —————>堆栈、GD、early malloc空间的初始化 
…………| 
…………————->board_init_f —————>uboot relocate前的板级初始化以及relocate的区域规划 
…………| 
…………————->relocate_code、relocate_vectors —————>进行uboot和异常中断向量表的重定向 
…………| 
…………————->旧堆栈的清空 
…………| 
…………————->board_init_r —————>uboot relocate后的板级初始化 
…………| 
…………————->run_main_loop —————>进入命令行状态,等待终端输入命令以及对命令进行处理

三、arch级初始化代码分析

1、_start

上述已经说明了_start是整个uboot的入口,其代码如下: 
arch/arm/lib/vector.S

_start:
#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG.word   CONFIG_SYS_DV_NOR_BOOT_CFG
#endifb   reset
  • 1
  • 2
  • 3
  • 4
  • 5

会跳转到reset中。

2、reset

建议先参考[kernel 启动流程] (第二章)第一阶段之——设置SVC、关闭中断,了解一下为什么要设置SVC、关闭中断以及如何操作。

代码如下: 
arch/arm/cpu/armv7/start.S

    .globl  reset.globl  save_boot_params_retreset:/* 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, cpsrand r1, r0, #0x1f       @ mask mode bitsteq r1, #0x1a       @ test for HYP modebicne   r0, r0, #0x1f       @ clear all mode bitsorrne   r0, r0, #0x13       @ set SVC modeorr r0, r0, #0xc0       @ disable FIQ and IRQmsr cpsr,r0
@@ 以上通过设置CPSR寄存器里设置CPU为SVC模式,禁止中断
@@ 具体操作可以参考《[kernel 启动流程] (第二章)第一阶段之——设置SVC、关闭中断》的分析/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INITbl  cpu_init_cp15
@@ 调用cpu_init_cp15,初始化协处理器CP15,从而禁用MMU和TLB。
@@ 后面会有一小节进行分析bl  cpu_init_crit
@@ 调用cpu_init_crit,进行一些关键的初始化动作,也就是平台级和板级的初始化
@@ 后面会有一小节进行分析
#endifbl  _main
@@ 跳转到主函数,也就是板级初始化函数
@@ 下一节中进行说明。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

3、cpu_init_cp15

建议先参考[kernel 启动流程] (第六章)第一阶段之——打开MMU两篇文章的分析。 
cpu_init_cp15主要用于对cp15协处理器进行初始化,其主要目的就是关闭其MMU和TLB。 
代码如下(去掉无关部分的代码): 
arch/arm/cpu/armv7/start.S

ENTRY(cpu_init_cp15)/** Invalidate L1 I/D*/mov r0, #0          @ set up for MCRmcr p15, 0, r0, c8, c7, 0   @ invalidate TLBsmcr p15, 0, r0, c7, c5, 0   @ invalidate icachemcr p15, 0, r0, c7, c5, 6   @ invalidate BP arraymcr     p15, 0, r0, c7, c10, 4  @ DSBmcr     p15, 0, r0, c7, c5, 4   @ ISB
@@ 这里只需要知道是对CP15处理器的部分寄存器清零即可。
@@ 将协处理器的c7\c8清零等等,各个寄存器的含义请参考《ARM的CP15协处理器的寄存器》/** disable MMU stuff and caches*/mrc p15, 0, r0, c1, c0, 0bic r0, r0, #0x00002000 @ clear bits 13 (--V-)bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)orr r0, r0, #0x00000002 @ set bit 1 (--A-) Alignorr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB
#ifdef CONFIG_SYS_ICACHE_OFFbic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache
#elseorr r0, r0, #0x00001000 @ set bit 12 (I) I-cache
#endifmcr p15, 0, r0, c1, c0, 0
@@ 通过上述的文章的介绍,我们可以知道cp15的c1寄存器就是MMU控制器
@@ 上述对MMU的一些位进行清零和置位,达到关闭MMU和cache的目的,具体的话去看一下上述文章吧。ENDPROC(cpu_init_cp15)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

4、cpu_init_crit

cpu_init_crit,进行一些关键寄存器的初始化动。其代码核心就是lowlevel_init,如下 
arch/arm/cpu/armv7/start.S

ENTRY(cpu_init_crit)/** Jump to board specific initialization...* The Mask ROM will have already initialized* basic memory. Go here to bump up clock rate and handle* wake up conditions.*/b   lowlevel_init       @ go setup pll,mux,memory
ENDPROC(cpu_init_crit)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

所以说lowlevel_init就是这个函数的核心。 
lowlevel_init一般是由板级代码自己实现的。但是对于某些平台来说,也可以使用通用的lowlevel_init,其定义在arch/arm/cpu/lowlevel_init.S中 
以tiny210为例,在移植tiny210的过程中,就需要在board/samsung/tiny210下,也就是板级目录下面创建lowlevel_init.S,在内部实现lowlevel_init。(其实只要实现了lowlevel_init了就好,没必要说在哪里是实现,但是通常规范都是创建了lowlevel_init.S来专门实现lowlevel_init函数)。

在lowlevel_init中,我们要实现如下:

  • 检查一些复位状态
  • 关闭看门狗
  • 系统时钟的初始化
  • 内存、DDR的初始化
  • 串口初始化(可选)
  • Nand flash的初始化

下面以tiny210的lowlevel_init为例(这里说明一下,当时移植tiny210的时候,是直接把kangear的这个lowlevel_init.S文件拿过来用的) 
这部分代码和平台相关性很强,简单介绍一下即可 
board/samsung/tiny210/lowlevel_init.S

lowlevel_init:push    {lr}/* check reset status  */ldr r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)ldr r1, [r0]bic r1, r1, #0xfff6ffffcmp r1, #0x10000beq wakeup_reset_precmp r1, #0x80000beq wakeup_reset_from_didle
@@ 读取复位状态寄存器0xE010_a000的值,判断复位状态。/* IO Retention release */ldr r0, =(ELFIN_CLOCK_POWER_BASE + OTHERS_OFFSET)ldr r1, [r0]ldr r2, =IO_RET_RELorr r1, r1, r2str r1, [r0]
@@ 读取混合状态寄存器E010_e000的值,对其中的某些位进行置位,复位后需要对某些wakeup位置1,具体我也没搞懂。/* Disable Watchdog */ldr r0, =ELFIN_WATCHDOG_BASE    /* 0xE2700000 */mov r1, #0str r1, [r0]
@@ 关闭看门狗@@ 这里忽略掉一部分对外部SROM操作的代码/* when we already run in ram, we don't need to relocate U-Boot.* and actually, memory controller must be configured before U-Boot* is running in ram.*/ldr r0, =0x00ffffffbic r1, pc, r0      /* r0 <- current base addr of code */ldr r2, _TEXT_BASE      /* r1 <- original base addr in ram */bic r2, r2, r0      /* r0 <- current base addr of code */cmp     r1, r2                  /* compare r0, r1                  */beq     1f          /* r0 == r1 then skip sdram init   */
@@ 判断是否已经在SDRAM上运行了,如果是的话,就跳过以下两个对ddr初始化的步骤
@@ 判断方法如下:
@@ 1、获取当前pc指针的地址,屏蔽其低24bit,存放与r1中
@@ 2、获取_TEXT_BASE(CONFIG_SYS_TEXT_BASE)地址,也就是uboot代码段的链接地址,后续在uboot篇的时候会说明,并屏蔽其低24bit
@@ 3、如果相等的话,就跳过DDR初始化的部分/* init system clock */bl system_clock_init
@@ 初始化系统时钟,后续有时间再研究一下具体怎么配置的/* Memory initialize */bl mem_ctrl_asm_init
@@ 重点注意:在这里初始化DDR的!!!后续会写一篇文章说明一下s5pv210平台如何初始化DDR.
@@ 其实,在tiny210的项目中,已经在spl里面对ddr初始化了一遍,这里还是又重新初始化了一遍,从实际测试结果来看,并不影响正常的使用。1:/* for UART */bl uart_asm_init
@@ 串口初始化,到这里串口会打印出一个'O'字符,后续通过写字符到UTXH_OFFSET寄存器中,就可以在串口上输出相应的字符。bl tzpc_init#if defined(CONFIG_NAND)/* simple init for NAND */bl nand_asm_init
@@ 简单地初始化一下NAND flash,有可能BL2的镜像是在nand  flash上面的。
#endif/* Print 'K' */ldr r0, =ELFIN_UART_CONSOLE_BASEldr r1, =0x4b4b4b4bstr r1, [r0, #UTXH_OFFSET]
@@ 再串口上打印‘K’字符,表示lowlevel_init已经完成pop {pc}
@@ 弹出PC指针,即返回。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

当串口中打印出‘OK’的字符的时候,说明lowlevel_init已经执行完成。

三、板级初始化代码分析

1、_main

板级初始化代码的入口就是_main。从这里开始分析。 
建议可以和《[uboot] (番外篇)global_data介绍》和《[uboot] (番外篇)uboot relocation介绍》结合起来看。 
代码如下,去除无关代码部分 
arch/arm/lib/crt0.S

ENTRY(_main)/** Set up initial C runtime environment and call board_init_f(0).*/ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)bic sp, sp, #7  /* 8-byte alignment for ABI compliance */mov r0, spbl  board_init_f_alloc_reservemov sp, r0/* set up gd here, outside any C code */mov r9, r0bl  board_init_f_init_reserve
@@ 以上是堆栈、GD、early malloc空间的分配,具体参考《[uboot] (番外篇)global_data介绍》mov r0, #0bl  board_init_f
@@ uboot relocate前的板级初始化以及relocate的区域规划,后续小节继续说明
@@ 其中relocate区域规划也可以参考一下《[uboot] (番外篇)uboot relocation介绍》/** 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 sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */bic sp, sp, #7  /* 8-byte alignment for ABI compliance */ldr r9, [r9, #GD_BD]        /* r9 = gd->bd */sub r9, r9, #GD_SIZE        /* new GD is below bd */adr lr, hereldr r0, [r9, #GD_RELOC_OFF]     /* r0 = gd->reloc_off */add lr, lr, r0ldr r0, [r9, #GD_RELOCADDR]     /* r0 = gd->relocaddr */b   relocate_code
here:
/** now relocate vectors*/bl  relocate_vectors
@@ GD、uboot、异常中断向量表的relocate,可以参考《[uboot] (番外篇)uboot relocation介绍》,这里不详细说明/* Set up final (full) environment */bl  c_runtime_cpu_setup /* we still call old routine here */
@@ 通过操作协处理器的c7寄存器来关闭Icacheldr 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
@@ 因为堆栈段已经被relocate,所以这里需要清空原来的堆栈段的内容bl coloured_LED_initbl red_led_on
@@ LED灯的初始化,可以不实现,想要实现的话,可以在board里重新实现一个函数定义。/* call board_init_r(gd_t *id, ulong dest_addr) */mov     r0, r9                  /* gd_t */ldr r1, [r9, #GD_RELOCADDR] /* dest_addr *//* call board_init_r */ldr pc, =board_init_r   /* this is auto-relocated! *//* we should not return here. */
@@ uboot relocate后的板级初始化,注意,uboot必须在这里就完成工作,或者在里面实现死循环,不应该返回。
ENDPROC(_main)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

通过上述,有两个很重要的初始化函数,board_init_f和board_init_r,后续继续说明。

2、board_init_f

代码如下: 
common/board_f.c

void board_init_f(ulong boot_flags)
{gd->flags = boot_flags;gd->have_console = 0;
// 设置global_data里面的一些标志位if (initcall_run_list(init_sequence_f))hang();
// 调用initcall_run_list依次执行init_sequence_f函数数组里面的函数,initcall_run_list这里不深究
// 一旦init_sequence_f的函数出错,会导致initcall_run_list返回不为0,而从卡掉
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

打开DEBUG宏之后,可以通过log观察哪些init函数被调用,如下log:

uboot log中有如下log:
initcall: 23e005a4
根据u-boot.map可以发现对应.text.print_cpuinfo0x23e005a4        0x8 arch/arm/cpu/armv7/built-in.o0x23e005a4                print_cpuinfo
也就是说print_cpuinfo被initcall调用了。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

所以uboot relocate之前的板级初始化的核心就是init_sequence_f中定义的函数了。 
如下,这里只做简单的说明,需要的时候再具体分析:

static init_fnc_t init_sequence_f[] = {setup_mon_len,
// 计算整个镜像的长度gd->mon_leninitf_malloc,
// early malloc的内存池的设定initf_console_record,
// console的log的缓存arch_cpu_init,      /* basic arch cpu dependent setup */
// cpu的一些特殊的初始化initf_dm,arch_cpu_init_dm,mark_bootstage,     /* need timer, go after init dm *//* TODO: can any of this go into arch_cpu_init()? */env_init,       /* initialize environment */
// 环境变量的初始化,后续会专门研究一下关于环境变量的内容init_baud_rate,     /* initialze baudrate settings */
// 波特率的初始化serial_init,        /* serial communications setup */
// 串口的初始化console_init_f,     /* stage 1 init of console */
// console的初始化print_cpuinfo,      /* display cpu info (and speed) */
// 打印CPU的信息init_func_i2c,init_func_spi,
// i2c和spi的初始化dram_init,      /* configure available RAM banks */
// ddr的初始化,最重要的是ddr ram size的设置!!!!gd->ram_size
// 如果说uboot是在ROM、flash中运行的话,那么这里就必须要对DDR进行初始化
//========================================setup_dest_addr,reserve_round_4k,reserve_trace,setup_machine,reserve_global_data,reserve_fdt,reserve_arch,reserve_stacks,
// ==以上部分是对relocate区域的规划,具体参考《[uboot] (番外篇)uboot relocation介绍》setup_dram_config,show_dram_config,display_new_sp,reloc_fdt,setup_reloc,
// relocation之后gd一些成员的设置NULL,
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

注意,必须保证上述的函数都正确地返回0值,否则会导致hang。

3、board_init_r

代码如下: 
common/board_r.c

void board_init_r(gd_t *new_gd, ulong dest_addr)
{if (initcall_run_list(init_sequence_r))hang();
// 调用initcall_run_list依次执行init_sequence_r函数数组里面的函数,initcall_run_list这里不深究
// 一旦init_sequence_r的函数出错,会导致initcall_run_list返回不为0,而从卡掉/* NOTREACHED - run_main_loop() does not return */hang();
// uboot要求在这个函数里面终止一切工作,或者进入死循环,一旦试图返回,则直接hang。
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

所以uboot relocate之前的板级初始化的核心就是init_sequence_r中定义的函数了。 
如下,这里只做简单的说明,需要的时候再具体分析: 
common/board_r.c

init_fnc_t init_sequence_r[] = {initr_trace,
// trace相关的初始化initr_reloc,
// gd中一些关于relocate的标识的设置initr_reloc_global_data,
// relocate之后,gd中一些的成员的重新设置initr_malloc,
// malloc内存池的设置initr_console_record,bootstage_relocate,initr_bootstage,
#if defined(CONFIG_ARM) || defined(CONFIG_NDS32)board_init, /* Setup chipselects */
// 板级自己需要的特殊的初始化函数,如board/samsung/tiny210/board.c中定义了board_init这个函数
#endifstdio_init_tables,initr_serial,
// 串口初始化initr_announce,
// 打印uboot运行位置的loginitr_logbuffer,
// logbuffer的初始化power_init_board,
#ifdef CONFIG_CMD_NANDinitr_nand,
// 如果使用nand flash,那么这里需要对nand进行初始化
#endif
#ifdef CONFIG_GENERIC_MMCinitr_mmc,
// 如果使用emmc,那么这里需要对nand进行初始化
#endifinitr_env,
// 初始化环境变量initr_secondary_cpu,stdio_add_devices,initr_jumptable,console_init_r,     /* fully init console as a device */interrupt_init,
// 初始化中断
#if defined(CONFIG_ARM) || defined(CONFIG_AVR32)initr_enable_interrupts,
// 使能中断
#endifrun_main_loop,
// 进入一个死循环,在死循环里面处理终端命令。
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

最终,uboot运行到了run_main_loop,并且在run_main_loop进入命令行状态,等待终端输入命令以及对命令进行处理。 
到此,uboot流程也就完成了,后续会专门说明uboot的run_main_loop是怎么运行的。

这篇关于uboot流程——uboot启动流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1121494

相关文章

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

MySQL数据库宕机,启动不起来,教你一招搞定!

作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等)公众号:老苏畅谈运维欢迎关注本人公众号,更多精彩与您分享。 MySQL数据库宕机,数据页损坏问题,启动不起来,该如何排查和解决,本文将为你说明具体的排查过程。 查看MySQL error日志 查看 MySQL error日志,排查哪个表(表空间

springboot3打包成war包,用tomcat8启动

1、在pom中,将打包类型改为war <packaging>war</packaging> 2、pom中排除SpringBoot内置的Tomcat容器并添加Tomcat依赖,用于编译和测试,         *依赖时一定设置 scope 为 provided (相当于 tomcat 依赖只在本地运行和测试的时候有效,         打包的时候会排除这个依赖)<scope>provided

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

用命令行的方式启动.netcore webapi

用命令行的方式启动.netcore web项目 进入指定的项目文件夹,比如我发布后的代码放在下面文件夹中 在此地址栏中输入“cmd”,打开命令提示符,进入到发布代码目录 命令行启动.netcore项目的命令为:  dotnet 项目启动文件.dll --urls="http://*:对外端口" --ip="本机ip" --port=项目内部端口 例: dotnet Imagine.M

Linux服务器Java启动脚本

Linux服务器Java启动脚本 1、初版2、优化版本3、常用脚本仓库 本文章介绍了如何在Linux服务器上执行Java并启动jar包, 通常我们会使用nohup直接启动,但是还是需要手动停止然后再次启动, 那如何更优雅的在服务器上启动jar包呢,让我们一起探讨一下吧。 1、初版 第一个版本是常用的做法,直接使用nohup后台启动jar包, 并将日志输出到当前文件夹n

衡石分析平台使用手册-单机安装及启动

单机安装及启动​ 本文讲述如何在单机环境下进行 HENGSHI SENSE 安装的操作过程。 在安装前请确认网络环境,如果是隔离环境,无法连接互联网时,请先按照 离线环境安装依赖的指导进行依赖包的安装,然后按照本文的指导继续操作。如果网络环境可以连接互联网,请直接按照本文的指导进行安装。 准备工作​ 请参考安装环境文档准备安装环境。 配置用户与安装目录。 在操作前请检查您是否有 sud

SpringBoot项目是如何启动

启动步骤 概念 运行main方法,初始化SpringApplication 从spring.factories读取listener ApplicationContentInitializer运行run方法读取环境变量,配置信息创建SpringApplication上下文预初始化上下文,将启动类作为配置类进行读取调用 refresh 加载 IOC容器,加载所有的自动配置类,创建容器在这个过程

嵌入式Openharmony系统构建与启动详解

大家好,今天主要给大家分享一下,如何构建Openharmony子系统以及系统的启动过程分解。 第一:OpenHarmony系统构建      首先熟悉一下,构建系统是一种自动化处理工具的集合,通过将源代码文件进行一系列处理,最终生成和用户可以使用的目标文件。这里的目标文件包括静态链接库文件、动态链接库文件、可执行文件、脚本文件、配置文件等。      我们在编写hellowor