Chinaunix首页 | 论坛 | 博客
  • 博客访问: 404393
  • 博文数量: 120
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 741
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-27 18:15
文章分类

全部博文(120)

文章存档

2016年(13)

2015年(41)

2014年(66)

我的朋友

分类: Android平台

2014-08-12 00:20:33

下面分析一下boot.axf, 其代码都在目录lichee/boot/boot1/apps/Boot_Android中
1.链接脚本
  1. OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
  2. OUTPUT_ARCH(arm)
  3. SECTIONS
  4. {
  5.     . = 0x42800000;
  6.      EGON2_MAGIC : { magic.o(.rodata) }
  7.     .text : { *(.text) *(.rodata)}
  8.     .data : { *(.data) }
  9.     .bss : { *(.bss) }

  10. }
2. magic.c
在lichee/boot/boot1/apps/Boot_Android/magic.c中
  1. const eGon2_mod_t modinfo =
  2.     {
  3.         {'e','G','o','n','2','a','p','p'},
  4.         0x01000000,
  5.         0x0,
  6.         BootMain, //虽然还不是很理解,但是这应该就是首地址了
  7.         0
  8.     };

3. BootMain
在lichee/boot/boot1/apps/Boot_Android/BootMain.c中
  1. int BootMain(int argc, char **argv)
  2. {
  3.     memset(&board_res, 0, sizeof(boot_hardware_res));
  4.     memset(&boot1_priv_para, 0, sizeof(boot1_private_head_t));

  5.     ret = wBoot_get_para(WBOOT_PARA_GLOBAL, &boot1_priv_para);

  6.     global_info = (boot_global_info_t *)wBoot_malloc(sizeof(boot_global_info_t));
  7.     memset(global_info, 0, sizeof(boot_global_info_t));
  8.     ret = script_patch("c:\\boot.ini", global_info, 0);     //3.1 解析boot.ini,将解析结果放在global_info中
  9.     BoardInit_Display(global_info->display_device, global_info->display_mode);   //按照boot.ini中的参数进行显示的初始化
  10.     if(check_power_status())
  11.     {
  12.         ret = -1;
  13.     }
  14.     else
  15.     {
  16.         //3.2解析c:\linux\linux.ini,读取里面的img_name(u-boot.bin),到内存地img_base(0x4A000000)处
  17.        //para_addr为空, kernal_addr=0x4a000000, logo_status=0
  18.         BootOS_detect_os_type(&para_addr, &kernal_addr, (void *)global_info, &logo_status);    
  19.     }
  20.     BoardExit(logo_status, ret);
  21.     BootOS(para_addr, kernal_addr);    //3.3跳到kernel_addr处运行
  22. }

3.1 解析boot.ini,结果存在global_info中
script_patch("c:\\boot.ini", global_info, 0);
  1. __s32 script_patch(char *script_name, void *script_buf, __s32 boot_script_type)
  2. {
  3.     //打开boot.ini
  4.     script_file = wBoot_fopen(script_name, "rb");
  5.     //查找boot.ini的长度
  6.     script_len = wBoot_flen(script_file);
  7.     //在堆上为boot.ini分配空间
  8.     script_addr = (char *)wBoot_malloc(script_len);
  9.     //将boot.ini读到内存中
  10.     wBoot_fread(script_addr, 1, script_len, script_file);
  11.     wBoot_fclose(script_file);
  12.     //参数boot_script_type=0
  13.     if(!boot_script_type)
  14.     {    
  15.         //解析boot.ini,并将解析后的值存在script_buf中
  16.        //这个script_buf使用时转为结构体boot_global_info_t
  17.         ret = parser_script_os_sel(script_addr, script_len, script_buf);
  18.     }
  19.     else
  20.     {
  21.         ret = parser_script_os_img(script_addr, script_len, script_buf);
  22.     }

  23.     return ret;
  24. }
parser_script_os_sel这个函数进行具体的解析工作:
    按行读取boot.ini中的内容,每行的首字节代表了该行的类型,
           ; --> 注释行
           [ --> 主键行
          空行忽略,其它为sub_key
    对sub_key中的字符串进行匹配,需要数字的将字符串中的值转为数字
3.2 解析参数并加载u-boot
调用:BootOS_detect_os_type(&para_addr, &kernal_addr, (void *)global_info, &logo_status);    
其中global_info是解析自boot.ini的参数指明了当前的system类型,其它的3个参数是需要赋值的
  1. __s32 BootOS_detect_os_type(__u32 *para_addr, __u32 *kernal_addr, void *os_info, int *logo_status)
  2. { 
  3.     //解析linux/linux.ini的配置到os_img_info中
  4.     script_patch("c:\\linux\\linux.ini", &os_img_info, 1);
  5.     boot_show_logo("c:\\os_show\\bootlogo.bmp", 1, BOOT_LOGO_MEM_BASE); //show logo
  6.     PreBootOS((char *)&os_img_info, kernal_addr, para_addr, logo_status);
  7.     read_boot_img(boot_part_start,0x40007800);

  8.     return ret;
  9. }
3.2.1 解析参数并加载u-boot
 调用:PreBootOS((char *)&os_img_info, kernal_addr, para_addr, logo_status);
其中os_img_info是从c:\linux\linux.ini解析出来的参数,其它的3个参数是需要赋值的
  1. __s32 PreBootOS(char *os_para, __u32 *kernal_addr, __u32 *para_addr, __s32 *logo_status)
  2. {
  3.     boot_sys_img_set_t *os_img;
  4.     os_img = (boot_sys_img_set_t *)os_para;
  5.     *logo_status = os_img->logo_off;               //赋值logo_staus值为0
  6.     boot_show_logo(os_img->logo_name, os_img->logo_show, BOOT_LOGO_MEM_BASE);  //show logo
  7.     ret = boot_dsipatch_kernal(os_img, kernal_addr, para_addr);    //加载u-boot.bin,kernal_addr就是加载的地址(0x4a000000)
  8.     return 0;
  9. }
3.2.1.1 加载u-boot.bin
将u-boot.bin加载到内存的0x4a000000处,kenel_addr是加载的内存地址(0x4a000000),para_addr是参数的地址(为空)
  1. static __s32 boot_dsipatch_kernal(boot_sys_img_set_t *os_img, __u32 *kernal_addr, __u32 *para_addr)
  2. {
  3.     __inf("load kernel start\n");
  4. #ifndef SPEED_UP_BOOT
  5.     count = os_img->img_count;
  6.     for(i = 0; i < count; i++)
  7.     {
  8.         if(1 != i)
  9.         {
  10.             address = (void *)os_img->img_set[i].img_base;
  11.         }
  12.         else
  13.         {
  14.             address = wBoot_malloc(64 * 1024);
  15.         }
  16.         
  17.         hd_file = wBoot_fopen(os_img->img_set[i].img_name, "rb");
  18.         
  19.         file_length = wBoot_flen(hd_file);
  20.         
  21.         wBoot_fread(address, 1, file_length, hd_file);
  22.         wBoot_fclose(hd_file);

  23.         os_img->img_set[i].img_full_size = file_length;
  24.         if(1 == i)
  25.         {
  26.             do_boot_linux((char *)os_img->img_set[1].img_base, (char *)address, file_length);
  27.             wBoot_free(address);
  28.         }
  29.         address = NULL;
  30.         hd_file = NULL;
  31.         file_length = 0;
  32.     }
  33.     address = (void *)os_img->script_info.img_base;
  34.     memcpy(address, (void *)SCRIPT_BASE, os_img->script_info.img_size);
  35.     os_img->script_info.img_full_size = os_img->script_info.img_size;
  36.     *kernal_addr = os_img->img_set[0].img_base;
  37.     *para_addr      = os_img->img_set[1].img_base;
  38. #else
  39.     //这儿执行的应该是上面的#ifndef,上下都是同一个意思,而且下面的看起来更清楚一些
  40.     //这儿的kernel_addr与wBoot_fopen都是直接赋的值,其实应该是从c:\linux\linux.ini中读取
  41.     //作用是将u-boot.bin加载到内存的0x4a000000处
  42.     *kernal_addr = 0x4a000000;
  43.     hd_file = wBoot_fopen("c:\\linux\\u-boot.bin", "rb");
  44.     file_length = wBoot_flen(hd_file);
  45.     wBoot_fread((void *)(*kernal_addr), 1, file_length, hd_file);
  46.     wBoot_fclose(hd_file);
  47. #endif
  48.     __inf("load kernel successed\n");

  49.     return 0;
  50. }
3.3 执行u-boot
调用BootOS(para_addr, kernal_addr),
实际上是产生了一个软中断
  1. void BootOS(__u32 para_addr, __u32 kernal_addr)
  2. {
  3.     wBoot_jump_to_linux(0, 3495, para_addr, kernal_addr);
  4. }
3.3.1 产生软中断
产生一个软中断EGON2_SWI_JUMP_TO_LINUX
在lichee/boot/boot1/misc/syacall/syscall_misc.c中
  1. int wBoot_jump_to_linux(int addr, int mod_id, unsigned int paddr, unsigned int kernal_addr)
  2. {
  3.     asm("stmfd sp!, {lr}");
  4.     asm("swi %0"::"Ir"(EGON2_SWI_JUMP_TO_LINUX));
  5.     asm("ldmfd sp!, {lr}");
  6. }
3.3.2 进入软中断入口函数
在lichee/boot/boot1/core/arm_board/arm_swi.c中
  1. void eGon2_swi_handler_entry(__u32 swi_number, struct swi_regs * swi_reg)
  2. {
  3.     case EGON2_SWI_JUMP_TO_LINUX:
  4.     {
  5.         eGon2_jump_to_android_linux(swi_reg->reg[0], swi_reg->reg[1], swi_reg->reg[2], swi_reg->reg[3]);
  6.     }
  7. }
3.3.3 终于开始执行u-boot了
lichee/boot/boot1/core/jump_to/jump.c
  1. void eGon2_jump_to_android_linux(__s32 zero, __s32 mod_id, __u32 paddr, __u32 kernal_addr)
  2. {
  3.     void (*kernel_entry)(int zero, int arch, uint params);
  4.     //一系列的关闭操作
  5.     ...
  6.     kernel_entry = (void (*)(int, int, __u32))(kernal_addr); //将0x4A000000转为函数指针
  7.     kernel_entry(zero, mod_id, paddr); //执行
  8.     return;
  9. }







阅读(625) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~