- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在研究我的机器(x86_64 Linux、IvyBridge)中的 BIOS 代码。我使用以下过程转储 BIOS 代码:
$ sudo cat /proc/iomem | grep ROM
000f0000-000fffff : System ROM
$ sudo dd if=/dev/mem of=bios.dump bs=1M count=1
然后我使用 radare2 来读取和反汇编二进制转储:
$ r2 -b 16 bios.dump
[0000:0000]> s 0xffff0
[f000:fff0]> pd 3
: f000:fff0 0f09 wbinvd
`=< f000:fff2 e927f5 jmp 0xff51c
f000:fff5 0000 add byte [bx + si], al
我知道x86处理器初始化总是从16位8086环境开始,并且要执行的第一条指令位于f000:fff0
,即0xffff0
。所以我去那个位置并反汇编代码。
令我惊讶的是,第一条指令是 WBINVD
,其功能是使缓存失效,这在处理器上电或复位时似乎无关紧要。我希望第一条指令只是指向较低内存地址的 jmp
。
为什么jmp
之前有一个WBINVD
?
我已经搜索过英特尔手册第 3 卷第 9 章处理器管理和初始化的相关部分,但它没有提及任何有关 WBINVD
的内容。我也查了一些网上资源,但没有找到任何解释。
跟随jmp
指令到0xff51c
之后,代码就更有趣了;它正在进行 self 检查:
[f000:f51c]> pd
f000:f51c dbe3 fninit
f000:f51e 0f6ec0 movd mm0, eax
f000:f521 6631c0 xor eax, eax
f000:f524 8ec0 mov es, ax
f000:f526 8cc8 mov ax, cs
f000:f528 8ed8 mov ds, ax
f000:f52a b800f0 mov ax, 0xf000
f000:f52d 8ec0 mov es, ax
f000:f52f 6726a0f0ff00. mov al, byte es:[0xfff0] ; [0xfff0:1]=0
f000:f536 3cea cmp al, 0xea
,=< f000:f538 750f jne 0xff549
| f000:f53a b91b00 mov cx, 0x1b
| f000:f53d 0f32 rdmsr ; check BSP (Boot Strap Processor) flag, if set, loop back to 0xffff0; otherwise, infinite hlt
| f000:f53f f6c401 test ah, 1
,==< f000:f542 7441 je 0xff585
,===< f000:f544 eaf0ff00f0 ljmp 0xf000:0xfff0
||`-> f000:f549 b001 mov al, 1
|| f000:f54b e680 out 0x80, al
|| f000:f54d 66be8cfdffff mov esi, 0xfffffd8c ; 4294966668
|| f000:f553 662e0f0114 lgdt cs:[si]
|| f000:f558 0f20c0 mov eax, cr0
|| f000:f55b 6683c803 or eax, 3
|| f000:f55f 0f22c0 mov cr0, eax
|| f000:f562 0f20e0 mov eax, cr4
|| f000:f565 660d00060000 or eax, 0x600
|| f000:f56b 0f22e0 mov cr4, eax
|| f000:f56e b81800 mov ax, 0x18
|| f000:f571 8ed8 mov ds, ax
|| f000:f573 8ec0 mov es, ax
|| f000:f575 8ee0 mov fs, ax
|| f000:f577 8ee8 mov gs, ax
|| f000:f579 8ed0 mov ss, ax
|| f000:f57b 66be92fdffff mov esi, 0xfffffd92 ; 4294966674
|| f000:f581 662eff2c ljmp cs:[si]
|`.-> f000:f585 fa cli
| : f000:f586 f4 hlt
| `=< f000:f587 ebfc jmp 0xff585
总而言之,这个 BIOS 代码在 0xffff0
处读取自身,并将该字节与 0xea
进行比较,这正是远跳转的操作码:
f000:f52a b800f0 mov ax, 0xf000
f000:f52d 8ec0 mov es, ax
f000:f52f 6726a0f0ff00. mov al, byte es:[0xfff0] ; [0xfff0:1]=0
f000:f536 3cea cmp al, 0xea
如果发现0xffff0
处的代码是远跳转,那么就会进入无限循环。
更准确地说,AP(应用程序处理器)将在 hlt
指令处无限循环,而 BSP(引导带处理器)将循环回到开头 0xffff0
。由于 0xffff0
处的代码不会改变,因此我们可以得出结论,BSP 总是会找到 0xea
的字节,并且永远不会跳出循环。
那么这个自检的目的是什么呢?我简直不敢相信这是阻止修改的天真的尝试。
最佳答案
尽管很难推理,但请记住负载 mov al, byte es:[0xfff0]
不读取 BIOS 第一条指令,即使 es
设置为0xf000
。
第一条指令读取自 0xfffffff0
,PCH 也可能会别名 0xf0000-0xfffff
至0xffff0000-0xffffffff
重置时,因此当 BSP 启动时,它将执行您转储的代码。
IIRC,除非明确唤醒,否则 AP 不会启动。
然后,BSP 将继续初始化硬件(从转储来看)。
在某些时候,它将设置 0xf0000-0xfffff
的属性映射。引导对内存的读取和写入(或仅写入然后读取)。
最终结果是,当处理器(硬件线程)启动时,它将执行闪存中的代码,直到执行远跳转。
此时cs
根据实模式规则正确计算基数(与虚幻模式非常相似),并且将从 0xf0000-0xfffff
获取指令。 (即来自 RAM)。
所有这一切同时cs
段值实际上没有改变。
BSP 在某个时刻将启动其多处理器初始化例程,向每个人(包括他自己)广播一个 INIT-SIPI-SIPI,这将导致 AP 进入休眠状态并发出 ljmp 0xf000:0xfff0
消息。对于 BSP。
这里的技巧是跳转的目标 0xf000:0xfff0
,与wbinvd
的总线地址不同。说明。
可能还有其他东西,可能是另一个初始化例程。
初始化结束时,BIOS 可以简单地重置 0xf0000-0xfffff
的属性。落入闪存(因此可以进行软件重置),防止(无意)转储中间代码。
这不是很有效,但 BIOS 通常不是代码的杰作。
我没有足够的元素来确定发生了什么,我的观点是 ljmp 0xf000:0xfff0
和 mov al, byte es:[0xfff0]
不必从他们所在的同一区域进行读取。
考虑到这一点,一切皆有可能。
只有适当的逆向工程才能证明这一点。
关于wbinvd
,我在评论中建议它可能与热启动设施有关,而 Peter Cordes 则建议它可能与缓存即 RAM 有关。
这是有道理的,但我想永远不会确定。
这也可能是 cargo 崇拜的一个例子,程序员根据谣言认为该指令是必要的。
关于assembly - 为什么 BIOS 入口点以 WBINVD 指令开头?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54274221/
2种参数:尺寸和价格。目前,我只能单击选择/突出显示尺寸列中的一个,也只能单击选择/突出显示价格列中的一个,而不会影响另一个列中的一个。 当我点击尺寸时,会添加一个 URL 参数“#size=4”。单
在css命名约定中,有什么原因,一些object最好以前缀o-和component开头> 以 c- 开头? 我知道 o- 代表 object 而 c- 代表 component,但为什么不呢?难道我们
这就很迷惑了,一下子,下面的代码就不行了。尝试让我的 Android 很好地显示网页已经显示的内容: HttpClient httpclient = new DefaultHttpClient();
我正在将我的网站发布到我无法控制的 IIS 服务器,我想从代码隐藏中了解它的 URL 是否以“http”或“https”开头。 首先,我在本地尝试了这两种解决方案,都返回了正确的值(“http”):
如果我运行: sbin/start-dfs.sh 然后它实际上并没有启动一个名称节点尽管打印: Starting namenodes on [0.0.0.0] 0.0.0.0: starting na
我正在开发一个包含一些数组的模块。现在我的数组包含: $omearray = array ( '#title' = 'title', 0 = array ( 'another array',
对于 PMD,我希望有一个规则来警告我那些以 my 开头的丑陋变量。 这意味着我必须接受所有不以my开头的变量。 所以,我需要一个正则表达式(re),其行为如下: re.match('myVar')
出于某种奇怪的原因,当我尝试使用 URLConnection 获取网页源时,我在输出中得到“null”。有人可以解释一下吗? 我的方法: public String getPageSource()
如何批量检查某个字符串(记录文本文件中的行)是否以特定单词开头? 我知道如何检查句子/行(字符串)中是否存在单词(子字符串),但我如何检查天气是否以这个词开头? 谢谢:) 最佳答案 这可以通过 FIN
我有一个列表,其中包含多个网址和一些字符串,例如#skipsideNav、#content。我正在从这些字符串中分离出 url if link.startswith('/'): local_u
我有以下 html 标记: 我想选择类 bubble bubble_white 和 bubble bubble_black。我正在考虑下面的代码,但它不起作用: $(".bubbl
我有一个用于文件名验证的正则表达式。在这里: /^[0-9a-zA-Z\^\&\'\@\{\}\[\]\,\$\=\!\-\#\(\)\.\%\+\~\_; ]+$/ 如何更改它以检查文件名不是以
我正在构建一个自动填充函数,它接受一个字符串输入并返回一个字符串建议列表。 Sequelize 的 iLike:query返回出现查询字符串的每个字符串。我想支持查询是前缀的字符串。例如当query=
我首先知道这可能是有史以来看起来最糟糕的正则表达式,但这里是。 我有这个正则表达式 (?:http://)?(?:www.)?youtu(?:be)?.(?:[a-z]){2,3}(?:[a-z/?=
尝试读取文件并根据行创建字典,跳过以#符号开头的行 文件示例: param1=val1 # here is comment 我的功能: def readFromFile(name): conf
我的程序正在读取文本文件并根据文本执行操作。但是文本的第一行是有问题的。显然它以“”开头。这弄乱了我的 startsWith() 检查。 为了理解这个问题,我使用了这段代码: System.ou
我的印象是变量名只能以字母和 _ 开头,但是在测试时,我还发现变量名可以以 $ 开头,如下所示: 代码 #include int main() { int myvar=13; int
我试过这个... Dim myMatches As String() = System.Text.RegularExpressions.Regex.Split(postRow.Item("Post")
开头
我正在使用CKEditor,默认情况下在内容的开头添加了。 即使将enterMode设置为,它也只会影响Enter键的作用,并保留开始的。 我遇到的问题是,如果文本以标记开头,它将围绕它包装,并且图像
我有一个List ,其中有五个字符串: abc def ghi jkl mno 我还有另一个字符串“pq”,我需要知道列表中的每个字符串是否都不以“pq”开头-我将如何使用LINQ(.NET 4.0)
我是一名优秀的程序员,十分优秀!