diff mbox series

[2/9] util: Add cpuinfo-i386.c

Message ID 20230518044058.2777467-3-richard.henderson@linaro.org
State New
Headers show
Series Host-specific includes, begin cpuinfo.h | expand

Commit Message

Richard Henderson May 18, 2023, 4:40 a.m. UTC
Add cpuinfo.h for i386 and x86_64, and the initialization
for that in util/.  Populate that with a slightly altered
copy of the tcg host probing code.  Other uses of cpuid.h
will be adjusted one patch at a time.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/host/i386/cpuinfo.h   | 38 ++++++++++++++
 include/host/x86_64/cpuinfo.h |  1 +
 util/cpuinfo-i386.c           | 97 +++++++++++++++++++++++++++++++++++
 util/meson.build              |  4 ++
 4 files changed, 140 insertions(+)
 create mode 100644 include/host/i386/cpuinfo.h
 create mode 100644 include/host/x86_64/cpuinfo.h
 create mode 100644 util/cpuinfo-i386.c

Comments

Juan Quintela May 18, 2023, 9:35 a.m. UTC | #1
Richard Henderson <richard.henderson@linaro.org> wrote:
> Add cpuinfo.h for i386 and x86_64, and the initialization
> for that in util/.  Populate that with a slightly altered
> copy of the tcg host probing code.  Other uses of cpuid.h
> will be adjusted one patch at a time.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Juan Quintela <quintela@redhat.com>

For what is worth my vote O:-)

> +#define CPUINFO_ALWAYS          (1u << 0)  /* so cpuinfo is nonzero */
> +#define CPUINFO_CMOV            (1u << 1)
> +#define CPUINFO_MOVBE           (1u << 2)
> +#define CPUINFO_LZCNT           (1u << 3)
> +#define CPUINFO_POPCNT          (1u << 4)
> +#define CPUINFO_BMI1            (1u << 5)
> +#define CPUINFO_BMI2            (1u << 6)
> +#define CPUINFO_SSE2            (1u << 7)
> +#define CPUINFO_SSE4            (1u << 8)
> +#define CPUINFO_AVX1            (1u << 9)
> +#define CPUINFO_AVX2            (1u << 10)
> +#define CPUINFO_AVX512F         (1u << 11)
> +#define CPUINFO_AVX512VL        (1u << 12)
> +#define CPUINFO_AVX512BW        (1u << 13)
> +#define CPUINFO_AVX512DQ        (1u << 14)
> +#define CPUINFO_AVX512VBMI2     (1u << 15)
> +#define CPUINFO_ATOMIC_VMOVDQA  (1u << 16)
> +
> +/* Initialized with a constructor. */
> +extern unsigned cpuinfo;

On one hand, it is weird having a flags variable that is only 32bit.  I
am so user to put 64 bit flags. Future proof, blah, blah, ...

On the other hand, if tcg has survived for so long with only 16 bits, it
is inside posibility that 32bits are more than enough.

> +unsigned cpuinfo;
> +
> +/* Called both as constructor and (possibly) via other constructors. */
> +unsigned __attribute__((constructor)) cpuinfo_init(void)
> +{
> +    unsigned info = cpuinfo;
> +
> +    if (info) {
> +        return info;
> +    }

Have to look several times to this, because info "needed to be"" a
static variable, right? O:-)
Richard Henderson May 18, 2023, 12:45 p.m. UTC | #2
On 5/18/23 02:35, Juan Quintela wrote:
> Richard Henderson <richard.henderson@linaro.org> wrote:
>> Add cpuinfo.h for i386 and x86_64, and the initialization
>> for that in util/.  Populate that with a slightly altered
>> copy of the tcg host probing code.  Other uses of cpuid.h
>> will be adjusted one patch at a time.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> 
> Reviewed-by: Juan Quintela <quintela@redhat.com>
> 
> For what is worth my vote O:-)
> 
>> +#define CPUINFO_ALWAYS          (1u << 0)  /* so cpuinfo is nonzero */
>> +#define CPUINFO_CMOV            (1u << 1)
>> +#define CPUINFO_MOVBE           (1u << 2)
>> +#define CPUINFO_LZCNT           (1u << 3)
>> +#define CPUINFO_POPCNT          (1u << 4)
>> +#define CPUINFO_BMI1            (1u << 5)
>> +#define CPUINFO_BMI2            (1u << 6)
>> +#define CPUINFO_SSE2            (1u << 7)
>> +#define CPUINFO_SSE4            (1u << 8)
>> +#define CPUINFO_AVX1            (1u << 9)
>> +#define CPUINFO_AVX2            (1u << 10)
>> +#define CPUINFO_AVX512F         (1u << 11)
>> +#define CPUINFO_AVX512VL        (1u << 12)
>> +#define CPUINFO_AVX512BW        (1u << 13)
>> +#define CPUINFO_AVX512DQ        (1u << 14)
>> +#define CPUINFO_AVX512VBMI2     (1u << 15)
>> +#define CPUINFO_ATOMIC_VMOVDQA  (1u << 16)
>> +
>> +/* Initialized with a constructor. */
>> +extern unsigned cpuinfo;
> 
> On one hand, it is weird having a flags variable that is only 32bit.  I
> am so user to put 64 bit flags. Future proof, blah, blah, ...
> 
> On the other hand, if tcg has survived for so long with only 16 bits, it
> is inside posibility that 32bits are more than enough.

Indeed.  Nor is this an public abi that needs future-proofing -- in the event we need more 
bits, we change it.

>> +/* Called both as constructor and (possibly) via other constructors. */
>> +unsigned __attribute__((constructor)) cpuinfo_init(void)
>> +{
>> +    unsigned info = cpuinfo;
>> +
>> +    if (info) {
>> +        return info;
>> +    }
> 
> Have to look several times to this, because info "needed to be"" a
> static variable, right? O:-)

:-)


r~
diff mbox series

Patch

diff --git a/include/host/i386/cpuinfo.h b/include/host/i386/cpuinfo.h
new file mode 100644
index 0000000000..e6f7461378
--- /dev/null
+++ b/include/host/i386/cpuinfo.h
@@ -0,0 +1,38 @@ 
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * Host specific cpu indentification for x86.
+ */
+
+#ifndef HOST_CPUINFO_H
+#define HOST_CPUINFO_H
+
+/* Digested version of <cpuid.h> */
+
+#define CPUINFO_ALWAYS          (1u << 0)  /* so cpuinfo is nonzero */
+#define CPUINFO_CMOV            (1u << 1)
+#define CPUINFO_MOVBE           (1u << 2)
+#define CPUINFO_LZCNT           (1u << 3)
+#define CPUINFO_POPCNT          (1u << 4)
+#define CPUINFO_BMI1            (1u << 5)
+#define CPUINFO_BMI2            (1u << 6)
+#define CPUINFO_SSE2            (1u << 7)
+#define CPUINFO_SSE4            (1u << 8)
+#define CPUINFO_AVX1            (1u << 9)
+#define CPUINFO_AVX2            (1u << 10)
+#define CPUINFO_AVX512F         (1u << 11)
+#define CPUINFO_AVX512VL        (1u << 12)
+#define CPUINFO_AVX512BW        (1u << 13)
+#define CPUINFO_AVX512DQ        (1u << 14)
+#define CPUINFO_AVX512VBMI2     (1u << 15)
+#define CPUINFO_ATOMIC_VMOVDQA  (1u << 16)
+
+/* Initialized with a constructor. */
+extern unsigned cpuinfo;
+
+/*
+ * We cannot rely on constructor ordering, so other constructors must
+ * use the function interface rather than the variable above.
+ */
+unsigned cpuinfo_init(void);
+
+#endif /* HOST_CPUINFO_H */
diff --git a/include/host/x86_64/cpuinfo.h b/include/host/x86_64/cpuinfo.h
new file mode 100644
index 0000000000..535a8d79d4
--- /dev/null
+++ b/include/host/x86_64/cpuinfo.h
@@ -0,0 +1 @@ 
+#include "host/i386/cpuinfo.h"
diff --git a/util/cpuinfo-i386.c b/util/cpuinfo-i386.c
new file mode 100644
index 0000000000..cb9475c688
--- /dev/null
+++ b/util/cpuinfo-i386.c
@@ -0,0 +1,97 @@ 
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * Host specific cpu indentification for x86.
+ */
+
+#include "qemu/osdep.h"
+#include "cpuinfo.h"
+#ifdef CONFIG_CPUID_H
+# include "qemu/cpuid.h"
+#endif
+
+unsigned cpuinfo;
+
+/* Called both as constructor and (possibly) via other constructors. */
+unsigned __attribute__((constructor)) cpuinfo_init(void)
+{
+    unsigned info = cpuinfo;
+
+    if (info) {
+        return info;
+    }
+
+#ifdef CONFIG_CPUID_H
+    unsigned max, a, b, c, d, b7 = 0, c7 = 0;
+
+    max = __get_cpuid_max(0, 0);
+
+    if (max >= 7) {
+        __cpuid_count(7, 0, a, b7, c7, d);
+        info |= (b7 & bit_BMI ? CPUINFO_BMI1 : 0);
+        info |= (b7 & bit_BMI2 ? CPUINFO_BMI2 : 0);
+    }
+
+    if (max >= 1) {
+        __cpuid(1, a, b, c, d);
+
+        info |= (d & bit_CMOV ? CPUINFO_CMOV : 0);
+        info |= (d & bit_SSE2 ? CPUINFO_SSE2 : 0);
+        info |= (c & bit_SSE4_1 ? CPUINFO_SSE4 : 0);
+        info |= (c & bit_MOVBE ? CPUINFO_MOVBE : 0);
+        info |= (c & bit_POPCNT ? CPUINFO_POPCNT : 0);
+
+        /* For AVX features, we must check available and usable. */
+        if ((c & bit_AVX) && (c & bit_OSXSAVE)) {
+            unsigned bv = xgetbv_low(0);
+
+            if ((bv & 6) == 6) {
+                info |= CPUINFO_AVX1;
+                info |= (b7 & bit_AVX2 ? CPUINFO_AVX2 : 0);
+
+                if ((bv & 0xe0) == 0xe0) {
+                    info |= (b7 & bit_AVX512F ? CPUINFO_AVX512F : 0);
+                    info |= (b7 & bit_AVX512VL ? CPUINFO_AVX512VL : 0);
+                    info |= (b7 & bit_AVX512BW ? CPUINFO_AVX512BW : 0);
+                    info |= (b7 & bit_AVX512DQ ? CPUINFO_AVX512DQ : 0);
+                    info |= (c7 & bit_AVX512VBMI2 ? CPUINFO_AVX512VBMI2 : 0);
+                }
+
+                /*
+                 * The Intel SDM has added:
+                 *   Processors that enumerate support for IntelĀ® AVX
+                 *   (by setting the feature flag CPUID.01H:ECX.AVX[bit 28])
+                 *   guarantee that the 16-byte memory operations performed
+                 *   by the following instructions will always be carried
+                 *   out atomically:
+                 *   - MOVAPD, MOVAPS, and MOVDQA.
+                 *   - VMOVAPD, VMOVAPS, and VMOVDQA when encoded with VEX.128.
+                 *   - VMOVAPD, VMOVAPS, VMOVDQA32, and VMOVDQA64 when encoded
+                 *     with EVEX.128 and k0 (masking disabled).
+                 * Note that these instructions require the linear addresses
+                 * of their memory operands to be 16-byte aligned.
+                 *
+                 * AMD has provided an even stronger guarantee that processors
+                 * with AVX provide 16-byte atomicity for all cachable,
+                 * naturally aligned single loads and stores, e.g. MOVDQU.
+                 *
+                 * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104688
+                 */
+                __cpuid(0, a, b, c, d);
+                if (c == signature_INTEL_ecx || c == signature_AMD_ecx) {
+                    info |= CPUINFO_ATOMIC_VMOVDQA;
+                }
+            }
+        }
+    }
+
+    max = __get_cpuid_max(0x8000000, 0);
+    if (max >= 1) {
+        __cpuid(0x80000001, a, b, c, d);
+        info |= (c & bit_LZCNT ? CPUINFO_LZCNT : 0);
+    }
+#endif
+
+    info |= CPUINFO_ALWAYS;
+    cpuinfo = info;
+    return info;
+}
diff --git a/util/meson.build b/util/meson.build
index 3c2cfc6ede..714c783b4c 100644
--- a/util/meson.build
+++ b/util/meson.build
@@ -106,3 +106,7 @@  if have_block
   endif
   util_ss.add(when: 'CONFIG_LINUX', if_true: files('vfio-helpers.c'))
 endif
+
+if cpu in ['x86', 'x86_64']
+  util_ss.add(files('cpuinfo-i386.c'))
+endif