IA-32e架构下的内核初始化内存管理
初级内存管理单元
关于内存的分页
- 以往的物理页是按照4KB进行分配和管理的, 而在Linux之后流行的就是2MB大小的物理页的分配和管理, 整个物理内存管理单元也是2MB物理页管理的
先获取基本的物理地址空间信息
- 在bootloader程序中, 已经调用了BIOS的int 15h中断将物理内存地址的结构体放置到了1MB之下的物理地址0x7e00处, 我们需要将其提取出来
- 每一条物理空间信息BIOS加载到内存时20B, 因此我们要获取该数据, 也需要定义一个结构体也占用20B的物理内存大小, 获取0x7e00地址上的数据, 但是在IA-32e模式下, 我们能够使用的是线性地址, 不能直接访问物理地址, 访问物理地址需要通过我们已经在head.S程序中定义好的页表进行页的映射, 在head.S中我们只进行了10MB的映射, 这对于我们目前来说已经足够了, 不过我们还是要知道物理地址0对应的线性地址时多少, 这样我们才能进行编码
- 物理地址空间的大小为32个, 我们一开始先打印出这些信息, 输出物理内存哪些是可用的(type == 1), 如果多了脏数据(type > 4)证明这个地方的数据经不明数据污染了, 也就是说有数据将BIOS写到0x7e00地址上的数据覆盖了, 那我们就不要在读取了, 因为已经是错误的了, 没有意义了, 打印出来我们总共可用的内存大小
在分配可用物理页之前先获取可用物理页的页数
- 在这个部分, 我们需要对复制BIOS的全部物理地址空间信息到一个memory_management_struct中, 这个结构体就是我们内存管理的核心, 它保存着所有的内存页的信息, 包括不可用的
- 接下来我们计算出可用的物理内存页数, 获取一个可用的物理内存段之后, 我们对其起始地址尽心2MB的物理页的对齐, 返回的就是对齐后的物理地址, 接着计算出这个物理内存段的结束地址end, (end - start) >> page_2m_shift 计算出在这个物理段中有几个物理页, 也就一个分隔游戏, start就是对齐之后的物理地址, 在操作系统中一般有两个可用的物理地址段, 即为A和B, 他们一般不在一起, 第一个就是从我们的物理地址0开始的物理内存段, 显然我们的bootloader和内核代码都在这里, 这里肯定是可用的物理内存, 其实地址就是0, 对齐后的地址也是0, 因为2MB对齐就是将我们所有的内存分成一个一个的2MB, 但是另外一个可用的物理地址段它的start地址就不一定就是在一个矩形的2MB的起始位置了, 也就是说地址不对齐了, 这个时候我们就需要进行物理地址的对齐, 一般来说经过运算后, 我们原来的物理地址start的物理地址会增加一点到一个2MB的起始地址, 虽然这样会浪费一小段可用的物理地址空间, 但是我们完成了2MB的分隔, 更加方便我们的管理
分配可用物理内存页
需要用到的逻辑上的结构体
- struct page --> 代表的就是我们说的2MB的物理页, 但是它本身不是2MB, 而是他管理的物理内存时2MB的, 这里所谓的管理就是通过属性保存地址, phyaddr就是管理的物理页的物理起始地址
- struct zone --> 区域空间结构体, 它与page联系紧密, 它标志一个可用物理地址段, 就是我们在上面讲到了两个可用的物理地址段, 他代表着一个段, 怎么代表的呢, 也是通过属性startaddr和endaddr, startaddr保存着一个可用物理内存段的起始地址, endaddr保存着一个可用物理内存段的结束地址, 我们已经知道另一个一个物理段是很大的, 有多个2MB的物理页, 因此这里的endaddr - startadd的值也大于2MB, 所以会有多个page结构体引用着一个zone, 用来在逻辑层面上模拟分配一个页
- 上面已经提到过的memory_management_struct(在后面简称为mm), 他包含了从BIOS获取的物理地址信息, bitsmap(就是一个整数, 和ext3文件系统一样一样的)用来方便索引空闲的物理页page, 一个page结构体数组(在逻辑上属于zone), 一个zone结构体数组, 内核代码结束位置, 自己的结束位置,注意page和zone结构体分配在了内核代码之后, zone在page之后
开始分配可用物理内存页(类似与Python中的__new__()魔法方法的功能, 但是与Java中的new关键字的功能不同, 这里只是为page和zone结构体分配了内存, 这里到处了实质: 可用物理页的分配就是在为结构体创建内存空间, 但是不进行初始化)
初始化bitmap
- mm.bits_size属性赋值为我们之前计算出来的可用物理内存页的个数, 这样才能确定bitmap的大小
- 将bitmap的值置为0, 虽然在这个时候我们的内核代码已经在内存中了, 我们理应将对应的bitmap中的一个位置位, 但是我们现在的内存管理的数据结构体还不完善, 所以我们将这个往后推
初始化page struct结构体数组
- mm.pages_size等都记录下来, page结构体采用的4K物理页的对齐方式, 反正这些元数据结构体会比较特殊
- 分配内存空间, 将所有的值初始化为0
初始化zone 结构体数组
- 分配内存空间, 将所有的值初始化为0
第二次初始化(此时数据结构体的内存大致已经分配好了, 就是属性需要进行赋值, 类似于Python中的__init__()方法)
- 先为zone结构体进行属性的初始化, 从mm中的bios的物理地址空间信息中读取 type == 1的地址, 对齐, 赋值该zone的start, end和上面的一样计算, 这样一个物理段就初始化完毕了, 此时在这个物理段zone的基础上初始上page的属性(但是这里的zone和page, 并不是所有的属性都被初始化了, 有一些需要在函数page_init中进行初始化), 我们知道page都是属于zone的, 通过循环将zone所代表的物理段分成多个2MB大小的物理页, 当然是使用page结构体的phyaddr和length来表示了, 接着这样page指向该zone, 表示page的所属是谁
现在我们也为page和zone的属性都赋值了, 现在我们就要通过一个page_init函数来初始化内核代码所在的内存, 还记得上面提到了在初始化bitmap的时候, 我说过的要将这个事情往后推吗!
在初始化内存的时候, page的属性refcount++, page指向的zone的freepages--, pageusing++, 并且置位bitmap表示已用
内存管理需要的东西完成了, 下面就是通过一个函数接口来通过访问这里的内存管理机制分配到内存了
通过alloc_pages函数返回一个struct page数组内核层和应用层使用
- 判断向内存中的哪个区域要物理页
- 通过bitmap找到指定连续数量的未被使用的位, 通过该位计算得出这个page数组的首地址, 将连续的page数据返回, 同时标志bitmap对应的位已用
IA-32e架构下的内核初始化内存管理的更多相关文章
- 启动期间的内存管理之bootmem_init初始化内存管理–Linux内存管理(十二)
1. 启动过程中的内存初始化 首先我们来看看start_kernel是如何初始化系统的, start_kerne定义在init/main.c?v=4.7, line 479 其代码很复杂, 我们只截取 ...
- Linux内核笔记--内存管理之用户态进程内存分配
内核版本:linux-2.6.11 Linux在加载一个可执行程序的时候做了种种复杂的工作,内存分配是其中非常重要的一环,作为一个linux程序员必然会想要知道这个过程到底是怎么样的,内核源码会告诉你 ...
- 24小时学通Linux内核之内存管理方式
昨天分析的进程的代码让自己还在头昏目眩,脑子中这几天都是关于Linux内核的,对于自己出现的一些问题我会继续改正,希望和大家好好分享,共同进步.今天将会讲诉Linux如何追踪和管理用户空间进程的可用内 ...
- Linux内核之内存管理
Linux内核之内存管理 Linux利用的是分段+分页单元把逻辑地址转换为物理地址; RAM的某些部分永久地分配给内核, 并用来存放内核代码以及静态内核数据结构; RAM的其余部分称动态内存(dyna ...
- ARC下需要注意的内存管理
ARC下需要注意的内存管理 2016/04/03 · iOS开发 · 内存管理 分享到:1 原文出处: 一不(@luoyibu) 之前发了一篇关于图片加载优化的文章,还是引起很多人关注的,不过也 ...
- Linux内核之内存管理完全剖析
linux虚拟内存管理功能 ? 大地址空间:? 进程保护:? 内存映射:? 公平的物理内存分配:? 共享虚拟内存.实现结构剖析 (1)内存映射模块(mmap):负责把磁盘文件的逻辑地址映射到虚拟地 ...
- Linux内核之 内存管理
前面几篇介绍了进程的一些知识,从这篇开始介绍内存.文件.IO等知识,发现更不好写哈哈.但还是有必要记录下自己的所学所思.供后续翻阅,同时写作也是一个巩固的过程. 这些知识以前有文档涉及过,但是角度不同 ...
- PHP内核研究(内存管理1)
PHP内存管理 PHP在5.3之前采用的是引用计数法 PHP在5.3之后采用了新的垃圾回收机制 操作系统在申请内存空间的时候回引发系统调用 在操作系统申请内存空间的时候,会将CPU从用户态切换到内核态 ...
- windows内核驱动内存管理之Lookaside使用
Windows内存管理中使用了类似于容器的东西,叫做Lookaside对象,每次程序员申请内存都会从Lookaside里面申请,只有不足的时候,Lookaside才会向内存又一次申请内存空间,这样减少 ...
随机推荐
- eval实例
.... var sel_MedicineType = 'sel_MedicineType' + lastIndex; eval(sel_MedicineType + "= new C_Se ...
- 判断本地是否存在Jquery文件,如果不存在则使用CDN加速的Jquery文件
<script>//判断是否成功将Jquery库引入,如果没有成功引入则引入本地Jquery库if (typeof jQuery == 'undefined') {document.wri ...
- Mybatis基于代理Dao实现CRUD操作 及 Mybatis的参数深入
Mybatis基于代理Dao实现CRUD操作 使用要求: 1.持久层接口和持久层接口的映射配置必须在相同的包下 2.持久层映射配置中mapper标签的namespace属性取值必须是持久层接口的全限定 ...
- Educational Codeforces Round 60 (Rated for Div. 2)D(思维,DP,快速幂)
#include <bits/stdc++.h>using namespace std;const long long mod = 1e9+7;unordered_map<long ...
- [MOOC程序设计与算法二] 递归二
1.表达式计算 输入为四则运算表达式,仅由整数.+.-.* ./ .(.) 组成,没有空格,要求求其值.假设运算符结果都是整数 ."/"结果也是整数 表达式也是递归的定义: 表达式 ...
- Java框架之搭建环境maven报错
*maven Dependencies 中的地址通过POM 才会增加 正确是 1. m2所在位置 遇到的问题: java.lang.ClassNotFoundException: org.spring ...
- (multi)set的某些操作
(multi)set的某些操作 我们可以把multiset当作平衡树用~ 注意,必须定义小于运算符. s.begin() 返回指向第一个元素的迭代器. s.end() 返回指向最后元素的后面那个虚拟元 ...
- 洛谷P2526 [SHOI2001]小狗散步(二分图匹配)
题目背景 Grant喜欢带着他的小狗Pandog散步.Grant以一定的速度沿着固定路线走,该路线可能自交.Pandog喜欢游览沿途的景点,不过会在给定的N个点和主人相遇.小狗和主人同时从(X1,Y1 ...
- HackerRank - array-partition 并查集
https://vjudge.net/contest/279745#problem/G 每次将质数的倍数放进一个集合中,那么如果最后的集合数为n的话: 方案数: 2^n -2 : #include&l ...
- SQL 模糊查询 可以正则匹配 (转)
1. % 表示任意0个或多个字符.如下语句:Select * FROM user Where name LIKE '%三%'; 将会把name为“张三”,“三脚猫”,“唐三藏”等等有“三”的全找出来. ...