- 论坛徽章:
- 9
|
本帖最后由 Tinnal 于 2014-08-06 00:28 编辑
回复 9# qq1158291633
我大概明白你的意思了。我描述一下,看看是不是你的场景。
你要MAP很大一块物理内存(远大于128M),因此vmalloc的想法肯定是不行了,因为没这么多虚拟地址。这一点你也明白,并且你也说了,window也没有这么多。你想要的是内核给你一段连续的虚拟地址,例如30M,然后你还想内核给你一个函数,每一次能让你map 30M物理内存到这段虚拟地址。究竟每次map哪50M,由你自己决定。
其实如果那个50M变成4K,就是你想要的效果。你只是嫌弃这样每次能用的只有4K,可能连最基本的业务都运行不起来,或者切太碎不好管理。
如果我的理解没有错,内核其实有对应的函数,只是模块不会这么用而已,内核自己已经这么用了。
具体的代码其实就是ioremap(如果需要cache,还有ioremap_fullcache), 这个函数你给他一段物理地址,它会给你map成连续的虚拟地址,直接用它在你这种场景不适合,因为1)每次都得iounmap再ioremap;2)每次ioremap有可能返回地地址不一样。
看上去不合适你用户,但打开这个函数实现后,你就会豁然开朗。
void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
{
。。。。。省略一大堆安全判断 。。。。。。。。
//下面是页表属性设定,抄就行了。唯一的改动也就是根据是否采用cache改改flags的值。
prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY
| _PAGE_ACCESSED | flags);
。。。省略对齐操作,这工作我知到你肯定会做的 。。。。。。。。
//呵呵,下面的接口不就是你想要的一次申请一段虚拟工间的接口吗?乐死了吧!
//不过get_vm_area接口没有导出,不能在模块里用,已导出的接口为alloc_vm_area。已经有内核模块在你这个接口了,可以放心使用。
area = get_vm_area(size, VM_IOREMAP | (flags << 20));
if (!area)
return NULL;
area->phys_addr = phys_addr;
addr = (void __iomem *) area->addr;
//下面的函数也没有导出,要不把它导出来用。
//要不戏参照alloc_vm_area的另一个用户grant-table.c,使用已经导出的apply_to_page_range函数。
if (ioremap_page_range((unsigned long) addr,
(unsigned long) addr + size, phys_addr, prot)) {
vunmap((void __force *) addr);
return NULL;
}
return (void __iomem *) (offset + (char __iomem *)addr);
总得来于有两套方案:
1. 参照ioremap, 把get_vm_area、ioremap_page_range都导出去,再实现你的算法。代码量少。
2. 参照grant-table.c, 使用已导出的alloc_vm_area、apply_to_page_range接口。代码量也不太,但apply_to_page_range有一个回调要注册。
3. 内核vmap的实现也能参考,呵呵。
Over,唉,又长又臭。我也臭了,洗操去。
|
|