?
es wäre sinnvoll, zuerst eax auszulesen, wenn man cpuid mit 0 ausgeführt hat, da man dadurch den maximalen cpuid steuerungscode erkennen kann.
dann wäre da noch Applicaton Note AP-485. keine ahnung ob das so richtig angegeben ist. der titel lautet: Processor Identification and the CPUID Instruction. da steht jede menge drin sogar mit ein codebeispielen. allerdings gilt das nur für intel prozessoren. ein großteil ist sicher auf prozessoren anderer hersteller anzuwenden.
hier mein code als kleine klasse:
class physical_cpu {
protected:
unsigned long _eax[4];
unsigned long _ebx[4];
unsigned long _ecx[4];
unsigned long _edx[4];
unsigned char _vendor[13];
public:
enum feature {
fpu = 1,
floating_point_unit = fpu,
vme = (1 << 1),
virtual_8086_mode_enhancements = vme,
de = (1 << 2),
debug_extension = de,
pse = (1 << 3),
page_size_extension = pse,
tsc = (1 << 4),
time_stamp_counter = tsc,
msr = (1 << 5),
model_specific_registers = msr,
pae = (1 << 6),
physical_address_extension = pae,
mce = (1 << 7),
machine_check_exception = mce,
cx8 = (1 << 8),
cmpxchg8b_instruction = cx8,
apic = (1 << 9),
advanced_programmable_interrupt_controler = apic,
sep = (1 << 11),
sysenter_present = sep,
mtrr = (1 << 12),
memory_type_range_register = mtrr,
pge = (1 << 13),
pte_global_extension = pge,
mca = (1 << 14),
machine_check_architecture = mca,
cmov = (1 << 15),
pat = (1 << 16),
page_attribute_table = pat,
pse36 = (1 << 17),
page_size_extension_with_36_bit_addresses = pse36,
psn = (1 << 18),
processor_serial_number = psn,
clfl = (1 << 19),
clflush_instruction = clfl,
ds = (1 << 21),
debug_store = ds,
acpi = (1 << 22),
mmx = (1 << 23),
multimedia_extension = mmx,
fxsr = (1 << 24),
fxsave_fxrestore_instructions = fxsr,
fx_save_restore = fxsr,
sse = (1 << 25),
sse2 = (1 << 26),
htt = (1 << 28),
hyper_threading_technology = htt,
tm = (1 << 29),
thermal_monitor = tm,
cpuid = 3,
est = 5,
enhanced_intel_speed_step_technology = est,
tm2 = 7,
thermal_monitor2 = tm2
};
physical_cpu(void) {
_eax[0] = _eax[1] = _eax[1] = _eax[3] = 0;
_ebx[0] = _ebx[1] = _ebx[1] = _ebx[3] = 0;
_ecx[0] = _ecx[1] = _ecx[1] = _ecx[3] = 0;
_edx[0] = _edx[1] = _edx[1] = _edx[3] = 0;
register unsigned long level = 0;
do {
asm ( "cpuid \n\t" : "=a"(_eax[level]), "=b"(_ebx[level]), "=c"(_ecx[level]), "=d"(_edx[level]) : "a"(level) );
level++;
} while(level <= _eax[0]);
(*(unsigned long*)_vendor) = _ebx[0];
(*(unsigned long*)(_vendor + 4)) = _edx[0];
(*(unsigned long*)(_vendor + 8)) = _ecx[0];
_vendor[12] = 0;
}
const bool supports(register const feature f) const {
switch(f) {
case fpu:
case vme:
case de:
case pse:
case tsc:
case msr:
case pae:
case mce:
case cx8:
case apic:
case mtrr:
case pge:
case mca:
case cmov:
case pat:
case pse36:
case psn:
case clfl:
case ds:
case acpi:
case mmx:
case fxsr:
case sse:
case sse2:
case htt:
case tm: { return (_edx[1] & f); break; }
case sep: { return (_edx[1] & f) && !((family() == 6) && (model() < 3) && (stepping() < 3)); break; }
case cpuid: { return true; break; /* currently not implemented */ }
case est: { return _ebx[1] & (1 << 7); break; }
case tm2: { return _ebx[1] & (1 << 8); break; }
default: { return false; }
}
}
inline const unsigned char* vendor(void) const { return _vendor; }
inline const unsigned long family(void) const { return ((_eax[1] >> 8) & 15); }
inline const unsigned long model(void) const { return ((_eax[1] >> 4) & 15); }
inline const unsigned long stepping(void) const { return (_eax[1] & 15); }
inline const unsigned long cpuid_level(void) const { return _eax[0]; }
inline const unsigned long feature_flags(void) const { return _edx[1]; }
inline const unsigned long extented_feature_flags(void) const { return _ecx[1] ; }
inline const unsigned long logical_prozessor_count(void) const {
/*
see Architecure Software Developer's Manuel, Volume 3: System Programming Guide
chapter 7.6.3, Detecting Hyper-Threading Technology
*/
if(_edx[1] & htt) { return (_ebx[1] >> 16) & 0xFF; }
return 1;
}
inline void halt(void) {
asm ( "hlt" );
return;
}
};