Linux内核在I386架构下的内存管理

2023-11-10

转载自:http://blog.csdn.net/li_shyng/article/details/5545973

同类型的:http://www.kerneltravel.net/journal/ii/

I386是Intel的x86系列CUP中一个重要的里程碑。Linux最初就是I386 CPU上实现的。本文介绍Linux内核对I386架构系统进行内存管理,以及从逻辑地址到物理地址的转换方式。对于绝大多数现代的操作系统,例如:Windows NT(包括Windows 2000、Windows XP)在内存管理的实现方式基本上大同小异,通过对Linux分析,也可以加强对非源码开放式操作系统的理解。在I386架构上的现代操作系统,无一例外都需要在保护模式下工作。所以,先来介绍I386在保护模式有别于实模式的特性。

一、  I386 CPU保护模式下的新特性

  1. 1.  特权级别

CPU分为4个特权级别,0-3, 0最高,3最低。每条指令有其适用的级别。Linux和各种I386 Unix都 只用到0和3级别,对应Linux/Unix中的系统态和用户态。

  1. 2.  增加段寄存器

增加FS,GS段地址寄存器。加上原来的4个段寄存器,I386一共提供6个段寄存器。在保护模式下,以前实模式下的段寄存器还是有用的。不过它不再用来存放段的基址,而是用来存放“段选择子”(段描述项),其实段寄存器的名字也变成了“段选择子寄存器”或“段描述项寄存器”。在访问内存的时候,我们需要给出的是“段选择子”(段描述项),而不是段基址了。在段描述项中包含段基址、权限等信息。

  1. 3.  增加段表寄存器
  • 增加GDTR,LDTR,他们只用特权指令才能访问。配合段寄存器使用。

GDTR——全局段描述表寄存器 global descriptor table regisiter

LDTR——局部段描述表寄存器 local descriptor table regisiter

  • GDTR或LDTR加载GDT或LDT中的基地址。

GDT——全局地址段描述数据项表。

LDT——局部地址段描述数据项表。

  • 在Linux中只使用GDT。LDT在做虚拟机时候下才使用。
  1. 4.  中断向量

“中断向量”中不仅是程序的入口地址,而类似psw  + “入口地址”的方式,但更复杂。把各种中断向量归为4种类型的门。例如:cup在穿越中断门的时候自动关闭中断。 ......,很多说道,归根结底就是为了提供对“进程切换”和“中断响应”的更细致的控制。

  1. 5.  中断向量的保存与恢复

每种类型门的中断向量都包含段选择码TSS,它是用于保存任务现场的数据结构。

TSS——任务状态段 Task_state segment。  

当前任务(进程)被调度后,当前CPU各个寄存器的数据被保存到上一个任务(进程)的TSS中;当前任务的TSS的内容被装入各种寄存器,完成任务切换。

  1. 6.  增加的其他寄存器
  • 增加IDTR,TR寄存器,只有特权指令才能访问它们。

IDTR——中断向量表指针寄存器

TR——任务寄存器,用于指向当前任务(进程)的TSS。

  • 增加CR3寄存器,指向页表目录的基地址。页表目录,在有的操作系统教材上也叫做,外层页表。
  1. 7.  中断向量表的位置

IDT不再只保存在0开始的位置,可以在内存的任何位置,IDTR指向之。

IDT——中断向量表

IDTR——中断向量表指针寄存器

 

二、  Linux对I386的内存管理

  1. 1.  内存的初始化

1)   由于Linux需要在多种CPU上运行,而且大部分RISC CPU对段式内存管理的支持都很弱,所以在2.2内核以后,Linux基本上采取了绕过段式内存管理的策略。主要通过2个手段:

a)   通过所有进程指向共用两个GDT表项(其实一共四个表项,内核用2个,其他所有进程共用2个),一个代表数据段,一个代表代码段。

b)   并把这两个段基地址都设置为0,长度设置为最大,这就是所谓的平面内存。

2)   启用页式内存管理。初始化页表。

页表项:

 

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

P

R/W

U/S

PWT

PCD

A

D

0

0

OS专用

物理内存块号

 

页表项占32位,4个字节。其中高20位,为物理内存块号,2的20次方 = 1M,就是说共可以匹配1M个的物理块,其中一个物理块的大小规定为4K,这样共可以支持1M×4K=4G的物理内存。页表的低12位存放页面的控制信息。

下面看到就是页面表:

控制信息

物理块号

每项4个字节
共1024项
共4K

页表0

每个页表4K
共1024个
共4M

 

 

 

 

 

 

 

 

 

 

 

 

控制信息

物理块号

每项4个字节
共1024项
共4K

页表1023s

 

为了匹配4G的物理内存,需要建立1M个这样的页表项,每个页表项4个字节,1M×4=4M字节。这就是说,存储页表项的物理内存就需要4M字节,而物理内存是分块管理的,每块4K,这样就需要4M字节除以4K字节 = 1024个物理内存块存储页面表项。为了管理这1024个物理内存块,需要建立外层页表项。

外层页表项格式与内层页表项一致。占用空间:1024×4字节=4K,这样所有的外层表项就正好占用一个物理块。

外层页表在物理内存中的存放示意图:

 

控制信息

物理块号

外层页表
每项4个字节
共1024项
共4K

 

在实际的内存中,单个的页表一定占用一个物理页面(按4K边界对齐),页表的基地址的形式一定是 0xXXXXX000,

转换成2进制形式:

xxxxxxxxxxxxxxxxxxxx000000000000

12位的低地址都是0,这说明20位的物理块号,一定能找到页表的基地址。并且表项是按线性存储的。如果已知表项和页表的基地址,就可以通过指针的偏移找到相应的表项。

然而,各个内层页表在物理内存页面中则可能不是连续存放的,不过这没关系,外层页表的基地址是操作系统已知的,通过外层页表项的物理块号就可以找到它们。

3)   Linux对页表的管理

Linux是怎么知道哪些页表已经分配出去了,哪些是空闲的呢?解决的办法是,在内核中设有专门的数据结构,记录没有分配出去的页表。内核为新创建的进程分配页面,已经存在的进程申请页面都是以此为依据。

4)   Linux对物理内存的管理

在大多数情况下,系统实际拥有的物理内存可能没有达到4G。那么Linux有是怎么知道实际的物理内存的情况呢?解决办法依然是在内核中设有专门的数据结构,记录物理内存的情况。

  1. 2.  分配内存与寻址的过程

1)   程序的编译和链接

编译器把源代码文件编译成模块,链接器把各个模块链接起来。大体上把程序分为代码段、数据段、BSS段、堆(heap)段和栈段;并完成从符号到逻辑地址的转换。

2)   程序的装入和进程的创建

程序装入内存运行的功能是由execve()这一系统调用实现的。简单来讲,程序的装入主要包含以下几个步骤:

a)   读入可执行文件的头部信息以确定其文件格式及地址空间的大小;

b)   以段的形式划分地址空间(分配页面);

c)   将可执行程序读入地址空间中的各个段,建立虚实地址间的映射关系;

d)   将bbs段清零;

e)   创建堆栈段;

f)   建立程序参数、环境变量等程序运行过程中所需的信息;

g)   启动运行。

前面提到了,Linux内核已经不再为每个进程维护各自的段表了,相反为所有进程维护同一张段表,就是所谓的GDT,而且所有的用户进程共同使用其中的2条记录,而且由于使用Intel所谓平面地址空间,在理论上段内使用的逻辑地址可以是从0x00000000~0xFFFFFFFF之间的任意值。

现在有两个问题,一是如何为一个进程的各段分配逻辑地址,保证各段的逻辑地址不互相冲突呢?二是由于每个进程的寻址空间都是4G,在每个进程中都有可能使用像0x8048394这样逻辑地址,系统是怎么把他们区分开的呢,是怎么分别映射到不同的物理内存上的中的呢?

第一个问题,链接器来帮我们解决。在链接的过程中完成符号到逻辑地址的转换,并保持在同一个程序中不会为两个符号分配相同的逻辑地址。

第二个问题解决办法则十分巧妙,Linux内核为每个进程都建立一个页表目录,这个页表目录就是上面提到的外层页表,1024项,每项4字节。内核把进程已经使用的页面记录到这个页表目录中。由于在运行期间,内核负责空闲页表的维护,它不会把相同的页面分配给不同的进程,而页面是和物理内存地址直接映射的,所有尽管不同进程使用的逻辑地址可以相同,但不会映射到现同的物理内存地址上去的。下面就会提到逻辑地址到物理地址的转换的过程。

顺便提一下,由于绝大多数进程使用的内存都远小于4G,所有大多数页表目录项都是空的。

  1. 3.  从逻辑地址->线性地址->物理地址的转换

用户程序经过汇编后,所有的指令基本使用的都是逻辑地址。如果使用I386的段式内存管理,需要先把逻辑地址转换成线性地址,但Linux绕过了I386的段式内存管理(这需要gcc编译链接器的帮助),用户程序中的逻辑地址就已经是线性地址了,所以从逻辑地址到线性地址无需转换。

在CPU使用页式内存管理前,线性地址就是物理地址,不经转换可以直接使用。但是一旦启用了页式内存管理,就先把线性地址转换成为物理地址后才能使用。这工作由CPU内部的MMU硬件单元来完成。

下面给出的是逻辑内存的格式:

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

页内地址偏移

页表项 10位

目录号 10位

 

下面给出的是一个逻辑内存的值:0x480492A0

按照2进制展开三个字段分别为:

0100100000  0001001001 001010100000

目录号       = 0100100000(二进制)    = 0x120

页表项       = 0001001001(二进制)    = 0x49

页内地址偏移 = 001010100000 (二进制) = 0x2A0

 

CPU在CR3(目录表寄存器)的支持下,找到当前进程的目录表基地址,加0x120个字(每个字等于4个字节)后,得到目录表项;从表项中取出页表的基地址,加0x49个字,得到页表项;从页表项中取出物理块号,加0x2A0,得到实际的物理地址。

在这个过程中,逻辑地址在程序的编译链接的时候就确定了。页表项中的物理块号在操作系统初始化的时候也确定了(因为使用虚拟存储器,会发生换入换出,在这里先不管它)。唯独页表的基地址是在运行时候才分配的,就是说,内核具体上给进程分配哪些页表,只用在进程创建或进程申请内存的时候才能定下来。

在这里假设上面的例子的被分配的页表的页表项中的物理块号是0x02000000,那么实际的物理地址就是 0x02000000 + 0x2A0 = 0x020002A0。

  1. 4. 关于PAE

Pentium pro的以后的Intel的X86系列CPU有了36根地址线,支持3级页式内存管理,为了保持与原有软件兼容,还是使用32位的线性地址。这就是Intel所谓的PAE(Physical Address Extensions)。 它的好处是,虽然每个进程的寻址空间还是4G,但是整个系统的可用内存已经达到64G。它的实现的基本思路是同时支持4K和2M的内存页面,而且使用3层页表进行内存管理。它可以看作对I386的扩展,但是具体实现十分繁琐,在这里就不详细介绍了。

 

转载于:https://www.cnblogs.com/wang-can/p/3369528.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux内核在I386架构下的内存管理 的相关文章

  • Pycharm Debug(断点调试)超详细攻略

    前言 PyCharm Debug 可以帮助开发者在代码运行时进行实时的调试和错误排查 提高代码开发效率和代码质量 当然也可以对源码进行断点调试 领略源码的魅力 具体操作步骤 准备一段代码 让我们来举个简单的栗子 这段代码主要作用 循环ran
  • VUE基本指令(v-model,v-html,v-text,v-bind,v-if,v-show,v-for,v-on:click,组件,过滤器)

    文章目录 双向数据绑定 v bind v bind title简化写法为 title 设置类名 v bind class 隐藏 显示元素 v if和v show v for 遍历数组 遍历对象 v on click 点击事件 简化语法 cl
  • 未授权访问漏洞1

    未授权访问漏洞产生的原因 未授权访问漏洞是站由于网站管理员对站点的资源所拥有的权限或站点配置文件没有进行合理的配置 导致没有进行授权的用户可以访问到高级资源 常见的未授权访问漏洞 1 Redis未授权访问 漏洞简述 Redis是一种缓存数据
  • 实现统计某个目录中的java文件个数(子目录也算进去)

    实现统计某个目录中的java文件个数 子目录也算进去 package com summer io01 import java io File public class Demo07 public static int javaFileNum
  • python输出特征相关矩阵_两个特征矩阵的有效成对相关

    似乎 遵循了皮尔逊相关系数公式的定义 该公式适用于A amp B 基于这个公式 你可以很容易地将向量化 因为A和 列的成对计算是相互独立的 这里有一个使用 Get number of rows in either A or B N B sh
  • STM32 IIC通信-硬件从机 cube-HAL库

    前言 搞过很长时间的stm32 了 但是一直没有深入的研究底层 iic方面之前多是作为主机 而且多是使用io口模拟的 网上在这方面有用的东西确实不多 由于工作需要学习了下iic硬件从机的使用 使用cube创建工程 hal库 上次用cube还
  • sublime text3中代码格式化

    有两种方式 1 选中要格式化的代码 然后依次选择以下菜单 Edit gt Line gt Reindent 2 依次选择以下菜单 Preference gt Key Bindings user 然后 自己设置快捷键 keys ctrl sh
  • 告白玫瑰

    关注微信公众号 ClassmateJie 更多惊喜等待你的发掘 直接看实现效果 电脑端 手机端 使用场景 发给女神告白 提供一些文案 自从遇见你 我的世界变得不一样了 每一天都因为你而变得特别 我想告诉你 我喜欢你 不仅仅是因为你的美丽 还
  • 【win10】电脑剪贴板失效,解决办法。

    1 打开任务管理器 把剪贴板的进程结束 2 打开运行 输入rdpclip exe 即可解决
  • 状态压缩DP

    状态压缩DP前置知识 问题简介 基于状态压缩的动态规划 又叫集合动态规划 顾名思义 这是一类以集合信息为状态的特殊的动态规划问题 主要有传统集合动态规划和基于连通性状态压缩的动态规划两种 一般的动态规划往往着眼于整体 从中提取出两三个关键信
  • docker 安装mongodb

    1 取最新版的 MongoDB 镜像 gt docker pull mongo latest 2 查看本地镜像 gt docker images REPOSITORY TAG IMAGE ID CREATED SIZE mongo late
  • 数据库查询优化

    文章目录 1 代码优化 2 定位到慢SQL上 并优化 3 合理使用索引 重点 4 分表查询 5 缓存 6 异步 多线程 1 代码优化 减少没有必要的代码 例如for循环次数过多 作了很多无谓的条件判断 相同逻辑重复多次等 2 定位到慢SQL
  • 微服务分布式构架开发实战 附下载地址

    微服务是一种软件架构风格 目标是将一个复杂的应用拆分成多个服务模块 每个模块专注单一业务功能对外提供服务 并可以独立编译及部署 同时各模块间互相通信彼此协作 组合为整体对外提供完整服务 以往的图书大多只针对微服务分布式架构自身的知识点讲解
  • Linux iptables常用命令

    iptables 是 Linux 中重要的访问控制手段 是俗称的 Linux 防火墙系统的重要组成部分 这里记录了iptables 防火墙规则的一些常用的操作指令 下面的操作以 CentOS 为基础介绍 应该对不同的 Linux 发行版都差
  • 日志分析系列之平台实现

    本系列故事纯属虚构 如有雷同实属巧合 平台实现前的说明 小B在给老板汇报了 统一日志分析平台 项目后 老板拍板立即开始做 争取下一次能及时发现攻击并且追踪攻击者 于是小B开始分析了市面上商业与开源的日志分析平台架构 大家都神似如下图 知道了
  • 基于知识图谱的个性化学习推荐系统的设计与实现_kaic

    摘 要 Abstract 1 绪 论 1 1 研究背景及意义 1 2 国内外现状研究 1 3 研究工作和论文结构 2 相关技术 2 1 HTML 语言 2 2 Python 语言 2 3 数据库技术 2 4 Django 框架 3 系统分析
  • Nvidia Jetson 编解码开发(7)Jetpack 4.x版本Multimedia API 硬件编码开发--输出端对接ROS publish

    1 前言 Nvidia Jetson 编解码开发 6 Jetpack 4 x版本Multimedia API 硬件编码开发 输入端对接Camera V4L2采集 free xx的博客 CSDN博客 基于上篇基于开发 需求 1 2路Camer
  • C语言void指针及使用注意事项详解

    void 指针是一种特殊的指针 表示为 无类型指针 在 ANSI C 中使用它来代替 char 作为通用指针的类型 由于 void 指针没有特定的类型 因此它可以指向任何类型的数据 也就是说 任何类型的指针都可以直接赋值给 void 指针
  • js如何实现一个文本框只能输入数字 且是100的倍数

    var a 123 b 200 d test a a 100 0 false d test b b 100 0 true 转载
  • 安全网络通信(SSL&JSSE)

    目录 一 概念介绍 1 SSL简介 2 加密通信 3 安全证书 4 SSL握手 二 keytool工具生成证书 三 JSSE简介 1 KeyStore KeyManager与TrustManager类 2 SSLContext类 3 SSL

随机推荐

  • Linux系统更换默认启动内核版本方法

    1 得到当前系统已安装的所有内核版本 root localhost grep menuentry boot grub2 grub cfg cut d f2 CentOS 3 10 0 el7 x86 64 24 Workstation Ed
  • Python 微积分数值和符号计算(计算机代数)

    在积分学中 定积分是一个运算符 给定实值变量的实值函数和区间 a b 关联到该函数是其图形在区间 a b 中所包含的区域 给定一个变量的函数的以下积分 1 5 2 x
  • 购买阿里云服务器,先试试主机免费试用能抢到不 ...

    阿里云提供6个月的免费试用期 购买阿里云服务器之前先试试能不能免费抢到使用主机 先试用再正式购买 用起来更放心哈 步骤 1 进入阿里云导航栏的最新活动页 选择新手专区里面的阿里云免费套餐 2 根据自己账户的实名认证信息是个人认证还是企业认证
  • 12-24小时制

    编写一个程序 要求用户输入24小时制的时间 然后显示12小时制的时间 输入格式 输入在一行中给出带有中间的 符号 半角的冒号 的24小时制的时间 如12 34表示12点34分 当小时或分钟数小于10时 均没有前导的零 如5 6表示5点零6分
  • 自动控制原理知识点梳理——整体框架

    用的是胡寿松自动控制原理第七版 内容跟着书本和课上PPT 章节设置差不多 整体思路如下图 第一章 自动控制的一般概念 第二章 控制系统的数学模型 第三到五章分别是时域分析法 复频域分析法 根轨迹 频域分析法 第六章线性系统的校正方法 第八章
  • 各种坐标系下的散度、梯度、旋度公式

    引言 本文介绍了散度 梯度和旋度在直角坐标系 柱坐标系和球坐标系三种常见坐标系下的表示 记录一下 具体可以利用梅拉系数进行推导 谨记 梯度 标量求梯度得到矢量 散度 矢量求散度得到标量 旋度 矢量求旋度得到矢量 1 直角坐标系 标量表示 f
  • 使用CDN服务时遇到【HTTP PUT PATCH DELETE等请求方法不支持】【请求未到源站】【CDN直接返回404】【Cloudreve无法删除文件】的问题及解决方案

    异想之旅 本人原创博客完全手敲 绝对非搬运 全网不可能有重复 本人无团队 仅为技术爱好者进行分享 所有内容不牵扯广告 本人所有文章仅在CSDN 掘金和个人博客 一定是异想之旅域名 发布 除此之外全部是盗文 给赶时间的朋友们一句话总结 阿里
  • React 实现井字棋游戏 (tic-tac-toe) 教程 (5) <译自官方文档>

    React 实现井字棋游戏 tic tac toe 教程 1 lt 译自官方文档 gt React 实现井字棋游戏 tic tac toe 教程 2 lt 译自官方文档 gt React 实现井字棋游戏 tic tac toe 教程 3 l
  • 如何解决VS中scanf使用时报错或无法使用的问题

    目录 前言 1 问题 2 问题原因 3 如何解决 4 如何设置 总结 前言 新手上手VS想必都会遇到这个问题 在使用scanf时会出现警告 或者直接报错导致程序终止的问题 今天我就向大家讲解一下如何解决这个问题 1 问题 初识c语言的同学在
  • 解决gateway报错org.springframework.cloud.gateway.support.NotFoundException: Unable to find instance for

    gateway报错 org springframework cloud gateway support NotFoundException Unable to find instance for localhost 配置 浏览器访问 htt
  • Python实现中国移动提出的ABCDNETS和DSSN数联网技术介绍

    Python实现中国移动提出的ABCDNETS和DSSN数联网技术介绍 随着网络技术的发展 数联网技术成为了未来网络的关键技术之一 在这个方向上 中国移动提出了ABCDNETS和DSSN两种不同的数联网技术 分别针对不同应用场景进行优化 本
  • textarea文字垂直居中_word小技巧:制作封面时将文字置于页面中心

    有时侯我们需要将文字放置于页面的中间 水平居中和垂直居中 特别是在做封面的时侯 水平居中比较简单 但是发现如果要将一个或多个文字垂直居中处理确没有直接的办法 诸如PS CDR等专业排版软件要垂直居中非常容易 word里面要垂直居中可以通过下
  • django保存表单数据到数据库中

    这一部分涉及一下几个模块 前端HTML表单 表单验证的Form 数据库结构Model 后端处理的View 文章目录 前端HTML 表单验证Form 数据库结构Model 后端处理的View 更多数据库操作 前端HTML 网页文件 save
  • 【校招VIP】java开源框架之Zookeeper

    考点介绍 ZooKeeper是一个分布式的 开放源码的分布式应用程序协调服务 主要为了解决分布式架构下数据一致性问题 典型的应用场景有分布式配置中心 分布式注册中心 分布式锁 分布式队列 集群选举 分布式屏障 发布 订阅等场景 本期分享的j
  • python自动化访问百度地图

    要在 Python 中自动化访问百度地图 你可以使用第三方库 selenium 来实现 Selenium 是一种自动化测试工具 可以模拟用户在浏览器上执行操作 首先 你需要安装 Selenium 可以通过运行以下命令来安装它 pip ins
  • Go语言面试题--基础语法(16)

    文章目录 1 f1 f2 f3 函数分别返回什么 2 下面代码段输出什么 3 关于channel的特性 下面说法正确的是 1 f1 f2 f3 函数分别返回什么 func main fmt Println f1 fmt Println f2
  • 【HDLBits 刷题 13】Buliding Larger Circuits

    目录 写在前面 Buliding Larger Circuits count1k shiftcount fsm seq fsmshift fsm fancytimer fsm onehot 写在前面 以下的解题方法不一定为最佳解决方案 有更
  • 构造树型结构数据

    构造树型结构数据 param data 数据源 param id id字段 默认 id param parentId 父节点字段 默认 parentId param children 孩子节点字段 默认 children export fu
  • AUC的计算、物理意义,

    文章目录 一 定义 二 性质 三 计算 3 1 方法一 根据定义 3 2 方法二 根据意义 3 3 方法三 方法二优化 3 4 方法四 工业场景 四 物理意义推导 一 定义 ROC曲线与坐标轴围成的面积 ROC曲线由不同阈值下 TPR Y轴
  • Linux内核在I386架构下的内存管理

    转载自 http blog csdn net li shyng article details 5545973 同类型的 http www kerneltravel net journal ii I386是Intel的x86系列CUP中一个