uboot——启动第二阶段分析
来源:互联网 发布:舒尔特表训练软件 编辑:程序博客网 时间:2024/06/06 17:58
uboot中一个很长的函数start_armboot构成了整个uboot启动的第二阶段,在这个很长的函数中还调用了其他函数用来实现很多功能。
1、init_sequence
init_fnc_t *init_sequence[] = { cpu_init, /* basic cpu dependent setup */#if defined(CONFIG_SKIP_RELOCATE_UBOOT) reloc_init, /* Set the relocation done flag, must do this AFTER cpu_init(), but as soon as possible */#endif 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#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) init_func_i2c,#endif dram_init, /* configure available RAM banks */ display_dram_config, NULL,};
init_sequence是一个函数指针数组,数组中存储了很多个函数指针,这些指向指向的函数都是init_fnc_t类型(特征是接收参数是void类型,返回值是int)。通过一个for循环实现遍历,将所有的函数调用。都是板级硬件的初始化以及gd、gd->bd中的数据结构的初始化。
譬如:
网卡初始化、机器码(gd->bd->bi_arch_number)、内核传参DDR地址(gd->bd->bi_boot_params)、Timer4初始化为10ms一次、波特率设置(gd->bd->bi_baudrate和gd->baudrate)、console第一阶段初始化(gd->have_console设置为1)、打印uboot的启动信息、打印cpu相关设置信息、检查并打印当前开发板名字、DDR配置信息初始化(gd->bd->bi_dram)、打印DDR总容量。
cpu_init 空的
board_init 网卡、机器码、内存传参地址
dm9000_pre_init 网卡
gd->bd->bi_arch_number 机器码
gd->bd->bi_boot_params 内存传参地址
interrupt_init 定时器
env_init
init_baudrate gd数据结构中波特率
serial_init 空的
console_init_f 空的
display_banner 打印启动信息
print_cpuinfo 打印CPU时钟设置信息
checkboard 检验开发板名字
dram_init gd数据结构中DDR信息
display_dram_config 打印DDR配置信息表
结构体 gd_t
typedef struct global_data { bd_t *bd; unsigned long flags; unsigned long baudrate; unsigned long have_console; /* serial_init() was called */ unsigned long reloc_off; /* Relocation Offset */ 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#if 0 unsigned long cpu_clk; /* CPU clock in Hz! */ unsigned long bus_clk; phys_size_t ram_size; /* RAM size */ unsigned long reset_status; /* reset status register at boot */#endif void **jt; /* jump table */} gd_t;
结构体bd_t
typedef struct bd_info { int bi_baudrate; /* serial console baudrate */ unsigned long bi_ip_addr; /* IP Address */ unsigned char bi_enetaddr[6]; /* Ethernet adress */ struct environment_s *bi_env; 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];#ifdef CONFIG_HAS_ETH1 /* second onboard ethernet port */ unsigned char bi_enet1addr[6];#endif} bd_t;
2、mem_malloc_init
初始化uboot自己维护的堆管理器的内存
(1)mem_malloc_init函数用来初始化uboot的堆管理器。
(2)uboot中自己维护了一段堆内存,肯定自己就有一套代码来管理这个堆内存。有了这些东西uboot中你也可以malloc、free这套机制来申请内存和释放内存。我们在DDR内存中给堆预留了896KB的内存。
/* armboot_start is defined in the board-specific linker script */#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */ mem_malloc_init (CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE);#else mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);#endifstatic void mem_malloc_init (ulong dest_addr){ mem_malloc_start = dest_addr; mem_malloc_end = dest_addr + CFG_MALLOC_LEN; mem_malloc_brk = mem_malloc_start; memset ((void *) mem_malloc_start, 0, mem_malloc_end - mem_malloc_start);}
3、mmc_initialize
inand/SD卡的SoC控制器和卡的初始化
(1)mmc_initialize看名字就应该是MMC相关的一些基础的初始化,其实就是用来初始化SoC内部的SD/MMC控制器的。函数在uboot/drivers/mmc/mmc.c里。
(2)uboot中对硬件的操作(譬如网卡、SD卡···)都是借用的linux内核中的驱动来实现的,uboot根目录底下有个drivers文件夹,这里面放的全都是从linux内核中移植过来的各种驱动源文件。
(3)mmc_initialize是具体硬件架构无关的一个MMC初始化函数,所有的使用了这套架构的代码都掉用这个函数来完成MMC的初始化。mmc_initialize中再调用board_mmc_init和cpu_mmc_init来完成具体的硬件的MMC控制器初始化工作。
(4)cpu_mmc_init在uboot/cpu/s5pc11x/cpu.c中,这里面又间接的调用了drivers/mmc/s3c_mmcxxx.c中的驱动代码来初始化硬件MMC控制器。这里面分层很多,分层的思想一定要有,否则完全就糊涂了。
#if defined(CONFIG_X210) #if defined(CONFIG_GENERIC_MMC) puts ("SD/MMC: "); mmc_exist = mmc_initialize(gd->bd); if (mmc_exist != 0) { puts ("0 MB\n");#ifdef CONFIG_CHECK_X210CV3 check_flash_flag=0;//check inand error!#endif }#ifdef CONFIG_CHECK_X210CV3 else { check_flash_flag=1;//check inand ok! }#endif #endif #if defined(CONFIG_MTD_ONENAND) puts("OneNAND: "); onenand_init(); /*setenv("bootcmd", "onenand read c0008000 80000 380000;bootm c0008000");*/ #else //puts("OneNAND: (FSR layer enabled)\n"); #endif #if defined(CONFIG_CMD_NAND) puts("NAND: "); nand_init(); #endif#endif /* CONFIG_X210 */
4、env_relocate
环境变量重定位
1)env_relocate是环境变量的重定位,完成从SD卡中将环境变量读取到DDR中的任务。
(2)环境变量到底从哪里来?SD卡中有一些(8个)独立的扇区作为环境变量存储区域的。但是我们烧录/部署系统时,我们只是烧录了uboot分区、kernel分区和rootfs分区,根本不曾烧录env分区。所以当我们烧录完系统第一次启动时ENV分区是空的,本次启动uboot尝试去SD卡的ENV分区读取环境变量时失败(读取回来后进行CRC校验时失败),我们uboot选择从uboot内部代码中设置的一套默认的环境变量出发来使用(这就是默认环境变量);这套默认的环境变量在本次运行时会被读取到DDR中的环境变量中,然后被写入(也可能是你saveenv时写入,也可能是uboot设计了第一次读取默认环境变量后就写入)SD卡的ENV分区。然后下次再次开机时uboot就会从SD卡的ENV分区读取环境变量到DDR中,这次读取就不会失败了。
(3)真正的从SD卡到DDR中重定位ENV的代码是在env_relocate_spec内部的movi_read_env完成的。
void env_relocate (void){ DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__, gd->reloc_off);#ifdef CONFIG_AMIGAONEG3SE enable_nvram();#endif#ifdef ENV_IS_EMBEDDED /* * The environment buffer is embedded with the text segment, * just relocate the environment pointer */ env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off); DEBUGF ("%s[%d] embedded ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);#else /* * We must allocate a buffer for the environment */ env_ptr = (env_t *)malloc (CFG_ENV_SIZE); DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);#endif if (gd->env_valid == 0) {#if defined(CONFIG_GTH) || defined(CFG_ENV_IS_NOWHERE) /* Environment not changable */ puts ("Using default environment\n\n");#else puts ("*** Warning - bad CRC, using default environment\n\n"); show_boot_progress (-60);#endif set_default_env(); } else { env_relocate_spec (); } gd->env_addr = (ulong)&(env_ptr->data);#ifdef CONFIG_AMIGAONEG3SE disable_nvram();#endif}
5、 devices_init 空的
jumptable_init 不用关注的
devices_init (); /* get the devices list going. */jumptable_init ();
6、console_init_r
真正的控制台初始化
(1)console_init_f是控制台的第一阶段初始化,console_init_r是第二阶段初始化。实际上第一阶段初始化并没有实质性工作,第二阶段初始化才进行了实质性工作。
(2)console_init_r就是console的纯软件架构方面的初始化(说白了就是去给console相关的数据结构中填充相应的值),所以属于纯软件配置类型的初始化。
(3)uboot的console实际上并没有干有意义的转化,它就是直接调用的串口通信的函数。所以用不用console实际并没有什么分别。(在linux内console就可以提供缓冲机制等不用console不能实现的东西)。
/* Called after the relocation - use desired console functions */int console_init_r (void){ device_t *inputdev = NULL, *outputdev = NULL; int i, items = ListNumItems (devlist);#ifdef CONFIG_SPLASH_SCREEN /* suppress all output if splash screen is enabled and we have a bmp to display */ if (getenv("splashimage") != NULL) gd->flags |= GD_FLG_SILENT;#endif /* Scan devices looking for input and output devices */ for (i = 1; (i <= items) && ((inputdev == NULL) || (outputdev == NULL)); i++ ) { device_t *dev = ListGetPtrToItem (devlist, i); if ((dev->flags & DEV_FLAGS_INPUT) && (inputdev == NULL)) { inputdev = dev; } if ((dev->flags & DEV_FLAGS_OUTPUT) && (outputdev == NULL)) { outputdev = dev; } } /* Initializes output console first */ if (outputdev != NULL) { console_setfile (stdout, outputdev); console_setfile (stderr, outputdev); } /* Initializes input console */ if (inputdev != NULL) { console_setfile (stdin, inputdev); } gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */#ifndef CFG_CONSOLE_INFO_QUIET /* Print information */ puts ("In: "); if (stdio_devices[stdin] == NULL) { puts ("No input devices available!\n"); } else { printf ("%s\n", stdio_devices[stdin]->name); } puts ("Out: "); if (stdio_devices[stdout] == NULL) { puts ("No output devices available!\n"); } else { printf ("%s\n", stdio_devices[stdout]->name); } puts ("Err: "); if (stdio_devices[stderr] == NULL) { puts ("No error devices available!\n"); } else { printf ("%s\n", stdio_devices[stderr]->name); }#endif /* CFG_CONSOLE_INFO_QUIET */#ifndef CONFIG_X210 /* Setting environment variables */ for (i = 0; i < 3; i++) { setenv (stdio_names[i], stdio_devices[i]->name); }#endif#if 0 /* If nothing usable installed, use only the initial console */ if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) return (0);#endif return (0);}
7、enable_interrupts 、 board_late_init 和 eth_initialize
空的
void enable_interrupts (void){ return;}
8、x210_preboot_init
LCD初始化和显示logo
int x210_preboot_init(void){ mpadfb_init(); return 1;}
9、check_menu_update_from_sd
检查自动更新
/* * GPH0_2: LEFT */static int check_menu_update_from_sd(void){ unsigned int i; unsigned int reg; //GPH0_2 reg = readl(GPH0CON); reg = reg & ~(0xf<<8) | (0x0<<8); writel(reg,GPH0CON); for(i=0;i<100;i++) udelay(500); reg = readl(GPH0DAT); reg = reg & (0x1<<2); if(reg) return 1; else //update mode return 0;}
10、main_loop
主循环,不负责任的认为是一个死循环。
总结:第二阶段主要是对开发板级别的硬件、软件数据结构进行初始化。
init_sequence
cpu_init 空的
board_init 网卡、机器码、内存传参地址
dm9000_pre_init 网卡
gd->bd->bi_arch_number 机器码
gd->bd->bi_boot_params 内存传参地址
interrupt_init 定时器
env_init
init_baudrate gd数据结构中波特率
serial_init 空的
console_init_f 空的
display_banner 打印启动信息
print_cpuinfo 打印CPU时钟设置信息
checkboard 检验开发板名字
dram_init gd数据结构中DDR信息
display_dram_config 打印DDR配置信息表
mem_malloc_init 初始化uboot自己维护的堆管理器的内存
mmc_initialize inand/SD卡的SoC控制器和卡的初始化
env_relocate 环境变量重定位
gd->bd->bi_ip_addr gd数据结构赋值
gd->bd->bi_enetaddr gd数据结构赋值
devices_init 空的
jumptable_init 不用关注的
console_init_r 真正的控制台初始化
enable_interrupts 空的
loadaddr、bootfile 环境变量读出初始化全局变量
board_late_init 空的
eth_initialize 空的
x210_preboot_init LCD初始化和显示logo
check_menu_update_from_sd 检查自动更新
main_loop 主循环
启动过程特征总结
(1)第一阶段为汇编阶段、第二阶段为C阶段
(2)第一阶段在SRAM中、第二阶段在DRAM中
(3)第一阶段注重SoC内部、第二阶段注重SoC外部Board内部
- uboot——启动第二阶段分析
- uboot 启动流程分析(二) — 第二阶段
- uboot 启动流程分析(二) — 第二阶段
- uboot - 启动流程分析【第二阶段】
- uboot启动第二阶段详细分析(1)
- uboot启动第二阶段详细分析(2)
- uboot启动第二阶段之x-load分析
- TQ210 —— s5pv210 board.c分析(uboot第二阶段)
- uboot启动第二阶段
- UBoot启动第二阶段
- uboot第二阶段启动过程
- uboot第二阶段启动流程
- Uboot启动的第二阶段
- uboot启动第二阶段1
- uboot启动第二阶段2
- uboot启动第二阶段
- uboot第二阶段分析
- uboot第二阶段详细分析
- MyBatis SQL xml处理小于号与大于号
- 类和对象
- 模拟退火算法-TSP
- placeholder文字设定样式
- Java设计模式之代理模式
- uboot——启动第二阶段分析
- 七牛云存储____七牛js直接上传图片
- Pyspider windows下的安装
- Android中的线程池
- Java设计模式之观察者模式
- zoj 3601unrequited Love
- 常用颜色定义
- HW accelerated
- WinSock 异步I/O模型[1]---选择模型 - select