关于静态映射与动态映射io地址时虚拟地址的问题:
一直有个问题,当我们人为的去静态的分配好IO地址所对应的虚拟地址时,此时我们已经占用了一片虚拟地址空间,但是此时使用io_remap去动态映射时,会不会申请到的虚拟地址空间
会和我们已经占用的静态映射空间重叠,如果重叠,我们此时再去操作这个虚拟地址时就会出现很多问题。
针对这个问题,
对于arm平台:
首先需要去填充一个结构体,也就是静态映射表,表明哪段IO地址可以使用哪段虚拟地址,这个虚拟地址的安排是我们人为安排的,
问:这个虚拟地址有没有什么规定,还是说只要在虚拟地址的内核空间(3G-4G)就可以?
一般来讲我们需要避开内核的线性映射区,这一片虚拟地址已经用于映射DDR了,不要破坏这一块映射区。从下面代码的初始化也可以看出,我们会将这个虚拟地址安排在内核线性映射区后的vmalloc区内,
这个区域也是ioreamp动态映射方式的映射区。这样的话,大家共用一片虚拟地址空间。
但是会不会同一个IO物理地址,使用静态映射和ioremap后的虚拟地址是一样的?答案是不会,静态映射的时候这一片虚拟地址已经被标记过,ioremap会绕过这一段,得到的地址不一样,而且同一 个物理地址是支持被映射到不同的虚拟地址空间的。
我也看到过将IO地址直接映射到内核线性映射区间的,这样也可以,但是并不推荐,因为这一片已经用来映射物理地址了,如果内核使用这里的虚拟地址去操作物理内存,但是你将IO外设的物理地 址映射到了这里,那这里到底谁用?会出现问题。所以应该有效利用起虚拟地址空间,内核线性映射区被外设DDR全部映射,IO地址作为同等地位的外设应该映射到其他的虚拟地址空间去。
然后使用函数iotable_init为需要的io物理地址与虚拟地址建立映射关系,这一步完了后
我们才可以在程序中直接使用映射后的虚拟地址,否则会出现异常。在set_up阶段会去调用machine结构体中的map_io成员函数,该函数完成映射表的初始化
#define VIRT_SYSTEM (VMALLOC_END - SIZE_IO)
#define VIRT_ARM_PERIPHBASE (VIRT_SYSTEM - SIZE_ARM_PERIPHBASE)
#define VIRT_NOR_FLASH (VIRT_ARM_PERIPHBASE - SIZE_NOR_FLASH)
static struct map_desc sxxx_io_desc[] __initdata =
{
{
.virtual = VIRT_SYSTEM,//有的使用IO_ADDRESS宏来进行转化,这是一个可以客制化的一个宏,输入为物理地址,输出为计算好的虚拟地址,我们可以改动让其算出我们想要的虚拟地址。
.pfn = __phys_to_pfn(PHYS_SYSTEM),
.length = SIZE_IO,
.type = MT_DEVICE,
},
{
.virtual = VIRT_ARM_PERIPHBASE,
.pfn = __phys_to_pfn(PHYS_ARM_PERIPHBASE),
.length = SIZE_ARM_PERIPHBASE,
.type = MT_DEVICE,
},
};
void __init sxxx_map_io(void)
{
iotable_init(sxxx_io_desc, ARRAY_SIZE(sxxx_io_desc));
}
MACHINE_START(SXXXX, BOARD_NAME)
.atag_offset = 0x100,
.map_io = sxxx_map_io,
.
.
.
MACHINE_END