学习自 狄泰软件

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,实模式与保护模式切换编程相关推荐

  1. 深入理解计算机系统-之-内存寻址(二)--存储保护机制(CPU实模式与保护模式)

    cpu的保护模式由来 分段机制 8086的诞生,标志着Intel 正式进入了x86时代,这是个多么具有纪念意义的日子:1978-6-8.同时,8086的诞生也是处理器内存寻址技术的第一次飞跃. 对于一 ...

  2. ASM:《X86汇编语言-从实模式到保护模式》第10章:32位x86处理器的编程架构

    ★PART1:32位的x86处理器执行方式和架构 1. 寄存器的拓展(IA-32) 从80386开始,处理器内的寄存器从16位拓展到32位,命名其实就是在前面加上e(Extend)就好了,8个通用寄存 ...

  3. 实模式和保护模式区别及寻址方式

    64KB-4GB-64TB? 我记得大学的汇编课程.组成原理课里老师讲过实模式和保护模式的区别,在很多书本上也有谈及,无奈本人理解和感悟能力实在太差,在很长一段时间里都没真正的明白它们的内含,更别说为 ...

  4. MIT-JOS系列1:实模式和保护模式下的段寻址方式

    实模式下的段寻址 以8086为例 8086 段寄存器16位(段地址/基地址),寄存器16位(偏移地址),地址总线20位(寻址1M:2^20) 实际物理地址 = (段寄存器 << 4) + ...

  5. Linux下的实模式和保护模式

    实模式:(即实地址访问模式)它是Intel公司80286及以后的x86(80386,80486和80586等)兼容处理器(CPU)的一种操作模式.实模式被特殊定义为20位地址内存可访问空间上,这就意味 ...

  6. x86从实模式到保护模式 pdf_【自制操作系统04】从实模式到保护模式

    通过前三章的努力,我们成功将控制权转交给了 loader.asm 这个程序.具体说就是 bios 通过加载并跳转到 0x7c00(IMB大叔们定的) 把控制权转交给了我们操作系统的第一个汇编程序 mb ...

  7. X86汇编语言从实模式到保护模式11:指令格式及操作尺寸

    目录 1. 80286的16位保护模式 1.1 80286寄存器 1.2 80286段描述符 1.3 80286保护模式内存访问 2. 指令操作尺寸 2.1 指令操作尺寸的概念 2.2 16位处理器的 ...

  8. 【操作系统 3.了解实模式与保护模式的区别】

    一.实模式与保护模式鸟瞰 我这人喜欢直面问题,其实本章只需要搞明白三个主要问题就行了, 什么是实模式和保护模式, 实模式与保护模式的区别是什么, 怎么进入保护模式. 我先来简单阐述下这三个问题 什么是 ...

  9. X86实模式与保护模式简介

    0 引言 从80386开始,CPU有三种工作方式:实模式,保护模式和虚拟8086模式(v86模式).只有在刚刚启动的时候是real-mode,等到操作系统运行起来以后就切换到protected-mod ...

  10. 实模式、保护模式和虚拟8086模式

    参考自:实模式与保护模式解惑之(一)--二者的起源与区别(河西无名式) 概述:实模式和保护模式是处理器发展的两个非常重要的阶段.这两个模式下的编程也有着显著的不同,弄明实模式与保护模式的区别是理解操作 ...

最新文章

  1. 【 MATLAB 】使用 filter 函数产生给定线性时不变系统的单位阶跃响应
  2. Exchange 2013部署系列之(三)分角色部署
  3. apache kafka技术分享系列(目录索引)--转载
  4. MyBatis关联查询,表字段相同,resultMap映射问题的解决办法
  5. .NET Core跨平台的奥秘[中篇]:复用之殇
  6. R-apply()函数
  7. Pytorch的BatchNorm层使用中容易出现的问题
  8. Struts2初始化过程代码分析
  9. 信奥中的数学:斯特林数、卡特兰数
  10. 【Kafka】kafka Removed ✘✘✘ expired offsets in ✘✘✘ milliseconds.
  11. 【逆向知识】VS程序反汇编找main函数
  12. OAUI前台设计(二)
  13. 云视频安防监控解决方案
  14. SpacePack 运维工具之 Auto fdisk
  15. 开源盛世:谈谈开源代码的使用与安全风险
  16. 根据RGB配色改变图片颜色
  17. 如何成为一个合格的聚合支付代理商
  18. 闲人博上介绍R语言的一篇好文章
  19. android 自动翻页插件,网页自动翻页Chrome插件下载
  20. 数学建模用python好吗_用 Python 做数学建模

热门文章

  1. DNS各地延迟排行榜
  2. 最短哈密尔顿圈matlab解法_数学建模学习笔记
  3. 关于怎样写商业计划书
  4. imageJ如何在视频每一帧中添加text
  5. 全国青少年软件编程等级考试内容,知识点思维导图(Scratch编程三级)
  6. python dataframe的某一列变为list_手把手教你用Python爬中国电影票房数据
  7. 1563页Go语言中文文档,涵盖Go语言所有核心知识点
  8. 利用PS将图片上的中文改写成英文
  9. SAP ABAP Loop…Assigning与Loop…Into的比较
  10. 计算机桌面上的照片转pdf免费,电脑上怎样快速将图片转PDF