早期的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,除了重置之外没有任何办法离开保护模式)。
我纯粹是出于业余爱好,试图理解 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,除了重置之外没有任何办法离开保护模式)。