assembly - 早期BIOS如何使用CALL?

标签 assembly x86 reverse-engineering bios

我纯粹是出于爱好原因,试图理解 PC 中的一些低级代码。我为随机的旧 Gigabyte MB ( https://www.gigabyte.com/Motherboard/GA-8I845GE775-G-rev-10/support#support-dl-bios ) 下载了一个过时的 BIOS ROM 镜像,它已经有将近 15 年的历史了,所以我希望它不会损害任何人的知识产权。我将使用此文件作为引用。

我一开始就被绊倒了。这些似乎是处理器上电后看到的第一条指令:

f000:fff0  ljmp 0xf000:0xe05b
f000:e05b  jmp 0xf46c
f000:f46c  cli
f000:f46d  cld
f000:f470  smsw ax       ; read CR0
f000:f473  test al, 1    ; test Protected Mode Enable
f000:f475  je 0xf480
[assuming PE is zero – jump:]
f000:f480  jmp 0xe043
f000:e043  mov al, 0x8f
f000:e045  out 0x70, al  ; CMOS controller: disable NMI, set index 0xf
f000:e047  out 0xeb, al  ; this port is presumably unoccupied: just a delay mechanism
f000:e049  in al, 0x71   ; read 0xf (CMOS Shutdown Status)
f000:e04b  out 0xeb, al  ; more delay
f000:e04d  or al, al
f000:e04f  jmp 0xf483
f000:f483  jne 0xf488
[assuming status = 0 (Power on or soft reset) – pass:]
f000:f485  call 0x4dee

假设计算机开机时 CMOS 关闭状态为零,BIOS 将在 f000:f485 处发出调用。在早期,我们不会尝试检测是否存在任何 RAM。堆栈段和堆栈指针也尚未设置。 f000:f485 处的代码确实看起来像一个函数,并以 ret 结尾。这怎么可能,调用在哪里存储返回地址?

或者我是否误解了从端口0x71返回的值?我引用了这两个文档:

0x8f写入0x70的含义:https://wiki.osdev.org/CMOS#CMOS_Registers

随后从0x71读取的值的含义:http://www.bioscentral.com/misc/cmosmap.htm

最佳答案

有2种情况:

a)“冷启动”(例如,当计算机未运行而您将其打开时)。在这种情况下;内存 Controller 不会被初始化,关闭状态不会被设置,jne 0xf488会导致代码跳转到其他地方,call也不会被处决。

b) “热启动”(例如,当您在计算机已经运行后重置计算机时)。在这种情况下;内存 Controller 仍处于初始化状态(从之前发生“冷启动”时开始),将设置关闭状态,jne 0xf488 不会执行任何操作,call 将被执行(但这没关系,因为内存 Controller 已初始化)。

Assuming the CMOS shutdown status is zero upon powering the computer on...

没有。关闭状态字节值为(根据 Ralph Brown 的中断列表):

  • 0x00 = 软件重置或意外重置
  • 0x01 = 在虚拟模式下检查内存大小后重置
  • 0x02 = 在实/虚拟模式下成功进行内存测试后重置
  • 0x03 = 在实/虚拟模式下内存测试失败后重置
  • 0x04 = INT 0x19 重新启动
  • 0x05 = 齐平键盘并跳转。 0x0040:0x0067
  • 0x06 = 重置(虚拟模式测试成功后)
  • 0x07 = 重置(在虚拟模式下测试失败后)
  • 0x08 = 在 protected =模式 RAM 测试期间由 POST 使用
  • 0x09 = 用于 INT 0x15/0x87( block 移动)支持
  • 0x0A = 通过 JMP 恢复执行。 0x0040:0x0067
  • 0x0B = 通过 IRET 恢复执行。 0x0040:0x0067
  • 0x0C = 通过 RETF 恢复执行。 0x0040:0x0067
  • 0x0D 至 0xFF = 执行加电复位(“冷启动”)

注意:Ralph Brown 的中断列表已经很久没有维护了。我预计其中一些是旧的和/或仅适用于一些非常旧的计算机(例如 80286,除了重置之外没有任何方法可以离开保护模式)。

关于assembly - 早期BIOS如何使用CALL?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57970485/

相关文章:

c++ - 编译后 ASM 优化丢失了吗?

c - 原子位测试和设置 (BTS) 的内在汇编

macos - 将功能注入(inject)二进制文件的最佳方法

entity-framework-4 - Entity Framework Power Tools CTP1 可以为存储过程生成类吗?

c++ - 为类似 nm 的命令编写代码 [C++]

assembly - 低级语言的堆栈和堆栈框架

c - 我如何简化/压缩代码(如果可能)?

c - 程序集-从字符数组中获取符号标签?

c - x86 中断处理程序在使用无限循环时被阻塞

algorithm - 汇编中 x86 上的带符号 64 位乘法和 128 位除法