【我所认知的BIOS】->反汇编BIOS之Bootblock(2)--CPU micro code updateBy Lightseed5/12/20101、CPU micro code的背景先做个铺垫为什么要在BIOS刚刚开始跑的时候就来讲CPU的micro code。以下引用自网络:;-------------------------------------在十多年前的Pentium时代, INTEL曾经发布过有缺陷的CPU,因为浮点运算表边界上有几个数据错误,导致在某些应用会出现错误,这个错误概率很小,出错几率小于千万分之一,但在还是被捅出来了. INTEL为此召回CPU.从Pentium Pro起, INTEL决定给CPU留出一个补丁接口,当CPU内部有缺陷的时候,通过加载微码(Microcode),可以修复CPU的部分缺陷.INTEL说,他们只测试过的CPU都是加载了微码的,如果没有加载微码, INTEL不保证会出现什么问题.现在的CPU有一个CPUID,通过执行CPUID指令,可以知道当前CPU的版本和Stepping.根据这个信息,再给CPU打相应的补丁.下图就是CPUID=06D2, Rev.A2何时给CPU打补丁?在给CPU初始化的时候,就需要把INTEL提供的微码写进CPU去,因此,加载CPU微码就是系统BIOS的任务.如果系统的CPU是可更换的,那么其微码也需要更换.因此,在BIOD里,一般要包进若干个ID的CPU微码,以便工厂安排不同的SKU出货.如果BIOS发布是在CPU发布之前,那么BIOS里很可能就没有包进最新的微码,这个系统要使用新CPU的时候, CPU微码是无法加载的.另外, BIOS ROM容量有限,一个微码补丁最小有2K,如果平台兼容的CPU很多,则微码数量是十分巨大的,台式机某些主板可能兼容20多个CPU版本,那么微码的体积很大, BIOS里根本包不下这么多东西,于是,厂商不得不缩水,去掉一些不常用的微码.这些不常用的微码一般都是早期的CPU,如DOTHAN早期的A STEPPING就很可能没有对应的微码包进你的本本中去.不打补丁会有什么问题?INTEL说他们没测过不打补丁的CPU,也就不知道会出什么问题.呵呵,这显然,他们不想说太多技术细节而已.以俺的经验,如果不打补丁, 99.99%的时候,用户是感觉不到的,除非问题特别突出.只是俺遇到过几个明显的例子,为此出了几身汗.有几个案例:1,某Prescott CPU,在台式机上发热量特别大,超出Design Point,后来发现没加载微码,加上微码就正常了;2,某Pentium D CPU,进WINDOWS XP会蓝屏,以安全模式进去后,安装一个SP2补丁,就正常了.后来查出,也是微码没加载;3,某Pentium M架构CPU,在使用CPU内部TSC时,发现测出的CPU内部频率高出实现的4倍,如2GHz CPU测出却有8GHz,后查,也是没加载微码造成的异常.此类案例很多,特别是Core架构CPU,不但微码必须加载,而且要求尽早加载,否则,连BIOS都跑不完,系统就挂了.但是INTEL但至今没有任何官方对每个CPU微码版本进行描述的文件.怎么检查CPU微码是否加载?加载微码后,在CPU的MSR(机器特定寄存器)里可以读出版本号. INTEL IA-32编程手册上给出标准检查方法: MOV ECX, 008bhXOR EAX, EAXXOR EDX, EDXWRMSR ;向MSR 8BH写0,清除MSR中的信息MOV EAX, 0001CPUID ;读CPUID,让CPU查看微码版本,并把微码版本送到MSR 8B中MOV ECX, 008bhRDMSR ;读出当前CPU微码版本执行上面的代码后,如果EDX的值为0,则说明你的CPU微码是没有没加载的,你的CPU运行在有缺陷的状态.如果不为0,则显示的是当前微码版本号以上代码可以在DOS环境下,用DEBUG32调试界面执行.;----------------------------------------------------2、来来来,动手反汇编了!!!2.1 BIOS开始的代码如果您做了前两篇的东西,那么您会不难反汇编到这里来,(F000_FFF0跳到F000:E05B,然后再一个near jmp到了F000:E1B0)也就是下面这段代码。这段代码也就是Award BIOS最开始的代码部分了。之前我们有研究过,当CPU收到reset信号后它内部会做一系列的动作,而且当第一次从FFFF_FFF0H处取指令执行的时候,还会在对应的寄存器中保存一些相关的信息。在http://blog.csdn.net/lightseed/archive/2009/10/27/4735101.aspx中的图1您可以看到DX里面究竟存了什么值。(其实就是CPU的type。)在加注的时候,其实我个人更喜欢用英语注释哈。但是在之前有人说想要我用中文注释,想了又想,其实真的没有必要。如果连这点英语都看不懂,那么我想看datasheet也估计很困难。所以最后还是确定用English来注释。注解有误的话,还往各位谅解并指正,我会尽快修正。_F000:E1B0_F000:E1B0 loc_FE1B0: ; CODE XREF: _F000:E05BJ_F000:E1B0 mov gs, dx ; Save CPU type to GS_F000:E1B2 cli ; Close interrupt_F000:E1B3 cld_F000:E1B4 mov ax, cs_F000:E1B6 mov ss, ax ; CS and SS use the same segment, that can use ROM_CALL_F000:E1B8 mov sp, 0E1BEh ; First Use ROM_CALL_F000:E1BB jmp BT_CPU_Init ; Save esp(Return Address)这段代码也就是BIOS开始两个JMP后的代码,应该说比较好理解。在E1B8这里BIOS第一次用了上一节中提到的ROM_CALL这个宏。也遇到了第一个函数。BT_CPU_Init其实是在CPU开始跑code的最开始就针对特殊的CPU做patch。那么我就来详细和大家说说这个函数。2.2 CPU micro code update关于这个函数,原本我是有反汇编的源代码的,代码不复存在,但是原理却能够说清楚。(下面的说明,基本上就是这个函数所作的所有动作。反汇编出来的地址,其实我们可以暂且跳过,看原理就好。)上面micro code update的全部函数。一些简单的动作,我也在code中注释了。我着重拎一些不太好懂的说说。①_F000:0036在这行中,主要是先对比一下CPU是否为Cedar Mill B1,如果不是那么这个函数就不用跑了。Patch当然也就不用做了。(如果你照着我之前做的动作,那么这个行数应该是能对的上的,但是就算对不上也没有关系。只看我的算法讲解就可以了。)至于code的细节嘛,那你就自己慢慢体会吧。②_F000:0049在这行中,有一个对比的指令,其实很明显可以猜到这就是CPU micro code的标志。_F000:0049 cmp dword ptr [esi], '1SB*' ; Compare if it is CPU micro code?让我们用ultraedit打开之前说的那个BIOS的BIN来看看,如图1图1从图1中可以看出,“*BS1”是处于bin文件中的6000段的,也就是BIOS在实际跑中的E000段。所以和代码中的段刚好符合。如果把整个E000段都找完了还是找不到的话,那么就说明没有这个部分的micro code,直接就return了。③_F000:005B这行是为了得到CPU micro code的base address。这个地址是CBROM填入了,我们可以不用care它。只需要知道从这里可以得到CPU micro code就好了。见图2 bin文件中实际的micro code位置FFFE_57E0H。 图2紧接着,我们可以从对应的地址处看到实际的CPU micro code。如图3 图3而牵涉到CPU的micro code那么就不得不提它的结构。从micro code的第0个字节算起,会有如下一个表。CPU micro code开始几个flagHeaderVersion;offset 00hUpdateRevision;offset 04hUpdateData;offset 08hProcessorVersion;offset 0chChecksum;offset 10hLoaderRevision;offset 14hPlatform_ID;offset 18hDataSize;offset 1chTotalSize;offset 20hReserved;offset 24hUpdate_Data;offset 30h有了这几个说明,我想从Update_Micro_code_Start:开始的那些EBX+XX之类的比较就应该没有什么问题了哦。看看图3中,我还给大家标了一些标志出来。您可以追追看。④_F000:0080和_F000:0086两行操作的是MSR寄存器17H。它的说明在3 B里面有说,以下是截图。_F000:0080 mov ecx, 17h_F000:0086 rdmsr 图4⑤_F000:00A2这行主要是初始化MSR的79H。关于它的说明也是在3B里面见图5所示。_F000:009B mov eax, ebx_F000:009E add eax, 30h ; '0'_F000:00A2 mov ecx, 79h ; 'y' ; MSR register to update micro code_F000:00A8 xor edx, edx_F000:00AB wrmsr 图5经过那么多的判断后,最终只确定了一件事,那就是目前的CPU确实是应该update以下它的micro code了,于是在_F000:00AB wrmsr命令执行后,CPU开始升级它的micro code。至此关于CPU在Bootblock的时候升级micro code的动作就做完了。其实在后面POST的时候,也会有这样的动作,但是原理都是一样的。(稍微有些些差别)我们理解原理就好啦。呵呵。。。希望大家喜欢。