[CRIU] [PATCH 06/22] cpu: Prepare scaffold for obtaining cpu features
Pavel Emelyanov
xemul at parallels.com
Wed Dec 12 08:47:29 EST 2012
On 11/22/2012 01:05 AM, Cyrill Gorcunov wrote:
>
> While this patch may look a big one, in real it does pretty simple things
>
> - adds ability to parse /proc/cpuinfo to find which FPU c/r modes
> _kernel_ does support (some features can be disabled via kernel
> command line, for example the kernel may run with "nofxsr" option
> which won't allow us to do a checkpoint)
>
> - adds ability to find some of rt-features the _cpu_ supports. In
> particular if xsave insn is supported we need to know how big memory
> slab is needed to keep complete fpu frame
>
> - it adds symbolic names for all the fetures known to the kernel at
> the moment, i decided to bring them all in because it allow us to
> extend parsing in more flexible way if needed (ie to add new feature
> parsing simply extend cpu_parse_flags by two lines of code)
>
> Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
> ---
> Makefile | 1 +
> cpu.c | 144 ++++++++++++++++++
> include/cpu.h | 412 ++++++++++++++++++++++++++++++++++++++++++++++++++
> include/proc_parse.h | 2 +
> proc_parse.c | 28 ++++
> 5 files changed, 587 insertions(+), 0 deletions(-)
> create mode 100644 cpu.c
> create mode 100644 include/cpu.h
>
> +/* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */
> +#define X86_FEATURE_FPU (0*32+ 0) /* Onboard FPU */
> +#define X86_FEATURE_VME (0*32+ 1) /* Virtual Mode Extensions */
> +#define X86_FEATURE_DE (0*32+ 2) /* Debugging Extensions */
> +#define X86_FEATURE_PSE (0*32+ 3) /* Page Size Extensions */
> +#define X86_FEATURE_TSC (0*32+ 4) /* Time Stamp Counter */
> +#define X86_FEATURE_MSR (0*32+ 5) /* Model-Specific Registers */
> +#define X86_FEATURE_PAE (0*32+ 6) /* Physical Address Extensions */
> +#define X86_FEATURE_MCE (0*32+ 7) /* Machine Check Exception */
> +#define X86_FEATURE_CX8 (0*32+ 8) /* CMPXCHG8 instruction */
> +#define X86_FEATURE_APIC (0*32+ 9) /* Onboard APIC */
> +#define X86_FEATURE_SEP (0*32+11) /* SYSENTER/SYSEXIT */
> +#define X86_FEATURE_MTRR (0*32+12) /* Memory Type Range Registers */
> +#define X86_FEATURE_PGE (0*32+13) /* Page Global Enable */
> +#define X86_FEATURE_MCA (0*32+14) /* Machine Check Architecture */
> +#define X86_FEATURE_CMOV (0*32+15) /* CMOV instructions */
> + /* (plus FCMOVcc, FCOMI with FPU) */
Why do we need all this crap, while we use only 3 of them?
> +int cpu_parse_flags(CpuFeature *feature, char *line)
> +{
> + char *tok;
> +
> + for (tok = strtok(line, " \t\n"); tok;
> + tok = strtok(NULL, " \t\n")) {
> + if (!strcmp(tok, x86_cap_flags[X86_FEATURE_FXSR]))
> + feature->fxsr = true;
> + else if (!strcmp(tok, x86_cap_flags[X86_FEATURE_XSAVE]))
> + feature->xsave = true;
> + else if (!strcmp(tok, x86_cap_flags[X86_FEATURE_FPU]))
> + feature->fpu = true;
> + }
> +
> + return 0;
> +}
Should be in proc_parse.c
> +int cpu_fill_feature(CpuFeature *feature)
> +{
> + /*
> + * Simply fills the cache if nil passed.
> + */
> +
> + if (feature) {
> + cpu_feature__init(feature);
> + if (likely(use_cached_feature)) {
> + feature->fpu = cached_feature.fpu;
> + feature->fxsr = cached_feature.fxsr;
> + feature->xsave = cached_feature.xsave;
> + return 0;
> + }
> + }
> +
> + if (parse_cpuinfo_features(&cached_feature))
> + return -1;
> +
> + use_cached_feature = true;
> +
> + if (!feature)
> + return 0;
> +
> + return cpu_fill_feature(feature);
This is awful :( This kind of code is typically written like
if (!cache)
cache = refill_cache
val = cache
> +}
> +bool cpu_check_feature(CpuFeature *feature)
> +{
> + if (!feature->fpu) {
> + pr_err("The FPU is unsupported\n");
> + return false;
> + }
> +
> + if (!feature->fxsr) {
> + pr_err("The cpu doesn't support `fxsave' instruction\n");
> + return false;
> + }
> +
> + return true;
> +}
Name of function is bad.
> +int cpu_rt_init(void)
> +{
> + u32 eax, ebx, ecx, edx;
> +
> + /*
> + * Make sure the cpu we're running on
> + * can run FPU related stuff.
> + */
> + cpuid(1, &eax, &ebx, &ecx, &edx);
> + ((u32 *)rt_cpu_features)[0] = edx;
> + ((u32 *)rt_cpu_features)[4] = ecx;
> +
First we call cpuid...
> +
> + if (cpu_fill_feature(NULL))
> + return -1;
> +
> + if (!cpu_check_feature(&cached_feature))
> + return -1;
> +
> + return 0;
> +}
... then read /proc/cpuinfo. What for?
More information about the CRIU
mailing list