关闭

skyeye的初始化

811人阅读 评论(0) 收藏 举报

今天早早地回到了住处,早上起来感觉到脖子很不舒服,白天在实验室里扭动一下都不容易,得好好善待自己,身体是革命的本钱啊!

看了一下以前的blog,本来很早就想写关于ipv6的总结,可是过去都快一个月了,现在都提不起兴致,看来干什么都得趁热打铁,学习也是,不及时总结好多

心得,经验都白白丢失了,将来想捡起来又得费一番功夫。不知道什么时候把这个好习惯给丢了  :(

这段时间因为产品开始联调,所以接触到了单板,bootloader等东西,虽然以前有过相关的学习,但是进入真正的环境还是第一次。所以刚开始好多东西不清

楚,好在经过两个星期的学习,也算是渐渐弄清楚了一些东西。

嵌入式系统开发是时下很热的话题,在各个领域的应用极为广泛,所以有很多人都想望着上面发展。另一方面因为其设计到很多底层的软硬件只是,更是能吸

引一部分底层技术爱好者的兴趣。可是对于很多人来说,嵌入式开发板需要的一笔投入让其望而却步。正是在这种背景下,skyeye--天目应运而生。关于

skyeye的介绍,百度一下就可以知道。最新本版应该是1.2。研究了他一个星期,主要是看它的初始话代码,因为我想弄清楚他的配置文件里面各项究竟是什么

含义。它的源码里面用到了大量的函数指针给跟踪带来了很大的麻烦。在main函数中解析完输入参数后,调用init函数,主要的初始化流程可以解释如下:
1)init: 如果是第一次调用init,那么初始化device--->初始化所有以支持的设备:net,lcd,flash等,将其放入到全局二维指针global_mod_set中;初始化

arch--->初始化所有支持的架构,目前包括arm,bfin,mips,clodfire,ppc,将每种架构对应的arch_config_t 放入到全局数组skyeye_archs中;
2)读取config文件,并一步步解析里面的选项,这里用到了一个重要的变量skyeye_option_t skyeye_options;它的每一项表示对于某种选项,应该用那个函数

进行解析。下面是一些常用的解析过程:
   A)arch:一般来说这是首先被解析确定的,有些选项依赖于它。从arch_config_t skyeye_archs[]中,找到于配置相等的arch(arm,ppc,mips等),赋给

skyeye_config.arch;
   B)cpu:如果已经解析了arch,那么调用此arch的cpu解析函数,初始化全局结构cpu_config_t *p_arm_cpu;如果还没有初始化arch,则默认arch为arm。以

arm的cpu解析为例,他在全局结构arm_cpus中找与配置选项一致的cpu name,并用*p_arm_cpu指向匹配的项;
   C)mach:此选项指定特定的开发板,是整个skyeye运行的中心配置结构。与cpu的解析类似,都是调用arch的mach解析函数(每种arch对应若干种cpu,针对每

种cpu有可能有若干种开发板,所以,arch是根本)。同样,也是在一个全局数组machine_config_t arm_machines中,找mach name与配置中一致的项,并赋值

给skyeye_config.mach。
   D)mem:类似,调用以初始化好的arch的mem解析函数。以arm为例,主要工作是初始化mem_config_t arm_mem结构体。
typedef struct
{
 int bank_num;
 int current_num; /*current num of bank */
 mem_bank_t mem_banks[MAX_BANK];
} mem_config_t;
    核心结构是mem_banks-->记录了读写数据的方法,此mem_bank对应的起始地址,文件名,类型(RAM,ROM,FLASH)。解析函数的工作就是初始

arm_mem.mem_banks,依据选项中的MAP,TYPE,FILE等参数,初始各mem_banks的成员。如果有FILE选项,则将指定的文件名拷贝到mem_banks中的相应char数组

中(仅仅是拷贝文件名,真正的装入文件将在arm_reset_state-->ARMul_Reset-->mem_reset 函数调用中进行);如果有BOOT=YES,则将

skyeye_config.start_address = mb[num].addr--->此mem_bank的起始地址。
  其他的选项的解析思路应该与此类似,只是每种选项的特性不同,需要初始化的设置的变量不一样而已。比如net,在linux平台下,需要特定的设备文件存

在,所以要求你装载某个net驱动模块,以在/dev下面生成指定的设备文件。
  现在的版本的skyeye与internal文档的描述有些出入,但实现思路应该还是不变的。核心的结构还是skyeye_option_t 。与设备有关的是

machine_config_t.struct device_desc **devices;可以把它看作是指向了一张表,里面的每一项都是指向此machine的某个设备的指针。结构体struct

device_desc 是描述具体的设备。里面有大量的函数指针,用于读取字节,字等,进行I/O操作的函数。这些函数指针大致可以分为两类(这是我自己归纳的,

不一定正确。参考源码中的 set_device等函数):IO/mem/init类,此设备特有的操作函数。设备描述结构体中还有一个指向其所属的设备类型的指针,以获得

一些此类型设备共有的操作函数。
  因为对bootloader比较感兴趣,所以特别关注了一下程序运行的起始地址,以下是确定方法。
    相关的变量有三个 static unsigned long load_addr = 0x0;
                     static unsigned long load_addr_mask = 0xffffffff;
                     uint32_t             skyeye_config.start_address;
    1)通过-e参数输入elf文件名,-l参数输入load_addr ,load_addr_mask。没有-l参数的话,elf将被装载到它的入口处,也就是elf文件里的指定的地址;

否则装载到-l指定的地址。通过 tea_load_exec
    2)通过内存选项的boot,可以指定 skyeye_config.start_address。在tea_load_exec 中,如果skyeye_config.start_address为零,那么将会被置为elf

文件的入口。
    3)在main函数中,init后,如果输入了elf文件,则调用tea_load_exec (exec_file, 0),载入elf文件,设置skyeye_config.start_address。并把pc指针

设置为(skyeye_config.start_address & load_addr_mask)|load_addr --->  相当于是在skyeye_config.start_address的基础上偏移 load_addr ???有时间

可以试验一下

所以,指定程序运行的起始地址有一下几种方法:
1) 在elf文件中,通过链接器等指定程序的入口,不用-l参数,boot选项。那么从elf的entry开始执行
2) 使用-l参数,指定load_addr,和load_addr_mask ,那么从load_addr开始执行
3) 在mem设置中,指定boot=yes,那么起始运行地址为(skyeye_config.start_address & load_addr_mask)|load_addr。如果没有elf文件,则起始地址就是此

mem_bank的起始地址。如果有elf文件,又有-l选项,那么依据上式确定起始地址。 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:80816次
    • 积分:1468
    • 等级:
    • 排名:千里之外
    • 原创:67篇
    • 转载:3篇
    • 译文:0篇
    • 评论:9条
    最新评论