Skip to contentSkip to conversation

Configure hvm's cpuid

PATCH In review Jean Guyader 3 participants 4 messages Apr 24, 2008 Arm/actions semi architecture

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Configure hvm's cpuid

Hi,

This patch is to configure the cpuid's replies for hvm guests. The cpuid's replies are now pre-calculated in libxc and given to the hypervisor via a new domctl.

There is two part for this patch :
- We can overwrite cpuid's replies.
- We can check that a vm is compatible with a host's processor.

Best regards,

Signature · 1 line
Jean Guyader
tools/examples/xmexample.hvm +24 -0
diff -r 4e6577dec729 tools/examples/xmexample.hvm
@@ -219,3 +219,27 @@ serial='pty'
 #-----------------------------------------------------------------------------
 #   Set keyboard layout, default is en-us keyboard. 
 #keymap='ja'
+
+#-----------------------------------------------------------------------------
+#   Configure guest CPUID responses:
+#cpuid=[ '1:ecx=xxxxxxxxxxxxxxxxxxxxxxxxxx1xxxxx,
+#           eax=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' ]
+# - Set the VMX feature flag in the guest (CPUID_1:ECX:5)
+# - Default behaviour for all other bits in ECX And EAX registers.
+# 
+# Each successive character represent a lesser-significant bit:
+#  '1' -> force the corresponding bit to 1
+#  '0' -> force to 0
+#  'x' -> we don't care (default behaviour)
+#  'k' -> pass through the host bit value
+#  's' -> as 'k' but preserve across save/restore and migration
+#
+#   Configure host CPUID consistency checks, which must be satisfied for this
+#   VM to be allowed to run on this host:on this host's processor:
+#cpuid_check=[ '1:ecx=xxxxxxxxxxxxxxxxxxxxxxxxxx1xxxxx' ]
+#
+# The format is similar to the above for 'cpuid':
+#  '1' -> the bit must be '1'
+#  '0' -> the bit must be '0'
+#  'x' -> we don't care (do not check)
+#  's' -> the bit must be the same as the host that started this VM
tools/libxc/Makefile +1 -0
diff -r 4e6577dec729 tools/libxc/Makefile
@@ -53,6 +53,7 @@ GUEST_SRCS-y                 += xc_dom_c
 GUEST_SRCS-y                 += xc_dom_compat_linux.c
 
 GUEST_SRCS-$(CONFIG_X86)     += xc_dom_x86.c
+GUEST_SRCS-$(CONFIG_X86)     += xc_cpuid_x86.c
 GUEST_SRCS-$(CONFIG_IA64)    += xc_dom_ia64.c
 GUEST_SRCS-$(CONFIG_POWERPC) += xc_dom_powerpc.c
 endif
tools/libxc/xc_cpufeature.h new file +115 -0

115 lines not on this page · raw message

tools/libxc/xc_cpuid_x86.c new file +430 -0

430 lines not on this page · raw message

tools/libxc/xenctrl.h +16 -0
diff -r 4e6577dec729 tools/libxc/xenctrl.h
@@ -983,4 +983,20 @@ int xc_domain_set_target(int xc_handle,
                          uint32_t domid,
                          uint32_t target);
 
+#if defined(__i386__) || defined(__x86_64__)
+int xc_cpuid_check(int xc,
+                   const unsigned int *input,
+                   const char **config,
+                   char **config_transformed);
+int xc_cpuid_set(int xc,
+                 domid_t domid,
+                 const unsigned int *input,
+                 const char **config,
+                 char **config_transformed);
+int xc_cpuid_apply_policy(int xc,
+                          domid_t domid);
+void xc_cpuid_to_str(const unsigned int *regs,
+                     char **strs);
+#endif
+
 #endif /* XENCTRL_H */
tools/python/xen/lowlevel/xc/xc.c +135 -0

147 lines not on this page · raw message

tools/python/xen/xend/XendCheckpoint.py +1 -0
diff -r 4e6577dec729 tools/python/xen/xend/XendCheckpoint.py
@@ -309,6 +309,7 @@ def restore(xd, fd, dominfo = None, paus
                 else:
                     break
             os.close(qemu_fd)
+            restore_image.setCpuid()
 
 
         os.read(fd, 1)           # Wait for source to close connection
tools/python/xen/xend/XendConfig.py +51 -0

81 lines not on this page · raw message

tools/python/xen/xend/image.py +33 -0
diff -r 4e6577dec729 tools/python/xen/xend/image.py
@@ -551,6 +551,38 @@ class HVMImageHandler(ImageHandler):
         self.acpi = int(vmConfig['platform'].get('acpi', 0))
         self.guest_os_type = vmConfig['platform'].get('guest_os_type')
 
+        self.vmConfig = vmConfig
+           
+    def setCpuid(self):
+        xc.domain_set_policy_cpuid(self.vm.getDomid())
+
+        if 'cpuid' in self.vmConfig:
+            cpuid = self.vmConfig['cpuid']
+            transformed = {}
+            for sinput, regs in cpuid.iteritems():
+                inputs = sinput.split(',')
+                input = long(inputs[0])
+                sub_input = None
+                if len(inputs) == 2:
+                    sub_input = long(inputs[1])
+                t = xc.domain_set_cpuid(self.vm.getDomid(),
+                                        input, sub_input, regs)
+                transformed[sinput] = t
+            self.vmConfig['cpuid'] = transformed
+
+        if 'cpuid_check' in self.vmConfig:
+            cpuid_check = self.vmConfig['cpuid_check']
+            transformed = {}
+            for sinput, regs_check in cpuid_check.iteritems():
+                inputs = sinput.split(',')
+                input = long(inputs[0])
+                sub_input = None
+                if len(inputs) == 2:
+                    sub_input = long(inputs[1])
+                t = xc.domain_check_cpuid(input, sub_input, regs_check)
+                transformed[sinput] = t
+            self.vmConfig['cpuid_check'] = transformed
+
     # Return a list of cmd line args to the device models based on the
     # xm config file
     def parseDeviceModelArgs(self, vmConfig):
@@ -718,6 +750,7 @@ class X86_HVM_ImageHandler(HVMImageHandl
 
     def buildDomain(self):
         xc.hvm_set_param(self.vm.getDomid(), HVM_PARAM_PAE_ENABLED, self.pae)
+        self.setCpuid()
         return HVMImageHandler.buildDomain(self)
 
     def getRequiredAvailableMemory(self, mem_kb):
tools/python/xen/xm/create.py +31 -2
diff -r 4e6577dec729 tools/python/xen/xm/create.py
@@ -549,6 +549,14 @@ gopts.var('hap', val='HAP',
           use="""Hap status (0=hap is disabled;
           1=hap is enabled.""")
 
+gopts.var('cpuid', val="IN[,SIN]:eax=EAX,ebx=EBX,exc=ECX,edx=EDX",
+          fn=append_value, default=[],
+          use="""Cpuid description.""")
+
+gopts.var('cpuid_check', val="IN[,SIN]:eax=EAX,ebx=EBX,exc=ECX,edx=EDX",
+          fn=append_value, default=[],
+          use="""Cpuid check description.""")
+
 def err(msg):
     """Print an error to stderr and exit.
     """
@@ -755,7 +763,7 @@ def configure_hvm(config_image, vals):
              'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten',
              'sdl', 'display', 'xauthority', 'rtc_timeoffset', 'monitor',
              'acpi', 'apic', 'usb', 'usbdevice', 'keymap', 'pci', 'hpet',
-             'guest_os_type', 'hap', 'opengl']
+             'guest_os_type', 'hap', 'opengl', 'cpuid', 'cpuid_check']
 
     for a in args:
         if a in vals.__dict__ and vals.__dict__[a] is not None:
@@ -779,7 +787,8 @@ def make_config(vals):
     map(add_conf, ['name', 'memory', 'maxmem', 'shadow_memory',
                    'restart', 'on_poweroff',
                    'on_reboot', 'on_crash', 'vcpus', 'vcpu_avail', 'features',
-                   'on_xend_start', 'on_xend_stop', 'target'])
+                   'on_xend_start', 'on_xend_stop', 'target', 'cpuid',
+                   'cpuid_check'])
 
     if vals.uuid is not None:
         config.append(['uuid', vals.uuid])
@@ -842,6 +851,24 @@ def preprocess_disk(vals):
             err('Invalid disk specifier: ' + v)
         disk.append(d)
     vals.disk = disk
+
+def preprocess_cpuid(vals, attr_name):
+    if not vals.cpuid: return
+    cpuid = {} 
+    for cpuid_input in getattr(vals, attr_name):
+        cpuid_match = re.match(r"(?P<input>(0x)?[0-9A-Fa-f]+):(?P<regs>.*)", cpuid_input)
+        if cpuid_match != None:
+            res_cpuid = cpuid_match.groupdict()
+            input = res_cpuid['input']
+            regs = res_cpuid['regs'].split(',')
+            cpuid[input]= {} # New input
+            for reg in regs:
+                reg_match = re.match(r"(?P<reg>eax|ebx|ecx|edx)=(?P<val>.*)", reg)
+                if reg_match == None:
+                    err("cpuid's syntax is (eax|ebx|ecx|edx)=value")
+                res = reg_match.groupdict()
+                cpuid[input][res['reg']] = res['val'] # new register
+    setattr(vals, attr_name, cpuid)
 
 def preprocess_pci(vals):
     if not vals.pci: return
@@ -1047,6 +1074,8 @@ def preprocess(vals):
     preprocess_vnc(vals)
     preprocess_vtpm(vals)
     preprocess_access_control(vals)
+    preprocess_cpuid(vals, 'cpuid')
+    preprocess_cpuid(vals, 'cpuid_check')
 
 
 def comma_sep_kv_to_dict(c):
xen/arch/x86/domain.c +39 -2

61 lines not on this page · raw message

xen/arch/x86/domctl.c +39 -0
diff -r 4e6577dec729 xen/arch/x86/domctl.c
@@ -842,6 +842,45 @@ long arch_do_domctl(
     }
     break;
 
+    case XEN_DOMCTL_set_cpuid:
+    {
+        struct domain *d;
+        xen_domctl_cpuid_t *ctl = &domctl->u.cpuid;
+        cpuid_input_t *cpuid = NULL; 
+        int i;
+
+        ret = -ESRCH;
+        d = rcu_lock_domain_by_id(domctl->domain);
+        if ( d == NULL )
+            break;
+
+        for ( i = 0; i < MAX_CPUID_INPUT; i++ )
+        {
+            cpuid = &d->arch.cpuids[i];
+
+            if ( cpuid->input[0] == XEN_CPUID_INPUT_UNUSED )
+                break;
+
+            if ( (cpuid->input[0] == ctl->input[0]) &&
+                 ((cpuid->input[1] == XEN_CPUID_INPUT_UNUSED) ||
+                  (cpuid->input[1] == ctl->input[1])) )
+                break;
+        }
+        
+        if ( i == MAX_CPUID_INPUT )
+        {
+            ret = -ENOENT;
+        }
+        else
+        {
+            memcpy(cpuid, ctl, sizeof(cpuid_input_t));
+            ret = 0;
+        }
+
+        rcu_unlock_domain(d);
+    }
+    break;
+
     default:
         ret = -ENOSYS;
         break;
xen/arch/x86/hvm/hvm.c +44 -59

187 lines not on this page · raw message

xen/arch/x86/hvm/svm/svm.c +2 -47

58 lines not on this page · raw message

xen/arch/x86/hvm/vmx/vmx.c +10 -23
diff -r 4e6577dec729 xen/arch/x86/hvm/vmx/vmx.c
@@ -1311,34 +1311,21 @@ static void vmx_cpuid_intercept(
     unsigned int *ecx, unsigned int *edx)
 {
     unsigned int input = *eax;
-    unsigned int count = *ecx;
+    struct segment_register cs;
+    struct vcpu *v = current;
 
     hvm_cpuid(input, eax, ebx, ecx, edx);
 
     switch ( input )
     {
-    case 0x00000001:
-        /* Mask AMD-only features. */
-        *ecx &= ~(bitmaskof(X86_FEATURE_POPCNT));
-        break;
-
-    case 0x00000004:
-        cpuid_count(input, count, eax, ebx, ecx, edx);
-        *eax &= 0x3FFF; /* one core */
-        break;
-
-    case 0x00000006:
-    case 0x00000009:
-        *eax = *ebx = *ecx = *edx = 0;
-        break;
-
-    case 0x80000001:
-        /* Only a few features are advertised in Intel's 0x80000001. */
-        *ecx &= (bitmaskof(X86_FEATURE_LAHF_LM));
-        *edx &= (bitmaskof(X86_FEATURE_NX) |
-                 bitmaskof(X86_FEATURE_LM) |
-                 bitmaskof(X86_FEATURE_SYSCALL));
-        break;
+        case 0x80000001:
+            /* SYSCALL is visible iff running in long mode. */
+            hvm_get_segment_register(v, x86_seg_cs, &cs);
+            if ( cs.attr.fields.l )
+                *edx |= bitmaskof(X86_FEATURE_SYSCALL);
+            else
+                *edx &= ~(bitmaskof(X86_FEATURE_SYSCALL));
+            break;
     }
 
     HVMTRACE_3D(CPUID, current, input,
xen/include/asm-x86/domain.h +13 -0
diff -r 4e6577dec729 xen/include/asm-x86/domain.h
@@ -187,6 +187,9 @@ struct paging_vcpu {
     struct shadow_vcpu shadow;
 };
 
+#define MAX_CPUID_INPUT 40
+typedef xen_domctl_cpuid_t cpuid_input_t;
+
 struct p2m_domain;
 
 struct arch_domain
@@ -243,6 +246,8 @@ struct arch_domain
         RELMEM_done,
     } relmem;
     struct list_head relmem_list;
+
+    cpuid_input_t cpuids[MAX_CPUID_INPUT];
 } __cacheline_aligned;
 
 #ifdef CONFIG_X86_PAE
@@ -353,6 +358,14 @@ unsigned long pv_guest_cr4_fixup(unsigne
 #define real_cr4_to_pv_guest_cr4(c) \
     ((c) & ~(X86_CR4_PGE | X86_CR4_PSE))
 
+void domain_cpuid(struct domain *d,
+                  unsigned int  input,
+                  unsigned int  sub_input,
+                  unsigned int  *eax,
+                  unsigned int  *ebx,
+                  unsigned int  *ecx,
+                  unsigned int  *edx);
+
 #endif /* __ASM_DOMAIN_H__ */
 
 /*
xen/include/public/domctl.h +16 -0
diff -r 4e6577dec729 xen/include/public/domctl.h
@@ -571,6 +571,19 @@ typedef struct xen_domctl_set_target xen
 typedef struct xen_domctl_set_target xen_domctl_set_target_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_target_t);
 
+#if defined(__i386__) || defined(__x86_64__)
+# define XEN_CPUID_INPUT_UNUSED  0xFFFFFFFF
+# define XEN_DOMCTL_set_cpuid 49
+struct xen_domctl_cpuid {
+  unsigned int  input[2];
+  unsigned int  eax;
+  unsigned int  ebx;
+  unsigned int  ecx;
+  unsigned int  edx;
+};
+typedef struct xen_domctl_cpuid xen_domctl_cpuid_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_cpuid_t);
+#endif
 
 struct xen_domctl {
     uint32_t cmd;
@@ -609,6 +622,9 @@ struct xen_domctl {
         struct xen_domctl_ext_vcpucontext   ext_vcpucontext;
         struct xen_domctl_set_opt_feature   set_opt_feature;
         struct xen_domctl_set_target        set_target;
+#if defined(__i386__) || defined(__x86_64__)
+        struct xen_domctl_cpuid             cpuid;
+#endif
         uint8_t                             pad[128];
     } u;
 };

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

#1 lore raw
Quoted 3 lines · Jean Guyader

This patch is to configure the cpuid's replies for hvm guests. The cpuid's replies are now pre-calculated in libxc and given to the hypervisor via a new domctl.

You need to update the ChangeLog.

(Is the Xen API work dead? Every patch that adds new domain options only seems to modify .py config files)

john

#2 lore raw
Quoted 5 lines · John Levon
Quoted 3 lines

This patch is to configure the cpuid's replies for hvm guests. The cpuid's replies are now pre-calculated in libxc and given to the hypervisor via a new domctl.

You need to update the ChangeLog.

For the new domctl? I'll add something when I check it in.

Quoted 2 lines

(Is the Xen API work dead? Every patch that adds new domain options only seems to modify .py config files)

I think a lot of devs use the 'legacy' configuration methods exclusively.

-- Keir

#3 lore raw
Quoted 7 lines · Keir Fraser
Quoted 5 lines
Quoted 3 lines

This patch is to configure the cpuid's replies for hvm guests. The cpuid's replies are now pre-calculated in libxc and given to the hypervisor via a new domctl.

You need to update the ChangeLog.

For the new domctl? I'll add something when I check it in.

Yep, thanks.

regards
john