首页 > 系统相关 >操作系统-内存管理-内存读取

操作系统-内存管理-内存读取

时间:2023-01-05 10:12:30浏览次数:59  
标签:操作系统 中断 memblock BIOS 内存 memory 读取

文章大部分表述图片来自 : https://www.jeanleo.com/2021/07/06/linux内存管理剖析/ 。 非原创

内存是如何给读取的

    计算机上电启动的时候,BIOS会检测并计算物理内存大小。比方说现在通用的内存都是DIMM针脚插槽类型的,它的PIN针脚有两百多个,各个针脚各有自己的定义,BIOS就是通过对不同针脚的高低电平设置,由内存反馈其规格信息给BIOS,然后BIOS计算出容量。大概原理就这样了。但是我们重点是操作系统需要感知主机的内存空间,它是怎么知道的呢?它是通过BIOS提供的接口去询问出来的。这个接口就是0x15中断,其中参数重点参数是ax寄存器中需要设置值e820。然后通过intcall(0x15, &ireg, &oreg)中断调用,由BIOS通过oreg.di出参将内存信息返回回来。该实现在/arch/x86/boot/memory.c中的detect_memory,由于代码出参oreg.di也是ireg.di传进去的值,所以代码里面直接读了buf空间内存。由于每调用一次intcall只会返回一条内存数据信息,所以会循环调用多次才能够探明整个内存空间。

1297993-20211114115224453-86847209.png

也就是说 操作系统 --> BIOS中断 中断来感知内存空间的,这个0x15是一个中断号 ,定义在中断表述表,而这个中断表又是从哪里来的呢?我们在上篇文章 里写道加载 BIOS 的环节会加载中断表。

    计算机刚开机的时候只有1M的内存可以使用。 此时内存会被各种外设瓜分,映射在内存的相应区域。同理,BIOS里的信息会被映射到内存的一段连续的区域中(0xC0000–0xFFFFF),其中最为关键的系统BIOS被映射到了0xF0000–0xFFFFF位置,CPU开机就是执行了系统BIOS这块内存区域中的代码,注意BIOS中的程序还会占用内存开头的一些区域,如把中断向量表写在了内存开始的位置。

    在开机的一瞬间,CPU中的PC寄存器被强制初始化为0xFFFF0。BIOS程序的入口地址就是0xFFFF0,然后CPU就开始跑起来,执行BIOS中的程序。

中断0x15有三个子功能,子功能号放到EAX或者AX中,其简要说明:

  • EAX = 0xE820 遍历所有内存
  • AX = 0xE801 分别检测低 15 MB 和 16 MB ~ 4 GB的内存,最大支持 4 GB。
  • AX = 0x88 最简单的子功能,只能检测64MB的内存,若超过也只返回 64 MB。

具体的子功能讲解见这篇文章

内存由谁来读取

    内存探测必然是kernel吗?答案是否定的。先说一下kernel的binary文件吧,它通常放在/boot/下面,名字通常命名为vmlinuz。这个文件是由setup.bin和vmlinux构造而成,其中vmlinux又由kernel编译目录arch/x86/boot/compressed下的cmdline.o、head.o、kaslr.o等连同压缩后的vmlinux.bin.gz合并构成。其中检测内存的detect_memory()函数就是在setup.bin里面,但是这仅限于Grub legacy(即Grup 0.97到1.97版本)引导kernel的时候,setup.bin才会被执行到,也就是仅在该情况下内存探测才是由kernel引导的领头羊去完成的。
    
    到了Grub2(即Grub 1.98到现在最新版本)引导linux系统的时候,则由Grub直接探明内存布局,然后解析vmlinuz文件,并且直接加载vmlinux部分的内容到内存中并跳转执行head_32函数,而内存布局则通过参数boot_params传递执行。
    
    谁探明内存布局对内存管理有影响吗?没影响的,所以这里是可以忽略的废话。既然废话就多说两句,为什么要分开setup.bin和vmlinux呢?这是因为setup.bin运行在实模式下面,而vmlinux则运行在保护模式下面。所以也就是说grub2是进入了保护模式后才加载引导的kernel。

1297993-20211114121928779-829326418.png

我们从上面的描述中知道了,内存读取这个动作发起人,不一定是内核,以现在GRUB作为操作系统引导程序来说,内存读取这个动作是由GRUB来发起触发BISO中断,进行内存探测的,这其中讲到实模式和保护模式,我们后续会讲到 。

内存读取以后

管理-探知的e820表如何处理?是如何被管理的

    前面已经知道了如何探明内存空间得到e820图,得知了内存的位置、大小和类型。在e820__memory_setup()函数内会将重叠的内存空间根据属性进行筛选,并将同属性的相邻内存空间进行合并处理。整个处理过程如右侧所示,虽然实现上会对内存进行分割合并处理,但是实际上内存并不会这么错乱重叠的。处理完毕后,会通过e820__print_table()对外打印。通过dmesg可以看到如图左侧所示的信息。

1297993-20211115224925206-612173490.png

那么是如何分割和合并的呢? 可以看到重叠的部分就会合并,而分散的部分则是合并 ,

使用-内存(指被 Memblock 管理的内存)划分分配

    内存是连续的吗?

    物理内存是连续的,但是细心的话,可以发现e820提供的数据中并不连续,中间0xA0000到0xFFFFF的内存并未在其中。这是历史原因遗留下来的,它并非不存在,而是被BIOS保留下来用作显卡显存的映射以及BIOS自留给ROM使用的空间。所以呈现出来有一个空洞位置。


    对此我们可以通过/proc/iomem查看到这些物理内存被如何划分分配。iomem主要呈现系统中设备的物理布局,包括未被e820所呈现的,它甚至能够将kernel在物理内存的加载位置呈现出来。

1297993-20211115231800698-890452300.png

我们这里就可以知道 dmesg 命令看到的是计算机开始探测到的内存空间 ,而 cat /proc/iomem 则是BIOS虚拟地址在物理内存上的一个映射可以看见貌似只使用了 1MB 的空间 ,关于着 1MB 的相关知识点见 A20

那么 Memblock 上的内存 又是如何被分配出去的呢 ? Memblock 内存维护着两个 struct :

  • memory : 指向系统可用物理内存区

  • reserved : 指向系统预留区 (就是给分配出去了)

      memblock管理表由命名为memblock的全局数据结构变量管理,它主要通过可用内存memory和保留内存reserved两个成员结构体变量区分管理。
      
      例如可用内存全部都挂入到memblock.memory.regions下,该可用内存同时又以全局变量数组memblock_memory_init_regions而命名,该数组成员主要记录内存的基址、大小和类型,如图显示的是该算法的管理结构关系。类似的被保留的内存则在memblock_reserved_init_regions全局数组结构下管理。
      
      于此阶段,我们可以通过memblock_alloc()和memblock_free()对内存进行申请释放,而分配的方式很简单,根据需要分配的size到可用的内存空间memblock_memory_init_regions中去查找连续的等大小空间,然后将其分割开来,将分配出去的挂入到memblock_reserved_init_regions管理区中,而剩余的则放回到memblock_memory_init_regions。尤其是如果我们需要申请永久保留的内存可在此申请,即后续内存管理将不会对此内存进行分配回收管理。
      
      memblock内存管理只是一个过渡形态,不会长期存在,毕竟如此任意分割内存的分配方式长久运行后会导致严重的碎片化。因此后面将会建立内存映射,构造内存管理框架。
    

来自参考资料中的描述我们知道此阶段的内存分配非常简单,就是在两个数组里任意分配,有可能会造成内存碎片化, 但是此时分配的内存是给什么的呢?上面分配的内存就是给上图用的。

具体相关的底层逻辑见 :

1297993-20211115233213443-178650984.png

1297993-20211115233237146-788941172.png

1297993-20211115233300536-4434451.png

读取的内存将会如何管理, 给谁管理

查看读取出来的内存够空间

Linux dmesg 命令, kernel 会将开机信息存储在 ring buffer 中。您若是开机时来不及查看信息,可利用 dmesg 来查看。开机信息亦保存在 /var/log 目录中,名称为 dmesg 的文件里。
命令 :

 dmesg | less

1297993-20211115224016170-839141824.png

查看虚拟地的映射的分布

cat /proc/iomem

1297993-20211115224303385-779752500.png

虚拟地址映射的内容

其他

中断

关于“中断”,参考资料中有篇文章有详细介绍到。
中断,英文名为Interrupt,计算机的世界里处处都有中断,任何工作都离不开中断,可以说整个计算机系统就是由中断来驱动的。那么什么是中断?简单来说就是CPU停下当前的工作任务,去处理其他事情,处理完后回来继续执行刚才的任务,这一过程便是中断。

两张图可以知道中断的类型

1297993-20211114120844382-1583466236.jpg

总结

这一节主要是讲介绍物理内存空间是如何被读取出来的,然后读取出来以后又是如何被管理和分配的,其中涉及到 BIOS 的相关知识点,比如 BIOS 中断调用,还有包括memblock 这个结构去管理内存的,在 使用-内存(指被 Memblock 管理的内存)划分分配 章节我们也知道了BIOS 在 memblock 上申请了 1MB 的空间来映射一些内容,包括 BIOS 映射区, DOS 暂存区等 。

最后我们还介绍了两个查看内存相关的方式 ,一个是查看物理空间被读取出来后的内存全貌,一个是虚拟地址上的内存分布, 各个位置放着什么东西 。

参考资料

标签:操作系统,中断,memblock,BIOS,内存,memory,读取
From: https://www.cnblogs.com/Benjious/p/17026769.html

相关文章

  • 软件开发入门教程网 Search之C++ 动态内存
       C++基本的输入输出   ......
  • Linux 内存问题
    Linux内存问题1 内存使用率过高现象描述Linux云服务器实例出现由内存问题引发的故障。例如,系统内部服务响应速度变慢、服务器登录不上、系统触发OOM(OutOfMemory)等......
  • 操作系统-IA32的地址转换
    概述该篇介绍的是IA-32/Linux中的地址转换,转化的动机是什么?是如何转化的?下文的段描述符和描述符表太难理解,可以近似认为段描述符=段表项,描述符表=......
  • 基于不同操作系统升级知行之桥的常见问题
    此前的文章知行之桥2022版本升级之页面变化以及监控邮件答疑给大家分享了一些升级到知行之桥最新版本关于Web页面显示和监控邮件的一些问题,本篇将分享一些windows和Linux不......
  • 关于asan内存检测工具的原理和使用
    Hello,各位看官好,小弟的公司最近开始使用asan这个工具了,最近在晚上查了一下,不查不知道,一查吓一跳,这个工具真的是神一般的工具,所以我就花了一点时间整理了一下asan工具的......
  • 使用Jmeter读取和使用Redis数据
    前言消息队列和缓存是目前主流的中间件,我们在日常测试过程中,无论是接口还是压力测试,都会遇到需要处理这些中间件数据的情况。本文以Redis对缓存做一个简单的介绍,并基于Jme......
  • FreeSWITCH无法读取wav文件
    错误日志如下:190032016-10-0613:18:27.223464[ERR]switch_core_file.c:260Invalidfileformat[wav]for[/usr/local/freeswitch/sounds/music/8000/suite-espan......
  • 如何获取 Android 设备的CPU核数、时钟频率以及内存大小
    因项目需要,分析了一下Facebook的开源项目-​​DeviceYearClass​​。DeviceYearClass的主要功能是根据CPU核数、时钟频率以及内存大小对设备进行分级。代码很......
  • 异构操作系统的“融合计算”
    近些年,由随着应用场景日益丰富和多样化,计算工作越来越复杂,传统的计算方式(单机计算/分布式计算)已经不能满足,需要一种新的更强大的计算模式来解决这些问题,这是融合计算产生的......
  • Spark生态之Alluxio学习25--spark从HDFS和Alluxio读取时间比较
    更多代码请见:​​https://github.com/xubo245/SparkLearning​​Spark生态之Alluxio学习版本:alluxio-1.3.0(tachyon),spark-1.5.2,hadoop-2.6.01.解释想要分析alluxio加速效果......