从0x8000 0000开始是Windows CE内核使用的虚拟地址空间。虚拟地址0x8000 0000到0x9FFF FFFF一段用来静态映射所有的物理地址。也就是说Windows CE会把所有的物理内存一比一的映射到这段虚拟地址上。这段地址一共有512MB,这也就是Windows CE所支持的物理地址的最大值为512MB的由来。
虚拟地址0xA000 0000到0xBFFF FFFF会重复映射所有的物理内存,如图所示。这一段对物理内存的映射与0x80000000一段最大的不同是从0x8000 0000开始的一段物理内存是有缓冲的,而从0xA000 0000开始的一段是没有缓存的。通常,缓冲可以提高系统的I/O效率,但是对于一些OAL或者Bootloader中的设备驱动程序来说,使用缓冲有可能会造成灾难性后果,因为缓冲有可能会更改我们对设备的写操作顺序。因此在驱动程序中我们如果需要直接访问设备I/O或寄存器,我们通常使用0xA000 0000一段物理地址。
用gpio做为例子.
S3C2440的GPACON地址为0x56000000
mini2440\Src\Inc\oemaddrtab_cfg.inc文件中
g_oalAddressTable
DCD 0x80000000, 0x30000000, 64 ; 32 MB DRAM BANK 6
DCD 0x84000000, 0x10000000, 32 ; nGCS2: PCMCIA/PCCARD
DCD 0x86000000, 0x18000000, 32 ; 32 MB SROM(SRAM/ROM) BANK 3
DCD 0x88000000, 0x20000000, 32 ; 32 MB SROM(SRAM/ROM) BANK 4
DCD 0x8A000000, 0x28000000, 32 ; 32 MB SROM(SRAM/ROM) BANK 5
DCD 0x8C000000, 0x08000000, 32 ; 32 MB SROM(SRAM/ROM) BANK 1
DCD 0x90800000, 0x48000000, 1 ; Memory control register
DCD 0x90900000, 0x49000000, 1 ; USB Host register
DCD 0x90A00000, 0x4A000000, 1 ; Interrupt Control register
DCD 0x90B00000, 0x4B000000, 1 ; DMA control register
DCD 0x90C00000, 0x4C000000, 1 ; Clock & Power register
DCD 0x90D00000, 0x4D000000, 1 ; LCD control register
DCD 0x90E00000, 0x4E000000, 1 ; NAND flash control register
DCD 0x90F00000, 0x4F000000, 1 ; Camera control register
DCD 0x91000000, 0x50000000, 1 ; UART control register
DCD 0x91100000, 0x51000000, 1 ; PWM timer register
DCD 0x91200000, 0x52000000, 1 ; USB device register
DCD 0x91300000, 0x53000000, 1 ; Watchdog Timer register
DCD 0x91400000, 0x54000000, 1 ; IIC control register
DCD 0x91500000, 0x55000000, 1 ; IIS control register
DCD 0x91600000, 0x56000000, 1 ; I/O Port register
DCD 0x91700000, 0x57000000, 1 ; RTC control register
DCD 0x91800000, 0x58000000, 1 ; A/D convert register
DCD 0x91900000, 0x59000000, 1 ; SPI register
DCD 0x91A00000, 0x5A000000, 1 ; SD Interface register
DCD 0x92000000, 0x00000000, 32 ; 32 MB SROM(SRAM/ROM) BANK 0
DCD 0x00000000, 0x00000000, 0 ; end of table
那么wince中0x56000000就映射到了0x91600000
当然0x91600000也重复映射到了不缓存的地址0xB1600000
所以mini2440中有
#define IOP_BASE 0xB1600000 // 0x56000000
volatile IOPreg
*s2440IOP = (IOPreg *)IOP_BASE;
void Virtual_Alloc()
{
// GPIO Virtual alloc
s2440IOP = (volatile IOPreg *) VirtualAlloc(0,sizeof(IOPreg),MEM_RESERVE, PAGE_NOACCESS);
if(s2440IOP == NULL) {
RETAILMSG(1,(TEXT("For s2440IOP: VirtualAlloc faiLED!\r\n")));
}
else {
if(!VirtualCopy((PVOID)s2440IOP,(PVOID)(IOP_BASE),sizeof(IOPreg),PAGE_READWRITE | PAGE_NOCACHE )) {
RETAILMSG(1,(TEXT("For s2440IOP: VirtualCopy faiLED!\r\n")));
}
}
}
但是tq2440中却是更直接的做法
#define S3C2440A_BASE_REG_PA_IOPORT (0x56000000)
volatile S3C2440A_IOPORT_REG *v_pIOPregs ;
/* IO Register Allocation */
v_pIOPregs = (volatile S3C2440A_IOPORT_REG *)VirtualAlloc(0, sizeof(S3C2440A_IOPORT_REG), MEM_RESERVE, PAGE_NOACCESS);
if (v_pIOPregs == NULL)
{
ERRORMSG(1,(TEXT("For IOPregs : VirtualAlloc faiGPIO!\r\n")));
RetValue = FALSE;
}
else
{
if (!VirtualCopy((PVOID)v_pIOPregs, (PVOID)(S3C2440A_BASE_REG_PA_IOPORT >> 8), sizeof(S3C2440A_IOPORT_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE))
{
ERRORMSG(1,(TEXT("For IOPregs: VirtualCopy faiGPIO!\r\n")));
RetValue = FALSE;
}
}
Arm体系结构中,其它设备和存储器同等对待,统一编址到4G的地址空间中,所以所有设备都相当于是特殊地址的物理内存.
如果要访问某一地址的物理内存,因为wince的mmu启动以后就不能直接访问物理内存了,所以要通过虚拟内存来访问物理内存.
LPVOID VirtualAlloc(
LPVOID lpAddress,
DWORD dwSize,
DWORD flAllocationType,
DWORD flProtect
);
用来在虚拟内存空间中保留一块地方.
BOOL VirtualCopy(
LPVOID lpvDest,
LPVOID lpvSrc,
DWORD cbSize,
DWORD fdwProtect
);
用来把一块物理内存和虚拟内存绑定.
这样以后访问虚拟内存就相当于访问了物理内存了.