@@ -1783,6 +1783,15 @@ int xc_domain_debug_control(xc_interface *xch,
uint32_t vcpu);
#if defined(__i386__) || defined(__x86_64__)
+typedef struct xc_cpuid_policy_build_info_sgx {
+ uint64_t epc_base;
+ uint64_t epc_size;
+} xc_cpuid_policy_build_info_sgx_t;
+
+typedef struct xc_cpuid_policy_build_info {
+ xc_cpuid_policy_build_info_sgx_t sgx;
+} xc_cpuid_policy_build_info_t;
+
int xc_cpuid_check(xc_interface *xch,
const unsigned int *input,
const char **config,
@@ -1794,6 +1803,7 @@ int xc_cpuid_set(xc_interface *xch,
char **config_transformed);
int xc_cpuid_apply_policy(xc_interface *xch,
domid_t domid,
+ xc_cpuid_policy_build_info_t *b_info,
uint32_t *featureset,
unsigned int nr_features);
void xc_cpuid_to_str(const unsigned int *regs,
@@ -38,7 +38,7 @@ enum {
#define clear_feature(idx, dst) ((dst) &= ~bitmaskof(idx))
#define set_feature(idx, dst) ((dst) |= bitmaskof(idx))
-#define DEF_MAX_BASE 0x0000000du
+#define DEF_MAX_BASE 0x00000012u
#define DEF_MAX_INTELEXT 0x80000008u
#define DEF_MAX_AMDEXT 0x8000001cu
@@ -178,6 +178,8 @@ struct cpuid_domain_info
/* HVM-only information. */
bool pae;
bool nestedhvm;
+
+ xc_cpuid_policy_build_info_t *b_info;
};
static void cpuid(const unsigned int *input, unsigned int *regs)
@@ -369,6 +371,12 @@ static void intel_xc_cpuid_policy(xc_interface *xch,
const struct cpuid_domain_info *info,
const unsigned int *input, unsigned int *regs)
{
+ xc_cpuid_policy_build_info_t *b_info = info->b_info;
+ xc_cpuid_policy_build_info_sgx_t *sgx = NULL;
+
+ if ( b_info )
+ sgx = &b_info->sgx;
+
switch ( input[0] )
{
case 0x00000004:
@@ -381,6 +389,30 @@ static void intel_xc_cpuid_policy(xc_interface *xch,
regs[3] &= 0x3ffu;
break;
+ case 0x00000012:
+ if ( !sgx ) {
+ regs[0] = regs[1] = regs[2] = regs[3] = 0;
+ break;
+ }
+
+ if ( !sgx->epc_base || !sgx->epc_size ) {
+ regs[0] = regs[1] = regs[2] = regs[3] = 0;
+ break;
+ }
+
+ if ( input[1] == 2 ) {
+ /*
+ * FIX EPC base and size for SGX CPUID leaf 2. Xen hypervisor is
+ * depending on XEN_DOMCTL_set_cpuid to know domain's EPC base
+ * and size.
+ */
+ regs[0] = (uint32_t)(sgx->epc_base & 0xfffff000) | 0x1;
+ regs[1] = (uint32_t)(sgx->epc_base >> 32);
+ regs[2] = (uint32_t)(sgx->epc_size & 0xfffff000) | 0x1;
+ regs[3] = (uint32_t)(sgx->epc_size >> 32);
+ }
+ break;
+
case 0x80000000:
if ( regs[0] > DEF_MAX_INTELEXT )
regs[0] = DEF_MAX_INTELEXT;
@@ -444,6 +476,10 @@ static void xc_cpuid_hvm_policy(xc_interface *xch,
regs[1] = regs[2] = regs[3] = 0;
break;
+ case 0x00000012:
+ /* Intel SGX. Passthrough to Intel function */
+ break;
+
case 0x80000000:
/* Passthrough to cpu vendor specific functions */
break;
@@ -649,12 +685,13 @@ void xc_cpuid_to_str(const unsigned int *regs, char **strs)
}
}
-static void sanitise_featureset(struct cpuid_domain_info *info)
+static int sanitise_featureset(struct cpuid_domain_info *info)
{
const uint32_t fs_size = xc_get_cpu_featureset_size();
uint32_t disabled_features[fs_size];
static const uint32_t deep_features[] = INIT_DEEP_FEATURES;
unsigned int i, b;
+ xc_cpuid_policy_build_info_t *b_info = info->b_info;
if ( info->hvm )
{
@@ -707,9 +744,19 @@ static void sanitise_featureset(struct cpuid_domain_info *info)
disabled_features[i] &= ~dfs[i];
}
}
+
+ /* Cannot support 'epc' parameter if SGX is unavailable */
+ if ( b_info && b_info->sgx.epc_base && b_info->sgx.epc_size )
+ if (!test_bit(X86_FEATURE_SGX, info->featureset)) {
+ printf("Xen hypervisor doesn't support SGX.\n");
+ return -EFAULT;
+ }
+
+ return 0;
}
int xc_cpuid_apply_policy(xc_interface *xch, domid_t domid,
+ xc_cpuid_policy_build_info_t *b_info,
uint32_t *featureset,
unsigned int nr_features)
{
@@ -722,6 +769,8 @@ int xc_cpuid_apply_policy(xc_interface *xch, domid_t domid,
if ( rc )
goto out;
+ info.b_info = b_info;
+
cpuid(input, regs);
base_max = (regs[0] <= DEF_MAX_BASE) ? regs[0] : DEF_MAX_BASE;
input[0] = 0x80000000;
@@ -732,7 +781,9 @@ int xc_cpuid_apply_policy(xc_interface *xch, domid_t domid,
else
ext_max = (regs[0] <= DEF_MAX_INTELEXT) ? regs[0] : DEF_MAX_INTELEXT;
- sanitise_featureset(&info);
+ rc = sanitise_featureset(&info);
+ if ( rc )
+ goto out;
input[0] = 0;
input[1] = XEN_CPUID_INPUT_UNUSED;
@@ -757,12 +808,21 @@ int xc_cpuid_apply_policy(xc_interface *xch, domid_t domid,
continue;
}
+ /* Intel SGX */
+ if ( input[0] == 0x12 )
+ {
+ input[1]++;
+ /* Intel SGX has 3 leaves */
+ if ( input[1] < 3 )
+ continue;
+ }
+
input[0]++;
if ( !(input[0] & 0x80000000u) && (input[0] > base_max ) )
input[0] = 0x80000000u;
input[1] = XEN_CPUID_INPUT_UNUSED;
- if ( (input[0] == 4) || (input[0] == 7) )
+ if ( (input[0] == 4) || (input[0] == 7) || input[0] == 0x12)
input[1] = 0;
else if ( input[0] == 0xd )
input[1] = 1; /* Xen automatically calculates almost everything. */
@@ -1949,7 +1949,8 @@ libxl_device_pci *libxl_device_pci_assignable_list(libxl_ctx *ctx, int *num);
int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str);
int libxl_cpuid_parse_config_xend(libxl_cpuid_policy_list *cpuid,
const char* str);
-void libxl_cpuid_apply_policy(libxl_ctx *ctx, uint32_t domid);
+int libxl_cpuid_apply_policy(libxl_ctx *ctx, uint32_t domid,
+ libxl_domain_build_info *info);
void libxl_cpuid_set(libxl_ctx *ctx, uint32_t domid,
libxl_cpuid_policy_list cpuid);
@@ -332,9 +332,20 @@ int libxl_cpuid_parse_config_xend(libxl_cpuid_policy_list *cpuid,
return 0;
}
-void libxl_cpuid_apply_policy(libxl_ctx *ctx, uint32_t domid)
+int libxl_cpuid_apply_policy(libxl_ctx *ctx, uint32_t domid,
+ libxl_domain_build_info *info)
{
- xc_cpuid_apply_policy(ctx->xch, domid, NULL, 0);
+ xc_cpuid_policy_build_info_t cpuid_binfo;
+
+ memset(&cpuid_binfo, 0, sizeof (xc_cpuid_policy_build_info_t));
+
+ /* Currently only Intel SGX needs info when applying CPUID policy */
+ if (info->type == LIBXL_DOMAIN_TYPE_HVM) {
+ cpuid_binfo.sgx.epc_base = info->u.hvm.sgx.epcbase;
+ cpuid_binfo.sgx.epc_size = (info->u.hvm.sgx.epckb << 10);
+ }
+
+ return xc_cpuid_apply_policy(ctx->xch, domid, &cpuid_binfo, NULL, 0);
}
void libxl_cpuid_set(libxl_ctx *ctx, uint32_t domid,
@@ -535,7 +535,11 @@ int libxl__build_post(libxl__gc *gc, uint32_t domid,
return ERROR_FAIL;
}
- libxl_cpuid_apply_policy(ctx, domid);
+ rc = libxl_cpuid_apply_policy(ctx, domid, info);
+ if (rc) {
+ LOG(ERROR, "Failed to apply CPUID policy (%d)", rc);
+ return ERROR_FAIL;
+ }
if (info->cpuid != NULL)
libxl_cpuid_set(ctx, domid, info->cpuid);
@@ -34,8 +34,10 @@ int libxl_cpuid_parse_config_xend(libxl_cpuid_policy_list *cpuid,
return 0;
}
-void libxl_cpuid_apply_policy(libxl_ctx *ctx, uint32_t domid)
+int libxl_cpuid_apply_policy(libxl_ctx *ctx, uint32_t domid,
+ libxl_domain_build_info *info)
{
+ return 0;
}
void libxl_cpuid_set(libxl_ctx *ctx, uint32_t domid,
@@ -796,7 +796,16 @@ CAMLprim value stub_xc_domain_cpuid_apply_policy(value xch, value domid)
#if defined(__i386__) || defined(__x86_64__)
int r;
- r = xc_cpuid_apply_policy(_H(xch), _D(domid), NULL, 0);
+ /*
+ * FIXME:
+ *
+ * Don't support passing SGX info to xc_cpuid_apply_policy here. To be
+ * honest I don't know the purpose of this CAML function, so I don't
+ * know whether we need to allow *caller* of this function to pass SGX
+ * info. As EPC base is calculated internally by toolstack so I think
+ * it is also impossible to pass EPC base from *user*.
+ */
+ r = xc_cpuid_apply_policy(_H(xch), _D(domid), NULL, NULL, 0);
if (r < 0)
failwith_xc(_H(xch));
#else
@@ -742,7 +742,16 @@ static PyObject *pyxc_dom_set_policy_cpuid(XcObject *self,
if ( !PyArg_ParseTuple(args, "i", &domid) )
return NULL;
- if ( xc_cpuid_apply_policy(self->xc_handle, domid, NULL, 0) )
+ /*
+ * FIXME:
+ *
+ * Don't support passing SGX info to xc_cpuid_apply_policy here. To be
+ * honest I don't know the purpose of this python function, so I don't
+ * know whether we need to allow *caller* of this function to pass SGX
+ * info. As EPC base is calculated internally by toolstack so I think
+ * it is also impossible to pass EPC base from *user*.
+ */
+ if ( xc_cpuid_apply_policy(self->xc_handle, domid, NULL, NULL, 0) )
return pyxc_error_to_exception(self->xc_handle);
Py_INCREF(zero);
In libxc, a new structure 'xc_cpuid_policy_build_info_t' is added to carry domain's EPC base and size info from libxl. libxl_cpuid_apply_policy is also changed to take 'libxl_domain_build_info_t' as parameter, where domain's EPC base and size can be got and passed to xc_cpuid_apply_policy. xc_cpuid_apply_policy is extended to support SGX CPUID. If hypervisor doesn't report SGX feature in host type cpufeatureset, then using 'epc' parameter results in domain creation failure as SGX cannot be supported. Signed-off-by: Kai Huang <kai.huang@linux.intel.com> --- tools/libxc/include/xenctrl.h | 10 ++++++ tools/libxc/xc_cpuid_x86.c | 68 ++++++++++++++++++++++++++++++++++--- tools/libxl/libxl.h | 3 +- tools/libxl/libxl_cpuid.c | 15 ++++++-- tools/libxl/libxl_dom.c | 6 +++- tools/libxl/libxl_nocpuid.c | 4 ++- tools/ocaml/libs/xc/xenctrl_stubs.c | 11 +++++- tools/python/xen/lowlevel/xc/xc.c | 11 +++++- 8 files changed, 117 insertions(+), 11 deletions(-)