80286 与 80386,实模式与保护模式切换编程
学习自 狄泰软件
1 EAX与AX不是独立的,EAX是32位的寄存器,而AX是EAX的低16位。
2 or 对两个操作数进行逻辑(按位)或操作
3
word 两个字节 16位
dword 四个字节 32位
80286 虽然有了保护模式,但其依然是 16 位的 CPU ,其通用寄存器还是 16 位宽,但其与 8086 不同的是其地址线由 20 位变为了 24 位,即寻址空间变成了 24 次方,等于 16MB 大小。虽然80286可以将地址线变成了24位,可以访问16MB的内存,但是其用来寻址的通用寄存器还是16位的,也没有突破一个寄存器只能访问64kb空间的限制,如果用寄存器来进行地址访问,那么,想访问16MB的内存,就需要不断地变换段基址,所以很快就被淘汰了。
80286的缺陷
单独的一个寄存器无法访问到全部内存空间, 也就是若用寄存器存储段内偏移地址
只能访问到 64kb大小的段。
改革背景
每次 CPU 变革的原因几乎都是地址总线宽度不够导致的,即内存需求越来越大,干脆直接将地址线直接改成32位的,可以访问4GB的内存地址
1985年推出的第一个32位的微处理器,它的地址总线和寄存器都是32位的
段基址是32位的,寄存器也是32位的,这样在任意一个段都可以访问到4GB的空间了,甚至段基址地址可以是0,直接用段偏移地址就可以4GB空间的任意角落,这就开启了平坦模式的时代
8086
80286
80386
X指的是 该处理器的版本
在保护模式下,定义一个段,必须要提供段的三个要素:
1 段的起始地址
2 段的界限(段内的偏移地址的最大值)
3 段属性(如 我们平时所用的 代码段是只读的,那么它是怎么被指定成只读的呢? 就是依靠段属性!!! DA_DR标识符)
选择子的本质就是 索引,这个索引特别的是分为两部分,第一部分就是传统的索引,它的值就是0 1 2 3 4 5 … 指的就是段描述符表当中的第0项 第1项 第2项 …第n项等等,相当于数组下标。第二部分是特殊部分 ,选择子的属性:
PRL : 占用 第0位 – 第1位 是关于特权级属性,占用两位,表示4个值 0 1 2 3 ,四个级别
TI : 占用1位,是第三位 所以代表 0 或者 4
0 : GDT 表示该选择子想要去访问的段描述符是 全局段描述符
4 : LDT 表示该选择子想要去访问的段描述符是 局部段描述符
; 描述符
; usage: Descriptor Base, Limit, Attr
; Base: dd
; Limit: dd (low 20 bits available)
; Attr: dw (lower 4 bits of higher byte are always 0)
%macro Descriptor 3 ; 这个宏需要三个参数 段基址, 段界限, 段属性
dw %2 & 0xFFFF ; 段界限1 将第2个参数,段界限的低16位 排放在段描述符这8个字节的前16位上 0 - 15
dw %1 & 0xFFFF ; 段基址1 将第1个参数,段基址的低16位 排放在段描述符这8个字节的 16 - 31 位
db (%1 >> 16) & 0xFF ; 段基址2 将第1个参数,段基址第16位 – 第23位 共8位 排放在段描述符这8个字节的 32 - 39 位
; %3 & 0xF0FF 将第三个参数 段属性 的低8位 排放 段描述符的 40 - 47 位。 高4位放在 段描述符的 52 - 55 位
; (%2 >> 8) & 0xF00 将将第2个参数 段界限的 16 - 19 位 放在 段描述符的 48 - 51位
dw ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF) ; 属性1 + 段界限2 + 属性2
db (%1 >> 24) & 0xFF ; 段基址3 将第1个参数,段基址的高8位 24 - 31 排放在段描述符这8个字节 24 - 31位
%endmacro ; 共 8 字节
Descriptor 宏定义
; GDT_ENTRY标签 是全局段描述符表GDT 的入口地址
; 段基址, 段界限, 段属性
GDT_ENTRY : Descriptor 0, 0, 0
; ODE32_DESC 标签 (DA_C + DA_32 : 32位模式(保护模式)下的段,具有只执行代码段的属性)
CODE32_DESC : Descriptor 0, Code32SegLen - 1, DA_C + DA_32
;计算全局段描述附表的长度 = 当前行偏移地址 - 全局段描述符表入口地址
GdtLen equ $ - GDT_ENTRY
;可以看做一个结构体 第一个成员指定 全局段描述符表的界限,即相对入口地址 偏移的最大值。
;段描述符表 的 标识数据结构 用于加载段描述符表
GdtPtr:
dw GdtLen - 1
;GDT基地址 需要重新计算
dd 0
定义代码段,section 所定义的代码段仅限于原代码里的代码段,是未经编译的以文本的形式存在的代码段。
定义两个代码节,S1代码节先出现,所以它里面的代码先被存放,01 02 00 00,至于后面两个字节的 00,是由于代码节之间的内存对齐,从第一个代码节 切换到 第二个代码节的时候 必须四字节对齐。如下面的两个代码节 .s1 .s2 ,那么 从.s1 切换到 .s2 的时候 必须是保证四字节对齐。所以.s1 代码节所占用的内存数必须是4的整数倍, 没有的填0补齐。所以编译后 得到的结果就是右图
1
2 保护模式是从实模式转换进入的,在默认情况下就是实模式,而实模式中就是 16位的数据和代码
3 必须使用 无条件跳转指令jmp 从16位代码段 跳转到32位 代码段
makefile
.PHONY : all clean rebuildBOOT_SRC := boot.asm
BOOT_OUT := bootLOADER_SRC := loader.asm
INCLUDE_SRC := inc.asm
LOADER_OUT := loaderIMG := data.img
IMG_PATH := /mnt/hgfsRM := rm -frall : $(IMG) $(BOOT_OUT) $(LOADER_OUT)@echo "Build Success ==> D.T.OS!"$(IMG) :bximage $@ -q -fd -size=1.44$(BOOT_OUT) : $(BOOT_SRC)nasm $^ -o $@dd if=$@ of=$(IMG) bs=512 count=1 conv=notrunc$(LOADER_OUT) : $(LOADER_SRC) $(INCLUDE_SRC)nasm $< -o $@sudo mount -o loop $(IMG) $(IMG_PATH)sudo cp $@ $(IMG_PATH)/$@sudo umount $(IMG_PATH)clean :$(RM) $(IMG) $(BOOT_OUT) $(LOADER_OUT)rebuild :@$(MAKE) clean@$(MAKE) all
代码段位于 代码段,段基址位于 代码段寄存器 CS
全局段描述符表 位于数据段,段基址位于 数据段寄存器 DS
loader.asm
%include "inc.asm"
;程序起始地址
org 0x9000;无条件跳转到 CODE16_SEGMENT标签处执行
jmp CODE16_SEGMENT;定义 全局段描述符表, 描述符表中的第0个描述符不使用,仅用于占位
;定义一个名为 .gdt 的逻辑代码段 ,是源码级别的代码段
[section .gdt]
; 段基址, 段界限, 段属性;段描述符表 第0项
;定义一个段描述符GDT_ENTRY GDT_ENTRY标签 全局段描述符GDT 的入口地址,第0项不使用 仅用于占位 所以设置为0
GDT_ENTRY : Descriptor 0, 0, 0;段描述符表 第1项
;定义一个段描述符CODE32_DESC CODE32_DESC标签
;属性:32位模式(保护模式)下的段,具有只执行代码段的属性
CODE32_DESC : Descriptor 0, Code32SegLen - 1, DA_C + DA_32
; GDT end;该全局段描述附表的长度 = 当前行偏移地址 - 全局段描述符表入口地址
GdtLen equ $ - GDT_ENTRY;可以看做一个结构体 第一个成员指定 全局段描述符表的界限,即相对入口地址 偏移的最大值。
;记录全局段描述符表 起始地址
;段描述符表 的 标识数据结构 用于加载段描述符表
GdtPtr:; GDT 界限 两个字节 dwdw GdtLen - 1; GDT 基地址 四个字节 dddd 0; GDT Selector
; 定义 段描述符CODE32_DESC 的选择子
; 段描述符索引值是 1 , 属性是 SA_TIG(表示该选择子想要去访问的段描述符是 全局段描述符) + SA_RPL0(特权级 第0特权级)Code32Selector equ (0x0001 << 3) + SA_TIG + SA_RPL0; end of [section .gdt] 全局段描述附表 结束;定义实模式代码段 16位代码段,需要按照16位的方式进行编译 所以只是编译器按照16位方式进行编译 [bits 16]
[section .s16]
[bits 16]
CODE16_SEGMENT:mov ax, csmov ds, axmov es, axmov ss, ax;定义栈顶mov sp, 0x7c00; initialize GDT for 32 bits code segment ; 设置32位段基址 到 段描述符;将当前代码段寄存器值 左移4位mov eax, 0mov ax, cs;eax 左移4位shl eax, 4;段寄存器<<4) + (32位代码段 偏移地址 == 32位代码段的真实物理地址,即段基地址add eax, CODE32_SEGMENT;将 ax寄存器保存的值 拿两个字节 放到 CODE32_DESC+2 地址处, 段基址的0-15位 放到 段描述符的16-31 位mov word [CODE32_DESC + 2], ax;eax 右移16位 也就是低16位被移出去了shr eax, 16; al(ax低8位) 此时al是32位代码段基地址当中的第三个字节(段基址 16-23位) 放到 段描述符的32-39位mov byte [CODE32_DESC + 4], al; ah(ax高8位) 此时ah是32位代码段基地址当中第四个字节(段基址 24-31位) 放到 段描述符的55-63位 第七个字节mov byte [CODE32_DESC + 7], ah; initialize GDT pointer struct ; 全局段描述符表 起始地址mov eax, 0mov ax, ds;将 段寄存器值 左移4位shl eax, 4;段寄存器<<4) + (段描述符GDT_ENTRY 偏移地址 == 段描述符GDT_ENTRY 的真实物理地址add eax, GDT_ENTRY; 段描述符GDT_ENTRY 的真实物理地址 放到 GdtPtr 结构体第二个字节出 代表 GDT 基地址mov dword [GdtPtr + 2], eax; 1. load GDT 加载全局段描述符表 lgdt指定 GdtPtr结构lgdt [GdtPtr]; 2. close interrupt 关闭中断,因为现在马上要跳转到保护模式了cli ; 3. open A20 打开 A20 地址线in al, 0x92or al, 00000010bout 0x92, al; 4. enter protect mode 通知处理器进入保护模式 将某个寄存器对应位置1mov eax, cr0or eax, 0x01mov cr0, eax; 5. jump to 32 bits code 从16位的实模式 跳转到 32位的保护模式; 注意 这里使用的是选择子,用来访问 全局段描述符表里面 第2项段描述符 CODE32_DESC段描述符 它记录了32位代码段(保护模式代码段)的起始地址,界限,属性等等。; 使用选择子进行跳转 ,得到32位代码段 段描述符的内容(CODE32_DESC),根据内容 得到段基址 再加上段内偏移地址0 就是真实的32位代码段的入口地址jmp dword Code32Selector : 0;定义保护模式代码段 32位代码段,需要按照32位的方式进行编译 所以只是编译器按照32位方式进行编译 [bits 32]
[section .s32]
[bits 32]
; 32位代码段 段基址
CODE32_SEGMENT:mov eax, 0jmp CODE32_SEGMENTCode32SegLen equ $ - CODE32_SEGMENT
inc.asm
; Segment Attribute 段属性定义
DA_32 equ 0x4000
DA_DR equ 0x90
DA_DRW equ 0x92
DA_DRWA equ 0x93
DA_C equ 0x98
DA_CR equ 0x9A
DA_CCO equ 0x9C
DA_CCOR equ 0x9E; Selector Attribute 选择子属性定义
SA_RPL0 equ 0
SA_RPL1 equ 1
SA_RPL2 equ 2
SA_RPL3 equ 3SA_TIG equ 0
SA_TIL equ 4; 描述符 段描述符所需要的宏
; usage: Descriptor Base, Limit, Attr
; Base: dd
; Limit: dd (low 20 bits available)
; Attr: dw (lower 4 bits of higher byte are always 0)
%macro Descriptor 3 ; 段基址, 段界限, 段属性dw %2 & 0xFFFF ; 段界限1dw %1 & 0xFFFF ; 段基址1db (%1 >> 16) & 0xFF ; 段基址2dw ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF) ; 属性1 + 段界限2 + 属性2db (%1 >> 24) & 0xFF ; 段基址3
%endmacro ; 共 8 字节
80286 与 80386,实模式与保护模式切换编程相关推荐
- 深入理解计算机系统-之-内存寻址(二)--存储保护机制(CPU实模式与保护模式)
cpu的保护模式由来 分段机制 8086的诞生,标志着Intel 正式进入了x86时代,这是个多么具有纪念意义的日子:1978-6-8.同时,8086的诞生也是处理器内存寻址技术的第一次飞跃. 对于一 ...
- ASM:《X86汇编语言-从实模式到保护模式》第10章:32位x86处理器的编程架构
★PART1:32位的x86处理器执行方式和架构 1. 寄存器的拓展(IA-32) 从80386开始,处理器内的寄存器从16位拓展到32位,命名其实就是在前面加上e(Extend)就好了,8个通用寄存 ...
- 实模式和保护模式区别及寻址方式
64KB-4GB-64TB? 我记得大学的汇编课程.组成原理课里老师讲过实模式和保护模式的区别,在很多书本上也有谈及,无奈本人理解和感悟能力实在太差,在很长一段时间里都没真正的明白它们的内含,更别说为 ...
- MIT-JOS系列1:实模式和保护模式下的段寻址方式
实模式下的段寻址 以8086为例 8086 段寄存器16位(段地址/基地址),寄存器16位(偏移地址),地址总线20位(寻址1M:2^20) 实际物理地址 = (段寄存器 << 4) + ...
- Linux下的实模式和保护模式
实模式:(即实地址访问模式)它是Intel公司80286及以后的x86(80386,80486和80586等)兼容处理器(CPU)的一种操作模式.实模式被特殊定义为20位地址内存可访问空间上,这就意味 ...
- x86从实模式到保护模式 pdf_【自制操作系统04】从实模式到保护模式
通过前三章的努力,我们成功将控制权转交给了 loader.asm 这个程序.具体说就是 bios 通过加载并跳转到 0x7c00(IMB大叔们定的) 把控制权转交给了我们操作系统的第一个汇编程序 mb ...
- X86汇编语言从实模式到保护模式11:指令格式及操作尺寸
目录 1. 80286的16位保护模式 1.1 80286寄存器 1.2 80286段描述符 1.3 80286保护模式内存访问 2. 指令操作尺寸 2.1 指令操作尺寸的概念 2.2 16位处理器的 ...
- 【操作系统 3.了解实模式与保护模式的区别】
一.实模式与保护模式鸟瞰 我这人喜欢直面问题,其实本章只需要搞明白三个主要问题就行了, 什么是实模式和保护模式, 实模式与保护模式的区别是什么, 怎么进入保护模式. 我先来简单阐述下这三个问题 什么是 ...
- X86实模式与保护模式简介
0 引言 从80386开始,CPU有三种工作方式:实模式,保护模式和虚拟8086模式(v86模式).只有在刚刚启动的时候是real-mode,等到操作系统运行起来以后就切换到protected-mod ...
- 实模式、保护模式和虚拟8086模式
参考自:实模式与保护模式解惑之(一)--二者的起源与区别(河西无名式) 概述:实模式和保护模式是处理器发展的两个非常重要的阶段.这两个模式下的编程也有着显著的不同,弄明实模式与保护模式的区别是理解操作 ...
最新文章
- Hide the common top menu in Ubuntu 12.04
- 【运维】阿里云宝塔面板部署JavaWeb项目
- SerfJ REST
- libgdx 3D 测试一
- Java实现Runnable接口创建多线程
- Github 大牛封装 Python 代码,实现自动发送邮件只需三行代码
- 欢迎来到我的第一个个人laravel尝试论坛项目,给予评价和建议 谢谢。
- 电脑pin码忘了登录不进系统_想要大屏打王者,家里电视用不了?投屏到电脑试试...
- 阅读总结:如何在生产中成功运用Docker
- (九)linux中断编程
- HDU 2340 - Obfuscation(dp)
- 【SQL】CONNECT BY 层次化查询
- easymock使用方法_EasyMock静态方法– PowerMock,JUnit 4,TestNG
- ssm整合(crm案例)
- 利用shell删除labelme打错的标签
- “造星工厂“乐华娱乐IPO,如何寻找下一个“王一博“?
- 深入了解Unity剔除(草稿)
- Python简单绘制柱状图
- pygame小游戏——中国地图拼图小游戏
- 《Ensemble Learning Methods for Deep Learning Neural Networks》笔记
热门文章
- 解决win10自动锁屏问题的一个方法
- 1-MySQL事务特性
- 计算机历史记录无法删除,win10时间线灰色浏览记录删不掉怎么回事_win10时间线历史灰色无法删除的解决教程-win7之家...
- 计算机怎么快捷截图桌面,屏幕截屏的快捷键是什么 6种电脑截图快捷键操作方法...
- 大胖子走迷宫【第十届】【决赛】
- python多条件选股_通达信几种实用的条件选股公式,一旦掌握,至少翻翻!
- python 绘图库_Python安装可视化绘图库,你真的会了吗?一文告诉你全部
- 阿里巴巴高级Java面试题(首发,70道)
- UltraISO 软碟通制作 Windows 7 系统 U 盘启动盘
- 需求分析与原型图设计