blob分析

 

要移植BLOB,最好先看懂BLOB的工作流程。本人只针对intel开发板mtwilson来理解BLOB,相信其他板子也是一样的,BLOB对各种板子的支持在configure.in中有列出。

BLOB对各种CPU的支持在configure.in中定义,编译器直接编译出针对某个CPU的执行文件?可我在用ADS1.2的时候没有说编译前就要选择CPU啊。对了,这里选择的是目标板体系结构的具体型号,这一点在ADS中也是要选择的。这么说来,ADS1.2不支持intel的PXA系列芯片?因为选择的列表中没有PXA.

对于ARM平台的BLOB,启动代码都在START.S等汇编文件中,这里的语法跟汇编语言有些不一样,你可以在arm-linux-as工具的as.info文件中找到答案。

物理空间位置在PXA270的manule中有定义。

START.S中启动后立即跳到start-pxa.S中的reset处理,reset中关闭各中断。然后再realreset中调用gpio-pxa.S,在gpio-pxa.S对gpio初始化。然后调用memsetup-pxa.S对存储器设置。再跳转到start.S中的normal_boot。

normal_boot中会检查BLOB在RAM中起始地址之后的1M空间地址。这里调用了testmem.S中的testram。如果BLOB在RAM中的起始地址出错,会进入死循环。

开发板的程序地址空间分配是在 blob/include/blob/arch/下你的板子名称的头文件中定义的。该头文件中的BLOB_ABS_BASE_ADDR是FLASH中的BLOB将自己除前4K外copy 到RAM中的目标地址,也就是BLOB在RAM中的起始地址。

start.S中piggy_start是要拷贝到RAM中的那部分BLOB的起始地址,相应的piggy_end就是结束地址。

copy完成后跳到RAM中的BLOB运行第二阶段。

 

第二阶段从哪里开始执行可以在src/blob下面的链接脚本文件start-ld-script中找到线索,其中表明piggy_start地址是blob-rest-piggy.o,再根据blob-rest-piggy.o查到该目录下的makefile文件,该makefile下详细罗列了BLOB第二阶段的一些源文件。

第一个源文件是trampoline.S, 在该文件的后面跳转到C语言代码的main().

修改blob的flash驱动

如何将flash的驱动程序从sst39vf160改为amd29lv160

本方法适用www.start-web.net/tpu上面下载的blob源码

1, 执行make maintainer-clean
删除各个文件家下的.dep 和Makefile

2, 修改主目录下的configure.in 将该文件中的sst16.o欧改为amd29lv160.o
(对应的amd29lv160.c这个文件你的自给写,参看sst的该一下就行)

3, 修改mba44b0.c 将其中的函数init_mbck_flash_drive 中的sst16_flash_driver改为amd_29lv160_flash_driver (amd_29lv160_flash_driver 在amd29lv160.c 中实现)

4, 执行autoconf

5, 执行./configure --with-board=mba-44b0 --host=i686-pc-linux-gnu --with-linux-prefix=/usr/src/linux arm-unknown-linux-gnu (注意此处的/usr/src/linux 是我做的一个链接, 你先要按照README中的要求对你的pc机上面的源代码树进行处理. 然后在/usr/src/目录下执行 ln -s ./linux-2.4 ./linux)


6, make

 ==================================

pxa-regs.h中定义了开发板中CPU各片选的地址空间。

0x%08x :  输出格式前缀0x长度为8的16进制格式数据。

mian()里会调用init_subsystems(void)函数,跟踪这个函数,发现要理解这个函数是有些困难的,但从它的名字就可以看出,这个函数是用来初始化一些子系统的,你可以不管他,直接在各个模块比如flash.c下去做你的事情,当然,了解它的机制是最好不过了。
函数里有个循环for(i = INIT_LEVEL_MIN; i <= INIT_LEVEL_MAX; i++),显然,程序把要初始化的内容分了等级。在循环里调用call_funcs函数,call_funcs(initlist_t *start, initlist_t *end, u32 magic, int level)把__initlist_start到__initlist_end这一段的数据进行初始化,事实上,这一段内都是由下面这个结构组成的。
typedef struct {
 u32 magic;
 initfunc_t callback;
 int level;
} initlist_t;
call_funcs中定义结构指针initlist_t *item,并赋值item = start,也就是把item指向了下面讲到的初始化函数结构表中的一个模块初始化函数所在的结构,初始化这个结构时,magic是个定值,callback是个指向函数的指针,item->callback()初始化这个指针,可以认为也就执行了相应的模块初始化。
这些结构是怎么被放到__initlist_start到__initlist_end这一段中的呢?
下面这个宏起了作用,fn就是指向初始化函数的指针,lvl是初始化函数的优先级别。
#define __initlist(fn, lvl) /
static initlist_t __init_##fn __init = { /
 magic:    INIT_MAGIC, /
 callback: fn, /
 level:   lvl }
__initlist把下面这些函数构建成了一张初始化函数结构表,根据这张表初始化各个模块。
/src/blob/mtwilson.c(304):__initlist(init_mtwilson_flash_driver, INIT_LEVEL_DRIVER_SELECTION);
/src/blob/mtwilson.c(354):__initlist(mtwilson_init_hardware, INIT_LEVEL_DRIVER_SELECTION);
/src/lib/lcd-pxa.c(394):__initlist(lcd_activate, INIT_LEVEL_INITIAL_HARDWARE);
/src/blob/initcalls.c(45):__initlist(serial_default_init, INIT_LEVEL_INITIAL_HARDWARE); //
/src/blob/initcalls.c(46):__initlist(enable_icache, INIT_LEVEL_INITIAL_HARDWARE);  //
/src/blob/initcalls.c(47):__initlist(led_init,  INIT_LEVEL_INITIAL_HARDWARE);  //
/src/blob/initcalls.c(48):__initlist(timer_init,  INIT_LEVEL_OTHER_HARDWARE); //
/src/lib/ether.c(66):__initlist(ether_init, INIT_LEVEL_OTHER_HARDWARE);
/src/lib/command.c(79):__initlist(init_commands, INIT_LEVEL_OTHER_STUFF); //
src/blob/flash.c(194):__initlist(init_flash, INIT_LEVEL_OTHER_STUFF + 1); //
/src/lib/generic_io.c(109):__initlist(io_init, INIT_LEVEL_OTHER_STUFF + 1);
/src/blob/initcalls.c(51):__initlist(init_flash_io, INIT_LEVEL_OTHER_STUFF + 2);
/src/blob/initcalls.c(52):__initlist(init_part_io, INIT_LEVEL_OTHER_STUFF + 2);
/src/blob/initcalls.c(53):__initlist(init_ram_io, INIT_LEVEL_OTHER_STUFF + 2);
/src/lib/tar.c(107):__initlist(init_tar_default_io, INIT_LEVEL_OTHER_STUFF + 2);
/src/blob/partition.c(374):__initlist(ptable_init, INIT_LEVEL_OTHER_STUFF + 2);
/src/lib/cf.c(208):__initlist(cf_default_io_init, INIT_LEVEL_OTHER_STUFF + 2);

上面列表中的函数都是两个for语句可能做的,但具体会做哪几个,由编译时的配置决定。
一般先执行最前面的两个和体系结构相关的:***_flash_driver、
***_init_hardware。然后(公共的)6个 加注释符的一般也是必须的。

command.c里用了与init.c一样的机制

__commandlist(fn, nm, hlp)把所有的命令制成一个表

/BLOB/include/blob/command.h(56):#define __commandlist(fn, nm, hlp) /
/BLOB/src/blob/chkmem.c(240):__commandlist(ChkMem, "chkmem", chkmemhelp);
/BLOB/src/blob/clock.c(92):__commandlist(SetClock, "clock", clockhelp);
/BLOB/src/blob/flash-commands.c(136):__commandlist(Flash, "flash", flashhelp);
/BLOB/src/blob/flash-commands.c(171):__commandlist(Lock, "lock", lockhelp);
/BLOB/src/blob/flash-commands.c(207):__commandlist(Unlock, "unlock", unlockhelp);
/BLOB/src/blob/flash-commands.c(242):__commandlist(Erase, "erase", erasehelp);
/BLOB/src/blob/linux.c(106):__commandlist(boot_linux, "bootm", boothelp);
/BLOB/src/blob/main.c(292):__commandlist(PrintStatus, "status", statushelp);
/BLOB/src/blob/main.c(308):__commandlist(Reload, "reload", reloadhelp);
/BLOB/src/blob/mtwilson.c(408):__commandlist( cmd_flash_write, "fwrite", flashwritehelp );
/BLOB/src/blob/mtwilson.c(454):__commandlist( cmd_flash_erase, "ferase", flasherasehelp );
/BLOB/src/blob/mtwilson.c(532):__commandlist(cmd_clock_info, "clockinfo", clockinfohelp);
/BLOB/src/blob/mtwilson.c(563):__commandlist(cmd_go, "go", gohelp);
/BLOB/src/blob/partition.c(481):__commandlist(ptprint, "ptprint", ptprint_help);
/BLOB/src/blob/reboot.c(67):__commandlist(reblob, "reblob", reblobhelp);
/BLOB/src/blob/system3.c(301):__commandlist(sysver_cmd, "sysver", sysver_help);
/BLOB/src/blob/system3.c(341):__commandlist(sys3dbg_cmd, "sys3dbg", sys3dbg_help);
/BLOB/src/blob/system3.c(415):__commandlist(fwrite_cmd, "fwrite", fwrite_help);
/BLOB/src/blob/system3.c(419):__commandlist(ferase_cmd, "ferase", ferase_help);
/BLOB/src/blob/system3.c(424):__commandlist(dlfile_cmd, "dlfile", dlfile_help);
/BLOB/src/commands/dummy.c(53): *   __commandlist(dummy_cmd, "dummy", dummy_help);
/BLOB/src/diag/lcd.c(316):__commandlist(lcd_test, "lcdtest", testlcdhelp);
/BLOB/src/diag/regs-pxa.c(268):__commandlist(regs_show, "regs", regshelp);
/BLOB/src/diag/system3.c(261):__commandlist(smctest, "smctest", smctesthelp);
/BLOB/src/lib/command.c(245):__commandlist(help, "help", helphelp);
/BLOB/src/lib/download.c(211):__commandlist(SetDownloadSpeed, "speed", speedhelp);
/BLOB/src/lib/ether-smc9196.c(649):__commandlist(smctest, "smctest", smctesthelp);

我发现visual C++还是个很好的批量查找软件,我在做这张列表时当时手工用了很长时间,格式还不好看,后来发现visual C++的批量查找功能,速度快n倍,格式还更整齐

这今天在看BLOB对各个设备初始化时一时摸不着头脑,看得一头雾水。现在我想应该是不知道BLOB对初始化列表的顺序的原因,这个问题在init.h里能找到答案,

#define INIT_LEVEL_DRIVER_SELECTION (0)
#define INIT_LEVEL_INITIAL_HARDWARE (10)
#define INIT_LEVEL_PARAM_LIST  (20)
#define INIT_LEVEL_OTHER_HARDWARE (30)
#define INIT_LEVEL_OTHER_STUFF  (40)
 

括号里的数值越小,优先级越高,也就是先初始化。

下面一个一个分析这些初始化

static void init_mtwilson_flash_driver(void)
{
 int i = 0;
 flash_descriptors = NULL;
  flash_driver = NULL;
  /* Two banks */
  for (i=0; i<2; i++) {
   struct flash_chip *chip = flash_chips + i;

   chip->base = i * 0x04000000;
 
   if (BOOT_DEF & 0x1) chip->buswidth = 2;
   else chip->buswidth = 4;

  flash_probe(chip);
 }

#ifdef FLASH_SYNC_MODE_SUPPORT
 /* BOOT ROM sync-mode */
 flash_sync_mode(&flash_chips[0]);
#endif
}
__initlist(init_mtwilson_flash_driver, INIT_LEVEL_DRIVER_SELECTION);

这个初始化函数中,对片内片外FLASH进行初始化,估计flash_descriptors和flash_driver指向的是CPU片上FLASH,而mtwilson所用CPU PXA270没有片上FLASH,因此flash_descriptors = NULL;flash_driver = NULL;而flash_chip则是针对外部FLASH的结构。为什么这里认为有两片32位FLASH?而且chip->base = i * 0x04000000;表明第二片FLASH起始地址在64M。chip->buswidth = 4 表示外部FLASH总线宽度32位。

static void mtwilson_init_hardware(void)
{
//......
}
__initlist(mtwilson_init_hardware, INIT_LEVEL_DRIVER_SELECTION);
在这个函数至少会执行下面几句
 reboot_driver = &pxa_reboot_driver;
 serial_driver = &pxa_serial_driver;
 led_driver = &mmap_led_driver;
 timer_driver = &intelarm_timer_driver;
也就是对前面这几个驱动初始化。

blob/include/blob/arch/pxa-regs.h

#define GAFR(x)  __REG2(0x40E00054, ((x) & 0x70) >> 2)
GAFR(x)是个寄存器变量,它指向的地址就是x所在寄存器的地址
__REG2(x,y)的作用是如果y是常数,则返回__REG(x+y),
((x) & 0x70)中的x指第x个GPIO口,每个寄存器能定义16个GPIO口的功能,因此第x脚所在寄存器地址就是x之前16的整数的那个io口所在字节的地址,和0x70位与操作,相当于舍去低4位,而高4位不会变(总共120个io口转换成16进制高字节也是7),也就是得出了x之前的那个16的整数倍的io口,如第58个IO口,((58) & 0x70) = 48,刚好处在和58同一个寄存器的最低位,总之((x) & 0x70)是求出和x在同一寄存器的最低位的io脚,假设这个io口是第d个io口,d脚所在字节地址就是x脚所在寄存器的起始地址,因为每个io口功能定义占了2个位,因此这个d脚相对第0脚所在地址偏移了 d*2位,再除以8就是偏移的字节,加上0x40E00054就是x脚所在寄存器的起始地址了。由此可以得出((x) & 0x70) >> 2 也可写成(((x) & 0x70)*2) >> 3, 乘2相当于少右移1位,所以写成((x) & 0x70) >> 2。 这里的右移2位很容易被误解为求出x所在字节偏移量,除以每个寄存器占4个字节得到x寄存器的地址偏移量,其实这样的想法是错的。

#define SETALTFUNC(pin, func) GAFR(pin) = (GAFR(pin) & ~GAFR_bits((pin), 3)) | GAFR_bits((pin), (func))
pin:第几个IO脚 
func:可用功能的功能代码,0:普通IO口, 1:可用功能1, 2:可用功能2,3:可用功能3。
注意了,不是每个IO口都有好几个可用功能。

#define GPIO_bit(x) (1 << ((x) & 0x1f))  /*寄存器中位定位,最多只能移31位,并赋值1 */
#define GAFR_bits(x,y) ((y) << (((x) & 0xf) * 2)) /*忽略高4位,得到x口在寄存器中的位地址,并填11 */
#define GAFR(x)  __REG2(0x40E00054, ((x) & 0x70) >> 2)   /*定义指向x所在寄存器的寄存器变量,这里是功能选择寄存器 */
#define SETALTFUNC(pin, func) GAFR(pin) = (GAFR(pin) & ~GAFR_bits((pin), 3)) | GAFR_bits((pin), (func))
/*在x对应的位中填0,和要填的功能码位或*/

你可能感兴趣的:(ARM)