两种实现PPC地址重映射的方案,uboot powerpc

来源:互联网 发布:guitar rig5 mac 破解 编辑:程序博客网 时间:2024/04/30 23:22

两种实现PPC地址重映射的方案

sailor_forever sailing_9806#163.comhttp://blog.csdn.net/sailor_8318/archive/2009/09/03/4513710.aspx


1                                     General

本文介绍了powerpc架构下两种典型的地址重映射方案,详细描述了其实现过程。

2                                     HCWR/BRx/ORx 

MPC8270共有11bank,即共有11CS。在硬件设计上,每一个存储器对应一个CS。对于每一个bank,有两个重要的寄存器即BRxORx。当CPU发出读写请求时,首先进行地址空间的检查及匹配,匹配因素就是BR决定的基地址和OR的地址匹配屏蔽码。当匹配成功时,才由对应的CS产生相关控制信号,进行实际的内存访问。

////////////

11.2.1 Address and Address Space Checking

The defined base address is written to the BRx. The banksize is written to the ORx. Each time a bus cycle access is requested onthe 60x or local bus, addresses are compared with each bank. If a match isfound on a memory controller bank, the attributes defined in the BRx andORx for that bank are used to control the memory access. If a match isfound in more than one bank, the lowest-numbered bank handles the memory access(that is, bank 0 has priority over bank 1).

 

11.3.1 Base Registers (BRx)

The base registers (BR0–BR11) contain the base address andaddress types that the memory controller uses to compare the address bus valuewith the current address accessed. Each register also includes a memory attributeand selects the machine for memory operation handling

 

//////////////

 

由此可见,每个bank的基地址是可灵活配置的。这是PPC区别于ARM系统的一个重点。在ARM中,每个bank的地址空间是固定,和CPU自身相关,和存储器无关。

 

既然地址是由软件配置的,那么上电时软件还没运行时,是如何确定启动Flash的地址呢?CS0一般连接的是FlashEEPROM之类的存储设备,因此上电时BR0OR0有默认值。BR0的默认基地址是由硬件配置字决定的。

CIP1 Core initial prefix. Defines the initial value of MSR[IP].

Exception prefix. The setting of this bit specifies whether anexception vector offset is prepended with Fs or 0s. In the following description,nnnnn is the offset of the exception vector.

0 MSR[IP] = 1 (default). Exceptions are vectored to the physicaladdress 0xFFFn_nnnn

1 MSR[IP] = 0 Exceptions are vectored to the physical address0x000n_nnnn.

BMS Boot memory space. Defines the initial value for BR0[BA].There are two possible boot memory regions: HIMEM and LOMEM.

0 0xFE00_0000—0xFFFF_FFFF

1 0x0000_0000—0x01FF_FFFF

 

只有OR0在上电时的值是有效的,AM域决定了哪些位用于地址匹配

0–16 AM Address mask. Masks corresponding BRx bits. Maskingaddress bits independently allows external devices of different size addressranges to be used.

0 Corresponding address bits are masked.

1 The corresponding address bits are used in the comparison withaddress pins. Address mask bits can be set or cleared in any order in thefield, allowing a resource to reside in more than one area of the address map.AM can be read or written at any time.

Note: After system reset, OR0[AM] is 1111_1110_0000_0000_0.

 

PPC有高端地址启动和低端地址启动。高端时Flash基地址为0xFE00_0000,而OR0的高7位需要进行地址匹配,因此复位向量的地址必须为0xFFF00100,这就意味着代码存储位置相对于Flash的偏移量为0x01F00000,即31M,因此高端启动时Flash至少32M

 

同理低端启动时,复位向量的地址必须为0x0000 0100Flash基地址为0,程序的烧录地址相对于Flash的偏移量为0

 

通常中断向量表的基地址为0,为了更快的响应中断,SDRAM的地址需要最终映射到0地址。若上电时Flash的首地址为0,那么如何切换才能保证能够正常取指呢?

 

3                                     利用OR0的地址屏蔽位


/* When booting from ROM (Flash or EPROM), clear the                        */
/* Address Mask in OR0 so ROM appears everywhere                            */
/*--------------------------------------------------------------*/

lis                    r3, (CFG_IMMR+IM_REGBASE)@h
lwz                  r4, IM_OR0@l(r3)
li                     r5, 0x7fff
and                 r4, r4, r5
stw                 r4, IM_OR0@l(r3)

/* Calculate absolute address in FLASH and jump there                           */
/*--------------------------------------------------------------*/
lis                    r3, CFG_MONITOR_BASE@h
ori                   r3, r3, CFG_MONITOR_BASE@l
addi                r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
mtlr                 r3
blr

in_flash:

 

清除OR0的地址匹配位,则不进行匹配的单位是32K,即任何地址访问只有末15位地址信息有效,因此都将从Flash0---32k内取指。当跳转到编译链接的Flash地址处时,由于CFG_MONITOR_BASE被屏蔽,只有in_flash- _start + EXC_OFF_SYS_RESET是有效的,因此实际的取指位置相对于Flash的偏移量为in_flash- _start + EXC_OFF_SYS_RESET,正好为in_flash标号所在的代码位置,这样就实现了无缝切换。

 

在未改变OR0之前,程序将只能在32k内取指。当软件将BR0OR0更改为实际设计的值时,指令访问的地址经过匹配后,仍将从Flash取指。而此时0地址经过匹配后将不再是Flash中的地址。便可将SDRAM所在的bank的基地址设置为0,拷贝中断向量表至SDRAM,即可快速响应中断。

 

因为程序的编译链接地址是基于flash首地址的,因为启动过程中用到了函数指针这些静态符号表,因此flash中的代码是位置相关的,也就是说运行地址和链接地址必须一致。

 

但程序当前仍然在flash中运行,那么是怎么跳转到SDRAM中的呢?跳转之前需要将代码先拷贝到SDRAM中去,那拷贝到SDRAM的何位置呢?这个是动态计算出来的,通常是SDRAM高端地址减去印象大小的位置。这和ARM的代码重定位有很大的区别,ARM映像的链接地址即是最终拷贝到SDRAM中的位置,拷贝代码之前flash中运行的代码是位置无关的,SDRAM中运行的代码是位置相关的,必须拷贝到程序的链接地址。

/*
  * void relocate_code (addr_sp, gd, addr_moni)
  *
  * This "function" does not return, instead it continues in RAM
  * after relocating the monitor code.
  *
  * r3 = dest
  * r4 = src
  * r5 = length in bytes
  * r6 = cachelinesize
  */
                      .globl              relocate_code
relocate_code:
                      mr                  r1,  r3                                 /* Set new stack pointer            */
                      mr                  r9, r4                                 /* Save copy of Global Datapointer                      */
                      mr                  r10, r5                                /* Save copy of Destination Address         */
 
                      mr                  r3, r5                                                                         /* Destination Address            */
                      lis                    r4,CFG_MONITOR_BASE@h                                /* Source     Address         */
                      ori                   r4, r4, CFG_MONITOR_BASE@l
                      lis                    r5,CFG_MONITOR_LEN@h                                   /* Length inBytes         */
                      ori                   r5, r5, CFG_MONITOR_LEN@l
                      li                     r6,CFG_CACHELINE_SIZE                                    /* Cache LineSize       */
 
                      /*
                        * Fix GOT pointer:
                        *
                        * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address
                        *
                        * Offset:
                        */
                      sub                 r15, r10, r4
 
                      /* First our own GOT */
                      add                 r14, r14, r15
                      /* then the one used by the C code */
                      add                 r30, r30, r15
 
                      /*
                        * Now relocate code
                        */
 
                      cmplw            cr1,r3,r4
                      addi                r0,r5,3
                      srwi.               r0,r0,2
                      beq                cr1,4f                                 /* In place copy is notnecessary                      */
                      beq                7f                                       /* Protect against 0count                                */
                      mtctr              r0
                      bge                 cr1,2f
 
                      la                    r8,-4(r4)
                      la                    r7,-4(r3)
1:                   lwzu                r0,4(r8)
                      stwu               r0,4(r7)
                      bdnz               1b
                      b                     4f
 
2:                   slwi                 r0,r0,2
                      add                 r8,r4,r0
                      add                 r7,r3,r0
3:                   lwzu                r0,-4(r8)
                      stwu               r0,-4(r7)
                      bdnz               3b
 
/*
  * Now flush the cache: note that we must start from a cache aligned
  * address. Otherwise we might miss one cache line.
  */
。。。。
 
/*
  * We are done. Do not return, instead branch to second part of board
  * initialization, now running from RAM.
  */
 
                      addi                r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
                      mtlr                 r0
                      blr
 
in_ram:

r10为 SDRAM中代码预拷贝的位置, blr功能是将 lr赋值给 PC指针,即实现了跳转,正好为 SDRAM中 in_ram标号的位置。对于 ppc ,在 SDRAM 中运行的代码由于运行地址和链接地址不一致,对于函数指针 /数组首地址这些静态符号表必须进行重定位以便能够正确解析相关符号。

/************************************************************************
* This is the next part if the initialization sequence: we are now
  * running from RAM and have a "normal" C environment, i. e. global
  * data can be written, BSS has been cleared, the stack size in not
  * that critical any more, etc.
  *
************************************************************************
  */
 
void board_init_r (gd_t *id, ulong dest_addr)
{
 
                      gd->reloc_off = dest_addr - CFG_MONITOR_BASE;
 
                      /*
                        * We have to relocate the command table manually
                        */
                      for (cmdtp = &cmd_tbl[0]; cmdtp->name; cmdtp++) {
                                             ulong addr;
 
                                             addr = (ulong) (cmdtp->cmd) + gd->reloc_off;
。。。
}
 
之后拷贝中断向量表至 SDARM 首地址,因此中断处理中用到了静态的函数指针,因此需要重定位,以便中断响应时能跳转到 SDRAM 中的中断处理函数中去
/*
* Setup trap handlers
*/
trap_init (dest_addr);
 
至此,整个运行环境就搭建起来了。

 

4                                     利用DPRAM切换FlashSDRAM

 

切换过程中如何保证取指的正确性是关键,若切换时程序既不运行在Flash中也未运行在SDRAM中,则可随意切换。PPC正是利用了内部DPRAM来实现的。

 

启动阶段,Flash基地址为0SDRAM地址为非0的某值,将代码拷贝至SDRAM首地址,然后将切换代码拷贝至DPRAM,跳转至DPRAM运行,此时便可随意更改FlashSDRAMBR,即实现了FlashSDRAM地址空间的重映射,Flash映射到非0地址,SDRAM映射到0地址。

 

程序编译链接地址为flash0地址,跳转时的绝对符号表地址是基于flash0地址的,因为代码在SDRAMFlash中有同样的备份,因此跳转至0地址的SDRAM运行的第一条语句总是可以正常取指。

 

/**@***********************************************************/
/*  FUNCTION: copy_and_start_monitor0.                                                 */
/*                                                                                     */
/*  PURPOSE: Copy and start monitor0:                                                  */
/*           - Copy all Boot0 Section into Global SDRAM.                               */
/*           - Copy address_swap routine into DPRAM.                                   */
/*           - Call address_swap routine.                                              */
/*                                                                                     */
/**@***********************************************************/
void copy_and_start_monitor0(void)
{
    Uint32 *flash_addr, *ram_addr;

    /* Copy all Boot0 Section into Global SDRAM*/
    for(flash_addr = (Uint32 *)STARTUP_FLASH_START, ram_addr = (Uint32 *)STARTUP_GLOBAL_SDRAM_START;
      flash_addr < (Uint32 *)BOOT0_SECTION_LENGTH;)
    {
         *ram_addr++ = *flash_addr++;
    }

   /* Copy address_swap routine into DPRAM */
    for(flash_addr = (Uint32 *)address_swap, ram_addr = (Uint32 *)DPRAM_SWAP_RESERVED;
      ram_addr < (Uint32 *)(DPRAM_SWAP_RESERVED + DPRAM_SWAP_RESERVED_LENGTH);)
    {
        *ram_addr++ = *flash_addr++;
    }

    /*  Call address_swap routine (never returns!)*/
    ((void(*)(void(*)(void)))DPRAM_SWAP_RESERVED)(monitor0_entry);
}

/**@*************************************************************/
/*  FUNCTION: address_swap.                                                            */
/*                                                                                     */
/*  PURPOSE: Swap address to/from SDRAM and FLASH.                                     */
/*                                                                                     */
/**@**************************************************************/
void address_swap(void(*sdram_entry_point)(void))
{

    /* Set Base Address of Chip Select 1 (SDRAM) to SWAP_GLOBAL_SDRAM_START */
    set16_reg(BR1, SWAP_GLOBAL_SDRAM_START >> 16);

    SYNC;

     /* Set Base Address of Chip Select 0 (FLASH) to SWAP_FLASH_START */
    set16_reg(BR0, SWAP_FLASH_START >> 16);

    ISYNC;

     /* Jump to program in SDRAM */
    (* sdram_entry_point)();

}   /* address_swap */

原创粉丝点击