段地址轻松体验(实模式和保护模式)

合集下载

内存寻址的三种模式

内存寻址的三种模式

内存寻址的三种模型1. 地址的种类首先明确一下逻辑地址和线性地址这两个概念:1. 逻辑地址2. 线性地址3. 物理地址1.1 逻辑地址:逻辑地址是编译器生成的,我们使用在linux环境下,使用C语言指针时,指针的值就是逻辑地址。

对于每个进程而言,他们都有一样的进程地址空间,类似的逻辑地址,甚至很可能相同。

1.2 线性地址:线性地址是由分段机制将逻辑地址转化而来的,如果没有分段机制作用,那么程序的逻辑地址就是线性地址了。

1.3 物理地址物理地址是CPU在地址总线上发出的电平信号,要得到物理地址,必须要将逻辑地址经过分段,分页等机制转化而来。

2. 三种寻址模型x86体系结构下,使用的较多的内存寻址模型主要有三种:1. 实模式扁平模型real mode flat model2. 实模式分段模型real mode segment model3. 保护模式扁平模型protected mode flat model下面是对这三种模型的描述实模式和保护模式相对,实模式运行于20位地址总线,保护模式则启用了32位地址总线,地址使用的是虚拟地址,引入了描述符表;虽然二者都引入了段这样一个概念,但是实模式的段是64KB固定大小,只有16KB个不同的段,CS,DS等存储的是段的序号(想想为什么?)。

保护模式则引入了GDT和LDT段描述符表的数据结构来定义每个段。

扁平模型和分段模型相对,区别在于程序的线性地址是共享一个地址空间还是需要分成多个段,即为多个程序同时运行在同一个CS,DS的范围内还是每个程序都拥有自己的CS,DS:前者(flat)指令的逻辑地址要形成线性地址,不需要切换CS,DS;后者的逻辑地址,必须要经过段选择子去查找段描述符,切换CS,DS,才能形成线性地址。

3. 实模式扁平模型该模式只有在386及更高的处理器中才能出现!80386的实模式,就是指CPU可用的地址线只有20位,能寻址0~1MB的地址空间。

从实模式到保护模式中断技术的教学认识

从实模式到保护模式中断技术的教学认识

从实模式到保护模式中断技术的教学认识【摘要】结合《微机原理及应用》课程的教学实践,简述了实模式中断系统的要点,分析了保护模式中断系统的中断过程,阐述了实模式与保护模式中断的比较,提出了教学过程中如何处理中断系统的内容。

【关键词】中断技术;实模式;保护模式;描述符Abstract:This paper expounded the main points of real mode interrupt system with self’s teaching practice of the course“microcomputer principle and application”,and analyzed the interrupt process of interrupt system at protection mode,this paper gave the interrupt comparison about protected mode and real mode,put forward how to deal with the content of the interrupt system in the process of teaching.Keywords:interrupt technology;real mode;protected mode;descriptor在《微机原理及应用》课程中,中断机制和中断技术是很重要的内容,它是微机系统的主要组成部分之一。

随着计算机技术的不断发展,尤其是计算机运行的速度越来越高,对计算机的性能要求也随之愈来愈高,不仅要求外设与CPU 并行操作,而且要求计算机能够随时通过中断方式发现错误,计算机出现异常时能够及时处理故障等。

在实模式下和保护模式下分别转到中断服务程序入口地址的方式区别很大,工作在保护模式下的微型计算机,其中断的功能越来越强,中断系统越来越复杂,组成中断系统的中断技术成为了计算机系统中十分重要的技术,它是《微机原理及应用》课程教学中的重点,也是难点。

保护模式下寻址(易懂)

保护模式下寻址(易懂)

保护模式下寻址(易懂)保护模式下寻址(易懂):网上看到的一强帖,不转不行了,牛人啊,把这段代码拿捏的相当到位括号中是我的加注段机制轻松体验[内存寻址]实模式下的内存寻址:让我们首先来回顾实模式下的寻址方式段首地址×16+偏移量=物理地址为什么要×16?因为在8086CPU中,地址线是20位,但寄存器是16位的,最高寻址64KB,它无法寻址到1M内存。

于是,Intel设计了这种寻址方式,先缩小4位成16位放入到段寄存器,用到时候,再将其扩大到20位,这也造成了段的首地址必须是16的倍数的限制。

保护模式下分段机制的内存寻址:保护模式下分段机制是利用一个称作段选择符的偏移量,从而到描述符表找到需要的段描述符,而这个段描述符中就存放着真正的段的物理首地址,再加上偏移量一段话,出现了三个新名词:1、段选择子2、描述符表3、段描述符我们现在可以这样来理解这段话:有一个结构体类型,它有三个成员变量:段物理首地址段界限段属性内存中,维护一个该结构体类型的是一个数组。

而分段机制就是利用一个索引,找到该数组对应的结构体,从而得到段的物理首地址,然后加上偏移量,得到真正的物理地址。

公式:xxxx:yyyyyyyy其中,xxxx也就是索引,yyyyyyyy是偏移量(因为32位寄存器,所以8个16进制)xxxx存放在段寄存器中。

现在,我们来到过来分析一下那三个新名词。

段描述符,一个结构体,它有三个成员变量:1、段物理首地址2、段界限3、段属性我们再来重温一遍描述符表,也就是一个数组,什么样的数组呢?是一个段描述符组成的数组。

接下来看看段选择子:段选择子,也就是数组的索引,但这时候的索引不在是高级语言中数组的下标,而是我们将要找的那个段描述符相对于数组首地址(也就是全局描述表的首地址)偏移位置。

就这么简单,如图:图中,通过Selector(段选择子)找到存储在Descriptor Table(描述符表)中某个Descriptor(段描述符),该段描述符中存放有该段的物理首地址,所以就可以找到内存中真正的物理段首地址SegmentOffset(偏移量):就是相对该段的偏移量物理首地址+偏移量就得到了物理地址本图就是DATA但这时,心细的朋友就发现了一个GDTR这个家伙还没有提到!我们来看一下什么是GDTR ?Global Descriptor Table Register(全局描述符表寄存器)但是这个寄存器有什么用呢?大家想一下,段描述符表现在是存放在内存中,那CPU是如何知道它在哪里呢?所以,Intel 公司设计了一个全局描述符表寄存器,专门用来存放段描述符表的首地址,以便找到内存中段描述符表。

详解实模式,保护模式,虚拟8086模式

详解实模式,保护模式,虚拟8086模式
详解实模式,保护模式,虚拟8086模式
2014年11月29日 0:59
• 80x86处理器有三种工作模式:实模式,保护模式和虚拟8086模式
• 历史 ○ DOS时代,汇编凭借着特权可以随时访问系统内核,直接操作硬件,对系统安全造成威胁 ○ Windows时代的到来,不仅给我们带来了华丽的界面,更多的是给我们带来了“保护机 制”。将系统内核层层封装,用户仅能通过Windows提供的接口访问内核。即保护模式 ○ 为了兼容以前的MS-DOS程序,虚拟86模式应运而生。虚拟8086模式是以任务形式在保护模式 上执行的, 在80386上可以同时支持由多个真正的80386任务和虚拟8086模式构成的任务 ○ 其实,实模式和虚拟8086模式是为了向下兼容而设置的. 而保护模式是我们的主角, 是我们现
实际上, 80386就是通过在实模式下初始化控制寄存器, GDTR, LDTR, IDTR与TR等管理寄存 器以及页表, 然后再通过加载CR0使其中的保护模式使能位置位而进入保护模式的. 当然, 实模式下不支持硬件上的多任务切换
实模式下的中断处理方式和8086处理器相同, 也用中断向量表来定位中断服务程序地址 中断向量表的结构也和8086处理器一样: 每4个字节组成一个中断向量, 其中包括两个字节
○ 虚拟8086模式是以任务形式在保护模式上执行的, 在80386上可以同时支持由多个真正的 80386任务和虚拟8086模式构成的任务。虚拟8086模式以保护模式为基础, 它的工作方式实际 上是实模式和保护模式的混合
• 实模式
○ 以8086架构进行讲解,8086上一代8088 CPU中的寄存器都是8位的。而8086是16位的,是
显示的视频缓冲区和BIOS的地址空间
• 而在内存低端, 安排了中断向量表和BIOS数据区; 剩下从

80386 和 保护模式

80386 和 保护模式

80386 和保护模式___William LiuIntel CPU 一般可以运行在两种模式之下,即实模式和保护模式。

早期的 Intel CPU ( 8086 , 8088 )只能工作在实模式之下,系统中只能运行单个任务,而且只能使用实地址模式。

对于 Intel 80386 以上的芯片则还可以运行在 32 位的保护模式之下。

在保护模式之下的 CPU 可以支持多任务;支持 4GB 的物理内存;支持 64TB 的虚拟内存;支持内存的页式管理和段式管理以及支持特权级。

本文档将首先介绍 Intel 80386 CPU 的几个内部寄存器,然后再由浅入深的分别介绍保护模式下的段式管理,页式管理,虚拟内存,多任务以及特权级管理等几个方面。

Intel 80386 CPU 的内部寄存器这一部分先大致介绍一下 386 的内部寄存器,具体细节在后面的几节中再详细说明。

一般来说, CPU 设计用来系统编程的系统寄存器包括如下几类:•标志寄存器 (EFLAGS)•内存管理寄存器 (GDTR , LDTR , IDTR , TR)•控制寄存器 (CR0 , CR1 , CR2 , CR3 , CR4)•兼容 8086 通用寄存器( EAX , EBX , ECX , EDX )•兼容 8086 段寄存器( CS , DS , ES , SS , FS , GS )•兼容 8086 数据寄存器( ESI , EDI , EIP , ESP )下面分别加以介绍:1) 标志寄存器 EFLAGS :跟 8086/8088 的 FLAGS 大致差不多。

只不过位宽由 16bit 变成了 32bit ,负责的状态标志也多了一些。

见图一所示:图一: EFLAGS 的结构其中系统标志: VM -虚拟 8086 模式; RF -恢复标志; NT -任务嵌套标志;IOPL - I/O 特权级标志; IF -中断允许标志。

2) 内存管理寄存器:一共有 4 个,用于分段内存管理,都是用于存放指针的,只是所指的再内存单元中的内容有所不同。

x86汇编语言:从实模式到保护模式(第2版)

x86汇编语言:从实模式到保护模式(第2版)

16.1 任务的隔离和特权级保护 16.2 代码清单16-1 16.3 内核程序的初始化 16.4 加载用户程序并创建任务 16.5 用户程序的执行 本章习题
17.1 本章代码清单 17.2 任务切换前的设置 17.3 任务切换的方法 17.4 用jmp指令发起任务切换的实例 17.5 处理器在实施任务切换时的操作 17.6 程序的编译和运行 本章习题
第9章 硬盘和 显卡的访问与 控制
5.1 计算机的启动过程 5.2 创建和使用虚拟机
6.1 本章代码清单 6.2 欢迎来到主引导扇区 6.3 注释 6.4 在屏幕上显示文字 6.5 显示标号的汇编地址 6.6 使程序进入无限循环状态 6.7 完成并编译主引导扇区代码 6.8 加载和运行主引导扇区代码 6.9 程序的调试技术
7.1 代码清单7-1 7.2 跳过非指令的数据区 7.3 在数据声明中使用字面值 7.4 段地址的初始化 7.5 段之间的批量数据传送 7.6 使用循环分解数位 7.7 计算机中的负数 7.8 数位的显示 7.9 其他标志位和条件转移指令
8.1 从1加到100的故事 8.2 代码清单8-1 8.3 显示字符串 8.4 计算1到100的累加和 8.5 累加和各个数位的分解与显示 8.6 程序的编译和运行 8.7 8086处理器的寻址方式 本章习题
3.1 寄存器和字长 3.2 内存访问和字节序 3.3 古老的INTEL 8086处理器 本章习题
4.1 汇编语言程序 4.2 NASM编译器 4.3 配书文件包的下载和使用 本章习题
第6章 编写主引 导扇区代码
第5章 虚拟机的 安装和使用
第7章 相同的功 能,不同的代码
第8章 比高斯 更快的计算
精彩摘录
这是《x86汇编语言:从实模式到保护模式(第2版)》的读书笔记模板,可以替换为自己的精彩内容摘录。

Linux0.11——从实模式到保护模式

Linux0.11——从实模式到保护模式

Linux0.11——从实模式到保护模式综述最近在阅读Linux 0.11的源码时,对于setup.s⽂件中设置GDT表的部分不是很理解,后来经过刘国军⽼师的指点,结合赵炯博⼠的《Linux内核完全注释》的第四章《80X86保护模式及其编程》,对于保护模式有了⼀些粗浅的了解和认识。

备忘。

本⽂章主要讲解保护模式的寻址机制与setup.s中的切换部分。

保护模式保护模式运⾏在80286及其之后的所有CPU上,但是为了保证向前兼容性,正常的CPU在启动时并不会默认进⼊保护模式,⽽是会进⼊实模式,随后通过⼀系列设定转⼊保护模式。

在16位实模式下,CPU寻址时使⽤16位段寄存器的内容乘以16当作段基地址,加上16位段偏移地址形成20位的物理地址,所以最⼤寻址仅为1MB字节,最⼤段长度64KB。

在实模式下,所有的段都是可以任意访问的,即任意读、写和执⾏。

虽然在80286点CPU上已经出现了保护模式,但是其寄存器的位宽仍然是16位,只不过其地址线由20位扩⼤到了24位,寻址空间随即扩⼤到了16MB。

真正的32位保护模式出现在80386上,其地址总线和寄存器都是32位宽的,因此寻址空间扩⼤到了4GB。

保护模式下,CPU寻址主要有两种模式,⼀是分段模式,⼆是分段和分页相结合,分页⽆法单独出现。

保护模式的分段模式为每⼀段增加了段属性来限制⽤户程序对内存中⼀些段的操作。

在全局描述符表(GDT)中,每个段的表项存储了⼀个段的基本属性,例如段的基地址、段的界限、段的类型(代码段、数据段)、段的执⾏权限等。

分页模式的出现使得程序员可以编写远远⼤于内存的程序⽽⽆需担⼼内存的容量,在该模式下,内存被划分为“页”存储,磁盘的⼀部分⽤作虚拟内存,当应⽤程序执⾏时需要的某些代码或数据所在的页不在内存中时,CPU就会产⽣⼀个缺页异常,从磁盘中将所需的页调⼊内存中后恢复执⾏,在应⽤程序看来,所需的代码或数据仿佛⼀直存在内存上。

重要数据结构在保护模式中,有⼏个长得很像的名字⼀直是我们⼼头噩梦:GDT、GDTR、LGDT、LDT、LDTR、LLDT……事实上,并不是那么难区分。

保护模式详解

保护模式详解

保护模式详解在ia32下,cpu有两种⼯作模式:实模式和保护模式。

在实模式下,16位的寄存器⽤“段+偏移”的⽅法计算有效地址。

段寄存器始终是16位的。

在实模式下,段值xxxxh表⽰的以xxxx0h开始的⼀段内存。

但在保护模式下,段寄存器的值变成了⼀个索引(还有附加信息)这个索引指向了⼀个数据结构的表(gdt/ldt)项,表项(描述符)中详细定义了段的其实地址、界限、属性等内容。

保护模式需要理解:描述符,选择⼦描述符包括,存储段描述符(代码段,数据段,堆栈段),系统描述符(任务状态段TSS,局部描述符表LDT),门描述符(调⽤门,任务门,中断门,陷阱门),下⾯以存储段描述符位例我们看⼀下描述符的结构:描述符共8个字节:0,1字节是段界限(2字节)2,3,4字节是段基址的低24位(3字节)5,6字节是段基址的属性(2字节)7字节是段机制的⾼8位(1字节)属性:(1) P:存在(Present)位。

P=1 表⽰描述符对地址转换是有效的,或者说该描述符所描述的段存在,即在内存中;P=0 表⽰描述符对地址转换⽆效,即该段不存在。

使⽤该描述符进⾏内存访问时会引起异常。

(2) DPL: 表⽰描述符特权级(Descriptor Privilege level),共2位。

它规定了所描述段的特权级,⽤于特权检查,以决定对该段能否访问。

(3) DT:说明描述符的类型。

对于存储段描述符⽽⾔,DT=1,以区别与系统段描述符和门描述符(DT=0)。

(4) TYPE: 说明存储段描述符所描述的存储段的具体属性。

数据段类型类型值说明----------------------------------0只读1只读、已访问2读/写3读/写、已访问4只读、向下扩展5只读、向下扩展、已访问6读/写、向下扩展7读/写、向下扩展、已访问选择⼦的结构:RPL(Requested Privilege Level): 请求特权级,⽤于特权检查。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

段机制轻松体验(实模式和保护模式)[内存寻址]实模式下的内存寻址:让我们首先来回顾实模式下的寻址方式段首地址×16+偏移量=物理地址为什么要×16?因为在8086CPU中,地址线是20位,但寄存器是16位的,最高寻址64KB,它无法寻址到1M内存。

于是,Intel设计了这种寻址方式,先缩小4位成16位放入到段寄存器,用到时候,再将其扩大到20位,这也造成了段的首地址必须是16的倍数的限制。

保护模式下分段机制的内存寻址:保护模式下分段机制是利用一个称作段选择符的偏移量,从而到描述符表找到需要的段描述符,而这个段描述符中就存放着真正的段的物理首地址,再加上偏移量一段话,出现了三个新名词:1、段选择子2、描述符表3、段描述符我们现在可以这样来理解这段话:有一个结构体类型,它有三个成员变量:段物理首地址段界限段属性内存中,维护一个该结构体类型的是一个数组。

而分段机制就是利用一个索引,找到该数组对应的结构体,从而得到段的物理首地址,然后加上偏移量,得到真正的物理地址。

公式:xxxx:yyyyyyyy其中,xxxx也就是索引,yyyyyyyy是偏移量(因为32位寄存器,所以8个16进制)xxxx 存放在段寄存器中。

现在,我们来到过来分析一下那三个新名词。

段描述符,一个结构体,它有三个成员变量:1、段物理首地址2、段界限3、段属性我们再来重温一遍描述符表,也就是一个数组,什么样的数组呢?是一个段描述符组成的数组。

接下来看看段选择子:段选择子,也就是数组的索引,但这时候的索引不再是高级语言中数组的下标,而是我们将要找的那个段描述符相对于数组首地址(也就是全局描述表的首地址)偏移位置。

就这么简单,如图:图中,通过Selector (段选择子)找到存储在Descriptor Table (描述符表)中某个Descriptor (段描述符),该段描述符中存放有该段的物理首地址,所以就可以找到内存中真正的物理段首地址SegmentOffset (偏移量):就是相对该段的偏移量 物理首地址+偏移量就得到了物理地址 本图就是DATA 。

但这时,心细的朋友就发现了一个GDTR 这个家伙还没有提到!我们来看一下什么是GDTR ? Global Descriptor Table Register (全局描述符表寄存器)但是这个寄存器有什么用呢?大家想一下,段描述符表现在是存放在内存中,那CPU 是如何知道它在哪里呢?所以,Intel 公司设计了一个全局描述符表寄存器,专门用来存放段描述符表的首地址,以便找到内存中段描述符表。

这时,段描述符表地址被存到GDTR寄存器中了。

好了,分析就到这,我们来看一下正式的定义:当x86 CPU 工作在保护模式时,可以使用全部32根地址线访问4GB的内存,因为80386的所有通用寄存器都是32位的,所以用任何一个通用寄存器来间接寻址,不用分段就可以访问4G空间中任意的内存地址。

也就是说我们直接可以用Eip寄存器就可以找到茫茫内存里面所有的值!但这并不意味着,此时段寄存器就不再有用了[其实还有部分原因是要与8086兼容。

实际上,段寄存器更加有用了,虽然在寻址上没有分段的限制了,但在保护模式下,一个地址空间是否可以被写入,可以被多少优先级的代码写入,是不是允许执行等等涉及保护的问题就出来了。

[想想吧,单单就是靠eip找到所有内存的值显然不够的,醒醒吧,我们到了80386时代了,我们需要保护模式,要指示出来那些内存段是操作系统核心用的,那些是你打游戏时用的,打游戏时的CPU不能访问到操作系统核心所用的内存段。

我们需要分出"级别"来] 。

要解决这些问题,必须对一个地址空间定义一些安全上的属性。

段寄存器这时就派上了用场。

但是设计属性和保护模式下段的参数,要表示的信息太多了,要用64位长的数据才能表示。

我们把这64位的属性数据叫做段描述符,上面说过,它包含3个变量:段物理首地址、段界限、段属性,80386的段寄存器是16位(注意:通用寄存器在保护模式下都是32位,但段寄存器没有被改变,比如CS还是16位的,16位的段寄存器怎么可能装下一个64位的段描述符)的,无法放下保护模式下64位的段描述符。

如何解决这个问题呢?方法是把所有段的段描述符顺序存放在内存中的指定位置,组成一个段描述符表(Descriptor Table);而段寄存器中的16位用来做索引信息,这时,段寄存器中的信息不再是段地址了,而是段选择子(Selector)。

可以通过它在段描述符表中“选择”一个项目已得到段的全部信息。

也就是说我们在另一个地方把段描述符放好,然后通过选择子来找到这个段描述符。

那么段描述符表存放在哪里呢?80386引入了两个新的寄存器来管理段描述符,就是GDTR 和LDTR,(LDTR大家先忘记它,随着学习的深入,我们会在以后学习)。

==========================================================这样,用以下几步来总体体验下保护模式下寻址的机制1、段寄存器中存放段选择子Selector2、GDTR中存放着段描述符表的首地址3、通过选择子,根据GDTR中的首地址,就能找到对应的段描述符4、段描述符中有段的物理首地址,就得到段在内存中的首地址5、加上偏移量,就找到在这个段中存放的数据的真正物理地址。

=================================好的,那我们开始编码,看看如何实现先前描述的内容首先,既然我们需要一个数组,全局描述符表,那我们就定义一块连续的结构体:[SECTION .gdt] ;为了代码可读性,我们将这个数组放到一个节中;由一块连续的地址组成的,不就是一个数组吗?看下面代码,^_^段基地址段界限段属性GDT_BEGIN: Descriptor 0, 0, 0GDT_CODE32: Descriptor 0, 0, DA_C;上面,我定义了二个连续地址的结构体,大家先认为Descriptor就是一个结构体类型,我们会在以后详细讲述;第一个结构体,全部是0,是为了遵循Intel规范,先记得就OK;第二个定义了一个代码段,段基地址和段界限我们暂且还不知道,先初始化为0,但是因为是个代码段,代码段具备执行的属性,那么DA_C就代表是一个可执行代码段,DA_C 是一个预先定义好的常量,我们会在详细讲解段描述符中讲解。

我们继续来实现,那么下面,我们就需要设计段选择子了,因为上面代码已经包含了段描述符和全局描述符表还记得选择子是个什么东西吗?段选择子:也就是数组的索引,但这时候的索引不在是高级语言中数组的下标,而是我们将要找的那个段描述符相对于数组首地址(也就是全局描述表的首地址)偏移位置。

看我代码怎么实现,包含以上代码不再说明:[SECTION .gdt]GDT_BEGIN: Descriptor 0, 0, 0GDT_CODE32: Descriptor 0, 0, DA_C;下面是定义代码段选择子,它就是相对数组首地址的偏移量SelectorCode32equ GDT_CODE32 - GDT_BEGIN;因为第一个段描述符,不被使用,所以就不比设置段选择子了。

=================================偏移地址:注意一点,我们在程序中使用的都是偏移地址,相对于段的偏移地址,用上面的例子来说,象GDT_CODE32 GDT_BEGIN 这些结构体的首地址都是相对于数据段的偏移量。

什么意思呢?因为我们的程序到底加载到内存的哪个地方是不固定,不知道的,只需使用偏移地址操作就行了,如:SelectorCode32 ,它本身就是一个偏移地址但是SelectorCode32 equ GDT_CODE32 - GDT_BEGIN怎么解释呢?GDT_CODE32是相对于数据段的偏移量,GDT_BEGIN也是相对于数据段的偏移量,虽然它是数组的首地址,说的罗索一些,GDT_BEGIN是数组的首地址,但是它是相对于数据段的偏移量那么两个偏移量相减就是GDT_CODE32 相对于GDT_BEGIN的偏移量所以,我们要时时刻刻记得,在程序中,我们永远使用的是偏移量,因为我们不知道程序将要被加载内存那块地方。

好了,基础也学的差不多了,下面我们要自己动手写一段程序,实现实模式到保护模式之间的跳转;=================================================================== ;实现从实模式到保护模式之间的跳转;参考:《自己动手写操作系统》;----------------------------------------------------------------------%include "pm.inc"org 0100hjmp LABEL_BEGIN[SECTION .gdt]GDT_BEGIN: Descriptor 0, 0, 0GDT_CODE32: Descriptor 0, LenOfCode32 - 1, DA_C + DA_32GDT_VIDEO: Descriptor 0B8000H, 0FFFFH, DA_DRWGdtLen equ $ - GDT_BEGINGdtPtr dw GdtLen - 1dd 0;定义段选择子SelectorCode32 equ GDT_CODE32 - GDT_BEGIN SelectorVideoequ GDT_VIDEO - GDT_BEGIN[SECTION .main][BITS 16]LABEL_BEGIN:mov ax, csmov ds, axmoves, axmovss, ax;初始化32位代码段选择子;我们可以在实模式下通过段寄存器×16 +偏移量得到物理地址,;那么,我们就可以将这个物理地址放到段描述符中,以供保护模式下使用,;因为保护模式下只能通过段选择子+偏移量xoreax, eaxmov ax, csshleax, 4add eax, LABEL_CODE32mov word [GDT_CODE32 + 2],axshreax, 16mov byte [GDT_CODE32 + 4],almov byte [GDT_CODE32 + 7],ah;得到段描述符表的物理地址,并将其放到GdtPtr中xoreax, eaxmov ax, dsshleax, 4add eax, GDT_BEGINmov dword [GdtPtr + 2],eax;加载到gdtr,因为现在段描述符表在内存中,我们必须要让CPU知道段描述符表在哪个位置;通过使用lgdtr就可以将源加载到gdtr寄存器中lgdt [GdtPtr];关中断cli;打开A20线in al, 92hor al, 00000010bout 92h, al;准备切换到保护模式,设置PE为1moveax, cr0or eax, 1mov cr0, eax;现在已经处在保护模式分段机制下,所以寻址必须使用段选择子:偏移量来寻址;跳转到32位代码段中;因为此时偏移量位32位,所以必须dword告诉编译器,不然,编译器将阶段成16位jmp dword SelectorCode32:0;跳转到32位代码段第一条指令开始执行[SECTION .code32][BITS 32]LABEL_CODE32:mov ax, SelectorVideomoves, axxoredi, edimovedi, (80 * 10 + 10)mov ah, 0chmov al, 'G'mov [es:edi],axjmp $LenOfCode32 equ $ - LABEL_CODE32这段代码的大概意思是:先在16位代码段,实模式下运行,在实模式下,通过段寄存器×16+偏移量得到32位代码的真正物理首地址,并将放入到段描述符表中,以供在保护模式下使用,上面说过了,保护模式下寻址,是通过段选择子,段描述符表,段描述符一起工作寻址的。

相关文档
最新文档