board_init_r和board_init_f差不多,都是执行一个循环。这里是循环执行init_sequence_r[]里的函数指针。
一、board_init_r(common/board_r.c)
void board_init_r(gd_t *new_gd, ulong dest_addr) { #ifdef CONFIG_NEEDS_MANUAL_RELOC int i; #endif #ifdef CONFIG_AVR32 mmu_init_r(dest_addr); #endif #if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64) gd = new_gd; #endif #ifdef CONFIG_NEEDS_MANUAL_RELOC for (i = 0; i < ARRAY_SIZE(init_sequence_r); i++) init_sequence_r[i] += gd->reloc_off; #endif if (initcall_run_list(init_sequence_r)) hang(); /* NOTREACHED - run_main_loop() does not return */ hang(); }
在上一篇博客中我们已经介绍了该函数调用表时会传入两个参数:
- new_gd:为u-boot重定位后的新地址的gd结构;
- dest_addr:u-boot重定位后的地址;
然后循环遍历init_sequence_r中的每一个函数,并执行。
二、init_sequence_r
/* * Over time we hope to remove these functions with code fragments and * stub funtcions, and instead call the relevant function directly. * * We also hope to remove most of the driver-related init and do it if/when * the driver is later used. * * TODO: perhaps reset the watchdog in the initcall function after each call? */ init_fnc_t init_sequence_r[] = { initr_trace, initr_reloc, /* TODO: could x86/PPC have this also perhaps? */ #ifdef CONFIG_ARM initr_caches, /* Note: For Freescale LS2 SoCs, new MMU table is created in DDR. * A temporary mapping of IFC high region is since removed, * so environmental variables in NOR flash is not availble * until board_init() is called below to remap IFC to high * region. */ #endif initr_reloc_global_data, #if defined(CONFIG_SYS_INIT_RAM_LOCK) && defined(CONFIG_E500) initr_unlock_ram_in_cache, #endif initr_barrier, initr_malloc, initr_console_record, #ifdef CONFIG_SYS_NONCACHED_MEMORY initr_noncached, #endif bootstage_relocate, #ifdef CONFIG_DM initr_dm, #endif initr_bootstage, #if defined(CONFIG_ARM) || defined(CONFIG_NDS32) board_init, /* Setup chipselects */ #endif /* * TODO: printing of the clock inforamtion of the board is now * implemented as part of bdinfo command. Currently only support for * davinci SOC's is added. Remove this check once all the board * implement this. */ #ifdef CONFIG_CLOCKS set_cpu_clk_info, /* Setup clock information */ #endif #ifdef CONFIG_EFI_LOADER efi_memory_init, #endif stdio_init_tables, initr_serial, initr_announce, INIT_FUNC_WATCHDOG_RESET #ifdef CONFIG_NEEDS_MANUAL_RELOC initr_manual_reloc_cmdtable, #endif #if defined(CONFIG_PPC) || defined(CONFIG_M68K) initr_trap, #endif #ifdef CONFIG_ADDR_MAP initr_addr_map, #endif #if defined(CONFIG_BOARD_EARLY_INIT_R) board_early_init_r, #endif INIT_FUNC_WATCHDOG_RESET #ifdef CONFIG_LOGBUFFER initr_logbuffer, #endif #ifdef CONFIG_POST initr_post_backlog, #endif INIT_FUNC_WATCHDOG_RESET #ifdef CONFIG_SYS_DELAYED_ICACHE initr_icache_enable, #endif #if defined(CONFIG_PCI) && defined(CONFIG_SYS_EARLY_PCI_INIT) /* * Do early PCI configuration _before_ the flash gets initialised, * because PCU ressources are crucial for flash access on some boards. */ initr_pci, #endif #ifdef CONFIG_WINBOND_83C553 initr_w83c553f, #endif #ifdef CONFIG_ARCH_EARLY_INIT_R arch_early_init_r, #endif power_init_board, #ifndef CONFIG_SYS_NO_FLASH initr_flash, #endif INIT_FUNC_WATCHDOG_RESET #if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_X86) || defined(CONFIG_SPARC) /* initialize higher level parts of CPU like time base and timers */ cpu_init_r, #endif #ifdef CONFIG_PPC initr_spi, #endif #ifdef CONFIG_CMD_NAND initr_nand, #endif #ifdef CONFIG_CMD_ONENAND initr_onenand, #endif #ifdef CONFIG_GENERIC_MMC initr_mmc, #endif #ifdef CONFIG_HAS_DATAFLASH initr_dataflash, #endif initr_env, #ifdef CONFIG_SYS_BOOTPARAMS_LEN initr_malloc_bootparams, #endif INIT_FUNC_WATCHDOG_RESET initr_secondary_cpu, #if defined(CONFIG_ID_EEPROM) || defined(CONFIG_SYS_I2C_MAC_OFFSET) mac_read_from_eeprom, #endif INIT_FUNC_WATCHDOG_RESET #if defined(CONFIG_PCI) && !defined(CONFIG_SYS_EARLY_PCI_INIT) /* * Do pci configuration */ initr_pci, #endif stdio_add_devices, initr_jumptable, #ifdef CONFIG_API initr_api, #endif console_init_r, /* fully init console as a device */ #ifdef CONFIG_DISPLAY_BOARDINFO_LATE show_board_info, #endif #ifdef CONFIG_ARCH_MISC_INIT arch_misc_init, /* miscellaneous arch-dependent init */ #endif #ifdef CONFIG_MISC_INIT_R misc_init_r, /* miscellaneous platform-dependent init */ #endif INIT_FUNC_WATCHDOG_RESET #ifdef CONFIG_CMD_KGDB initr_kgdb, #endif interrupt_init, #if defined(CONFIG_ARM) || defined(CONFIG_AVR32) initr_enable_interrupts, #endif #if defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32) || defined(CONFIG_M68K) timer_init, /* initialize timer */ #endif #if defined(CONFIG_STATUS_LED) initr_status_led, #endif /* PPC has a udelay(20) here dating from 2002. Why? */ #ifdef CONFIG_CMD_NET initr_ethaddr, #endif #ifdef CONFIG_BOARD_LATE_INIT board_late_init, #endif #if defined(CONFIG_CMD_AMBAPP) ambapp_init_reloc, #if defined(CONFIG_SYS_AMBAPP_PRINT_ON_STARTUP) initr_ambapp_print, #endif #endif #ifdef CONFIG_CMD_SCSI INIT_FUNC_WATCHDOG_RESET initr_scsi, #endif #ifdef CONFIG_CMD_DOC INIT_FUNC_WATCHDOG_RESET initr_doc, #endif #ifdef CONFIG_BITBANGMII initr_bbmii, #endif #ifdef CONFIG_CMD_NET INIT_FUNC_WATCHDOG_RESET initr_net, #endif #ifdef CONFIG_POST initr_post, #endif #if defined(CONFIG_CMD_PCMCIA) && !defined(CONFIG_CMD_IDE) initr_pcmcia, #endif #if defined(CONFIG_CMD_IDE) initr_ide, #endif #ifdef CONFIG_LAST_STAGE_INIT INIT_FUNC_WATCHDOG_RESET /* * Some parts can be only initialized if all others (like * Interrupts) are up and running (i.e. the PC-style ISA * keyboard). */ last_stage_init, #endif #ifdef CONFIG_CMD_BEDBUG INIT_FUNC_WATCHDOG_RESET initr_bedbug, #endif #if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER) initr_mem, #endif #ifdef CONFIG_PS2KBD initr_kbd, #endif #if defined(CONFIG_SPARC) prom_init, #endif run_main_loop, };
通过反汇编代码我们可以确定实际定义了哪些函数:
0007220c <init_sequence_r>: 7220c: 0000eab0 .word 0x0000eab0 initr_trace 72210: 0000eab8 .word 0x0000eab8 initr_reloc 72214: 0000ec88 .word 0x0000ec88 initr_caches 72218: 0000ead0 .word 0x0000ead0 initr_reloc_global_data 7221c: 0000eaf8 .word 0x0000eaf8 initr_barrier 72220: 0000ec6c .word 0x0000ec6c initr_malloc 72224: 0000eb00 .word 0x0000eb00 initr_console_record 72228: 0000ea8c .word 0x0000ea8c bootstage_relocate 7222c: 0000ec58 .word 0x0000ec58 initr_bootstage 72230: 0000111c .word 0x0000111c board_init 72234: 000163c8 .word 0x000163c8 stdio_init_tables 72238: 0000ec48 .word 0x0000ec48 initr_serial 7223c: 0000eb10 .word 0x0000eb10 initr_announce 72240: 0000eb08 .word 0x0000eb08 power_init_board 72244: 0000ebcc .word 0x0000ebcc initr_flash 72248: 0000ebb0 .word 0x0000ebb0 initr_nand 7224c: 0000eb80 .word 0x0000eb80 initr_env 72250: 0000eaa0 .word 0x0000eaa0 initr_secondary_cpu 72254: 00016488 .word 0x00016488 stdio_add_devices 72258: 0000eb70 .word 0x0000eb70 initr_jumptable 7225c: 000146e0 .word 0x000146e0 console_init_r 72260: 00000ae0 .word 0x00000ae0 interrupt_init 72264: 0000eb60 .word 0x0000eb60 initr_enable_interrupts 72268: 0000eb40 .word 0x0000eb40 initr_ethaddr 7226c: 0000eb24 .word 0x0000eb24 initr_net 72270: 0000eb18 .word 0x0000eb18 run_main_loop
三、各个函数指针
3.1 initr_trace(common/board_r.c)
static int initr_trace(void) { #ifdef CONFIG_TRACE trace_init(gd->trace_buff, CONFIG_TRACE_BUFFER_SIZE); #endif return 0; }
3.2 initr_reloc(common/board_r.c)
static int initr_reloc(void) { /* tell others: relocation done */ gd->flags |= GD_FLG_RELOC | GD_FLG_FULL_MALLOC_INIT; return 0; }
常量GD_FLG_RELOC 和GD_FLG_FULL_MALLOC_INIT定义如下:
/* * Global Data Flags - the top 16 bits are reserved for arch-specific flags */ #define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */ #define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */ #define GD_FLG_SILENT 0x00004 /* Silent mode */ #define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */ #define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */ #define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */ #define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */ #define GD_FLG_ENV_READY 0x00080 /* Env. imported into hash table */ #define GD_FLG_SERIAL_READY 0x00100 /* Pre-reloc serial console ready */ #define GD_FLG_FULL_MALLOC_INIT 0x00200 /* Full malloc() is ready */ #define GD_FLG_SPL_INIT 0x00400 /* spl_init() has been called */ #define GD_FLG_SKIP_RELOC 0x00800 /* Don't relocate */ #define GD_FLG_RECORD 0x01000 /* Record console */
设置gd->flags标志位第1位、第10位为1。
3.3 initr_caches(common/board_r.c)
static int initr_caches(void) { /* Enable caches */ enable_caches(); return 0; }
enable_caches()使能缓存,定义在arch/arm/lib/cache.c:
/* * Default implementation of enable_caches() * Real implementation should be in platform code */ __weak void enable_caches(void) { puts("WARNING: Caches not enabledn"); }
3.4 initr_reloc_global_data(common/board_r.c)
static int initr_reloc_global_data(void) { #ifdef __ARM__ monitor_flash_len = _end - __image_copy_start; #elif defined(CONFIG_NDS32) monitor_flash_len = (ulong)&_end - (ulong)&_start; #elif !defined(CONFIG_SANDBOX) && !defined(CONFIG_NIOS2) monitor_flash_len = (ulong)&__init_end - gd->relocaddr; #endif #if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx) /* * The gd->cpu pointer is set to an address in flash before relocation. * We need to update it to point to the same CPU entry in RAM. * TODO: why not just add gd->reloc_ofs? */ gd->arch.cpu += gd->relocaddr - CONFIG_SYS_MONITOR_BASE; /* * If we didn't know the cpu mask & # cores, we can save them of * now rather than 'computing' them constantly */ fixup_cpu(); #endif #ifdef CONFIG_SYS_EXTRA_ENV_RELOC /* * Some systems need to relocate the env_addr pointer early because the * location it points to will get invalidated before env_relocate is * called. One example is on systems that might use a L2 or L3 cache * in SRAM mode and initialize that cache from SRAM mode back to being * a cache in cpu_init_r. */ gd->env_addr += gd->relocaddr - CONFIG_SYS_MONITOR_BASE; #endif #ifdef CONFIG_OF_EMBED /* * The fdt_blob needs to be moved to new relocation address * incase of FDT blob is embedded with in image */ gd->fdt_blob += gd->reloc_off; #endif #ifdef CONFIG_EFI_LOADER efi_runtime_relocate(gd->relocaddr, NULL); #endif return 0; }
全局变量monitor_flash_len定义:
ulong monitor_flash_len;
其中_end和rel_dyn_end 值是一样的。
3.5 initr_barrier(common/board_r.c)
static int initr_barrier(void) { #ifdef CONFIG_PPC /* TODO: Can we not use dmb() macros for this? */ asm("sync ; isync"); #endif return 0; }
3.6 initr_malloc(common/board_r.c)
static int initr_malloc(void) { ulong malloc_start; #ifdef CONFIG_SYS_MALLOC_F_LEN debug("Pre-reloc malloc() used %#lx bytes (%ld KB)n", gd->malloc_ptr, gd->malloc_ptr / 1024); #endif /* The malloc area is immediately below the monitor copy in DRAM */ malloc_start = gd->relocaddr - TOTAL_MALLOC_LEN; mem_malloc_init((ulong)map_sysmem(malloc_start, TOTAL_MALLOC_LEN), TOTAL_MALLOC_LEN); return 0; }
从board_init_f画出的内存图可知,u-boot重定位地址的下面就是预留的堆区。
设置malloc的起始地址,malloc_start设置为u-boot重定位后的地址-TOTAL_MALLOC_LEN,TOTAL_MALLOC_LEN之前有介绍4MB。
然后填充了三个全局变量并将堆区全部清零:
void mem_malloc_init(ulong start, ulong size) { mem_malloc_start = start; mem_malloc_end = start + size; mem_malloc_brk = start; debug("using memory %#lx-%#lx for malloc()n", mem_malloc_start, mem_malloc_end); #ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT /* 定义这个宏则堆区初始化为0,否则不初始化 */ memset((void *)mem_malloc_start, 0x0, size); #endif malloc_bin_reloc(); }
3.7 initr_console_record(common/board_r.c)
static int initr_console_record(void) { #if defined(CONFIG_CONSOLE_RECORD) return console_record_init(); #else return 0; #endif }
3.8 bootstage_relocate(common/bootstage.c)
int bootstage_relocate(void) { int i; /* * Duplicate all strings. They may point to an old location in the * program .text section that can eventually get trashed. */ for (i = 0; i < BOOTSTAGE_ID_COUNT; i++) if (record[i].name) record[i].name = strdup(record[i].name); return 0; }
3.9 initr_bootstage(common/board_r.c)
static int initr_bootstage(void) { /* We cannot do this before initr_dm() */ bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r"); return 0; }
标记BOOTSTAGE_ID_START_UBOOT_R阶段信息。
3.10 board_init(board/samsung/smdk2410/smdk2410.c)
int board_init(void) { /* arch number of SMDK2410-Board */ gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; /* adress of boot parameters */ gd->bd->bi_boot_params = 0x30000100; icache_enable(); dcache_enable(); return 0; }
gd->bd->bi_arch_number修改成SMDK2410的机器码,启动linux需要的,但实际测试,这个就算不设置也能够启动,但我们还是将其添加上(可在arch/arm/include/asm/mach-types.h中找到。
#define MACH_TYPE_SMDK2410 193
然后设置gd->bd->bi_boot_params,从0x30000100地址开始存放启动参数,内核启动时会从这里取出参数。
3.11 stdio_init_tables(common/sdtio.c)
int stdio_init_tables(void) { #if defined(CONFIG_NEEDS_MANUAL_RELOC) /* already relocated for current ARM implementation */ ulong relocation_offset = gd->reloc_off; int i; /* relocate device name pointers */ for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) { stdio_names[i] = (char *) (((ulong) stdio_names[i]) + relocation_offset); } #endif /* CONFIG_NEEDS_MANUAL_RELOC */ /* Initialize the list */ INIT_LIST_HEAD(&(devs.list)); return 0; }
初始化了一个双向循环链表:
static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; }
3.12 initr_serial(common/board_r.c)注册串口驱动
static int initr_serial(void) { serial_initialize(); return 0; }
serial_initialize定义在drivers/serial/serial.c文件:
/** * serial_initialize() - Register all compiled-in serial port drivers * * This function registers all serial port drivers that are compiled * into the U-Boot binary with the serial core, thus making them * available to U-Boot to use. Lastly, this function assigns a default * serial port to the serial core. That serial port is then used as a * default output. */ void serial_initialize(void) { amirix_serial_initialize(); arc_serial_initialize(); arm_dcc_initialize(); asc_serial_initialize(); atmel_serial_initialize(); au1x00_serial_initialize(); bfin_jtag_initialize(); bfin_serial_initialize(); bmw_serial_initialize(); clps7111_serial_initialize(); cogent_serial_initialize(); cpci750_serial_initialize(); evb64260_serial_initialize(); imx_serial_initialize(); iop480_serial_initialize(); jz_serial_initialize(); leon2_serial_initialize(); leon3_serial_initialize(); lh7a40x_serial_initialize(); lpc32xx_serial_initialize(); marvell_serial_initialize(); max3100_serial_initialize(); mcf_serial_initialize(); ml2_serial_initialize(); mpc512x_serial_initialize(); mpc5xx_serial_initialize(); mpc8260_scc_serial_initialize(); mpc8260_smc_serial_initialize(); mpc85xx_serial_initialize(); mpc8xx_serial_initialize(); mxc_serial_initialize(); mxs_auart_initialize(); ns16550_serial_initialize(); oc_serial_initialize(); p3mx_serial_initialize(); pl01x_serial_initialize(); pxa_serial_initialize(); s3c24xx_serial_initialize(); s5p_serial_initialize(); sa1100_serial_initialize(); sandbox_serial_initialize(); sconsole_serial_initialize(); sh_serial_initialize(); stm32_serial_initialize(); uartlite_serial_initialize(); zynq_serial_initialize(); serial_assign(default_serial_console()->name); }
串口设备注册:
void s3c24xx_serial_initialize(void) { serial_register(&s3c24xx_serial0_device); serial_register(&s3c24xx_serial1_device); serial_register(&s3c24xx_serial2_device); }
/** * serial_register() - Register serial driver with serial driver core * @dev: Pointer to the serial driver structure * * This function registers the serial driver supplied via @dev with * serial driver core, thus making U-Boot aware of it and making it * available for U-Boot to use. On platforms that still require manual * relocation of constant variables, relocation of the supplied structure * is performed. */ void serial_register(struct serial_device *dev) { #ifdef CONFIG_NEEDS_MANUAL_RELOC if (dev->start) dev->start += gd->reloc_off; if (dev->stop) dev->stop += gd->reloc_off; if (dev->setbrg) dev->setbrg += gd->reloc_off; if (dev->getc) dev->getc += gd->reloc_off; if (dev->tstc) dev->tstc += gd->reloc_off; if (dev->putc) dev->putc += gd->reloc_off; if (dev->puts) dev->puts += gd->reloc_off; #endif dev->next = serial_devices; serial_devices = dev; }
static struct serial_device *serial_devices;
struct serial_device { /* enough bytes to match alignment of following func pointer */ char name[16]; int (*start)(void); int (*stop)(void); void (*setbrg)(void); int (*getc)(void); int (*tstc)(void); void (*putc)(const char c); void (*puts)(const char *s); #if CONFIG_POST & CONFIG_SYS_POST_UART void (*loop)(int); #endif struct serial_device *next; };
这段代码执行完之后串口设备指针serial_devices指向如下图,可以看出这个一个单向链表结构:
3.13 initr_announce(common/board_r.c)
static int initr_announce(void) { debug("Now running in RAM - U-Boot at: %08lxn", gd->relocaddr); return 0; }
3.14 power_init_board(common/board_r.c)
__weak int power_init_board(void) { return 0; }
3.15 initr_flash(common/board_r.c)初始化NOR FLASH
static int initr_flash(void) { ulong flash_size = 0; bd_t *bd = gd->bd; puts("Flash: "); if (board_flash_wp_on()) printf("Uninitialized - Write Protect Onn"); else flash_size = flash_init(); print_size(flash_size, ""); #ifdef CONFIG_SYS_FLASH_CHECKSUM /* * Compute and print flash CRC if flashchecksum is set to 'y' * * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX */ if (getenv_yesno("flashchecksum") == 1) { printf(" CRC: %08X", crc32(0, (const unsigned char *) CONFIG_SYS_FLASH_BASE, flash_size)); } #endif /* CONFIG_SYS_FLASH_CHECKSUM */ putc('n'); /* update start of FLASH memory */ #ifdef CONFIG_SYS_FLASH_BASE bd->bi_flashstart = CONFIG_SYS_FLASH_BASE; #endif /* size of FLASH memory (final value) */ bd->bi_flashsize = flash_size; #if defined(CONFIG_SYS_UPDATE_FLASH_SIZE) /* Make a update of the Memctrl. */ update_flash_size(flash_size); #endif #if defined(CONFIG_OXC) || defined(CONFIG_RMU) /* flash mapped at end of memory map */ bd->bi_flashoffset = CONFIG_SYS_TEXT_BASE + flash_size; #elif CONFIG_SYS_MONITOR_BASE == CONFIG_SYS_FLASH_BASE bd->bi_flashoffset = monitor_flash_len; /* reserved area for monitor */ #endif return 0; }
flash_init用于初始化NOR FLASH。该函数在driversmtdcfi_flash.c中定义:
unsigned long flash_init (void) { unsigned long size = 0; int i; #ifdef CONFIG_SYS_FLASH_PROTECTION /* read environment from EEPROM */ char s[64]; getenv_f("unlock", s, sizeof(s)); #endif #ifdef CONFIG_CFI_FLASH /* for driver model */ cfi_flash_init_dm(); #endif /* Init: no FLASHes known */ for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) { flash_info[i].flash_id = FLASH_UNKNOWN; /* Optionally write flash configuration register */ cfi_flash_set_config_reg(cfi_flash_bank_addr(i), cfi_flash_config_reg(i)); if (!flash_detect_legacy(cfi_flash_bank_addr(i), i)) flash_get_size(cfi_flash_bank_addr(i), i); size += flash_info[i].size; if (flash_info[i].flash_id == FLASH_UNKNOWN) { #ifndef CONFIG_SYS_FLASH_QUIET_TEST printf ("## Unknown flash on Bank %d " "- Size = 0x%08lx = %ld MBn", i+1, flash_info[i].size, flash_info[i].size >> 20); #endif /* CONFIG_SYS_FLASH_QUIET_TEST */ } #ifdef CONFIG_SYS_FLASH_PROTECTION else if (strcmp(s, "yes") == 0) { /* * Only the U-Boot image and it's environment * is protected, all other sectors are * unprotected (unlocked) if flash hardware * protection is used (CONFIG_SYS_FLASH_PROTECTION) * and the environment variable "unlock" is * set to "yes". */ if (flash_info[i].legacy_unlock) { int k; /* * Disable legacy_unlock temporarily, * since flash_real_protect would * relock all other sectors again * otherwise. */ flash_info[i].legacy_unlock = 0; /* * Legacy unlocking (e.g. Intel J3) -> * unlock only one sector. This will * unlock all sectors. */ flash_real_protect (&flash_info[i], 0, 0); flash_info[i].legacy_unlock = 1; /* * Manually mark other sectors as * unlocked (unprotected) */ for (k = 1; k < flash_info[i].sector_count; k++) flash_info[i].protect[k] = 0; } else { /* * No legancy unlocking -> unlock all sectors */ flash_protect (FLAG_PROTECT_CLEAR, flash_info[i].start[0], flash_info[i].start[0] + flash_info[i].size - 1, &flash_info[i]); } } #endif /* CONFIG_SYS_FLASH_PROTECTION */ } flash_protect_default(); #ifdef CONFIG_FLASH_CFI_MTD cfi_mtd_init(); #endif return (size); }
3.16 initr_nand(common/board_r.c)初始化NAND FLASH
static int initr_nand(void) { puts("NAND: "); nand_init(); return 0; }
初始化nand flash,并输出nand falsh信息。其中nand_init()定义在drivers/mtd/nand/nand.c文件中:
void nand_init(void) { #ifdef CONFIG_SYS_NAND_SELF_INIT board_nand_init(); #else int i; for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) nand_init_chip(i); #endif printf("%lu MiBn", total_nand_size / 1024); #ifdef CONFIG_SYS_NAND_SELECT_DEVICE /* * Select the chip in the board/cpu specific driver */ board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device); #endif }
nand_init_chip定义:
#ifndef CONFIG_SYS_NAND_SELF_INIT static void nand_init_chip(int i) { struct mtd_info *mtd = &nand_info[i]; struct nand_chip *nand = &nand_chip[i]; ulong base_addr = base_address[i]; int maxchips = CONFIG_SYS_NAND_MAX_CHIPS; if (maxchips < 1) maxchips = 1; mtd->priv = nand; nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr; if (board_nand_init(nand)) return; if (nand_scan(mtd, maxchips)) return; nand_register(i); } #endif
board_nand_init在drivers/mtd/nand/s3c2410_nand.c文件中定义:
int board_nand_init(struct nand_chip *nand) { u_int32_t cfg; u_int8_t tacls, twrph0, twrph1; struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power(); struct s3c24x0_nand *nand_reg = s3c24x0_get_base_nand(); debug("board_nand_init()n"); writel(readl(&clk_power->clkcon) | (1 << 4), &clk_power->clkcon); /* initialize hardware */ #if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING) tacls = CONFIG_S3C24XX_TACLS; twrph0 = CONFIG_S3C24XX_TWRPH0; twrph1 = CONFIG_S3C24XX_TWRPH1; #else tacls = 4; twrph0 = 8; twrph1 = 8; #endif cfg = S3C2410_NFCONF_EN; cfg |= S3C2410_NFCONF_TACLS(tacls - 1); cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); writel(cfg, &nand_reg->nfconf); /* initialize nand_chip data structure */ nand->IO_ADDR_R = (void *)&nand_reg->nfdata; nand->IO_ADDR_W = (void *)&nand_reg->nfdata; nand->select_chip = NULL; /* read_buf and write_buf are default */ /* read_byte and write_byte are default */ #ifdef CONFIG_NAND_SPL nand->read_buf = nand_read_buf; #endif /* hwcontrol always must be implemented */ nand->cmd_ctrl = s3c24x0_hwcontrol; nand->dev_ready = s3c24x0_dev_ready; #ifdef CONFIG_S3C2410_NAND_HWECC nand->ecc.hwctl = s3c24x0_nand_enable_hwecc; nand->ecc.calculate = s3c24x0_nand_calculate_ecc; nand->ecc.correct = s3c24x0_nand_correct_data; nand->ecc.mode = NAND_ECC_HW; nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; nand->ecc.strength = 1; #else nand->ecc.mode = NAND_ECC_SOFT; #endif #ifdef CONFIG_S3C2410_NAND_BBT nand->bbt_options |= NAND_BBT_USE_FLASH; #endif debug("end of nand_initn"); return 0; }
3.17 initr_env(common/board_r.c)
static int initr_env(void) { /* initialize environment */ if (should_load_env()) env_relocate(); else set_default_env(NULL); #ifdef CONFIG_OF_CONTROL setenv_addr("fdtcontroladdr", gd->fdt_blob); #endif /* Initialize from environment */ load_addr = getenv_ulong("loadaddr", 16, load_addr); #if defined(CONFIG_SYS_EXTBDINFO) #if defined(CONFIG_405GP) || defined(CONFIG_405EP) #if defined(CONFIG_I2CFAST) /* * set bi_iic_fast for linux taking environment variable * "i2cfast" into account */ { char *s = getenv("i2cfast"); if (s && ((*s == 'y') || (*s == 'Y'))) { gd->bd->bi_iic_fast[0] = 1; gd->bd->bi_iic_fast[1] = 1; } } #endif /* CONFIG_I2CFAST */ #endif /* CONFIG_405GP, CONFIG_405EP */ #endif /* CONFIG_SYS_EXTBDINFO */ return 0; }
其中should_load_env定义如下:
static int should_load_env(void) { #ifdef CONFIG_OF_CONTROL return fdtdec_get_config_int(gd->fdt_blob, "load-environment", 1); #elif defined CONFIG_DELAY_ENVIRONMENT return 0; #else return 1; #endif }
然后执行env_relocate:
void env_relocate(void) { #if defined(CONFIG_NEEDS_MANUAL_RELOC) env_reloc(); env_htab.change_ok += gd->reloc_off; #endif if (gd->env_valid == 0) { #if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD) /* Environment not changable */ set_default_env(NULL); #else bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM); set_default_env("!bad CRC"); #endif } else { env_relocate_spec(); } }
这里介绍一下set_default_env:
void set_default_env(const char *s) { int flags = 0; /* 我们的环境变量没配置过,正常是不会超出范围 */ if (sizeof(default_environment) > ENV_SIZE) { puts("*** Error - default environment is too largenn"); return; } /* 上面传进来的是"!bad CRC" */ if (s) { if (*s == '!') { /* 第一个字符是'!' */ printf("*** Warning - %s, " "using default environmentnn", s + 1); /* 跳过!,打印我们看到的一样 */ } else { flags = H_INTERACTIVE; puts(s); } } else { puts("Using default environmentnn"); } if (himport_r(&env_htab, (char *)default_environment, sizeof(default_environment), ' ', flags, 0, 0, NULL) == 0) error("Environment import failed: errno = %dn", errno); /* 标记使用默认环境变量和环境变量成功 */ gd->flags |= GD_FLG_ENV_READY; }
himport_r函数设置环境变量default_environment到Hash Table表中:
/* * Import linearized data into hash table. * * This is the inverse function to hexport(): it takes a linear list * of "name=value" pairs and creates hash table entries from it. * * Entries without "value", i. e. consisting of only "name" or * "name=", will cause this entry to be deleted from the hash table. * * The "flag" argument can be used to control the behaviour: when the * H_NOCLEAR bit is set, then an existing hash table will kept, i. e. * new data will be added to an existing hash table; otherwise, old * data will be discarded and a new hash table will be created. * * The separator character for the "name=value" pairs can be selected, * so we both support importing from externally stored environment * data (separated by NUL characters) and from plain text files * (entries separated by newline characters). * * To allow for nicely formatted text input, leading white space * (sequences of SPACE and TAB chars) is ignored, and entries starting * (after removal of any leading white space) with a '#' character are * considered comments and ignored. * * [NOTE: this means that a variable name cannot start with a '#' * character.] * * When using a non-NUL separator character, backslash is used as * escape character in the value part, allowing for example for * multi-line values. * * In theory, arbitrary separator characters can be used, but only * ' ' and 'n' have really been tested. */ int himport_r(struct hsearch_data *htab, const char *env, size_t size, const char sep, int flag, int crlf_is_lf, int nvars, char * const vars[]) { char *data, *sp, *dp, *name, *value; char *localvars[nvars]; int i; /* Test for correct arguments. */ if (htab == NULL) { __set_errno(EINVAL); return 0; } /* we allocate new space to make sure we can write to the array */ if ((data = malloc(size + 1)) == NULL) { debug("himport_r: can't malloc %zu bytesn", size + 1); __set_errno(ENOMEM); return 0; } memcpy(data, env, size); data[size] = '