初级内存管理单元

关于内存的分页

  • 以往的物理页是按照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架构下的内核初始化内存管理的更多相关文章

  1. 启动期间的内存管理之bootmem_init初始化内存管理–Linux内存管理(十二)

    1. 启动过程中的内存初始化 首先我们来看看start_kernel是如何初始化系统的, start_kerne定义在init/main.c?v=4.7, line 479 其代码很复杂, 我们只截取 ...

  2. Linux内核笔记--内存管理之用户态进程内存分配

    内核版本:linux-2.6.11 Linux在加载一个可执行程序的时候做了种种复杂的工作,内存分配是其中非常重要的一环,作为一个linux程序员必然会想要知道这个过程到底是怎么样的,内核源码会告诉你 ...

  3. 24小时学通Linux内核之内存管理方式

    昨天分析的进程的代码让自己还在头昏目眩,脑子中这几天都是关于Linux内核的,对于自己出现的一些问题我会继续改正,希望和大家好好分享,共同进步.今天将会讲诉Linux如何追踪和管理用户空间进程的可用内 ...

  4. Linux内核之内存管理

    Linux内核之内存管理 Linux利用的是分段+分页单元把逻辑地址转换为物理地址; RAM的某些部分永久地分配给内核, 并用来存放内核代码以及静态内核数据结构; RAM的其余部分称动态内存(dyna ...

  5. ARC下需要注意的内存管理

    ARC下需要注意的内存管理 2016/04/03 · iOS开发 · 内存管理 分享到:1 原文出处: 一不(@luoyibu)    之前发了一篇关于图片加载优化的文章,还是引起很多人关注的,不过也 ...

  6. Linux内核之内存管理完全剖析

    linux虚拟内存管理功能 ? 大地址空间:? 进程保护:? 内存映射:? 公平的物理内存分配:? 共享虚拟内存.实现结构剖析   (1)内存映射模块(mmap):负责把磁盘文件的逻辑地址映射到虚拟地 ...

  7. Linux内核之 内存管理

    前面几篇介绍了进程的一些知识,从这篇开始介绍内存.文件.IO等知识,发现更不好写哈哈.但还是有必要记录下自己的所学所思.供后续翻阅,同时写作也是一个巩固的过程. 这些知识以前有文档涉及过,但是角度不同 ...

  8. PHP内核研究(内存管理1)

    PHP内存管理 PHP在5.3之前采用的是引用计数法 PHP在5.3之后采用了新的垃圾回收机制 操作系统在申请内存空间的时候回引发系统调用 在操作系统申请内存空间的时候,会将CPU从用户态切换到内核态 ...

  9. windows内核驱动内存管理之Lookaside使用

    Windows内存管理中使用了类似于容器的东西,叫做Lookaside对象,每次程序员申请内存都会从Lookaside里面申请,只有不足的时候,Lookaside才会向内存又一次申请内存空间,这样减少 ...

随机推荐

  1. 混合APP开发-hybrid 升级流程

    本文来自网易云社区 作者:王贝 目前大多数APP已经应用hybrid进混合开发,这不,我们的gacha APP这个版本已经开始使用hybrid来开发了,hybrid的优势这里就不多说了,这里主要讲一下 ...

  2. java中计算一段时间内白天的时间和夜晚的时间

    之前,采用拼接字符串的形式,不断地在Date类型和Long类型之间转换,实在是太过于麻烦,后来采取了这种思路:假设我们将22:00 ~ 10:00 视为夜间时间,则我们先计算出10:00 相对于当天的 ...

  3. 启动HBase脚本start-hbase.sh时报Class path contains multiple SLF4J bindings.解决方法

    1. 使用start-hbase.sh启动HBase时报Class path contains multiple SLF4J bindings.错误,原因是jar包冲突导致的.所以,对于和Hadoop ...

  4. 1、OpenCV Python 图像加载和保存

    __author__ = "WSX" import cv2 as cv # 这里的文件是图片或者视频 def Save_File( image ): cv.imwrite(&quo ...

  5. linux 内核的 switch_to原理

    switch_to:这是一个宏,有三个参数prev,next,last 局部变量prev,next:指向进程描述符的内存地址 首先明确的是:last和prev是同一个,用last只是为了理解方便,完全 ...

  6. [SCOI2007]蜥蜴 BZOJ1066 最大流

    题目背景 07四川省选 题目描述 在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外. 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴 ...

  7. opencv-图片合成视频

    无论视频的合成还是分解我们都需要进行解码器或者是编码器(因为视频不是一帧一帧进行存储的,而是进行过压缩编码.) import cv2 img = cv2.imread('image1.jpg') im ...

  8. Android layout布局属性、标签属性总结大全

    RelativeLayout 第一类:属性值为true可false android:layout_centerHrizontal        水平居中 android:layout_centerVe ...

  9. Oracle redo undo

    通常对undo有一个误解,认为undo用于数据库物理地恢复到执行语句或事务之前的样子,但实际上并非如此.数据库只是逻辑地恢复到原来的样子,所有修改都被逻辑地取消,但是数据结构以及数据库块本身在回滚后可 ...

  10. linux 中iscsi服务

      ###############第一步: 创建一个2G的分区第二步: yum install targetcli -y 第三步:创建一个2G的分区,并同步  第四步:  执行tagetclils查看 ...