linux uboot启动流程分析,uboot启动流程分析

描述

U-Boot

U-Boot,全称 Universal Boot Loader,是遵循GPL条款的开放源码项目。U-Boot的作用是系统引导。U-Boot从FADSROM、8xxROM、PPCBOOT逐步发展演化而来。其源码目录、编译形式与Linux内核很相似,事实上,不少U-Boot源码就是根据相应的Linux内核源程序进行简化而形成的,尤其是一些设备的驱动程序,这从U-Boot源码的注释中能体现这一点。

U-Boot不仅仅支持嵌入式Linux系统的引导,它还支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS, android嵌入式操作系统。其目前要支持的目标操作系统是OpenBSD, NetBSD, FreeBSD,4.4BSD, Linux, SVR4, Esix, Solaris, Irix, SCO, Dell, NCR, VxWorks, LynxOS, pSOS, QNX, RTEMS, ARTOS, android。这是U-Boot中Universal的一层含义,另外一层含义则是U-Boot除了支持PowerPC系列的处理器外,还能支持MIPS、 x86、ARM、NIOS、XScale等诸多常用系列的处理器。

这两个特点正是U-Boot项目的开发目标,即支持尽可能多的嵌入式处理器和嵌入式操作系统。就目前来看,U-Boot对PowerPC系列处理器支持最为丰富,对Linux的支持最完善。其它系列的处理器和操作系统基本是在2002年11 月PPCBOOT改名为U-Boot后逐步扩充的。从PPCBOOT向U-Boot的顺利过渡,很大程度上归功于U-Boot的维护人德国DENX软件工程中心Wolfgang Denk[以下简称W.D]本人精湛专业水平和执着不懈的努力。当前,U-Boot项目正在他的领军之下,众多有志于开放源码BOOT LOADER移植工作的嵌入式开发人员正如火如荼地将各个不同系列嵌入式处理器的移植工作不断展开和深入,以支持更多的嵌入式操作系统的装载与引导。

62db9fe138ce9f78e6ac4422058921b9.png

uboot启动流程分析

可知程序的入口在_start,在SourceInsight中查找可发现程序的入口_start在u-boot-2016.05\arch\arm\lib\vectors.S中。

。。。

ENTRY(_start)

SECTIONS

{

。。。

。 = 0x00000000;

。 = ALIGN(4);

.text :

{

*(.__image_copy_start)

*(.vectors)

CPUDIR/start.o (.text*)

*(.text*)

}

。。。

。 = ALIGN(4);

.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }

。 = ALIGN(4);

.data : {

*(.data*)

}

。 = ALIGN(4);

。 = 。;

。。。

.bss_start __rel_dyn_start (OVERLAY) : {

KEEP(*(.__bss_start));

__bss_base = 。;

}

.bss __bss_base (OVERLAY) : {

*(.bss*)

。 = ALIGN(4);

__bss_limit = 。;

}

.bss_end __bss_limit (OVERLAY) : {

KEEP(*(.__bss_end));

}

。。。

}

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152

进入boot-2016.05\arch\arm\lib\vectors.S中,可以看到从_start开始后就跳转到reset去执行:

。。。

.globl _start

。。。

_start:

#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG

.word CONFIG_SYS_DV_NOR_BOOT_CFG

#endif

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

。。.12345678910111213141516171819202122

1、从u-boot-2016.05\arch\arm\cpu\arm920t\start.S中reset执行

主要执行流程:reset -》 cpu_init_crit -》 lowlevel_init -》 _main

reset:

。。。

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

bl cpu_init_crit

#endif

bl _main

。。。

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

cpu_init_crit:

。。。

bl lowlevel_init

。。。

#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

1234567891011121314151617181920212223

2、由bl _main跳转到u-boot-2016.05\arch\arm\lib\crt0.S中从入口_main开始执行

主要执行流程:board_init_f -》 relocate_code -》 board_init_r

ENTRY(_main)

。。。

bl board_init_f_alloc_reserve

。。。

bl board_init_f_init_reserve

。。。

bl board_init_f

#if ! defined(CONFIG_SPL_BUILD)

。。。

b relocate_code

。。。

#endif

#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)

。。。

#if defined(CONFIG_SYS_THUMB_BUILD)

。。。

#else

ldr pc, =board_init_r

#endif

#endif

ENDPROC(_main)123456789101112131415161718192021222324252627282930313233

这部分有三点说明:

⑴、u-boot-2016.05\common\board_f.c:board_init_f通过initcall_run_list(init_sequence_f)函数执行一系列初始化函数以实现前半部分板级初始化。全局结构体gd在u-boot-2016.05\arch\arm\include\asm\global_data.h中声明:

#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm (“r9”)1

⑵、u-boot-2016.05\arch\arm\lib\relocate.S:relocate_code实现uboot代码的重定位,此部分如果觉得源代码不是简单明了可自己改写。

⑶、去重定位uboot有两种路径:

一种是将gd-》flags设为0,在初始化函数序列init_sequence_f中的jump_to_copy函数中去跳转到relocate_code:

static int jump_to_copy(void)

{

if (gd-》flags & GD_FLG_SKIP_RELOC)

return 0;

。。。

#if defined(CONFIG_X86) || defined(CONFIG_ARC)

。。。

#else

relocate_code(gd-》start_addr_sp, gd-》new_gd, gd-》relocaddr);

#endif

return 0;

}1234567891011121314

另一种就是不宏定义CONFIG_SPL_BUILD,然后在u-boot-2016.05\arch\arm\lib\crt0.S中通过

#if ! defined(CONFIG_SPL_BUILD)

。。。

b relocate_code

。。。

#endif123456789

来跳转到relocate_code。以上两种方法选其一,另一种就得去掉。

3、在上一步通过ldr pc, =board_init_r指令进入u-boot-2016.05\common\board_r.c:board_init_r函数,进而调用initcall_run_list(init_sequence_r)函数执行一系列初始化函数以实现后半部分板级初始化,并在initcall_run_list函数里进入run_main_loop不再返回。

void board_init_r(gd_t *new_gd, ulong dest_addr)

{

。。。

if (initcall_run_list(init_sequence_r))

hang();

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

hang();

}

1234567891011

init_sequence_r是一个函数指针数组,里面存放了很多初始化函数指针,里面有两个重要的函数指针initr_announce和run_main_loop:

init_fnc_t init_sequence_r[] = {

。。。

initr_announce,

。。。

run_main_loop,

};12345678910

initr_announce函数声明从此处开始程序就将跳转到RAM中运行:

static int initr_announce(void)

{

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

return 0;

}12345

最后一项是run_main_loop ,进入run_main_loop 后便不再返回。

4、在run_main_loop 里会进入u-boot-2016.05\common\main.c:main_loop函数

static int run_main_loop(void)

{

。。。

for (;;)

main_loop();

return 0;

}12345678

进入main_loop之前就已经完成初始化,接下来准备去处理命令

/* We come here after U-Boot is initialised and ready to process commands */

void main_loop(void)

{

const char *s;

bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, “main_loop”);

。。。

/* get environment_variable: s = getenv(“bootcmd”); -》 bootcmd */

s = bootdelay_process();

。。。

autoboot_command(s);

。。。

}123456789101112131415161718

main_loop函数里有两个重要的过程:

⑴、首先在bootdelay_process函数里通过s = getenv(“bootcmd”)得到bootcmd参数并返回bootcmd参数,

const char *bootdelay_process(void)

{

char *s;

int bootdelay;

。。。

s = getenv(“bootdelay”);

。。。

debug(“### main_loop entered: bootdelay=%d\n\n”, bootdelay);

。。。

s = getenv(“bootcmd”);

。。。

stored_bootdelay = bootdelay;

return s;

}1234567891011121314151617181920212223

其中,bootcmd参数通过以下方式指定:

先在u-boot-2016.05\include\env_default.h中

#ifdef CONFIG_BOOTCOMMAND

“bootcmd=” CONFIG_BOOTCOMMAND “\0”

#endif123

再在u-boot-2016.05\include\configs\smdk2440.h中指定

#define CONFIG_BOOTCOMMAND “nand read 30000000 kernel;bootm 30000000”1

⑵、然后进入autoboot_command函数,并将bootcmd参数传入,继而进入run_command_list函数,继续将bootcmd参数传入

void autoboot_command(const char *s)

{

。。。

if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {

。。。

run_command_list(s, -1, 0);

。。。

}

。。。

}

123456789101112

5、从autoboot_command函数进入u-boot-2016.05\common\cli.c:run_command_list函数后,接着会调用board_run_command函数去执行命令

int run_command_list(const char *cmd, int len, int flag)

{

int need_buff = 1;

char *buff = (char *)cmd; /* cast away const */

int rcode = 0;

if (len == -1) {

len = strlen(cmd);

#ifdef CONFIG_SYS_HUSH_PARSER

。。。

#else

/* the built-in parser will change our string if it sees \n */

need_buff = strchr(cmd, ‘\n’) != NULL;

#endif

}

if (need_buff) {

buff = malloc(len + 1);

if (!buff)

return 1;

memcpy(buff, cmd, len);

buff[len] = ‘\0’;

}

#ifdef CONFIG_SYS_HUSH_PARSER

。。。

#ifdef CONFIG_CMDLINE

。。。

#else

rcode = board_run_command(buff);

#endif

#endif

。。。

}1234567891011121314151617181920212223242526272829303132

那么,board_run_command如何去执行命令?

首先,board_run_command函数通过bootcmd参数中的bootm命令找到u-boot-2016.05\cmd\bootm.c中的

U_BOOT_CMD(

bootm, CONFIG_SYS_MAXARGS, 1, do_bootm,

“boot application image from memory”, bootm_help_text

);1234

然后,根据这个信息找到执行bootm命令的处理函数指针do_bootm,并进入do_bootm函数执行相关代码,而U_BOOT_CMD在u-boot-2016.05\include\command.h中定义:

#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) \

U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)12

#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, \

_comp) \

_CMD_REMOVE(sub_ ## _name, _cmd)123

#define _CMD_REMOVE(_name, _cmd) \

int __remove_ ## _name(void) \

{ \

if (0) \

_cmd(NULL, 0, 0, NULL); \

return 0; \

}1234567

在此,board_run_command函数还会将bootm命令中的参数(内核映像所在地址)30000000赋给bootm_headers_t结构体变量images,则images首地址就是30000000,images在u-boot-2016.05\cmd\bootm.c中定义:

bootm_headers_t images; 1

6、根据U_BOOT_CMD信息进入u-boot-2016.05\cmd\bootm.c:do_bootm函数

int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])

{

。。。

return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START |

BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER |

BOOTM_STATE_LOADOS |

#if defined(CONFIG_PPC) || defined(CONFIG_MIPS)

BOOTM_STATE_OS_CMDLINE |

#endif

BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |

BOOTM_STATE_OS_GO, &images, 1);

}

1234567891011121314

其中BOOTM_STATE_START 、BOOTM_STATE_FINDOS 、BOOTM_STATE_FINDOTHER 、BOOTM_STATE_LOADOS 、BOOTM_STATE_OS_PREP 、BOOTM_STATE_OS_FAKE_GO 这些在u-boot-2016.05\include\image.h中bootm_headers结构体中指定:

#define BOOTM_STATE_START (0x00000001)

#define BOOTM_STATE_FINDOS (0x00000002)

#define BOOTM_STATE_FINDOTHER (0x00000004)

#define BOOTM_STATE_LOADOS (0x00000008)

#define BOOTM_STATE_RAMDISK (0x00000010)

#define BOOTM_STATE_FDT (0x00000020)

#define BOOTM_STATE_OS_CMDLINE (0x00000040)

#define BOOTM_STATE_OS_BD_T (0x00000080)

#define BOOTM_STATE_OS_PREP (0x00000100)

#define BOOTM_STATE_OS_FAKE_GO (0x00000200) /* ‘Almost’ run the OS */

#define BOOTM_STATE_OS_GO (0x00000400)1234567891011

7、从do_bootm进入u-boot-2016.05\common\bootm.c:do_bootm_states函数,Now run the OS!

int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],

int states, bootm_headers_t *images, int boot_progress)

{

boot_os_fn *boot_fn;

ulong iflag = 0;

int ret = 0, need_boot_fn;

images-》state |= states;

/*

* Work through the states and see how far we get. We stop on

* any error.

*/

if (states & BOOTM_STATE_START)

ret = bootm_start(cmdtp, flag, argc, argv);

if (!ret && (states & BOOTM_STATE_FINDOS))

ret = bootm_find_os(cmdtp, flag, argc, argv);

if (!ret && (states & BOOTM_STATE_FINDOTHER)) {

ret = bootm_find_other(cmdtp, flag, argc, argv);

argc = 0; /* consume the args */

}

/* Load the OS */

if (!ret && (states & BOOTM_STATE_LOADOS)) {

ulong load_end;

iflag = bootm_disable_interrupts();

ret = bootm_load_os(images, &load_end, 0);

if (ret == 0)

lmb_reserve(&images-》lmb, images-》os.load,

(load_end - images-》os.load));

else if (ret && ret != BOOTM_ERR_OVERLAP)

goto err;

else if (ret == BOOTM_ERR_OVERLAP)

ret = 0;

#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)

if (images-》os.os == IH_OS_LINUX)

fixup_silent_linux();

#endif

}

/* Relocate the ramdisk */

#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH

if (!ret && (states & BOOTM_STATE_RAMDISK)) {

ulong rd_len = images-》rd_end - images-》rd_start;

ret = boot_ramdisk_high(&images-》lmb, images-》rd_start,

rd_len, &images-》initrd_start, &images-》initrd_end);

if (!ret) {

setenv_hex(“initrd_start”, images-》initrd_start);

setenv_hex(“initrd_end”, images-》initrd_end);

}

}

#endif

#if IMAGE_ENABLE_OF_LIBFDT && defined(CONFIG_LMB)

if (!ret && (states & BOOTM_STATE_FDT)) {

boot_fdt_add_mem_rsv_regions(&images-》lmb, images-》ft_addr);

ret = boot_relocate_fdt(&images-》lmb, &images-》ft_addr,

&images-》ft_len);

}

#endif

/* From now on, we need the OS boot function */

if (ret)

return ret;

boot_fn = bootm_os_get_boot_func(images-》os.os);

need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE |

BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP |

BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO);

if (boot_fn == NULL && need_boot_fn) {

if (iflag)

enable_interrupts();

printf(“ERROR: booting os ‘%s’ (%d) is not supported\n”,

genimg_get_os_name(images-》os.os), images-》os.os);

bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS);

return 1;

}

/* Call various other states that are not generally used */

if (!ret && (states & BOOTM_STATE_OS_CMDLINE))

ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images);

if (!ret && (states & BOOTM_STATE_OS_BD_T))

ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images);

if (!ret && (states & BOOTM_STATE_OS_PREP))

ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);

#ifdef CONFIG_TRACE

/* Pretend to run the OS, then run a user command */

if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) {

char *cmd_list = getenv(“fakegocmd”);

ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO,

images, boot_fn);

if (!ret && cmd_list)

ret = run_command_list(cmd_list, -1, flag);

}

#endif

/* Check for unsupported subcommand. */

if (ret) {

puts(“subcommand not supported\n”);

return ret;

}

/* Now run the OS! We hope this doesn‘t return */

if (!ret && (states & BOOTM_STATE_OS_GO))

ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO,

images, boot_fn);

/* Deal with any fallout */

err:

if (iflag)

enable_interrupts();

if (ret == BOOTM_ERR_UNIMPLEMENTED)

bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL);

else if (ret == BOOTM_ERR_RESET)

do_reset(cmdtp, flag, argc, argv);

return ret;

}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123

do_bootm_states函数总共分8个部分:

⑴、 Work through the states and see how far we get. We stop on any error.

53a52464b53ca737928d0583be8f18b7.png

其中主要函数bootm_find_os实现三个功能:get kernel image header, start address and length,get image parameters。大概过程是:bootm_find_os -》 boot_get_kernel -》 image_get_kernel 。

static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,

char * const argv[])

{

const void *os_hdr;

bool ep_found = false;

int ret;

/* get kernel image header, start address and length */

os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,

&images, &images.os.image_start, &images.os.image_len);

。。。

/* get image parameters */

switch (genimg_get_format(os_hdr)) {

#if defined(CONFIG_IMAGE_FORMAT_LEGACY)

case IMAGE_FORMAT_LEGACY: /*旧系统格式的内核映像*/

images.os.type = image_get_type(os_hdr);

images.os.comp = image_get_comp(os_hdr);

images.os.os = image_get_os(os_hdr);

images.os.end = image_get_image_end(os_hdr);

images.os.load = image_get_load(os_hdr);

images.os.arch = image_get_arch(os_hdr);

break;

#endif

#if IMAGE_ENABLE_FIT

case IMAGE_FORMAT_FIT:

。。。

#endif

#ifdef CONFIG_ANDROID_BOOT_IMAGE

case IMAGE_FORMAT_ANDROID:

。。。

#endif

default:

puts(“ERROR: unknown image format type!\n”);

return 1;

}

。。。

if (images.os.type == IH_TYPE_KERNEL_NOLOAD) {

images.os.load = images.os.image_start;

images.ep += images.os.load;

}

。。.123456789101112131415161718192021222324252627282930313233343536373839404142434445

关于boot_get_kernel 、image_get_kernel 的说明:

boot_get_kernel - find kernel image(returns:

pointer to image header if valid image was found, plus kernel start address and length, otherwise NULL)

image_get_kernel - verify legacy format kernel image(returns:

pointer to a legacy image header if valid image was found otherwise return NULL)

⑵、Load the OS

⑶、Relocate the ramdisk

⑷、From now on, we need the OS boot function

由boot_fn = bootm_os_get_boot_func(images-》os.os);得到boot处理函数指针并赋给boot_fn。

①、关于参数images-》os.os,可以由下列定义得知它是系统内核的类型,并在(2)中被赋值,若系统类型为linux,则images-》os.os=5。

typedef struct bootm_headers {

。。。

#ifndef USE_HOSTCC /*USE_HOSTCC 没有宏定义*/

image_info_t os; /* os image info */

ulong ep; /* entry point of OS */

ulong rd_start, rd_end;/* ramdisk start/end */

char *ft_addr; /* flat dev tree address */

ulong ft_len; /* length of flat device tree */

ulong initrd_start;

ulong initrd_end;

ulong cmdline_start;

ulong cmdline_end;

bd_t *kbd;

#endif

。。。

} bootm_headers_t;1234567891011121314151617181920212223

bootm_headers_t images;1

typedef struct image_info {

ulong start, end; /* start/end of blob */

ulong image_start, image_len; /* start of image within blob, len of image */

ulong load; /* load addr for the image */

uint8_t comp, type, os; /* compression, type of image, os type */

uint8_t arch; /* CPU architecture */

} image_info_t;1234567

得到images.os.os的值:

static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,

char * const argv[])

{

const void *os_hdr;

。。。

/* get kernel image header, start address and length */

os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,

&images, &images.os.image_start, &images.os.image_len);

。。。

/* get image parameters */

switch (genimg_get_format(os_hdr)) {

#if defined(CONFIG_IMAGE_FORMAT_LEGACY)

case IMAGE_FORMAT_LEGACY: /*旧系统格式的内核映像*/

。。。

images.os.os = image_get_os(os_hdr);

。。。

break;

#endif12345678910111213141516171819202122

②、bootm_os_get_boot_func中会用到函数指针数组boot_os,该数组利用传入的images.os.os=5的值得到boot处理函数指针do_bootm_linux返回给boot_fn 。

boot_fn = bootm_os_get_boot_func(images-》os.os);1

boot_os_fn *bootm_os_get_boot_func(int os)

{

。。。

return boot_os[os];

}

123456

static boot_os_fn *boot_os[] = {

[IH_OS_U_BOOT] = do_bootm_standalone,

#ifdef CONFIG_BOOTM_LINUX

[IH_OS_LINUX] = do_bootm_linux,

#endif

#ifdef CONFIG_BOOTM_NETBSD

[IH_OS_NETBSD] = do_bootm_netbsd,

#endif

。。。

};12345678910

操作系统代号可在u-boot-2016.05\include\image.h中查看

/*

* Operating System Codes

*/

#define IH_OS_INVALID 0 /* Invalid OS */

#define IH_OS_OPENBSD 1 /* OpenBSD */

#define IH_OS_NETBSD 2 /* NetBSD */

#define IH_OS_FREEBSD 3 /* FreeBSD */

#define IH_OS_4_4BSD 4 /* 4.4BSD */

#define IH_OS_LINUX 5 /* Linux */

。。。

123456789101112

⑸、Call various other states that are not generally used

⑹、Check for unsupported subcommand

⑺、Now run the OS! We hope this doesn’t return

if (!ret && (states & BOOTM_STATE_OS_GO))

ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO,

images, boot_fn);

1234

从do_bootm_states进入u-boot-2016.05\common\bootm_os.c:boot_selected_os函数,执行boot_fn(state, argc, argv, images);

int boot_selected_os(int argc, char * const argv[], int state,

bootm_headers_t *images, boot_os_fn *boot_fn)

{

。。。

boot_fn(state, argc, argv, images);

。。。

}1234567

⑻、Deal with any fallout

8、执行boot_fn(state, argc, argv, images),因为boot_fn=do_bootm_linux,所以相当于执行do_bootm_linux(state, argc, argv, images),程序跳到u-boot-2016.05\arch\arm\lib\bootm.c:

/* Main Entry point for arm bootm implementation*/

int do_bootm_linux(int flag, int argc, char * const argv[],

bootm_headers_t *images)

{

。。。

boot_jump_linux(images, flag);

。。。

}12345678

do_bootm_linux -》 boot_jump_linux -》 kernel_entry(0, machid, r2);

static void boot_jump_linux(bootm_headers_t *images, int flag)

{

。。。

unsigned long machid = gd-》bd-》bi_arch_number;

char *s;

void (*kernel_entry)(int zero, int arch, uint params);

unsigned long r2;

int fake = (flag & BOOTM_STATE_OS_FAKE_GO);

kernel_entry = (void (*)(int, int, uint))images-》ep; /* ep:entry point of OS*/

s = getenv(“machid”);

if (s) {

if (strict_strtoul(s, 16, &machid) 《 0) {

debug(“strict_strtoul failed!\n”);

return;

}

printf(“Using machid 0x%lx from environment\n”, machid);

}

。。。

if (IMAGE_ENABLE_OF_LIBFDT && images-》ft_len)

r2 = (unsigned long)images-》ft_addr;

else

r2 = gd-》bd-》bi_boot_params;

if (!fake) {

。。。

kernel_entry(0, machid, r2);

}

#endif

}12345678910111213141516171819202122232425262728293031323334

run the OS!

说明:

关于kernel_entry = (void (*)(int, int, uint))images-》ep;中的images-》ep在u-boot-2016.05\common\bootm.c:bootm_find_os函数中被赋值。

static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,

char * const argv[])

{

。。。

if (images.os.type == IH_TYPE_KERNEL_NOLOAD) {

images.os.load = images.os.image_start;

images.ep += images.os.load;

}

。。。

}

打开APP阅读更多精彩内容

点击阅读全文

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux U-Boot启动流程如下: 1. 开机自检:U-Boot会进行一些硬件自检,例如检查内存、CPU、串口等。 2. 加载U-Boot:U-Boot会从Flash中读取自身代码,并将其加载到内存中。 3. 初始化:U-Boot会初始化一些硬件设备,例如串口、网卡等。 4. 加载内核:U-Boot会从Flash中读取Linux内核,并将其加载到内存中。 5. 启动内核:U-Boot会将控制权转交给内核,并启动Linux系统。 6. 内核初始化:Linux内核会进行一些初始化工作,例如初始化进程、文件系统等。 7. 用户空间初始化:Linux内核会启动init进程,并初始化用户空间。 8. 用户空间运行:Linux系统启动完成后,用户可以在用户空间中运行应用程序。 ### 回答2: Linux系统的启动流程分为UEFI与BIOS两种模式,而最重要的启动阶段便是uboot启动阶段。uboot是一款开源的嵌入式操作系统的引导程序,它可以加载并启动Linux操作系统。接下来我们深入了解一下Linux uboot启动流程。 1. 启动元件的初始化 uboot首先进行启动元件的初始化,启动元件包括RAM、Flash、UART、NAND Flash、SD卡等。它通过初始化它们,来保证它们可以被操作系统正常使用。 2. 加载uboot的参数 接下来uboot会读取启动设备上固定的位置文件system.map。这个文件中记录着uboot所需要的各种参数,例如内存信息、启动设备的信息等。uboot会将这些参数加载到内存中,以便执行下一步操作。 3. 加载内核 uboot接着会从启动设备的固定位置读取内核文件,并将内核加载到内存中的指定位置。同时,它还会设置Linux内核的启动参数,例如根分区的位置、启动命令行参数等。当内核被完全加载到内存中后,uboot会将控制权转交给内核。 4. 内核启动 内核将被启动,开始执行初始化任务和启动服务。它会根据uboot传递的参数信息,找到根文件系统分区,并将其挂载到根目录下。接着,内核会继续启动Deamon(服务)进程,例如SSH服务,以便与用户进行交互。在一些需要应用程序自启的系统中,内核也会启动一些相应应用程序。 总之,Ubuto的启动流程就是先初始化启动元件,然后加载uboot的参数,加载内核,最后启动内核,让其运行Linux操作系统。这样,Linux操作系统就完成了从uboot到内核的启动过程,准备好与用户进行交互使用。 ### 回答3: 在嵌入式设备中,U-Boot是一种常用的开源启动引导程序,通常用于在Linux系统上启动操作系统。下面就是Linux U-Boot启动流程。 1. 加载启动程序。当设备上电时,CPU会将引导ROM中的第一条指令加载到CPU的寄存器中执行,这个指令会将U-Boot启动程序加载到RAM中。 2. 硬件初始化。开始运行U-Boot启动程序时,首先需要初始化硬件。U-Boot通过硬件抽象层(HAL)完成这些操作,例如:内存初始化、外设初始化、CPU时钟初始化等。 3. 加载设备树。设备树是一种描述硬件以及软件之间联系的机器可读文本文件,U-Boot从存储设备中读取设备树文件并将其加载到内存中。 4. 加载内核。U-Boot启动程序会尝试从存储设备中读取内核。在加载内核之前,需要确定内核的位置、大小以及参数。 5. 加载根文件系统。内核启动时需要知道根文件系统的位置,并将其加载到内存中。 6. 启动内核。一旦内核和根文件系统被完全加载到内存中,U-Boot会将内核的控制权交给内核,此时内核会从RAM中读取U-Boot加载的设备树信息。 7. 系统初始化。内核启动后,会开始进行系统级别的初始化,例如挂载根文件系统、启动初始化脚本等。 8. 用户程序启动。一旦初始化完成,系统就会启动用户程序,此时用户可以通过终端界面或其他方式与设备进行交互。 这就是Linux U-Boot启动流程,了解这些流程可以帮助开发者更好地理解嵌入式系统的启动过程,以及如何针对系统进行调试和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值