内核基础概念

Posted sxds-wxm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内核基础概念相关的知识,希望对你有一定的参考价值。

学习内核的本质其实是学习操作系统的原理

内核可以分成两类:

  • 宏内核:追求性能,大部分系统代码放在0环,代表:Linux
  • 微内核:追求维护性,大部分系统代码在3环,代表:Minix(Linux作者老师的作品),其中著名的设计:动态链接库,在Windows中也使用

Windows算是微内核和宏内核特点都具有的操作系统。

80x86处理器的工作模式

8086处理器有三种工作模式,分别是:实模式,保护模式,虚拟86模式,其中关系为:
技术分享图片
16位汇编中 iret可以进入保护模式。

分段式内存管理

如何保证操作内存的动作是否合法?

GDT、LDT

操作系统通电后进入实模式,做了一系列初始化的动作后进入到保护模式,在保护模式中,CPU执行所有和内存有关的操作都会通过查表来确定操作是否合法,这个表就是GDT和LDT表,表的格式由CPU厂商决定,所以为了能兼容多款CPU,操作系统代码里多用条件宏来实现。

地址的转换

  • 逻辑地址:在程序调试中见到的地址,实际上是:段+偏移的形式
  • 线性地址:逻辑地址转物理地址的中间层,逻辑地址是段中的偏移地址然后加上基地址就是线性地址。
  • 物理地址:物理内存条上的真实地址
逻辑地址如何转换到物理地址?

首先通过逻辑地址的偏移查第一次表得到线性地址,再查第二次表得到物理地址。为什么要查第二次表呢?因为第二张表实际上是为了实现虚拟内存,那么就是说这段内存可能是在磁盘上的,访问的时候会先查表,然后从磁盘上调到内存中,有些情况下(关闭了虚拟内存)查第一次表的结果等价于物理地址。

为什么要叫线性地址?

从逻辑地址转换到线性地址,是一块平坦且连续的地址,实际上对应到物理地址上,并不是连续的。
技术分享图片

如何计算线性地址的范围?

例如:

  • 设段A的基地址等于00012345H,段界限等于5678H,并且段界限以字节为单位(G=0),那么段A对应线性地址空间中从00012345H-000179BDH的区域。
  • 如果段界限以4K字节为单位 (G=1),那么段A对应线性地址空间中从00012345H-0568B344H(=00012345H+5678000H+0FFFH) 的区域。
如何从逻辑地址 ===查表===>> 线性地址

这个表也叫做分段表,结构如下图
技术分享图片
这种奇葩的做法来源于为了兼容286的历史遗留问题。

描述符

用于表示上述定义段的三个参数的数据结构称为描述符。每个描述符长8个字节。在保护方式下,每一个段都有一个相应的描述符来描述。

存储段描述符

存储段是存放可由程序直接进行访问的代码和数据的段。存储段描述符描述存储段,所以存储段描述符也被称为代码和数据段描述符。

描述符是一个8个字节的结构,具体结构如下:
技术分享图片

  • Limit 0:15项和Limit 16:19项一起构成20位的段界限。20位的段界限最大值为0xFFFFF,单位是字节或者分页(有Flags项Gr位来确定)。在分页机状态下最大可以表达4G的内存空间。

  • Base0:23项和Base24:31一起构成32位的段基址,是线性还是物理地址也取绝于分页机制是否开启。

整个的解析结构如下图:
技术分享图片

Access Byte
  • Pr位:存在位,对于一个有效的内存分段此值必定为1。

  • Privl位:优先级位(2位),取值从0-3,对应Ring0-Ring3级别。

    注:Privl右面那一位为1时表示此描述符对应是代码段和数据段,否则为系统或者各种门描述符。

  • Ex位:可执行位,为1时表示此描述符对应是代码段,否则为数据段。

  • DC位:(1)对于数据段,表于数据段的增长方向,0表示向上。1表示向下,也就是偏移大于段基址。(2)对于代码段,表示是否遵循一致原则。(当此位为1时,也就是遵循一致原则,不同优先级代码跳转时,优先级同目标代码所在段一致。为0时,刚跳转时优先级不变。)

  • RW位:读写位,(1)对于数据段,为1时表示可写,为0时表示不可写。数据段总是可读。(2)对于代码段,为1时表示可读,为0时表示不可读。代码段总是不可写。

  • Ac位:保留位,设置为0,当被访问过时系统将其改写为1。

Flags

全局和局部描述符表

  • 每个任务的局部描述符表LDT含有该任务自己的代码段、数据段和堆栈段的描述符,也包含该任务所使用的一些门描述符,如任务门和调用门描述符等。随着任务的切换,系统当前的局部描述符表LDT也随之切换。

  • 全局描述符表GDT含有每一个任务都可能或可以访问的段的描述符,通常包含描述操作系统所使用的代码段、数据段和堆栈段的描述符,也包含多种特殊数据段描述符,如各个用于描述任务LDT的特殊数据段等。在任务切换时,并不切换GDT。

通过LDT可以使各个任务私有的各个段与其它任务相隔离,从而达到受保护的目的。通过GDT可以使各任务都需要使用的段能够被共享。

GDT存储在GDTR寄存器, 通过汇编指令LGDT载入。它的操作码是一个结构的地址,这个结构描述GDT的大小和地址。共6个字节,如下:
技术分享图片

  • Size项(2个字节)是GDT的字节数减1(这也意味着GDT大小不可能为0)。2个字节对应最大值是65535,也就是说一个GDT最大也就是65536字节(8192个内存分段)。
  • Offset项(4个字节)指向GDT的线性地址(未开启分页机制则是物理地址)。

LDT存在LDTR寄存器中,存有局部进程的描述符表,LDTR中的内容根据线程的切换不停切换,表中的内容由操作系统来修改,若我们拿到0环权限,自己修改LDTR,改到目标进程,那么修改自己的内存就相当于修改了目标进程的内存,这是内核修改的一个经典招式

通过段选择子确定逻辑地址到物理地址的转化

段选择子

在保护方式下,虚拟地址空间(相当于逻辑地址空间)中存储单元的地址由段选择子和段内偏移两部分组成。段选择子长16位,在32位程序下,CPU的段寄存器中保存的就是选择子,其格式如下表所示:
技术分享图片

  • 段选择子的高13位是描述符索引(Index):所谓描述符索引是指描述符在描述符表中的序号。(windows不使用这种CPU的做法,而Linux使用)
  • 段选择子的第2位是引用描述符表指示位,标记为TI(Table Indicator),TI=0指示从全局描述符表GDT中读取描述符;TI=1指示从局部描述符表LDT中读取描述符。
  • RPL:特权级描述符,CPU比较这一项个描述符的特权级判断访问操作是否能进行下去
具体通过逻辑地址查找线性地址的例子:

现有逻辑地址:23:13ac34b,假如段寄存器中的的选择子Index为:0000000000100,RPL:11,先比对,是三环程序,继续操作,去LDT表中的第4项拿到段首地址,加上偏移13ac34b,得到线性地址。










以上是关于内核基础概念的主要内容,如果未能解决你的问题,请参考以下文章

什么是在 C++ 中获取总内核数量的跨平台代码片段? [复制]

鸿蒙轻内核A核源码分析系列五 虚实映射基础概念

linux设备驱动归纳总结内核的相关基础概念

Linux内核的启动流程之基础概念

Linux之内核编译基础概念

Android Fragments 基础知识:为啥?这在概念上是错误的吗?