debuggers.hg

changeset 22263:27c01a2e2a47

xl: implement parsing of cpuid parameter and translate to Xen interface

Parses a string enumerating cpuid flags and their behavior.
The syntax is: cpuid = "host,<flagname>=[01xks],..."
Supports:
0: clear this flag
1: set this flag
x: don't care, use the default handling
k: use the host value
s: as k, but keep stable across migrations

For multiple bit flags there have to be numbers passed (hex or dec),
like: family=0x10,model=4

Signed-off-by: Andre Przywara <andre.przywara@amd.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
committer: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
author Andre Przywara <andre.przywara@amd.com>
date Fri Oct 01 17:20:41 2010 +0100 (2010-10-01)
parents b89fa6d3f754
children a8c72f5a6bce
files tools/libxl/libxl.c tools/libxl/libxl.h tools/libxl/xl_cmdimpl.c
line diff
     1.1 --- a/tools/libxl/libxl.c	Fri Oct 01 15:42:46 2010 +0100
     1.2 +++ b/tools/libxl/libxl.c	Fri Oct 01 17:20:41 2010 +0100
     1.3 @@ -3524,6 +3524,225 @@ uint32_t libxl_vm_get_start_time(libxl_c
     1.4      return ret;
     1.5  }
     1.6  
     1.7 +#define CPUID_REG_INV 0
     1.8 +#define CPUID_REG_EAX 1
     1.9 +#define CPUID_REG_EBX 2
    1.10 +#define CPUID_REG_ECX 3
    1.11 +#define CPUID_REG_EDX 4
    1.12 +
    1.13 +/* mapping CPUID features to names
    1.14 + * holds a "name" for each feature, specified by the "leaf" number (and an
    1.15 + * optional "subleaf" in ECX), the "reg"ister (EAX-EDX) used and a number of
    1.16 + * bits starting with "bit" and being "length" bits long.
    1.17 + * Used for the static structure describing all features.
    1.18 + */
    1.19 +struct cpuid_flags {
    1.20 +    char* name;
    1.21 +    uint32_t leaf;
    1.22 +    uint32_t subleaf;
    1.23 +    int reg;
    1.24 +    int bit;
    1.25 +    int length;
    1.26 +};
    1.27 +
    1.28 +/* go through the dynamic array finding the entry for a specified leaf.
    1.29 + * if no entry exists, allocate one and return that.
    1.30 + */
    1.31 +static libxl_cpuid_policy_list cpuid_find_match(libxl_cpuid_policy_list *list,
    1.32 +                                          uint32_t leaf, uint32_t subleaf)
    1.33 +{
    1.34 +    int i = 0;
    1.35 +
    1.36 +    if (*list != NULL) {
    1.37 +        for (i = 0; (*list)[i].input[0] != XEN_CPUID_INPUT_UNUSED; i++) {
    1.38 +            if ((*list)[i].input[0] == leaf && (*list)[i].input[1] == subleaf)
    1.39 +                return *list + i;
    1.40 +        }
    1.41 +    }
    1.42 +    *list = realloc(*list, sizeof((*list)[0]) * (i + 2));
    1.43 +    (*list)[i].input[0] = leaf;
    1.44 +    (*list)[i].input[1] = subleaf;
    1.45 +    memset((*list)[i].policy, 0, 4 * sizeof(char*));
    1.46 +    (*list)[i + 1].input[0] = XEN_CPUID_INPUT_UNUSED;
    1.47 +    return *list + i;
    1.48 +}
    1.49 +
    1.50 +/* parse a single key=value pair and translate it into the libxc
    1.51 + * used interface using 32-characters strings for each register.
    1.52 + * Will overwrite earlier entries and thus can be called multiple
    1.53 + * times.
    1.54 + */
    1.55 +int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str)
    1.56 +{
    1.57 +#define NA XEN_CPUID_INPUT_UNUSED
    1.58 +    struct cpuid_flags cpuid_flags[] = {
    1.59 +        {"maxleaf",      0x00000000, NA, CPUID_REG_EAX,  0, 32},
    1.60 +      /* the following two entries are subject to tweaking later in the code */
    1.61 +        {"family",       0x00000001, NA, CPUID_REG_EAX,  8,  8},
    1.62 +        {"model",        0x00000001, NA, CPUID_REG_EAX,  4,  8},
    1.63 +        {"stepping",     0x00000001, NA, CPUID_REG_EAX,  0,  4},
    1.64 +        {"localapicid",  0x00000001, NA, CPUID_REG_EBX, 24,  8},
    1.65 +        {"proccount",    0x00000001, NA, CPUID_REG_EBX, 16,  8},
    1.66 +        {"clflush",      0x00000001, NA, CPUID_REG_EBX,  8,  8},
    1.67 +        {"brandid",      0x00000001, NA, CPUID_REG_EBX,  0,  8},
    1.68 +        {"f16c",         0x00000001, NA, CPUID_REG_ECX, 29,  1},
    1.69 +        {"avx",          0x00000001, NA, CPUID_REG_ECX, 28,  1},
    1.70 +        {"osxsave",      0x00000001, NA, CPUID_REG_ECX, 27,  1},
    1.71 +        {"xsave",        0x00000001, NA, CPUID_REG_ECX, 26,  1},
    1.72 +        {"aes",          0x00000001, NA, CPUID_REG_ECX, 25,  1},
    1.73 +        {"popcnt",       0x00000001, NA, CPUID_REG_ECX, 23,  1},
    1.74 +        {"movbe",        0x00000001, NA, CPUID_REG_ECX, 22,  1},
    1.75 +        {"x2apic",       0x00000001, NA, CPUID_REG_ECX, 21,  1},
    1.76 +        {"sse4.2",       0x00000001, NA, CPUID_REG_ECX, 20,  1},
    1.77 +        {"sse4.1",       0x00000001, NA, CPUID_REG_ECX, 19,  1},
    1.78 +        {"dca",          0x00000001, NA, CPUID_REG_ECX, 18,  1},
    1.79 +        {"pdcm",         0x00000001, NA, CPUID_REG_ECX, 15,  1},
    1.80 +        {"xtpr",         0x00000001, NA, CPUID_REG_ECX, 14,  1},
    1.81 +        {"cmpxchg16",    0x00000001, NA, CPUID_REG_ECX, 13,  1},
    1.82 +        {"cntxid",       0x00000001, NA, CPUID_REG_ECX, 10,  1},
    1.83 +        {"ssse3",        0x00000001, NA, CPUID_REG_ECX,  9,  1},
    1.84 +        {"tm2",          0x00000001, NA, CPUID_REG_ECX,  8,  1},
    1.85 +        {"est",          0x00000001, NA, CPUID_REG_ECX,  7,  1},
    1.86 +        {"smx",          0x00000001, NA, CPUID_REG_ECX,  6,  1},
    1.87 +        {"vmx",          0x00000001, NA, CPUID_REG_ECX,  5,  1},
    1.88 +        {"dscpl",        0x00000001, NA, CPUID_REG_ECX,  4,  1},
    1.89 +        {"monitor",      0x00000001, NA, CPUID_REG_ECX,  3,  1},
    1.90 +        {"dtes64",       0x00000001, NA, CPUID_REG_ECX,  2,  1},
    1.91 +        {"sse3",         0x00000001, NA, CPUID_REG_ECX,  0,  1},
    1.92 +        {"pbe",          0x00000001, NA, CPUID_REG_EDX, 31,  1},
    1.93 +        {"ia64",         0x00000001, NA, CPUID_REG_EDX, 30,  1},
    1.94 +        {"tm",           0x00000001, NA, CPUID_REG_EDX, 29,  1},
    1.95 +        {"htt",          0x00000001, NA, CPUID_REG_EDX, 28,  1},
    1.96 +        {"ss",           0x00000001, NA, CPUID_REG_EDX, 27,  1},
    1.97 +        {"sse2",         0x00000001, NA, CPUID_REG_EDX, 26,  1},
    1.98 +        {"sse",          0x00000001, NA, CPUID_REG_EDX, 25,  1},
    1.99 +        {"fxsr",         0x00000001, NA, CPUID_REG_EDX, 24,  1},
   1.100 +        {"mmx",          0x00000001, NA, CPUID_REG_EDX, 23,  1},
   1.101 +        {"acpi",         0x00000001, NA, CPUID_REG_EDX, 22,  1},
   1.102 +        {"ds",           0x00000001, NA, CPUID_REG_EDX, 21,  1},
   1.103 +        {"clfsh",        0x00000001, NA, CPUID_REG_EDX, 19,  1},
   1.104 +        {"psn",          0x00000001, NA, CPUID_REG_EDX, 18,  1},
   1.105 +        {"pse36",        0x00000001, NA, CPUID_REG_EDX, 17,  1},
   1.106 +        {"pat",          0x00000001, NA, CPUID_REG_EDX, 16,  1},
   1.107 +        {"cmov",         0x00000001, NA, CPUID_REG_EDX, 15,  1},
   1.108 +        {"mca",          0x00000001, NA, CPUID_REG_EDX, 14,  1},
   1.109 +        {"pge",          0x00000001, NA, CPUID_REG_EDX, 13,  1},
   1.110 +        {"mtrr",         0x00000001, NA, CPUID_REG_EDX, 12,  1},
   1.111 +        {"sysenter",     0x00000001, NA, CPUID_REG_EDX, 11,  1},
   1.112 +        {"apic",         0x00000001, NA, CPUID_REG_EDX,  9,  1},
   1.113 +        {"cmpxchg8",     0x00000001, NA, CPUID_REG_EDX,  8,  1},
   1.114 +        {"mce",          0x00000001, NA, CPUID_REG_EDX,  7,  1},
   1.115 +        {"pae",          0x00000001, NA, CPUID_REG_EDX,  6,  1},
   1.116 +        {"msr",          0x00000001, NA, CPUID_REG_EDX,  5,  1},
   1.117 +        {"tsc",          0x00000001, NA, CPUID_REG_EDX,  4,  1},
   1.118 +        {"pse",          0x00000001, NA, CPUID_REG_EDX,  3,  1},
   1.119 +        {"de",           0x00000001, NA, CPUID_REG_EDX,  2,  1},
   1.120 +        {"vme",          0x00000001, NA, CPUID_REG_EDX,  1,  1},
   1.121 +        {"fpu",          0x00000001, NA, CPUID_REG_EDX,  0,  1},
   1.122 +        {"topoext",      0x80000001, NA, CPUID_REG_ECX, 22,  1},
   1.123 +        {"tbm",          0x80000001, NA, CPUID_REG_ECX, 21,  1},
   1.124 +        {"nodeid",       0x80000001, NA, CPUID_REG_ECX, 19,  1},
   1.125 +        {"fma4",         0x80000001, NA, CPUID_REG_ECX, 16,  1},
   1.126 +        {"lwp",          0x80000001, NA, CPUID_REG_ECX, 15,  1},
   1.127 +        {"wdt",          0x80000001, NA, CPUID_REG_ECX, 13,  1},
   1.128 +        {"skinit",       0x80000001, NA, CPUID_REG_ECX, 12,  1},
   1.129 +        {"xop",          0x80000001, NA, CPUID_REG_ECX, 11,  1},
   1.130 +        {"ibs",          0x80000001, NA, CPUID_REG_ECX, 10,  1},
   1.131 +        {"osvw",         0x80000001, NA, CPUID_REG_ECX, 10,  1},
   1.132 +        {"3dnowprefetch",0x80000001, NA, CPUID_REG_ECX,  8,  1},
   1.133 +        {"misalignsse",  0x80000001, NA, CPUID_REG_ECX,  7,  1},
   1.134 +        {"sse4a",        0x80000001, NA, CPUID_REG_ECX,  6,  1},
   1.135 +        {"abm",          0x80000001, NA, CPUID_REG_ECX,  5,  1},
   1.136 +        {"altmovcr8",    0x80000001, NA, CPUID_REG_ECX,  4,  1},
   1.137 +        {"extapic",      0x80000001, NA, CPUID_REG_ECX,  3,  1},
   1.138 +        {"svm",          0x80000001, NA, CPUID_REG_ECX,  2,  1},
   1.139 +        {"cmplegacy",    0x80000001, NA, CPUID_REG_ECX,  1,  1},
   1.140 +        {"lahfsahf",     0x80000001, NA, CPUID_REG_ECX,  0,  1},
   1.141 +        {"3dnow",        0x80000001, NA, CPUID_REG_EDX, 31,  1},
   1.142 +        {"3dnowext",     0x80000001, NA, CPUID_REG_EDX, 30,  1},
   1.143 +        {"lm",           0x80000001, NA, CPUID_REG_EDX, 29,  1},
   1.144 +        {"rdtscp",       0x80000001, NA, CPUID_REG_EDX, 27,  1},
   1.145 +        {"page1gb",      0x80000001, NA, CPUID_REG_EDX, 26,  1},
   1.146 +        {"ffxsr",        0x80000001, NA, CPUID_REG_EDX, 25,  1},
   1.147 +        {"mmxext",       0x80000001, NA, CPUID_REG_EDX, 22,  1},
   1.148 +        {"nx",           0x80000001, NA, CPUID_REG_EDX, 20,  1},
   1.149 +        {"syscall",      0x80000001, NA, CPUID_REG_EDX, 11,  1},
   1.150 +        {"procpkg",      0x00000004,  0, CPUID_REG_EAX, 26,  6},
   1.151 +        {"apicidsize",   0x80000008, NA, CPUID_REG_ECX, 12,  4},
   1.152 +        {"nc",           0x80000008, NA, CPUID_REG_ECX,  0,  8},
   1.153 +
   1.154 +        {NULL, 0, CPUID_REG_INV, 0, 0}
   1.155 +    };
   1.156 +#undef NA
   1.157 +    char *sep, *val, *endptr;
   1.158 +    int i;
   1.159 +    struct cpuid_flags *flag;
   1.160 +    struct libxl__cpuid_policy *entry;
   1.161 +    unsigned long num;
   1.162 +    char flags[33], *resstr;
   1.163 +
   1.164 +    sep = strchr(str, '=');
   1.165 +    if (sep == NULL) {
   1.166 +        return 1;
   1.167 +    } else {
   1.168 +        val = sep + 1;
   1.169 +    }
   1.170 +    for (flag = cpuid_flags; flag->name != NULL; flag++) {
   1.171 +        if(!strncmp(str, flag->name, sep - str) && flag->name[sep - str] == 0)
   1.172 +            break;
   1.173 +    }
   1.174 +    if (flag->name == NULL) {
   1.175 +        return 2;
   1.176 +    }
   1.177 +    entry = cpuid_find_match(cpuid, flag->leaf, flag->subleaf);
   1.178 +    resstr = entry->policy[flag->reg - 1];
   1.179 +    if (resstr == NULL) {
   1.180 +        resstr = strdup("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
   1.181 +    }
   1.182 +    num = strtoull(val, &endptr, 0);
   1.183 +    flags[flag->length] = 0;
   1.184 +    if (endptr != val) {
   1.185 +        /* is this was a valid number, write the binary form into the string */
   1.186 +        for (i = 0; i < flag->length; i++) {
   1.187 +            flags[flag->length - 1 - i] = "01"[!!(num & (1 << i))];
   1.188 +        }
   1.189 +    } else {
   1.190 +        switch(val[0]) {
   1.191 +        case 'x': case 'k': case 's':
   1.192 +            memset(flags, val[0], flag->length);
   1.193 +            break;
   1.194 +        default:
   1.195 +            return 3;
   1.196 +        }
   1.197 +    }
   1.198 +    /* the family and model entry is potentially split up across
   1.199 +     * two fields in Fn0000_0001_EAX, so handle them here separately.
   1.200 +     */
   1.201 +    if (!strncmp(str, "family", sep - str)) {
   1.202 +        if (num < 16) {
   1.203 +            memcpy(resstr + (32 - 4) - flag->bit, flags + 4, 4);
   1.204 +            memcpy(resstr + (32 - 8) - 20, "00000000", 8);
   1.205 +        } else {
   1.206 +            num -= 15;
   1.207 +            memcpy(resstr + (32 - 4) - flag->bit, "1111", 4);
   1.208 +            for (i = 0; i < 7; i++) {
   1.209 +                flags[7 - i] = "01"[num & 1];
   1.210 +                num >>= 1;
   1.211 +            }
   1.212 +            memcpy(resstr + (32 - 8) - 20, flags, 8);
   1.213 +        }
   1.214 +    } else if (!strncmp(str, "model", sep - str)) {
   1.215 +        memcpy(resstr + (32 - 4) - 16, flags, 4);
   1.216 +        memcpy(resstr + (32 - 4) - flag->bit, flags + 4, 4);
   1.217 +    } else {
   1.218 +        memcpy(resstr + (32 - flag->length) - flag->bit, flags,
   1.219 +               flag->length);
   1.220 +    }
   1.221 +    entry->policy[flag->reg - 1] = resstr;
   1.222 +
   1.223 +    return 0;
   1.224 +}
   1.225 +
   1.226  char *libxl_tmem_list(libxl_ctx *ctx, uint32_t domid, int use_long)
   1.227  {
   1.228      int rc;
     2.1 --- a/tools/libxl/libxl.h	Fri Oct 01 15:42:46 2010 +0100
     2.2 +++ b/tools/libxl/libxl.h	Fri Oct 01 17:20:41 2010 +0100
     2.3 @@ -411,6 +411,7 @@ int libxl_device_pci_shutdown(libxl_ctx 
     2.4  int libxl_device_pci_list_assigned(libxl_ctx *ctx, libxl_device_pci **list, uint32_t domid, int *num);
     2.5  int libxl_device_pci_list_assignable(libxl_ctx *ctx, libxl_device_pci **list, int *num);
     2.6  int libxl_device_pci_parse_bdf(libxl_ctx *ctx, libxl_device_pci *pcidev, const char *str);
     2.7 +int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str);
     2.8  
     2.9  /*
    2.10   * Functions for allowing users of libxl to store private data
     3.1 --- a/tools/libxl/xl_cmdimpl.c	Fri Oct 01 15:42:46 2010 +0100
     3.2 +++ b/tools/libxl/xl_cmdimpl.c	Fri Oct 01 17:20:41 2010 +0100
     3.3 @@ -1085,6 +1085,17 @@ skip_vfb:
     3.4          }
     3.5      }
     3.6  
     3.7 +    if (!xlu_cfg_get_string(config, "cpuid", &buf)) {
     3.8 +        char *buf2, *p, *strtok_ptr;
     3.9 +
    3.10 +        buf2 = strdup(buf);
    3.11 +        p = strtok_r(buf2, ",", &strtok_ptr);
    3.12 +        for (p = strtok_r(NULL, ",", &strtok_ptr); p != NULL;
    3.13 +             p = strtok_r(NULL, ",", &strtok_ptr))
    3.14 +            libxl_cpuid_parse_config(&b_info->cpuid, p);
    3.15 +        free(buf2);
    3.16 +    }
    3.17 +
    3.18      if (c_info->hvm == 1) {
    3.19          /* init dm from c and b */
    3.20          init_dm_info(dm_info, c_info, b_info);