本文转载,地址:http://blog.csdn.net/xuguod20042576/archive/2009/10/12/4656746.aspx,版权问题,马上删除
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zengdebiao/archive/2009/04/15/4074753.aspx
如果我们要在 WINCE 环境下进行 ARM 项目开发,清楚的了解 WINCE 系统环境下 ARM 空间的应用机制是很必要的。
g_oalAddressTable 地址映射表
在我们的开发中,不同类型不同功能的产品,需要使用不同的外设,从而也占用了不同的 ARM 总线物理空间。那么我们怎么让操作系统和 BOOTLOADER 知道硬件外围占用了 ARM 的哪些物理空间,并如何让操作系统和 BOOTLOADER 高效的管理这些空间呢? g_oalAddressTable 这个映射表,就是为了满足这个要求提出来的。
g_oalAddressTable 的每一行都定义了一个存储段的映射,格式:段的虚拟起始地址,段的物理起始地址,段的长度(单位是 M ) . 以下是个实际的例子:
g_oalAddressTable
DCD 0x88000000, CSP_BASE_MEM_PA_CSD0, 128 ; DDR RAM
DCD 0x80000000, CSP_BASE_MEM_PA_CS0, 32 ; NOR Flash
DCD 0x90000000, CSP_BASE_MEM_PA_CS2, 32 ; CS2
DCD 0x92000000, CSP_BASE_MEM_PA_CS3, 32 ; CS3
DCD 0x94000000, CSP_BASE_MEM_PA_CS4, 32 ; CPLD
DCD 0x96000000, CSP_BASE_MEM_PA_CS5, 32 ; SRAM
DCD 0x98000000, CSP_BASE_MEM_PA_PCMCIA_CF, 64 ; PCMCIA/CF
DCD 0x9C000000, CSP_BASE_REG_PA_AIPI1, 1 ; Internal registers (AIPI1 + AIPI2 + AITC + ROM Patch)
DCD 0x9C100000, CSP_BASE_REG_PA_CSI, 1 ; CSI + ATA
DCD 0x9C200000, CSP_BASE_REG_PA_NANDFC, 1 ; EMI modules (NANDFC + ESDRAMC + WEIM + M3IF + PCMCIA)
DCD 0x9C300000, CSP_BASE_MEM_PA_VRAM, 1 ; VRAM (45K)
DCD 0x00000000, 0x00000000, 0 ; Terminate table
以上映射表实例中, DDR RAM 占用了以虚拟地址 0X88000000 为起始的 128M 的空间,它所对应的物理地址空间是以宏 CSP_BASE_MEM_PA_CSD0 定义值为起始地址的 128M 的空间。而 NOR FLASH 占用了以虚拟地址 0X80000000 为起始的 32M 的空间,其对应的物理地址空间是 CSP_BASE_MEM_PA_CS0 起始的 32M 空间。其它依此类推。
以上这个结构是给系统程序本身用的,对开发编译环境是不可见的。这个映射表在以下几个地方用到了:
第一, 在 bootloader 建立 MMU 页表的时候有用到,此代码通常位于 Bootloader 中 StartUp.s 文件中,举例如下:
; Load address of OEMAddressTable into r0
adrl r0, g_oalAddressTable
; Load base address of page tables into r1
ldr r1, =(MmuPageTableBase)
; Branch to set up MMU & enable caches
; to avoid SDRAM multiple read failure
b mmuSetup // 此函数进行 MMU 页表的构建,并启动 MMU
。。。。。。。。。。
第二, 在 WINCE OS 建立 MMU 页表的时候也有用到,此代码位于 C:/WINCE500/PRIVATE/WINCEOS/COREOS/NK/KERNEL/ARM/armtrap.s 文件的 KernelStart 函数中:
LEAF_ENTRY KernelStart
mov r11, r0 ; r0 在 KernelStart 被调用之前就已经赋值等于 g_oalAddressTable
。。。。。。。。
第三, 在 虚拟地址和物理地址相互转换的函数中用到了:
下面抄了一段代码如下, 从这个代码看出 ARM 虚拟内存和物理内存的关系。
VOID* OALPAtoVA(UINT32 pa, BOOL cached)
{
OAL_ADDRESS_TABLE *pTable = g_oalAddressTable ;
VOID *va = NULL;
OALMSG(OAL_MEMORY&&OAL_FUNC, (L "+OALPAtoVA(0x%x, %d)/r/n" , pa, cached));
// Search the table for address range
while (pTable->size != 0)
{
if ( pa >= pTable->PA && pa <= (pTable->PA + (pTable->size << 20) - 1) )
break ; // match found 找到表中相近的内存
pTable++;
}
// If address table entry is valid compute the VA
if (pTable->size != 0)
{
va = (VOID *)(pTable->CA + (pa - pTable->PA));
// If VA is uncached, set the uncached bit
if (!cached) (UINT32)va |= OAL_MEMORY_CACHE_BIT;
}
// Indicate the virtual address
OALMSG(OAL_MEMORY&&OAL_FUNC, (L "-OALPAtoVA(va = 0x%08x)/r/n" , va));
return va;
}
存储空间配置文件
到目前为止,我们已经让程序本身知道了目标系统中有哪些有效的物理地址空间,但这些信息对我们的开发环境是透明的,我们的开发环境要建立 BOOT 和 NK 的映射文件,也需要知道我们目标系统的地址空间的配置情况。这就导致了另一个概念的提出: BIB 文件,其全称 Binary Image Builder File 。
在 BIB 文件中分为 4 大项: MEMORY 项, CONFIG 项, MODULES 项和 FILES 项。下面会详细介绍上面的 4 大项:
1. MEMORY 项
一般都在 config.bib 文件中定义,开头会有 MEMORY 的字样。这里定义了为 WinCE image 以及其他模块预留的 RAM ,同时也定义了 WinCE 可以使用的 RAM 。具体格式如下:
MEMORY NAME Start Address Memory Size Type
NAME :该内存区域的名字,必须是唯一的。
Start Address :该内存区域的起始地址,用十六进制表示。
Memory Size :该内存区域的大小,用十六进制表示。
Type :内存区域的类型。包涵的多种类型如下:
类型值
描述
FIXUPVAR
用于在 WinCE 编译的 Makeimg 阶段,就初始化一个内核中的全局变量。
NANDIMAGE
当创建了一个使用 BinFS 的 image 的时候, NAND 设备上的 WinCE kernel 重定向到 RAM 中的区域,当系统访问该区域的时候, BinFS 会负责访问 Nand 设备上相应的位置,并返回数据给系统,实际上就是在 Nand 设备上面实现了 XIP 的功能。
RAM
定义了被 WinCE 系统使用的 RAM 区域,这块内存必须是连续的,这里有一点要注意就是从硬件的角度来说,这块内存不能跨越两片 SDRAM ,也就是说整个区域空间必须在一片硬件 SDRAM 上。
RAMIMAGE
定义了一块内存区域用于加载 WinCE image ,实际上 WinCE 启动以后, image 会被拷贝到这块内存区域上面运行。一个 image 只能有一个连续的 RAMIMAGE 区域。
RESERVED
这块内存区域会被预留出来,一般用于 Frambuffer 或者是 DMA Buffer ,或者是一块共享内存用于 EBOOT 传递参数给 WinCE 系统。
EXTENSION
定义了一块 WinCE image 中的区域作为 ROMHDR extension 的数据区域。
下面是一个内核映像配置实例:
MEMORY
; ----------------- Reserved Region Mapping (2 MB) ---------------------
; Start Addr End Addr Mem Type Region Name Size
; 0x88000000 0x88000FFF SDRAM DRV_GLB 4 KB
; 0x88001000 0x880FFFFF SDRAM EBOOT_USED 1020 KB
; 0x88100000 0x881FFFFF SDRAM FRAMEBUFFER 1 MB
; ----------------------------------------------------------------------
; Name Address Size Type
ARGS 88000000 00001000 RESERVED
VPU 88001000 000FF000 RESERVED
FRAMEBUFFER 88100000 00100000 RESERVED
IF IMGFLASH !
; --------------------------- RAM image --------------------------------
; Start Addr End Addr Mem Type Region Name Size
; 0x88000000 0x881FFFFF SDRAM reserved 2 MB
; 0x88200000 0x8B1FFFFF SDRAM NK 48 MB
; 0x8B200000 0x8FFFFFFF SDRAM RAM 78 MB
; ----------------------------------------------------------------------
; Name Address Size Type
NK 88200000 03000000 RAMIMAGE //nk image 在 SDRAM
RAM 8B200000 04E00000 RAM
ENDIF
IF IMGFLASH
; --------------------- FLASH image with EBOOT -------------------------
; Start Addr End Addr Mem Type Region Name Size
; 0x80000000 0x8003FFFF FLASH resident EBOOT 256 KB
; IF BSP_KITL_ETHFEC
; 0x80040000 0x81FF7FFF FLASH NK 31.75 MB - 32KB
; ELSE
; 0x80040000 0x81FFFFFF FLASH NK 31.75 MB
; ENDIF
; 0x88000000 0x881FFFFF SDRAM reserved 2 MB
; 0x88200000 0x8FFFFFFF SDRAM RAM 126 MB
; ----------------------------------------------------------------------
IF IMGEBOOT
; Name Address Size Type
IF BSP_KITL_ETHFEC
NK 80040000 01FB8000 RAMIMAGE
ELSE
NK 80040000 01FC0000 RAMIMAGE
ENDIF
RAM 88200000 07E00000 RAM
ENDIF
; ------------------- FLASH image without EBOOT ------------------------
; Start Addr End Addr Mem Type Region Name Size
; IF BSP_KITL_ETHFEC
; 0x80000000 0x81FF7FFF FLASH NK 32 MB - 32KB
; ELSE
; 0x80000000 0x81FFFFFF FLASH NK 32 MB
; ENDIF
; 0x88000000 0x881FFFFF SDRAM reserved 2 MB
; 0x88200000 0x8FFFFFFF SDRAM RAM 126 MB
; ----------------------------------------------------------------------
IF IMGEBOOT !
; Name Address Size Type
IF BSP_KITL_ETHFEC
NK 80000000 01FF8000 RAMIMAGE
ELSE
NK 80000000 02000000 RAMIMAGE
ENDIF
RAM 88200000 07E00000 RAM
ENDIF
ENDIF
2. CONFIG 项
一般在 config.bib 文件中定义,定义了一些额外的配置参数,其中一些对于 WinCE image 来说也很重要。具体格式如下:
CONFIG ITEM=Parameter
ITEM
描述
AUTOSIZE
允许未被使用的 WinCE image 的 RAM 被用作 WinCE 系统的 RAM 。默认值为 ON 。
COMPRESSION
允许 Romimage.exe 压缩 WinCE image 中的可写入部分。默认值为 ON 。
BOOTJUMP
定义了跳转跳转页在 RAMIMAGE 空间的地址。而不是默认情况下的 RAMIMAGE 的首地址。默认值为 NONE 。
FSRAMPERCENT
定义了文件系统使用的内存的百分比。默认值为 0x80808080 。 Byte 0 :第一个 2MB 中,每 1MB 所包含的 4KB 的倍数。 Byte 1 :第二个 2MB 中,每 1MB 所包含的 4KB 的倍数。 Byte 2 :第三个 2MB 中,每 1MB 所包含的 4KB 的倍数。 Byte 3 :剩下的内存中,每 1MB 所包含的 4KB 的倍数。
KERNELFIXUPS
定义了 Romimage.exe 是否重新定向内核的可写入区域。默认值为 ON ,内核的可写入区域被重新定向到 RAMIMAGE 的起始位置。
OUTPUT
定义了最终生成的 image 存放的路径。默认为 %_FLATRELEASEDIR% 。
PROFILE
定义了是否在 WinCE image 中包含 profiler 的结构和符号。默认值为 OFF 。
RESETVECTOR
重新指定跳转页的位置,一般针对 MIPS 芯片从 0x9FC00000 开始引导的问题。
ROMFLAGS
内核标记位,可以进行组合: 0x01 表示禁用按需分页。 0x02 表示禁用完全内核模式,完全内核模式表示所有的线程都运行在内核模式。 0x10 表示只信任 ROM MODULES 中的模块。 0x20 表示停止刷新 TLB 。 0x40 表示按照 /base 链接选项中的地址加载 DLL 。
ROMSTART
指 WinCE image 在内存中的起始地址。
ROMSIZE
指 WinCE image 的大小。
ROMWIDTH
指数据总线的宽度。
ROMOFFSET
指定一个偏移量来修改 .bin 文件中的每一个记录的地址。一般用于 ROM 中的 .bin 文件加载到 RAM 来运行的情况,主要是表示存储 .bin 的位置和运行 .bin 的位置不一样。
SRE
使 Romimage.exe 产生一个 .sre 文件。默认值为 OFF 。
X86BOOT
定义是否插入一条跳转指令,在 x86 复位向量地址的时候。
具体例子如下:
CONFIG
; ---------------------- All Image Types Settings ----------------------
; KERNELFIXUPS = ON (sections to which the kernel can write are
; relocated to the start of RAM)
; SRE = ON (Romimage.exe produces an .sre file)
; ----------------------------------------------------------------------
KERNELFIXUPS=ON
; --------------------------- RAM image --------------------------------
; AUTOSIZE = ON (allows NK and RAM space to resize automatically)
; ROMSIZE = 0x04000000 (64 MB)
; ROMSTART = 0x88000000 (SDRAM virtual address base)
; ROMWIDTH = 32 (32-bit wide memory, entire image in one file)
; ----------------------------------------------------------------------
IF IMGFLASH !
AUTOSIZE=ON
ROMSIZE=04000000
ROMSTART=88000000
ROMWIDTH=32
ENDIF
; ------------------- FLASH image with/without EBOOT -------------------
; ROMSIZE = 0x02000000 (32 MB) for without EBOOT and FEC support
; else should eliminate their size
; IF IMGEBOOT
; ROMSTART = 0x80040000 (256KB(0x40000) area is reserved for EBoot)
; ELSE
; ROMSTART = 0x80000000 (NOR virtual address base)
; ENDIF
; ROMWIDTH = 32 (32-bit wide memory, entire image in one file)
; ----------------------------------------------------------------------
IF IMGFLASH
IF IMGEBOOT
IF BSP_KITL_ETHFEC
ROMSIZE=01FB8000
ROMSTART=80040000
ELSE
ROMSIZE=01FC0000
ROMSTART=80040000
ENDIF
ENDIF
IF IMGEBOOT !
IF BSP_KITL_ETHFEC
ROMSIZE=01FF8000
ROMSTART=80000000
ELSE
ROMSIZE=02000000
ROMSTART=80000000
ENDIF
ENDIF
ROMWIDTH=32
ENDIF
; ------------------------------ COMPRESSION ---------------------------
; NK COMPRESSION
; ----------------------------------------------------------------------
; @CESYSGEN IF !NK_NKNOCOMP
COMPRESSION=ON
; @CESYSGEN ENDIF !NK_NKNOCOMP
; @CESYSGEN IF NK_NKNOCOMP
; @CESYSGEN ENDIF NK_NKNOCOMP
; ---------------------- Profiling-enabled kernel ----------------------
; PROFILE = ON (includes profiler structure and symbols in image)
; ----------------------------------------------------------------------
IF IMGPROFILER
PROFILE=ON
ENDIF
; --------------------- Profiling-disabled kernel ----------------------
; PROFILE = OFF (does not include profiler structure and symbols)
; ----------------------------------------------------------------------
IF IMGPROFILER !
PROFILE=OFF
ENDIF;
; ROMFLAGS is a bitmask of options for the kernel
; ROMFLAGS 0x0001 Disallow Paging
; ROMFLAGS 0x0002 Not all KMode
; ROMFLAGS 0x0010 Trust Module only
;
IF IMGTRUSTROMONLY
IF IMGNOTALLKMODE
ROMFLAGS=12
ENDIF
IF IMGNOTALLKMODE !
ROMFLAGS=10
ENDIF
ENDIF
IF IMGTRUSTROMONLY !
IF IMGNOTALLKMODE
ROMFLAGS=2
ENDIF
IF IMGNOTALLKMODE !
ROMFLAGS=0
ENDIF
ENDIF
3 . MODULES 项和 FILES 项
该项列出了所有被包含在 WinCE image 中的模块以及文件,以及这些模块和文件以什么方式被加载到内存中。具体格式如下:
MODULES
Name Path Memory Type
Name :模块的名字,比如一个 dll 或者 exe 文件的文件名。
Path :路径,一般都是 WinCE 的工程的 Release 目录。
Memory :指定该模块被放在哪个区域,一般都是 NK 区域。
Type :定义了文件的类型。具体如下:
类型
描述
S
系统文件。
H
隐藏文件。
R
只压缩模块的资源部分。
C
压缩模块的所有部分。
D
禁止调试。
N
模块是不可信任的。
P
告诉 Romimage.exe 不需要检查 CPU 的类型。
K
告诉 Romimage.exe 必需固定该模块的内核地址。有该标记的模块只能被 LoadKernelLibrary 函数加载。
X
告诉 Romimage.exe 对该模块签名。
M
运行时加载整个模块,不要按需分页。
L
告诉 Romimage.exe 不要分离 ROM DLL 。
一般 FILES 项的 Type 只支持 S , H , N , D 几个类型,而 MODULES 项的 Type 是都支持的。
举例如下:
FILES
; Name Path Memory Type
; -------------------- -------------------------------------- ------ ----
ETCHA.exe $(_FLATRELEASEDIR)/ETCHA.exe NK U
ETCHA.lnk $(_FLATRELEASEDIR)/ETCHA.lnk NK U
tcal.exe $(_FLATRELEASEDIR)/tcal.exe NK U
IF BSP_FSL_WLAN_LP1070
uwa_airoha.bin $(_TARGETPLATROOT)/SRC/DRIVERS/LP107X/LP1070/uwa_airoha.bin
NK U
mac_airoha_STA.bin $(_TARGETPLATROOT)/SRC/DRIVERS/LP107X/LP1070/mac_airoha_STA.bin NK U
ENDIF
对于 BIB 文件来说同样支持 “ 条件编译 ” ,在上面例子中我们也看到了,我们可以通过设置环境变量来选择性地将某些模块打包到 WinCE image 中。一般在 BSP 中,对于一些驱动模块的环境变量我们 IF 来进行条件判断。而对于 WinCE 的系统模块来说,一般都是 SYSGEN 变量,应该使用 @CESYSGEN IF 来判断。
我们在 BSP 的开发中最常见的主要就是 eboot.bib , config.bib , platform.bib 和 project.bib 。下面简单介绍一下:
project.bib :该文件主要自创建的 WinCE 工程中所需的一些文件。
platform.bib :该文件包含了和硬件平台相关的文件,主要以驱动程序为主。
config.bib :该文件描述了 WinCE 系统的内存的配置。
eboot.bib :该文件描述了 WinCE 的 eboot 的内存的配置。
还有其他的一些 bib 文件,在 WinCE 系统编译后都会背拷贝到工程的 release 目录下面。比如 common.bib , ie.bib 等。这些文件列出了 WinCE 的组件相关的文件,根据用户订制的系统,会被选择性的打包到 WinCE image 中。
总结
到此,我们对 ARM 空间的应用有了一个基本的了解。在结束本话题之前,我想再强调一点, g_oalAddressTable 地址映射表对程序本身可见,但对开发环境是透明的。而 BIB 文件是给开发环境使用的,当然在编译链接阶段会把 BIB 中设置的某些信息通过 TOC 传递给 OS 和 bootloader. 由于 g_oalAddressTable 的内容开发环境不可见,而 BIB 文件的内容 OS 和 bootloader 不可见,所以我们开发的时候必须手动维护这两者的一致性,不能有冲突。
adr,adrl和ldr指令的用法比较
ADR :
这是一条小范围的地址读取伪指令,它将基于PC的相对偏移的地址值读到目标寄存器中。
使用的格式:ADR register,exper。
在编译源程序时,汇编器首先计算出当前PC到exper的偏移值#offset_to_exper,然后会用一条ADD或者SUB指令来替换这条伪指令,例如:ADD register,PC,#offset_to_exper。
注意,标号exper与指令必须在同一代码段。
ADRL :
这是一条中等范围的地址读取伪指令,它将基于PC的相对偏移的地址值读到目标寄存器中。
使用的格式:ADRL register,exper。
在编译源程序时,汇编器会用两条合适的指令来替换这条伪指令。
例如:
ADD register,PC,offset1
ADD register,register,offset2
与ADR相比,它能读取更大范围的地址。
注意,标号exper与指令必须在同一代码段。
LDR :
第一种情况:
当LDR用做ARM指令时,它将基于PC的相对偏移地址处存储的值读到目标寄存器中。
应用格式:LDR register,[expr]
第二种情况:
当LDR用做ARM伪指令时,它用于大范围的地址读取。
其实说它用于大范围的读取,还不如说它用于大范围的地址赋值。我们来看一下这条伪指令的应用格式:LDR register,=expr/label_expr ,显然,我们可以直观的看出,指令的目的就是要将expr或label_expr赋值(=)给register.所以在编译时,当expr或 label_expr的值没有超出MOV和MVN的范围时,采用MOV或MVN指令来代替这条伪指令就显得理所当然了。当expr或label_expr 的值超出MOV和MVN的范围时,汇编器将expr或label_expr放入文字池中,并使用一条程序相对偏移指令LDR从文字池读出常量。例如:LDR register,[PC,#offset to literal pool]
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xuguod20042576/archive/2009/10/12/4656746.aspx