Hi,
Ok, I ran into some troubles and partially changed my plans to suit, so I thought I'd describe exactly what I'm doing (and cover Smiddy's "do it during OS install" idea at the same time).
First, the troubles:
- For AMD CPUs the official brand name string selection algorithm (intended to be done by the BIOS) relies on accurately measuring the speed of the CPU, and in some cases depends on the L2 cache size, the CPU speed and the FSB speed (e.g. AMD Athlon MP and XP CPUs) . I'm not convinced I can accurately measure the speed of the CPU in all cases (taking into account SMM and power/temperature management, that can make the CPU seem slower than it really is).
For VIA/IDT/Centaur CPUs I can't find enough information for some models (Ezra-T, Esther), and for most of them different branded CPUs are practically identical - there's the "normal" model (like "C3/Samuel 2") and the equivelent "Eden ESP ???" model. I don't know what the difference is, but family/model/stepping, cache size, features, etc are all identical (might just be a different CPU socket for all I can tell).
For GeodeGX2 and similar, if I do know it's one of these chips I can't do much about it because all CPUID information can be false. I can correct the vendor ID but that might be all, depending on what was changed.
For SiS I can't get any information at all.
Now for what I'm doing...
During boot, a boot loader loads a boot image into memory which contains everything used after that (until some device drivers are working). All code is modular, where modules come from the boot image. The boot loader starts a "boot manager" module, which uses other modules including the CPU detection module.
This means I can have 100 different CPU detection modules without much trouble, and it will be possible for other people to write custom CPU detection modules. For e.g. for an embedded system where the OS is burnt onto a ROM and the entire system is sealed the manufacturer would probably replace the CPU detection code with some static "the CPU is X" code that doesn't do any detection. There's also a boot script (a "<variable> = <value>" format) which can be used to control the behaviour of any boot modules. Despite all of this, for normal desktop/server situations the code I'm writing is fast and compresses well, so there shouldn't be much reason to skip this checking each boot.
The CPU detection module is responsible for detecting how many CPUs there are, the relationships between the CPUs, and what each CPU is (features, caches, etc). Some of the results are used to determine which modules are used later on (for e.g. if all CPUs support long mode the OS automatically decides to use 64-bit kernel modules). This may involve loading a CPU specific kernel module to support vendor specific CPU features (like MTRRs, power management and machine check exception).
In addition, the CPU detection code sets 3 groups of flags. The first group is which features the CPU actually supports reliably (not what it says it supports), where each flag uniquely represents a specific feature, including things like 3DNow, cryptography extensions, VMX, SVM and power management (LongRun, LongHaul, etc).
The second set of flags ("CPU errata") are used for CPU bug work-arounds, for e.g. if a Pentium is detected the "F00F" flag would be set and later code would implement the work-around for it.
The third set of flags ("CPU flaws") are used for warning system administrators about CPU bugs that can cause "erratic behavior or reduced stability". The idea here is that the system administrator can easily decide if the CPU should be used or not. For a critical 24/7 server you might not want to use something that locks up occasionally due to bus problems (some Pentium II chips). For a server in a bank used for handling large transactions, calculating interest, etc, you might not want a CPU with certain FPU accuracy problems (Pentium).
There's also a smaller set of "instruction set" flags used to determine which applications can run (MMX, extendedMMX, 3DNow, extended 3DNow, SSE1/2/3). For e.g. if an application requires MMX it can set a flag in it's header that the OS will check before allowing it to start. In some cases (e.g. an SMP machine with mixed Pentiums) this can mean the application is restricted to the CPUs that support MMX and prevented from running on CPUs that don't.
Now, getting back to the "CPUID forgery", it will go like this. If the CPU is unforgable or if the CPU detection code can reliable detect the correct details, then everything is good. If the code can't reliably detect the CPU brand string, then it'll set a "CPU errata" flag to let others know that the brand string may be wrong (but it won't effect the OS). If the family/model/stepping details can't be detected reliably then it'll set a "CPU flaw" flag to indicate that (under certain conditions) erratic behavior or reduced stability is possible. If the CPUs features can't be detected reliably, the OS will just use a reduced set of features.
This means for most CPUs everything is fine. For some AMD CPUs you'd get the "brand string might be wrong" errata flag. For some IDT/VIA/Centaur CPUs and some NSC/Geode CPUs you might get the errata flag and the "may be unstable due to wrong CPU model" flaw flag, and for some NSC/Geode CPUs you might also get a reduced set of features.
In addition, there's another flaw flag which is set when my code doesn't know if the CPU has bugs or not. For most Intel and AMD CPUs the information is available from the manufacturers and this flag can be cleared (once I write all the CPU bug detection code for the CPUs). For almost all other manufacturers and for older 80486s this flag would be set.
The end result is that system administrators will be able to easily figure out which potential problems each computer has (without spending hours looking through manufacturer documentation), and my OS can (potentially) become far more reliable than OS's like Windows, Linux, etc.
Cheers,
Brendan