是不是我错了,本想这个函数会如网上所说将进行非连续内存管理的初始化,但是对于2.6.34的ARM架构而言,该函数实际完成的业务非常少。

内存管理的初始化读到此处,我感觉原有的认识存在很大缺陷:

(1)内核空间的下限是3G吗?永久映射的PKMAP_BASE已在3G下;

(2)低端内存是896M吗?2.6.32的omap4430的VMLLOC_END是1G - 128M,VMALLOC_MIN是1G - 128M -128M;

(3)还存在固定映射吗?FIXADDR_SIZE的空间已被FIX_KMAP_BEGIN ~ FIXK_KMAP_END完全占据;

(4)I/O空间在初始化已固定映射至VMALLOC_END到FIXADDR_START之间的一块虚拟空间区域.

(5)用户态不可以执行3G以上空间代码吗?kuser_cmpxchg_check检测的意义;

(6)引入MODULES_END的意义是什么?

对于ARM架构,vmalloc_init中的for循环就没有执行,如有误,望指正.

void vmalloc_init(void)
|-->for_each_possible_cpu(i)
|--{
| struct vmap_block_queue *vbq;
| vbq = &per_cpu(vmap_block_queue, i);
| spin_lock_init(&vbp->lock);
| INIT_LIST_HEAD(&vbq->free);
|--}
|
|--for(tmp = vmlist; tmp; tmp = tmp->next)
|--{
| xxxxxxxx
| 对于2..34的ARM架构而言,vmlist直到此时仍为0;
| 所以该循环不会执行,至于网上的资料大概是针对X86的.
|--}
|
|--vmap_area_pcpu_hole = VMALLOC_END;
| vmap_initialized = true;

如下部分是我后期再看init_arch_irq()中看的,主要是因为我们知道:对于ARM架构, vmalloc_init中的for循环没有执行,那么我们自然会想何时对首次修改vmlist以及如何修改.

init_arch_irq中会执行ioremap函数,以下记录该函数的执行流程.

#define ioremap(cookie, size) \
__arm_ioremap(cookie, size, MT_DEVICE) void *__arm_ioremap(unsigned long phys_addr, size_t size,
unsigned int mtype)
|-->__arm_ioremap_caller(phys_addr, size, mtype, NULL) void *__arm_ioremap_caller(unsigned long phys_addr, size_t size,
unsigned int mtype, void *caller)
|-->unsigned long offset = phys_addr & ~PAGE_MASK;
| 对于SOC,例如sep612,每个IP模块的所占空间都是4K的整数倍,所以
| 一般情况下offset = ;
|
|-->unsigned long pfn = __phys_to_pfn(phys_addr);
|
|-->return __arm_ioremap_pfn_caller(pfn, offset, size, mtype, caller);
void *__arm_ioremap_pfn_caller(unsigned long pfn, unsigned long offset,
size_t size, unsigned int mtype, void *caller)
|-->const struct mem_type *type = get_mem_type(mtype)
| mem_type中存放页表映射属性,及页表的级数
|
|-->size = PAGE_ALIGN(offset + size);
|
|-->struct vm_struct *area = get_vm_area_caller(size, VM_IOREMAP,
| caller);
| 根据size,在VMALLOC_START ~ VMALLOC_END中申请一块size + PAGE_SIZE
| 大小的虚拟空间,由于非连续内存区域的管理还利用了红黑树,因此在获得vm_struct
| 实例的同时,也将申请vmap_area实例,将申请的虚拟空间,纳入红黑树
| vmap_area_root.rb_node的管理.
|
|-->unsigned long addr = (unsigned long)area->addr;
|
|-->remap_area_pages(addr, pfn, size, type);
| 前面讲过,申请的虚拟空间是size + PAGE_SIZE,此处我们看到,
| 映射的物理空间大小是size.
|
|-->flush_cache_vmap(addr, addr+size);
|
|-->return (void *) (offset + addr);
struct vm_struct *get_vm_area_caller(unsigned long size,
unsigned long flags, void *caller)
|-->return __get_vm_area_node(size, , flags, VMALLOC_START,
VMALLOC_END, -, GFP_KERNEL, caller); 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)
|-->struct vmap_area *va = NULL;
| struct vm_struct *area = NULL;
|
|-->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 = << bit;
|--}
| 对于IO 映射部分做了对其修正.
|
|
|-->size = PAGE_ALIGN(size);
|
|-->area = kzalloc_node(sizeof(*area), gfp_mask & GPF_RECLAIM_MASK,
| node);
| 对于非连续内存区,既使用了vmlist这样的链表管理,也使用了vmap_area_root
| 之类的红黑树进行管理,此处即申请需插入到vmlist链表中的vm_struct实例中.
|
|-->size += PAGE_SIZE;
| 为了安全考虑,多申请了一页的虚拟空间(注意只是虚拟空间).
|
|-->va = alloc_vmap_area(size, align, start, end, node, gpf_mask);
| 从虚拟内存start ~ end中申请一块size大小的虚拟空间,起止地址放在
| vmap_area实例中,并将该vmap_area实例插入到以vmap_area_root.rb_node
| 为根的红黑树中.
|
|-->insert_vmalloc_vm(area, va, flags, caller);
| 将vmap_area实例和vm_struct实例关联起来,并将vm_struct实例插入到
| vmlist链表中.
将vmap_area实例和vm_struct实例关联起来,并将vm_struct实例插入到vmlist链表中.
void insert_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va)
|-->struct vm_struct *tmp, **p;
|
|-->vm->flags = flags;
| vm->addr = (void *)va->va_start;
| vm->size = va->va_end - va->va_start;
| vm->caller = caller;
| va->private = vm;
| va->flags |= VM_VM_AREA;
|
|-->for(p = &vmlist; (tmp = *p) != NULL; p = &tmp->next)
|--{
| if(tmp->addr >= vm->addr) break;
|--}
|
|--vm->next = *p;
| *p = vm;

内存管理 初始化(六)vmalloc_init 及 ioremap的更多相关文章

  1. 内存管理 初始化(八) 至kswapd_init

    至此,内存初始化部分已看完,遗留问题: 1.对于unicore或者mips的页表建立都很清楚,但是对于ARM我不清楚: 初始化部分涉及的页表映射建立,我都以unicore架构为准,ARM的页表映射从原 ...

  2. linux内存管理初始化

    内存管理子系统是linux内核最核心最重要的一部分,内核的其他部分都需要在内存管理子系统的基础上运行.而对其初始化是了解整个内存管理子系统的基础.对相关数据结构的初始化是从全局启动例程start_ke ...

  3. 伙伴系统之避免碎片--Linux内存管理(十六)

    1 前景提要 1.1 碎片化问题 分页与分段 页是信息的物理单位, 分页是为了实现非连续分配, 以便解决内存碎片问题, 或者说分页是由于系统管理的需要. 段是信息的逻辑单位,它含有一组意义相对完整的信 ...

  4. 内存管理 初始化(五)kmem_cache_init 初始化slab分配器(上)

    看了下kmem_cache_init,涉及到不同MIGRATE间的buddy system的迁移,kmem_cache的构建,slab分配器头的构建.buddy system的伙伴拆分. 对于SMP系 ...

  5. 内存管理初始化源码4:add_active_range

    我们在阅读源码时,函数功能可以分为两类:1. bootmem.c 2. page_alloc.c. 1. bootmem.c是关于bootmem allocator的,上篇文章已经简述过. 2. pa ...

  6. 内存管理初始化源码3:bootmem

    start_kernel ——> setup_arch ——> arch_mem_init ——> bootmem_init ——> init_bootmem_node: 此时 ...

  7. 内存管理初始化源码2:setup_arch

    PFN相关宏说明: /* kernel/include/linux/pfn.h */ PFN : Page Frame Number(物理页帧) /* * PFN_ALIGN:返回地址x所在那一页帧的 ...

  8. 内存管理初始化源码1:setup_arch

    源码声明:基于Linux kernel 3.08 1. 在kernel/arch/mips/kernel/head.S中会做一些特定硬件相关的初始化,然后会调用内核启动函数:start_kernel: ...

  9. 内存管理 初始化(二)bootmem位图分配器建立 及 使用

    本地的笔记有点长,先把bootmem位图分配器的建立 及  使用过程做下梳理. 都是代码,上面做了标注.开始的汇编部分省略了(涉及的内容不多,除了swapper_pg_dir的分配). 该记录不会再添 ...

随机推荐

  1. 前端弹窗展示后台html文件

    1,首先使用window.open函数,弹出返回jsp页面的窗口,对应viewZhengXinReport()方法,进行jsp页面的请求跳转forward 2,然后在jsp页面中使用ajax同步请求后 ...

  2. 1:(0or1)

    public class User    {       public int ID { get; set; }       public string UserName { get; set; } ...

  3. WCF数据契约

    当使用DataMember时,和访问符无关,及时使用了private,成员都是可见的.相反如果使用static,为不可见. 上述的两个数据成员是等效的,如果是等效的话 数据成员的顺序也必须是相同的. ...

  4. OCMock 3 参考

    Typorahtml, body {overflow-x: initial !important;}.CodeMirror { height: auto; } .CodeMirror-scroll { ...

  5. Linux shell while

    sh count=1 while [ $count -le 5 ]; do echo 1234567890abcdefghqwertyuiopdasdk > /dev/ttyS1 & e ...

  6. sql临时表,表变量,CTE,游标使用方法

    if OBJECT_ID('groups') is not null drop table groups create table groups ( groupid ), val int null ) ...

  7. c# 读取excel数据的两种方法

    转载自:http://developer.51cto.com/art/201302/380622.htm, 方法一:OleDb: 用这种方法读取Excel速度还是非常的快的,但这种方式读取数据的时候不 ...

  8. EF5.x Code First 一对多关联条件查询,Contains,Any,All

    背景 通过多个部门id获取所有用户,部门和用户是多对多. 已知部门id,获取该部门包括该部门下的所有子部门的所有用户. 关系如下: public class Entity:IEntity { publ ...

  9. print、print_r、echo到底有什么区别?

    echo和print都可以做输出,不同的是,echo不是函数,没有返回值,而print是一个函数有返回值,所以相对而言如果只是输出 echo 会更快,而print_r通常用于打印变量的相关信息,通常在 ...

  10. placeholder兼容IE8解决方案

    1.原因:placeholder是h5的新属性,IE10以前的浏览器(8.9)不支持此属性.   2.解决方法:jQuery三方插件  jquery-placeholder 3.快速开始: <! ...