结合上面的文章,CPU上电后第一条指令是通过CS:IP来指定的,CPU厂家会给其初始值,对于386处理器来说,CPU第一条指令地址是

                  0xFFFFFFF0

  这里会有一个问题,CPU怎么能一上来就去0xFFFFFFF0取指令呢?因为此时的内存都没有初始化呢,内存中什么都没有,第一条指令毫无疑问肯定在BIOS中,现在用来烧写BIOS的Flash芯片一般也就256KB、1MB、4MB,都是非常小的,怎么也没有0xFFFFFFF0这个地址的。

  这里就需要说一下x86的地址编码方式了,我们平时说的内存,主存是指RAM,但是这里会有些问题,因为RAM是从0开始的一个地址范围,而ROM也是从0开始的一个地址范围,当我们要访问一个地址,比如0x100,此时到底是去RAM里找还是去ROM里找呢?

  x86解决这个问题的方法是“统一编码”,也可以叫做地址映射,也就是在CPU眼里,它只看到一块打的空间,对于32位CPU,从0开始,4G结束,64位的CPU最大范围就更大了,CPU才不懂什么叫RAM,什么叫ROM,什么叫硬盘的,地址映射的概念就是给地址分段,不同位置是有不同的作用的,大部分是用来给程序运行的RAM的,但还有部分是映射给ROM,IO或者其他设备,下图是一种典型的地址映射关系:

  

  那么问题又来了,上面不是说CPU上电后会去0xFFFFFFF0处取第一条指令,这条指令肯定是在BIOS中,但是上图中BIOS的映射地址时0xF0000,这个就有点懵了,到底是为什么呢?那么BIOS代码到底映射在什么位置呢?

  答案是--两个地址都有,BIOS的代码肯定是存在EPROM中的,CPU中的硬件回把EPROM芯片映射到2个地方,一个是从0xFFFFFFFF(4G)处向下扩展,一个是从0xFFFFF(1MB)处向下扩展,第一个映射是因为第一条指令在0xFFFFFFF0处,所以EPROM必须在哪个位置,第二个映射是为了兼容,在16位时代就有了,另外地址映射是占据地址空间,总是你的PC机只有2G内存也没关系,因为病没有使用内存,使用的只是地址空间,所到底对于CPU来说,它才不知道哪是哪,它只知道服从硬件安排,上面的所有所有地址映射,都是给程序员看的,不是给CPU看的,CPU只认各种“门”电路。

  那么第一条指令的内容是什么呢?

  这是比较容易产生混淆的地方,多数人说第一条指令是个长跳转(long jmp),跳转到0~0xFFFFF(0-1MB)这一段,然后再执行BIOS剩余的指令,但是intel手册中却又这么一段话:

  

   简单的说,就是不让有长跳转动作,其实这两种都对,intel手册上说的是让BIOS在高地址空间运行,器件一直修改CS寄存器,也就是一直使用Base+EIP的方式生成地址,这种新式方法应该是UEFI的,那种刚开始就长跳转的属于老式做法。

  假设有一块1M的flash芯片,第一条指令一般都是在0xFFFF0的这个位置,这样的原因,我们可以很简单的想到,这是为了把这1M空间方便的映射到4G地址中最高的1M中吧,可能看起来比较对齐吧。

  BIOS也就是ROM的地址空间通过CPU的硬件自动映射到了高地址1M,但是我们平时看到的都是低于1M的BIOS,因为在高地址的时候,CPU实际上是在访问ROM,这段时间内,基本的操作就是硬件初始化,最重要的肯定是RAM等重要硬件的初始化,初始化完成后,CPU根据BIOS中的“搬家”代码,回将ROM的所有内容拷贝到RAM中(整体拷贝比较方便,如果是想着把前面执行过的剔除掉,得不偿失),当然这个位置肯定就是低1M的地址空间,比如上图中,从0xF0000开始的那64Kb空间(放心,一般的BIOS不会超过64KB),拷贝完成后,CPU会执行一条长跳转,这会引起CS寄存器的改变,也就会控制CPU指向RAM进行执行程序了,这样带来2个好处,第一肯定是RAM比ROM更快,第二是这样重新满足了实模式下寻址范围是1M的这一特点,当然CPU寻址方式回重新回归到CS左移4位+IP的模式。

  到这里还有一些疑问:我们一般会认为第一条紫菱本身就是一条长跳转指令,那么CPU是怎么完成内存初始化后,并将BIOS相关数据拷贝到1M以下地址空间呢?这里有几种可能(方便说服内心的猜测),第一是这条指令并不是真正的长跳转,而是先进行一些基本的初始化,才跳转,第二是ROM到地址空间的映射并不是简单的映射到搞地质的1M,而是有着更复杂的映射方式,使得长跳转后时间上CPU还是在访问ROM,第三就是CPU一旦上电,就自动的由硬件将BIOS内容复制到对应的RAM中,这一点在ARM9的工作模式可以验证。

  

电脑CPU开机上电后的第一条指令的更多相关文章

  1. postgresql分组后获取第一条数据

    -- 根据编号分组取第一条数据 select * from table t where t.no=(select max(no) from table t1 where t1.no=t.no) -- ...

  2. 自己动手写处理器之第四阶段(1)——第一条指令ori的实现

    将陆续上传本人写的新书<自己动手写处理器>(尚未出版),今天是第11篇,我尽量每周四篇 第4章 第一条指令ori的实现 前面几章介绍了非常多预备知识,也描绘了即将要实现的OpenMIPS处 ...

  3. oracle获取排序后的第一条信息

    查询表table1里字段id小于10的所有数据,并且让数据根据id降序排列,然后得到第一条数据 select * from (select * from table1 where id<10 o ...

  4. sqlserver 数据库分组后取第一条数据

    分享一个朋友的人工智能教程.零基础!通俗易懂!风趣幽默!大家可以看看是否对自己有帮助,点击查看教程. 比如查询用户某一天最后一笔交易后的账户余额 SELECT *( SELECT *, row_num ...

  5. oracle排序后的第一条记录

    该查寻语句没有经过任何的优化,因为oracle没有SQL的TOP关键字,但是有一个ROWNUM的列,因此,可以通过ROWNUM来进行查询.oracle的关于rownum的参考手册里面提到了    分析 ...

  6. SQL group by 分组后,同一组的排序后取第一条

    SELECT * FROM(                SELECT                     [SPID]                    ,[PH1]           ...

  7. 王爽《汇编》检测9.1(1) | 若要使程序中的jmp指令执行后,CS:IP指向程序的第一条指令,在data段中应该定义哪些数据?

    ;监测点9.1(1) assume cs:code data segment db dup() data ends code segment start: mov ax,data :这一段一定要补上 ...

  8. MSSQL 分组后取每组第一条(group by order by)

    查询中经常遇到这种查询,分组后取每组第一条.分享下一个SQL语句: --根据 x 分组后.根据 y 排序后取第一条 select * from ( select ROW_NUMBER() over(p ...

  9. Linux 从头学 01:CPU 是如何执行一条指令的?

    作 者:道哥,10+年的嵌入式开发老兵. 公众号:[IOT物联网小镇],专注于:C/C++.Linux操作系统.应用程序设计.物联网.单片机和嵌入式开发等领域. 公众号回复[书籍],获取 Linux. ...

随机推荐

  1. Flutter - 下载别人的Flutter项目,本地编译不过

    如果直接下载了别人的Flutter项目,点击运行基本会不通过的,这是gradle版本差异造成的. 你需要修改android/gradle/wrapper/gradle-wrapper.properti ...

  2. java并发编程——并发容器

    概述 java cocurrent包提供了很多并发容器,在提供并发控制的前提下,通过优化,提升性能.本文主要讨论常见的并发容器的实现机制和绝妙之处,但并不会对所有实现细节面面俱到. 为什么JUC需要提 ...

  3. Scrapy中的POST请求发送和递归爬取

    POST请求发送 重写爬虫应用文件中继承Spider类的 类的里面的start_requests(self)这个方法 def start_requests(self): #请求的url post_ur ...

  4. php 文件上传缩略图路径分析类

    <?php //文件上传时分析路径信息 //author:songzhenghe 2014-1-24 //version 0.1 class path_ana {     private $da ...

  5. Python之pexpect详解

    一.引子 Pexpect程序主要用于人机对话的模拟,就是那种系统提问,人来回答yes/no,或者账号登陆输入用户名和密码等等的情况.因为这种情况特别多而且繁琐,所以很多语言都有各种自己的实现.最初的第 ...

  6. vue-scroller实现vue单页面的上拉加载和下拉刷新问题

    在vue中如何简单的实现页面的上拉加载和下拉刷新,在这里我推荐使用vue-scrolle插件. vue-scrolle的基本使用方法: 1.下载 npm i vue-scroller -D 2.导包 ...

  7. RabbitMQ入门:发布/订阅(Publish/Subscribe)

    在前面的两篇博客中 RabbitMQ入门:Hello RabbitMQ 代码实例 RabbitMQ入门:工作队列(Work Queue) 遇到的实例都是一个消息只发送给一个消费者(工作者),他们的消息 ...

  8. 使用tensorflow进行mnist数字识别【模型训练+预测+模型保存+模型恢复】

      import sys,os sys.path.append(os.pardir) import numpy as np from tensorflow.examples.tutorials.mni ...

  9. Ubuntu下LimeSDR Mini使用说明

    本文内容.开发板及配件仅限用于学校或科研院所开展科研实验! 淘宝店铺名称:开源SDR实验室 LimeSDR链接:https://item.taobao.com/item.htm?spm=a230r.1 ...

  10. systemctl status ssh.service 服务重启出现报错

    Case: ubuntu在从Ubuntu 16.04 LTS 升级到18.04 的时候,执行 do-release-upgrade -d 后,发现ssh无法登陆服务器, Solution: 1.通过s ...