Configure hvm's cpuid
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -571,6 +571,19 @@ typedef struct xen_domctl_set_target xentypedef 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
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
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
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