• 《深入理解Linux内核》条目式笔记 _3


    下面25条描述主要介绍硬件中段(segment)是如何组织的, 以及如何从逻辑地址(logic address)转换为线性地址(linear address)。

    51. 段寄存器(segmentation registers)是处理器提供的用于快速访问段选择子的部件, 包括cs, ss, ds, es, fs和gs。这些段寄存器可以被程序复用, 只要复用前把寄存器里的内容保存到内存中, 用完后再恢复。

    52. cs(code segment)代码段寄存器, 指向包含程序指令的段。还包括一个2位的域,用于标识CPU的当前优先级级别(Current Privilege Level), Linux用其中的级别0表示内核模式, 级别3表示用户模式。

    53. ss(stack segment)堆栈段寄存器, 指向包含当前运行的程序的堆栈的段。

    54. ds(data segment)数据段寄存器, 指向包含全局数据和静态数据的段。

    55. es, fs, gs为通常寄存器, 可能指向随机的数据段。

    56. 段描述符(segment descriptor)是用来描述段的特征的8字节长的数据, 它通常存储于全局描述表(Global Descriptor Table, GDT) 或者局部描述符表(Local Descriptor Table, LDT)中。

    57. 全局描述符表GDT通常只能一个, 它的地址和大小通常存储在一个叫gdtr的控制寄存器中。

    58. 局部描述符表LDT允许各个进程独自拥有, 它的地址和大小通常存储在一个叫ldtr的控制寄存器中。

    59. 段描述符(Segment Descriptor)之域: Base,指明段的起始地址。

    60. 段描述符(Segment Descriptor)之域: G,指明的大小粒度, 为字节(bytes),或者为4k字节(4096 bytes)。

    61. 段描述符(Segment Descriptor)之域: Limit,  指向段的最后一个内存单元的偏移量。当G为0时, 段的范围为1byte到1MB, 当G为1时, 段的范围为4KB到4GB。

    62. 段描述符(Segment Descriptor)之域: S,  系统标记位, 若为0, 则该段是系统段, 存储类似局部描述符GDT的关键数据结构, 否则是一个普通的代码或者数据段。

    63. 段描述符(Segment Descriptor)之域: Type, 指明段的类型和访问权限。

    64. 段描述符(Segment Descriptor)之域:DPL, 描述符优先级别(Descriptor Privilege Level), 用于限制对段的访问。级别为0的段只允许CPL为0的CPU访问, 级别为3的段允许任意CPL的CPU访问。

    65. 段描述符(Segment Descriptor)之域: P, Segment Present标记, 指明当前段是否在内存中, 若为0表示不在内存中。 Linux总是设置该P域为1, 因为它从来不把整个段都交换到磁盘中。

    66. 段描述符(Segment Descriptor)之域 D or B, 指明该段包含的是代码还是数据。 若段地址的偏移量为32位的, 通常设置为1, 若为16位的, 通常设置成0.

    67. 段描述符(Segment Descriptor)之域 AVL, Linux忽略该域。

    68. Linux中使用的段描述符的类型: 代码段描述符(Code Segment Descriptor), 指向代码段, 存储在全局描述符表或者局部描述符表中, 设置了S标记(表明非系统段)。

    69. Linux中使用的段描述符的类型: 数据段描述符(Data Segment Descriptor), 指向数据段, 存储在全局描述符表或者局部 描述符表中, 设置了S标记。 它是实现ss (stack segment)的元素。

    70. Linux中使用的段描述符的类型: 任务状态段描述符表(Task State Segment Descriptor), 指向任务状态段, 该段存储了处理器当前的寄存器的状态, 它只能存储在全局描述符表中。 Type域只能是11或者是9(取决于当前进程是否正被CPU执行), 不设置S标记(表明是系统段)。

    71. Linux中使用的段描述符的类型: 局部描述符表描述符(Local Descriptor Table Descriptor), 指向包含局部描述符表的段, 它只能存储在全局描述符表中, Type域被设置为值2, 不设置S标记(表明这是系统段)。

    72. 快速访问段描述符: 通过为6个可编程寄存器(cs, ds, ss, es ,fs, gs)各自提供一个不可编程的寄存器。 这些不可编程的寄存器里面各自包含一个8字节的段描述符。 每次从内存中加到一个段选择子(见第50条描述)到段寄存器中时, 相应的段描述符也从内存中加载到对应的不可编程寄存器中。 这样, 下次转换逻辑地址时, 就可以直接从该寄存器中取得相应段的信息, 而不必访问存储在内存中的全局描述符表或者局部 描述符表, 从而加快了访问段描述符的速度。 当且仅当段寄存器的内存发生改变时, 需要重新访问全局描述符表或者局部 描述符表。

    73. 继第50条描述, 段选择子(segment selector)的域:a, index, 索引, 用于指向包含在全局描述符表或者局部描述符表中的段描述符元素; b. TI, 表指示符, 指明是在全局描述符中还是在局部 描述符(为1时)中; c. RPL, 相应的段选择子会被加载到代码段寄存器中。

    74. 在GDT或者LDT中段描述符的地址为: GDT或者LDT的址 +   段描述符中的index值 * 8。  GDT中能存储的段描述符的最大数量为8191个( 2^13 -1).

    75. 逻辑地址(logical address)转换为线性地址(linear address)的具体 过程:首先取得段选择子(Segment Selector)中的表指示符域TI的值, 从而确定是存储在GDT中还是在LDT中。 GDT的地址可以从gdtr寄存器中取得, LDT的地址可以由ldtr寄存器取得。 接着, 计算段描述符的地址(具体见第74描述)。最后, 把段描述符的基地址base和段选择子中的偏移量offset相加,即得到对应的线性地址。  前面两步可以由不可编程寄存器(见第72描述)完成。

    后续会介绍在Linux中, 段是如何组织的。

  • 相关阅读:
    EntityFramework之创建数据库及基本操作(一)
    Entity Framework Code First (八)迁移 Migrations
    [转]Tomcat启动报错:AnnotationConfigBeanDefinitionParser are only available on JDK 1.5 and higher
    [转]bootstrap table本地数据使用方法
    [转]MySQL-5.7 Update语句详解
    [转]操作MySQL数据库报出:Parameter index out of range (1 > number of parameters, which is
    [转]在MySQL中创建实现自增的序列(Sequence)的教程
    [转]MySQL如何设置自动增长序列 SEQUENCE
    [转]Mustache 使用心得总结
    [转]关于重定向RedirectAttributes的用法
  • 原文地址:https://www.cnblogs.com/quiet/p/2427615.html
Copyright © 2020-2023  润新知