cpuid/x86: use leaf 80000008 for AMD physical core counts
This commit is contained in:
parent
471c81c43a
commit
0df4fd4bfa
@ -42,17 +42,48 @@ cpuid_t cpuid (u32 query, u32 param = 0)
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace {
|
||||
enum vendor_t {
|
||||
INTEL,
|
||||
AMD,
|
||||
|
||||
UNKNOWN
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static constexpr
|
||||
vendor_t
|
||||
find_vendor (cpuid_t const &leaf0)
|
||||
{
|
||||
constexpr struct {
|
||||
u32 b, c, d;
|
||||
vendor_t vendor;
|
||||
} VALUES[] = {
|
||||
{ 0x68747541, 0x444d4163, 0x69746e65, AMD },
|
||||
{ 0x756e6547, 0x6c65746e, 0x49656e69, INTEL },
|
||||
};
|
||||
|
||||
for (auto const &v: VALUES) {
|
||||
if (v.b == leaf0.b && v.c == leaf0.c && v.d == leaf0.d)
|
||||
return v.vendor;
|
||||
}
|
||||
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
x86::x86 ()
|
||||
{
|
||||
const auto &[largest_function, vendor0, vendor2, vendor1] = cpuid (0);
|
||||
(void)largest_function;
|
||||
auto const leaf0 = cpuid (0);
|
||||
memcpy (vendor_name.data () + 0, &leaf0.b, sizeof (leaf0.b));
|
||||
memcpy (vendor_name.data () + 4, &leaf0.d, sizeof (leaf0.d));
|
||||
memcpy (vendor_name.data () + 8, &leaf0.c, sizeof (leaf0.c));
|
||||
|
||||
memcpy (vendor_name.data () + 0, &vendor0, sizeof (vendor0));
|
||||
memcpy (vendor_name.data () + 4, &vendor1, sizeof (vendor1));
|
||||
memcpy (vendor_name.data () + 8, &vendor2, sizeof (vendor2));
|
||||
|
||||
const bool is_amd = vendor0 == 0x68747541 && vendor1 == 0x69746e65 && vendor2 == 0x444d4163;
|
||||
auto const vendor = find_vendor (leaf0);
|
||||
|
||||
{
|
||||
auto features = cpuid (1);
|
||||
@ -66,7 +97,10 @@ x86::x86 ()
|
||||
simd.sse2 = features.d & (1u << 26);
|
||||
|
||||
cores.hyper_threading = features.d & (1u << 28);
|
||||
cores.logical = from_bits (features.b, 23, 16);
|
||||
if (cores.hyper_threading)
|
||||
cores.logical = from_bits (features.b, 23, 16);
|
||||
else
|
||||
cores.logical = 0;
|
||||
}
|
||||
|
||||
{
|
||||
@ -79,16 +113,36 @@ x86::x86 ()
|
||||
memcpy (&product_name[0x20], &product2, sizeof (product2));
|
||||
}
|
||||
|
||||
// Function 4 isn't implemented by AMD. Intel uses it for cache
|
||||
// descriptors. It has some useful information (like procesor counts) but
|
||||
// it's ugly as sin; try to avoid using it.
|
||||
// { (void)cpuid (0x0b, 4); }
|
||||
if (vendor == INTEL) {
|
||||
cores.logical = cores.physical = 0;
|
||||
|
||||
if (is_amd) {
|
||||
auto long_mode = cpuid (0x8000'0008);
|
||||
auto apic_id_size = from_bits (long_mode.c, 15, 12);
|
||||
(void)apic_id_size;
|
||||
cores.physical = 0; //from_bits (long_mode.c, 7, 0) + 1;
|
||||
for (int level = 0; true; ++level) {
|
||||
auto const param = cpuid (0x4, level);
|
||||
|
||||
// The final level will set the 'cache type' bits to zero to
|
||||
// indicate there are no more caches.
|
||||
if ((param.a & 0b1111) == 0)
|
||||
break;
|
||||
|
||||
cores.physical = max (
|
||||
cores.physical,
|
||||
cruft::cast::lossless<int> (from_bits (param.a, 31, 26)) + 1
|
||||
);
|
||||
cores.logical = max (
|
||||
cores.physical,
|
||||
cruft::cast::lossless<int> (from_bits (param.a, 25, 14)) + 1
|
||||
);
|
||||
}
|
||||
} else if (vendor == AMD) {
|
||||
auto const size_identifiers = cpuid (0x8000'0008);
|
||||
|
||||
if (auto const apic_id_size = from_bits (size_identifiers.c, 15, 12); apic_id_size) {
|
||||
cores.physical = 1 << (apic_id_size - 1);
|
||||
} else {
|
||||
cores.physical = (size_identifiers.c & 0xff) + 1;
|
||||
}
|
||||
} else {
|
||||
cores.physical = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user