早期的BIOS如何使用CALL?

How can early BIOS use CALL?

我纯粹是出于业余爱好,试图理解 PC 中的一些低级代码。我为一个随机的旧技嘉 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 结尾。这怎么可能,call 在哪里存储 return 地址?

或者我误解了从端口 0x71 编辑的值 return?我参考了这两个文档:

0x8f写成0x70的意思:https://wiki.osdev.org/CMOS#CMOS_Registers

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

有2个案例:

a) "cold boot"(例如,当计算机未 运行 而您打开它时)。在这种情况下;内存控制器不会被初始化,关闭状态不会被设置,jne 0xf488 会导致代码跳转到其他地方,call 不会被执行。

b) "warm boot"(例如,当您在已经 运行 后重置计算机时)。在这种情况下;内存控制器仍在初始化(从之前发生的 "cold boot" 开始),将设置关闭状态,jne 0xf488 不会执行任何操作,并且 call 将被执行(但这很好,因为内存控制器已初始化)。

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

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

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

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