首页 > 其他分享 >chapter3------保护模式之初始化GDT

chapter3------保护模式之初始化GDT

时间:2024-07-27 18:07:37浏览次数:12  
标签:保护模式 GDT LABEL eax 描述符 寄存器 ------ DESC

实模式

  • 运行于16位的CPU环境下:
    • 16位的寄存器
    • 16位的数据总线
    • 20位的地址总线,以及1MB的寻址能力(2^20B)
    • 一个地址由段和偏移两部分组成,物理地址=段值x16+偏移(段值和偏移都是16位,段值左移四位最后计算出来的地址才是20位)

保护模式

  • 运行与32位的CPU环境下
    • 32位的寄存器
    • 32位的数据总线
    • 32位的地址总线,以及4GB的寻址能力(2^32B)
    • 一个地址仍旧由段和偏移两部分组成

保护模式与实模式的区别

  • 实模式下的段值可以看做是地址的一部分,段值为xxxxh表示以xxxx0h(物理地址,段值二进制左移4位,16进制左移一位)开始的一段内存
  • 保护模式下的段值仅仅只是一个索引,指向一个数据结构(GDT或LDT)的一个表项(描述符),表项中详细定义了段的起始地址、界限、属性等内容

GDT(Global Descriptor Table,全局描述符表)

GDT中的每一个描述符就定义一个段

  • 描述符分为3类

    • 代码段和数据段描述符
    • 系统段描述符
    • 门描述符
  • 代码段和数据段描述符的结构
    (共8个字节,段基址4个字节,段界限2个字节,属性2个字节)

代码段和数据段描述符

  • 选择子的结构
    (共2个字节,16位)
    若不考虑前3位,那么可以将选择子看成是对应描述符相对于GDT基址的偏移
    选择子

  • 程序如何将对应段与寄存器联系起来呢?

mov ax, Selector      ; Selector表示一个选择子
mov gs, ax            ; gs表示段寄存器
  • 保护模式下的寻址

保护模式下的寻址

让我们解析下这个寻址过程:

  1. 首先,我们在程序中使用的是逻辑地址(段:偏移的形式)
  2. 段寄存器存储的是一个段描述符的选择子,指向GDT或LDT结构数组中的某个表项
  3. 指向的段描述符结合偏移量在定位到线性地址(由它的基址、界限、属性决定)

实模式跳转到保护模式

分为6步

  • 准备GDT
  • 用lgdt加载gdtr
    • GdtPtr是个小的数据结构,共6个字节(前两个字节是GDT的界限,后4个字节是GDT的基地址),把GDT的物理地址填充到这个数据结构中,然后执行指令lgdt [GdtPtr]将GdtPtr指示的6个字节加载到寄存器gdtr中
      gdtr
      gdtr寄存器与GdtPtr的结构完全一样
  • 关中断
    • 执行指令cli
  • 打开A20
    • 执行指令
; 打开地址线A20
in  al, 92h
or  al, 00000010b
out 92h, al
  • 置cr0的PE位(第0个位置)为1
    • 寄存器cr0的PE位为0表示CPU运行于实模式,为1表示保护模式
    • 执行指令
; 准备切换到保护模式
mov eax, cr0
or  eax, 1
mov cr0, eax
  • 跳转,进入保护模式
    • 此时cs寄存器的值还是实模式下的值,将代码段的选择子装入cs寄存器中
    • 执行指令jmp dword selector:0,selector根据自己的选择子替换,dword不可省略

初始化段描述符---程序解析

以下程序以代码段LABEL_DESC_CODE32为例

  • 准备GDT的信息
[SECTION .gdt]
; GDT
;                              段基址,           段界限,           属性
LABEL_GDT:         Descriptor       0,                0,           0      ; 空描述符
LABEL_DESC_CODE32: Descriptor       0, SegCode32Len - 1, DA_C + DA_32     ; 非一致代码段
LABEL_DESC_VIDEO:  Descriptor 0B8000h,           0ffffh,       DA_DRW     ; 显存首地址
; GDT 结束

GdtLen      equ $ - LABEL_GDT   ; GDT长度
GdtPtr      dw  GdtLen - 1      ; GDT界限
            dd  0               ; GDT基地址

; GDT 选择子
SelectorCode32      equ LABEL_DESC_CODE32   - LABEL_GDT
SelectorVideo       equ LABEL_DESC_VIDEO    - LABEL_GDT
; END of [SECTION .gdt]

LABEL_GDT就是GDT的首地址了

  • 初始化GDT:加载段选择子
xor eax, eax                 ; 清空 eax 寄存器
mov ax, cs                   ; 将当前代码段寄存器 cs 的值加载到 ax 寄存器
shl eax, 4                   ; 将 ax 寄存器的值左移4位(乘以16),获得段的线性地址
add eax, LABEL_DESC_CODE32   ; 将 LABEL_DESC_CODE32 的地址加到 eax 中,得到代码段的线性地址
  • 初始化GDT:设置描述符的其他字段
mov word [LABEL_DESC_CODE32 + 2], ax   ; 将 ax 寄存器的低16位存储到 LABEL_DESC_CODE32+2 的位置,这是段选择子
shr eax, 16                            ; 将 eax 寄存器右移16位,获得高16位
mov byte [LABEL_DESC_CODE32 + 4], al   ; 将 al 寄存器的低8位存储到 LABEL_DESC_CODE32+4 的位置,描述符的访问权限字节
mov byte [LABEL_DESC_CODE32 + 7], ah   ; 将 ah 寄存器的高8位存储到 LABEL_DESC_CODE32+7 的位置,描述符的段基址的高字节
  • 加载全局描述符表寄存器(GDTR)
xor eax, eax                  ; 清空 eax 寄存器
mov ax, ds                    ; 将数据段寄存器 ds 的值加载到 ax 寄存器
shl eax, 4                    ; 将 ax 寄存器的值左移4位(乘以16),获得全局描述符表(GDT)的基地址
add eax, LABEL_GDT            ; 将 LABEL_GDT 的地址加到 eax 中,得到完整的 GDT 的线性地址
mov dword [GdtPtr + 2], eax   ; 将 eax 的值存储到 GdtPtr+2 的位置,准备加载 GDTR 寄存器

lgdt    [GdtPtr]              ; 加载 GDTR

标签:保护模式,GDT,LABEL,eax,描述符,寄存器,------,DESC
From: https://www.cnblogs.com/winter-z/p/18327122

相关文章

  • 洛谷P1042 [NOIP2003 普及组] 乒乓球
    题目链接:-P1042[NOIP2003普及组]乒乓球[NOIP2003普及组]乒乓球题目背景国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及。其中11分制改革引起了很大的争议,有一部分球员因为无法适应新规则只能选择退役。华华就是其中一位,他退役......
  • Visual Studio版本号、MSVC版本、工具集版本号
    IDE              发布时间   工具集版本   MSC_VER      MSVC++          系统支持       使用频率VisualC++6.0       1998       V60       1200......
  • Vue 3 中 13 种不同的组件通信方法
    在Vue3中,组件之间的通信是构建应用程序的关键。本指南将介绍13种不同的组件通信方法,从最简单到最复杂,帮助你选择最适合你需求的方式。h21.父组件向子组件传递数据(Props)这是最基本也是最常用的通信方式。父组件通过属性向子组件传递数据。「父组件:」<template>......
  • 计组笔记第七章——输入输出系统
    7.1.1I/O系统和IO控制方式常见I/O设备:鼠标、键盘;显示器、打印机;硬盘、光盘。主机如何与I/0设备进行交互?I/O接口:又称I/O控制器、设备控制器,负责协调主机与外部设备之间的数据传输。I/O接口与CPU之间靠总线连接,与外设之间靠USB连接线连接。I/O接口多种多样,也会指定相应的标......
  • 数组基础、多维数组、静态Array
    数组:一组数据。本身是一种类型(引用类型),但它中存储的元素(项)也有数据类型,数组只能用来存储类型相同的强类型的数据,比如班级只能用来存放学生,不能放别的。数组在内存中是按定长连续来存储的,具有相同数据类型的数据元素的有序集合。inta=10;//一个数据boolb=true;//一......
  • 【0299】Postgres内核之 INSERT INTO 原始解析树 转 Query 树 (3)
    相关文章:【0297】Postgres内核之INSERTINTO原始解析树转Query树(1)【0298】Postgres内核之INSERTINTO原始解析树转Query树(2)1.opentable(RangeVar指定)在完成了由函数setup_parser_errposition_callback()完成的解析器错误位置报告回调函数的注册后,接下来通......
  • 聚类模型——未知类别
    个人学习笔记,课程为数学建模清风付费课程目录一、K-means聚类算法1.1流程1.2图解1.3流程图1.4评价二、K-means++算法2.1流程2.2Spss软件操作2.3讨论三、系统(层次)聚类3.1概述3.2流程3.3Spss软件操作3.4聚类谱系图(树状图)3.5用图形估计聚类的数量 3.6聚合系数......
  • 算法训练 2024.7.27 17:25
    目录1.两数之和2.反转链表3.是否为有效的括号4.最长公共前缀5.合并两个有序数组6.岛屿的个数7.最小路径和8.三数之和9.计数质数10.字符串转换整数(atoi)1.两数之和题目:给定一个整数数组nums和一个目标值target,请你在该数组中找出和为目标值的那两个整......
  • 基于redis实现分布式锁
           分布式锁1.基于redis实现分布式锁注意:这里设置过期时间,是为了预防死锁。如果某个线程获取了锁,但还没等它执行完业务,释放锁。服务器就宕机了,那么就不会有人再去释放锁,出现了死锁问题。简单业务代码:publicinterfaceILock{booleantryLock(longt......
  • Python 中的正反斜杠用法详解
    在Python编程中,字符串是一个常用的数据类型,字符串中的斜杠(反斜杠\和正斜杠/)具有特殊的用法和意义,本文将介绍这两种斜杠的用法。一、反斜杠的转义作用在Python中,反斜杠(\)被称为转义字符,它常用于两个主要目的。1.引入特殊字符反斜杠可以用来引入特殊字符序列,这些序列在Py......