从大方面来说,u-boot的启动分成两个阶段,第一个阶段主要的职责是准备初始化的环境,主要有以下几点

①设置异常向量表

②把CPU的工作模式设置为SVC32模式

③关闭中断、MMU和cache

④关闭看门狗

⑤初始化内存、时钟、串口

⑥设置堆栈

⑦代码搬移

⑧清bss段

⑨跳转到c语言中执行(第二阶段)

此时系统还没有进入C语言的运行阶段,并没有堆栈,也就不需要额外的RAM。

第二阶段在上一段建立好C语言运行环境的基础上,进行各种外设的初始化,并循环执行用户命令。主要流程图如下

当我们执行make命令来构建u-boot时,它的构建过程是:首先使用交叉编译工具将各目录下的源文件生成目标文件(*.o),目标文件生成后,会将若干个目标文件组合成静态库文件(*.a),最后通过链接各个静态库文件生成ELF格式的可执行文件。在链接的过程中,需要根据链接脚本(一般是各个以lds为后缀的文本文件),确定目标文件的各个段,链接文件通常是board/<board>/目录中的u-boot.lds文件。一般在链接脚本中通过

ENTRY(_start)

来指定入口为_start标号,通过文本段(.text)的第一个目标来制定u-boot入口文件。所以我们通过这个链接脚本文件可以确定u-boot执行的入口。

Tiny4412 u-boot的链接脚本内容为

//  board/samsung/tiny4412/u-boot.lds
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
. = ALIGN();
.text :
{
arch/arm/cpu/armv7/start.o (.text)
board/samsung/tiny4412/libtiny4412.o (.text)
arch/arm/cpu/armv7/exynos/libexynos.o (.text)
*(.text)
}
. = ALIGN();
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN();
.data : {
*(.data)
}
. = ALIGN();
. = .;
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
. = ALIGN();
.rel.dyn : {
__rel_dyn_start = .;
*(.rel*)
__rel_dyn_end = .;
}
.dynsym : {
__dynsym_start = .;
*(.dynsym)
}
.bss __rel_dyn_start (OVERLAY) : {
__bss_start = .;
*(.bss)
. = ALIGN();
_end = .;
}
/DISCARD/ : { *(.dynstr*) }
/DISCARD/ : { *(.dynamic*) }
/DISCARD/ : { *(.plt*) }
/DISCARD/ : { *(.interp*) }
/DISCARD/ : { *(.gnu*) }
}

在本链接脚本文件中,定义了起始地址为0x00000000,每个段使用4字节对齐(.ALIGN(4)),几个段分别为代码段(.text)、只读数据段(.rodata)、数据段(.data)其中,代码段的第一个目标为arch/arm/cpu/armv7/start.o,在其中定义了映像文件的入口_start。

下面来具体分析一下这个start.S。

在文件的一开始定义了映像的入口_start和中断向量表。

.globl _start  //定义u-boot入口
_start: 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
_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
_pad: .word 0x12345678 /* now *= */

系统开机进入到u-boot运行时,首先进入到u-boot的入口_start标号处,然后通过 b  reset 跳转到reset标号处,我们就到reset标号一探究竟。

/*
* the actual reset code
*/
reset:
/*
*设置CPU工作模式为SVC32模式
* set the cpu to SVC32 mode
*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr,r0
//......
//调用 cpu_init_crit
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif

首先会将CPU的工作模式设置为svc32模式,然后便调用 cpu_init_crit ,需要注意的是,这里使用的是 bl 指令,也就是说在运行完 cpu_init_crit 标号处的代码之后,会通过

mov    pc, lr            @ back to my caller

指令回到reset中继续执行

bl    cpu_init_crit

下面的指令(所以这里我们应该使用 调用来描述更为贴切)。下面我们去看一下 cpu_init_crit 指令处做了哪些事

/*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************/
cpu_init_crit: //调用 cache_init
bl cache_init /*
*使 L1 I/D 无效
* Invalidate L1 I/D
*/
mov r0, # @ set up for MCR
mcr p15, , r0, c8, c7, @ invalidate TLBs
mcr p15, , r0, c7, c5, @ invalidate icache
/*
* 关闭 MMU 和 cache
* disable MMU stuff and caches
*/
mrc p15, , r0, c1, c0,
bic r0, r0, #0x00002000 @ clear bits (--V-)
bic r0, r0, #0x00000007 @ clear bits : (-CAM)
orr r0, r0, #0x00000002 @ set bit (--A-) Align
orr r0, r0, #0x00000800 @ set bit (Z---) BTB
mcr p15, , r0, c1, c0,
/*
* 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.
*/
mov ip, lr @ persevere link reg across call
//调用 lowlevel_init
bl lowlevel_init @ go setup pll,mux,memory
mov lr, ip @ restore link
//返回到 reset 标号继续执行
mov pc, lr @ back to my caller
/*

首先分析 cache_init ,它被定义在  board/samsung/tiny4412/lowlevel_init.S 文件中

    .globl cache_init
cache_init:
mov pc, lr

可以看出来,这是一个空函数(暂且将它叫做函数-_-!!)。

接下来我们就要去分析 lowlevel_init 了,它也被定义在board/samsung/tiny4412/lowlevel_init.S 文件中

    .globl lowlevel_init
lowlevel_init: //初始化串口
bl uart_asm_init //Read booting information
//读取启动信息
bl read_om
/* 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, =0xff000fff
bic 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 after_copy /* r0 == r1 then skip sdram init and u-boot.bin loading */
//初始化内存
/* Memory initialize */
bl mem_ctrl_asm_init
//初始化系统时钟
/* init system clock */
bl system_clock_init /*
eg:
1: ;A
cmp r0, #0
beq 1f ; r0==0那么向前跳转到B处执行
bne 1b ; 否则向后跳转到A处执行
:1: ;B
*/ // 向前跳转到1: 标号处执行
b 1f
1:
//初始化 trust zone
bl tzpc_init
b load_uboot
after_copy:
#ifdef CONFIG_ENABLE_MMU
bl enable_mmu
#endif
/* store second boot information in u-boot C level variable */
ldr r0, =CONFIG_PHY_UBOOT_BASE
sub r0, r0, #8
ldr r1, [r0]
ldr r0, _second_boot_info
str r1, [r0]
/* Print 'K' */
ldr r0, =S5PV310_UART_CONSOLE_BASE
ldr r1, =0x4b4b4b4b
str r1, [r0, #UTXH_OFFSET]
//第二阶段入口,调用C语言函数:board_init_f
ldr r0, _board_init_f
mov pc, r0 _board_init_f:
.word board_init_f
load_uboot:
ldr r0, =INF_REG_BASE
ldr r1, [r0, #INF_REG3_OFFSET]
cmp r1, #BOOT_NAND
beq nand_boot
cmp r1, #BOOT_ONENAND
beq onenand_boot
cmp r1, #BOOT_MMCSD
beq mmcsd_boot
cmp r1, #BOOT_EMMC
beq emmc_boot
cmp r1, #BOOT_EMMC_4_4
beq emmc_boot_4_4
cmp r1, #BOOT_NOR
beq nor_boot
cmp r1, #BOOT_SEC_DEV
beq mmcsd_boot
nand_boot:
mov r0, #0x1000
bl copy_uboot_to_ram
b after_copy
onenand_boot:
bl onenand_bl2_copy /*goto 0x1010*/
b after_copy
mmcsd_boot:
#ifdef CONFIG_SMDKC220
//#ifdef CONFIG_CLK_BUS_DMC_200_400
ldr r0, =ELFIN_CLOCK_BASE
ldr r2, =CLK_DIV_FSYS2_OFFSET
ldr r1, [r0, r2]
orr r1, r1, #0xf
str r1, [r0, r2]
//#endif
#else
#if defined(CONFIG_CLK_1000_400_200) || defined(CONFIG_CLK_1000_200_200) || defined(CONFIG_CLK_800_400_200)
ldr r0, =ELFIN_CLOCK_BASE
ldr r2, =CLK_DIV_FSYS2_OFFSET
ldr r1, [r0, r2]
orr r1, r1, #0xf
str r1, [r0, r2]
#endif
#endif
bl movi_uboot_copy
b after_copy
emmc_boot:
#if defined(CONFIG_CLK_1000_400_200) || defined(CONFIG_CLK_1000_200_200) || defined(CONFIG_CLK_800_400_200)
ldr r0, =ELFIN_CLOCK_BASE
ldr r2, =CLK_DIV_FSYS1_OFFSET
ldr r1, [r0, r2]
orr r1, r1, #0xf
str r1, [r0, r2]
#endif
bl emmc_uboot_copy
b after_copy
emmc_boot_4_4:
/* read TCBCNT to get Transferred CIU card byte count */
ldr r0, =0x1255005c
ldr r1, [r0]
ldr r2, =0x6000
cmp r1, r2
/* store second boot information in DRAM */
ldr r0, =CONFIG_PHY_UBOOT_BASE
sub r0, r0, #8
mov r3, #0
movlo r3, #1
str r3, [r0]
/* if transferred CIU card byte count >= 0x6000 (24 KB) */
/* BL1 and BL2 are loaded from emmc 4.4 */
/* Otherwise BL1 and BL2 are loaded from sdmmc ch2. */
blo mmcsd_boot
/* mmc ch4 devider value change */
bl mmc_ch4_devider_change
/* u-boot image copy from boot partition to DRAM. */
bl emmc_4_4_uboot_copy
/* Exit Boot mood */
bl emmc_4_4_endbootOp_eMMC
b after_copy

在 lowlevel_init 中,主要做了一些初始化工作,比如系统时钟、内存、串口等的初始化工作,然后初始化堆栈、清bss段,并进行了代码搬移,为第二阶段C语言程序运行提供保障。最后通过

ldr r0, _board_init_f
mov pc, r0

指令跳转到第二阶段C语言函数 board_init_f 函数处。接着我们就去分析一下这个函数。

在分析board_init_f函数之前,先来了解以下gd_t数据结构

// arch/arm/include/asm/global_data.h
typedef struct global_data {
bd_t *bd;
unsigned long flags;
unsigned long baudrate;
unsigned long have_console; /* serial_init() was called */
unsigned long env_addr; /* Address of Environment struct */
unsigned long env_valid; /* Checksum of Environment valid? */
unsigned long fb_base; /* base address of frame buffer */
#ifdef CONFIG_VFD
unsigned char vfd_type; /* display type */
#endif
#ifdef CONFIG_FSL_ESDHC
unsigned long sdhc_clk;
#endif
#ifdef CONFIG_AT91FAMILY
/* "static data" needed by at91's clock.c */
unsigned long cpu_clk_rate_hz;
unsigned long main_clk_rate_hz;
unsigned long mck_rate_hz;
unsigned long plla_rate_hz;
unsigned long pllb_rate_hz;
unsigned long at91_pllb_usb_init;
#endif
#ifdef CONFIG_ARM
/* "static data" needed by most of timer.c on ARM platforms */
unsigned long timer_rate_hz;
unsigned long tbl;
unsigned long tbu;
unsigned long long timer_reset_value;
unsigned long lastinc;
#endif
unsigned long relocaddr; /* Start address of U-Boot in RAM */
phys_size_t ram_size; /* RAM size */
unsigned long mon_len; /* monitor len */
unsigned long irq_sp; /* irq stack pointer */
unsigned long start_addr_sp; /* start_addr_stackpointer */
unsigned long reloc_off;
#if !(defined(CONFIG_SYS_NO_ICACHE) && defined(CONFIG_SYS_NO_DCACHE))
unsigned long tlb_addr;
#endif
void **jt; /* jump table */
char env_buf[]; /* buffer for getenv() before reloc. */
} gd_t;
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")

u-boot中使用一个结构体gd_t来存储全局区的数据,使用一个存储在寄存器中的指针gd来记录全局数据区的地址。

DECLARE_GLOBAL_DATA_PTR

在board/samsung/tiny4412/tiny4412.c被声明。

u-boot 中还有一个数据结构 bd_t用来存放板级相关的全局数据,是gd_t中结构体指针成员bd的结构体类型。

//   arch/arm/include/asm/u-boot.h
typedef struct bd_info {
int bi_baudrate; /* serial console baudrate */
unsigned long bi_ip_addr; /* IP Address */
ulong bi_arch_number; /* unique id for this board */
ulong bi_boot_params; /* where this board expects params */
struct /* RAM configuration */
{
ulong start;
ulong size;
} bi_dram[CONFIG_NR_DRAM_BANKS];
} bd_t;

u-boot启动内核时要给内核传递参数,这时需要使用gd_t、bd_t结构体中的信息来设置标记列表。了解了这两个数据结构我们就去分析一下board_init_f函数

//   arch/arm/lib/board.c
void board_init_f(ulong bootflag)
{
bd_t *bd;
init_fnc_t **init_fnc_ptr;
gd_t *id;
ulong addr, addr_sp;
//计算全局数据结构的地址,保存在gd指针中
/* Pointer is writable since we allocated a register for it */
gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory"); memset((void*)gd, , sizeof (gd_t));
gd->mon_len = _bss_end_ofs;
逐个调用init_sequence数组的初始化函数
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != ) {
hang();
}
}
debug ("monitor len: %08lX\n", gd->mon_len);
/*
* Ram is setup, size stored in gd !!
*/
debug ("ramsize: %08lX\n", gd->ram_size);
//填充gd数据结构
gd->bd->bi_baudrate = gd->baudrate;
/* Ram ist board specific, so move it to board code ... */
dram_init_banksize();
display_dram_config(); /* and display it */
gd->relocaddr = addr;
gd->start_addr_sp = addr_sp;
gd->reloc_off = addr - _TEXT_BASE;
debug ("relocation Offset is: %08lx\n", gd->reloc_off);
memcpy(id, (void *)gd, sizeof (gd_t));
//调用arch/arm/cpu/armv7/start.S relocate_code
relocate_code(addr_sp, id, addr);
/* NOTREACHED - relocate_code() does not return */
}

u-boot使用一个init_sequence数组来存储大多数开发板都要执行的初始化函数的函数指针

// arch/arm/lib/board.c
typedef int (init_fnc_t)(void);
init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init, /* basic arch cpu dependent setup */
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_F)
board_early_init_f,
#endif
timer_init, /* initialize timer */
#ifdef CONFIG_FSL_ESDHC
get_clocks,
#endif
env_init, /* initialize environment */
#if defined(CONFIG_S5P6450) && !defined(CONFIG_S5P6460_IP_TEST)
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
#endif
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init, /* configure available RAM banks */
#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI)
arm_pci_init,
#endif
NULL,
};

board_init_f函数在调用完初始化函数指针、填充完gd结构之后,调用了arch/arm/cpu/armv7/start.S中的relocate_code去看一下relocate_code做了什么

    .globl    relocate_code
relocate_code:
mov r4, r0 /* save addr_sp */
mov r5, r1 /* save addr of gd */
mov r6, r2 /* save addr of destination */
/* Set up the stack */
stack_setup:
mov sp, r4
adr r0, _start
#if defined(CONFIG_S5PC110) && defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
sub r0, r0, #
#endif
#ifndef CONFIG_PRELOADER
cmp r0, r6
beq clear_bss /* skip relocation */
#endif
mov r1, r6 /* r1 <- scratch for copy_loop */
ldr r2, _TEXT_BASE
ldr r3, _bss_start_ofs
add r2, r0, r3 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r9-r10} /* copy from source address [r0] */
stmia r1!, {r9-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end address [r2] */
blo copy_loop
#ifndef CONFIG_PRELOADER
/*
* fix .rel.dyn relocations
*/
ldr r0, _TEXT_BASE /* r0 <- Text base */
sub r9, r6, r0 /* r9 <- relocation offset */
ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */
add r10, r10, r0 /* r10 <- sym table in FLASH */
ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */
add r2, r2, r0 /* r2 <- rel dyn start in FLASH */
ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */
add r3, r3, r0 /* r3 <- rel dyn end in FLASH */
fixloop:
ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */
add r0, r0, r9 /* r0 <- location to fix up in RAM */
ldr r1, [r2, #]
and r7, r1, #0xff
cmp r7, # /* relative fixup? */
beq fixrel
cmp r7, # /* absolute fixup? */
beq fixabs
/* ignore unknown type of fixup */
b fixnext
fixabs:
/* absolute fix: set location to (offset) symbol value */
mov r1, r1, LSR # /* r1 <- symbol index in .dynsym */
add r1, r10, r1 /* r1 <- address of symbol in table */
ldr r1, [r1, #] /* r1 <- symbol value */
add r1, r1, r9 /* r1 <- relocated sym addr */
b fixnext
fixrel:
/* relative fix: increase location by offset */
ldr r1, [r0]
add r1, r1, r9
fixnext:
str r1, [r0]
add r2, r2, # /* each rel.dyn entry is bytes */
cmp r2, r3
blo fixloop
clear_bss:
ldr r0, _bss_start_ofs
ldr r1, _bss_end_ofs
ldr r3, _TEXT_BASE /* Text base */
mov r4, r6 /* reloc addr */
add r0, r0, r4
add r1, r1, r4
mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #
cmp r0, r1
bne clbss_l
#endif /* #ifndef CONFIG_PRELOADER */
/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
*/ //调用board_init_r
jump_2_ram:
ldr r0, _board_init_r_ofs
adr r1, _start
add lr, r0, r1
@ add lr, lr, r9
/* setup parameters for board_init_r */
mov r0, r5 /* gd_t */
mov r1, r6 /* dest_addr */
/* jump to it ... */
mov pc, lr
_board_init_r_ofs:
.word board_init_r - _start

可见,最后调用了board_init_r函数

//   arch/arm/lib/board.c
void board_init_r(gd_t *id, ulong dest_addr)
{
char *s;
bd_t *bd;
ulong malloc_start;
gd = id;
bd = gd->bd;
gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
monitor_flash_len = _bss_start_ofs;
debug ("monitor flash len: %08lX\n", monitor_flash_len);
board_init(); /* Setup chipselects */
debug ("Now running in RAM - U-Boot at: %08lx\n", dest_addr);
/* The Malloc area is immediately below the monitor copy in DRAM */
malloc_start = dest_addr - TOTAL_MALLOC_LEN;
mem_malloc_init(malloc_start, TOTAL_MALLOC_LEN);
//初始化MMC
#ifdef CONFIG_GENERIC_MMC
mmc_initialize(bd);
#endif
//初始化环境变量
/* initialize environment */
env_relocate();
//将环境变量中的IP填充到gd结构体
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr("ipaddr");
stdio_init(); /* get the devices list going. */
jumptable_init();
//初始化并使能中断
/* set up exceptions */
interrupt_init();
/* enable exceptions */
enable_interrupts();
/* Initialize from environment */
if ((s = getenv("loadaddr")) != NULL) {
load_addr = simple_strtoul(s, NULL, );
}
//进入到main_loop
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop();
}
/* NOTREACHED - no way out of command loop except booting */
}

最后调用了main_loop

待完成:

①main_loop分析

②启动内核过程

。。。。。。

Tiny4412 u-boot分析(2)u-boot启动流程的更多相关文章

  1. Flink架构分析之Standalone模式启动流程

    概述 FLIP6 对Flink架构进行了改进,引入了Dispatcher组件集成了所有任务共享的一些组件:SubmittedJobGraphStore,LibraryCacheManager等,为了保 ...

  2. springBoot高级:自动配置分析,事件监听,启动流程分析,监控,部署

    知识点梳理 课堂讲义 02-SpringBoot自动配置-@Conditional使用 Condition是Spring4.0后引入的条件化配置接口,通过实现Condition接口可以完成有条件的加载 ...

  3. linux根文件系统制作,busybox启动流程分析

    分析 busybox-1.1.6 启动流程,并 制作一个小的根文件系统 源码百度云链接:https://pan.baidu.com/s/1tJhwctqj4VB4IpuKCA9m1g 提取码 :l10 ...

  4. Netty源码分析第1章(Netty启动流程)---->第1节: 服务端初始化

    Netty源码分析第一章:  Server启动流程 概述: 本章主要讲解server启动的关键步骤, 读者只需要了解server启动的大概逻辑, 知道关键的步骤在哪个类执行即可, 并不需要了解每一步的 ...

  5. Netty源码分析第1章(Netty启动流程)---->第2节: NioServerSocketChannel的创建

    Netty源码分析第一章:  Server启动流程 第二节:NioServerSocketChannel的创建 我们如果熟悉Nio, 则对channel的概念则不会陌生, channel在相当于一个通 ...

  6. Netty源码分析第1章(Netty启动流程)---->第3节: 服务端channel初始化

    Netty源码分析第一章:Netty启动流程   第三节:服务端channel初始化 回顾上一小节的initAndRegister()方法: final ChannelFuture initAndRe ...

  7. Netty源码分析第1章(Netty启动流程)---->第4节: 注册多路复用

    Netty源码分析第一章:Netty启动流程   第四节:注册多路复用 回顾下以上的小节, 我们知道了channel的的创建和初始化过程, 那么channel是如何注册到selector中的呢?我们继 ...

  8. Envoy 源码分析--程序启动过程

    目录 Envoy 源码分析--程序启动过程 初始化 main 入口 MainCommon 初始化 服务 InstanceImpl 初始化 启动 main 启动入口 服务启动流程 LDS 服务启动流程 ...

  9. SpringBoot的启动流程是怎样的?SpringBoot源码(七)

    注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 温故而知新 本篇接 SpringBoot内置的各种Starter是怎样构建的? SpringBoot源码(六) 温故而知新, ...

  10. React Native 启动流程简析

    导读:本文以 react-native-cli 创建的示例工程(安卓部分)为例,分析 React Native 的启动流程. 工程创建步骤可以参考官网.本文所分析 React Native 版本为 v ...

随机推荐

  1. POJ2741 Colored Cubes

    Description There are several colored cubes. All of them are of the same size but they may be colore ...

  2. 有若干个箱子,假设每个箱子的最大承重为 MaxW 。将货物分配装箱

    今天在博客园中看到一个博问,就写了下实现代码. 问题: 有若干个箱子,假设每个箱子的最大承重为 MaxW .有一批物品,它们的重量分别为w1.w2...Wn,假设每个物品的重量都不超过箱子承重.写个算 ...

  3. bt种子文件是什么(包括bt文件结构)

    bt种子文件是什么(包括bt文件结构) 一.总结 一句话总结:带特定格式特定信息(资源的url相关信息)的一个字符串(和json有点异曲同工之妙的感觉). 1.bt种子文件和json的区别和联系? 共 ...

  4. CLR事件与路由事件在XAML代码中应用时的区别

    <Window x:Class="Demo_window.Window2"xmlns="http://schemas.microsoft.com/winfx/200 ...

  5. hdu 2509 Be the Winner(anti nim)

    Be the Winner Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tot ...

  6. maven pom.xml 配置 cxf-codegen-plugin 生成web服务客户类型

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  7. 从virustotal上下载病毒样本

    #!/usr/bin/env python import os import csv #import Queue import zipfile import requests import argpa ...

  8. ES6 类(Class)基本用法和静态属性+方法详解

    原文地址:http://blog.csdn.net/pcaxb/article/details/53759637 ES6 类(Class)基本用法和静态属性+方法详解 JavaScript语言的传统方 ...

  9. 移动端rem设置,自动更改html<font-size>

    <script> (function (doc, win) { var docEl = doc.documentElement, resizeEvt = 'orientationchang ...

  10. [转]C++ 智能指针详解

    转自:http://blog.csdn.net/xt_xiaotian/article/details/5714477 C++ 智能指针详解 一.简介 由于 C++ 语言没有自动内存回收机制,程序员每 ...