+/*
+ * Determine cpu model and set global cpuid_xxx variables
+ *
+ * Relies on 386 eflags bit 18 (AC) always being zero & 486 preserving it.
+ * Relies on 486 eflags bit 21 (ID) always being zero & 586 preserving it.
+ * Relies on CPUID instruction for next x86 generations
+ * (assumes cpuid-family-homogenous MPs; else convert to per-cpu array)
+ */
+
+ENTRY(set_cpu_model)
+ FRAME
+ pushl %ebx /* save ebx */
+ andl $~0x3,%esp /* Align stack to avoid AC fault */
+ pushfl /* push EFLAGS */
+ popl %eax /* pop into eax */
+ movl %eax,%ecx /* Save original EFLAGS */
+ xorl $(EFL_AC+EFL_ID),%eax /* toggle ID,AC bits */
+ pushl %eax /* push new value */
+ popfl /* through the EFLAGS register */
+ pushfl /* and back */
+ popl %eax /* into eax */
+ movb $(CPUID_FAMILY_386),EXT(cpuid_family)
+ pushl %ecx /* push original EFLAGS */
+ popfl /* restore EFLAGS */
+ xorl %ecx,%eax /* see what changed */
+ testl $ EFL_AC,%eax /* test AC bit */
+ jz 0f /* if AC toggled (486 or higher) */
+
+ movb $(CPUID_FAMILY_486),EXT(cpuid_family)
+ testl $ EFL_ID,%eax /* test ID bit */
+ jz 0f /* if ID toggled use cpuid instruction */
+
+ xorl %eax,%eax /* get vendor identification string */
+ .word 0xA20F /* cpuid instruction */
+ movl %eax,EXT(cpuid_value) /* Store high value */
+ movl %ebx,EXT(cpuid_vid) /* Store byte 0-3 of Vendor ID */
+ movl %edx,EXT(cpuid_vid)+4 /* Store byte 4-7 of Vendor ID */
+ movl %ecx,EXT(cpuid_vid)+8 /* Store byte 8-B of Vendor ID */
+ movl $1,%eax /* get processor signature */
+ .word 0xA20F /* cpuid instruction */
+ movl %edx,EXT(cpuid_feature) /* Store feature flags */
+ movl %eax,%ecx /* Save original signature */
+ andb $0xF,%al /* Get Stepping ID */
+ movb %al,EXT(cpuid_stepping) /* Save Stepping ID */
+ movl %ecx,%eax /* Get original signature */
+ shrl $4,%eax /* Shift Stepping ID */
+ movl %eax,%ecx /* Save original signature */
+ andb $0xF,%al /* Get Model */
+ movb %al,EXT(cpuid_model) /* Save Model */
+ movl %ecx,%eax /* Get original signature */
+ shrl $4,%eax /* Shift Stepping ID */
+ movl %eax,%ecx /* Save original signature */
+ andb $0xF,%al /* Get Family */
+ movb %al,EXT(cpuid_family) /* Save Family */
+ movl %ecx,%eax /* Get original signature */
+ shrl $4,%eax /* Shift Stepping ID */
+ andb $0x3,%al /* Get Type */
+ movb %al,EXT(cpuid_type) /* Save Type */
+
+ movl EXT(cpuid_value),%eax /* Get high value */
+ cmpl $2,%eax /* Test if processor configuration */
+ jle 0f /* is present */
+ movl $2,%eax /* get processor configuration */
+ .word 0xA20F /* cpuid instruction */
+ movl %eax,EXT(cpuid_cache) /* Store byte 0-3 of configuration */
+ movl %ebx,EXT(cpuid_cache)+4 /* Store byte 4-7 of configuration */
+ movl %ecx,EXT(cpuid_cache)+8 /* Store byte 8-B of configuration */
+ movl %edx,EXT(cpuid_cache)+12 /* Store byte C-F of configuration */
+0:
+ popl %ebx /* restore ebx */
+ EMARF
+ ret /* return */
+