开始学习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: |
|
来自: 喜欢雨路的火... > 《XBase-PXA255》