PowerPC non-DPAA 平台上的启动方式

来源:互联网 发布:网络宣传策划方案 编辑:程序博客网 时间:2024/05/17 07:13

09年在MPC8536E上做启动开发的工作,当时的目标就是将“从NOR flash/NAND flash/SD卡/SPI flash启动”这几中方式用比较统一的方式来实现,并将patch推到Wolfgang的U-Boot tree上。下面是当时开发时做的一些记录,所以基于的U-Boot code是09年的,但变化不大,重要的是原理。


PowerPC CPU可以从不同的存储介质上启动,最常用的是从NOR flash启动,还可以从NAND flash启动,从SD卡启动,从SPI flash启动。为什么需要这么多种的启动方式?需求驱动,本来NOR flash是启动设备的最佳选择,能擦除且字节访问,但容量不够大,所以在单板设计中还可能需要另外一种存储介质去存放kernel image,根文件系统什么的,比如使用NAND flash,这时问题就来了,系统中既然有个NAND flash,能不能将bootloader也放在NAND flash中,从而可以从NAND flash启动?但人家NAND flash志存高远,当时设计的目的是为了取代硬盘而不是作为非易失行存储介质去和NOR flash抢饭碗,像U盘,SD卡,记忆棒,还有固态硬盘SSD神马的,内部都是NAND flash,这也就注定了NAND flash是以block为单位访问的,但我们CPU只能是字节访问,所以要想从NAND flash启动还得需要eLBC controller的帮忙(NOR/NAND一般都挂在local bus控制器上)。从SD卡上启动就更进一步了,整个系统都在一块卡上,拎着想去哪就去哪,呵呵。下面就开始扯吧,先会扯一点CPU地址空间,LAW,TLB,cache什么的,然后是各个不同启动机制的介绍,U-Boot启动代码的解析还有相关的patch介绍,在Wolfgang 的git tree上,还有开发碰到的问题等等。。。

下面这些问题应该能从本文中找到答案:

1. CPU的基础知识和各种启动方式的原理
   - U-Boot image存放在NOR flash/NAND flash/SPI flash/SD 卡的什么位置?
   - CPU core启动时怎么去相应的存储介质读取U-Boot image?
   - U-Boot image的连接地址和image在存储介质存放的地址有关系吗?
   - CPU的一些基础知识:地址空间AS0/AS1,TLB,LAW

2. 启动代码的一些重要细节
   - U-Boot在L1 Dcache中建立的stack
   - 怎么将L2 Cache初始化为SRAM?
   - SRAM的空间怎么分配?
   - CPU怎么在地址空间(AS0/AS1)进行切换?为什么要切换?
   - 代码relocate的过程。比如从NAND flash到L2 SRAM,在到DDR。
   - 代码在L2 SRAM运行时,需要使用L2 SRAM作为堆栈,怎么建立相应的堆栈?

1. 基础


1.1 CPU地址空间

先来张MPC8536E的架构框图:




什么是地址空间呢?在手册上也叫local address map,就是core能够访问到的36bit的地址空间。这个地址空间包括各个功能模块能够访问到的地址空间,DDR SDRAM空间以及CCSR地址空间。CPU core是怎么访问SOC上的各个功能模块的?比如eLBC控制器,DDR控制器,PCI控制器等等。通过LAW(Local AccessWindow)寄存器来配置。每个LAW寄存器将一段地址空间和相应的功能模块连接起来,从core出来的物理地址和各个LAW的地址进行比较,如果在某个LAW指定的地址空间,那么就将这个交易发送给该LAW指定的功能模块。

每个LAW可指定的地址空间大小为4K-32G。

特别提醒:LAWBA[BASE_ADDR]域必须和地址空间大小对齐。


在这个地址空间中有三段地址是比较特殊的:


1.CCSR的地址空间

这段地址空间只需要通过CCSBAR寄存器来指定起始地址,地址空间大小是固定的1M空间(e500 core是1M,e500mc是16M)。

CCSRBARConfiguration,Control, and Status Registers Base Address Register)的缺省值是0xFF700000


访问该空间的TLB在设置时,需要将IG位置1.


2.L2 SRAM地址空间

MPC8536E有512K的L2 cache,该cache可以配置为SRAM使用,此时需要通过L2CTL[L2SRAM]域来指定L2SRAM的大小,通过L2SRBAR寄存器指定其实地址。


3.缺省的8M bootrom地址空间

一般soc会定义8MBbootRom启动地址空间(0xFF80_0000–0xFFFF_FFFF),在core复位启动访问第一条指令时能够直接访问指定启动设备的地址空间。启动设备可以指定挂在eLBC上的NAND flashNOR flash,或者指定SDCARD/SPI flash


上述地址空间配置优先级:

L2SRBAR指定的地址优先于其他方式指定的地址空间;

CCSRBAR指定的地址空间不能和DDR控制器指定的地址空间重复,否则,cpu行为是未定义的;

LAW之间的地址如果重复,则低编号LAW覆盖高编号LAW的地址空间;


1.2 TLB


TLB简单说就是将程序虚拟地址转化为物理地址的一个查找表。TLB使用WIMGE字段来指定所访问地址空间的属性。以后会单独写下TLB,比如怎么配置TLB,怎么查找TLB,TLB在U-Boot和内核的使用,内核进程切换时TLB的切换操作等。


在启动的时候,所有L1/L2MMU中的TLB Entry都为无效的,除了TLB1Entry0,Entry被赋予以下数值来指定地址空间0(AS0)中的4KB启动地址空间(0xFFFF_F000– 0xFFFF_FFFF)。在U-Boot代码中,这段4K代码被称为bootpage,即cpu/mpc85xx/start.S中的bootpg汇编代码。

E500 core在复位的时候会去0xFFFF_FFFC去读取第一条指令,该指令一般是一条跳转指令,跳转到bootpg的头部去执行。




1.2.1 TLB WIMGE

WIMGE字段是e500内核进行虚实地址转化时,用来描述TLB对应的物理地址空间的访问属性字段。这几个字段配置和Cache的MESI协议来保持Cache一致性。


Write-throughrequired (W)

若此位为1,说明对该物理地址空间访问时采用cache-through策略;

若此位为0,说明对该物理地址空间访问时采用cache-back策略;


Caching inhibited (I)

若此位为1,说明对该物理地址空间访问时不使用L1 cache

若此位为0,说明对该物理地址空间访问时使用L1 cache


Memory coherency required (M)

若此位为1,说明对该物理地址空间访问时需要进行存储一致性处理;


Guarded(G)

若此位为1,说明对该物理地址空间访问时需要对相应的地址空间进行保护,阻止PowerPC的猜测访问;


Endianness(E)

若此位为1,说明对该物理地址空间访问时采用小端模式;

若此位为0,说明对该物理地址空间访问时采用大端模式;


想更多了解write through/write back,cache inhibited和guarded怎么影响Cache一致性,请参阅EREF。


2.boot from NOR flash


一般NOR flash挂接在CPU的eLBC控制器上,通过CS0来片选。要想从NOR flash启动,首先将编译好的512K U-Boot image烧写到NOR flash的最后512K中。CPU core启动时会去0xFFFFFFFC处取第一条指令执行,一般是一条跳转指令跳转到bootpage的地方,因为NOR flash是可以字节访问的,随后CPU会顺序执行NOR flash中的代码。


2.1 eLBC


eLBC通过GPCM连接NOR flash,通过FCM来连接NAND flash

BR0/OR0– BR7/OR7 指定eLBC 8个片选信号所对应的地址空间和属性。CS0连接启动设备,比如从NOR flash启动时,NOR flash必须连接到CS0上。从NAND flash启动时,NAND flash必须连接到CS0上。对于既有NOR flash又有NAND flash的单板,并且支持两种启动模式的话,需要CPLD来动态切换CS0片选信号指向启动设备。

当选择从NOR flash启动时,CS0是作为启动片选信号输出,选择的地址和空间由BR0OR0信息来决定,该寄存器启动值如下,显然访问的是从0– 0xFFFFFFFF4G地址空间。该片选信号一直按照此种方式运行直到第一次更改BR0OR0的值



在往NORflash烧写U-Boot程序时,是将512Kimage写到flash的最后512K字节,即eff8_0000开始的地方。core启动时第一条指令是FFFF_FFFC实际上读取的就是就是efff_fffc处的指令(0x4BFF_F004)。


2.2 启动过程


首先一个问题是U-Boot image要烧写到NOR flash的哪个地址?是由CPU和NOR flash的硬件连线决定的。同时该地址也决定了U-Boot的CONFIG_SYS_TEXT_BASE的值,该值在config.mk文件中赋值给-Ttext,也就是U-Boot image中text段的起始地址。

关于 ld script的内容可以参考《Using ld - The GNU linker》的小册子。这里只提下面几个参数:

1. -T指定使用的script文件

2. -e指定image的开始执行的地址

3. -Ttext: 和--section-start .text同义,该字段的意思是给text段指定绝对地址。


#ifndef CONFIG_SYS_TEXT_BASE
#define CONFIG_SYS_TEXT_BASE    0xeff80000
#endif

LDFLAGS_u-boot += -T $(obj)u-boot.lds $(LDFLAGS_FINAL)
ifneq ($(CONFIG_SYS_TEXT_BASE),)
LDFLAGS_u-boot += -Ttext $(CONFIG_SYS_TEXT_BASE)
endif


以MPC8536DS单板来看下CPU 和 NOR flash的硬件连线:



使用的NOR flash芯片是128MB的29GL01GP,通过单板上的一个拨线开关可以将128M的flash划分为4个bank,每个bank 32M。

通过上图可以看到CPU地址线的使用如下:

0 1 2 3

4 5 6

7-30

31

读取flash时,高4位不会用到,所以分配该4位主要看U_Boot的地址空间分配。在8536DS中分配的是e

Localbus地址空间是从e000_0000efff_efff.

Promjete0000000-e7ffffff

NOR flash:

e8000000-efffffff


通过FPGA来设置flash25/26两位地址线,相当于把NOR flash划分为4region

连接NOR flash的低24位数据线(32M)

通过16bit的数据线连接NORflash,所以不care最低位

1110


10 0

10 1

11 0

11 1


0_0…0=> e800_0000 – e9ff_ffff

0_0…0=> ea00_0000 – ebff_ffff

0_0…0=> ec00_0000 – edff_ffff

0_0…0=> ee00_0000 – efff_ffff


x



在往NOR flash烧写U-Boot程序时,是将512Kimage写到flash的最后512K字节,即eff8_0000开始的地方。core启动时,会去地址FFFF_FFFC获取第一条指令实际上读取的就是efff_fffc处的指令,因为CPU高4位数据线根本就没有连接到NOR flash上

那么在地址efff_fffc地方存放的是什么指令,需要看U-Bootld script,因为ld script决定了U-Boot image每个段存放的内容。


U-Boot image使用的load scriptor 是u-boot.lds


SECTIONS

{

......


.text :

{

*(.text)

*(.got1)

}:text

_etext= .;

PROVIDE(etext = .);


/*Read-write section, merged into data segment: */

.= (. + 0x00FF) & 0xFFFFFF00;

_erotext= .;

PROVIDE(erotext = .);

......

.bootpg RESET_VECTOR_ADDRESS - 0xffc :

{

cpu/mpc85xx/start.o(.bootpg)

}:text = 0xffff


.resetvec RESET_VECTOR_ADDRESS :

{

*(.resetvec)

}:text = 0xffff


.= RESET_VECTOR_ADDRESS + 0x4;


.= ALIGN(4);

_end= . ;

PROVIDE(end = .);

}

"board/freescale/mpc8536ds/config.mk"

ifndefTEXT_BASE

TEXT_BASE= 0xeff80000

Endif


RESET_VECTOR_ADDRESS= 0xeffffffc

"cpu/mpc85xx/resetvec.S"


.section.resetvec,"ax"

b_start_e500



从上面的ldscript可以看出,u-boot image最后的4个字节存放的是启动向量,即一条跳转到bootpg的跳转指令(0x4BFF_F004)。可以通过objdump u-boot 找到U-Boot image最后4个字节的内容。


显然core启动时读取的就是这条指令0x4BFF_F004,这条指令是条跳转指令(因为OP = 010010),core的指令译码单元会执行如下的计算来得到跳转到的地址:

010010  11 1111 1111 1111 0000 0000 01 0 0

-------|-----------------------------------|--|---

OP     | LI                                |AA|LK

--------------------------------------------------


EXTS(LI || 0b00) => 0xFFFFF004

CIA              => 0xFFFFFFFC

-------------------------------

                    0xFFFFF000


通过objdump u-boot可以看到effff000出存放的代码,对应的是start.S文件中的4k 的启动代码段bootpg。

effff000<_start_e500>:

effff000: 38 00 00 02 li r0,2

effff004: 7c 12 fb a6 mtdbcr0 r0

effff008: 7c 13 fb a6 mtspr 1011,r0

effff00c: 7c 30 4a a6 mfspr r1,304

effff010: 7c 30 4b a6 mtspr 304,r1

effff014: 3c 40 00 01 lis r2,1

effff018: 60 42 00 01 ori r2,r2,1

effff01c: 7c 52 fb a6 mtdbcr0 r2

effff020: 4c 00 01 2c isync

effff024: 7c 53 fb a6 mtspr 1011,r2

effff028: 4c 00 01 2c isync

effff02c: 7c 00 04 ac sync


"cpu/mpc85xx/start.S"


.section.bootpg,"ax"

.globl_start_e500


_start_e500:


/*clear registers/arrays not reset by hardware */


/*L1 */

li r0,2

mtspr L1CSR0,r0 /* invalidate d-cache */

mtspr L1CSR1,r0 /* invalidate i-cache */


mfspr r1,DBSR

mtspr DBSR,r1 /*



随后就顺序执行start.S代码,具体的代码分析在下面的boot from NAND flash会有介绍。


3.boot from NAND flash

下面是支持boot from NAND/SD/SPI flash的一些patch:

ppc/85xx: add boot from NAND/eSDHC/eSPI support:
http://git.denx.de/cgi-bin/gitweb.cgi?p=u-boot.git;a=commit;h=7da53351d817c6d77364cfde922891f37d0e5ed8
NAND boot: MPC8536DS support:
http://git.denx.de/cgi-bin/gitweb.cgi?p=u-boot.git;a=commit;h=9a1a0aedbbd56f901bfbc124f18ec6d9dcefe282
On-chip ROM boot: MPC8536DS support:
http://git.denx.de/cgi-bin/gitweb.cgi?p=u-boot.git;a=commit;h=e40ac4870c6e72302044e98338322f45c34435bd
Add README.mpc8536ds:
http://git.denx.de/cgi-bin/gitweb.cgi?p=u-boot.git;a=commit;h=693a048d8ac191181f5b9adbff642d3f1bbd479f

建议先可以看下这些patch的commit log,这样对整个启动流程和代码的实现有个整体的了解。我将NAND boot: MPC8536DS support的commit log拷贝过来了,懒得翻译了,凑乎看吧。
NAND boot: MPC8536DS support

MPC8536E can support booting from NAND flash which uses the
image u-boot-nand.bin. This image contains two parts: a 4K
NAND loader and a main U-Boot image. The former is appended
to the latter to produce u-boot-nand.bin. The 4K NAND loader
includes the corresponding nand_spl directory, along with the
code twisted by CONFIG_NAND_SPL. The main U-Boot image just
like a general U-Boot image except the parts that included by
CONFIG_SYS_RAMBOOT.

When power on, eLBC will automatically load from bank 0 the
4K NAND loader into the FCM buffer RAM where CPU can execute
the boot code directly. In the first stage, the NAND loader
copies itself to RAM or L2SRAM to free up the FCM buffer RAM,
then loads the main image from NAND flash to RAM or L2SRAM
and boot from it.

This patch implements the NAND loader to load the main image
into L2SRAM, so the main image can configure the RAM by using
SPD EEPROM. In the first stage, the NAND loader copies itself
to the second to last 4K address space, and uses the last 4K
address space as the initial RAM for stack.

Obviously, the size of L2SRAM shouldn't be less than the size
of the image used. If so, the workaround is to generate another
image that includes the code to configure the RAM by SPD and
load it to L2SRAM first, then relocate the main image to RAM
to boot up.


3.1 TEXT_BASE

为什么从NAND启动时,TEXT_BASE设置为0xF8F8_2000.


因为我们需要将4K NAND loader和第二阶段的image合并起来(通过cat命令),然后烧写到NAND flash。启动时FCM会将4K NAND loader拷贝到FCM RAM buffer中,而4K NAND loader会将4K NAND loader和第二阶段image拷贝到L2SRAM中。我配置L2SRAM的地址是0xF8F80000,加上4K NAND loader,加上4k bootpg,所以第二阶段的text段应该在0xF8F82000.

3.2 eLBC


NAND启动时LCS0是从eLBC启动时的片选输出,且BR0OR0设置的值是固定的,如下:


-------------------------------------------------

Register| Filed | setting

-------------------------------------------------

BR0 | BA <-> 0000_0000_0000_0000_0

|PS <-> port size,跳线选择

|MSEL <-> 001, FCM

-------------------------------------------------

OR0 | AM <-> 0000_0000_0000_0000_0, 4G

|PGS <-> Page Size,跳线选择

-------------------------------------------------


显然从0-4G空间的访问都访问由该LCS0控制的memory芯片。LCS0一直以这种方式操作直到程序第一次往OR0写数据。


当选择从NAND Flash启动时,即选择FCMbootRom controllereLBC通过LCS0来选择要访问的NAND Flash,并循环搜索NAND Flash的每一block的开始两个page,直到找到4K boot code,然后将4K boot code拷贝到内部的RAM buffer中,RA Mbuffer是字节寻址的,以后CPU执行指令从该RAM buffer获取。


访问8Mboot region会指向bootRom location指定的接口,在此即为eLBC,实际上访问的是FCM中的4K RAM buffer,所以访问0xFF80_00000xFFFF_FFFF8M空间时访问的都是4K FCM RAM buffer


E500上电执行的第一条指令是0xFFFF_FFFC,访问FCM RAM buffer来获取第一条指令:

b_start_e500 (0x4BFFFB40).


010010  11 1111 1111 1111 1011 0100 00  0 0

-------|-------------------------------|--|---

OP     | LI                            |AA|LK

----------------------------------------------


EXTS(LI|| 0b00) => 0xFFFFFB40

CIA             => 0xFFF00FFC

-------------------------------

                   0xFFF00B3C <-> _start_e500对应的地址


3.3 代码解析


下面就是详细的代码解析:

"cpu/mpc85xx/start.S"

.section.bootpg,"ax"

.globl_start_e500


_start_e500:

Invalidated-cache

Invalidatei-cache

EnableL1 Cache

Setinterrupt vector


Settemp mapping in AS1 to boot windows

设置AS1TLB1/Entry15 -> Boot代码


Set mapping in AS1 to Init Ram

设置AS1TLB1/Entry14 -> Initial Ram


Switchto AS1

Set mapping in AS1 to Init Ram


        lis     r6,MSR_IS|MSR_DS@h

ori     r6,r6,MSR_IS|MSR_DS@l

lis     r7,switch_as@h

ori     r7,r7,switch_as@l


mtspr   SPRN_SRR0,r7

mtspr   SPRN_SRR1,r6

rfi


        进行地址空间切换时,需要配置好准备跳到的地址空间的LAWTLB,最基本的三个就是:

Boot代码所在位置的LAW/TLBInitRam对应的LAW/TLBCCSR对应的TLB.

但上面代码为什么没有设置LAWe500有缺省的8Mboot空间(0xFF80_0000–

0xFFFF_FFFF.CCSRBAR对应的就是1MLAW


rfi指令用来进行地址空间的切换。rfi就是返回到SRR0寄存器的地址,恢复SRR1的内容到MSR

显然我们设置了MSR[DS]和MSR[IS]为1,也就是取指令和数据都到AS1中取。


switch_as:

Allocate Init Ram in date cache

/* Allocate Initial RAM in L1 data cache.
     */
    lis     r3,CONFIG_SYS_INIT_RAM_ADDR@h
    ori     r3,r3,CONFIG_SYS_INIT_RAM_ADDR@l
    mfspr   r2, L1CFG0
    andi.   r2, r2, 0x1ff
    /* cache size * 1024 / (2 * L1 line size) */
    slwi    r2, r2, (10 - 1 - L1_CACHE_SHIFT)
    mtctr   r2
    li      r0,0
1:
    dcbz    r0,r3
    dcbtls  0,r0,r3
    addi    r3,r3,CONFIG_SYS_CACHELINE_SIZE
    bdnz    1b

  1. Initial RAM对应的地址没有设备响应

  2. Initial RAM对应的TLBI属性必须为0,即使能cache,如果访问的是cache inhibitedmemory,该指令会访问该地址对应的backing store,而实际上该init ram没有对应任何有效的设备,所以请该地址必然会出错。如果I=0,即dcbz指令会在该地址对应的cache中建立而且不从相应的momory设备读取数据。这样再使用dcbtls将该block锁定即建立了一片能够访问的堆栈空间。

  3. Initial RAM通过dcbtls设置为lock,从此访问该地址只是从data cache中获取,而不会去读该地址对应的设备,如果有的话。


Jump out the last 4K page bootpg to .text, and continue

#ifdef CONFIG_SYS_RAMBOOT

    b __start_cont

#else

    /* Calulate absolute address in Flash and jump there */

    lis r3, CONFIG_SYS_MONITOR_BASE@h

    ori r3, r3, CONFIG_SYS_MONITOR_BASE@l

    addi r3, r3, __start_cont - _start + _START_OFFSET

    mtlr r3

    blr r3

#endif

若是boot from NAND/SD/SPI flash,直接跳转到_start_cont

若是boot from NOR flash,有上面的操作。在此之前的4K bootpg的PC

FFFF_xxxx开始的地址,读出的内容地址是eff8_xxxx(链接地址),在跳转之后,

PC跳转到eff8_xxxx开始的地址(即_start_cont处)


.text

.align 4

.globl _start_cont

_start_cont:


Setup the stack in initial RAM

即将sp指针(r1)指向刚刚allocate并初始化好的堆栈,并建立堆栈的调用关系。


GET_GOT

bl cpu_init_early_f

->设置CCSRBAR对应的TLB,将CCSRBAR迁移到0xFFE0_0000

在没有设置CCSRBAR0xFFE0_0000时,访问该地址实际上访问的就是FCM RAM

Buffer,而当将0xFFE0_0000写入到CCSRBAR时,该地址对应的1M空间清零,对应

1Mregister memory map

->配置AS0LAW/TLB


Switch back to AS0


bl cpu_init_f [cpu/mpc85xx/cpu_init_nand.c]

  1. 重新设置BR0/OR0,到此BR0/OR0boot状态恢复到正常的片选引脚,而限制在LCS0上的所有限制都将无效,比如访问8Mbootr egion并不是都映射到FCM RAM buffer。此时设置BR0/OR0指向NAND Flash对应的地址(0xFFF0_0000)只有

0xFFF0_0000-0xFFF0_1000对应的是FCM RAM buffer.

  1. 初始化L2SRAM


blboard_init_f [nand_spl/board/freescale/mpc8536ds/nand_boot.c]

  1. 设置BR3/OR3,访问FPGA,该部分是单板相关的

  2. 初始化串口

  3. 调用relocate_code,将4K NAND loader本身拷贝到L2SRAM的倒数第二个4K处,堆栈使用L2SRAM倒数第一个4K空间。

  4. relocate_code最后会调用board_init_r,将4K NAND loader 和第二阶段的image拷贝到L2SRAM的起始处,然后跳转到第二阶段的image开始处执行。


isync



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

nand_spl/board/freescale/mpc8536ds/nand_boot.c:


voidboard_init_f(ulong bootflag)

{

relocate_code(CONFIG_SYS_NAND_U_BOOT_RELOC_SP,0,

CONFIG_SYS_NAND_U_BOOT_RELOC);

4K NAND loader拷贝到L2 SRAM的倒数第二个4K的空间,而此时使用的堆栈是

L2SRAM的倒数第一个4K空间。

  1. 为什么要首先拷贝4KNAND loader

因为拷贝main image的代码就在4K NAND loader中,即在FCMRAM buffer

中,nand_load函数中会将FMR[BOOT]清零,这会将FCM RAM buffer也清零,

即将运行的代码清空了,必然会出错,所以首先将4K NAND Loader拷贝到L2 SRAM

再运行nand_load函数来加载main image

}


下面这两个宏用来完成4K NAND loader的自拷贝:

#define CONFIG_SYS_NAND_U_BOOT_RELOC (CONFIG_SYS_INIT_L2_END - 0x2000)

指示4K NAND loader需要copy到的地址


#define CONFIG_SYS_NAND_U_BOOT_RELOC_SP ((CONFIG_SYS_INIT_L2_END - 1) &~0xF)

指示4K NAND laoderL2SRAM中运行时使用的堆栈

"cpu/mpc85xx/start.S":


.globl relocate_code

relocate_code:

relocate code

addi r0,r10,in_ram - _start + _START_OFFSET

mtlr r0

blr /* NEVER RETURNS! */

.globl in_ram

in_ram:

从现在开始就是在L2SRAM的倒数第二个4K空间运行


Adjust GOT

Adjust FIXUP_TABLE

bl board_init_r


voidboard_init_r(gd_t *gd, ulong dest_addr)

{

nand_boot();

}


voidnand_boot(void)

{

__attribute__((noreturn))void (*uboot)(void);


/*

*Load U-Boot image from NAND into RAM

*/

nand_load(CONFIG_SYS_NAND_U_BOOT_OFFS,

CONFIG_SYS_NAND_U_BOOT_SIZE,

(uchar*)CONFIG_SYS_NAND_U_BOOT_DST);

NAND flash 0地址开始的地方拷贝504K的数据到0xF8F8_0000L2SRAM中),

实际上拷贝了两部分iamge4K NAND Loadermian image。显然main image

的大小最多为500K


  1. 为什么要拷贝4K NAND Loder

  2. 为什么偏移地址为0

为了方便,4K NAND loadermain image合在一起写入到NAND Flash

而从NAND Flash拷贝数据是以block为单位,所以从0开始读会方便一些。

当然也可以将4K NAND loader扩展到flash的一个block长度,然后从flash

拷贝数据时跳过第一个block


/*

*Jump to U-Boot image

*/

puts("transfering control\n");


/*

*Clean d-cache and invalidate i-cache, to

*make sure that no stale data is executed.

*/

flush_cache(CONFIG_SYS_NAND_U_BOOT_DST,

CONFIG_SYS_NAND_U_BOOT_SIZE);

uboot= (void *)CONFIG_SYS_NAND_U_BOOT_START;

uboot();

}


#define CONFIG_SYS_NAND_U_BOOT_START 0xF8F8_1000 <-> _start_e500

0xF8F8_1000,对应第二阶段image_start_e500


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


第二阶段代码的运行。


现在代码在L2 SRAM中执行main imagebootpg,运行代码,即boot_page代码,的地址空间为0xF8F8_1000– 0xF8F8_2000, 此时在AS0TLB1/E5,6保证能够访问main image.bootpg的内容。


"board/freescale/mpc8536ds/tlb.c"

struct fsl_e_tlb_entry tlb_table[] = {

#ifdefined (CONFIG_SYS_RAMBOOT) &&defined(CONFIG_SYS_INIT_L2_ADDR)

/**I*G - L2SRAM */

SET_TLB_ENTRY(1,CONFIG_SYS_INIT_L2_ADDR,

CONFIG_SYS_INIT_L2_ADDR_PHYS,

MAS3_SX|MAS3_SW|MAS3_SR,MAS2_I|MAS2_G,

0,5, BOOKE_PAGESZ_256K, 1),

SET_TLB_ENTRY(1,CONFIG_SYS_INIT_L2_ADDR + 0x40000,

CONFIG_SYS_INIT_L2_ADDR_PHYS+ 0x40000,

MAS3_SX|MAS3_SW|MAS3_SR,MAS2_I|MAS2_G,

0,6, BOOKE_PAGESZ_256K, 1),

#endif

}


0xF8F80000– 0xF8FFFFF = 512K


在切换到AS1需要先设置好AS1中使用的代码的TLBTLB1/E15完成此功能使用如下的映射那么到底映射的是从哪个地址开始到那个地址结束

此时TEXT_BASE0xF8F82000.


"cpu/mpc85xx/start.S"


lis r7,FSL_BOOKE_MAS1(1, 1, 0, 1, BOOKE_PAGESZ_1M)@h

ori r7,r7,FSL_BOOKE_MAS1(1, 1, 0, 1, BOOKE_PAGESZ_1M)@l


lis r8,FSL_BOOKE_MAS2(TEXT_BASE, (MAS2_I|MAS2_G))@h

ori r8,r8,FSL_BOOKE_MAS2(TEXT_BASE, (MAS2_I|MAS2_G))@l


lis r9,FSL_BOOKE_MAS3(TEXT_BASE, 0, (MAS3_SX|MAS3_SW|MAS3_SR))@h

ori r9,r9,FSL_BOOKE_MAS3(TEXT_BASE, 0,(MAS3_SX|MAS3_SW|MAS3_SR))@l


直接看上去0xF8F8_2000– 0xF908_1FFF,好像没有覆盖4kboot page代码。


Allocate Initial RAM in data cache这段代码还在4K boot page代码中,显然运行在0xF8F8_1000-0xF8F8_2000这段空间,只有运行到_start_cont才跳转出4K NANDloader的范围,那么跳转到AS1后应该不能运行,但实际上是能够运行的,是由于EPN/RPN的地址和该Entry设置的地址空间大小有关系,即需要与该地址空间大小对齐。这样EPNRPN都设置为0xF8F0_00001M地址空间为0xF8F0_0000-0xF8FF_FFFF.


Effective page number:

Depending on page size of the TLB entry, only the bits associated with apage boundary are valid

Real page number:

Depending on page size of the TLB entry, only the bits associated with apage boundary are valid


0xF8F8_2000

0x0010_0000

---------------

0xF8F0_0000


0xF8FF_FFFF



4.boot from On-chip ROM

boot from NAND flash的流程类似,区别就是在这种启动方式下没有所谓的4K NAND loader,而是通过CPU中的一段ROM代码来将第二阶段image拷贝到目的地(L2 SRAM)。


5. 在调试和patch upstream过程中还碰到的问题:


5.1初遇E500的猜测访问

初始L2 SRAMTLB地址空间是设置为1M的地址空间,但实际上L2SRAM只有512K,这样就存在512K的地址空间空洞。E500内核的猜测访问在访问L2 SRAM时可能访问到并不存在的512K地址空间空洞上。


在调试中发现,在512KL2SRAM空间上运行ram u-boot image时,运行到初始化串口时便hang了。后来将L2 SRAMTLB映射改为512K映射即可。


5.2 体会cache一致性


在使用nand_load4k NAND loader ram uboot image拷贝到L2 SRAM之后,需要调用flash_cachecache中的数据更新到L2SRAM中。


5.3 遭遇manually relocation


问题描述:是当时的笔记,懒得翻译了。。。

For example, the bad block table for NAND has the described relationship:

 

static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };

static struct nand_bbt_descr bbt_main_descr = {
       ......

       .pattern =bbt_pattern
};

 

The followings are the dump info:

f8ff28b4<bbt_pattern>:
f8ff28b4:      42 62 74 30     bc+    18,eq,f8ff9ce4 <__compound_literal.18+0x20>

 

f8ffa0b4<bbt_main_descr>:

......
f8ffa0d4:      f8 ff 28 b4     std    r7,10420(r31)

 

When we relocate the ram-version image into RAM, the address of bbt_main_descr

and bbt_pattern will offset to the memory address, but the contents of the

address'f8ffa0d4' should be "f8 ff 28 b4" that points to the address of

bbt_pattern in L2 SRAM, so when we disable L2SRAM, access this address will

hang the system. so we need to relocate the pointer manually.


这是我当时解决该问题的patch:

fsl_elbc_nand: redirect the pointer of bbt pattern to RAM

http://git.denx.de/cgi-bin/gitweb.cgi?p=u-boot.git;a=commit;h=66372fe2ab11cdeb0e841ad9eb6ba79769db4909


后来Peter添加了对powerpc-mrelocatable的支持,彻底解决的该问题。


5.4 mkconfig

在upstream过程中,wolfgang同学反映比较强烈的问题就是在Makefile中添加许多编译的选项,比如从NAND启动添加一个选项,从SD启动又要添加一个选项,而每个选项有5,6行的样子,这样添下去Makefile总有一天会臃肿到没法看和没法维护,所以他反对在添加一个一个的选项,于是就搞了下面的patch来解决这个问题:

mkconfig: split the board make target to multiple config targets

http://git.denx.de/cgi-bin/gitweb.cgi?p=u-boot.git;a=commit;h=804d83a563c47b55e1f14f5de3b6e9d7e2a7ef5e

后来Wolfgang同学又将所有的编译选项移到boards.cfg文件中,在mkconfig文件中添加些shell脚本来处理所有的编译选项。

原创粉丝点击