aboutsummaryrefslogtreecommitdiff
path: root/x86.c
blob: 647d6ac6b3b15ce3b6d20fc6349e8ff4245a7226 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "common.h"

/***
 *
 * @param leaf
 * @param reg union regs_t
 * @return contents of eax register
 */
unsigned int CPUID(unsigned int leaf, union regs_t *reg) {
    memset(reg, 0, sizeof(*reg));
    __get_cpuid(leaf, &reg->gpr.eax, &reg->gpr.ebx, &reg->gpr.ecx, &reg->gpr.edx);
    return reg->gpr.eax;
}

int is_cpu_hyperthreaded() {
    union regs_t reg;

    CPUID(1, &reg);
    // Hyperthreading feature flag is located in bit 28 of EDX (regs[3])
    if (reg.gpr.edx & bit_HTT) {
        // hyperthreaded
        return 1;
    }
    return 0;
}

int is_cpu_virtual() {
    union regs_t reg;

    CPUID(1, &reg);
    // Virtualization flag is located in bit 31 of ECX
    if (reg.gpr.ecx & bit_VRT) {
        return 1;
    }
    return 0;
}

char *get_sys_product() {
    union regs_t reg;
    char *vendor;

    vendor = NULL;
    if (is_cpu_virtual()) {
        vendor = calloc(255, sizeof(*vendor));
        if (!vendor) {
            return NULL;
        }
        CPUID(0x40000000, &reg);
        strncat(vendor, (char *) &reg.bytes[1], sizeof(reg.bytes));
        rstrip(vendor);
    }
#if defined(__linux__)
    if (!vendor || !strlen(vendor)) {
        vendor = get_sys_dmi_product();
        rstrip(vendor);
    }
#elif defined(__APPLE__)
    if (!vendor || !strlen(vendor)) {
        vendor = get_sys_product_darwin();
        rstrip(vendor);
    }
#endif
    return vendor;
}

unsigned int get_cpu_count() {
    union regs_t reg;
    unsigned int result;

    if (is_cpu_hyperthreaded()) {
        CPUID(1, &reg);
        // cpu count is located in bits 16:23 of EBX
        result = reg.gpr.ebx >> 16 & 0xff;
    } else { // Legacy check
        // Core Count is located in 0:7 of ECX
        CPUID(0x80000008, &reg);
        result = 1 + (reg.gpr.ecx & 0xff);
    }

#if defined(__linux__) || (defined(__APPLE__) || defined(TARGET_OS_MAC))
    if (result == 1) {
        // One CPU might indicate we were unable to poll the information
        // See what the kernel thinks
        result = sysconf(_SC_NPROCESSORS_ONLN);
    }
#endif
    return result;
}

char *get_cpu_manufacturer() {
    union regs_t reg;
    char *manufacturer;

    CPUID(0, &reg);
    manufacturer = calloc(sizeof(reg.bytes), sizeof(*reg.bytes));
    if (!manufacturer) {
        return NULL;
    }
    strncat(manufacturer, (char *) &reg.bytes[1], 4);
    strncat(manufacturer, (char *) &reg.bytes[3], 4);
    strncat(manufacturer, (char *) &reg.bytes[2], 4);
    return manufacturer;
}

char *get_cpu_vendor() {
    union regs_t reg;
    char *vendor;

    vendor = calloc(sizeof(reg.bytes) * 3, sizeof(*reg.bytes));
    for (unsigned int leaf = 2; leaf < 5; leaf++) {
        CPUID(0x80000000 + leaf, &reg);
        strncat(vendor, (char *) reg.bytes, sizeof(reg.bytes));
    }

    rstrip(vendor);
    return vendor;
}