u-boot分析

4.Bootloader:u-boot.2009.08分析与移植
4.1:分析u-boot根文件夹下的Makefile,能够看到uboot编译的顺序例如以下,由此可知编译运行的第一个文件是cpu/$(CPU)/start.o,又因为是基于
arm920t架构的,所以去分析cpu/arm920t/start.S源文件。


# U-Boot objects....order is important (i.e. start must be first)
OBJS  = cpu/$(CPU)/start.o
OBJS := $(addprefix $(obj),$(OBJS))

LIBS  = lib_generic/libgeneric.a
LIBS += lib_generic/lzma/liblzma.a
LIBS += lib_generic/lzo/liblzo.a 
LIBS += $(shell if [ -f board/$(VENDOR)/common/Makefile ]; then echo \
"board/$(VENDOR)/common/lib$(VENDOR).a"; fi)
LIBS += cpu/$(CPU)/lib$(CPU).a
LIBS += lib_$(ARCH)/lib$(ARCH).a
LIBS += fs/...(.a)
LIBS += net/libnet.a
LIBS += disk/libdisk.a
LIBS += drivers/...(.a)
LIBS += common/libcommon.a
LIBS += libfdt/libfdt.a
LIBS += api/libapi.a
LIBS += post/libpost.a
LIBS := $(addprefix $(obj),$(LIBS))


4.2:分析cpu/arm920t/start.S源文件:由ARM架构可知程序的运行顺序是开发板一上电即从零地址開始运行,在零地址存放的是一条复位异常中断处
理,依次分析可知程序从上电開始的运行依次例如以下:设置处理器模式、关闭看门狗、关闭中断、设置分频系数比、系统初始化(flush I/D cache、disable MMU、内存sdram相关初始化)、重定位代码(从flash复制uboot代码到SDRAM中)、初始化堆栈、清除bss段、跳转到第二阶段的C语言代码入口函数start_armboot处
运行。


(1).globl _start
 _start: b       start_code

(2)start_code:
  /* set the cpu to SVC32 mode*/
/* turn off the watchdog */
/* mask all IRQs by setting all bits in the INTMR - default */
/* setup FCLK:HCLK:PCLK */
bl cpu_init_crit  /*do sys-critical inits only at reboot*/
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
/* relocate U-Boot from nor flash to RAM */
/* Set up the stack */
/* Clear bss */
/*  jump to second stage */
ldr pc, _start_armboot
_start_armboot:.word start_armboot


4.3:分析/lib_arm/board.c里的start_armboot函数:
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
memset ((void*)gd, 0, sizeof (gd_t));等,初始化gd_t结构体指针gd,并初始化。



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
board_init, /* basic board dependent setup */
#if defined(CONFIG_USE_IRQ)
interrupt_init,/* set up exceptions */
#endif
timer_init, /* initialize timer */
env_init, /* initialize environment */
init_baudrate,/* initialze baudrate settings */
serial_init, /* serial communications setup */
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
display_dram_config,
NULL,
};

for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
},通过一个for循环来依次訪问函数指针数组init_sequence中的成员函数,进一步完毕相关初始化和相关设置。

nand_init(); /* go init the NAND */。初始化nand flash。
serial_initialize();   。初始化串口。

/* 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 */,在无限for循环内,运行main_loop函数。


4.4:分析/common/main.c里的main_loop函数:处理uboot命令。


/*
* Main Loop for Monitor Command Processing
*/
for(;;){
#ifdef CONFIG_BOOT_RETRY_TIME
if (rc >= 0) {
/* Saw enough of a valid command to
* restart the timeout.
*/
reset_cmd_timeout();
}
#endif
len = readline (CONFIG_SYS_PROMPT);
flag = 0; /* assume no special flags for now */
if (len > 0)
strcpy (lastcommand, console_buffer);
else if (len == 0)
flag |= CMD_FLAG_REPEAT;
#ifdef CONFIG_BOOT_RETRY_TIME
else if (len == -2) {
/* -2 means timed out, retry autoboot
*/
puts ("\nTimed out waiting for command\n");
# ifdef CONFIG_RESET_TO_RETRY
/* Reinit board to run initialization code again */
do_reset (NULL, 0, 0, NULL);
# else
return; /* retry autoboot */
# endif
}
#endif
if (len == -1)
puts ("<INTERRUPT>\n");
else
rc = run_command (lastcommand, flag);
if (rc <= 0) {
/* invalid command or not repeatable, forget it */
lastcommand[0] = 0;
}
}
依据输入的命令格式,解析命令參数,运行命令(运行run_command函数)。/common/main.c里的run_command函数。依据命令表结构体cmd_tbl_s来找到输入命令所相应的实现函数。
/*
  * Monitor Command Table
  */

struct cmd_tbl_s {
char *name;/* Command Name */
int maxargs;/* maximum number of arguments */
int repeatable;/* autorepeat allowed?

*/
/* Implementation function*/
int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);
char *usage;/* Usage message (short)*/
#ifdef CONFIG_SYS_LONGHELP
char *help;/* Help  message (long)*/
#endif
#ifdef CONFIG_AUTO_COMPLETE
/* do auto completion on the arguments */
int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
typedef struct cmd_tbl_scmd_tbl_t;
cmd_tbl_t *cmdtp;
/* OK - call function to do the command */
if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
rc = -1;
}//至此。依据不同的uboot命令,去运行不同的实现函数。
4.5:uboot启动linux操作系统的命令是bootm。uboot的bootm命令的实现文件是cmd_bootm.c,所以接着来分析/common/cmd_bootm.c文件:命令实现的格式例如以下:当中命令是bootm,实现函数是do_bootm函数。
#define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))
#ifdef  CONFIG_SYS_LONGHELP
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}
#else /* no long help info */
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage}
#endif /* CONFIG_SYS_LONGHELP */

U_BOOT_CMD(
bootm, CONFIG_SYS_MAXARGS, 1,do_bootm,
"boot application image from memory",
"[addr [arg ...]]\n    - boot application image stored in memory\n"
"\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
"\t'arg' can be the address of an initrd image\n"
"\tbdt     - OS specific bd_t processing\n"
"\tcmdline - OS specific command line processing/setup\n"
"\tprep    - OS specific prep before relocation or go\n"
"\tgo      - start OS"
);


4.6:分析/common/cmd_bootm.c中的do_bootm函数:
static bootm_headers_t images;/* pointers to os/initrd/fdt images */
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
disable_interrupts();
usb_stop();
icache_disable();
dcache_disable();
ret = bootm_load_os(images.os, &load_end, 1); //载入详细的操作系统
images.os.os == IH_OS_LINUX  //假设详细载入的是linux,则有下面
boot_os_fn *boot_fn;
boot_fn = boot_os[images.os.os];//boot_fn指针指向boot_os数组中的特定类型函数
boot_fn(0, argc, argv, &images);//调用do_bootm_linux函数
boot_os_fn * boot_os[] = {
#ifdef CONFIG_BOOTM_LINUX
[IH_OS_LINUX] = do_bootm_linux,
#endif
... ...
}; //由此可知,若载入的是linux系统。则调用do_bootm_linux函数,do_bootm_linux在/lib_arm/bootm.c文件中


4.7:分析/lib_arm/bootm.c中的do_bootm_linux函数:
void (*theKernel)(int zero, int arch, uint params);
theKernel = (void (*)(int, int, uint))images->ep;//images->ep(entry point)
setup_start_tag (bd);
... ...
setup_end_tag (bd);
theKernel (0, machid, bd->bi_boot_params); //至此。跳转到linux内核開始运行,系统启动起来
/* does not return */
return 1;

posted on 2019-04-02 08:38  xfgnongmin  阅读(118)  评论(0编辑  收藏  举报

导航