高端内存映射
与高端映射对立的是低端映射或所谓直接映射,内核中有关变量定义它们的它们的分界点,全局变量high_memory,该变量定义在mm/memory.c文件中(存在MMU的前提下),可见不区分体系结构,对于当前我手头的marvell的arm设备即对于arm体系结构,high_memory在初始化阶段的创建内存页表时初始化值,它的值就是:物理内存最后一个node的末尾,比如物理内存只有一个node,大小是256MB,再根据如下的算法就可以得出high_memory是多少:
high_memory = __va((max_low << PAGE_SHIFT) - 1) + 1;
max_low代表的是当前node的在物理内存中的物理页地址,比如物理内存从0x0开始(由PHYS_OFFSET决定),大小是256MB,即65536(0x10000)个物理页,那么max_low的值为0x10000,则high_memory的值为该物理页地址转为物理地址再转为虚拟地址的结果:0xd0000000。
high_memory之上就是高端内存的范围,这样的说法也不一定对,比如对于有的体系结构如arm,它的永久映射实际上就在high_memory之下的地方,但它依然是高端内存,所有物理内存都在初始化时映射在低端空间也是不一定正确的(这个可以在初始化时内存映射中发现,哪样的物理内存是会属于HIGHMEM区),所以我想通常意义的高端内存可以基本上定义为“不能直接通过偏移实现虚拟地址和物理地址映射”的虚拟空间、而“可以直接通过偏移实现虚拟地址和物理地址映射”的虚拟空间是低端内存(为什么低端映射也叫直接映射,这里体现出了直接的感觉)这样的方式界定比较好一些。
大体上内核有3种高端映射的机制,分别是永久映射、临时映射、非连续内存分配映射,
前面的文章细致描述过内核是如何通过slab/buddy获取大大小小的连续的物理内存的,它们是linux在低端虚拟地址空间的分配机制,使用连续物理内存是有很大好处的,对于充分利用CPU的cache有极大的利好;此外buddy和slab分别尽力的避免了物理内存空间的外碎片和内碎片;
只是有些时候比如我们的物理内存本身就不大,随着运行时间增长,物理内存的碎片还是可能会越来越多,分配连续的物理内存尤其是大尺寸连续的物理内存将越来越费劲;
为了尽可能避免这种情况或者在出现这种情况下能够缓解进一步费劲,对于某些不频繁的分配释放的内存申请,可以采用一种方式,即所谓的不连续内存分配如下图:
PAGE_OFFSET |
high_memory |
VMALLOC_START |
Vmalloc 1 |
4KB隔离带 |
Vmalloc 2 |
4KB隔离带 |
Vmalloc 3 |
4KB隔离带 |
…….. |
VMALLOC_END |
PKMAP_BASE |
8MB隔离带 |
Vmalloc N |
8KB隔离带 |
低端(物理)内存映射 |
FIXADDR_START |
永久映射区 |
临时映射区 |
通过上图,不连续内存映射空间即vmalloc区在4GB地址空间的什么位置应该很清楚了,现在描述下所谓不连续内存映射空间是什么意思:
不连续内存映射,不连续是指物理内存不连续,后面描述它的具体实现就能很清楚的发现它为什么是不连续,这里直接知道结果就是它映射物理地址的方式是一页一页映射的,比如需要映射10页物理地址空间,那么它是10次调用alloc_page从buddy获取,这样就会存在物理地址不连续的可能,之所以这样做就是如上面所说,某些东西申请内存后不会频繁的访问,并且它的长度如果不是很大的话,那么它适合vmalloc,因为分配一个连续的很大的物理地址是越来越困难的;
但是它的虚拟地址是连续的,如上面的图所示,每一个vmalloc X就是一个vmalloc映射,显然虚拟地址是连续的,只是它映射的物理地址是不一定连续的;
看到这里,就会明白为什么vmalloc需要增加内存页表的表项了,这都是初始化时没有的映射关系,而且确切的说是需要二级映射的,因为虚拟地址和物理地址之间都是一页一页映射的,可见vmalloc申请起来比较麻烦;另外,虚拟地址和物理地址之间都是一页一页映射,说明最好在申请的时候也按页的整数倍即对齐值申请。
那么,宏VMALLOC_START和VMALLOC_END是怎么定义的呢?如下:
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_END (PAGE_OFFSET + 0x30000000)
即vmalloc区始于high_memory加8MB的位置,结束于一个固定位置为0xF0000000;
最后看看到底哪些场合使用vmalloc:
1、swap;2、为module分配空间,见函数module_alloc就明白了;3、为IO驱动程序分配缓冲区(ioremap);
1、接口函数:
接口函数就是vmalloc和__vmalloc,它俩的区别就是vmalloc只需指定长度即可,而__vmalloc是由调用者自行指定gfpmask和prot参数,prot参数一般都是PAGE_KERNEL,gfpmask参数一般就是GFP_KERNEL | __GFP_HIGHMEM,调用__vmalloc可能会加上标志GFP_ZERO用于清零,它们都调用函数__vmalloc_node;此外还有个用于只申请一段vmalloc区间但不映射物理地址的接口函数get_vm_area;
2、具体实现:
static void *__vmalloc_node(unsigned long size, unsigned long align,
gfp_t gfp_mask, pgprot_t prot,
int node, void *caller)
{
struct vm_struct *area;
void *addr;
unsigned long real_size = size;
/*size 页对齐,因为vmalloc映射的物理内存不连续,所以是一页一页的映射,
即映射的物理内存大小必然是页的倍数,所以必须页对齐*/
size = PAGE_ALIGN(size);
/*检查size正确性,不能为0且不能大于totalram_pages,
totalram_pages是bootmem分配器移交给伙伴系统的物理内存页数总和*/
if (!size || (size >> PAGE_SHIFT) > totalram_pages)
return NULL;
/*申请一个vm_struct插入vmlist链表,申请一个vmap_area并插入红黑树
完成非连续内存区的高端虚拟地址分配,注意size总会额外在最后加一页,用于安全区(上图的4KB隔离带)
注意: vm_struct本身是使用kmalloc_node()在slab,所以在低端内存中;
而函数alloc_vmap_area真正分配了连续的高端虚拟地址
简单的总结: 分配一个vm_struct结构,获取对应长度(注意额外加一页)高端连续地址,最终插入vmlist链表*/
area = __get_vm_area_node(size, align, VM_ALLOC, VMALLOC_START,
VMALLOC_END, node, gfp_mask, caller);
if (!area)
return NULL;
/*本函数实际的给虚拟地址映射了不连续的物理内存(调用函数alloc_page一页一页的分配物理地址,函数map_vm_area实现映射)
返回值是分配的高端虚拟地址的起始*/
addr = __vmalloc_area_node(area, gfp_mask, prot, node, caller);
/*
* A ref_count = 3 is needed because the vm_struct and vmap_area
* structures allocated in the __get_vm_area_node() function contain
* references to the virtual address of the vmalloc'ed block.
*/
kmemleak_alloc(addr, real_size, 3, gfp_mask);
/*返回值是分配的高端虚拟地址的起始*/
return addr;
}
主要就是两大部分:分配高端虚拟地址(即分配一段vmalloc区间) + 给虚拟地址映射物理地址;
进入函数__get_vm_area_node:
static struct vm_struct *__get_vm_area_node(unsigned long size,
unsigned long align, unsigned long flags, unsigned long start,
unsigned long end, int node, gfp_t gfp_mask, void *caller)
{
static struct vmap_area *va;
struct vm_struct *area;
BUG_ON(in_interrupt());
if (flags & VM_IOREMAP) {
int bit = fls(size);
if (bit > IOREMAP_MAX_ORDER)
bit = IOREMAP_MAX_ORDER;
else if (bit < PAGE_SHIFT)
bit = PAGE_SHIFT;
align = 1ul << bit;
}
size = PAGE_ALIGN(size);
if (unlikely(!size))
return NULL;
/*申请一个vm_struct,本质还是通过kmalloc申请,申请的是高端的虚拟内存
kmalloc可保证虚拟内存的连续性,这验证了vmalloc申请的虚拟地址是连续的
本质就是: 使用kmalloc_node()在slab中,分配一个vm_struct结构*/
area = kzalloc_node(sizeof(*area), gfp_mask & GFP_RECLAIM_MASK, node);
if (unlikely(!area))
return NULL;
/*
* We always allocate a guard page.
*/
/*vmalloc总是要将size加上一个页框的大小作为安全区*/
size += PAGE_SIZE;
/*在start到end中,分配足够size大小的内核虚拟空间*/
/*注意: vmap_area结构体(返回值va)本身也是通过kmalloc分配,所以也在低端内存中,
它的成员va_start和va_end指示了真正申请的高端虚拟内存的地址范围,可见是线性的(连续的)
[va_start---va_end]落在高端内存的非连续映射区(vmalloc区)中,va_end - va_start = size = 实际需要映射长度 + 4KB(安全区)
寻找新节点在红黑树的插入点并计算出应该的高端地址值(addr),关于红黑树,细节暂不讨论留在后续
将最终的高端地址值赋给va,并插入红黑树中*/
va = alloc_vmap_area(size, align, start, end, node, gfp_mask);
if (IS_ERR(va)) {
kfree(area);
return NULL;
}
/*将va的值(高端地址起始和长度)赋给area,最终把area插入vmlist链表*/
insert_vmalloc_vm(area, va, flags, caller);
/*这里area已经被赋值的成员有,addr和size(高端地址)、flag、caller*/
return area;
}
首先注意结构体vm_struct,它是vmalloc的管理方法非常重要:
struct vm_struct {
struct vm_struct *next; /*指向下一个vm区域*/
void *addr; /*指向第一个内存单元(线性地址)*/
unsigned long size; /*该块内存区的大小*/
unsigned long flags; /*内存类型的标识字段*/
struct page **pages; /*指向页描述符指针数组*/
unsigned int nr_pages; /*内存区大小对应的页框数*/
unsigned long phys_addr; /*用来映射硬件设备的IO共享内存,其他情况下为0*/
void *caller; /*调用vmalloc类的函数的返回地址*/
};
全局变量vmlist是管理所有vmalloc对象的链表表头,每个vmalloc映射都要把它的映射结果即一个struct vm_struct型的描述符加入链表中,成员next用于这个链表;addr指示这段vmalloc区的虚拟地址起始;size标识这段vmalloc区的长度;flags标识映射方式,在include/linux/vmalloc.h文件中有明确的使用方式,像在__vmalloc_node调用就是VM_ALLOC:
#define VM_IOREMAP 0x00000001 /* ioremap() and friends */
#define VM_ALLOC 0x00000002 /* vmalloc() */
#define VM_MAP 0x00000004 /* vmap()ed pages */
#define VM_USERMAP 0x00000008 /* suitable for remap_vmalloc_range */
#define VM_VPAGES 0x00000010 /* buffer for pages was vmalloc'ed */
成员pages是一个数组,每个成员都是所映射的物理页的page描述符地址;nr_pages标识所映射的物理页,注意它不包括一页的隔离带;phys_addr用来映射硬件设备的IO共享内存,其他情况下为0;caller是调用vmalloc类的函数的返回地址,它是用于调试和找问题的比如可以通过proc下的vmallocinfo看是哪个函数在申请高端虚拟内存;
对struct vm_struct有了个大概认识后可以具体看源码,首先通过kmalloc申请一个struct vm_struct结构变量area,注意这个结构变量本身是在低端连续内存区,然后调用函数alloc_vmap_area,这个比较重要如下:
static struct vmap_area *alloc_vmap_area(unsigned long size,
unsigned long align,
unsigned long vstart, unsigned long vend,
int node, gfp_t gfp_mask)
{
struct vmap_area *va;
struct rb_node *n;
unsigned long addr;
int purged = 0;
BUG_ON(!size);
BUG_ON(size & ~PAGE_MASK);
/*vmap_area结构体本身也是通过kmalloc分配,所以也在低端内存中*/
va = kmalloc_node(sizeof(struct vmap_area),
gfp_mask & GFP_RECLAIM_MASK, node);
if (unlikely(!va))
return ERR_PTR(-ENOMEM);
/*下面是寻找新节点在红黑树的插入点并计算出应该的高端地址值(addr),关于红黑树,细节暂不讨论留在后续*/
retry:
addr = ALIGN(vstart, align);
spin_lock(&vmap_area_lock);
if (addr + size - 1 < addr)
goto overflow;
/* XXX: could have a last_hole cache */
n = vmap_area_root.rb_node;
if (n) {
struct vmap_area *first = NULL;
do {
struct vmap_area *tmp;
tmp = rb_entry(n, struct vmap_area, rb_node);
if (tmp->va_end >= addr) {
if (!first && tmp->va_start < addr + size)
first = tmp;
n = n->rb_left;
} else {
first = tmp;
n = n->rb_right;
}
} while (n);
if (!first)
goto found;
if (first->va_end < addr) {
n = rb_next(&first->rb_node);
if (n)
first = rb_entry(n, struct vmap_area, rb_node);
else
goto found;
}
while (addr + size > first->va_start && addr + size <= vend) {
addr = ALIGN(first->va_end + PAGE_SIZE, align);
if (addr + size - 1 < addr)
goto overflow;
n = rb_next(&first->rb_node);
if (n)
first = rb_entry(n, struct vmap_area, rb_node);
else
goto found;
}
}
found:
if (addr + size > vend) {
overflow:
spin_unlock(&vmap_area_lock);
if (!purged) {
purge_vmap_area_lazy();
purged = 1;
goto retry;
}
if (printk_ratelimit())
printk(KERN_WARNING
"vmap allocation for size %lu failed: "
"use vmalloc=<size> to increase size.\n", size);
kfree(va);
return ERR_PTR(-EBUSY);
}
BUG_ON(addr & (align-1));
/*将最终的高端地址值赋给va,并插入红黑树中*/
va->va_start = addr;
va->va_end = addr + size;
va->flags = 0;
__insert_vmap_area(va);
spin_unlock(&vmap_area_lock);
return va;
}
这个函数alloc_vmap_area作用就是根据所要申请的高端地址的长度size(注意这里的size已经是加上一页隔离带的size),在vmalloc区找到一个合适的区间并把起始虚拟地址和结尾地址通知给内核,具体说来还包括struct vmap_area的问题,它是实际维护vmalloc信息的数据结构,比较复杂,linux内核维护vmalloc信息是通过红黑树算法(一种特殊的平衡二叉树,增删查改效率高)实现,这个东西比较麻烦一些,后续专门讨论它,但不了解它不影响对vmalloc管理的分析,这里知道alloc_vmap_area函数的最终作用是得到被分配的高端虚拟地址起始和结尾地址即可;
然后最终调用函数insert_vmalloc_vm把这个vm_struct结构变量加入vmlist链表,源码不贴了就。
这时还没有给这个vmalloc区分配和映射物理地址,现在调用函数__vmalloc_area_node:
static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
pgprot_t prot, int node, void *caller)
{
struct page **pages;
unsigned int nr_pages, array_size, i;
/*得到实际需要映射的页数(减去一页的安全区)*/
nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT;
/*并得到所需的空间(页数*page结构长度)*/
array_size = (nr_pages * sizeof(struct page *));
area->nr_pages = nr_pages;
/* Please note that the recursion is strictly bounded. */
/*不仅要映射的高端地址通过__get_vm_area_node分配高端地址,
提供映射的页指针也在高端地址分配,不足一页的话在低端地址中分配*/
if (array_size > PAGE_SIZE) {
pages = __vmalloc_node(array_size, 1, gfp_mask | __GFP_ZERO,
PAGE_KERNEL, node, caller);
area->flags |= VM_VPAGES;
} else {
pages = kmalloc_node(array_size,
(gfp_mask & GFP_RECLAIM_MASK) | __GFP_ZERO,
node);
}
/*将映射用的页表pages在分配到高端(不足一页在低端)地址后,赋给area*/
area->pages = pages;
area->caller = caller;
if (!area->pages) {
remove_vm_area(area->addr);
kfree(area);
return NULL;
}
/*从伙伴系统中进行物理内存页面的分配,注意是为每一个页面分配空间*/
for (i = 0; i < area->nr_pages; i++) {
struct page *page;
/*UMA系统*/
if (node < 0)
page = alloc_page(gfp_mask);
/*NUMA系统*/
else
page = alloc_pages_node(node, gfp_mask, 0);
if (unlikely(!page)) {
/* Successfully allocated i pages, free them in __vunmap() */
area->nr_pages = i;
goto fail;
}
/*将页表pages里的内容填充,填充的是一个一个的物理页地址*/
area->pages[i] = page;
}
/*area的addr和size代表了要映射的高端地址,pages里填充了实际被映射的物理页地址
接下来完成虚拟地址到物理地址的映射,注意最终是要创建二级映射(二级页表空间需从buddy申请,大小为1页)*/
if (map_vm_area(area, prot, &pages))
goto fail;
return area->addr;
fail:
vfree(area->addr);
return NULL;
}
首先实际需要映射的页数(注意不包含一页的隔离带),计算这个的目的是到页表所需的空间(页数*page结构长度),确切的说是二级页表所需的空间(从之前的文章可知道,二级映射的页表是动态创建的,一级页表即段页表是常驻内存),注意如果这个二级页表它所占的空间超出一页长度,那么也在vmalloc区里分配它,否则就在低端连续区分配即可;另外从编程角度看,这里递归了一下函数__vmalloc_node;
把二级页表地址和调用者成员赋值给area,接下来就开始分配物理空间了,这里可以清楚的看到是使用for循环一页一页分配的,这就是为什么物理地址不一定连续的原因;另外要注意,把这些物理页地址依次写进了二级页表表项,即“area->pages[i] = page”;
最后一个操作就是调用函数map_vm_area把分配的物理地址和高端虚拟地址做映射,
int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages)
{
unsigned long addr = (unsigned long)area->addr;
unsigned long end = addr + area->size - PAGE_SIZE;
int err;
/*start和end代表了要映射的高端地址,pages里填充了实际被映射的物理页地址
注意最终是要在内核页表中创建二级映射*/
err = vmap_page_range(addr, end, prot, *pages);
if (err > 0) {
*pages += err;
err = 0;
}
return err;
}
注意都是二级映射,这里涉及了内存页表知识可以看之前的描述内存页表的那篇文章,arm的MMU只有二级映射,本函数前期基本相当于空跑即跳过linux的pud、pmd,直到函数vmap_pte_range开始创建二级映射;
在proc下有个vmallocinfo,可以查看当前vmalloc信息,就是通过上面说的vmlist链表查看每一个正在映射的vmalloc,打印出虚拟起始地址、虚拟结尾地址、映射长度、调用者、映射页数、映射方式,非常简单源码如下:
static int s_show(struct seq_file *m, void *p)
{
struct vm_struct *v = p;
seq_printf(m, "0x%p-0x%p %7ld",
v->addr, v->addr + v->size, v->size);
if (v->caller) {
char buff[KSYM_SYMBOL_LEN];
seq_putc(m, ' ');
sprint_symbol(buff, (unsigned long)v->caller);
seq_puts(m, buff);
}
if (v->nr_pages)
seq_printf(m, " pages=%d", v->nr_pages);
if (v->phys_addr)
seq_printf(m, " phys=%lx", v->phys_addr);
if (v->flags & VM_IOREMAP)
seq_printf(m, " ioremap");
if (v->flags & VM_ALLOC)
seq_printf(m, " vmalloc");
if (v->flags & VM_MAP)
seq_printf(m, " vmap");
if (v->flags & VM_USERMAP)
seq_printf(m, " user");
if (v->flags & VM_VPAGES)
seq_printf(m, " vpages");
show_numa_info(m, v);
seq_putc(m, '\n');
return 0;
}
比如我的当前打印如下:
/ # cat proc/vmallocinfo
0xbf000000-0xbf0b3000 733184 module_alloc+0x54/0x60 pages=178 vmalloc
0xd085e000-0xd0860000 8192 __arm_ioremap_pfn+0x64/0x144 ioremap
0xd0861000-0xd0882000 135168 ubi_attach_mtd_dev+0x390/0x9c8 pages=32 vmalloc
0xd0883000-0xd08a4000 135168 ubi_attach_mtd_dev+0x3b0/0x9c8 pages=32 vmalloc
0xd08a5000-0xd08ac000 28672 ubi_read_volume_table+0x178/0x8cc pages=6 vmalloc
0xd08b6000-0xd08b8000 8192 __arm_ioremap_pfn+0x64/0x144 ioremap
0xd08ba000-0xd08bc000 8192 __arm_ioremap_pfn+0x64/0x144 ioremap
0xd08bd000-0xd08ce000 69632 lzo_init+0x18/0x30 pages=16 vmalloc
0xd08cf000-0xd0912000 274432 deflate_init+0x1c/0xe8 pages=66 vmalloc
0xd0913000-0xd0934000 135168 ubifs_get_sb+0x79c/0x1104 pages=32 vmalloc
0xd0935000-0xd0937000 8192 ubifs_lpt_init+0x30/0x428 pages=1 vmalloc
0xd095d000-0xd095f000 8192 ubifs_lpt_init+0x30/0x428 pages=1 vmalloc
0xd0960000-0xd0965000 20480 __arm_ioremap_pfn+0x64/0x144 ioremap
0xd0966000-0xd0987000 135168 ubi_attach_mtd_dev+0x390/0x9c8 pages=32 vmalloc
0xd0988000-0xd09a9000 135168 ubi_attach_mtd_dev+0x3b0/0x9c8 pages=32 vmalloc
0xd09aa000-0xd09b1000 28672 ubi_read_volume_table+0x178/0x8cc pages=6 vmalloc
0xd09ba000-0xd09db000 135168 ubifs_get_sb+0x79c/0x1104 pages=32 vmalloc
0xd09dc000-0xd09fd000 135168 ubifs_get_sb+0x7b8/0x1104 pages=32 vmalloc
0xd0a00000-0xd0b01000 1052672 __arm_ioremap_pfn+0x64/0x144 ioremap
0xd0bd0000-0xd0bd2000 8192 ubifs_lpt_init+0x220/0x428 pages=1 vmalloc
0xd0bd3000-0xd0bf4000 135168 ubifs_lpt_init+0x234/0x428 pages=32 vmalloc
0xd0bf5000-0xd0bf8000 12288 tpm_db_mod2_setup_jump_area+0x84/0x3cc pages=2 vmalloc
0xd0bf9000-0xd0bfb000 8192 tpm_db_mod2_setup_jump_area+0x100/0x3cc pages=1 vmalloc
0xd0bfc000-0xd0bfe000 8192 tpm_db_mod2_setup_jump_area+0x174/0x3cc pages=1 vmalloc
0xd0c00000-0xd0d01000 1052672 __arm_ioremap_pfn+0x64/0x144 ioremap
0xd0d24000-0xd0d45000 135168 ubifs_mount_orphans+0x44/0x41c pages=32 vmalloc
0xd0d46000-0xd0d48000 8192 tpm_db_mod2_setup_jump_area+0x1f4/0x3cc pages=1 vmalloc
0xd0d49000-0xd0d4b000 8192 tpm_db_mod2_setup_jump_area+0x270/0x3cc pages=1 vmalloc
0xd0d4c000-0xd0d4e000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0d4f000-0xd0d51000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0d52000-0xd0d54000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0d55000-0xd0d57000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0d58000-0xd0d5a000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0d5b000-0xd0d5d000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0d5e000-0xd0d60000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0d61000-0xd0d63000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0d64000-0xd0d66000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0d67000-0xd0d69000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0d6a000-0xd0d6c000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0d6d000-0xd0d6f000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0d70000-0xd0d72000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0d73000-0xd0d75000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0d76000-0xd0d78000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0d79000-0xd0d7b000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0d7c000-0xd0d7e000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0d7f000-0xd0d81000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0d82000-0xd0d84000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0d85000-0xd0d87000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0d88000-0xd0d8a000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0d8b000-0xd0d8d000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0d8e000-0xd0d90000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0d91000-0xd0d93000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0d94000-0xd0d96000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0d97000-0xd0d99000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0d9a000-0xd0d9c000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0d9d000-0xd0db0000 77824 tpm_db_mod2_setup_chain_area+0x264/0x308 pages=18 vmalloc
0xd0db1000-0xd0db4000 12288 tpm_db_mod2_setup_jump_area+0x84/0x3cc pages=2 vmalloc
0xd0db5000-0xd0db7000 8192 tpm_db_mod2_setup_jump_area+0x100/0x3cc pages=1 vmalloc
0xd0db8000-0xd0dba000 8192 tpm_db_mod2_setup_jump_area+0x174/0x3cc pages=1 vmalloc
0xd0dbb000-0xd0dbd000 8192 tpm_db_mod2_setup_jump_area+0x1f4/0x3cc pages=1 vmalloc
0xd0dbe000-0xd0dc0000 8192 tpm_db_mod2_setup_jump_area+0x270/0x3cc pages=1 vmalloc
0xd0dc1000-0xd0dc3000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0dc4000-0xd0dc6000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0dc7000-0xd0dc9000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0dca000-0xd0dcc000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0dcd000-0xd0dcf000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0dd0000-0xd0dd2000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0dd3000-0xd0dd5000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0dd6000-0xd0dd8000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0dd9000-0xd0ddb000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0ddc000-0xd0dde000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0ddf000-0xd0de1000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0de2000-0xd0de4000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0de5000-0xd0de7000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0de8000-0xd0dea000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0deb000-0xd0ded000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0dee000-0xd0df0000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0df1000-0xd0df3000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0df4000-0xd0df6000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0df7000-0xd0df9000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0dfa000-0xd0dfc000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0dfd000-0xd0dff000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0e00000-0xd0f01000 1052672 __arm_ioremap_pfn+0x64/0x144 ioremap
0xd0f02000-0xd0f04000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0f05000-0xd0f07000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0f08000-0xd0f0a000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0f0b000-0xd0f0d000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0f0e000-0xd0f10000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0f11000-0xd0f13000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0f14000-0xd0f27000 77824 tpm_db_mod2_setup_chain_area+0x264/0x308 pages=18 vmalloc
0xd0f28000-0xd0f2b000 12288 tpm_db_mod2_setup_jump_area+0x84/0x3cc pages=2 vmalloc
0xd0f2c000-0xd0f2e000 8192 tpm_db_mod2_setup_jump_area+0x100/0x3cc pages=1 vmalloc
0xd0f2f000-0xd0f31000 8192 tpm_db_mod2_setup_jump_area+0x174/0x3cc pages=1 vmalloc
0xd0f32000-0xd0f34000 8192 tpm_db_mod2_setup_jump_area+0x1f4/0x3cc pages=1 vmalloc
0xd0f35000-0xd0f37000 8192 tpm_db_mod2_setup_jump_area+0x270/0x3cc pages=1 vmalloc
0xd0f38000-0xd0f3a000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0f3b000-0xd0f3d000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0f3e000-0xd0f40000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0f41000-0xd0f43000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0f44000-0xd0f46000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0f47000-0xd0f49000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0f4a000-0xd0f4c000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0f4d000-0xd0f4f000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0f50000-0xd0f52000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0f53000-0xd0f55000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0f56000-0xd0f58000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0f59000-0xd0f5b000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0f5c000-0xd0f5e000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0f5f000-0xd0f61000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0f62000-0xd0f64000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0f65000-0xd0f67000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0f68000-0xd0f6a000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0f6b000-0xd0f6d000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0f6e000-0xd0f70000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0f71000-0xd0f73000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0f74000-0xd0f76000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0f77000-0xd0f79000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0f7a000-0xd0f7c000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0f7d000-0xd0f7f000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0f80000-0xd0f82000 8192 tpm_db_mod2_setup_chain_area+0xd4/0x308 pages=1 vmalloc
0xd0f83000-0xd0f85000 8192 tpm_db_mod2_setup_chain_area+0x150/0x308 pages=1 vmalloc
0xd0f86000-0xd0f88000 8192 tpm_db_mod2_setup_chain_area+0x1b0/0x308 pages=1 vmalloc
0xd0f89000-0xd0f9c000 77824 tpm_db_mod2_setup_chain_area+0x264/0x308 pages=18 vmalloc
0xd1000000-0xd1101000 1052672 __arm_ioremap_pfn+0x64/0x144 ioremap
0xd1200000-0xd1301000 1052672 __arm_ioremap_pfn+0x64/0x144 ioremap
是不是非常清楚!