精华内容
下载资源
问答
  • x86实模式到保护模式 李忠 王晓波 第3到4章 各个进制间的转换省略 实验环境 编译器 nasm 虚拟机 virtual box 小程序 hexview 观察编译后的机器代码 fixvhdwr 向虚拟硬盘写入数据 计算机启动简介 cpu的引脚 ...

    x86实模式到保护模式  李忠 王晓波

    第3到4章
    各个进制间的转换省略
    实验环境
    编译器  nasm
    虚拟机 virtual box
    小程序  hexview   观察编译后的机器代码
    fixvhdwr 向虚拟硬盘写入数据
    计算机启动简介
    cpu的引脚  reset    接受复位信号   电平由低变高时    cpu进行硬件的初始化  
    cs的内容为0xffff     其余寄存器为0
    内存   dram  随机访问存储器
    rom  只读存储器    例如bios系统需要无电存储
    8086   可以访问1m的空间  因为20位地址线
    1m的空间从物理上分为00000-9ffff位内存使用   占据较低的640k空间
    rom占用较低的64k   物理地址为f0000-fffff地址空间    而中间的一部分分为外围的部分板卡使用
    注意一旦ip位0x000f   那么cs组合后形成的物理地址因为一处而变成00001   将回到1m内存的最低端
    所以rom中位于物理地址0xffff0的地方  通常是一个跳转指令
    硬盘介绍
    硬盘分多个盘片  有中轴带动转动   上下两个盘面  分别有两个磁头   所有的磁头链接到机械臂上   当盘面转动时磁头每步进一次   都会在盘面上绕着中轴 画出一个圆圈   此为磁道  tarck      所有的磁头联动   所有盘面上的相同磁道组合在一起 形成一个虚拟的圆柱  称为柱面   cylinder   
    磁道   柱面   盘片   磁头都需要编号  
    磁头从0开始    磁道从0开始(最外圈)   盘片从1开始  (上下两个面)
    每个磁道还分为扇区     编号从1开始每扇区512字节   为存储数据的最小单位
    数据存取顺序:0磁头  0磁道写满后  再写1磁头0磁道 再2磁头0磁道   0好磁道组成的柱面写满后
    再写0磁头1磁道    1号柱面写满后  依次顺延  写3好柱面
     
    一切的开始从主引导扇区开始
    rom将硬盘的主引导扇区的内容写到内存地址为0x0000:0x7c00的位置   然后jmp  0x0000:0x7c00   指令进行跳转
     
    第5章
    编写主引导扇区的代码

    转载于:https://www.cnblogs.com/dongguolei/p/7896471.html

    展开全文
  • 操作系统的启动,英文称为bootstrap,又有汉译为“自举”,这...即使第一条指令成功运行,如何把操作系统从外存加载内存,以便执行一开始的初始化行为。 这两个问题都有了成熟的解决机制,为操作系统的启动铺设

    操作系统的启动,英文称为bootstrap,又有汉译为“自举”,这一个自指涉的词汇生动地描述了操作系统启动前所遇的矛盾:

    • 加电瞬间所有硬件处于一种随机状态,如何完成第一条指令的加载,如何了解整机的硬件状态,以便完成后续的操作系统启动。

    • 即使第一条指令成功运行,如何把操作系统从外存加载到内存,以便执行一开始的初始化行为。

    这两个问题都有了成熟的解决机制,为操作系统的启动铺设好了真正环境,分别是采取BIOS[1]和引导程序的解决方案。本文将从操作系统角度, 详述x86平台上与Linux内核启动过程悉悉相关的从实模式(virtual mode)保护模式(proctected mode)的演变过程, 以及x86平台上的Linux内核启动协议的变化。

    洪荒时代: 实模式

    从实模式到保护模式的变化,不仅是Intel处理器的一部发家史,更是30年来PC处理器的发展史。

    Intel处理器从4004的开基立业,到8008的初露锋芒,再到8080的引起哄动,标记着PC时代的曙光已经到来。1978年推出首枚16位处理器8086; 同年,又趁热打铁地推出性能更出色的8088处理器。该处理器的特点是把地址线扩展到到20条,由此可以寻址1M字节的内存空间(220=1M)。出于向后兼容的要求,该处理器的设计别出心裁,引入了很多人耳熟能详的“段”的概念,即把20位的物理地址划分为称为16位的段:16位的段内偏移。还引入了段寄存器,用以配合完成段基址 << 4 + 段内偏移到20位物理地址转换过程, 如图。

    1. 段基址: 0x1F21 << 4 + 段内偏移: 0x1027 = 物理地址: 0x 2 0 2 3 7
    2. 0x 1 F 2 1 0
    3. + 0x 1 0 2 7
    4. --------------
    5. 0x 2 0 2 3 7

    这种模式就叫做实模式(real mode), 它有以下几个问题:

    • 显然, 这种寻址方法的最大寻址值是(0xFFFF : 0xFFFF =)0x10FFEF, 这比20位地址总线能寻址的1M字节范围还大0xFFEF字节。该CPU采取的方法是Wrap Around**, 即对1M取模, 因此, 多出的0x100000 - 0x10FFEF实际是映射到0x0 - 0xFFEF。

    • 从地址构造模式看, 可以发现段基址有个特征,其低4位全为0,也就是说每个段的起始地址一定是16的整数倍, 这反映了这个名字的由来, 物理地址空间已经被人为地划分为64k(216)为大小的区间。但注意, 这只是一个人为的划分, 换句话说, 没有任何硬件机制的隔离, 一个进程只要修改段基址寄存器的内容, 就可以随意访问其他段的内容! 这是一个重大的安全漏洞。

    • 这种地址构造模式还有另一个问题, 也就是一个物理地址可以有多种表示方法。注意最终的物理地址中间12位是段基址和段内偏移重合的, 所以, 理论上最多可以有212种组合方式可以构造出同一个物理地址!

    文明时代: 保护模式

    保护模式的滥觞: 80286

    1982年, 伴随着Intel处理器史上最后一枚16位处理器80286的发布, 一种新的模式被引入了, 即为保护模式(proctected mode)。这一处理器地址总线宽度提高到了24位, 这意味着可以寻址(224=)16M字节的空间。不过前面说它仍然是16位的处理器, 因为它向后兼容, 仍然实现了前述的段寻址模式: 16位的段基址 : 16位的段内偏移。不同的是, 这枚CPU能够对内存及一些其他外围设备做硬件级的保护, 限制了一些非法地址的访问, 从而实现了硬件机制上的保护, 这也是这种名字的由来。

    该处理器的更大意义是, 它出于向后兼容的需要, 开启了操作系统启动时从实模式保护模式切换这一传统, 一直沿续至今。前面说过实模式的第一个问题, 就是地址的回绕(wrap around), 在80286的引入后, 更增添了许多麻烦: 现在已经能寻址最多16M字节的空间了, 不存在超过1M要回绕这一问题了。但是, 在机器刚开始启动的时候, 仍处于实模式, 只能访问1M字节的空间, 意味着此时A20 - A23这4根地址线是用不到的。于是, Intel采用了一种叫A20 Gate的解决方案:

    • 在系统开机时, CPU复位, 这A20-A23置为0, 即A20 Gate被禁用,则对0x100000-0x10FFEF之间的地址进行寻址时,还是取模(回绕),从0开始访问内存。

    • 在进入保护模式后, 24根地址线全部启用, 即A20 Gate被开启,则对0x100000-0x10FFEF之间的地址进行寻址时,访问实际的地址对应的物理内存。

    保护模式的辉煌: 32位处理器时代

    1985年,Intel推出了里程碑式的80386处理器, 也开启了一个称为i386x86的光辉时代。这枚处理器不仅是首枚32位处理器,还引入分页模式,而分页模式是现代操作系统实现虚拟内存的先决条件。

    同样为了向后兼容,80386保留了段机制, 但在保护模式下, 此时的16位段寄存器[2]存放的不再是段基址,而是一个13位的索引值,指向一张叫全局描述符表(GDT)局部描述符表(LDT)的某一项,表项长8字节, 包含着32位的段基址, 段长度, 段的访问权限之类的信息。前述的16位寄存器除了13位索引值外,剩下的两位(0-1)表示请求权限,一位(2)表示高13位是GDT还是LDT的索引值。此时的段寄存器被称为段选择子(selector)。 于是, 使用兼容的段基址和1段内偏移的方式, 通过一个间接的GDT表或LDT表, 从中取出段基址, 再加上段内偏移, 形成一个32位的地址。

    • 如果分布模式有启用, 这个地址就叫做线性地址(linear address), 要通过分页单元进一步处理, 形成最终的物理地址。

    • 如果分布模式没启用, 这个地址就是最终的物理地址。

    Linux内核启动协议

    Linux在X86平台上的启动协议随着内核的发展及硬件的发展,已经变得很复杂(详见内核源代码树Documentation/x86/boot.txt)。总的来说,启动协议分为旧内核(zImage)时代大内核(bzImage)时代(从协议2.0开始,已经发展到2.10)。接着将简要介绍这两种协议。

    旧内核(zImage)时代

    在旧内核时代(内核版本< 1.3.73),Linux内核映像还较小(zImage)。此时典型的物理内存布局如图1所示:

    1. | |
    2. 0A000 +------------------------+
    3. | Reserved for BIOS | Do not use. Reserved for BIOS EBDA.
    4. 09A000 +------------------------+
    5. | Command line |
    6. | Stack/heap | For use by the kernel real-mode code.
    7. 098000 +------------------------+
    8. | Kernel setup | The kernel real-mode code.
    9. 090200 +------------------------+
    10. | Kernel boot sector | The kernel legacy boot sector.
    11. 090000 +------------------------+
    12. | Protected-mode kernel | The bulk of the kernel image.
    13. 001000 +------------------------+
    14. | Boot loader | <- Boot sector entry point 0000:7C00
    15. 001000 +------------------------+
    16. | Reserved for MBR/BIOS |
    17. 000800 +------------------------+
    18. | Typically used by MBR |
    19. 000600 +------------------------+
    20. | BIOS use only |
    21. 000000 +------------------------+
    图1: 旧内核时代物理内存布局

    从图中看出,最高内存是0x0A000,即640K。这个数字历史缘于上世纪80年代,当时IBM所推出的第一台PC机采用的是前述的Intel 16位8088芯片,可供寻址的物理内存总共为1MB。这1MB中的低640KB供DOS以及应用程序使用,而高端的384KB则被留作它用,其中低端的640KB被称为常规内存(normal memory),高端的384KB则被称为保留内存(reserved memory),这两种不同的内存类型通过物理地址0xA0000得以分隔,此后这个分界线便被确定下来并沿用至今。

    下面将结合linux-0.1.1版本的启动代码及上图,简述旧内核(zImage)时代启动协议。

    • 从0x00000至0x01000这4k空间主要是保留给BIOS使用,存放加电自检期间检查到的系统硬件配置。比如BIOS在初始化硬件时,会把中断向量初始化放在地址0开始的物理内存处。

    • 接下来从0x01000开始,就是可以存放引导程序的地方。引导程序负责把内核映像加载到内存,再将控制权交给内核。BIOS在完成其加电自检(POST), 检测外围设备等工作后, 就把磁盘设备上的MBR(Master Boot Record)加载到物理地址0x07c00处(而不是恰好在0x01000)。其实MBR正是存放着引导程序。MBR块是硬盘第一个扇区,它的大小只有512字节。如此小的引导程序能把内核映像加载到内存吗? 在Linux初期,内核映像(zImage,有别于后来的大内核bImage)是很小的, 比如0.1.1版本内核的大小才196KB。所以,512byte的引导程序是可以把内核映像加载到内存的,这部分代码对应于之前的/boot/boot_sect.S这个文件,从名字可以看出,boot sector意即启动扇区,正是指MBR块。它在编译后大小刚好为512字节,能放在MBR块处。

    • 从图1中可以看出0x90000-0x90200处标明为内核启动扇区,为何此处又有一个大小为0x200(刚好512字节)的启动扇区块? 其实,前述的boot_sect.S文件,不仅做的是加载内核映像,它的第一步动作是把自身从0x7c00复制到0x9000处, 再加载实模式内核模块kernel setup, 最后才加载保护模式映像模块system。至于为何要移动自身这一步动作,是因为后续的加载setup模块动作加载到0x90200,需要用到跳转指令,而实模式下一个段大小64k, 所以boot_sect.S必须把自身移动到距离加载setup模块一个段距离内。

    • 接下来可以看到从0x90200处开始是kernel setup区域。boot_sect.S移动自身到0x9000后,会继而从硬盘紧接着放MBR块的kernel setup模块(占4扇区)加载到0x90200处。这个setup模块是内核实模式代码,由/boot/setup.S文件编译而成。它的作用是把BIOS加电自检时保存在最开始(0x0处)的硬件信息复制到一个安全的地方(0x9000处,没错,将会覆盖boot_sect块,但此时boot_sect已经执行完毕,没有用处了), 以备内核接着使用。

    • 接着kernel setup模块会把保护模式内核映像(由boot_sect.S加载的system模块,加载在0x1000处,从图中亦可印证)整体移动到物理地址0x00000处。此外,为了为接下来的system模块在保护模式下运行,还要进行临时设置中断描述符表(IDT)和全局描述符表(GDT)的操作。从图中可看到,从0x98000开始开辟作为实模式下的setup模块使用的栈空间, 以作为之后C语言接手系统后, 各个函数的活动空间。

    • 最后, 系统的控制交割给保护模式下的system模块,由它完成更多的系统初始化功能,此处不再赘述。

    以上整个过程如图2所描述。

    图片

    图2: 旧内核时代启动过程内核在内存中的位置变化

    大内核(bzImage)时代

    随着内核的发展,内核体积也越来越庞大,进入了大内核时代。像旧时代靠内核自身的512字节的引导程序已经无法完成如此复杂的功能,需要引入专门的引导程序。同时,启动协议也相应地进入了2.0时代。众所周知的引导程序有LInux LOader(LILO)及广泛使用的Grand Unified Bootloader(GRUB)。下面举例GRUB说明一下引导程序的加载内核的过程。

    • 首先执行基本的引导装载过程,该程序通常位于主引导记录(MBR)中,大小为512字节,由BIOS将其装入RAM中物理地址0x00007c00处,这就替代了旧内核时代内核自身的引程序,它的任务是建立实模式栈并利用BIOS指令将第二引导加载过程装入内存。

    • 第二引导加载过程(又称次引导过程)随后从磁盘读取可用操作系统的映射表,并提供给用户一个提示符,当用户选择需要被载入的操作系统,或是经过一段时间的延迟自动选择一个默认值之后,次引导过程便将相应分区下的内核映像以及initrd装载到内存中,而前述的映射表是GRUB通过读取/boot/grub/grub.conf文件中所设置的内容生成的。另外次引导过程还包括对特定文件系统(如ext2,ext3等)的支持以及对内核启动代码的初始化等职责,这就决定了次引导过程将占用较大的存储空间——连续多个扇区,从而无法装进单个扇区中,因此GRUB通常将该过程放在特定的文件系统中(通常是boot所在的根分区)。

    • 次引导过程拷贝到内存的目标中包括一个名为initrd的文件,该文件的全称为boot loader initialized RAM disk,即bootloader初始化内存盘。因为在Linux内核的启动过程中将会加载位于硬盘上的根文件系统,与硬盘相应的设备驱动程序又被存储在该文件系统中,这就导出一个矛盾:加载根文件系统需要使用设备驱动程序,而设备驱动程序在根文件系统加载之前又无法载入内存运行。当然解决该矛盾最简单的方法便是将设备驱动程序编译进内核,然而如今的Linux内核支持多种硬件架构,因此根文件系统可能被存储在IDE、SCSI、SATA、U盘等多种介质中,如果将所有的硬件驱动均编译进内核无疑将使得内核臃肿不堪,引入initrd正是为了解决如上问题,它主要用于实现一些模块的加载以及文件系统的安装等功能。在次引导过程完成相应文件的加载之后将会执行一个长跳转指令,该指令跳过实模式内核代码的前512个字节,也即跳到由前述链接脚本所指定的执行入口_start处开始执行,而所跳过的512字节正是我们之前剖析的Linux内核自带的引导程序,整个的衔接过程可谓天衣无缝。而内核自带的boot_sect模块已经失去了它的作用,所以,从2.6.24版本的内核开始,已经把boot_sect.Ssetup.S文件合并成为一个header.S文件。

    此时的使用2.0启动协议的bzImage内核的内存空间布局如图3所示。

    1. ~ ~
    2. | Protected-mode kernel |
    3. 100000 +------------------------+
    4. | I/O memory hole |
    5. 0A0000 +------------------------+
    6. | Reserved for BIOS | Leave as much as possible unused
    7. ~ ~
    8. | Command line | (Can also be below the X+10000 mark)
    9. X+10000 +------------------------+
    10. | Stack/heap | For use by the kernel real-mode code.
    11. X+08000 +------------------------+
    12. | Kernel setup | The kernel real-mode code.
    13. | Kernel boot sector | The kernel legacy boot sector.
    14. X +------------------------+
    15. | Boot loader | <- Boot sector entry point 0000:7C00
    16. 001000 +------------------------+
    17. | Reserved for MBR/BIOS |
    18. 000800 +------------------------+
    19. | Typically used by MBR |
    20. 000600 +------------------------+
    21. | BIOS use only |
    22. 000000 +------------------------+
    23. ... where the address X is as low as the design of the boot loader permits.
    图3: 大内核时代物理内存布局

    从图3可以看出,此时的内存大小也跟随着CPU寻址空间的扩展而增加到1M以上,但从0xA0000~0x100000-1范围内的物理内存通常保存BIOS例程,并且映射ISA图形卡上的内部内存。这个区域就是IBM兼容PC上从640KB到1MB之间的著名的洞——图1中的I/O memory hole:物理地址存在但被保留,不能由操作系统使用。

    此外,我们发现内核实模式启动扇区起始地址被定义为一个未知数X, 并且指出X的取值应是引导程序所允许的尽量低的地址值。从X开始,实模式的boot sector和setup代码,加上实模式所用作栈或堆的空间,不能超过0x9A000。因为一些新的BIOS需要使用从起始地址0x9A000开始的额外内存空间,该内存空间即扩展的BIOS数据区EBDA(Extended BIOS Data Area)。因此引导程序需要利用BIOS的”INT 12h”例程来探测该BIOS所允许的最低内存地址是多少,保证实模式内核代码空间不超过这个点,以免数据被EBDA数据区覆盖。

    最后,保护模式内核代码被加载到0x100000(即1M)处,而不是旧内核时代加载在0x10000处。这是大内核(bzImage)和小内核(zImage)的显著区别。

    * * * * * * 全文完 * * * * * *

    [1]: 现在已经有由Intel开始研发, 其后由一个专门的论坛研发维护的新标准UEFI, 用于取代老旧的BIOS。

    [2]: 其实段选择器还有32位隐藏的部分, 存放着段基址, 在第一次访问描述符表后会把当前段基址存放于此处, 用于加快访问, 所以它实际上是48位, 详见Intel文档。

    展开全文
  • X86实模式到保护模式 源代码。
  • X86汇编语言从实模式到保护模式X86汇编语言从实模式到保护模式X86汇编语言从实模式到保护模式X86汇编语言从实模式到保护模式X86汇编语言从实模式到保护模式
  • 文章目录x86寻址方式基址-偏移寻址分页寻址实模式寻址x86 分片寄存器32位保护模式寻址GDT结构GDT headGDT entry x86寻址方式 基址-偏移寻址 x86 cpu的寻址方式在历史早期主要是分片寻址(segmentation),其基本设计是...

    x86寻址方式

    基址-偏移寻址

    x86 cpu的寻址方式在历史早期主要是分片寻址(segmentation),其基本设计是任何地址由base 和 offset组成,通过将地址空间按不同规则切分成多块,每块起始地址作为base,在每个区块的偏移作为offset即可定位到具体物理地址,分片寻址在x86历史主要有两种

    • real mode
    • 32bit protect mode
      real mode(实模式) 主要用在早期16bit机器上,其寻址范围为[0, 1Mb], 32bit protect mode是从里程碑式的80386 cpu开始使用的,将寻址范围扩展到整个32位空间即[0, 4Gb].

    分页寻址

    在现代的操作系统和处理器中已经基本不再使用分片寻址方式,仅作为历史适配,更为广泛使用的是分页寻址(paging), 分页寻址将地址区分为虚拟地址和物理地址,通过页表将两者映射,这样对于编程语言而言只需要关注虚拟地址即可,因为这种情况下虚拟地址空间是完全平坦统一的,因此又被称为flat addr space(平坦地址空间).

    实模式寻址

    实模式寻址(real mode)非常简单,其形式为cs:ip,其中cs为分片寄存器(segment register),x86一共有6个分片寄存器,这里暂时只需要关注cs知道其为代码段的分片寄存器即可。cs作为基址,ipeip寄存器代表偏移值,两者的范围均为[0, 0xffff], 可以发现只使用了16位,这是因为实模式只在16位机器时代运用,现代32或者64bit机器出于适配在启动时仍然会进入模拟16bit模式以使用实模式。

    实模式下地址为addr = cs * 0x10 + ip,因此该模式下最多访问到1Mb地址空间,每个分片寻址空间为64kb。

    x86 分片寄存器

    register usage
    CS Code Segment
    DS Data Segment
    SS Stack Segment
    ES Extra Segment
    FS General Purpose Segments
    GS General Purpose Segments

    32位保护模式寻址

    32 bit protected mode 是随着80386诞生而出现的,该寻址模式将地址空间扩展到整个32bit,最大寻址4Gb,这里的保护模式指的是每个分片可以指定CPU的执行权限等级,即 cpu ring0~ ring3,这样同时增加了权限保护。

    这种模式的分片不再是固定,而是通过一个特殊格式的表来确定,称为GDT(global descriptor table), 使能时需要将该表的地址通过lgdt命令载入,GDT表的有多个entry,对应多个分片,运行时cs寄存器不再使用具体的值,而是赋值为需要的分片entry在GDT中的偏移。

    GDT结构

    GDT head

    GDT head

    • size 为所有GDT entry的大小减1,减1是因为最大size可为65536,而32bit最大只能表示65535,同时size也不会为0.
    • offset为之后的GDT entry 表的起始物理地址

    GDT entry

    在这里插入图片描述

    每个GDT entry 大小为8个byte, 其中Base一共有4个字节,范围[0, 4Gb], Limit一共占据20bit, 范围 [0, 1Mb], 剩余为一个8bit的AccessByte 和Flags,他们的结构如下:

    在这里插入图片描述

    其中每个位的详细含义可以查阅 12,其中值得关注的主要有:

    • Privi : 0~3代表CPU ring0~ring3
    • Ex: 为1代表可执行用于代码段,为0用于数据段
    • Gr: 分片粒度,为0则每个offset代表一个byte,为1则每个offset代表4Kb,如果此时将base设为0,Limit设为0xfffff,则此时一个分片即扩展到整个32bit空间即4Gb,通常在用不到分片而使用页表时这样设置

    1. 80386 reference guide ↩︎

    2. Global Descriptor Table ↩︎

    展开全文
  • x86 实模式保护模式

    千次阅读 2016-07-26 16:25:47
    0386开始,CPU有三种工作方式:实模式保护模式和虚拟8086模式。只有在刚刚启动的时候是real-mode,等到操作系统运行起来以后就切换protected-mode。实模式只能访问地址在1M以下的内存称为常规内存,我们把地址在...

    0386开始,CPU有三种工作方式:实模式保护模式虚拟8086模式。只有在刚刚启动的时候是real-mode,等到操作系统运行起来以后就切换到protected-mode。实模式只能访问地址在1M以下的内存称为常规内存,我们把地址在1M 以上的内存称为扩展内存。在保护模式下,全部32条地址线有效,可寻址高达4G字节的物理地址空间; 扩充的存储器分段管理机制和可选的存储器分页管理机制,不仅为存储器共享和保护提供了硬件支持,而且为实现虚拟存储器提供了硬件支持; 支持多任务,能够快速地进行任务切换(switch)保护任务环境(context); 4个特权级和完善的特权检查机制,既能实现资源共享又能保证代码和数据的安全和保密及任务的隔离; 支持虚拟8086方式,便于执行8086程序。


    实模式(Real Mode)

    它是 Intel公司80286及以后的x86(80386,8048680586)兼容处理器CPU)的一种操作模式。实模式被特殊定义为20位地址内存可访问空间上,这就意味着它的容量是220次幂(1M)的可访问内存空间(物理内存和BIOS-ROM),软件可通过这些地址直接访问BIOS程序和外围硬件。实模式下处理器没有硬件级内存保护概念和多道任务的工作模式。但是为了向下兼容,所以80286及以后的x86系列兼容处理器仍然是开机启动时工作在实模式下80186和早期的处理器仅有一种操作模式,就是后来我们所定义的实模式。实模式虽然能访问到1M的地址空间,但是由于BIOS的映射作用(即BIOS占用了部分空间地址资源),所以真正能使用的物理内存空间(内存条),也就是在640k924k之间。1M 地址空间组成是由 16位的段地址和16位的段内偏移地址组成的。用公式表示为:物理地址=左移4位的段地址+偏移地址

     

    286处理器体系结构引入了地址保护模式的概念,处理器能够对内存及一些其他外围设备做硬件级的保护设置(保护设置实质上就是屏蔽一些地址的访问)。使用这些新的特性,然而必不可少一些额外的在80186及以前处理器没有的操作规程。自从最初的x86微处理器规格以后,它对程序开发完全向下兼容,80286芯片被制作成启动时继承了以前版本芯片的特性,工作在实模式下,在这种模式下实际上是关闭了新的保护功能特性,因此能使以往的软件继续工作在新的芯片下。直到今天,甚至最新的x86处理器都是在计算机加电启动时都是工作在实模式下,它能运行为以前处理器芯片写的程序.

     

    DOS操作系统(例如 MS-DOS,DR-DOS)工作在实模式下,微软Windows早期的版本(它本质上是运行在DOS上的图形用户界面应用程序,实际上本身并不是一个操作系统)也是运行在实模式下,直到Windows3.0,它运行期间既有实模式又有保护模式,所以说它是一种混合模式工作。它的保护模式运行有两种不同意义(因为80286并没有完全地实现80386及以后的保护模式功能)

     

    1〉“标准保护模式”:这就是程序运行在保护模式下;

    2〉“虚拟保护模式(实质上还是实模式,是实模式上模拟的保护模式)”:它也使用32位地址寻址方式。Windows3.1彻底删除了对实模式的支持。在80286处理器芯片以后,Windows3.1成为主流操作系统(Windows/80286不是主流产品)。目前差不多所有的X86系列处理器操作系统(LinuxWindows95 and laterOS/2等)都是在启动时进行处理器设置而进入保护模式的。

     

    实模式工作机理:

    1> 对于8086/8088来说计算实际地址是用绝对地址对1M求模8086地址线的物理结构:20,也就是它可以物理寻址的内存范围为2^20个字节,即1 M空间,但由于8086/8088所使用的寄存器都是16位,能够表示的地址范围只有0-64K,这和1M地址空间来比较也太小了,所以为了在8086/8088下能够访问1M内存,Intel采取了分段寻址的模式:16位段基地址:16位偏移EA。其绝对地址计算方法为:16位基地址左移4+16位偏移=20位地址。  比如:DS=1000H EA=FFFFH 那么绝对地址就为:10000H +
    0FFFFH = 1FFFFH 地址单元
     。通过这种方法来实现使用16位寄存器访问1M的地址空间,这种技术是处理器内部实现的,通过上述分段技术模式,能够表示的最大内存为:
     
    FFFFh: FFFFh=FFFF0h+FFFFh=10FFEFh=1M+64K-16Bytes1M多余出来的部分被称做高端内存区HMA。但8086/8088只有20位地址线,只能够访问1M地址范围的数据,所以如果访问100000h~10FFEFh之间的内存(大于1M空间),则必须有第21根地址线来参与寻址(8086/8088没有)。因此,当程序员给出超过1M100000H-10FFEFH)的地址时,因为逻辑上正常,系统并不认为其访问越界而产生异常,而是自动从0开始计算,也就是说系统计算实际地址的时候是按照对1M求模的方式进行的,这种技术被称为wrap-around

     

     

    2> 对于80286或以上的CPU通过A20 GATE来控制A20地址线  技术发展到了 80286,虽然系统的地址总线由原来的20根发展为24根,这样能够访问的内存可以达到2^24=16M,但是Intel在设计80286时提出的目标是向下兼容,所以在实模式下,系统所表现的行为应该和8086/8088所表现的完全一样,也就是说,在实模式下,80386以及后续系列应该和8086/8088完全兼容仍然使用A20地址线。所以说80286芯片存在一个BUG:它开设A20地址线。如果程序员访问100000H-10FFEFH之间的内存,系统将实际访问这块内存(没有wrap-around技术),而不是象8086/8088一样从0开始。我们来看一副图:




    为了解决上述兼容性问题,IBM使用键盘控制器上剩余的一些输出线来管理第21根地址线(从0开始数是第20根) 的有效性,被称为A20 Gate

    1> 如果A20 Gate被打开,则当程序员给出100000H-10FFEFH之间的地址的时候,系统将真正访问这块内存区域;

    如果A20 Gate被禁止,则当程序员给出100000H-10FFEFH之间的地址的时候,系统仍然使用8086/8088的方式即取模方式(8086仿真)。绝大多数IBM PC兼容机默认的A20 Gate是被禁止的。现在许多新型PC上存在直接通过BIOS功能调用来控制A20 Gate的功能。


    保护模式(Protected Mode)

    上面所述的内存访问模式都是实模式,在80286以及更高系列的PC中,即使A20 Gate被打开,在实模式下所能够访问的内存最大也只能为10FFEFH,尽管它们的地址总线所能够访问的能力都大大超过这个限制。为了能够访问10FFEFH以上的内存,则必须进入保护模式。

    (286Intel 80286的另一种叫法) 它又被称作为虚拟地址保护模式。尽管在Intel 80286手册中已经提出了虚地址保护模式,但实际上它只是一个指引,真正的32位地址出现在Intel 80386上。保护模式本身是80286及以后兼容处理器序列之后产成的一种操作模式,它具有许多特性设计为提高系统的多道任务系统的稳定性。例如内存的保护分页机制硬件虚拟存储的支持。现代多数的x86处理器操作系统都运行在保护模式下,包括Linux, Free BSD, Windows3.0(它也运行在实模式下,为了和Windows 2.x应用程序兼容)及以后的版本。

     

    80286及以后的处理器另一种工作模式是实模式(仅当系统启动的一瞬间),本着向下兼容的原则屏蔽保护模式特性,从而容许老的软件能够运行在新的芯片上。作为一个设计规范,所有的x86系列处理器,除嵌入式Intel80387之外,都是系统启动工作在实模式下,确保遗留下的操作系统向下兼容。它们都必须被启动程序(操作系统程序最初运行代码)重新设置而相应进入保护模式的,在这之前任何的保护模式特性都是无效的。在现代计算机中,这种匹配进入保护模式是操作系统启动时最前沿的动作之一。

     

    在被调停的多道任务程序中,它可以从新工作在实模式下是相当可能的。保护模式的特性是阻止被其他任务或系统内核破坏已经不健全的程序的运行,保护模式也有对硬件的支持,例如中断运行程序,移动运行进程文档到另一个进程和置空多任务的保护功能。

     

    386及以后系列处理器不仅具有保护模式又具有32位寄存器,结果导致了处理功能的混乱,因为80286虽然支持保护模式,但是它的寄存器都是16位的,它是通过自身程序设定而模拟出的32位,并非32位寄存器处理。归咎于这种混乱现象,它促使Windows/386 及以后的版本彻底抛弃80286的虚拟保护模式,以后保护模式的操作系统都是运行在80386以上,不再运行在80286(尽管80286模式支持保护模式),所以说80286是一个过渡芯片,它是一个过渡产品

     

    尽管 286386处理器能够实现保护模式和兼容以前的版本,但是内存的1M以上空间还是不易存取,由于内存地址的回绕,IBM PC XT (现以废弃)设计一种模拟系统,它能过欺骗手段访问到1M以上的地址空间,就是开通了A20地址线。在保护模式里,前32个中断为处理器异常预留,例如,中断0D(十进制13)常规保护故障和中断00是除数为零异常。

     

    如果要访问更多的内存,则必须进入保护模式,那么,在保护模式下, A20
    Gate对于内存访问有什么影响呢?

    为了搞清楚这一点,我们先来看一看A20的工作原理。A20,从它的名字就可以看出来,其实它就是对于A20(从0开始数)的特殊处理(也就是对第21根地址线的处理)。如果A20 Gate被禁止,对于80286来说,其地址为24根地址线,其地址表示为EFFFFF;对于80386极其随后的32根地址线芯片来说,其地址表示为FFEFFFFF。这种表示的意思是:



    1> 如果A20
    Gate被禁止。则其第A20CPU做地址访问的时候是无效的,永远只能被作为0。所以,在保护模式下,如果A20
    Gate被禁止,则可以访问的内存只能是奇数1M段,即1M,3M,5M…,也就是00000-FFFFF, 200000-2FFFFF,300000-3FFFFF…

    2如果A20 Gate被打开。则其第20-bit是有效的,其值既可以是0,又可以是1。那么就可以使A20线传递实际的地址信号。如果A20 Gate被打开,则可以访问的内存则是连续的。


    实模式和保护模式的区别

    从表面上看,保护模式和实模式并没有太大的区别,二者都使用了内存段、中断和设备驱动来处理硬件,但二者有很多不同之处。我们知道,在实模式中内存被划分成段,每个段的大小为 64KB ,而这样的段地址可以用 16 位来表示。内存段的处理是通过和段寄存器相关联的内部机制来处理的,这些段寄存器( CS  DS  SS ES )的内容形成了物理地址的一部分。具体来说,最终的物理地址是由 16 位的段地址和 16 位的段内偏移地址组成的。用公式表示为:物理地址 = 左移 4 位的段地址 + 偏移地址。

    在保护模式下,段是通过一系列被称之为  描述符表  的表所定义的。段寄存器存储的是指向这些表的指针。用于定义内存段的表有两种:全局描述符表 (GDT) 局部描述符表 (LDT)  GDT 是一个段描述符数组,其中包含所有应用程序都可以使用的基本描述符。在实模式中,段长是固定的 (  64KB) ,而在保护模式中,段长是可变的,其最大可达 4GB LDT 也是段描述符的一个数组。与 GDT 不同, LDT 是一个段,其中存放的是局部的、不需要全局共享的段描述符。每一个操作系统都必须定义一个 GDT ,而每一个正在运行的任务都会有一个相应的 LDT 。每一个描述符的长度是 8 个字节,格式如图 3 所示。当段寄存器被加载的时候,段基地址就会从相应的表入口获得。描述符的内容会被存储在一个程序员不可见的影像寄存器 (shadow register) 之中,以便下一次同一个段可以使用该信息而不用每次都到表中提取。物理地址由 16 位或者 32 位的偏移加上影像寄存器中的基址组成。实模式和保护模式的不同可以从下图很清楚地看出来。


    实模式地址



    保护模式地址



    总结

    保护模式同实模式的根本区别是进程内存受保护与否。可寻址空间的区别只是这一原因的果。实模式将整个物理内存看成分段的区域,程序代码和数据位于不同区域,系统程序和用户程序没有区别对待,而且每一个指针都是指向"实在"的物理地址。这样一来,用户程序的一个指针如果指向了系统程序区域或其他用户程序 区域,并改变了值,那么对于这个被修改的系统程序或用户程序,其后果就很可能是灾难性的。为了克服这种低劣的内存管理方式,处理器厂商开发出保护模式。这 样,物理内存地址不能直接被程序访问,程序内部的地址(虚拟地址)要由操作系统转化为物理地址去访问,程序对此一无所知。

    至此,进程有了严格的边界,任何其他进程根本没有办法访问不属于自己的物理内存区域,甚至在自己的虚拟地址范围内也不是可以任意访问的,因为有一些虚拟区域已经被放进一些公共系统运行库。这些区域也不能随便修改,若修改就会有: SIGSEGV(linux 段错误);非法内存访问对话框(windows 对话框)。

    CPU启动环境为16位实模式,之后可以切换到保护模式。但从保护模式无法切换回实模式 。


    对于80X86处理器来说,从80386处理器开始,除了以前的实模式外,还增添了 
    保护模式和V86模式。实模式和V86模式都是为了和8086兼容而设置的。 
      
    实模式: 
          内存寻址方式为:段式寻址,即物理地址=段地址*16   +   段内偏移地址 
          可寻址任意地址,所有指令都相当于工作在特权级。 
          dos工作在实模式下 
    保护模式: 
          内存寻址方式为:支持内存分页和虚拟内存 
          支持多任务,可依靠硬件用一条指令即可实现任务切换,不同任务可工作在 不同的优先级下,操作系统工作在最高优先级0上,应用程序则运行       在较低优先级 上。从实模式到保护模式,需要建立GDT、IDT等数据表,然后通过修改控制寄存 器CR0的控制位(位0)来实现。 
          Windows工作在保护模式下。 
    虚拟8086模式: 
            内存寻址方式:段式寻址,与实模式一样 
            支持多任务和内存分页 
            v86模式主要是为了在保护模式下兼容以前的实模式应用,即可支持多任务, 
            但每个任务都是实模式的工作方式。 

    另外,中断和异常等的处理对于不同的工作模式都是不同的,具体的可以去 参看一些相关书籍。 


    以上转自:http://blog.csdn.net/kennyrose/article/details/7563649

    以下转自:http://ahhqlrg.lofter.com/post/1ccdac85_7882945

     Intel的实模式和保护模式,必须要知道的...

    一、Intel手册如是说 

            Intel的IA-32架构支持三种基本操作模式:保护模式、实地址模式和系统管理模式。操作模式决定了哪些指令和架构相关的特性是可用的:

    • 保护模式(protected mode)——是处理器的根本模式,在保护模式下,可以为直接运行的实地址模式程序提供保护的、多任务的环境,这种特性被称作“虚拟8086模式(virtual 8086 mode)”,尽管“虚拟8086”模式并不是一种真正的处理器模式;virtual 8086 mode实际上是保护模式的一种属性,在保护模式下,可以向任何任务提供这种属性。
    • 实地址模式(real-addess mode)——该模式以扩展的方式实现了8086CPU的程序运行环境(就像切换到保护模式和系统管理模式一样)。处理器在刚刚上电或者重启后的时候,处于实地址模式。
    • 系统管理模式(system manangement mode,SMM)——该模式提供操作系统或者执行程序一种透明的机制去实现平台相关的特性,例如电源管理和系统安全。当来自外部的或者APIC控制器的SMM中断pin脚被触发时,处理器在下列情况进入SMM。在SMM下,处理器切换到一个独立的地址空间,同时保存当前运行的程序或任务的上下文。SMM相关的代码可透明的执行。当SMM模式返回时,处理器返回SMI(system manangement interrupt)前的工作模式。SMM模式在Intel 386 SL和Intel 486 SL处理器时被引入,在Pentium家族时成为标准的IA-32架构的特性。

            Intel 64 架构增加了IA-32e模式,IA-32e模式又包含两种子模式:

    • 兼容模式(Compatibility mode)——兼容模式允许绝大部分16-bit/32-bit的应用可以无需重新编译就能直接在64bits的操作系统下运行。简单的,在IA-32架构下将“兼容子模式”称为“兼容模式”。兼容模式的可执行环境与Section 3.2定义的一致。兼容模式也支持所有的特权级别,在64-bit和保护模式下。运行在虚拟8086模式下的或用到硬件任务管理的程序,在此模式下无法工作。兼容模式做代码段基础被操作系统所启动,这意味着单独的64-bit操作系统可以通过64-bit模式支持64-bit应用,也可以通过兼容模式支持32-bit程序(无需再编译)。兼容模式类似于32-bit的保护模式,应用程序只能访问前4G的线性地址空间。兼容模式使用16-bit和32-bit的地址以及操作数长度。类似于保护模式,该模式允许应用程序通过PAE(物理地址扩展,Physical Address Extention)访问超过4G的物理内存。
    • 64-bit模式(64-bit  mode)——该模式使操作系统在64-bit线性地址空间上运行应用程序,在IA-32架构下,64-bit子模式被简称为64-bit模式。64-bit模式将通用寄存器和SIMD寄存器从8个扩展到16个。通用寄存器被增加到64bits宽。该模式还引入了新的操作数前缀(REX)来访问寄存器扩展。64-bit模式作为代码段基础被操作系统激活,该模式默认地址长度是64bits,但默认操作数长度为32bits,默认的操作数长度可以在指令级别被覆盖,通过使用REX操作数前缀结合操作数大小覆盖前缀。REX前缀被用来在64-bit模式下指定一个64-bit的操作数,通过这种机制,很多已经存在的指令代码可以被直接升级到访问64-bit地址空间和64-bit寄存器。        
    二、实模式的历史原因 

            早在1978年,Intel研制了8086处理器,8086处理有16-bit寄存器和16-bit的外部数据总线,但是却能够访问20-bit的地址(包含1MByte的地址空间)。8086通过引入“分段(segmentation)机制”来解决这个问题。在分段机制下,一个16bits的段寄存器包含了一个长度是64KBytes的“段”空间的起始指针。通过1次时可用一个段寄存器,8086处理器可以无需在段间切换就能寻址高达256KBytes。因此,通过段寄存器+16bits的指针就能访问20bits的地址空间,共1Mbytes。

            虽然8086/8088处理器采用的地址空间大小与外部总线位宽不一致,但是这显得很“别扭”,并且在1985年80386时被统一,地址空间和外部总线位宽均为32bits。

            为了兼容8086,这种分段管理内存的方式一直被保留下来。当然,实模式不仅仅是分段内存管理,而是“程序的运行环境”,所为的运行环境,还包括寄存器的长度。

    三、实模式和保护模式的区别 

            个人理解,因为x86的CPU在启动时首先处于实模式,也就8086的16位模式,主要特点有:

    • 内存管理采用段+偏移的方式进行;
    • 最大寻指位2的20次方,即1Mbyte;
    • 没有安全级别,直接操作CPU的各种功能;
    • 没有分页功能,没有虚拟地址的概念,只有物理地址;
    • 各种寄存器的位宽基本上是16位的(段寄存器为20位);

            实模式就是一种比较原始的模式,能看到CPU设计的初始过程。

            保护模式是32位模式,但是可以兼容16位的实模式,保护模式的特点有:

    • 内存管理采用段式+页式的方式;
    • 最大寻指位2的32次方,即4G,还可以通过PAE模式访问超过4G的部分。
    • 有4个安全级别,内存操作时有安全检查;
    • 因为有了分页功能,因此有虚拟地址和物理地址的区别;
    • 各种寄存器的位宽基本上都是32位的,但是可以兼容同名的16位寄存器;
    • 可以兼容实地址模式,也即实地址模式的程序无需再编译即可跑在保护模式下。

            对于64位CPU来说,兼容模式和64位模式也基本上一个道理,兼容模式为了兼容32位,也就兼容了16位,而64位模式本身不去兼容32位,是纯净的64位。

    四、实模式对OS的意义 

            仅从Linux操作系统考虑。因为32位CPU一上电后,首先处于实模式下,所以实模式是OS必须经历的一种模式。既然保护模式可以兼容实模式,那么CPU为什么还要提供专门的实模式呢?是否OS可以直接从实模式跳转到保护模式呢?

            实话说,这两个问题我也不太好回答。为了钱?对Linux系统来说,从实模式到保护模式的过程,实际上主要就是为了初始化保护模式的过程。从实际模式切换到保护模式不是开开关、按按钮,而需要准备工作,主要是为了开启分页机制做准备,要分页,必须有页表、段描述符,这些都需要通过内存初始化。关于具体的过程,请参考《Linux内核启动保护模式的过程》。

            个人认为实模式就是在CPU启动的时刻的低级模式,需要OS无需在该模式上做过多的事情,而仅仅为向高级模式转化做准备。

    展开全文
  • x86汇编语言-从实模式到保护模式 x86汇编语言-从实模式到保护模式
  • x86汇编语言 从实模式到保护模式 完整版 文字版 带书签,并有随书文件。
  • x86汇编语言 从实模式到保护模式,
  • x86汇编语言++从实模式到保护模式 x86汇编语言++从实模式到保护模式
  • x86汇编语言:从实模式到保护模式》主要讲述INTEL x86处理器的16位实模式、32位保护模式,至于虚拟8086模式,则是为了兼容传统的8086程序,现在看来已经完全过时,不再进行讲述。《x86汇编语言:从实模式到保护模式...
  • x86汇编语言 从实模式到保护模式完整版
  • x86汇编语言-从实模式到保护模式,高清 从底层讲述计算机原理
  • x86保护模式 实模式保护模式切换实例 实例一 逻辑功能 以十六进制数的形式显示从内存地址110000h开始的256个字节的值 实现步骤: 1 切换保护方式的准备 2. 切换到保护方式 3. 把指定内存区域的内容传送到...
  • x86汇编语言从实模式到保护模式- 光盘
  • 摸索了很长时间后,感觉一个靠谱的路线是:先学会一门语言对计算机有一个感觉,能做点事情--》再学点数据结构,不需要一次学的多么深--》王爽《汇编语言》--》李忠等《实模式到保护模式》--》哈工大李治军《操作系统...
  • x86汇编语言-从实模式到保护模式 书籍工具 配套书籍,更加方便
  • x86汇编语言-从实模式到保护模式 配套源码及资料

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 677
精华内容 270
关键字:

x86实模式到保护模式