分类: LINUX
2010-03-11 19:11:38
Vmalloc可以获得的地址在VMALLOC_START到VMALLOC_END的范围中。这两个符号在
/* include/asm/pgtable.h */
#define VMALLOC_OFFSET (8*1024*1024)
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
…………
high_memory值在这里定义:
/* arch/arm/mm/init.c */
void __init bootmem_init(struct meminfo *mi)
{
……
high_memory = __va(memend_pfn << PAGE_SHIFT);
}
在我们的板子上,这些值为:
high_mem = 0xc4000000 <--------- 3G+64M , high_memory既实际内存最大物理地址对应的的内核逻辑地址
VMALLOC_START = 0xc4800000 <--------- 3G+64M+8M (8M为内核规定的一个gap) ,vmalloc分配的起始地址(内核空间)
我在kernel里加了一些打印信息,打印出的结果如下:
Starting kernel ...
Linux version 2.6.18_pro500-omap5912_osk (root@ubuntu) (gcc version 4.2.0 20070319 (prerelease) (MontaVista 4.2.0-4.0.0.0702865 2007-03-26)) #36 Mon Jun 16 16:29:30 CST 2008
CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=00053177
Machine:
Memory policy: ECC disabled, Data cache writeback
high_mem = 0xc4000000 --------------------
vmalloc_start = 0xc4800000 ----------------------
…………
The following is the vmalloc test processing:
/* Vmalloc Test Module */
……
static int __init tcm_init(void)
{
struct resource * ret;
unsigned long * vaddr1 = NULL;
unsigned long * vaddr2 = NULL;
……
vaddr1 = vmalloc ( PAGE_SIZE );
printk("vaddr1 = 0x%p \n", vaddr1);
vaddr2 = vmalloc ( PAGE_SIZE );
printk("vaddr2 = 0x%p \n", vaddr2);
vfree(vaddr1);
vfree(vaddr2);
……
}
……
module_init(tcm_init);
module_exit(tcm_exit);
The running result:
# insmod tcm1.ko
vaddr1 = 0xc487a000 ß vmalloc分配的地址,大于0xc3ffffff (3G+64M)
vaddr2 = 0xc487c000
参考资料: (摘自《Linux 内存管理》)
……
vmalloc分配的内核虚拟内存与kmalloc/get_free_page分配的内核虚拟内存位于不同的区间,不会重叠。因为内核虚拟空间被分区管理,各司其职。进程空间地址分布从0到3G(其实是到PAGE_OFFSET, 在0x86中它等于0xC0000000),从3G到vmalloc_start这段地址是物理内存映射区域(该区域中包含了内核镜像、物理页面表mem_map等等)比如我使用的系统内存是64M(可以用free看到),那么(3G——3G+64M)这片内存就应该映射到物理内存,而vmalloc_start位置应在3G+64M附近(说"附近"因为是在物理内存映射区与vmalloc_start期间还会存在一个8M大小的gap来防止跃界),vmalloc_end的位置接近4G(说"接近"是因为最
后位置系统会保留一片128k大小的区域用于专用页面映射,还有可能会有高端内存映射区,这些都是细节,这里我们不做纠缠)。
由get_free_page或Kmalloc函数所分配的连续内存都陷于物理映射区域,所以它们返回的内核虚拟地址和实际物理地址仅仅是相差一个偏移量(PAGE_OFFSET),你可以很方便的将其转化为物理内存地址,同时内核也提供了virt_to_phys()函数将内核虚拟空间中的物理映射区地址转化为物理地址。要知道,物理内存映射区中的地址与内核页表是有序对应的,系统中的每个物理页面都可以找到它对应的内核虚拟地址(在物理内存映射区中的)。
而vmalloc分配的地址则限于vmalloc_start与vmalloc_end之间。每一块vmalloc分配的内核虚拟内存都对应一个vm_struct结构体(可别和vm_area_struct搞混,那可是进程虚拟内存区域的结构),不同的内核虚拟地址被4k大小的空闲区间隔,以防止越界——见下图)。与进程虚拟地址的特性一样,这些虚拟地址与物理内存没有简单的位移关系,必须通过内核页表才可转换为物理地址或物理页。它们有可能尚未被映射,在发生缺页时才真正分配物理页面。