mini2440系统移植篇之u-boot第二阶段C语言

来源:互联网 发布:网络视频监控施工方案 编辑:程序博客网 时间:2024/05/01 17:29

1. 第二阶段C语言

1.1. 初始化


由第一阶段汇编得知,最后跳到C语言的start_armboot,这个函数在lib_arm/board.c

1.1.1. 全局结构体

程序一开始申请两个全局结构体gdbdgd是全局相关的变量,主要有波特率,环境变量地址,帧缓冲地址,还有一个flag

typedefstructglobal_data {bd_t*bd;unsigned longflags;unsigned longbaudrate;unsigned longhave_console;/* serial_init() was called */unsigned longenv_addr;/* Address  of Environment struct */unsigned longenv_valid;/* Checksum of Environment valid? */unsigned longfb_base;/* base address of frame buffer */#ifdef CONFIG_VFDunsigned charvfd_type;/* display type */#endifvoid**jt;/* jump table */} gd_t;/* * Global Data Flags */#defineGD_FLG_RELOC0x00001/* Code was relocated to RAM*/#defineGD_FLG_DEVINIT0x00002/* Devices have been initialized*/#defineGD_FLG_SILENT0x00004/* Silent mode*/#defineGD_FLG_POSTFAIL0x00008/* Critical POST test failed*/#defineGD_FLG_POSTSTOP0x00010/* POST seqeunce aborted*/#defineGD_FLG_LOGINIT0x00020/* Log Buffer has been initialized*/#define GD_FLG_DISABLE_CONSOLE0x00040/* Disable console (in & out) */bd主要是存储开发板信息,重要的有机器码arch_number,启动参数boot_params和内存配置,这些信息等到启动内核时,会传递给内核。typedef struct bd_info {    intbi_baudrate;/* serial console baudrate */    unsigned longbi_ip_addr;/* IP Address */    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];} bd_t;

bd主要是存储开发板信息,重要的有机器码arch_number,启动参数boot_params和内存配置,这些信息等到启动内核时,会传递给内核。

typedef struct bd_info {    intbi_baudrate;/* serial console baudrate */    unsigned longbi_ip_addr;/* IP Address */    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];} bd_t;


1.1.2. 硬件初始化

接下来是一个函数指针表,进行各种硬件初始化,其中比较重要的是板子初始化board_init、串口初始化serial_init。只要display_banner能打出信息,说明串口可以用了,这是为以后可以调试奠定了基础。除了这个函数指针数组,接下来还会有flash、网卡、环境变量等初始化。

init_fnc_t *init_sequence[] = {#if defined(CONFIG_ARCH_CPU_INIT)arch_cpu_init,/* basic arch cpu dependent setup */#endifboard_init,/* basic board dependent setup */#if defined(CONFIG_USE_IRQ)interrupt_init,/* set up exceptions */#endiftimer_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,#endifdram_init,/* configure available RAM banks */#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)arm_pci_init,#endifdisplay_dram_config,NULL,};for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {if ((*init_fnc_ptr)() != 0) {hang ();}}

1.2. 主循环

完成了相关的初始化后,u-boot进入一个死循环。

/* main_loop() can return to retry autoboot, if so just run it again. */

for (;;) {

main_loop ();

}

这个死循环获取环境变量bootdelay的值,然后进行倒计时,在这段时间内控制台有按键响应,则进入等待命令输入模式,超时根据bootcmd启动内核。我在这里加了一个run_command("menu",0),即进入命令模式后,执行一个菜单选项,用于一键升级内核-u-boot等操作,方便开发。

main_loop()

{

配置自动完成

获取bootdelay

获取bootcmd

没有按键按下,执行bootcmd启动内核,否则继续向下执行

run_command("menu",0);  //==交互菜单

for()

{

len = readline (CONFIG_SYS_PROMPT); //==读输入

run_command (lastcommand, flag);

}

}

1.2.1. 加载内核

加载启动内核来至于run_command(bootcmd),首先是加载,把内核从flash拷贝到内存的指定位置。

 

加载内核

{

内核加载地址 image_header loader

内核运行地址 image_header ep

 

Flash拷贝kernel到内存 

nand read 内存地址(0x30007fc0) Flash偏移 大小

启动内核

bootm 内存地址(0x30008000)

}

1.2.2. 启动内核

启动内核,根据内核的编译地址和实际地址,决定要不要移动内核,启动内核之前,要设置给内核的参数,使用tag结构体。常用的保护5tag,开头setup_start_tag结尾setup_end_tag ,内存setup_memory_tags,命令行setup_commandline_tag (bd, commandline)setup_initrd_tag (bd, images->rd_start, images->rd_end)。最后启动内核是一个函数指针theKernel = (void (*)(int, int, uint))images->ep;//image_header的入口地址,第一个参数固定是0,第2个是机器码,保存在上面提到的bd全局结构体,第三个是内核参数tagbootloader巧妙地利用函数指针及传参规范将R0:0x0R1:机器号,R2:参数地址传递给内核.

 

do_bootm

{

bootm_start

{

boot_get_kernel

{

memmove

}

xxx

do_bootm_linux

}

}

 

do_bootm_linux

{

theKernel = (void (*)(int, int, uint))images->ep;//image_header的入口地址

 

获取machid

hyq2440.c board_init设置 gd->bd->bi_boot_params = 0x30000100;

这个就是tag起始地址

 

setup_start_tag (bd);

setup_memory_tags (bd);

setup_commandline_tag (bd, commandline); //根据bootargs设置tag

setup_initrd_tag (bd, images->rd_start, images->rd_end);

setup_end_tag (bd);

 

theKernel (0, machid, bd->bi_boot_params);

}

0 0
原创粉丝点击