new file mode 100644
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_UM_CPUFEATURE_H
+#define _ASM_UM_CPUFEATURE_H
+
+#include <asm/asm.h>
+#include <linux/bitops.h>
+#include <asm/processor-generic.h>
+#include <asm/cpufeatures.h>
+
+
+const char *host_cpu_feature_names[] = {"mmx", "xmm", "avx", "osxsave", "rep_good", "erms"};
+#define MAX_UM_CPU_FEATURES ARRAY_SIZE(host_cpu_feature_names)
+
+
+#define boot_cpu_has(bit) (boot_cpu_data.host_features & bit)
+
+#endif /* _ASM_UM_CPUFEATURE_H */
new file mode 100644
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_UM_CPUFEATURES_H
+#define _ASM_UM_CPUFEATURES_H
+
+/* Fake x86 Features of actual interest to UML */
+
+#define X86_FEATURE_MMX (1 << 0)
+#define X86_FEATURE_XMM (1 << 1)
+#define X86_FEATURE_AVX (1 << 2)
+#define X86_FEATURE_OSXSAVE (1 << 3)
+#define X86_FEATURE_REP_GOOD (1 << 4)
+#define X86_FEATURE_ERMS (1 << 5)
+
+#endif /* _ASM_UM_CPUFEATURES_H */
new file mode 100644
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _ASM_UM_FPU_API_H
+#define _ASM_UM_FPU_API_H
+
+/* Copyright (c) 2020 Cambridge Greys Ltd
+ * Copyright (c) 2020 Red Hat Inc.
+ * A set of "dummy" defines to allow the direct inclusion
+ * of x86 optimized copy, xor, etc routines into the
+ * UML code tree. */
+
+#define kernel_fpu_begin() (void)0
+#define kernel_fpu_end() (void)0
+
+#endif
@@ -90,6 +90,9 @@ extern void start_thread(struct pt_regs *regs, unsigned long entry,
struct cpuinfo_um {
unsigned long loops_per_jiffy;
int ipi_pipe[2];
+ /* There is only a small set of x86 features we are interested
+ * in for now */
+ unsigned long host_features;
};
extern struct cpuinfo_um boot_cpu_data;
new file mode 120000
@@ -0,0 +1 @@
+../../../x86/include/asm/xor.h
\ No newline at end of file
@@ -1,7 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0 */
-#include <asm-generic/xor.h>
+#ifndef _ASM_UM_XOR_H
+#define _ASM_UM_XOR_H
+
+#ifdef CONFIG_64BIT
+#undef CONFIG_X86_32
+#else
+#define CONFIG_X86_32 1
+#endif
+
+#include <asm/cpufeature.h>
+#include <asm/xor-x86.h>
#include <linux/time-internal.h>
+#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
+#undef XOR_SELECT_TEMPLATE
/* pick an arbitrary one - measuring isn't possible with inf-cpu */
#define XOR_SELECT_TEMPLATE(x) \
(time_travel_mode == TT_MODE_INFCPU ? &xor_block_8regs : NULL)
+#endif
+
+#endif
new file mode 120000
@@ -0,0 +1 @@
+../../../x86/include/asm/xor_32.h
\ No newline at end of file
new file mode 120000
@@ -0,0 +1 @@
+../../../x86/include/asm/xor_64.h
\ No newline at end of file
new file mode 120000
@@ -0,0 +1 @@
+../../../x86/include/asm/xor_avx.h
\ No newline at end of file
@@ -187,6 +187,7 @@ int os_poll(unsigned int n, const int *fds);
extern void os_early_checks(void);
extern void os_check_bugs(void);
extern void check_host_supports_tls(int *supports_tls, int *tls_min);
+extern unsigned long check_host_cpu_features(const char **feature_names, int n);
/* mem.c */
extern int create_mem_file(unsigned long long len);
@@ -15,6 +15,7 @@
#include <linux/kmsg_dump.h>
#include <asm/processor.h>
+#include <asm/cpufeature.h>
#include <asm/sections.h>
#include <asm/setup.h>
#include <as-layout.h>
@@ -48,9 +49,12 @@ static void __init add_arg(char *arg)
*/
struct cpuinfo_um boot_cpu_data = {
.loops_per_jiffy = 0,
- .ipi_pipe = { -1, -1 }
+ .ipi_pipe = { -1, -1 },
+ .host_features = 0
};
+EXPORT_SYMBOL(boot_cpu_data);
+
union thread_union cpu0_irqstack
__section(".data..init_irqstack") =
{ .thread_info = INIT_THREAD_INFO(init_task) };
@@ -67,9 +71,15 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "model name\t: UML\n");
seq_printf(m, "mode\t\t: skas\n");
seq_printf(m, "host\t\t: %s\n", host_info);
- seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
+ seq_printf(m, "bogomips\t: %lu.%02lu\n",
loops_per_jiffy/(500000/HZ),
(loops_per_jiffy/(5000/HZ)) % 100);
+ seq_printf(m, "flags\t\t:");
+ for (index = 0; index < MAX_UM_CPU_FEATURES; index++) {
+ if (boot_cpu_data.host_features & (1 << index))
+ seq_printf(m, " %s", host_cpu_feature_names[index]);
+ }
+ seq_printf(m, "\n\n");
return 0;
}
@@ -275,6 +285,9 @@ int __init linux_main(int argc, char **argv)
/* OS sanity checks that need to happen before the kernel runs */
os_early_checks();
+ boot_cpu_data.host_features =
+ check_host_cpu_features(host_cpu_feature_names, MAX_UM_CPU_FEATURES);
+
brk_start = (unsigned long) sbrk(0);
/*
@@ -321,6 +321,38 @@ static void __init check_coredump_limit(void)
os_info("%llu\n", (unsigned long long)lim.rlim_max);
}
+unsigned long __init check_host_cpu_features(const char **feature_names, int n)
+{
+ FILE *cpuinfo;
+ char *line = NULL;
+ size_t len = 0;
+ int i;
+ bool done_parsing = false;
+ unsigned long result = 0;
+
+ cpuinfo = fopen("/proc/cpuinfo", "r");
+ if (cpuinfo == NULL) {
+ os_info("Failed to get host CPU features\n");
+ } else {
+ while ((getline(&line, &len, cpuinfo)) != -1) {
+ if (strstr(line, "flags")) {
+ for (i = 0; i < n; i++) {
+ if (strstr(line, feature_names[i])) {
+ result |= (1 << i);
+ }
+ }
+ done_parsing = true;
+ }
+ free(line);
+ line = NULL;
+ if (done_parsing)
+ break;
+ }
+ fclose(cpuinfo);
+ }
+ return result;
+}
+
void __init os_early_checks(void)
{
int pid;