[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: how could i get the hexadecimal content in memory at address FFFF0000-FFFFFFF0?



2008/7/15 Taishan <taishan1982@gmail.com>:
> 哪里有关于这方面的权威文档我不大清楚,这里把我知道的一些情况在这里
> 说一下吧。首先有两个事情需要先明确一下:
>
>    第一,关于保护模式于实模式。所谓实模式,就是CPU在与 Intel 8086 完全
> 兼容的方式下运行。当年 Intel 还没有发家时,其微型处理器产品的老大、老二
> 和老三(即4004、8008和8080)并没有出多大的彩儿,直到老四8086出生,其孪生
> 兄弟8088被当时的大佬IBM选中作为其第一代PC机产品的中央处理器使用,Intel才
> 逐渐走向辉煌。Intel在8086以后生产的微型处理器产品在8086的基础上进行了极
> 大的改进,增添了许多强劲的功能,但是这些功能有些无法在与8086兼容的方式下
> 产生作用,所以为了同时兼顾兼容与性能这两方面的需求,Intel为CPU设定了两种
> 运行状态,即保护模式和实模式。在保护模式下CPU的所有功能全开,以最大的性
> 能运行;而在实模式下,除了主频较快、增添了一些指令以及扩展的寄存器外,几
> 乎与8086的运行方式没有什么不同。程序可以通过改变CPU的状态寄存器EFLAG中的
> 一位来改变运行模式。
>    在系统刚刚启动的时候CPU是运行在实模式下的,直到操作系统启动,才改变
> 到保护模式下运行,所以BIOS中的程序都是在实模式下运行的。在这里需要特别注
> 意的是8086只有20根地址线(80286有24根,80386有32根,现在的64位CPU有64
> 根),即它的寻址范围是在 00000H 到 FFFFFH,20位的二进制数,正好是一个
> 兆,因此在实模式下,不管你安装了1M、1G还是1T内存,你最多只能用1M。
>
>    第二,关于CPU实模式下"线性"地址表示与"段:偏移"地址表示的换算。保护
> 模式下的情况于实模式下有很大不同,这里只说一下关于实模式的。内存的地址是
> 为内存的最小存储单元(通常是一个字节)分派的一个唯一的编号。CPU通过地址
> 线将表示这个编号的电信号,放到地址总线上来选中某一个存储单元,再通过数据
> 线从数据总线访问这个被选中的存储单元,因此这个地址也称为"物理地址";同时
> 这些编号又是一些连续的整数,支持加减乘除这样的线性运算,所以也将这个编号
> 称为"线性地址"(注意,在保护模式下物理地址与线性地址是两个不同的概念,不
> 能混淆,但在实模式下物理地址与线性地址可以看作是一个概念)。在8086中寄存
> 器都是16位的,不足以表示一个20位的地址,因此Intel提出了一个用两个16位数
> 表示一个20位地址的方法,即"段:偏移"的表示方法。用于表示20位地址的两个16
> 位数一个被称为"段",一个被成为"偏移",将"段"乘以16再加上"偏移",就可以得
> 到一个20的数,作为地址使用。这里有一个问题,像FFFF:FFFF这样的地址,用上
> 面的方法换算的话会产生一个超过20二进制的数:
>        FFFFH * 10H + FFFFH = 10FFEFH
> 这时CPU会自动的丢掉超过20位的部分,变成 0FFEFH,因此,如果你访问
> FFFF:FFFF这个地址的话,你会发现访问的是 0FFEFH 这个字节,而不是
> 10FFEFH,这个处理称之为wrap。
>
>    这里说一些关于wrap的题外话,不感兴趣的可以跳过这一段。Intel在8086之
> 后推出的80286有24位地址线,因此Intel认为对超过20位的地址进行wrap处理没有
> 必要,所以80286及其以后的CPU都不再对超过20位的地址进行处理。这样就产生了
> 一个有趣的现象,一个程序可以在不改变到保护模式的情况下,通过 FFFF:0010
> 到 FFFF:FFFF 这些地址来访问1MB之上的64K内存(准确的说是64K-16个字节的内
> 存),当时就产生了很多利用这个技巧的软件。IBM考虑到兼容性的问题曾经希望
> Intel增加wrap的设计,不果后自己动手,在主板上用一个与门将A20地址线(第21
> 根地址线,从0开始编号)与一个控制信号连接到一起然后才将输出接到总线上。
> 这样如果需要wrap功能的话,将控制信号设为表示0的第电平,这样不管A20是0还
> 是1,最后输出的都是0,而不需要wrap的时候将控制信号设为高电平就行了。这个
> 控制信号的控制曾经被IBM放到键盘上,现在的PC机一般都通过软件来设置这个控
> 制信号,有些主板的CMOS设置程序中就有这个选项,有兴趣的人可以自己找找,一
> 般叫做Gate A20。当然,现在的操作系统都会自己设置A20的控制,在保护模式下
> 开启A20的wrap是灾难性的,除非你的操作系统和程序不使用第21位地址是1的内
> 存。
>
>    回归主题,线性地址对于一个存储单元是唯一的,但是"段"表示法不是唯一
> 的,例如下面的几个地址都是FFFF0H这个地址的段表示:
>    FFFF:0000   FEDC:1230   FCDE:3210   F000:FFF0   F777:8880
> 通过计算可以得到一个线性地址对应的段表示方法有 2^12 = 4096 种。因此这里
> 尽量使用线性地址,避免歧义。
>
>    下面说一下实模式下CPU可以访问的1M地址空间的使用情况。00000H 到
> 9FFFFH 这640K的地址空间分配给机器安装的RAM使用,也就是我们通常说的内存,
> 这一段地址空间历史上被成为常规内存(Standard Memory);A0000H 到 FFFFFH 这
> 一段384K历史上被成为高端内存(High Memory),一般由三部分内容组成:Video
> Ram区,通过对这段内存的读写控制显示器上的显示内容;扩展卡BIOS区,实际上
> 不只主板上有BIOS,在显卡、声卡、网卡、硬盘、光驱、键盘上一般也都有BIOS芯
> 片,其中有这些设备的规格信息和基本的中断处理访问程序,这些BIOS会被映射到
> 这一段地址区间;系统BIOS区,这个地址区段就是主板上BIOS芯片(即我们平常所
> 说一般意义上的BIOS)被映射到的区域。至于这几个区域的具体大小我记不大清楚
> 了,依稀记得系统BIOS区应该是这1M空间的最末尾的128K(即 E0000H 到
> FFFFFH),扩展卡BIOS区在系统BIOS区与Video Ram区之间,而Video Ram区
> 在扩展卡BIOS区与常规内存之间。
>    系统开机后,CS:IP被置为 FFFF:0000, 换算成线性地址就是 FFFF0H,即
> 1M地
> 址空间的最后16个字节处,打开用flashrom获取的BIOS镜像文件,找到最后的16个
> 字节,将前5个字节反汇编会发现是一个长跳转指令,这个指令跳转的目标才是真
> 正的加电自检(POST)程序。这末尾的十六个字节中的其他十一个字节一般是OEM
> 的信息,内容任意你甚至可以写上你自己的名字。
>    我的系统读取的BIOS镜像长度为512K(00000H 到 7FFFFH),最后十六个字节
> (7FFF0 d到 7FFFF)的前五个字节是 ea 5b e0 00 f0,反汇编过来就是
>         JMP  F000:E05B
> 即跳转到 FE05BH,这里就是真正的POST程序的位置。FE05BH相对于FFFFFH的偏移量
> 是
>         FE05BH - FFFFFH = -1FA4
> 因此 JMP  F000:E05B 的目标在镜像文件中的位置就是
>         7FFFFH -1FA4H = 7E05BH
>

非常感谢,我估计你比大学里的老师讲得更详细:)
我按照你的方法已经找到我的BIOS的入口了,(7FFF0 d到 7FFFF)的前五个字节是 ea aa ff 00 f0,接下来我就可以开始跟踪机器码了:)
这么看来intel cpu manul的确有问题,它说的第一条指令应该是near jmp,看来是不对的,因为ea是far jmp.
那么bios也的确应该在1M内存以内,而不是FFFF0000-FFFFFFF0,我实在不明白怎么会有这么严重的bug....


-- 
Regards!
Star
Shanghai, China

Reply to: