分享

XBase255自带bootloader阅读

 喜欢雨路的火焰狼 2006-11-07
开始学习Xbase板子上自带的linux光盘厘米的bootloader
根目录下Makefile,很简短,两条规则,一条以伪目标做最终缺省目标的规则加另外一toa伪目标规则,很好理解,进入src目录进行make
先看Makefile和ld-xscale两个文件
Makefile:
定义好相关变量,好好学习Makefile文件相关知识就明白了,再定义all伪目标为最终目标,后面都好理解“$<”是自动变量,代表目标中的第一量,在
 .s.o :
    $(COMPILE) -c $<
中代表“.s”
顺便学习gcc编译的一些参数
-nostdinc   不要在标准系统目录中寻找头文件.只搜索`-I‘选项指定的目录(以及当前目录,如果合适).结合使用`-nostdinc‘和`-I-‘选项,我们就可以把包含文件搜索限制在显式指定的目录.
-mcpu=strongarm110  规定目标ARM处理器的类型,这样gcc就会产生相应的汇编代码
-mapcs-32  ARM处理器相关的选项
-fomit-frame-pointer  优化选项,对有些函数,不把frame pointer保存在一个寄存器中,这样就避免了那些保存,还原frame pointers的指令,还有使得函数多一个额外的寄存器可用
-fPIC   目标机器支持的话,生成目标无关的代码,支持动态连接
-Wall  打开所有警告选项
OCFLAGS = -O binary -R .note -R .comment –S  这是objdump的选项,去除所有.note .comment 和符号信息,生成二进制格式文件
LDFLAGS = -static –nostdlib  连接参数, -static是不连接共享库,–nostdlib,仅搜索那些在命令行上显式指定的库路径. 在连接脚本中(包含在命令行上指定的连
接脚本)指定的库路径都被忽略.

ld-xscale:
查询学习报告002种关于ld文件的说明,体会次文件内容
看.text 段
.text 0xA4000000 - 0x80000: //   0xA4000000查手册是第二块SDRAM的起始地址,那么在//这里安装002报告的学习,就是相当设置ARM映像文件的ro_base值了,//地址在第一块SDRAM最后512K处了,
   {
      _ld_text_start = .;   //定义了.test 段开始地址量,在就是上面的0xA4000000 - 0x80000
      *(.text)          //在链接所有要链接文件的 .text .got .got.pld .rodata 段,其中.got .got.pld 两种段没见过,得查ld手册了
      *(.got)
      *(.got.pld)
      *(.rodata)
      _ld_text_end = .;
   }
   _ld_text_size = SIZEOF(.text);  //得到 .text  段的大小量
再看 .data  段
.data _ld_text_end : AT(ADDR(.text) + SIZEOF(.text))   //  _ld_text_end为 .data 段的起始地址,AT(ADDR(.text) + SIZEOF(.text)  这在002报告中没有讲述,我也就不明白了,查询ld手册,也是为了 .data 段load时load到AT()中地址,尽管它的relocation地址可能不是这个,比如手册上举的例子,引用手册上原话
AT ( LDADR )‘
     The expression LDADR that follows the `AT‘ keyword specifies the
     load address of the section.  The default (if you do not use the
     `AT‘ keyword) is to make the load address the same as the
     relocation address.  This feature is designed to make it easy to
     build a ROM image.  For example, this `SECTIONS‘ definition
     creates two output sections: one called `.text‘, which starts at
     `0x1000‘, and one called `.mdata‘, which is loaded at the end of
     the `.text‘ section even though its relocation address is
     `0x2000‘.  The symbol `_data‘ is defined with the value `0x2000‘:

          SECTIONS
            {
            .text 0x1000 : { *(.text) _etext = . ; }
            .mdata 0x2000 :
              AT ( ADDR(.text) + SIZEOF ( .text ) )
              { _data = . ; *(.data); _edata = . ;  }
            .bss 0x3000 :
              { _bstart = . ;  *(.bss) *(COMMON) ; _bend = . ;}
          }
此时就不明白了这个  .mdata  段中0x2000有什么用处了
(这里就是要明白LMA和VMA的区别,套用dyh的话,就应该是LMA是加载域的地址,VMA是运行时域的地址了那么AT中的地址就是LMA,而.text .data后面的地址是VMA了,这里很关键,得明白)
(在最后生成的elf文件中,程序头表结束到.text 开始处有很多0,.text到0x8000,32K处,在readelf查看时是在程序头中这个segment有0x8000对齐的要求,但在这连接脚本中看不出啊???)
到最后,定义了  _ld_stack_address = _ld_text_start + 0x80000; 这个量,那么在这里这个_ld_stack_address不就是0xA4000000吗?为什么要这么用一个表达式了,是不是为了程序清晰?并且这样就可以看出整个bootload 大小不能超过这个0x800000,512K了(对了,看config.h,中定义的LOADER_MAX_SIZE(0x00040000)   大小最大为256K)

还这里,这些地址都是定义在SDRAM空间里,最开始bootload不是要在flash中运行吗?这中间地址转化是个什么过程了??(这就是要搞清楚地址卷绕的问题,尽管出现了地址卷绕但PC中的值是正确的,要搞清楚,要画出初始化时的内存分配图,每次变动内存控制器,就要在心里清楚此时的内存结构图)

开始到了start_xscale.S 文件了:
这是 .S   大后缀,会预处理,可以用include指令, _start  是在上面ld文件中通报了程序初始入口点,只有一条b指令,这里迷糊了,他在在合理不排列中断向量表吗?不把指令 派到0x20处吗?
然后就是reset部分,屏蔽所有中断,ICMR和ICLR定义如下:(来自上机指导)
Interrupt Controller Mask register (ICMR)
该寄存器能够屏蔽中断源,寄存器上每1位对应一个中断源,只要在相应的位上设置0,就能屏蔽响应的中断。系统复位后,该寄存器全为0,即所有的中断源都被屏蔽
Interrupt Controller Level register (ICLR)
该寄存器能够决定中断源以IRQ或FIQ中断方式被处理。只要中断源没有被屏蔽,设置该寄存器后,如果是以IRQ中断方式被处理,则ICIR相应位会置1,如果是以FIQ中断方式被处理,则ICFR相应位会置1。系统复位后该寄存器全为0,则表示所有的中断源都以IRQ方式被处理。
这里好像有不同的屏蔽所有中断的方式,好些程序都不一样,
然后三个子程序,GPIO,SDRAM,初始化,把自己考到RAM中,然后开始装载内核,装载内核利用三个变量KERNEL_SRAM_BASE,KERNEL_DRAM_BASE,KERNEL_MAX_SIZE,具体是什么值,以后再说,拷贝完毕后,装入_ld_stack_address值到sp,转入到主程序  c_main   
Gpio_init:
(GPFR是功能选择,GPSR&GPCR是设置/清除输出pin的值,GPDR就是设置pin是输入还是输出了)
六个GPIO Alternate Function Register,GAFR0_L, GAFR0_U, GAFR1_L, GAFR1_U, GAFR2_L, GAFR2_U, 定义85根GPIO针的功能选择,他们初始值常量,在 .h  文件中定义,
#define GAFR0L_VALUE      0x80000000
#define GAFR0U_VALUE      0xA5000010
#define GAFR1L_VALUE      0x60008018
#define GAFR1U_VALUE      0xAAA5AAAA
#define GAFR2L_VALUE      0xAAA0000A
#define GAFR2U_VALUE      0x00000002
具体值,对照手册,121页开始,其中GPIO第15(0L-80),0U中A5 就是第29,30,31位10,第28 为01 ,1L中,pin47=01,pin46=10,pin39=10,pin34=01,1U中pin63,62,61,60,59,58,57,55,54,53,52,51,50,49,48=10,pin56=01,在2L中pin79,78,77,76,75,74,65,64=10,在2U中,pin80=10,总结一下,pin (15,29,30,31,39,46,48,49,50,51,52,53,54,55,57,58,59,60,61,62,63,64,65,74,75,76,77,78,79,80)为10,pin (28,34,47,56)为01,其他全为0;
再把设置三个GPSR的值为
#define GPSR0_VALUE       0x00408030//   00000000010000001000000000110000
#define GPSR1_VALUE       0x00BFA882//  00000000101111111010100010000010
#define GPSR2_VALUE       0x0001C000//   00000000000000011100000000000000
定义为1的位就设置该IO口为1
再设置三个GPCR值
#define GPCR0_VALUE       0xC0031100//
#define GPCR1_VALUE       0xFC400300
#define GPCR2_VALUE       0x00003FFF
再三个GPDR,
#define GPDR0_VALUE       0xC0439330//
#define GPDR1_VALUE       0xFCFFAB82
#define GPDR2_VALUE       0x0001FFFF
Datasheet上的例子说设置GPIO的其他功能时要先设置GPSR&GPCR,在设GPDR,在设GAFR,但这里好像恰好相反哦)
再接下来的PSSR,PSSR_RDH ,PSSR_PH,参考手册91页就了解了,属于电源管理中睡眠状态时GPIO的处理
GPIO初始化完毕。主要初始化了中断,GPIO

开始init_sdram:
这部分最烦,主要是对SDRAM,ROM各部分机理还不清楚,先看拷贝到RAM中代码
比较好理解,就是在ld文件定义了的_ld_text_start,_ld_text_and_data_size变量,从flash地址0,拷贝到_ld_text_start(0xA4000000-0x800000),长度是_ld_text_and_data_size,在实际运行过程中,这些地址怎么个过渡法,现在还不是很清楚了,(这里就是要有加载时域和运行时域的概念了,在前面内存初始化已经建立了初始的内存图,这时,代码中,拷贝的源基地址r0为0,就是加载域的起始地址,目的的基地址ld_text_start就是运行时域的起始地址,只有这样才能保证后面的地址访问是正确的,这里,要根据内存初始图仔细体会,我现在还没搞清楚内存初始化,所有这里也不明白,也不敢下手该地址,等完全明白了内存地址的变化后,再动手修改连接脚本中的地址,实现XIP的终极目标,能够XIP时,这里肯定要修改了,只要拷贝.data到RAM中去就可以了)
我认为,在这里一定要搞懂这里的内存初始化代码才继续下面主函数的理解

先设置CCCR,CLOCK_MANAGER_BASE在0x41300000,设置L,M,N,手册96页开始,先设CKEN,和OSCC,设CKEN(使能外围功能模块),使FFUART Unit Clock使能,FFUART的功能还不明白,其他的外网功能块的时钟都先不使能,OSCC使能32.768KHz晶体(打开OON,使得RTC和PM可以用这个脉冲了),然后设CCCR,0000 0010 0100 0001 N=100,M=10,L= 00001,那么Memory Frequency为27陪3.6864MHz,99.53MHz,大概100M,M=2,Run Mode Frequecy为200MHz了,N=2,则Turbo Mode Frequecy 为400MHz了,在设置协处理器P14, FCS=1,TURBO=1,Enter frequency change sequence Enter turbo mode,
在设OSCR为0,再等待0x300个脉冲,
再设置MSCx,手册229页,注意这个MSCx的作用,是配置跟片选信号nCS(1:0), nCS(3:2), and nCS(5:4)相关的静态内存
感觉这里是理解芯片存储器空间配置的关键了,这需要好心情好状态才能明白啊,datasheet又没有中文翻译
#define MSC0_VALUE      0x7FF87FF0 从后往前读,000-Nonburst ROM/Flash Memory,0-32bit,1111-RDF为23,1111-RDNx,对照手册读一下(这里对着手册也理解不了啊,郁闷啊)
#define MSC1_VALUE        0x12BC5554
#define MSC2_VALUE        0x7FF97FF1(这里在我的板子上,只有一块Intelâ strata flash 32MByte 的flash芯片,那不知道这里设着干嘛去了)
根据手册上建议,设置后要再读回一次,确保有效。
MECR为00000000,MCMEMO0,MCMEMO1,MCATT0,MCATT1,MCIO0,MCIO1手册263,是关于Expansion Memory (16-bit PC Card / Compact Flash) Bus Configuration register 的,我的板子上也没有吧,我现在还不清楚?
接下来是干什么的11步,“extracting the DRI”不知是什么啊,好郁闷啊,不知道最好从哪里开始下手查资料啊

根据程序注释,是要做DRI,就是当有GPIO reset时要在刷新间隔里刷新SDRAM,现在还不是很明白,好像这样的目的都是为了正确的配MDREFR[DRI],
明白了这里的步骤是根据datasheet 261页上建议的,看来手册整个第六部分都得好好看一遍才行,先看这里吧
第一步:说首先设置K0RUN和 E0PIN,清除 KXFREE
#define MDREFR_VALUE      0x000BC018  (0  1011 1100 0000 0001 1000)
这里对照手册198页看,r0即上面的VALUE,跟r1=0xfff与后,只有018即DRI的值了,
bic     r3, r3, r1   先把r3中的DRI清零,
bic    r3, r3, #0x03800000  再把KxFREE清零,使SDRAM not free-running,
orr     r3, r3, r0  此时,r0只剩DRI值为018了,这时,r3中的DRI也为018了
str     r3, [r12, #MDREFR]   这时就可以写回去了,
这里的MDREFR_VALUE不知道具体有什么用,直接把r0设为0x018,不就可以了,为什么要通过MDREFR_VALUE了?这里也没有设置K0RUN和E0PIN
第二步:主要是针对有Synchronous Static memory的设置,我们板子没有,就跳过
第三步:这步是对有SDRAM的系统来说的,要通过以下步骤转变SDRAM控制器
a. self-refresh and clock-stop
 b. self-refresh
c. power-down
d. PWRDNX
e. NOP
源码中也没做这步,认为前面已经做过了,但又说最好在这里放上Self-Refresh Disable,步明白
第四步:手册上的步骤好像就是说上面第三步怎么变换
写 MDREFR:K1RUN, K2RUN 配置MDREFR:K1DB2,K2DB2.
写MDREFR:SLFRSH


这里都看步下去了,看的也是稀里糊涂的,其实,还是因为对这些RAM的机制不明白,现在有把手册第6部分从头到尾细细看一遍的打算,步知道能步能实现,没信心!







最后转到main.c 文件中的C语言主函数,c_main( )执行,src下面start_xscale.S和start_xscale.c文件是一样的,为什么要这么安排了?
看include目录下的config.h文件
先根据板子型号是XHYPEr255A还是B,定义FLAHSHSIZE是16M还是32M,在这里肯定是32M了
#define SRAM_BASE_ADDR            (0x00000000)     静态内存基址
#define SRAM_SIZE            FLASHSIZE     大小,32M
#define SRAM_BLOCK_SIZE            (0x00040000)   块大小,256K

#define DRAM_BASE_ADDR            (0xA0000000)   SDRAM的基址,
#define DRAM_SIZE            (0x02000000)     SDRAM大小,32M???应该是此时只
需要32M就可以了

#define LOADER_DRAM_MAX_SIZE    (0x00010000)  loader在DRAM里最大大小64K
#define LOADER_SRAM_MAX_SIZE    (0x00040000)  在SRAM里256K
#define LOADER_DRAM_BASE        (DRAM_BASE_ADDR+DRAM_SIZE-LOADER_DRAM_MAX_SIZE) loader在DRAM中基址
#define STACK_POINT            (DRAM_BASE_ADDR+DRAM_SIZE-LOADER_DRAM_MAX_SIZE-4)  栈指针

#define KERNEL_SRAM_BASE        (0x000C0000)    内核在SRAM基址在3*256K,即第
四块block开始处
#define KERNEL_DRAM_BASE        (0xA0008000)  在DRAM中是DRAM基址+16K处
#define KERNEL_MAX_SIZE            (0x00200000)  内核最大为2M
#define NUM_KERNEL_BLOCKS    (KERNEL_MAX_SIZE / SRAM_BLOCK_SIZE) 8块

#define ROOT_SRAM_BASE            (0x002C0000)   在1011*256K处,第12块开始处
#define ROOT_DRAM_BASE            (0xA0000000)   在DRAM基址处
#define ROOT_MAX_SIZE            (0x01D00000)     最大30M
#define NUM_RAMDISK_BLOCKS        (RAMDISK_MAX_LEN / SRAM_BLOCK_SIZE)

#define LOADER_SRAM_BASE        (0x00000000)    在SRAM中基址0,
#define LOADER_MAX_SIZE            (0x00040000)   大小最大为512K
#define NUM_LOADER_BLOCKS        (LOADER_MAX_LEN / SRAM_BLOCK_SIZE)
这个文件定义了loader,kernel,root 三部分的地址参数量,
把ROOT_DRAM_BASE定义到DRAM_BASE_ADDR,想不清为什么,还要这里的ROOT_MAX_SIZE设为30M,也不明白,
开始看init_sdram:

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多