Board logo

标题: S3C44B0 调试笔记BIOS部分 [打印本页]

作者: linuxarm    时间: 2006-12-7 12:23     标题: S3C44B0 调试笔记BIOS部分

由于调试耗费了我太多时间,所以记录下来,方便以后复习,同时也希望能给初学者一点儿启示,大家少走弯路。

我是去年开始听说ARM的,可能是本人太闭塞了吧。看到后就有一种想玩的冲动,想从51升级ARM。网上都说44B0比较适合初学者。机缘巧合,21ic上看到有人叫卖44B0空板,很便宜100RMB,主板加简易JTAG小板。做研发的都穷啊。还不错,钱汇过去,板子第3天就回来了,就是网上流行的那个44B0 PCB。贴个图吧,随便找了块和我那块板子一模一样的:

 
      (FIGURE - 1)

拿到板子挺高兴的,检查了一下线路没问题。就按对方提供的BOM单采购元器件。先把电源部分焊上,测量没问题,再把必要的元器件焊上(CPU、SDRAM、FLASH、UART),同时还有JTAG小板。量电源和地没有短路,上电!电源灯亮了,没冒烟。

下面一步就是把BIOS程序烧写到FLASH上了,对方提供的是FLUTED,按照说明操作,烧录失败!这下傻了,最怕的就是这个,对于一个初学者来说,简直是灭顶之灾啊。首先怀疑CPU或FLSH是否虚焊,我的焊接水平一般,所以很值得怀疑,只好又搪了一遍。但问题依旧。又怀疑JTAG小板,仔细检查了一下没问题啊,跳线插插拔拔的也没无济于事。怀疑并口,重启进BIOS,并口设置也没问题。当天是没办法了,睡觉吧。

第二天就开始联系供应商,寻求帮助,但没什么结果。也是,就100块钱,还要什么服务啊。只好自己找问题,看到原理图上FLASH用的是SST 39VF160 ,我记得我的不一样啊?我的BOM上写的是AM29LV160,我又询问了供应商,他确认了一下说他的BOM写错了。狂晕啊。不过还好,终于找到问题了,但换FLASH还得周末去买啊,等不及了,看看这个能不能凑合用吧,改FLUTED的FCD文件,就是根目录那个DEFAULT.FCD。找到2块FLASH的Datasheet对比着改,连改带调,2个晚上,终于烧录成功了。拔下JTAG,接上串口,打开超级终端。复位,一堆乱码,我想应该差不多了,试着更改超级终端的设置。终于成功了,我看到BIOS的提示信息了,敲个help进去,出来一堆,当时感觉好爽,这个程序做的不错,和DOS一个感觉了,哈哈。

LSyDI6Lr.jpg


图片附件: [S3C44B0 调试笔记BIOS部分] LSyDI6Lr.jpg (2006-12-7 12:22, 27.39 KB) / 下载次数 256
http://bbs.eccn.com/attachment.php?aid=440&k=42f54e7231b8cfc0112f23026074f25c&t=1732255492&sid=kodcbc


作者: linuxarm    时间: 2006-12-7 12:23

然后焊上网络部分,输入ap,可以ping通,网络基本正常。随后就是下载uClinux了,按照供应商的说明文档,先把程序从0地址拷贝到0x1f0000,我运行copy命令,程序复位。重试,依旧。第一个想法就是,BIOS内部程序擦写FLASH的函数和我的芯片不兼容,无奈,只好对比着两块FLASH的Datasheet修改BIOS程序。调试了一个多礼拜,依旧。这下彻底崩溃了,感觉程序应该没有问题了。最终不得不放弃,只好换芯片,把AM29LV160换成了SST39VF160。 用最初的BIOS,但现象还是依旧,这可是怎么回是啊?仔细想了一下,会不会因为程序代码在FLASH里,而我又去擦除和写FLASH导致的系统崩溃?擦写FLASH的底层源码都有End-Detection, 例如擦Sector的BIOS源码,在发送完命令字后,有如下一段代码进行判断:

 while(1)
 {
  U16 i;

  i = *((volatile U16 *)sector)&0x40;
  if(i!=*((volatile U16 *)sector)&0x40) //D6 == D6
   continue;
  if(*((volatile U16 *)sector)&0x80) 
   break;        //D7 == 1
 }
      (CODE - 1)
用了2种方法判断擦除操作是否成功,看芯片资料,在这个时候,你去读FLASH那个扇区地址的话,会得到擦除是否成功的信息,而不是得到那个扇区号所对应绝对地址的数据!也就是说在这个时候去读特定地址sector会出错,那么是不是必须在擦写操作完成后,CPU才能取指,运行程序代码?对于我的这块板子,我感觉是这样的。因为它总是会DOWN在这里。但以前碰到过其他CPU,可以在同一块FLASH存储程序,同时程序又可以擦写这块FLASH的情况。这种区别会不会是不同FLASH型号造成的?期待指点。结论:S3C44B0的FLASH(39VF160)不能在自身运行程序的同时,对自己进行擦写操作。

那BIOS的源码有问题了,我该怎么做?看来现在只能把BIOS从Flash里copy到SDRAM中才行。用move命令实现copy: move 0 0xc000000 10000。但当我run 0xc000000 时,程序重启,为了确认程序是从哪里执行的,我写了一个读pc命令rdpc(见CODE - 2)。读出的pc值是0x41c4,显然,程序是从0地址重启了。这里又让人糊涂了,怎么又重启了呢?想不通了,这个疑问留在了这里,当时没有解决,后来拐了个弯才发现了问题。
int ReadPC(int argc, char *argv[])
{
 U32 i;
 U16 j,k;
 
 __asm
 {
  mov i,R15
 }
 j=i/0x10000;
 k=i%0x10000;
 printf("PC Value = 0x%x \n",i);
 printf("PC Value = %d - %d \n" ,j,k);
 __asm
 {
  MRS i,CPSR
 }
 j=i/0x10000;
 k=i%0x10000;
 printf("CPSR Value = 0x%x \n",i);
 printf("CPSR Value = %d - %d \n" ,j,k);
 return 0;
}
      (CODE - 2)


作者: linuxarm    时间: 2006-12-9 11:30

我又仔细看看供应商的说明文档,需要先把BIOS代码copy到0x1f0000,然后把uClinx的ROM文件下载到0xc000000位置运行。怎样才能把BIOS程序从0地址搬移到0x1f0000?决定还用FLUTED,先把0地址的数据擦除,然后把初始地址设成2031616(FLUTED用十进制),烧录成功,但不能启动。是不是因为程序从0地址进入,但不能执行到0x1f0000?可是我把前面的flash都擦了啊,都是0xff,程序应该可以跑到这里啊?看情况肯定是程序指针没有到0x1f0000了。搞不定了,这里耽误了一些时间,不过后来还是从BIOS的源码找到了突破口,我注意到了Prog命令,这段代码让人很费解了:
#define __ROM_SIZE 0x200000
#define BIOS_BASE (__ROM_SIZE-0x10000)
#define BIOS_LOAD (__ROM_SIZE-4)
 
 if(argc>4)
  if(strncmp(argv[4], "-no0", 4)==0)
   overwrite0 = 0;  
 
 if((prog_begin==0)&&overwrite0)
 {
  unsigned int ins;
  
  ins = *(unsigned int *)data_begin;    
  if((ins>>24)==0xea) // instruction: b xxxx, now just support b instruction!!!    bios_load_addr = ((ins&0xffffff)<<2)+8;
  else
   bios_load_addr = 4;  // other instruction, jump to 4
             
  bios_load_addr = (bios_load_addr-BIOS_LOAD-8)/4;
  bios_load_addr = (bios_load_addr&0xffffff)|0xea000000;     
  
  *(unsigned int *)data_begin = 0xea000000+(BIOS_BASE-8)/4;    
  
  modify_a0 = 1;          
 }
        (CODE - 3)
仔细分析了一下,程序的意思就是在你烧录0地址的时候,如果不选-no0参数,那么程序将会把0位置的数据通过计算转换成跳转指令的汇编码(0xeaxxxxxx)。替换成pc跳转到BIOS_BASE(0x200000-0x10000=0x1f0000)的指令,终于对上号了。 *(unsigned int *)data_begin = 0xea000000+(BIOS_BASE-8)/4; arm指令是32位的,所以除4,-8是因为3级流水线,如过这里不清楚的话,建议直接从ADS里看b指令的汇编码。

这下搞懂了,我就在BIOS里调用了prog函数,随便烧了几个字节到0地址。读出来看0~4分别是0xfe 0xbf 0x07 0xea。汇编码是:0xea07bffe。,0x7bffe是指跳转的指令数。arm是3级流水线,即pc为取指指针,pc-1是译码指针,pc-2是执行指针。程序复位,从地址0开始执行,跳转0x7bffe条指令。我们算一下,(0x7bffe+2)×4 =0x1f0000,也就是说,程序跳转到了0x1f0000。

X1mKRM7j.jpg


图片附件: [S3C44B0 调试笔记BIOS部分] X1mKRM7j.jpg (2006-12-9 11:30, 5.34 KB) / 下载次数 274
http://bbs.eccn.com/attachment.php?aid=462&k=43170451a8e87c36f2852bea048aca95&t=1732255492&sid=kodcbc


作者: linuxarm    时间: 2006-12-9 11:32

顺便提一下,我的BIOS里加的读函数,读指定地址的数据。
int ReadData(int argc, char *argv[])
{
 int addr, size,i;
 
 if(argc<3)
 {
  puts("Please enter move addr size\naddr = read addr, size = read size\n");
  return -1;  
 }
 
 addr = strtoul(argv[1]);
 size = strtoul(argv[2]);
 if(addr==-1||size==-1)
 {
  puts("Parameter error\n");
  return -1;
 }
 if(size>0x1000)
 {
  puts("Parameter error, size must less than 1000(in hex)\n");
  return -1;
 }
 
 printf("  Address        Data    \n");
 for(i=0;i<size/2;i++)
 {
  printf("  %x        %x    \n", addr+2*i,*((unsigned short *)addr+i));
 }
 return 0;
 
}
(CODE - 4)
板子复位,居然还是没有反映。。。。。。。。。。。。郁闷啊。

又怎么了呢?想吧。一时间真的搞不懂了。后来看了一些关于ads编译的资料,发现原来RO、RW和ZI还有文章。主要是没有技术支持,这些东西都要自己摸索,唉。。。。。。

 

Pp401oDn.jpg


HHAaBjO1.jpg


 

NCyXtKwe.jpg


图片附件: [S3C44B0 调试笔记BIOS部分] Pp401oDn.jpg (2006-12-9 11:32, 59.19 KB) / 下载次数 271
http://bbs.eccn.com/attachment.php?aid=463&k=356b736caad83a033de2acd3d77728ad&t=1732255492&sid=kodcbc



图片附件: [S3C44B0 调试笔记BIOS部分] HHAaBjO1.jpg (2006-12-9 11:32, 63.17 KB) / 下载次数 244
http://bbs.eccn.com/attachment.php?aid=464&k=059ee08f4f921e613a42a9676388cc6a&t=1732255492&sid=kodcbc



图片附件: [S3C44B0 调试笔记BIOS部分] NCyXtKwe.jpg (2006-12-9 11:32, 59.81 KB) / 下载次数 284
http://bbs.eccn.com/attachment.php?aid=465&k=fd3f1082c13d670ab2d95757cf90b7f5&t=1732255492&sid=kodcbc


作者: linuxarm    时间: 2006-12-9 11:35

ARM编译生成的代码中会分成两部分,RO和RW。同时编译会产生以下几个重要的地址空间分配变量:(如果想知道编译结束后,这些变量到底被赋了什么样的值,可以按照FIGURE-5配置ARM Linker。编译完成之后,你就可以看到很多编译细节,包括函数定位之类的信息。)
|Image$$RO$$Base| :Read Only 代码部分的起始地址。FIGURE – 3的RO BASE。
|Image$$RO$$Limit| :Read Only 代码部分的结束地址。
|Image$$RW$$Base| : Read Write 代码可读写部分的起始地址。FIGURE – 3的RWBASE。
|Image$$ZI$$Base|  :这里是程序中用到的一些变量使用的空间。
|Image$$ZI$$Limit| :变量结束的地址。

再看一段程序,BIOS中的初始化RAM的一部分程序:
 IMPORT InitSystem
 bl InitSystem 
 
 adr r0, ResetEntry
 ldr r1, BaseOfROM
 cmp r0, r1
 ldreq r0, TopOfROM
 beq InitRamData
   
 ldr r2, =CopyProcBeg
 sub r1, r2, r1
 add r0, r0, r1 
 ldr r3, =CopyProcEnd 

 ldmia r0!, {r4-r7}
 stmia r2!, {r4-r7}
 cmp r2, r3
 bcc %B0 
 
 ldr r3, TopOfROM  
 ldr pc, =CopyProcBeg
 
;***********************************************
CopyProcBeg 

 ldmia r0!, {r4-r11}
 stmia r2!, {r4-r11}
 cmp r2, r3
 bcc %B0 
CopyProcEnd
 
 sub r1, r2, r3
 sub r0, r0, r1  
 
InitRamData 
 ldr r2, BaseOfBSS
 ldr r3, BaseOfZero 
0
 cmp r2, r3
 ldrcc r1, [r0], #4
 strcc r1, [r2], #4
 bcc %B0 

 mov r0, #0
 ldr r3, EndOfBSS

 cmp r2, r3
 strcc r0, [r2], #4
 bcc %B1   
        
 ldr pc, GotoMain 

GotoMain DCD $MainEntry

;***********************************************
 IMPORT |Image$$RO$$Base| ; ROM code start 
 IMPORT |Image$$RO$$Limit| ; RAM data starts after ROM program
 IMPORT |Image$$RW$$Base| ; Pre-initialised variables
 IMPORT |Image$$ZI$$Base| ; uninitialised variables
 IMPORT |Image$$ZI$$Limit| ; End of variable RAM space


BaseOfROM DCD |Image$$RO$$Base|
TopOfROM DCD |Image$$RO$$Limit|
BaseOfBSS DCD |Image$$RW$$Base|
BaseOfZero DCD |Image$$ZI$$Base|
EndOfBSS DCD |Image$$ZI$$Limit|

  (CODE - 5)
ResetEntry是FIGURE-4中的 Image Entry Point。即程序入口地址。可以看出,上面程序的主要功能是将RO中的数据搬移至RW,同时将ZI中的数据清零。

这就对了,我最初的RO和ResetEntry都设至成了0,这样的话,数据搬移的时候就把已经被我擦除的Flash空间中的数据(一连串的0xff )搬到了RW段,所以导致程序无法正常运行了。我把RO和ResetEntry都设至成了0x1f0000,RW设成0xc700000。编译。然后再烧录到FLASH的0x1f0000。重启,OK啦!板子跑起来了,用rdpc命令,读出pc值是0x1f41c4(FIGURE - 6)。完全正确。不过还是BIOS程序,只不过换了个地址跑而已。不过这下明白了,前面提到的直接copy到0xc000000不能运行的问题也解开了。

2HcTOebC.jpg


图片附件: [S3C44B0 调试笔记BIOS部分] 2HcTOebC.jpg (2006-12-9 11:35, 7.27 KB) / 下载次数 285
http://bbs.eccn.com/attachment.php?aid=466&k=ba54ec3368f3c0f56c2c3e9a851fd460&t=1732255492&sid=kodcbc


作者: linuxarm    时间: 2006-12-11 12:16

重新设置了R0和ResetEntry都设至成了0xc000000,RW不变。然后编译成bin。从串口下载到板子的0xc000000处,然后run 0xc000000 。哈哈,跑起来了。rdpc返回值是0xc0041c4。正确。

下一步,是把uClinux的image下载到0xc000000处。在整个调试过程中,我的TCP/IP网络部分不知道什么时候坏掉了,看来还得抽时间去买个8019了。所以只好用串口下载了。串口下载了好几次,数据都不够,通讯会丢数据。最后不得不用FLUTED了,虽说慢点儿,但还是很好用啊(700多K,烧了50分钟吧)。image文件被烧到了0x100000处。然后重启进入0x1f0000处的BIOS程序,运行move 100000 c000000 100000 。然后run c000000。

 

 

1cVj1IN2.jpg


呵呵,启来了。不过后面报错了,看来我要装linux然后做修改了,到这里也算一个段落了,所以做个总结吧。

我的一点点心得,里面可能很多漏洞的地方,我也是个初学者,希望高手能够指点。



图片附件: [S3C44B0 调试笔记BIOS部分] 1cVj1IN2.jpg (2006-12-11 12:15, 22.55 KB) / 下载次数 275
http://bbs.eccn.com/attachment.php?aid=471&k=523633f0f6bdc20f6c24d743c131a63c&t=1732255492&sid=kodcbc






欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0