【我所认知的BIOS】->反汇编BIOS之Bootblock(6)
--关于S3与Normal reset BIOS的走向
By Lightseed
5/18/2010
一、BIOS的主流程
我们的BIOS主流程如图1所示,上一个章节我们的BIOS执行到了记录CPU type的东东,当时我们就发现其实在Record_CPU_type的前面还有其他函数。那么我们这节就来单独讨论这个问题。这个章节的内容是我们作为BIOS engineer必定要聊熟于心的东西,我想任何一个业内人士应该不会否认这点的。也是BIOS的一个走向的十字路口,搞清楚这章节我想对理解整个X86架构中的power management理解是一个很好的基础。
图1 BIOS主流程
二、Normal reset和Resume from Sx的算法
下面这段代码就是紧接了前面我们反汇编出来的BIOS源码的后半段。虽然这里短短数行,但是却把BIOS完全分成了两个不同的道路。Normal reset就会走平时我们理解的BIOS流程,继续进行后续的其他设备的初始化动作。而Resume from Sx的那条路就是从之前系统保存好的各个状态中逐个把系统的各个设备快速恢复他们的状态,进而BIOS把控制权交个OS,让OS自己也恢复到之前的状态。不过,后者我们暂时不去讨论,那个还牵涉到ACPI的部分,目前我们先说到这里,以后我肯定会和大家share的。(不过得让我把Normal reset这部分的BIOS和大家探讨完了以后哦。做事要有先后嘛~~)
_F000:E1CB SuperIO_INIT_Ret: ; CODE XREF: _F000:E28Ej
Call Detect_If_Power_failure;伪代码
_F000:E1E2 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
_F000:E1E5 dw 0E1E7h
_F000:E1E7 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
_F000:E1E7 mov dx, 4005h ; PM IO+5 Power Management 1 Control
_F000:E1EA in al, dx
_F000:E1EB cmp al, 0FFh ; If valid?
_F000:E1ED jz Not_Resume_From_Sx
_F000:E1EF and al, 1Ch ; Separate the 'Sleep Type' bits [bit 10~12]
_F000:E1EF ; 000b ON: Typically maps to S0 state.
_F000:E1EF ; 001b Asserts STPCLK#. Puts processor in Stop-Grant state. Optional to assert
_F000:E1EF ; CPUSLP# to put processor in sleep state: Typically maps to S1 state.
_F000:E1EF ; 010b Reserved
_F000:E1EF ; 011b Reserved
_F000:E1EF ; 100b Reserved
_F000:E1EF ; 101b Suspend-To-RAM. Assert SLP_S3#: Typically maps to S3 state.
_F000:E1EF ; 110b Suspend-To-Disk. Assert SLP_S3#, and SLP_S4#: Typically maps to S4 state.
_F000:E1EF ; 111b Soft Off. Assert SLP_S3#, SLP_S4#, and SLP_S5#: Typically maps to S5 state.
_F000:E1F1 cmp al, 14h
_F000:E1F3 jnz Not_Resume_From_Sx
_F000:E1F5 jmp Resume_From_S3 ; 如果是从S3回来,那么就BIOS进入到resume的分支。唤醒沉睡的系统了
_F000:E1F8 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
Not_Resume_From_Sx: ; 正常的BIOS boot
我说上面的这些短小的code就已经把大致的算法都说了,也许细心的大家也应该很容易弄明白的了。(哈哈。。。想想,其实BIOS并不是我们以前想的那么神秘对么?看看上面的代码,多简单哦~~相比起其他的大型算法而言,呵呵。。。不过不要高兴的太早哦-_-)容我慢慢道来:
①在这行中,
_F000:E1CE jmp Assume_Normal_Reset
用了ROM_CALL的做法,先假设当前的BIOS是Normal reset的。里面的函数,我想还是你自己跟一下比较好吧。
②接下来我要详细说一下Detect_If_Power_failure这个函数。这个函数的功能就是从南桥的power management的相关寄存器中取出相应的参数来做对比,check一下是否是系统有完全掉电,power failure。(下面这个函数实在是不想删它,保留着吧,因为这里的操作确实是很有意思。)
_F000:F6BC ;------------------------------------------------------------------------------------------------
_F000:F6BC Function: Detect_If_Power_failure
_F000:F6BC
_F000:F6BC Before detecting if resume from Sx, to detect if power failed.
_F000:F6BC If yes, clear the sleep state.
_F000:F6BC If no, go ahead.
_F000:F6BC ;------------------------------------------------------------------------------------------------
_F000:F6BC
_F000:F6BC Detect_If_Power_failure: ; CODE XREF: _F000:E1E2j
_F000:F6BC shl esp, 10h
_F000:F6C0 mov cx, 0F8A4h ; ICH6 General PM Configuration 3 Register
_F000:F6C3 mov sp, 0F6C9h
_F000:F6C6 jmp Get_Pci_Byte
_F000:F6C6 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
_F000:F6C9 dw 0F6CBh
_F000:F6CB ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
_F000:F6CB test al, 2 ; Power failure?
_F000:F6CB ; 0 = Indicates that the trickle current has not failed since the last time the bit was cleared. Software
_F000:F6CB ; clears this bit by writing a 1 to it.
_F000:F6CB ; 1 = Indicates that the trickle current (from the main battery or trickle supply) was removed or failed.
_F000:F6CD jz Not_Power_Failure
_F000:F6CF mov dx, 4005h ; PM IO+5 Power Management 1 Control
_F000:F6D2 in al, dx
_F000:F6D3 and al, 0E3h
_F000:F6D5 out dx, al ; Clear Sleep state. turn Sleep Enable off
_F000:F6D6
_F000:F6D6 Not_Power_Failure: ; CODE XREF: _F000:F6CDj
_F000:F6D6 shr esp, 10h
_F000:F6DA retn
_F000:F6DA ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
这个函数比较重要,所以要详细说明一下。_F000:F6C0这行是为了读取ICH6 General PM Configuration 3 Register这个寄存器。_F000:F6CB在后续我有做注释,它是去check这个寄存器中的bit 1,看看是否记录了南桥是否有Power failure的情况。(因为纵然你之前有可能系统是进入了S3,但是当power failure【其实就是完全掉电,电源插头拔掉的意思】的话,那么整个板子上的电都会掉,也就是说记录到内存里面的系统状态信息,就会丢失,那么必须要让BIOS从Normal reset那面启动。)如果是power failure的话,那么直接把Power Management 1 Control这个寄存器中记录SX状态的记录全部清掉。
我们来看看General PM Configuration 3 Register和Power Management 1 Control这两个寄存器的截图。
图2是General PM Configuration 3 Register寄存器中关于说明power failure的说明。图3是Power Management 1 Control中关于sleep type的说明。
图2
图3
③第二点中的函数弄清楚了,那么后续的动作就不难懂了。后续的动作,大致就是从Power Management 1 Control寄存器中读取出sleep type,然后判断,如果是确定系统是从Sx醒来的话,那么就进入到Resume_From_S3的BIOS分支中去。(那是后话,以后我们再研究。)如过是Normal reset那么就在_F000:E1F8这行中向80 port丢出debug code来,继续往后走了。
三、小结
虽然看上去似乎很简单,但是这里却很重要,所以花了比较多的笔墨来反复和大家说。BIOS中的十字路口我们就讲到这里,希望对大家有所启发。(如果想要了解关于S3的东西,那么我先建议您可以看看ACPI的spec,然后再结合ICH的datasheet先好好理解一下原理,这样对后续的讲解比较有帮助。)