02.加载GDT表,进入保护模式

news2024/11/30 0:51:21

加载GDT表,进入保护模式

加载GDT表,实现操作系统从实模式进入保护模式

参考
操作系统学习 — 启动操作系统:进入保护模式
保护模式与实模式
GDT、GDTR、LDT、LDTR
调用门与特权级
趣谈 Linux 操作系统

在01.硬盘启动盘,加载操作系统中BIOS在0x7c00处加载MBR,并让程序跳转到该处。MBR只是一个中转站,其他功能如加载GDT表、切换保护模式,需要loader完成。

1.实模式

概念:
在程序中用到的地址都是真实的物理地址,“段基址:段内偏移地址”产生的逻辑地址就是物理地址,即程序员可见的地址完全是真实的内存地址。
物理地址(physicaladdress)=段值(segment) * 16 + 偏移(offset)

缺点:

  • 没有权限划分,实模式下操作系统和用户程序属于同一特权级
  • 程序中用到的地址都是真实的物理地址,逻辑地址等于物理地址
  • 访问超过 64KB 的内存区域时要切换段基址,16位寄存器,2^16 = 64KB
  • 共 20 条地址线,最大可用内存为 1MB
  • 平坦模型,无法支持多任务,安全性无法保证

2.保护模式

概念:
保护模式下,全部32条地址线有效,可寻址高达4G字节的物理地址空间。保护模式下,地址表示方式:段(segment):偏移(offset),虽然段值仍然由原来的cs、ds等寄存器表示,但此时它仅仅变成了一个索引,这个索引指向了一个数据结构的一个表项(段描述符),表项中详细定义了段的起始地址、界限、属性等内容。这个数据结构就是全局描述符表GDT(LDT是局部的)。
段描述符
在实模式下,段地址并非真实的物理地址,在计算物理地址时,还要左移 4 位(乘以 16)。和实模式不同,在 32 位保护模式下,段地址是 32 位的线性地址,如果未开启分页功能,该线性地址就是物理地址

  • 段基址:指定了这个段的起始地址,它是一个32位的值,用于计算线性地址。
  • 段界限:段界限符 = 该段的大小。
  • G位G表示段界限粒度大小,假如 G = 1,粒度 = 4kb(最大段界限 = 2 20 ∗ 4 K B = 2 32 2^{20} * 4KB=2^{32} 2204KB=232),G = 0,粒度 = 1字节( 2 20 ∗ 1 = 2 20 2^{20} * 1=2^{20} 2201=220)。超过段界限,就会触发内存段保护。
  • 段类型:需要看两个字段:type和S位。
  • S位:S位的作用在于,指示这个段是不是系统段。只有知道了S位,type段才有意义。系统段就是说,这个段由硬件CPU运行,非系统段是由软件(OS/用户)运行。
    • S = 1 代码段或数据段的描述符
      在这里插入图片描述
    • S= 0 系统段的描述符
      在这里插入图片描述

3.分段机制

段描述符表

每个段都需要一个段描述符。这些描述符存储在内存的一段空间中,即全局描述符表GDT(或LDT)。
GDT与LDT的区别:

  • 范围不同:GDT 是全局段描述符表,包含系统中所有进程所需的所有段描述符,而 LDT 是局部段描述符表,只有在需要更多段描述符时才使用。
  • 使用限制不同:每个进程只能使用一个 GDT,但可以同时使用多个 LDT。
  • 加载方式不同:GDT 的基地址和限长保存在 GDTR 寄存器中,由 CPU 加载,而 LDT 的基地址和限长保存在相应进程的 LDTR寄存器中,由操作系统加载,与进程的虚拟地址空间独立。
  • 访问速度不同:由于 GDT 存储所有段描述符,因此访问 GDT 通常比访问 LDT 更快

描述符表的长度可变,最多可以包含8K个这样的描述符(因为段选择子是16位的,其中的13bit用来作index,2^13=8K)。

段选择器

实模式下的 6 个段寄存器 CS、 DS、 ES、 FS、 GS 和 SS,在保护模式下叫做段选择器。
其结构如下图所示
在这里插入图片描述

  • 第0-1位:请求特权级(Requestor Privilege Level, RPL),用于表示当前代码的特权级别。RPL可以取值0、1、2、3,其中0表示最高特权级,3表示最低特权级。
  • 第2位:表指示器(TableIndicator, TI),用于指示该段描述符存储在全局描述符表(GDT)还是局部描述符表(LDT)中。TI的值为0表示描述符存储在GDT 中,为1表示描述符存储在 LDT 中。
  • 第3-15位:索引(Index),用于标识段描述符在 GDT 或 LDT中的位置,索引的值必须是 8 的倍数。

段选择子的结构可以通过一个 16 位的寄存器来存储和传递,如 CS(代码段选择子)、DS(数据段选择子)和 SS(堆栈段选择子)等。当 CPU 访问某个段时,它会根据段选择子来确定所需的段描述符的位置,并加载该段描述符以获取相应的段基址、权限和限长等信息,从而实现对这个段的正确访问。

在这里插入图片描述
GDT表可以很大,存放在内存中,由 GDTR寄存器 存储它的地址。同理,LDT存储在LDTR中。其中:

  • GDTR全局描述符寄存器:48位,高32位存放GDT基址,低16为存放GDT限长。
    在这里插入图片描述
    • 通过 lgdt xxxx 将xxxx存储到 GDTR 寄存器,xxxx包含GDT内存起始地址和GDT界限。
    • 通过 sgdt xxxx获得当前 GDTR 寄存器的内容存储到 xxxx 当中。
  • LDTR局部描述符寄存器:16位,高13为存放LDT在GET中的索引值。

以此构建GDT表:

[SECTION .gdt]
DATA_SEG_BASE equ (0x1000)
DATA_SEG_LIMIT equ 0xfffff

CODE_SEG_BASE equ (0x0)
CODE_SEG_LIMIT equ 0xfffff
; 索引<<3位 = 地址相减  。2^3 = 8字节
CODE_SELECTOR equ (gdt_code - gdt_base) ; 代码段选择子
DATA_SELECTOR equ (gdt_data - gdt_base) ; 数据段选择子

gdt_base:
    dd 0, 0
gdt_code:
    dw CODE_SEG_LIMIT & 0xffff ; 段界限
    dw CODE_SEG_BASE & 0xffff ;
    db CODE_SEG_BASE >> 16 & 0xff
    ;    P_DPL_S_TYPE
    ; 其中1表示有效,00表示特权级0,1表示的代码段,1000表示代码段不可读写,可执行
    db 0b1_00_1_1000
    ;    G_DB_AVL_LIMIT
    ; 其中0表示段界限以字节为单,1表示此段是32位的,后四位表示段界限高4位。
    db 0b0_1_00_0000 | (CODE_SEG_LIMIT >> 16 & 0xf)
    db CODE_SEG_BASE >> 24 & 0xf
gdt_data:
    dw DATA_SEG_LIMIT & 0xffff
    dw DATA_SEG_BASE & 0xffff
    db DATA_SEG_BASE >> 16 & 0xff
    ;    P_DPL_S_TYPE
    ; ,其中1表示段描述符有效,00表示特权级0,1表示数据段,0010表示数据段可读写。
    db 0b1_00_1_0010
    ;    G_DB_AVL_LIMIT
    ;   其中1表示段界限以4KB作为单位,1表示此段是32位的,后四位表示段界限高4位。
    db 0b1_1_00_0000 | (DATA_SEG_LIMIT >> 16 & 0xf)
    db DATA_SEG_BASE >> 24 & 0xf

gdt_ptr:
    dw $ - gdt_base - 1
    dd gdt_base

寻址流程

寻址流程图下图所示:
在这里插入图片描述

分段机制下的虚拟地址由两部分组成,段选择子段内偏移量。段选择子保存段寄存器里面。段选择子里面最重要的是段号,用作段表的索引。段表里面保存的是这个段的基地址、段的界限和特权等级等。虚拟地址中的段内偏移量应该位于 0 和段界限之间。如果段内偏移量是合法的,就将段基地址加上段内偏移量得到物理内存地址。

  • 1.根据段选择子在段描述表中找到对应的段描述符号。
  • 2.根据段描述符获取段基址、段界限、特权等级等。
  • 3.根据段基地址和段内偏移量得到物理地址。

根据GDT寻址

当 TI=0时表示段描述符在GDT中
在这里插入图片描述
① 先从GDTR寄存器中获得GDT基址。
② 然后再GDT中以段选择符高13位位置索引值得到段描述符。
③ 段描述符符包含段的基址、限长、优先级等各种属性,这就得到了段的起始地址(基址),再以基址加上偏移地址(程序给出)才得到最后的线性地址。

根据LDT寻址

当TI=1时表示段描述符在LDT中
在这里插入图片描述
① 还是先从GDTR寄存器中获得GDT基址。
② 从LDTR寄存器中获取LDT所在段的位置索引(LDTR高13位)。
③ 以这个位置索引在GDT中得到LDT段描述符从而得到LDT段基址。
④ 用段选择符高13位位置索引值从LDT段中得到段描述符。根据位置索引在GDT中得到LDT段描述符从而得到LDT段基址。
⑤ 段描述符符包含段的基址、限长、优先级等各种属性,这就得到了段的起始地址(基址),再以基址加上偏移地址(程序给出)才得到最后的线性地址。

4.进入保护模式流程

进入保护模式的代码却是千奇百怪的,形式可不统一。比如进入保护模式需要三个步骤。

  • 打开 A20
  • 加载 gdt
  • 将 cr0 的 pe 位置 1

打开 A20

打开A20,避免地址回绕
在这里插入图片描述
打开方式:

  • 通过键盘控制器
  • 调用BIOS功能
  • 使用系统端口
    in    al,  92h
    or    al,  00000010b
    out   92h, al

加载 gdt

GDT 有两个相关的指令:

  • lgdt xxxx:xxxx有6字节,前2字节是一个gdt界限,后4字节是gdt起始地址。将 xxxx 存储到 gdtr
  • sgdt xxxx:获得gdtr的值,存储到 xxxx
    进入保护模式一定需要加载gdt,首先在loader建立一个GDT,然后将 GDT 的地址、界限存储到 GDTR 寄存器当中。
lgdt [gdt_ptr]

将 cr0 的 pe 位置 1

CR0 寄存器的第0位是 pe位,Protection Enable,用来启动保护模式,是保护模式的开关。所以这一步一般都是最后一步。
在这里插入图片描述
PE 为 0 表示在实模式下运行,PE 为 1 表示在保护模式下运行。

   mov eax, cr0
   or eax, 0x00000001
   mov cr0, eax

5.验证

进入保护模式流程图:
在这里插入图片描述
验证方法:

protected_mode:
   ; 设置段寄存器
   mov ax, DATA_SELECTOR      ; 设置数据段选择子为DATA_SELECTOR
   mov ds, ax        ; 将数据段寄存器设置为DATA_SELECTOR

    ; 转换为逻辑地址:ds:0xB7000
    ; ds 绑定数据段,基地址为0x1000, 对应的线性地址(物理地址)0xB7000+0x1000 = 0xB8000
    ; 0xB8000对应显存的物理地址,若能超过写入字符
    ; 说明CPU 能够正确地处理地址映射,并且成功进入了保护模式
    mov byte [0xB7000], 'A'

    ; 测试是否成功进入保护模式.如果没有,写入内存是失败的
  	; 同理逻辑地址为: ds:0x100000
  	; 对应的线性地址(物理地址) 0x101000
    xchg bx, bx
    mov byte [0x100000], 0xAB

    jmp $

在这里插入图片描述
在这里插入图片描述
当前未开启分页,线性地址=物理地址。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/626075.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

要能力、要稳定也要降本——百度多媒体技术回顾

摘要&#xff1a;多媒体技术生态进入到存量市场&#xff0c;客户既要又要还要成为常态。如何将能力、质量与稳定性、成本不断优化&#xff0c;就是各个多媒体技术平台的必修课。本文以百度智能视频云为例&#xff0c;纵览了其在RTC、边缘计算、视频编码等关键能力与用户体验和成…

腾讯搜索的系统架构是如何达到99.994%高可用的?

&#x1f449;腾小云导读 本文主要是搜索在稳定性治理实践的经验总结&#xff0c;讲述了搜狗搜索在技术债治理基础上如何将可用性提升一个量级&#xff0c;事故级 MTTD&#xff08;平均故障检测时间&#xff09;、MTTR&#xff08;平均响应时间&#xff09;优化一个量级&#x…

chatgpt赋能python:Python的IDLE运行方式

Python的IDLE运行方式 Python是一种非常流行的编程语言&#xff0c;其优雅简洁的语法和丰富的库资源&#xff0c;使得Python在很多领域都得到广泛应用。在Python的开发过程中&#xff0c;IDLE是一种常用的Python集成开发环境&#xff08;IDE&#xff09;&#xff0c;对于初学者…

关于操作系统调度器的三篇论文

【引子】没有忘记&#xff0c;目前从事的是DingOS 操作系统相关工作&#xff0c;没有因为LLM 而迷失。LLM 会成为基础设施&#xff0c;LLM 会为操作系统赋能&#xff0c;但是操作系统的价值是客观存在的&#xff0c;除非&#xff0c;计算机体系结构发生了翻天覆地的变化。 在任…

Java面试都只是背答案吗

Java 八股文面试当然要背&#xff0c;不背很难通过面试的 Java基础 Java基础面试题 Java的特点Java 与 C 的区别JDK/JRE/JVM三者的关系Java程序是编译执行还是解释执行&#xff1f;面向对象和面向过程的区别&#xff1f;面向对象有哪些特性&#xff1f;数组到底是不是对象&a…

编写Python程序求数组中最长的字符串

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 移船相近邀相见&#xff0c;添酒回灯重开宴。 大家好&#xff0c;我是皮皮。 一、前言 前几天在Python白银群【王子】问了一个Python基础的问题&#x…

Ubuntu离线安装docker与nvidia-docker

Ubuntu离线安装docker与nvidia-docker 安装 docker 20.10.17安装 nvidia-docker 和 nvidia-container-toolkit docker与nvidia-docker离线安装包 安装 docker 20.10.17 查看Ubuntu操作系统版本的详细信息&#xff0c;不同的版本所依赖的deb不同。 lsb_release -aCodename为&a…

一文带你读懂:TCP连接的三次握手和四次挥手(上篇)

TCP 是面向连接的协议&#xff0c;所以使用 TCP 前必须先建立连接&#xff0c;而建立连接是通过三次握手来进行的。 天下没有不散的宴席&#xff0c;对于 TCP 连接也是这样&#xff0c; TCP 断开连接是通过四次挥手方式。 下面我们通过实操&#xff0c;来彻底理解三次握手和四次…

linux ubi文件系统更新失败问题分析2

昨天打包了一个ubi根文件系统&#xff0c;打包成功&#xff0c;写板子flash成功&#xff0c;但系统运行后还是老的文件系统&#xff0c;具体过程如下&#xff1a; 使用脚本1&#xff0c;打包rootfs系统&#xff1a; 打包后的文件系统&#xff0c;下载到板子后&#xff0c;查看…

01_MySQL索引简介

影响性能下降、SQL慢体现在&#xff1a;执行时间长或者等待时间长 影响sql性能的常见情况&#xff1a; 数据过多&#xff1a;分库分表(根据微服务划分库、按照地域或时间分表存储、按照数据的特定字段对分库数量求余)关联了太多的表&#xff0c;太多join&#xff1a;允许表出现…

在口袋妖怪世界中理解ChatGPT的思维

深度学习自然语言处理 原创作者&#xff1a;Winni 今天为大家分享一篇研究&#xff0c;当ChatGPT穿越到口袋妖怪世界&#xff0c;是否会理解并应用这个虚构世界的知识呢&#xff1f; 熟悉口袋妖怪的朋友们一定知道&#xff0c;这些可爱的生物们有着各种不同的属性、类别和技能。…

TypeScript Vs JavaScript 区别

一、观察 1. JS 平常的复制类型 let val; val 123; val "123"; val true; val [1, 3, 5]; 注意点: 由于JS是弱类型的, 所以只要定义了一个变量, 就可以往这个变量中存储任意类型的数据 也正是因为如此, 所以会给我们带来一个问题 2. 假设a是一个数组, b是一个数值…

java+SSM+vue停车场管理系统

家家户户对于汽车的需求日益的增长。在促进了汽车行业的发展的同时&#xff0c;也对我国的交通造成了较大的压力。首先在日常的出行中&#xff0c;老旧城区道路狭窄&#xff0c;容易造成车辆的堵塞&#xff0c;每天早晚&#xff0c;接送孩子的车辆数密集&#xff0c;会造成相应…

【工业控制系统安全】深入了解 ICS612:ICS 网络安全:第 1 部分

ICS 从业者可以立即在实际情况中使用他们的 ICS612 培训。 降落飞机 我认识一家生产工厂的首席执行官&#xff0c;我们就叫他比尔吧&#xff0c;他希望他的关键团队成员真正了解他的运营团队每天为实现生产目标而承受的压力。比尔还希望他的经理和支持人员能够理解“让它发生”…

你知道支付宝转账怎么在自己的手机上不留痕迹吗

支付宝和微信支付是现代社会中非常普遍的移动支付方式&#xff0c;可以方便快捷地完成各种线上和线下交易。然而&#xff0c;在一些情况下&#xff0c;用户可能希望隐藏或删除某些转账的痕迹&#xff0c;以保护个人隐私或避免不必要的麻烦。对于支付宝而言&#xff0c;实际上有…

RabbitMQ - 幂等性、优先级、惰性

RabbitMQ - 幂等性、优先级、惰性 幂等性优先级队列惰性队列 幂等性 概念 用户对于同一操作发起的一次请求或者多次请求的结果是一致的&#xff0c;不会因为多次点击而产生了副作用。 举个最简单的例子&#xff0c;那就是支付&#xff0c;用户购买商品后支付&#xff0c;支付…

Mysql中联合索引的最左匹配

联合索引 通过将多个字段组合成一个索引&#xff0c;该索引就被称为联合索引。 比如&#xff0c;将商品表中的 product_no 和 name 字段组合成联合索引(product_no, name)&#xff0c;创建联合索引的方式如下&#xff1a; CREATE INDEX index_product_no_name ON product(pr…

尝试用Go goroutine实现一个简单的聊天服务

hello&#xff0c;大家好&#xff0c;我是张张&#xff0c;「架构精进之路」公号作者。 对于聊天服务&#xff0c;想必大家都不会陌生&#xff0c;因为在我们的生活中经常会用到。 我们用 Go 并发来实现一个聊天服务器&#xff0c;这个程序可以让一些用户通过服务器向其它所有用…

总有人问我 Cookie 是什么?

苏生不惑第432 篇原创文章&#xff0c;将本公众号设为星标&#xff0c;第一时间看最新文章。 之前分享过我写的微博批量下载工具2023 更新版&#xff1a;苏生不惑开发过的那些原创工具和脚本 &#xff0c;因为要输入自己账号的cookie&#xff0c;总有人问我cookie是什么?今天写…

FPGA 的数字信号处理:重写 FIR 逻辑以满足时序要求

在上一篇文章中&#xff08;FPGA 的数字信号处理&#xff1a;Verilog 实现简单的 FIR 滤波器&#xff09;演示了在 Verilog 中编写自定义 FIR 模块的初始demo。该项目在行为仿真中正常&#xff0c;但在布局和布线时未能满足时序要求。 所以今天的文章让我们来看看当设计不能满足…