CPUID: Why must MISC_ENABLE.LCMV be set to 0 for some functions? Can I temporarily overwrite it?
I'm trying to use CPUID, but there are some strings attached. According to sandpile.org's CPUID page, CPUID standard functions 0000_0004h and up will only work if the MISC_ENABLE.LCMV flag is set to 0. This flag is bit 22 of model-specific register (MSR) 1A0. Apparently, this limitation is due to a bug in Windows NT (thanks for making things easier on me, Microsoft ;)).
I can test for the presence of the LCMV flag with CPUID 0000_0001h (ecx flags, bit 3). Assuming it is present though, what exactly is it for, and why does it have such an effect on CPUID? Is MSR 1A0 a read/write register or read-only?开发者_运维知识库 How is such a special-purpose register even read from/written to using assembly code?
If the register is technically read/write, is it safe to reset bit 22 to 0 for the duration of the CPUID instruction, before restoring it to its original setting? Or am I pretty much screwed if it's set incorrectly (i.e. enabled)?
Finally, sandpile uses the wording,"This level is only enabled if MISC_ENABLE.LCMV is set to 0. This is due to a Windows NT bug." If a bunch of standard levels are specifically disabled for this reason, will that be reflected in the output of CPUID level 0000_000h's eax register (maximum supported standard level)?
Phew...I think that's about it.
You will want to download Intel® 64 and IA-32 Architectures Software Developer’s Manuals as it contains all the requested information.
I can test for the presence of the LCMV flag with CPUID 0000_0001h (ecx flags, bit 3). Assuming it is present though, what exactly is it for, and why does it have such an effect on CPUID?
The full name of the flag (see Vol. 3B B-17) is " Limit CPUID MaxVal" and states its effect as "When this bit is set to 1, CPUID.00H returns a maximum value in EAX[7:0] of 3".
Is MSR 1A0 a read/write register or read-only?
Read/Write according to the Intel manual (with one caveat, read on).
How is such a special-purpose register even read from/written to using assembly code?
You read using RDMSR
(Vol. 2B 4-301) and write using WRMSR
(Vol. 2B 4-505), but note that they require you to run in either real mode or privilege level 0 (a.k.a. kernel mode).
If the register is technically read/write, is it safe to reset bit 22 to 0 for the duration of the CPUID instruction, before restoring it to its original setting? Or am I pretty much screwed if it's set incorrectly (i.e. enabled)?
It should really only be set on buggy operating systems and there you shouldn't clear it. If you're writing your own kernel by all means go ahead and clear it as you yourself state it's only for buggy versions of NT and similar circumstances.
Finally, sandpile uses the wording,"This level is only enabled if MISC_ENABLE.LCMV is set to 0. This is due to a Windows NT bug." If a bunch of standard levels are specifically disabled for this reason, will that be reflected in the output of CPUID level 0000_000h's eax register (maximum supported standard level)?
Yes, it is specifically designed to force it to return 3 in this case (see the above description).
I only have a little bit to add to the very comprehensive answer given above. (I would have added it as a comment, but I can't add comments yet.) An Intel engineer provided a few more historical details on that issue at https://software.intel.com/en-us/forums/topic/306523?language=en#comment-1590394 Quoting from there with minor formatting/spelling fixes:
Some BIOS versions have a menu setting that allows the user to limit the max value (or leaf index) that CPUID will support after the next reboot. The BIOS provided this option solely for the purpose of allowing the end-user to work around a Microsoft Windows* NT 4.0 installation issue, because Windows NT 4.0's installation program had a bug and would blue-screen if CPUID reported it supports leaves higher than 3. Enabling the BIOS option to limit CPUIDs EAX maxvalue to 3 is needed only for the purpose of installing Windows NT 4.0. In all other situation, the BIOS should be configured to not restrict CPUID EAX max values.
When CPUID is limited with the restriction that it supports no higher leaves than 3, on the Intel Pentium 4 and later processor, leaf 3 is [also] not supported, so requesting CPUID to report leaf 4 will receive data from CPUID on leaf 2 (the highest leaf index). When software executes CPUID with an invalid EAX input value (i.e. leaf index), CPUID will report with the the highest leaf that it supports under the current runtime configuration.
Furthermore, the MSR flag in question is called "IA32_MISC_ENABLE.BOOT_NT4[bit 22]" in the current (June 2014) edition of the Intel® 64 and IA-32 Architectures Software Developer’s Manual. I suspect they decided to rename it at some point to make it more obvious that it is a legacy issue that can be safely ignored nowadays.
精彩评论