如果我们要在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不可见,所以我们开发的时候必须手动维护这两者的一致性,不能有冲突。