diff --git a/Makefile b/Makefile index 0db379099..ea76a1246 100644 --- a/Makefile +++ b/Makefile @@ -228,9 +228,9 @@ $(SOCCR_A): |soccr/built-in.o # # But note that we're already included # the nmk so we can reuse it there. -criu/%: images/built-in.o compel/plugins/std.built-in.o compel/compel-host $(VERSION_HEADER) .FORCE +criu/%: images/built-in.o compel/plugins/std.built-in.o compel/libcompel.a compel/compel-host $(VERSION_HEADER) .FORCE $(Q) $(MAKE) $(build)=criu $@ -criu: images/built-in.o compel/plugins/std.built-in.o compel/compel-host $(SOCCR_A) $(VERSION_HEADER) +criu: images/built-in.o compel/plugins/std.built-in.o compel/libcompel.a compel/compel-host $(SOCCR_A) $(VERSION_HEADER) $(Q) $(MAKE) $(build)=criu all .PHONY: criu diff --git a/Makefile.compel b/Makefile.compel index 885665011..366f604e9 100644 --- a/Makefile.compel +++ b/Makefile.compel @@ -33,6 +33,7 @@ compel-uapi-links += $(SRC_DIR)/compel/include/asm compel-deps += $(compel-uapi-links) compel-deps += $(COMPEL_VERSION_HEADER) compel-deps += $(CONFIG_HEADER) +compel-deps += include/common/asm # # Compel itself. diff --git a/compel/Makefile b/compel/Makefile index f47d48805..d421bc078 100644 --- a/compel/Makefile +++ b/compel/Makefile @@ -22,6 +22,8 @@ host-lib-y += src/lib/handle-elf.o lib-y += src/lib/log.o host-lib-y += src/lib/log.o +lib-y += arch/$(ARCH)/src/lib/cpu.o + ifeq ($(ARCH),x86) lib-y += src/lib/handle-elf-32.o host-lib-y += src/lib/handle-elf-32.o diff --git a/compel/arch/aarch64/src/lib/cpu.c b/compel/arch/aarch64/src/lib/cpu.c new file mode 100644 index 000000000..9e5d0d7fe --- /dev/null +++ b/compel/arch/aarch64/src/lib/cpu.c @@ -0,0 +1,28 @@ +#include +#include + +#include "uapi/compel/cpu.h" + +#include "common/bitops.h" + +#include "log.h" + +#undef LOG_PREFIX +#define LOG_PREFIX "cpu: " + +static compel_cpuinfo_t rt_info; +static bool rt_info_done = false; + +void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } +void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } +int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } +int compel_cpuid(compel_cpuinfo_t *info) { return 0; } + +bool cpu_has_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_test_cpu_cap(&rt_info, feature); +} diff --git a/compel/arch/aarch64/src/lib/include/uapi/asm/cpu.h b/compel/arch/aarch64/src/lib/include/uapi/asm/cpu.h new file mode 100644 index 000000000..c35460e15 --- /dev/null +++ b/compel/arch/aarch64/src/lib/include/uapi/asm/cpu.h @@ -0,0 +1,6 @@ +#ifndef UAPI_COMPEL_ASM_CPU_H__ +#define UAPI_COMPEL_ASM_CPU_H__ + +typedef struct { } compel_cpuinfo_t; + +#endif /* UAPI_COMPEL_ASM_CPU_H__ */ diff --git a/compel/arch/aarch64/src/lib/include/uapi/asm/processor-flags.h b/compel/arch/aarch64/src/lib/include/uapi/asm/processor-flags.h new file mode 100644 index 000000000..15719184a --- /dev/null +++ b/compel/arch/aarch64/src/lib/include/uapi/asm/processor-flags.h @@ -0,0 +1,4 @@ +#ifndef UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__ +#define UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__ + +#endif /* UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__ */ diff --git a/compel/arch/arm/src/lib/cpu.c b/compel/arch/arm/src/lib/cpu.c new file mode 100644 index 000000000..9e5d0d7fe --- /dev/null +++ b/compel/arch/arm/src/lib/cpu.c @@ -0,0 +1,28 @@ +#include +#include + +#include "uapi/compel/cpu.h" + +#include "common/bitops.h" + +#include "log.h" + +#undef LOG_PREFIX +#define LOG_PREFIX "cpu: " + +static compel_cpuinfo_t rt_info; +static bool rt_info_done = false; + +void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } +void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } +int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } +int compel_cpuid(compel_cpuinfo_t *info) { return 0; } + +bool cpu_has_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_test_cpu_cap(&rt_info, feature); +} diff --git a/compel/arch/arm/src/lib/include/uapi/asm/cpu.h b/compel/arch/arm/src/lib/include/uapi/asm/cpu.h new file mode 100644 index 000000000..c35460e15 --- /dev/null +++ b/compel/arch/arm/src/lib/include/uapi/asm/cpu.h @@ -0,0 +1,6 @@ +#ifndef UAPI_COMPEL_ASM_CPU_H__ +#define UAPI_COMPEL_ASM_CPU_H__ + +typedef struct { } compel_cpuinfo_t; + +#endif /* UAPI_COMPEL_ASM_CPU_H__ */ diff --git a/compel/arch/arm/src/lib/include/processor-flags.h b/compel/arch/arm/src/lib/include/uapi/asm/processor-flags.h similarity index 100% rename from compel/arch/arm/src/lib/include/processor-flags.h rename to compel/arch/arm/src/lib/include/uapi/asm/processor-flags.h diff --git a/compel/arch/ppc64/src/lib/cpu.c b/compel/arch/ppc64/src/lib/cpu.c new file mode 100644 index 000000000..e324b80f9 --- /dev/null +++ b/compel/arch/ppc64/src/lib/cpu.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include + +#include "uapi/compel/cpu.h" + +#include "common/bitops.h" + +#include "log.h" + +#undef LOG_PREFIX +#define LOG_PREFIX "cpu: " + +static compel_cpuinfo_t rt_info; +static bool rt_info_done = false; + +void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } +void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { } +int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature) { return 0; } + +int compel_cpuid(compel_cpuinfo_t *info) +{ + info->hwcap[0] = getauxval(AT_HWCAP); + info->hwcap[1] = getauxval(AT_HWCAP2); + + if (!info->hwcap[0] || !info->hwcap[1]) { + pr_err("Can't read the hardware capabilities"); + return -1; + } + + return 0; +} + +bool cpu_has_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_test_cpu_cap(&rt_info, feature); +} diff --git a/compel/arch/ppc64/src/lib/include/uapi/asm/cpu.h b/compel/arch/ppc64/src/lib/include/uapi/asm/cpu.h new file mode 100644 index 000000000..59925868c --- /dev/null +++ b/compel/arch/ppc64/src/lib/include/uapi/asm/cpu.h @@ -0,0 +1,10 @@ +#ifndef UAPI_COMPEL_ASM_CPU_H__ +#define UAPI_COMPEL_ASM_CPU_H__ + +#include + +typedef struct { + uint64_t hwcap[2]; +} compel_cpuinfo_t; + +#endif /* UAPI_COMPEL_ASM_CPU_H__ */ diff --git a/compel/arch/ppc64/src/lib/include/uapi/asm/processor-flags.h b/compel/arch/ppc64/src/lib/include/uapi/asm/processor-flags.h new file mode 100644 index 000000000..15719184a --- /dev/null +++ b/compel/arch/ppc64/src/lib/include/uapi/asm/processor-flags.h @@ -0,0 +1,4 @@ +#ifndef UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__ +#define UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__ + +#endif /* UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__ */ diff --git a/compel/arch/ppc64/src/lib/include/uapi/asm/processor.h b/compel/arch/ppc64/src/lib/include/uapi/asm/processor.h new file mode 100644 index 000000000..7376f8879 --- /dev/null +++ b/compel/arch/ppc64/src/lib/include/uapi/asm/processor.h @@ -0,0 +1,4 @@ +#ifndef UAPI_COMPEL_ASM_PROCESSOR_H__ +#define UAPI_COMPEL_ASM_PROCESSOR_H__ + +#endif /* UAPI_COMPEL_ASM_PROCESSOR_H__ */ diff --git a/compel/arch/x86/src/lib/cpu.c b/compel/arch/x86/src/lib/cpu.c new file mode 100644 index 000000000..7962a61c6 --- /dev/null +++ b/compel/arch/x86/src/lib/cpu.c @@ -0,0 +1,189 @@ +#include +#include + +#include "uapi/compel/cpu.h" + +#include "common/bitops.h" +#include "common/compiler.h" + +#include "log.h" + +#undef LOG_PREFIX +#define LOG_PREFIX "cpu: " + +static compel_cpuinfo_t rt_info; +static bool rt_info_done = false; + +void compel_set_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) +{ + if (likely(feature < NCAPINTS_BITS)) + set_bit(feature, (unsigned long *)c->x86_capability); +} + +void compel_clear_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) +{ + if (likely(feature < NCAPINTS_BITS)) + clear_bit(feature, (unsigned long *)c->x86_capability); +} + +int compel_test_cpu_cap(compel_cpuinfo_t *c, unsigned int feature) +{ + if (likely(feature < NCAPINTS_BITS)) + return test_bit(feature, (unsigned long *)c->x86_capability); + return 0; +} + +int compel_cpuid(compel_cpuinfo_t *c) +{ + /* + * See cpu_detect() in the kernel, also + * read cpuid specs not only from general + * SDM but for extended instructions set + * reference. + */ + + /* Get vendor name */ + cpuid(0x00000000, + (unsigned int *)&c->cpuid_level, + (unsigned int *)&c->x86_vendor_id[0], + (unsigned int *)&c->x86_vendor_id[8], + (unsigned int *)&c->x86_vendor_id[4]); + + if (!strcmp(c->x86_vendor_id, "GenuineIntel")) { + c->x86_vendor = X86_VENDOR_INTEL; + } else if (!strcmp(c->x86_vendor_id, "AuthenticAMD")) { + c->x86_vendor = X86_VENDOR_AMD; + } else { + pr_err("Unsupported CPU vendor %s\n", + c->x86_vendor_id); + return -1; + } + + c->x86_family = 4; + + /* Intel-defined flags: level 0x00000001 */ + if (c->cpuid_level >= 0x00000001) { + uint32_t eax, ebx, ecx, edx; + + cpuid(0x00000001, &eax, &ebx, &ecx, &edx); + c->x86_family = (eax >> 8) & 0xf; + c->x86_model = (eax >> 4) & 0xf; + c->x86_mask = eax & 0xf; + + if (c->x86_family == 0xf) + c->x86_family += (eax >> 20) & 0xff; + if (c->x86_family >= 0x6) + c->x86_model += ((eax >> 16) & 0xf) << 4; + + c->x86_capability[0] = edx; + c->x86_capability[4] = ecx; + } + + /* Additional Intel-defined flags: level 0x00000007 */ + if (c->cpuid_level >= 0x00000007) { + uint32_t eax, ebx, ecx, edx; + + cpuid_count(0x00000007, 0, &eax, &ebx, &ecx, &edx); + c->x86_capability[9] = ebx; + c->x86_capability[11] = ecx; + } + + /* Extended state features: level 0x0000000d */ + if (c->cpuid_level >= 0x0000000d) { + uint32_t eax, ebx, ecx, edx; + + cpuid_count(0x0000000d, 1, &eax, &ebx, &ecx, &edx); + c->x86_capability[10] = eax; + } + + /* AMD-defined flags: level 0x80000001 */ + c->extended_cpuid_level = cpuid_eax(0x80000000); + + if ((c->extended_cpuid_level & 0xffff0000) == 0x80000000) { + if (c->extended_cpuid_level >= 0x80000001) { + c->x86_capability[1] = cpuid_edx(0x80000001); + c->x86_capability[6] = cpuid_ecx(0x80000001); + } + } + + /* + * We're don't care about scattered features for now, + * otherwise look into init_scattered_cpuid_features() + * in kernel. + */ + + if (c->extended_cpuid_level >= 0x80000004) { + unsigned int *v; + char *p, *q; + v = (unsigned int *)c->x86_model_id; + cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]); + cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]); + cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]); + c->x86_model_id[48] = 0; + + /* + * Intel chips right-justify this string for some dumb reason; + * undo that brain damage: + */ + p = q = &c->x86_model_id[0]; + while (*p == ' ') + p++; + if (p != q) { + while (*p) + *q++ = *p++; + while (q <= &c->x86_model_id[48]) + *q++ = '\0'; /* Zero-pad the rest */ + } + } + + /* On x86-64 NOP is always present */ + compel_set_cpu_cap(c, X86_FEATURE_NOPL); + + switch (c->x86_vendor) { + case X86_VENDOR_INTEL: + /* + * Strictly speaking we need to read MSR_IA32_MISC_ENABLE + * here but on ring3 it's impossible. + */ + if (c->x86_family == 15) { + compel_clear_cpu_cap(c, X86_FEATURE_REP_GOOD); + compel_clear_cpu_cap(c, X86_FEATURE_ERMS); + } else if (c->x86_family == 6) { + /* On x86-64 rep is fine */ + compel_set_cpu_cap(c, X86_FEATURE_REP_GOOD); + } + + /* See filter_cpuid_features in kernel */ + if ((int32_t)c->cpuid_level < (int32_t)0x0000000d) + compel_clear_cpu_cap(c, X86_FEATURE_XSAVE); + break; + case X86_VENDOR_AMD: + /* + * Bit 31 in normal CPUID used for nonstandard 3DNow ID; + * 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway + */ + compel_clear_cpu_cap(c, 0 * 32 + 31); + if (c->x86_family >= 0x10) + compel_set_cpu_cap(c, X86_FEATURE_REP_GOOD); + if (c->x86_family == 0xf) { + uint32_t level; + + /* On C+ stepping K8 rep microcode works well for copy/memset */ + level = cpuid_eax(1); + if ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58) + compel_set_cpu_cap(c, X86_FEATURE_REP_GOOD); + } + break; + } + + return 0; +} + +bool cpu_has_feature(unsigned int feature) +{ + if (!rt_info_done) { + compel_cpuid(&rt_info); + rt_info_done = true; + } + return compel_test_cpu_cap(&rt_info, feature); +} diff --git a/criu/arch/x86/include/asm/cpu.h b/compel/arch/x86/src/lib/include/uapi/asm/cpu.h similarity index 95% rename from criu/arch/x86/include/asm/cpu.h rename to compel/arch/x86/src/lib/include/uapi/asm/cpu.h index 6f49229d6..f79ace1fc 100644 --- a/criu/arch/x86/include/asm/cpu.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/cpu.h @@ -1,7 +1,7 @@ #ifndef __CR_ASM_CPU_H__ #define __CR_ASM_CPU_H__ -#include "asm/types.h" +#include /* * Adopted from linux kernel and enhanced from Intel/AMD manuals. @@ -176,8 +176,6 @@ static inline unsigned int cpuid_edx(unsigned int op) return edx; } -#define X86_FEATURE_VERSION 1 - enum { X86_VENDOR_INTEL = 0, X86_VENDOR_AMD = 1, @@ -186,22 +184,17 @@ enum { }; struct cpuinfo_x86 { - u8 x86_family; - u8 x86_vendor; - u8 x86_model; - u8 x86_mask; - u32 x86_capability[NCAPINTS]; - u32 extended_cpuid_level; + uint8_t x86_family; + uint8_t x86_vendor; + uint8_t x86_model; + uint8_t x86_mask; + uint32_t x86_capability[NCAPINTS]; + uint32_t extended_cpuid_level; int cpuid_level; char x86_vendor_id[16]; char x86_model_id[64]; }; -extern bool cpu_has_feature(unsigned int feature); -extern int cpu_init(void); -extern int cpu_dump_cpuinfo(void); -extern int cpu_validate_cpuinfo(void); -extern int cpuinfo_dump(void); -extern int cpuinfo_check(void); +typedef struct cpuinfo_x86 compel_cpuinfo_t; -#endif /* __CR_CPU_H__ */ +#endif /* __CR_ASM_CPU_H__ */ diff --git a/compel/arch/x86/src/lib/include/processor-flags.h b/compel/arch/x86/src/lib/include/uapi/asm/processor-flags.h similarity index 100% rename from compel/arch/x86/src/lib/include/processor-flags.h rename to compel/arch/x86/src/lib/include/uapi/asm/processor-flags.h diff --git a/compel/include/uapi/cpu.h b/compel/include/uapi/cpu.h new file mode 100644 index 000000000..662883bc9 --- /dev/null +++ b/compel/include/uapi/cpu.h @@ -0,0 +1,14 @@ +#ifndef UAPI_COMPEL_CPU_H__ +#define UAPI_COMPEL_CPU_H__ + +#include + +#include + +extern void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature); +extern void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature); +extern int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature); +extern int compel_cpuid(compel_cpuinfo_t *info); +extern bool cpu_has_feature(unsigned int feature); + +#endif /* UAPI_COMPEL_CPU_H__ */ diff --git a/criu/Makefile b/criu/Makefile index 35febd8e8..6c06029e7 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -73,6 +73,7 @@ PROGRAM-BUILTINS += images/built-in.o PROGRAM-BUILTINS += $(obj)/built-in.o PROGRAM-BUILTINS += $(ARCH-LIB) PROGRAM-BUILTINS += soccr/libsoccr.a +PROGRAM-BUILTINS += compel/libcompel.a $(obj)/built-in.o: pie $(Q) $(MAKE) $(call build-as,Makefile.crtools,criu) all diff --git a/criu/arch/aarch64/cpu.c b/criu/arch/aarch64/cpu.c index 040fe14fc..34313fb15 100644 --- a/criu/arch/aarch64/cpu.c +++ b/criu/arch/aarch64/cpu.c @@ -4,11 +4,6 @@ #include #include "cpu.h" -bool cpu_has_feature(unsigned int feature) -{ - return false; -} - int cpu_init(void) { return 0; diff --git a/criu/arch/aarch64/crtools.c b/criu/arch/aarch64/crtools.c index 8e4f48656..fd34484df 100644 --- a/criu/arch/aarch64/crtools.c +++ b/criu/arch/aarch64/crtools.c @@ -4,6 +4,8 @@ #include #include "types.h" +#include + #include "asm/restorer.h" #include "common/compiler.h" #include "ptrace.h" diff --git a/criu/arch/aarch64/include/asm/cpu.h b/criu/arch/aarch64/include/asm/cpu.h deleted file mode 100644 index 59118c211..000000000 --- a/criu/arch/aarch64/include/asm/cpu.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/criu/arch/arm/cpu.c b/criu/arch/arm/cpu.c index 040fe14fc..34313fb15 100644 --- a/criu/arch/arm/cpu.c +++ b/criu/arch/arm/cpu.c @@ -4,11 +4,6 @@ #include #include "cpu.h" -bool cpu_has_feature(unsigned int feature) -{ - return false; -} - int cpu_init(void) { return 0; diff --git a/criu/arch/arm/crtools.c b/criu/arch/arm/crtools.c index d0576d5ae..07c6473f5 100644 --- a/criu/arch/arm/crtools.c +++ b/criu/arch/arm/crtools.c @@ -2,6 +2,8 @@ #include #include "types.h" +#include + #include "asm/restorer.h" #include "common/compiler.h" #include "asm/dump.h" diff --git a/criu/arch/arm/include/asm/cpu.h b/criu/arch/arm/include/asm/cpu.h deleted file mode 100644 index 59118c211..000000000 --- a/criu/arch/arm/include/asm/cpu.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/criu/arch/ppc64/cpu.c b/criu/arch/ppc64/cpu.c index 222bc62d1..aecba7801 100644 --- a/criu/arch/ppc64/cpu.c +++ b/criu/arch/ppc64/cpu.c @@ -6,7 +6,6 @@ #include #include "asm/types.h" -#include "asm/cpu.h" #include "cr_options.h" #include "image.h" @@ -17,7 +16,7 @@ #include "protobuf.h" #include "images/cpuinfo.pb-c.h" -static uint64_t hwcap[2]; +static compel_cpuinfo_t rt_cpuinfo; #ifdef __LITTLE_ENDIAN__ #define CURRENT_ENDIANNESS CPUINFO_PPC64_ENTRY__ENDIANNESS__LITTLEENDIAN @@ -27,14 +26,7 @@ static uint64_t hwcap[2]; int cpu_init(void) { - hwcap[0] = getauxval(AT_HWCAP); - hwcap[1] = getauxval(AT_HWCAP2); - - if (!hwcap[0] || !hwcap[1]) { - pr_err("Can't read the hardware capabilities"); - return -1; - } - return 0; + return compel_cpuid(&rt_cpuinfo); } int cpu_dump_cpuinfo(void) @@ -54,7 +46,7 @@ int cpu_dump_cpuinfo(void) cpu_ppc64_info.endian = CURRENT_ENDIANNESS; cpu_ppc64_info.n_hwcap = 2; - cpu_ppc64_info.hwcap = hwcap; + cpu_ppc64_info.hwcap = rt_cpuinfo.hwcap; ret = pb_write_one(img, &cpu_info, PB_CPUINFO); @@ -92,7 +84,8 @@ int cpu_validate_cpuinfo(void) } #define CHECK_FEATURE(s,f) do { \ - if ((cpu_ppc64_entry->hwcap[s] & f) && !(hwcap[s] & f)) { \ + if ((cpu_ppc64_entry->hwcap[s] & f) && \ + !(rt_cpuinfo.hwcap[s] & f)) { \ pr_err("CPU Feature %s required by image " \ "is not supported on host.\n", #f); \ goto error; \ diff --git a/criu/arch/ppc64/include/asm/cpu.h b/criu/arch/ppc64/include/asm/cpu.h deleted file mode 100644 index 59118c211..000000000 --- a/criu/arch/ppc64/include/asm/cpu.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/criu/arch/x86/cpu.c b/criu/arch/x86/cpu.c index 49fe203c3..d2b835286 100644 --- a/criu/arch/x86/cpu.c +++ b/criu/arch/x86/cpu.c @@ -10,6 +10,7 @@ #include "asm/types.h" #include "asm/cpu.h" #include "asm/fpu.h" +#include #include "common/compiler.h" @@ -26,181 +27,11 @@ #undef LOG_PREFIX #define LOG_PREFIX "cpu: " -static struct cpuinfo_x86 rt_cpu_info; - -static void set_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature) -{ - if (likely(feature < NCAPINTS_BITS)) - set_bit(feature, (unsigned long *)c->x86_capability); -} - -static void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature) -{ - if (likely(feature < NCAPINTS_BITS)) - clear_bit(feature, (unsigned long *)c->x86_capability); -} - -static int test_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature) -{ - if (likely(feature < NCAPINTS_BITS)) - return test_bit(feature, (unsigned long *)c->x86_capability); - return 0; -} - -bool cpu_has_feature(unsigned int feature) -{ - return test_cpu_cap(&rt_cpu_info, feature); -} - -static int cpu_init_cpuid(struct cpuinfo_x86 *c) -{ - /* - * See cpu_detect() in the kernel, also - * read cpuid specs not only from general - * SDM but for extended instructions set - * reference. - */ - - /* Get vendor name */ - cpuid(0x00000000, - (unsigned int *)&c->cpuid_level, - (unsigned int *)&c->x86_vendor_id[0], - (unsigned int *)&c->x86_vendor_id[8], - (unsigned int *)&c->x86_vendor_id[4]); - - if (!strcmp(c->x86_vendor_id, "GenuineIntel")) { - c->x86_vendor = X86_VENDOR_INTEL; - } else if (!strcmp(c->x86_vendor_id, "AuthenticAMD")) { - c->x86_vendor = X86_VENDOR_AMD; - } else { - pr_err("Unsupported CPU vendor %s\n", - c->x86_vendor_id); - return -1; - } - - c->x86_family = 4; - - /* Intel-defined flags: level 0x00000001 */ - if (c->cpuid_level >= 0x00000001) { - u32 eax, ebx, ecx, edx; - - cpuid(0x00000001, &eax, &ebx, &ecx, &edx); - c->x86_family = (eax >> 8) & 0xf; - c->x86_model = (eax >> 4) & 0xf; - c->x86_mask = eax & 0xf; - - if (c->x86_family == 0xf) - c->x86_family += (eax >> 20) & 0xff; - if (c->x86_family >= 0x6) - c->x86_model += ((eax >> 16) & 0xf) << 4; - - c->x86_capability[0] = edx; - c->x86_capability[4] = ecx; - } - - /* Additional Intel-defined flags: level 0x00000007 */ - if (c->cpuid_level >= 0x00000007) { - u32 eax, ebx, ecx, edx; - - cpuid_count(0x00000007, 0, &eax, &ebx, &ecx, &edx); - c->x86_capability[9] = ebx; - c->x86_capability[11] = ecx; - } - - /* Extended state features: level 0x0000000d */ - if (c->cpuid_level >= 0x0000000d) { - u32 eax, ebx, ecx, edx; - - cpuid_count(0x0000000d, 1, &eax, &ebx, &ecx, &edx); - c->x86_capability[10] = eax; - } - - /* AMD-defined flags: level 0x80000001 */ - c->extended_cpuid_level = cpuid_eax(0x80000000); - - if ((c->extended_cpuid_level & 0xffff0000) == 0x80000000) { - if (c->extended_cpuid_level >= 0x80000001) { - c->x86_capability[1] = cpuid_edx(0x80000001); - c->x86_capability[6] = cpuid_ecx(0x80000001); - } - } - - /* - * We're don't care about scattered features for now, - * otherwise look into init_scattered_cpuid_features() - * in kernel. - */ - - if (c->extended_cpuid_level >= 0x80000004) { - unsigned int *v; - char *p, *q; - v = (unsigned int *)c->x86_model_id; - cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]); - cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]); - cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]); - c->x86_model_id[48] = 0; - - /* - * Intel chips right-justify this string for some dumb reason; - * undo that brain damage: - */ - p = q = &c->x86_model_id[0]; - while (*p == ' ') - p++; - if (p != q) { - while (*p) - *q++ = *p++; - while (q <= &c->x86_model_id[48]) - *q++ = '\0'; /* Zero-pad the rest */ - } - } - - /* On x86-64 NOP is always present */ - set_cpu_cap(c, X86_FEATURE_NOPL); - - switch (c->x86_vendor) { - case X86_VENDOR_INTEL: - /* - * Strictly speaking we need to read MSR_IA32_MISC_ENABLE - * here but on ring3 it's impossible. - */ - if (c->x86_family == 15) { - clear_cpu_cap(c, X86_FEATURE_REP_GOOD); - clear_cpu_cap(c, X86_FEATURE_ERMS); - } else if (c->x86_family == 6) { - /* On x86-64 rep is fine */ - set_cpu_cap(c, X86_FEATURE_REP_GOOD); - } - - /* See filter_cpuid_features in kernel */ - if ((s32)c->cpuid_level < (s32)0x0000000d) - clear_cpu_cap(c, X86_FEATURE_XSAVE); - break; - case X86_VENDOR_AMD: - /* - * Bit 31 in normal CPUID used for nonstandard 3DNow ID; - * 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway - */ - clear_cpu_cap(c, 0 * 32 + 31); - if (c->x86_family >= 0x10) - set_cpu_cap(c, X86_FEATURE_REP_GOOD); - if (c->x86_family == 0xf) { - u32 level; - - /* On C+ stepping K8 rep microcode works well for copy/memset */ - level = cpuid_eax(1); - if ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58) - set_cpu_cap(c, X86_FEATURE_REP_GOOD); - } - break; - } - - return 0; -} +static compel_cpuinfo_t rt_cpu_info; int cpu_init(void) { - if (cpu_init_cpuid(&rt_cpu_info)) + if (compel_cpuid(&rt_cpu_info)) return -1; BUILD_BUG_ON(sizeof(struct xsave_struct) != XSAVE_SIZE); diff --git a/criu/arch/x86/infect.c b/criu/arch/x86/infect.c index fe9d581bb..4dc2f93db 100644 --- a/criu/arch/x86/infect.c +++ b/criu/arch/x86/infect.c @@ -9,7 +9,8 @@ #include "asm/cpu.h" #include "kerndat.h" -#include "compel/include/asm/processor-flags.h" +#include +#include #include "compel/include/errno.h" #include #include diff --git a/criu/include/cpu.h b/criu/include/cpu.h index e94525a9e..e30696790 100644 --- a/criu/include/cpu.h +++ b/criu/include/cpu.h @@ -1,9 +1,8 @@ #ifndef __CR_CPU_H__ #define __CR_CPU_H__ -#include "asm/cpu.h" +#include -extern bool cpu_has_feature(unsigned int feature); extern int cpu_init(void); extern int cpu_dump_cpuinfo(void); extern int cpu_validate_cpuinfo(void);