From fd07bc7791d74b5b274c62223cde3d8c7e552238 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 17 Dec 2014 16:48:00 +0300 Subject: [PATCH] cpu: Add 'ins' mode to --cpu-cap option In this mode we test if target cpu has all features present in image file but do not require bit to bit match: target cpu may be a new one with more features present. Signed-off-by: Cyrill Gorcunov Signed-off-by: Pavel Emelyanov --- Documentation/criu.txt | 6 ++ arch/x86/cpu.c | 122 +++++++++++++++++++++++++++++++++++++++-- cr-dump.c | 2 +- cr-restore.c | 2 +- crtools.c | 4 +- include/cr_options.h | 3 +- 6 files changed, 130 insertions(+), 9 deletions(-) diff --git a/Documentation/criu.txt b/Documentation/criu.txt index cf1a05d77..f9b6513dd 100644 --- a/Documentation/criu.txt +++ b/Documentation/criu.txt @@ -101,6 +101,12 @@ OPTIONS procceed. This is *default* mode if *--cpu-cap* is not present in command line. + - 'ins' Only require CPU compatibility on instructions level. On *dump* + all capabilities are writen into image file and on *restore* + only subset related to CPU instructions tested if target CPU + supports them. Unlike 'cpu' mode the target CPU may have more + features than ones present in image file. + - 'none'. Ignore capabilities. Most dangerous mode. The behaviour is implementation dependent. Try to not use it until really required. One possible need of using this option is when diff --git a/arch/x86/cpu.c b/arch/x86/cpu.c index 4f95990e9..9fcba7c4f 100644 --- a/arch/x86/cpu.c +++ b/arch/x86/cpu.c @@ -261,6 +261,112 @@ int cpu_dump_cpuinfo(void) return 0; } +#define __ins_bit(__l, __v) (1u << ((__v) - 32u * (__l))) + +static u32 x86_ins_capability_mask[NCAPINTS] = { + [0] = + __ins_bit(0, X86_FEATURE_FPU) | + __ins_bit(0, X86_FEATURE_TSC) | + __ins_bit(0, X86_FEATURE_CX8) | + __ins_bit(0, X86_FEATURE_SEP) | + __ins_bit(0, X86_FEATURE_CMOV) | + __ins_bit(0, X86_FEATURE_CLFLUSH) | + __ins_bit(0, X86_FEATURE_MMX) | + __ins_bit(0, X86_FEATURE_FXSR) | + __ins_bit(0, X86_FEATURE_XMM) | + __ins_bit(0, X86_FEATURE_XMM2), + + [1] = + __ins_bit(1, X86_FEATURE_SYSCALL) | + __ins_bit(1, X86_FEATURE_MMXEXT) | + __ins_bit(1, X86_FEATURE_RDTSCP) | + __ins_bit(1, X86_FEATURE_3DNOWEXT) | + __ins_bit(1, X86_FEATURE_3DNOW), + + [3] = + __ins_bit(3, X86_FEATURE_REP_GOOD) | + __ins_bit(3, X86_FEATURE_NOPL), + + [4] = + __ins_bit(4, X86_FEATURE_XMM3) | + __ins_bit(4, X86_FEATURE_PCLMULQDQ) | + __ins_bit(4, X86_FEATURE_MWAIT) | + __ins_bit(4, X86_FEATURE_SSSE3) | + __ins_bit(4, X86_FEATURE_CX16) | + __ins_bit(4, X86_FEATURE_XMM4_1) | + __ins_bit(4, X86_FEATURE_XMM4_2) | + __ins_bit(4, X86_FEATURE_MOVBE) | + __ins_bit(4, X86_FEATURE_POPCNT) | + __ins_bit(4, X86_FEATURE_AES) | + __ins_bit(4, X86_FEATURE_XSAVE) | + __ins_bit(4, X86_FEATURE_OSXSAVE) | + __ins_bit(4, X86_FEATURE_AVX) | + __ins_bit(4, X86_FEATURE_F16C) | + __ins_bit(4, X86_FEATURE_RDRAND), + + [6] = + __ins_bit(6, X86_FEATURE_ABM) | + __ins_bit(6, X86_FEATURE_SSE4A) | + __ins_bit(6, X86_FEATURE_MISALIGNSSE) | + __ins_bit(6, X86_FEATURE_3DNOWPREFETCH) | + __ins_bit(6, X86_FEATURE_XOP) | + __ins_bit(6, X86_FEATURE_FMA4) | + __ins_bit(6, X86_FEATURE_TBM), + + [9] = + __ins_bit(9, X86_FEATURE_FSGSBASE) | + __ins_bit(9, X86_FEATURE_BMI1) | + __ins_bit(9, X86_FEATURE_HLE) | + __ins_bit(9, X86_FEATURE_AVX2) | + __ins_bit(9, X86_FEATURE_BMI2) | + __ins_bit(9, X86_FEATURE_ERMS) | + __ins_bit(9, X86_FEATURE_RTM) | + __ins_bit(9, X86_FEATURE_MPX) | + __ins_bit(9, X86_FEATURE_AVX512F) | + __ins_bit(9, X86_FEATURE_AVX512DQ) | + __ins_bit(9, X86_FEATURE_RDSEED) | + __ins_bit(9, X86_FEATURE_ADX) | + __ins_bit(9, X86_FEATURE_CLFLUSHOPT) | + __ins_bit(9, X86_FEATURE_AVX512PF) | + __ins_bit(9, X86_FEATURE_AVX512ER) | + __ins_bit(9, X86_FEATURE_AVX512CD) | + __ins_bit(9, X86_FEATURE_SHA) | + __ins_bit(9, X86_FEATURE_AVX512BW) | + __ins_bit(9, X86_FEATURE_AVXVL), + + [10] = + __ins_bit(10, X86_FEATURE_XSAVEOPT) | + __ins_bit(10, X86_FEATURE_XSAVEC) | + __ins_bit(10, X86_FEATURE_XGETBV1) | + __ins_bit(10, X86_FEATURE_XSAVES), + + [11] = + __ins_bit(11, X86_FEATURE_PREFETCHWT1), +}; + +#undef __ins_bit + +static int cpu_validate_ins_features(CpuinfoX86Entry *img_x86_entry) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(rt_cpu_info.x86_capability); i++) { + u32 s = img_x86_entry->capability[i] & x86_ins_capability_mask[i]; + u32 d = rt_cpu_info.x86_capability[i] & x86_ins_capability_mask[i]; + + /* + * Destination might be more feature rich + * but not the reverse. + */ + if (s & ~d) { + pr_err("CPU instruction capabilities do not match run time\n"); + return -1; + } + } + + return 0; +} + static int cpu_validate_features(CpuinfoX86Entry *img_x86_entry) { if (img_x86_entry->n_capability != ARRAY_SIZE(rt_cpu_info.x86_capability)) { @@ -298,10 +404,14 @@ static int cpu_validate_features(CpuinfoX86Entry *img_x86_entry) } /* - * FIXME We need to bring ability to run images with lower - * features on more capable CPU. + * Capability on instructions level only. */ + if (opts.cpu_cap == CPU_CAP_INS) + return cpu_validate_ins_features(img_x86_entry); + /* + * Strict capability mode. Everything must match. + */ if (memcmp(img_x86_entry->capability, rt_cpu_info.x86_capability, sizeof(rt_cpu_info.x86_capability))) { pr_err("CPU capabilites do not match run time\n"); @@ -367,10 +477,12 @@ int cpuinfo_check(void) return 1; /* - * Force to check all caps because its been - * called as a special command from options. + * Force to check all caps if empty passed, + * still allow to check instructions only + * and etc. */ - opts.cpu_cap = CPU_CAP_ALL; + if (!opts.cpu_cap) + opts.cpu_cap = CPU_CAP_ALL; if (cpu_validate_cpuinfo()) return 1; diff --git a/cr-dump.c b/cr-dump.c index 31afaa07c..cfdde34a0 100644 --- a/cr-dump.c +++ b/cr-dump.c @@ -1832,7 +1832,7 @@ int cr_dump_tasks(pid_t pid) if (write_img_inventory()) goto err; - if (opts.cpu_cap & CPU_CAP_CPU) { + if (opts.cpu_cap & (CPU_CAP_CPU | CPU_CAP_INS)) { if (cpu_dump_cpuinfo()) goto err; } diff --git a/cr-restore.c b/cr-restore.c index 3844bf402..dc855f72e 100644 --- a/cr-restore.c +++ b/cr-restore.c @@ -1894,7 +1894,7 @@ int cr_restore_tasks(void) if (vdso_init()) goto err; - if (opts.cpu_cap & CPU_CAP_CPU) { + if (opts.cpu_cap & (CPU_CAP_INS | CPU_CAP_CPU)) { if (cpu_validate_cpuinfo()) goto err; } diff --git a/crtools.c b/crtools.c index c03b0252f..d23f30241 100644 --- a/crtools.c +++ b/crtools.c @@ -122,6 +122,8 @@ static int parse_cpu_cap(struct cr_options *opts, const char *optarg) ____cpu_set_cap(opts, CPU_CAP_NONE, inverse); else if (!strncmp(optarg, "cpu", 3)) ____cpu_set_cap(opts, CPU_CAP_CPU, inverse); + else if (!strncmp(optarg, "ins", 3)) + ____cpu_set_cap(opts, CPU_CAP_INS, inverse); else goto Esyntax; } @@ -595,7 +597,7 @@ usage: " -W|--work-dir DIR directory to cd and write logs/pidfiles/stats to\n" " (if not specified, value of --images-dir is used)\n" " --cpu-cap [CAP] require certain cpu capability. CAP: may be one of:\n" -" 'cpu','fpu','all','none'. To disable capability, prefix it with '^'.\n" +" 'cpu','fpu','all','ins','none'. To disable capability, prefix it with '^'.\n" " --exec-cmd execute the command specified after '--' on successful\n" " restore making it the parent of the restored process\n" "\n" diff --git a/include/cr_options.h b/include/cr_options.h index 3735b0919..d6ce2ae4d 100644 --- a/include/cr_options.h +++ b/include/cr_options.h @@ -11,7 +11,8 @@ #define CPU_CAP_NONE (0u) #define CPU_CAP_ALL (-1u) #define CPU_CAP_FPU (1u) /* Only FPU capability required */ -#define CPU_CAP_CPU (2u) /* CPU capability required */ +#define CPU_CAP_CPU (2u) /* Strict CPU capability required */ +#define CPU_CAP_INS (4u) /* Instructions CPU capatibility */ #define CPU_CAP_DEFAULT (CPU_CAP_FPU) struct cg_root_opt {