内存管理 初始化(六)vmalloc_init 及 ioremap
是不是我错了,本想这个函数会如网上所说将进行非连续内存管理的初始化,但是对于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的更多相关文章
- 内存管理 初始化(八) 至kswapd_init
至此,内存初始化部分已看完,遗留问题: 1.对于unicore或者mips的页表建立都很清楚,但是对于ARM我不清楚: 初始化部分涉及的页表映射建立,我都以unicore架构为准,ARM的页表映射从原 ...
- linux内存管理初始化
内存管理子系统是linux内核最核心最重要的一部分,内核的其他部分都需要在内存管理子系统的基础上运行.而对其初始化是了解整个内存管理子系统的基础.对相关数据结构的初始化是从全局启动例程start_ke ...
- 伙伴系统之避免碎片--Linux内存管理(十六)
1 前景提要 1.1 碎片化问题 分页与分段 页是信息的物理单位, 分页是为了实现非连续分配, 以便解决内存碎片问题, 或者说分页是由于系统管理的需要. 段是信息的逻辑单位,它含有一组意义相对完整的信 ...
- 内存管理 初始化(五)kmem_cache_init 初始化slab分配器(上)
看了下kmem_cache_init,涉及到不同MIGRATE间的buddy system的迁移,kmem_cache的构建,slab分配器头的构建.buddy system的伙伴拆分. 对于SMP系 ...
- 内存管理初始化源码4:add_active_range
我们在阅读源码时,函数功能可以分为两类:1. bootmem.c 2. page_alloc.c. 1. bootmem.c是关于bootmem allocator的,上篇文章已经简述过. 2. pa ...
- 内存管理初始化源码3:bootmem
start_kernel ——> setup_arch ——> arch_mem_init ——> bootmem_init ——> init_bootmem_node: 此时 ...
- 内存管理初始化源码2:setup_arch
PFN相关宏说明: /* kernel/include/linux/pfn.h */ PFN : Page Frame Number(物理页帧) /* * PFN_ALIGN:返回地址x所在那一页帧的 ...
- 内存管理初始化源码1:setup_arch
源码声明:基于Linux kernel 3.08 1. 在kernel/arch/mips/kernel/head.S中会做一些特定硬件相关的初始化,然后会调用内核启动函数:start_kernel: ...
- 内存管理 初始化(二)bootmem位图分配器建立 及 使用
本地的笔记有点长,先把bootmem位图分配器的建立 及 使用过程做下梳理. 都是代码,上面做了标注.开始的汇编部分省略了(涉及的内容不多,除了swapper_pg_dir的分配). 该记录不会再添 ...
随机推荐
- thinkphp验证码乱码的解决办法
很有可能是入口文件index.php和.htaccess文件要转换成 以UTF-8无BOM格式编码
- sphinx增量索引和主索引来实现索引的实时更新
项目中文章的信息内容因为持续有新增,而文章总量的基数又比较大,所以做搜索的时候,用了主索引+增量索引这种方式来实现索引的实时更新. 实现原理: 1. 新建一张表,记录一下上一次已经创建好索引的最后一条 ...
- 【MarkdownPad】不能输入表格Table
使用MarkdownPad时,需要制作一个表格.搜到参照这篇文章,发现还是无法显示表格,测试效果是如下这样的: Markdown文本: 显示效果: 谷歌一下,原来是MarkdownPad默认的处理器不 ...
- [code]代码格式1
格式 /********************************************************************************* *Copyright(C), ...
- Java编程的逻辑 (50) - 剖析EnumMap
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- Java编程的逻辑 (30) - 剖析StringBuilder
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...
- log4写完日志不会自动释放
今天想做个日志记录功能.网上查了下.决定使用log4net 来做. 但是最发现在写日志的时候.会一直占用当前的日志文件.当你想查看的时候会提示另一个进程占用了该文件. 只有到他创建下一个日志文件.然后 ...
- 多线程二:线程池(ThreadPool)
在上一篇中我们讲解了多线程的一些基本概念,并举了一些例子,在本章中我们将会讲解线程池:ThreadPool. 在开始讲解ThreadPool之前,我们先用下面的例子来回顾一下以前讲过的Thread. ...
- HashTable和HashMap的区别详解
一.HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长. HashMap是非线程安全的, ...
- postgresql远程连接中断的处理
在网络上连接远程服务器postgresql时,不活动时间稍长就会自动断开连接,不利于操作. 琢磨了一下,服务器上使用以下网络配置时,解决了这个问题. #man 7 tcp net.ipv4.t ...