7.4.1 Intel CPU物理结构

https://www.cnblogs.com/megachen/p/9768115.html

x86实模式

实模式

  • 20位:1M内存空间
  • 地址表示方式:段地址(16位):偏移地址(16位)
  • 段地址4位对齐

保护模式(Protect Mode)

  • 32位地址空间:4G内存
  • 支持多任务、任务切换、上下文保护
  • 进程隔离:代码和数据的安全
  • 支持分段机制和分页机制
  • 新的寄存器
    • EAX~EDX:扩充到32位
    • CR0~CR4
    • GDTR
    • LDTR
    • IDTR
    • ……

保护模式的寄存器模型

控制寄存器CR0

CR0的低5位组成机器状态字(MSW)

  • PE:0—实模式;1—保护模式
  • MP:1(系统有数字协处理器时)
  • EM:0(仿真协处理器)
  • TS:任务切换,切换任务时自动设置
  • PG:允许分页

控制寄存器CR2

如果发生缺页,引发缺页的线性地址保存在CR2中

控制寄存器CR3

CR3包含页目录基址:高20位

x86 CPU架构下的三种地址

逻辑地址:汇编语言(段:偏移)

若在保护模式下,DS不能理解为段基址

线性地址:由逻辑地址转换得到

物理地址

未分页 线性地址==物理地址

分页 线性地址!=物理地址

x86 CPU架构下的三种地址

线性地址(Linear Address)是逻辑地址到物理地址变换之间的中间层。在分段部件中逻辑地址是段中的偏移地址,然后加上基地址就是线性地址。

第一级:段机制(逻辑地址到线性地址)

第二级:分页机制(线性地址到物理地址)

逻辑地址、物理地址、线性地址

Intel架构下

凡是在代码中书写的内存地址都是逻辑地址,也就是采用基地址+偏移量,我们能够直接看到的也是逻辑地址,通过左移等操作可以计算出对应的物理地址(在实模式下逻辑地址与物理地址没有中间层所以是可以的,但是在保护模式则是行不通的,再说)

实模式下

逻辑地址通过左移等操作可以计算出对应的物理地址

保护模式

  • 在逻辑地址和物理地址之间多了一个中间层线性地址
  • 逻辑地址左移等操作计算出来的是线性地址而不再是物理地址了, 线性地址就是32位的整数
  • 通过分页机制将线性地址转为32位的物理地址

7.4.2 Intel CPU段机制

段与段描述符

一段连续内存

段描述符

描述段的属性,8字节(保护模式)

  1. 段基址
  2. 段界限
  3. 段属性
  4. 段类型
  5. 访问该段所需最小特权级
  6. 是否在内存
  7. ……

描述符(Descriptor)

段基址:32位(段基址1+段基址2)

段界限:20位(段界限1+段界限2)

TYPE值 数据段和代码段描述符 S=1 系统段和门描述符 S=0
0 只读 <未定义>
1 只读,已访问 可用286TSS
2 读/写 LDT
3 读/写,已访问 忙的286TSS
4 只读,向下扩展 286调用门
5 只读,向下扩展,已访问 任务门
6 读/写、向下扩展 286中断门
7 读/写,向下扩展,已访问 286陷阱门
8 只执行 <未定义>
9 只执行、已访问 可用386TSS
A 执行/读 <未定义>
B 执行/读、已访问 386TSS
C 只执行、一致码段 386调用门
D 只执行、一致码段、已访间 <未定义>
E 执行/读、一致码段 386中断门
F 执行/渎、一致码段、已访问 386陷阱门

描述符的数据结构

typedef struct Descriptor  {
unsigned int base24_31; //:8 基地址的高8位
unsigned int g; //:1 段长单位,0:字节
unsigned int d_b; //:1
unsigned int unused; //:1
unsigned int avl; //:1
unsigned int seg_limit_16_19; //:4 段界限高4位
unsigned int p; //:1
unsigned int dpl; //:1
unsigned int s; //:1
unsigned int type; //:4
unsigned int base_0_23; //:24 基地址的低24位
unsigned int seg_limit_O_15; //:16 段界限低16位
}

描述符表(Descriptor Table)

描述符表

存放描述符的数组

长度:8字节的整数倍

描述符表类型

  • 全局描述符表GDT:Global Descriptor Table
  • 局部描述符表LDT:Local Descriptor Table
  • 中断描述符表IDT:Interrupt Descriptor Table

全局描述符表GDT:Global Descriptor Table

包含所有进程可用的段描述符,系统进1个GDT表

局部描述符表LDT:Local Descriptor Table

包含与特定进程有关的描述符,每个进程由自己的LDT

中断描述符表IDT:Interrupt Descriptor Table

包含终端服务程序段的描述符(中断门描述符)

类似中断向量表

选择子(Selector)

选择子用于选择GDT/LDT中的某个描述符

  • 存放在段寄存器中:高13位是整数索引。

构成

  • 索引域(INDEX):13位,给出段描述符在GDT或者IDT中的位置
  • TI域(Table Indicator):1位,GDT(0)或IDT(1)
  • 特权级别域(Request Privilege Level):2位

例:LDT基址0012 0000H,GDT基址00100000H,CS=1007H

  1. 请求的特权级是多少?
  2. 目标段的描述符位于GDT中还是LDT中?
  3. 目标段的描述符的基地址是多少?

解:(CS)=1007H=0001 0000 0000 0111B

  1. RPL=3,申请的特权级位3

  2. TI=1,描述符位于LDT内

  3. 描述符相对于LDT基址的偏移量位

    \(0001 0000 0000 0B \times 8=512 \times 8 = 4096 = 1000H\)

    段描述符的地址为

    \(0012 0000H + 1000H = 0012 1000H\)

把逻辑地址转换到线性地址(32位,4G)

7.4.3 Linux页面机制

硬件分页

分页

  • Intel CPU的页
  • 通过设置CR0的PG位开启分页功能
  • 分页:线性地址→物理地址(线性地址是分段功能获取的)
  • 在MMU中进行分页

Linux的三级页表结构

普通页表实现时的问题

32位OS(4G空间),每页4K,页表每个记录占4字节

  • 进程的页数:4G/4K=1M个页

    • 页表的记录应有1M条记录

      • 页表所占内存:1M*4字节=4M

        • 页表占页框数:4M/4K=1K页框(连续)

问题:

  1. 难以找到连续1K个页框存放页表
  2. 页表全部放入过度消耗内存(4M)

解决办法

  1. 将4M的超大页表存储到离散的1K个页框中
  2. 仅将页表的部分内容调入内存
页号 页框号 中断位 外存地址 访问位 修改位
0 8 0 4000 1 0
1 24 0 8000 1 1

二级页表

把超大的页表(4M)以页为单位分成若干个小页表,存入离散的若干个页框中

为了对小页表进行管理和查找,另设置一个叫页目录的表,记录每个小页表的存放位置(页框号)

  • 页目录实际上是一个特殊页表:每个记录存放的是小页表的标号和其所在的页框号之间的对应关系

页目录:一级页表或外部页表;小页表:二级页表

Windows NT二级页表的结构

页目录号:小页表页号(页目录的索引)31-22

页号:页面的编号(页表的索引)21-12

页偏移:页偏移 11-0

二级页表地址的映射特点

  1. 访问数据需要三次访问内存
  2. 页目录调入内存
  3. 页表按需要调入内存
  4. 页面、页表、页目录的大小都刚好4K(占一个页框)

7.4.4 Linux对段的支持

Linux段机制

进程建立时,段机制对寄存器初始化:start_thread()

#define start_thread(regs, new_eip, new_esp) do {
__asm__("movl %0,%%fs ; movl %0,%%gs": :"r" (0));
set_fs(USER_DS);
//对段寄存器初始化
//__USER_DS数据段
regs->xds = __USER_DS;
regs->xes = __USER_DS;
regs->xss = __USER_DS;
//__USER_CS代码段
regs->xcs = __USER_CS;
regs->eip = new_eip;
regs->esp = new_esp;
} while (0)
#define __KERNEL_CS   0X10
#define __KERNEL_DS 0x18
#define __USER_CS 0x23
#define __USER_DS 0x2B
INDEX TI DPL
__KERNEL_CS 0X10 0000 0000 0001 0 0 0 0
__KERNEL_DS 0x18 0000 0000 0001 1 0 0 0
__USER_CS 0x23 0000 0000 0010 0 0 1 1
__USER_DS 0x2B 0000 0000 0010 1 0 1 1

INDEX:2,3,4,5;TI=0;DPL:0、3

GDT定义

ENTRY(gdt_table)
.quad 0x0000000000000000 /*NULL descriptor*/
.quad 0x0000000000000000 /*not used*/
.quad 0x00cf9a000000ffff /*0x10 kernel 4GB code at 0x00000000*/
.quad 0x00cf92000000ffff /*0x18 kernel 4GB data at 0x00000000*/
.quad 0x00cffa000000ffff /*0x23 user 4GB code at 0x00000000*/
.quad 0x00cff2000000ffff /*0x2b user 4GB data at 0x00000000*/
.quad 0x0000000000000000 /*not used*/
.quad 0x0000000000000000 /*not used*/

xxxx xxxx Gl00 hhhhPDP0 1010 xxxx xxxx xxxx xxxx xxxx xxxx hhhh hhhh hhhh hhhh

K_CS:0000 0000 1100 111110011010 0000 0000 0000 0000 0000 0000 1111111111111111

K_DS:0000 0000 1100 11111001 0010 0000 0000 0000 0000 0000 0000 1111111111111111

U_CS:0000 0000 1100 111111111010 0000 0000 0000 0000 0000 0000 1111111111111111

U_DS:0000 0000 1100 11111111 0010 0000 0000 0000 0000 0000 0000 1111111111111111 .

  • XXXX:基地址;hhhh:段界限
  • G位倒是1(段长单位4KB);P位都是1(段在内存)

Linux的段机制

  1. Linux四个范围一样的段:0~0xFFFFFFFF(4G)

    • 内核数据段|内核代码段|用户数据段|用户代码段
  2. 各段属性不同
    • 内核段特权级为0
    • 用户段特权级位3
  3. 作用
    • 利用段机制隔离用户数据和系统数据

      • 保留段的等级保护机制
    • 简化(避免)逻辑地址到线性地址转换
      • 可以直接将虚拟地址当作线性地址,二者完全一致

【av68676164(p55-p58)】 Intel CPU和Linux内存管理的更多相关文章

  1. linux内存管理

    一.Linux 进程在内存中的数据结构 一个可执行程序在存储(没有调入内存)时分为代码段,数据段,未初始化数据段三部分:    1) 代码段:存放CPU执行的机器指令.通常代码区是共享的,即其它执行程 ...

  2. Linux内存管理(二)

    Linux内存管理之二:Linux在X86上的虚拟内存管理 本文档来自网络,并稍有改动. 前言 Linux支持很多硬件运行平台,常用的有:Intel X86,Alpha,Sparc等.对于不能够通用的 ...

  3. Linux内存管理(一)

    Linux内存管理之一:基本概念篇 物理地址.线性地址(虚拟地址)和逻辑地址:阐述段式管理和页式管理基本概念:Linux操作系统内存管理和虚拟内存概念:为内核开发做一个基础铺垫. 内存是linux内核 ...

  4. [转帖]Linux分页机制之概述--Linux内存管理(六)

    Linux分页机制之概述--Linux内存管理(六) 2016年09月01日 19:46:08 JeanCheng 阅读数:5491 标签: linuxkernel内存管理分页架构更多 个人分类: ┈ ...

  5. linux内存管理---物理地址、线性地址、虚拟地址、逻辑地址之间的转换

    linux内存管理---虚拟地址.逻辑地址.线性地址.物理地址的区别(一) 这篇文章中介绍了四个名词的概念,下面针对四个地址的转换进行分析 CPU将一个虚拟内存空间中的地址转换为物理地址,需要进行两步 ...

  6. linux内存管理---虚拟地址、逻辑地址、线性地址、物理地址的区别(一)

    分析linux内存管理机制,离不了上述几个概念,在介绍上述几个概念之前,先从<深入理解linux内核>这本书中摘抄几段关于上述名词的解释: 一.<深入理解linux内核>的解释 ...

  7. 转 Linux内存管理原理

    Linux内存管理原理 在用户态,内核态逻辑地址专指下文说的线性偏移前的地址Linux内核虚拟3.伙伴算法和slab分配器 16个页面RAM因为最大连续内存大小为16个页面 页面最多16个页面,所以1 ...

  8. 【转帖】linux内存管理原理深入理解段式页式

    linux内存管理原理深入理解段式页式 https://blog.csdn.net/h674174380/article/details/75453750 其实一直没弄明白 linux 到底是 段页式 ...

  9. Linux内存管理和寻址详解

    1.概念 内存管理模式 段式:内存分为了多段,每段都是连续的内存,不同的段对应不用的用途.每个段的大小都不是统一的,会导致内存碎片和内存交换效率低的问题. 页式:内存划分为多个内存页进行管理,如在 L ...

随机推荐

  1. mongodb(五):聚合操作(python)

    pymongo的聚合操作 数据类型样式 /* 1 */ { "_id" : ObjectId("5e5a32fe2a89d7c2fc05b9fc"), &quo ...

  2. javascript基础(四): 操作表单

    表单是什么?form-----DOM树 文本框----text 下拉框----select 单选框----radio 多选框----checkbox 隐藏域----hidden 密码框----pass ...

  3. 数据可视化之powerBI技巧(十六)采悟:PowerBI作图技巧:动态显示可视化标题

    默认情况下,PowerBI图表的标题是静态的,为了增强图表的可读性,通过设置动态标题,可快速展示关键信息.提升沟通效率.本文通过两个简单的例子来看看PowerBI中如何创建动态标题. /01/ 拿之前 ...

  4. CentOS8.0 Docker Repository

    一.硬件软件准备      1.2台服务器或者电脑(使用云服务器1.阿里云 2.百度云各一台) ,系统均为CentOS 8.0      2.分别安装Docker      3.测试镜像准备(准备的是 ...

  5. Disease Manangement 疾病管理

    题目描述 Alas! \(A\) set of \(D (1 <= D <= 15)\) diseases (numbered \(1..D\)) is rshning through t ...

  6. 给咱的WP站点搬家

    前言 WordPress 作为全球最流行的博客系统,使用简单,功能丰富,用它来建站的用户非常多.对于站长们来说,网站搬家也是少不了的,有时我们需要更换主机空间,把网站从一个服务器迁移到另一个服务器上, ...

  7. 一起学Blazor WebAssembly 开发(1)

    最近blazor的WebAssembly 正式版出来了,正好手头有一个项目采用的前后端分离模式做的,后端用的abp vnext(.net core 的一个很著名的框架)框架开发的,其实前端之前考虑的使 ...

  8. 软件测试工程师之必备SQL语句基础

    作为一个软件测试工程师,我们在测试过程中往往需要对数据库数据进行操作,但是我们的操作大多以查询居多,有时会涉及到新增,修改,删除等操作,所以我们其实并不需要对数据库的操作有特别深入的了解,以下是我在工 ...

  9. vue学习(三) v-bind指令

    //html <div id="app"> <input type="button" value="ok" v-bind: ...

  10. Promise对象 异步编程

    Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大.所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是 ...