#001 VOID
#002 NTAPI
#003 KiInitializeKernel(IN PKPROCESS InitProcess,
# 004 IN PKTHREAD InitThread,
# 005 IN PVOID IdleStack,
# 006 IN PKPRCB Prcb,
# 007 IN CCHAR Number,
# 008 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
#009 {
上面传递的参数都是基于栈式,因此在这里就可以取到在汇编代码压栈参数。
#010 BOOLEAN NpxPresent;
#011 ULONG FeatureBits;
#012 ULONG PageDirectory[2];
#013 PVOID DpcStack;
#014 ULONG Vendor[3];
#015
#016 /* Detect and set the CPU Type */
#017 KiSetProcessorType();
上面调用函数KiSetProcessorType来检测当前硬件系统里的CPU类型,并且把CPU类型和特性保存到控制块PRCB里。因为不同的CPU具有不同的功能,比如INTEL、AMD、VIA都是X86的CPU,但它们是有很多浮点数指令不一样的,这样就需要针对不同的CPU作不同的处理。现在就来分析这个函数的实现,它的代码如下:
#001 VOID
#002 NTAPI
#003 KiSetProcessorType(VOID)
#004 {
#005 ULONG EFlags = 0, NewEFlags;
#006 ULONG Reg[4];
#007 ULONG Stepping, Type;
#008
#009 /* Start by assuming no CPUID data */
#010 KeGetCurrentPrcb()->CpuID = 0;
设置CPUID指令是否支持,这里初始化为不支持。
#011
#012 /* Save EFlags */
#013 Ke386SaveFlags(EFlags);
保存CPU当前的标志位,因为后面需要检测CPUID。
#014
#015 /* XOR out the ID bit and update EFlags */
#016 NewEFlags = EFlags ^ EFLAGS_ID;
#017 Ke386RestoreFlags(NewEFlags);
把CPUID指令位清空,再把它设置回到标志寄存器。
#018
#019 /* Get them back and see if they were modified */
#020 Ke386SaveFlags(NewEFlags);
获取标志寄存器的值,下面查看是否会改变这个值。
#021 if (NewEFlags != EFlags)
#022 {
如果标志位有变化,说明就是支持CPUID的指令。
#023 /* The modification worked, so CPUID exists. Set the ID Bit again. */
#024 EFlags |= EFLAGS_ID;
#025 Ke386RestoreFlags(EFlags);
#026
#027 /* Peform CPUID 0 to see if CPUID 1 is supported */
#028 CPUID(Reg, 0);
先操作CPUID的0类型的指令。
#029 if (Reg[0] > 0)
#030 {
#031 /* Do CPUID 1 now */
#032 CPUID(Reg, 1);
操作CPUID的1类型的指令。
#033
#034 /*
#035 * Get the Stepping and Type. The stepping contains both the
#036 * Model and the Step, while the Type contains the returned Type.
#037 * We ignore the family.
#038 *
#039 * For the stepping, we convert this: zzzzzzxy into this: x0y
#040 */
#041 Stepping = Reg[0] & 0xF0;
#042 Stepping <<= 4;
#043 Stepping += (Reg[0] & 0xFF);
#044 Stepping &= 0xF 0F ;
#045 Type = Reg[0] & 0xF00;
#046 Type >>= 8;
#047
#048 /* Save them in the PRCB */
#049 KeGetCurrentPrcb()->CpuID = TRUE;
#050 KeGetCurrentPrcb()->CpuType = (UCHAR)Type;
#051 KeGetCurrentPrcb()->CpuStep = (USHORT)Stepping;
上面获取到了CPU的类型,步进信息。
#052 }
#053 else
#054 {
#055 DPRINT1("CPUID Support lacking/n");
#056 }
#057 }
#058 else
#059 {
#060 DPRINT1("CPUID Support lacking/n");
#061 }
#062
#063 /* Restore EFLAGS */
#064 Ke386RestoreFlags(EFlags);
恢复原来标志寄存器值。
#065 }
其实这段代码是获取CPU类型和步进信息,不同的CPU获取的信息是不一样,下面通过其它软件获取到我的CPU信息,如下图:
在这个CPU应就是获取到CPU类型为6,而步进为FB。至于其它CPU信息,还会在后面继续探测和设置到内核数据结构里。