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. java IO流 (九) Path、Paths、Files的使用

    1.NIO的使用说明:>Java NIO (New IO,Non-Blocking IO)是从Java 1.4版本开始引入的一套新的IO API,可以替代标准的Java IO AP.>NI ...

  2. 数据可视化之 图表篇(一)Power BI可视化,几张图表认识疫情现状

    ​近期国际疫情愈演愈烈,在这个特殊的时期,一方面仍要照顾好自己.不要为疫情防治添乱,另一方面,也可以利用疫情数据提升自己的数据分析和可视化技能. 下面是我制作的几个可视化图表,分别注释了每个可视化用到 ...

  3. hihoCoder 1049 后序遍历 最详细的解题报告

    题目来源:后序遍历 解题思路:开始时我只知道先通过先序.中序求出二叉树,然后再后序遍历二叉树,这当然也是一种解题思路,但是会做一些无用功,比如:计算二叉树.其实,可以直接通过先序序列和中序序列直接求出 ...

  4. Angular 懒加载找不到模块问题解决方法

    问题: 懒加载无法找到模块 解决办法: 在app-routing.module.ts中引入该模块

  5. 当我谈 HTTP 时,我谈些什么?

    当我们打开网站时也许不会去留意网站前面的HTTP是怎么来的.但是它毫无疑问在网络中有着举足轻重的地位.本文从起源到发展,详说HTTP从1到3的演变. 说在前面 本文不致力于讲完 HTTP 的全部内容, ...

  6. Ethical Hacking - NETWORK PENETRATION TESTING(6)

    Creating a fake access point (honeypot) Fake access points can be handy in many scenarios, one examp ...

  7. NVIDIA GPU Turing架构简述

    NVIDIA GPU Turing架构简述 本文摘抄自Turing官方白皮书:https://www.nvidia.com/content/dam/en-zz/Solutions/design-vis ...

  8. SpringBoot + Spring Cloud Consul 服务注册和发现

    什么是Consul Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置.与其它分布式服务注册与发现的方案,Consul 的方案更"一站式" ...

  9. web自动化 -- 三种等待方式

    一.强制等待 二.隐式等待 注:隐式等待的作用域是全局,所以一般设置在整局代码的头几行. 如: 三.显示等待 元素存在: 元素可见: 元素可点击: 看到上图源码中有一个   element.is_en ...

  10. 今天发现郭的华为手机无法读写sd卡,找到了这个方法

    https://bbs.csdn.net/topics/391985867?page=1 华为P9是android 6.0 的==在API23+以上也就是安卓6.0以上的,进行了权限管理不止要在And ...