/* Get the processor features for the CPU */
FeatureBits = KiGetFeatureBits();
这里是通过函数KiGetFeatureBits来获取CPU特征位,它的代码如下:
#001 ULONG
#002 NTAPI
#003 KiGetFeatureBits(VOID)
#004 {
#005 PKPRCB Prcb = KeGetCurrentPrcb();
获取当前处理器控制块。
#006 ULONG Vendor;
#007 ULONG FeatureBits = KF_WORKING_PTE;
初始化为允许分页管理。
#008 ULONG Reg[4];
#009 BOOLEAN ExtendedCPUID = TRUE;
#010 ULONG CpuFeatures = 0;
#011
#012 /* Get the Vendor ID */
#013 Vendor = KiGetCpuVendor();
获取厂家标识。
#014
#015 /* Make sure we got a valid vendor ID at least. */
#016 if (!Vendor) return FeatureBits;
如果不认识的厂家CPU,就不用去获取特征了。
#017
#018 /* Get the CPUID Info. Features are in Reg[3]. */
#019 CPUID(Reg, 1);
获取CPU的ID信息。
#020
#021 /* Set the initial APIC ID */
#022 Prcb->InitialApicId = (UCHAR)(Reg[1] >> 24);
设置APIC(Advanced Programmable Interrupt Controller)的ID。
#023
根据不同的厂家处理。
#024 switch (Vendor)
#025 {
下面是INTEL的CPU特性识别。
#026 /* Intel CPUs */
#027 case CPU_INTEL:
#028 /* Check if it's a P6 */
#029 if (Prcb->CpuType == 6)
#030 {
#031 /* Perform the special sequence to get the MicroCode Signature */
#032 WRMSR(0x8B, 0);
#033 CPUID(Reg, 1);
#034 Prcb->UpdateSignature.QuadPart = RDMSR(0x8B);
#035 }
#036 else if (Prcb->CpuType == 5)
#037 {
#038 /* On P5, enable workaround for the LOCK errata. */
#039 KiI386PentiumLockErrataPresent = TRUE;
#040 }
#041
#042 /* Check for broken P6 with bad SMP PTE implementation */
#043 if (((Reg[0] & 0x0FF0) == 0x0610 && (Reg[0] & 0x 000F ) <= 0x9) ||
#044 ((Reg[0] & 0x0FF0) == 0x0630 && (Reg[0] & 0x 000F ) <= 0x4))
#045 {
#046 /* Remove support for correct PTE support. */
#047 FeatureBits &= ~KF_WORKING_PTE;
#048 }
#049
#050 /* Check if the CPU is too old to support SYSENTER */
#051 if ((Prcb->CpuType < 6) ||
#052 ((Prcb->CpuType == 6) && (Prcb->CpuStep < 0x0303)))
#053 {
#054 /* Disable it */
#055 Reg[3] &= ~0x800;
#056 }
#057
#058 /* Set the current features */
#059 CpuFeatures = Reg[3];
#060
#061 break;
#062
下面AMD的CPU特性识别处理。
#063 /* AMD CPUs */
#064 case CPU_AMD:
#065
#066 /* Check if this is a K5 or K6. (family 5) */
#067 if ((Reg[0] & 0x 0F 00) == 0x0500)
#068 {
#069 /* Get the Model Number */
#070 switch (Reg[0] & 0x 00F 0)
#071 {
#072 /* Model 1: K5 - 5k86 (initial models) */
#073 case 0x0010:
#074
#075 /* Check if this is Step 0 or 1. They don't support PGE */
#076 if ((Reg[0] & 0x 000F ) > 0x03) break;
#077
#078 /* Model 0: K5 - SSA5 */
#079 case 0x0000:
#080
#081 /* Model 0 doesn't support PGE at all. */
#082 Reg[3] &= ~0x2000;
#083 break;
#084
#085 /* Model 8: K6-2 */
#086 case 0x0080:
#087
#088 /* K6-2, Step 8 and over have support for MTRR. */
#089 if ((Reg[0] & 0x 000F ) >= 0x8) FeatureBits |= KF_AMDK6MTRR;
#090 break;
#091
#092 /* Model 9: K6-III
#093 Model D: K6-2+, K6-III+ */
#094 case 0x0090:
#095 case 0x00D0:
#096
#097 FeatureBits |= KF_AMDK6MTRR;
#098 break;
#099 }
#100 }
#101 else if((Reg[0] & 0x 0F 00) < 0x0500)
#102 {
#103 /* Families below 5 don't support PGE, PSE or CMOV at all */
#104 Reg[3] &= ~(0x08 | 0x2000 | 0x8000);
#105
#106 /* They also don't support advanced CPUID functions. */
#107 ExtendedCPUID = FALSE;
#108 }
#109
#110 /* Set the current features */
#111 CpuFeatures = Reg[3];
#112
#113 break;
#114
其它X86的CPU还没有处理。
#115 /* Cyrix CPUs */
#116 case CPU_CYRIX:
#117 break;
#118
#119 /* Transmeta CPUs */
#120 case CPU_TRANSMETA:
#121 /* Enable CMPXCHG8B if the family (>= 5), model and stepping (>= 4.2) support it */
#122 if ((Reg[0] & 0x0FFF) >= 0x0542)
#123 {
#124 WRMSR(0x80860004, RDMSR(0x80860004) | 0x0100);
#125 FeatureBits |= KF_CMPXCHG8B;
#126 }
#127
#128 break;
#129
#130 /* Centaur, IDT, Rise and VIA CPUs */
#131 case CPU_CENTAUR:
#132 case CPU_RISE:
#133 /* These CPUs don't report the presence of CMPXCHG8B through CPUID.
#134 However, this feature exists and operates properly without any additional steps. */
#135 FeatureBits |= KF_CMPXCHG8B;
#136
#137 break;
#138 }
#139
转换CPUID为内核使用的标识。
#140 /* Convert all CPUID Feature bits into our format */
#141 if (CpuFeatures & 0x00000002) FeatureBits |= KF_V86_VIS | KF_CR4;
#142 if (CpuFeatures & 0x00000008) FeatureBits |= KF_LARGE_PAGE | KF_CR4;
#143 if (CpuFeatures & 0x00000010) FeatureBits |= KF_RDTSC;
#144 if (CpuFeatures & 0x00000100) FeatureBits |= KF_CMPXCHG8B;
#145 if (CpuFeatures & 0x00000800) FeatureBits |= KF_FAST_SYSCALL;
#146 if (CpuFeatures & 0x00001000) FeatureBits |= KF_MTRR;
#147 if (CpuFeatures & 0x00002000) FeatureBits |= KF_GLOBAL_PAGE | KF_CR4;
#148 if (CpuFeatures & 0x00008000) FeatureBits |= KF_CMOV;
#149 if (CpuFeatures & 0x00010000) FeatureBits |= KF_PAT;
#150 if (CpuFeatures & 0x00200000) FeatureBits |= KF_DTS;
#151 if (CpuFeatures & 0x00800000) FeatureBits |= KF_MMX;
#152 if (CpuFeatures & 0x01000000) FeatureBits |= KF_FXSR;
#153 if (CpuFeatures & 0x02000000) FeatureBits |= KF_XMMI;
#154 if (CpuFeatures & 0x04000000) FeatureBits |= KF_XMMI64;
#155
检查CPU是否具有超线程。
#156 /* Check if the CPU has hyper-threading */
#157 if (CpuFeatures & 0x10000000)
#158 {
#159 /* Set the number of logical CPUs */
#160 Prcb->LogicalProcessorsPerPhysicalProcessor = (UCHAR)(Reg[1] >> 16);
#161 if (Prcb->LogicalProcessorsPerPhysicalProcessor > 1)
#162 {
#163 /* We're on dual-core */
#164 KiSMTProcessorsPresent = TRUE;
#165 }
#166 }
#167 else
#168 {
#169 /* We only have a single CPU */
#170 Prcb->LogicalProcessorsPerPhysicalProcessor = 1;
#171 }
#172
#173 /* Check if CPUID 0x80000000 is supported */
#174 if (ExtendedCPUID)
#175 {
#176 /* Do the call */
#177 CPUID(Reg, 0x80000000);
#178 if ((Reg[0] & 0xffffff00) == 0x80000000)
#179 {
#180 /* Check if CPUID 0x80000001 is supported */
#181 if (Reg[0] >= 0x80000001)
#182 {
#183 /* Check which extended features are available. */
#184 CPUID(Reg, 0x80000001);
#185
#186 /* Check if NX-bit is supported */
#187 if (Reg[3] & 0x00100000) FeatureBits |= KF_NX_BIT;
#188
#189 /* Now handle each features for each CPU Vendor */
#190 switch (Vendor)
#191 {
#192 case CPU_AMD:
#193 case CPU_CENTAUR:
#194 if (Reg[3] & 0x80000000) FeatureBits |= KF_3DNOW;
#195 break;
#196 }
#197 }
#198 }
#199 }
#200
#201 /* Return the Feature Bits */
#202 return FeatureBits;
#203 }
现在看看什么是APIC,APIC (高级可编程中断控制器)对计算机来讲有两个作用,
一是管理IRQ的分配,可以把传统的16个IRQ扩展到24个(传统的管理方式叫PIC),以适应更多的设备。
二是管理多CPU。
不过,如果板卡不是非常多的话,关闭 APIC对系统是没有什么影响的。
要实现SMP功能,我们使用的CPU必须具备以下要求:
CPU内部必须内置APIC单元。Intel 多处理规范的核心就是高级可编程中断控制器(Advanced Programmable Interrupt Controllers–APICs)的使用。CPU通过彼此发送中断来完成它们之间的通信。通过给中断附加动作(actions),不同的CPU可以在某种程度上彼此进行控制。每个CPU有自己的APIC(成为那个CPU的本地APIC),并且还有一个I/O APIC来处理由I/O设备引起的中断,这个I/O APIC是安装在主板上的,但每个CPU上的APIC则不可或缺,否则将无法处理多CPU之间的中断协调。