原博客:https://blog.csdn.net/xiaokangdream/article/details/79588088
我们之前讲到的UBOOT的第一阶段初始化,都是一些硬件的操作,之后的操作便在比较复杂的函数中去实现了,也是我们上节课讲到的:
这里把_start_armboot的地址赋值给pc,而_start_armboot的地址为:
也就是跳到start_armboot这个地址里。这应该是一个函数,我们看看这个函数的定义:
-
void start_armboot (void)
-
{
-
init_fnc_t **init_fnc_ptr;
-
char *s;
-
#ifndef CFG_NO_FLASH
-
ulong size;
-
#endif
-
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
-
unsigned
long addr;
-
#endif
-
-
/* Pointer is writable since we allocated a register for it */
-
gd = (
gd_t*)(_armboot_start - CFG_MALLOC_LEN -
sizeof(
gd_t));
-
/* compiler optimization barrier needed for GCC >= 3.4 */
-
__asm__ __volatile__(
"": : :
"memory");
-
-
memset ((
void*)gd,
0,
sizeof (
gd_t));
-
gd->bd = (
bd_t*)((
char*)gd -
sizeof(
bd_t));
-
memset (gd->bd,
0,
sizeof (
bd_t));
-
-
monitor_flash_len = _bss_start - _armboot_start;
-
-
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
-
if ((*init_fnc_ptr)() !=
0) {
-
hang ();
-
}
-
}
-
-
#ifndef CFG_NO_FLASH
-
/* configure available FLASH banks */
-
size = flash_init ();
-
display_flash_config (size);
-
#endif /* CFG_NO_FLASH */
-
-
#ifdef CONFIG_VFD
-
# ifndef PAGE_SIZE
-
# define PAGE_SIZE 4096
-
# endif
-
/*
-
* reserve memory for VFD display (always full pages)
-
*/
-
/* bss_end is defined in the board-specific linker script */
-
addr = (_bss_end + (PAGE_SIZE -
1)) & ~(PAGE_SIZE -
1);
-
size = vfd_setmem (addr);
-
gd->fb_base = addr;
-
#endif /* CONFIG_VFD */
-
-
#ifdef CONFIG_LCD
-
# ifndef PAGE_SIZE
-
# define PAGE_SIZE 4096
-
# endif
-
/*
-
* reserve memory for LCD display (always full pages)
-
*/
-
/* bss_end is defined in the board-specific linker script */
-
addr = (_bss_end + (PAGE_SIZE -
1)) & ~(PAGE_SIZE -
1);
-
size = lcd_setmem (addr);
-
gd->fb_base = addr;
-
#endif /* CONFIG_LCD */
-
-
/* armboot_start is defined in the board-specific linker script */
-
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
-
-
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-
puts (
"NAND: ");
-
nand_init();
/* go init the NAND */
-
#endif
-
-
#ifdef CONFIG_HAS_DATAFLASH
-
AT91F_DataflashInit();
-
dataflash_print_info();
-
#endif
-
-
/* initialize environment */
-
env_relocate ();
-
-
#ifdef CONFIG_VFD
-
/* must do this after the framebuffer is allocated */
-
drv_vfd_init();
-
#endif /* CONFIG_VFD */
-
-
/* IP Address */
-
gd->bd->bi_ip_addr = getenv_IPaddr (
"ipaddr");
-
-
/* MAC Address */
-
{
-
int i;
-
ulong reg;
-
char *s, *e;
-
char tmp[
64];
-
-
i = getenv_r (
"ethaddr", tmp,
sizeof (tmp));
-
s = (i >
0) ? tmp :
NULL;
-
-
for (reg =
0; reg <
6; ++reg) {
-
gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e,
16) :
0;
-
if (s)
-
s = (*e) ? e +
1 : e;
-
}
-
-
#ifdef CONFIG_HAS_ETH1
-
i = getenv_r (
"eth1addr", tmp,
sizeof (tmp));
-
s = (i >
0) ? tmp :
NULL;
-
-
for (reg =
0; reg <
6; ++reg) {
-
gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e,
16) :
0;
-
if (s)
-
s = (*e) ? e +
1 : e;
-
}
-
#endif
-
}
-
-
devices_init ();
/* get the devices list going. */
-
-
#ifdef CONFIG_CMC_PU2
-
load_sernum_ethaddr ();
-
#endif /* CONFIG_CMC_PU2 */
-
-
jumptable_init ();
-
-
console_init_r ();
/* fully init console as a device */
-
-
#if defined(CONFIG_MISC_INIT_R)
-
/* miscellaneous platform dependent initialisations */
-
misc_init_r ();
-
#endif
-
-
Port_Init();
-
if (!PreLoadedONRAM) {
-
/* enable exceptions */
-
enable_interrupts ();
-
/* add by www.100ask.net */
-
usb_init();
-
}
-
-
/* Perform network card initialisation if necessary */
-
#ifdef CONFIG_DRIVER_CS8900
-
cs8900_get_enetaddr (gd->bd->bi_enetaddr);
-
#endif
-
-
#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
-
if (getenv (
"ethaddr")) {
-
smc_set_mac_addr(gd->bd->bi_enetaddr);
-
}
-
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
-
-
/* Initialize from environment */
-
if ((s = getenv (
"loadaddr")) !=
NULL) {
-
load_addr = simple_strtoul (s,
NULL,
16);
-
}
-
#if (CONFIG_COMMANDS & CFG_CMD_NET)
-
if ((s = getenv (
"bootfile")) !=
NULL) {
-
copy_filename (BootFile, s,
sizeof (BootFile));
-
}
-
#endif /* CFG_CMD_NET */
-
-
#ifdef BOARD_LATE_INIT
-
board_late_init ();
-
#endif
-
#if (CONFIG_COMMANDS & CFG_CMD_NET)
-
#if defined(CONFIG_NET_MULTI)
-
puts (
"Net: ");
-
#endif
-
eth_initialize(gd->bd);
-
#endif
-
/* 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 */
-
}
首先看到这里:
这里的话给gd_t这个结构体分配了空间,其实这就是给我们分配一些全局数据的内存。我们继续往下看:
这个init_sequence是什么?我们搜索一下,发现在本文件中有相关的定义:
-
init_fnc_t *init_sequence[] = {
-
cpu_init,
/* basic cpu dependent setup */
-
board_init,
/* basic board dependent setup */
-
interrupt_init,
/* set up exceptions */
-
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
-
dram_init,
/* configure available RAM banks */
-
display_dram_config,
-
NULL,
-
};
我们发现,其里面都是一些函数指针,装有各种初始化函数:cpu的,开发版的,中断的,环境变量的,串口的等等。而这个init_sequence便是一个指针数组来的。所以,这个循环的意思就是分别执行各个初始化函数,如果返回值不为零的话,就会卡死在那里。这里我们研究一下其中的部分初始化函数,首先看到board_init:
-
int board_init (void)
-
{
-
S3C24X0_CLOCK_POWER *
const clk_power = S3C24X0_GetBase_CLOCK_POWER();
-
S3C24X0_GPIO *
const gpio = S3C24X0_GetBase_GPIO();
-
-
/* set up the I/O ports */
-
gpio->GPACON =
0x007FFFFF;
-
gpio->GPBCON =
0x00044555;
-
gpio->GPBUP =
0x000007FF;
-
gpio->GPCCON =
0xAAAAAAAA;
-
gpio->GPCUP =
0x0000FFFF;
-
gpio->GPDCON =
0xAAAAAAAA;
-
gpio->GPDUP =
0x0000FFFF;
-
gpio->GPECON =
0xAAAAAAAA;
-
gpio->GPEUP =
0x0000FFFF;
-
gpio->GPFCON =
0x000055AA;
-
gpio->GPFUP =
0x000000FF;
-
gpio->GPGCON =
0xFF95FFBA;
-
gpio->GPGUP =
0x0000FFFF;
-
gpio->GPHCON =
0x002AFAAA;
-
gpio->GPHUP =
0x000007FF;
-
-
/* support both of S3C2410 and S3C2440, by www.100ask.net */
-
if (isS3C2410)
-
{
-
/* arch number of SMDK2410-Board */
-
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
-
}
-
else
-
{
-
/* arch number of SMDK2440-Board */
-
gd->bd->bi_arch_number = MACH_TYPE_S3C2440;
-
}
-
-
/* adress of boot parameters */
-
gd->bd->bi_boot_params =
0x30000100;
-
#if 0
-
icache_enable();
-
dcache_enable();
-
#endif
-
return
0;
-
}
我们看到,函数的前面都是做一些初始化管脚的工作,初始化完管脚后,就开始设置机器ID:
-
/* support both of S3C2410 and S3C2440, by www.100ask.net */
-
if (isS3C2410)
-
{
-
/* arch number of SMDK2410-Board */
-
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
-
}
-
else
-
{
-
/* arch number of SMDK2440-Board */
-
gd->bd->bi_arch_number = MACH_TYPE_S3C2440;
-
}
检查开发板式2410还是2440,然后分别相应的值。最后则是设置内核需要的参数的地址:
-
/* adress of boot parameters */
-
gd->bd->bi_boot_params =
0x30000100;
这个值后面再讲,后面会用得到的。接下来,我们回到之前的start_armboot。我们知道,u-boot最终的目的是启动内核,所以我们现在更希望找到与启动内核比较有关的代码。我们看到接下来的代码:
这一步是初始化flash,它会识别出你当前所使用的norflash。我们继续往下看:
这一步是初始化nandflash,它会扫出单板。以上步骤,都是对flash初始化,执行了上面的步骤后,才有能力对flash进行读写,是我们从flash中读出内核并执行的基础。我们继续看:
这一步是初始化环境变量。我们继续往下看:
我们看到,到这里, 就是一个死循环了,那么这个函数是什么呢?我们进去看一下:
-
void main_loop (void)
-
{
-
#ifndef CFG_HUSH_PARSER
-
static
char lastcommand[CFG_CBSIZE] = {
0, };
-
int len;
-
int rc =
1;
-
int flag;
-
#endif
-
-
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
-
char *s;
-
int bootdelay;
-
#endif
-
#ifdef CONFIG_PREBOOT
-
char *p;
-
#endif
-
#ifdef CONFIG_BOOTCOUNT_LIMIT
-
unsigned
long bootcount =
0;
-
unsigned
long bootlimit =
0;
-
char *bcs;
-
char bcs_set[
16];
-
#endif /* CONFIG_BOOTCOUNT_LIMIT */
-
-
#if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
-
ulong bmp =
0;
/* default bitmap */
-
extern int trab_vfd (ulong bitmap);
-
-
#ifdef CONFIG_MODEM_SUPPORT
-
if (do_mdm_init)
-
bmp =
1;
/* alternate bitmap */
-
#endif
-
trab_vfd (bmp);
-
#endif /* CONFIG_VFD && VFD_TEST_LOGO */
-
-
#ifdef CONFIG_BOOTCOUNT_LIMIT
-
bootcount = bootcount_load();
-
bootcount++;
-
bootcount_store (bootcount);
-
sprintf (bcs_set,
"%lu", bootcount);
-
setenv (
"bootcount", bcs_set);
-
bcs = getenv (
"bootlimit");
-
bootlimit = bcs ? simple_strtoul (bcs,
NULL,
10) :
0;
-
#endif /* CONFIG_BOOTCOUNT_LIMIT */
-
-
#ifdef CONFIG_MODEM_SUPPORT
-
debug (
"DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init);
-
if (do_mdm_init) {
-
char *str = strdup(getenv(
"mdm_cmd"));
-
setenv (
"preboot", str);
/* set or delete definition */
-
if (str !=
NULL)
-
free (str);
-
mdm_init();
/* wait for modem connection */
-
}
-
#endif /* CONFIG_MODEM_SUPPORT */
-
-
#ifdef CONFIG_VERSION_VARIABLE
-
{
-
extern
char version_string[];
-
-
setenv (
"ver", version_string);
/* set version variable */
-
}
-
#endif /* CONFIG_VERSION_VARIABLE */
-
-
#ifdef CFG_HUSH_PARSER
-
u_boot_hush_start ();
-
#endif
-
-
#ifdef CONFIG_AUTO_COMPLETE
-
install_auto_complete();
-
#endif
-
-
#ifdef CONFIG_JFFS2_CMDLINE
-
extern int mtdparts_init(void);
-
if (!getenv(
"mtdparts"))
-
{
-
run_command(
"mtdparts default",
0);
-
}
-
else
-
{
-
mtdparts_init();
-
}
-
#endif
-
-
#ifdef CONFIG_PREBOOT
-
if ((p = getenv (
"preboot")) !=
NULL) {
-
# ifdef CONFIG_AUTOBOOT_KEYED
-
int prev = disable_ctrlc(
1);
/* disable Control C checking */
-
# endif
-
-
# ifndef CFG_HUSH_PARSER
-
run_command (p,
0);
-
# else
-
parse_string_outer(p, FLAG_PARSE_SEMICOLON |
-
FLAG_EXIT_FROM_LOOP);
-
# endif
-
-
# ifdef CONFIG_AUTOBOOT_KEYED
-
disable_ctrlc(prev);
/* restore Control C checking */
-
# endif
-
}
-
#endif /* CONFIG_PREBOOT */
-
-
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
-
s = getenv (
"bootdelay");
-
bootdelay = s ? (
int)simple_strtol(s,
NULL,
10) : CONFIG_BOOTDELAY;
-
-
debug (
"### main_loop entered: bootdelay=%d\n\n", bootdelay);
-
-
# ifdef CONFIG_BOOT_RETRY_TIME
-
init_cmd_timeout ();
-
# endif /* CONFIG_BOOT_RETRY_TIME */
-
-
if (PreLoadedONRAM) {
-
printf(
"Use these steps to program the image to flash:\n");
-
printf(
"1. In OpenOCD\n");
-
printf(
" Run the 'halt' command to halt u-boot\n");
-
printf(
" Run the 'load_image <file> <address>' command to load file to SDRAM\n");
-
printf(
" Run the 'resume' command to resume u-boot\n");
-
printf(
"2. In u-boot, use the flash commands to program the image to flash\n");
-
printf(
"Or, use the tftp or nfs command to download file, and then program the flash.\n");
-
goto PROMPT;
-
}
-
-
#ifdef CONFIG_BOOTCOUNT_LIMIT
-
if (bootlimit && (bootcount > bootlimit)) {
-
printf (
"Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
-
(
unsigned)bootlimit);
-
s = getenv (
"altbootcmd");
-
}
-
else
-
#endif
/* CONFIG_BOOTCOUNT_LIMIT */
-
s = getenv (
"bootcmd");
-
-
debug (
"### main_loop: bootcmd=\"%s\"\n", s ? s :
"<UNDEFINED>");
-
-
if (bootdelay >=
0 && s && !abortboot (bootdelay)) {
-
# ifdef CONFIG_AUTOBOOT_KEYED
-
int prev = disable_ctrlc(
1);
/* disable Control C checking */
-
# endif
-
-
# ifndef CFG_HUSH_PARSER
-
{
-
printf(
"Booting Linux ...\n");
-
run_command (s,
0);
-
}
-
# else
-
parse_string_outer(s, FLAG_PARSE_SEMICOLON |
-
FLAG_EXIT_FROM_LOOP);
-
# endif
-
-
# ifdef CONFIG_AUTOBOOT_KEYED
-
disable_ctrlc(prev);
/* restore Control C checking */
-
# endif
-
}
-
-
# ifdef CONFIG_MENUKEY
-
if (menukey == CONFIG_MENUKEY) {
-
s = getenv(
"menucmd");
-
if (s) {
-
# ifndef CFG_HUSH_PARSER
-
run_command (s,
0);
-
# else
-
parse_string_outer(s, FLAG_PARSE_SEMICOLON |
-
FLAG_EXIT_FROM_LOOP);
-
# endif
-
}
-
}
-
#endif /* CONFIG_MENUKEY */
-
#endif /* CONFIG_BOOTDELAY */
-
-
#ifdef CONFIG_AMIGAONEG3SE
-
{
-
extern void video_banner(void);
-
video_banner();
-
}
-
#endif
-
eth_init(gd->bd);
-
run_command(
"menu",
0);
-
/*
-
* Main Loop for Monitor Command Processing
-
*/
-
PROMPT:
-
#ifdef CFG_HUSH_PARSER
-
parse_file_outer();
-
/* This point is never reached */
-
for (;;);
-
#else
-
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 (CFG_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;
-
}
-
}
-
#endif /*CFG_HUSH_PARSER*/
-
}
我们看到这里:
这里首先获得bootcmd的环境变量值,然后打印出相关的信息:我们看一下bootcmd的环境变量值是多少:
我们大概可以推测,这是一条启动内核的两条指令。我们再看下面的代码:
这里是倒计时,。如果在这个倒数计时没到达到0 之前,没有输入空格键,就会打印下面的信息:
也就执行run_command(s,0),这个命令的具体内容下节课讲。