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

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

s ailor_forever sailing_9806#163.com
http://blog.csdn.net/sailor_8318/archive/2009/09/03/4513710.aspx


1                                      General

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

2                                      HCWR/BRx/ORx 

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

11.2.1 Address and Address Space Checking

The defined base address is written to the BRx . The bank size is written to the ORx . Each time a bus cycle access is requested on the 60x or local bus, addresses are compared with each bank. If a match is found on a memory controller bank, the attributes defined in the BRx and ORx for that bank are used to control the memory access. If a match is found 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 and address types that the memory controller uses to compare the address bus value with the current address accessed. Each register also includes a memory attribute and selects the machine for memory operation handling

 

//

 

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

 

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

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

Exception prefix. The setting of this bit specifies whether an exception 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 physical address 0xFFFn_nnnn

1 MSR[IP] = 0 Exceptions are vectored to the physical address 0x000n_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. Masking address bits independently allows external devices of different size address ranges to be used.

0 Corresponding address bits are masked.

1 The corresponding address bits are used in the comparison with address pins. Address mask bits can be set or cleared in any order in the field, 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 位需要进行地址匹配,因此复位向量的地址必须为 0xFFF0 0100 ,这就意味着代码存储位置相对于 Flash 的偏移量为 0x01F0 0000 ,即 31M ,因此高端启动时 Flash 至少 32M

 

同理低端启动时,复位向量的地址必须为 0x0000 0100 Flash 基地址为 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位地址信息有效,因此都将从 Flash 0---32k内取指。当跳转到编译链接的 Flash地址处时,由于 CFG_MONITOR_BASE被屏蔽,只有 in_flash - _start + EXC_OFF_SYS_RESET是有效的,因此实际的取指位置相对于 Flash的偏移量为 in_flash - _start + EXC_OFF_SYS_RESET,正好为 in_flash标号所在的代码位置,这样就实现了无缝切换。

 

在未改变 OR0 之前,程序将只能在 32k 内取指。当软件将 BR0 OR0 更改为实际设计的值时,指令访问的地址经过匹配后,仍将从 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 Data pointer                      */
                      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 in Bytes         */
                      ori                   r5, r5, CFG_MONITOR_LEN@l
                      li                     r6, CFG_CACHELINE_SIZE                                    /* Cache Line Size       */
 
                      /*
                        * 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 not necessary                      */
                      beq                 7f                                       /* Protect against 0 count                                */
                      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切换 Flash SDRAM

 

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

 

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

 

程序编译链接地址为 flash 0 地址,跳转时的绝对符号表地址是基于 flash 0 地址的,因为代码在 SDRAM Flash 中有同样的备份,因此跳转至 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 */

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值