首页 > 系统相关 >深入理解Linux内核——内存管理(1)

深入理解Linux内核——内存管理(1)

时间:2023-08-08 17:13:04浏览次数:50  
标签:GDT 寄存器 描述符 地址 选择符 内存 Linux 内核

提要:系列文章主要参考MIT 6.828课程以及两本书籍《深入理解Linux内核》``《深入Linux内核架构》对Linux内核内容进行总结。

内存管理的实现覆盖了多个领域:

  1. 内存中的物理内存页的管理
  2. 分配戴爱内存的伙伴系统
  3. 分配较小内存的slab、slub、slob分配器
  4. 分配非连续内存块的vmalloc分配器
  5. 进程的地址空间

传统的内存管理主要包括段式存储页式存储段页式存储,这里我们会以这部分开始,逐步介绍Linux内核中的内存管理,而要学习内存管理,首先需要了解内存寻址。所以本节内容主要讲解内存寻址的相关知识,并介绍Linux内核中的段、页式存储。

内存地址

在编程过程中,难免需要通过内存地址来访问内存中的某些内容,那么这个过程中地址是如何映射到对应的物理单元的呢?解决这一问题首先要区分三种不同的地址:

  1. 逻辑地址:逻辑地址是包含在机器语言指令中用来指定一个操作数或者一条指令的地址。每一个逻辑地址都由一个段和一个偏移量组成,偏移量指明了从段开始的地方到实际地址之间的距离。(这在分段结构中表现的极为明显)。
  2. 线性地址:线性地址是一个32位的无符号数,可以用来表示高达4GB的地址。线性地址通常使用十六进制数字表示,值的范围从0x00000000到0xffffffff(常用于页式存储)。
  3. 物理地址:用于内存芯片级内存单元寻址。它们与微处理器的地址引脚发送到内存总线上的电信号相对应。物理地址由32位或36位无符号整数表示。

内存控制单元(MMU)通过分段单元(硬件设备)将逻辑地址转化为线性地址。使用分页单元(硬件设备)把线性地址转化为物理地址:

               --------                     -------
|逻辑地址| --> |分段单元| --> |线性地址| --> |分页单元| --> |物理地址|
               --------                     -------

从格式上简单区别逻辑地址与线性地址,逻辑地址包含了两部分:段和偏移量(注意这两者是分开的),而线性地址知识一个32位无符号数,虽然后期也会根据地址的位数再次进行划分(详见分页部分),但终归只是一个线性的无符号数。

段式存储

硬件将逻辑地址转化为线性地址主要由分段单元完成该任务。逻辑地址由两部分组成:

  1. 段标识符:该字段是一个16位长的字段,称为段选择符负责从众多段中选择出正确的段,因为段信息会存储在一张段描述符表中,因此需要通过段选择符从段描述符表中索引找到正确的段描述符
  2. 指定段内相对地址的偏移量:32位长的字段(因为一个段可能很长,因此偏移量要足够大)

段选择符格式如下:

        15        3     2 1 0
          --------  ----  ---
段选择符 |  index  |  TL | RPL|
          --------  ----  ---

对于每个字段的含义,后续在详细讲解通过段选择符寻找对应段时会对每个字段给出解释。

段选择符被存放在段寄存器中,这使得可以方便快速地找到段选择符,段寄存器主要包括6个,分别为cs,ss,ds,es,fs,gs。其中有3个具有专门的用途:

段寄存器 描述
cs 代码段寄存器,指向包含指令序列的段
ss 栈段寄存器,指向包含当前程序栈的段
ds 数据段寄存器,指向包含静态数据或者全局数据段

其他3个段寄存器作一般用途,可以指向任意的数据段。

注意:cs寄存器还有一个很重要的功能:它含有一个两位的字段,用以指明CPU的当前特权级(GPL)。值为0代表最高优先级,而值为3代表最低优先级。Linux只用0级和3级,分别称为内核态和用户态。

段描述符

刚才提到过,每个段由一个8字节的段描述符表示,它描述了段的特征。段描述符放在全局描述符表(GDT)或者局部描述符表里(LDT)中(前面提到过)。通常只定义一个GDT,而每个进程除了存放在GDT中的段之外如果还需要创建附加段,就会创建自己的LDT。GDT在主存中的地址和大小存放在gdtr控制寄存器中,当前正被使用的LDT地址和大小存放在ldtr寄存器中。如下给出一个全局段描述符例子:

在段描述符表中通常会使用如下几种段描述符(简单了解各个段的作用即下面第一个表就好,具体字段的名称可以用到再回来查):

描述符名称 描述
代码段描述符 这个段描述符代表一个代码段,它可以放在GDT或LDT中。该描述符置S标志位1(非系统段)
数据段描述符 这个段描述符代表一个数据段,它可以放在GDT或LDT中。该描述符置S标志为1。栈段是通过一般的数据段实现的。
任务状态段描述符(TSSD) 这个段描述符代表一个任务状态段(Task State Segment, TSS),也就是说这个段用于保存处理器寄存器的内容。它只能出现在GDT中。根据相应的进程是否正在CPU上运行,其Type字段的值分别为11或9。这个描述符的S标志置为0。
局部描述符表描述符(LDTD) 这个段描述符代表一个包含LDT的段,它只出现在GDT中。相应的Type字段的值为2,s标志置为0

段描述符格式如下:

段描述符中各个字段含义如下:

字段表 描述
Base 包含段的首字节的线性地址
G 粒度标志:如果该位清0,则段大小以字节为单位,否则以4096的倍数计
Limit 存放段中最后一个内存单元的偏移量,从而决定段的长度。如果G被置为0,则一个段的大小在1个字节到1MB之间变化;否则,则在4KB到4GB之间变化。
S 系统标志:如果它被清0,则这是一个系统段,存储诸如LDT这种关键的数据结构,否则它是一个普通的代码段或者数据段。
Type 描述了段的类型特征和他的存取权限
DPL 描述符特权级(Descriptor Privilege Level)字段:用于限制对这个段的存取。它表示为访问这个段而要求的CPU最小的优先级。因此,DPL设为0的段只能当CPL为0时(即在内核态)才是可以访问的,而DPL设为3的段对任何CPL值都是可以访问的。
P Segment-Present标志:等于0表示段当前不在主存中。Linux总是把这个标志(第47位)设为1,因为它从来不把整个段交换到磁盘上去。
D或B 成为D或B的标志,取决于是代码段还是数据段。D或B的含义在两种情况下稍微有区别,但是如果段偏移量的地址是32位长,就基本上把它置为1,如果这个偏移量是16位长,它被清0。
AVL标志 可以由操作系统使用,但是被Linux忽略

快速访问段描述符

在本节主要介绍分段单元将逻辑地址转化为线性地址的过程。我们知道逻辑地址主要包括:16位的段选择符和32位的段偏移量,段选择符存放在段寄存器中。段选择符格式如下:

        15        3     2 1 0
          --------  ----  ---
段选择符 |  index  |  TL | RPL|
          --------  ----  ---

这里我们需要了解3个字段的含义:

字段名 描述
index 指定了放在GDT或者LDT中相应的段描述符的入口
TI TI(Table Indicator)标志:指明段描述符是在GDT中(TI = 0)或在LDT中(TI=1)
RPL 请求者特权级:当相应的段选择符装入到cs寄存器中时指示出CPU当前的特权级;它还可以用于在访问数据段时有选择地削弱处理器的特权级。

由于一个段描述符是8个字节长,因此它在GDT或LDT内的相对地址是由段选择符的最高13位的值乘以8得到的(8=2^3,13+3=16)。例如如果GDT在0x00020000(这个值保存在gdtr寄存器中),切由段选择符所指定的索引号为2,那么相应的段描述符地址为0x00020000+(2*8)0x00020010

逻辑地址转换规则如下图:

标签:GDT,寄存器,描述符,地址,选择符,内存,Linux,内核
From: https://www.cnblogs.com/yanlishao/p/17613495.html

相关文章

  • linux学习,模拟资源占用
    公司有一些云服务器,在华为云上,很多云服务器资源占用率不高,处于空闲状态。我担心领导检测到这些资源空闲的云服务器,会要求我们降低配置,同时会降低云服务器的采购预算。所以就想写一个shell脚本,模拟资源占用思路使用stress对内存进行压测,占用剩余内存的80%,可以模拟CPU和内存消耗使用d......
  • Linux防火墙firewalld&iptables(2)iptables开放指定端口开放指定端口
    一、CentOs6iptables基本操作#chkconfig--list|grepiptables 查看防火墙的服务#chkconfigiptablesoff 永久关闭防火墙#chkconfigiptableson 永久开启防火墙#servicestatusiptables 查看防火墙状态#servicestartiptables 启动防火墙#servicestopiptab......
  • uboot跳转内核
    记录uboot转到内核时相关的指令:setenvset_ubi'setmtdidsnand0=nand0;setmtdpartsmtdparts=nand0:0x7680000@0x900000(fs);ubipartfs'setenvbootkernel'ubiread0x84000000kernel&&bootm'setenvbootargs'ubi.mtd=ubiroot=/dev/ub......
  • linux安装Jenkins
    Jenkins简介Jenkins是⼀个基于Java语言编写的开源持续集成工具,可⽤于⾃动化与构建、测试、交付或部署软件相关的各种任务.jenkins优点:免费开源、安装运行简单、可跨平台部署、高度可配置、非常多高质量的插件、分布式构建也能高效运行jenkins官网:https://www.jenkins.io/安......
  • Linux基础知识
    第1章Linux入门一、Linux基本知识1、Linux介绍1.1简介Linux是一种操作系统,像Windows一样,但是Windows操作系统,个人终端用的比较多1.2特点免费、开源、安全、高效、稳定;处理高并发非常的强,很多企业的项目都部署到Linux服务器上运行1.3创始人:林纳斯(芬兰人),1991年发布1.4吉祥物:一只企......
  • 国标GB28181视频平台LntonGBS(源码版)国标视频平台内存错误导致崩溃的问题解决方案
    LntonGBS国标视频云服务通过支持国标GB28181协议,实现了设备接入、实时监控直播、录像、语音对讲、云存储、告警、级联等功能。同时,它还支持将接入的视频流以多种格式(包括RTSP、RTMP、FLV、HLS、WebRTC)进行全终端、全平台分发,实现了无插件播放在Web浏览器、手机浏览器、微信端、PC客......
  • Linux8
    IP地址、主机名1.IP地址每台联网的电脑都会有一个地址,用于和其他计算机进行通讯IPv4版本的地址格式:a.b.c.d,其中abcd表示0~255的数字,如192.168.88.101就是一个标准的IP地址可以通过命令:ifconfig,查看本机的ip地址 inet指的就是IP地址 ens33是主网卡 2.特殊IP地址1......
  • 怎么判断linux中的内核进程与用户进程
    在ubuntu或者centos中,1号init进程或者systemd为用户进程,它的子进程也为用户进程;2号kthreadd进程为内核进程,其子进程也为内核进程。所以,判断是否为内核进程是看它跟2号进程的关系。此外,0号进程idle也是内核进程。init进程init进程是所有其他进程的祖先进程,是系统启动时第一个被......
  • Linux系统下安装JDK环境
    1、进入终端测试是否安装jdk--java-version显示已经安装jdk2、然后我也不太清楚为什么我就已经安装了jdk要是有不清楚如何安装的友友们,可以查看这个网址:https://blog.csdn.net/qq_21187515/article/details/90295031按照这个教程进行安装3、也可以看这个网址https://blog.......
  • Linux打印服务-CUPS的安装、配置和使用
    原文:https://blog.csdn.net/limelove/article/details/121988838 CUPS(CommonUNIXPrintingSystem,即通用Unix打印系统)是苹果公司所有,一个打印集成服务。包括了前端接收打印命令的相关程序,后端控制打印机硬件的程序,中间则是打印驱动。首先来看看CUPS驱动打印机的方式。这里要......