diff --git a/arch/aarch64/cpu.c b/arch/aarch64/cpu.c index fc1b73e6d..59f61b769 100644 --- a/arch/aarch64/cpu.c +++ b/arch/aarch64/cpu.c @@ -12,3 +12,13 @@ int cpu_init(void) { return 0; } + +int cpu_dump_cpuinfo(void) +{ + return 0; +} + +int cpu_validate_cpuinfo(void) +{ + return 0; +} diff --git a/arch/arm/cpu.c b/arch/arm/cpu.c index fc1b73e6d..59f61b769 100644 --- a/arch/arm/cpu.c +++ b/arch/arm/cpu.c @@ -12,3 +12,13 @@ int cpu_init(void) { return 0; } + +int cpu_dump_cpuinfo(void) +{ + return 0; +} + +int cpu_validate_cpuinfo(void) +{ + return 0; +} diff --git a/arch/x86/cpu.c b/arch/x86/cpu.c index 12943e469..5ff30956d 100644 --- a/arch/x86/cpu.c +++ b/arch/x86/cpu.c @@ -13,12 +13,16 @@ #include "compiler.h" +#include "cr_options.h" #include "proc_parse.h" #include "util.h" #include "log.h" #include "cpu.h" +#include "protobuf.h" +#include "protobuf/cpuinfo.pb-c.h" + #undef LOG_PREFIX #define LOG_PREFIX "cpu: " @@ -220,3 +224,134 @@ int cpu_init(void) return 0; } + +int cpu_dump_cpuinfo(void) +{ + CpuinfoEntry cpu_info = CPUINFO_ENTRY__INIT; + CpuinfoX86Entry cpu_x86_info = CPUINFO_X86_ENTRY__INIT; + CpuinfoX86Entry *cpu_x86_info_ptr = &cpu_x86_info; + struct cr_img *img; + + img = open_image(CR_FD_CPUINFO, O_DUMP); + if (!img) + return -1; + + cpu_info.x86_entry = &cpu_x86_info_ptr; + cpu_info.n_x86_entry = 1; + + cpu_x86_info.vendor_id = (rt_cpu_info.x86_vendor == X86_VENDOR_INTEL) ? + CPUINFO_X86_ENTRY__VENDOR__INTEL : + CPUINFO_X86_ENTRY__VENDOR__AMD; + cpu_x86_info.cpu_family = rt_cpu_info.x86_family; + cpu_x86_info.model = rt_cpu_info.x86_model; + cpu_x86_info.stepping = rt_cpu_info.x86_mask; + cpu_x86_info.capability_ver = 1; + cpu_x86_info.n_capability = ARRAY_SIZE(rt_cpu_info.x86_capability); + cpu_x86_info.capability = (void *)rt_cpu_info.x86_capability; + + if (rt_cpu_info.x86_model_id[0]) + cpu_x86_info.model_id = rt_cpu_info.x86_model_id; + + if (pb_write_one(img, &cpu_info, PB_CPUINFO) < 0) { + close_image(img); + return -1; + } + + close_image(img); + return 0; +} + +static int cpu_validate_features(CpuinfoX86Entry *img_x86_entry) +{ + if (img_x86_entry->n_capability != ARRAY_SIZE(rt_cpu_info.x86_capability)) { + /* + * Image carries different number of bits. + * Simply reject, we can't guarantee anything + * in such case. + */ + pr_err("Size of features in image mismatch " + "one provided by run time CPU (%d:%d)\n", + (unsigned)img_x86_entry->n_capability, + (unsigned)ARRAY_SIZE(rt_cpu_info.x86_capability)); + return -1; + } + + if ((opts.cpu_cap & ~CPU_CAP_FPU) == CPU_CAP_FPU) { + /* + * If we're requested to check FPU only ignore + * any other bit. It's up to a user if the + * rest of mismatches won't cause problems. + */ + +#define __mismatch_fpu_bit(__bit) \ + (test_bit(__bit, (void *)img_x86_entry->capability) && \ + !cpu_has_feature(__bit)) + if (__mismatch_fpu_bit(X86_FEATURE_FPU) || + __mismatch_fpu_bit(X86_FEATURE_FXSR) || + __mismatch_fpu_bit(X86_FEATURE_XSAVE)) { + pr_err("FPU feature required by image " + "is not supported on host.\n"); + return -1; + } else + return 0; +#undef __mismatch_fpu_bit + } + + /* + * FIXME We need to bring ability to run images with lower + * features on more capable CPU. + */ + + 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"); + return -1; + } + + return 0; +} + +int cpu_validate_cpuinfo(void) +{ + CpuinfoX86Entry *img_x86_entry; + CpuinfoEntry *img_cpu_info; + struct cr_img *img; + int ret = -1; + + img = open_image(CR_FD_CPUINFO, O_RSTR | O_OPT); + if (!img) { + if (errno == ENOENT) + return 0; + else + return -1; + } + + if (pb_read_one(img, &img_cpu_info, PB_CPUINFO) < 0) + goto err; + + if (img_cpu_info->n_x86_entry != 1) { + pr_err("No x86 related cpuinfo in image, " + "corruption (n_x86_entry = %zi)\n", + img_cpu_info->n_x86_entry); + goto err; + } + + img_x86_entry = img_cpu_info->x86_entry[0]; + if (img_x86_entry->vendor_id != CPUINFO_X86_ENTRY__VENDOR__INTEL && + img_x86_entry->vendor_id != CPUINFO_X86_ENTRY__VENDOR__AMD) { + pr_err("Unknown cpu vendor %d\n", img_x86_entry->vendor_id); + goto err; + } + + if (img_x86_entry->n_capability != ARRAY_SIZE(rt_cpu_info.x86_capability)) { + pr_err("Image carries %u words while %u expected\n", + (unsigned)img_x86_entry->n_capability, + (unsigned)ARRAY_SIZE(rt_cpu_info.x86_capability)); + goto err; + } + + ret = cpu_validate_features(img_x86_entry); +err: + close_image(img); + return ret; +} diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index 4d5f3ed84..8dcf9b471 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -199,5 +199,7 @@ struct cpuinfo_x86 { 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); #endif /* __CR_CPU_H__ */ diff --git a/cr-dump.c b/cr-dump.c index df4bd737c..65c6f9c8a 100644 --- a/cr-dump.c +++ b/cr-dump.c @@ -1807,6 +1807,11 @@ int cr_dump_tasks(pid_t pid) if (write_img_inventory()) goto err; + if (opts.cpu_cap & CPU_CAP_CPU) { + if (cpu_dump_cpuinfo()) + goto err; + } + if (connect_to_page_server()) goto err; diff --git a/cr-restore.c b/cr-restore.c index 7c597b3d9..fd35bef2c 100644 --- a/cr-restore.c +++ b/cr-restore.c @@ -1863,6 +1863,11 @@ int cr_restore_tasks(void) if (vdso_init()) goto err; + if (opts.cpu_cap & CPU_CAP_CPU) { + if (cpu_validate_cpuinfo()) + goto err; + } + if (prepare_task_entries() < 0) goto err; diff --git a/crtools.c b/crtools.c index 87f442c72..ddf355eca 100644 --- a/crtools.c +++ b/crtools.c @@ -53,7 +53,7 @@ void init_opts(void) INIT_LIST_HEAD(&opts.ext_mounts); INIT_LIST_HEAD(&opts.new_cgroup_roots); - opts.cpu_cap = CPU_CAP_ALL; + opts.cpu_cap = CPU_CAP_DEFAULT; opts.manage_cgroups = false; opts.ps_socket = -1; } diff --git a/include/cpu.h b/include/cpu.h index aa3516b97..152dc0a59 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -5,5 +5,7 @@ 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); #endif /* __CR_CPU_H__ */