[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [RFC PATCH 09/16] common: Introduce confidential computing infrastructure
Introduce a subsystem that is used for future confidential computing platforms. This subsystem manages and provides hooks for domain management and exposes various informations for toolstack (COCO platform, supported features, ...). Add a domain creation flag to build a confidential computing guest. Signed-off-by: Teddy Astie <teddy.astie@xxxxxxxxxx> --- xen/arch/x86/domain.c | 4 + xen/arch/x86/hvm/hvm.c | 10 ++- xen/common/Kconfig | 5 ++ xen/common/Makefile | 1 + xen/common/coco.c | 134 ++++++++++++++++++++++++++++++++++ xen/common/domain.c | 41 ++++++++++- xen/include/hypercall-defs.c | 2 + xen/include/public/domctl.h | 5 +- xen/include/public/hvm/coco.h | 65 +++++++++++++++++ xen/include/public/xen.h | 1 + xen/include/xen/coco.h | 88 ++++++++++++++++++++++ xen/include/xen/sched.h | 10 +++ 12 files changed, 363 insertions(+), 3 deletions(-) create mode 100644 xen/common/coco.c create mode 100644 xen/include/public/hvm/coco.h create mode 100644 xen/include/xen/coco.h diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index f197dad4c0..a5783154ad 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -12,6 +12,7 @@ */ #include <xen/acpi.h> +#include <xen/coco.h> #include <xen/compat.h> #include <xen/console.h> #include <xen/cpu.h> @@ -948,6 +949,9 @@ void arch_domain_destroy(struct domain *d) free_xenheap_page(d->shared_info); cleanup_domain_irq_mapping(d); + if ( is_coco_domain(d) ) + coco_domain_destroy(d); + psr_domain_free(d); } diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 625ae2098b..e1bcf8e086 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -15,6 +15,7 @@ #include <xen/sched.h> #include <xen/irq.h> #include <xen/softirq.h> +#include <xen/coco.h> #include <xen/domain.h> #include <xen/domain_page.h> #include <xen/hypercall.h> @@ -702,7 +703,11 @@ int hvm_domain_initialise(struct domain *d, if ( rc ) goto fail2; - rc = hvm_asid_alloc(&d->arch.hvm.asid); + if ( is_coco_domain(d) && d->coco_ops && d->coco_ops->asid_alloc ) + rc = d->coco_ops->asid_alloc(d, &d->arch.hvm.asid); + else + rc = hvm_asid_alloc(&d->arch.hvm.asid); + if ( rc ) goto fail2; @@ -710,6 +715,9 @@ int hvm_domain_initialise(struct domain *d, if ( rc != 0 ) goto fail2; + if ( is_coco_domain(d) ) + coco_domain_initialise(d); + return 0; fail2: diff --git a/xen/common/Kconfig b/xen/common/Kconfig index 6d43be2e6e..1ddb73e707 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -576,4 +576,9 @@ config BUDDY_ALLOCATOR_SIZE Amount of memory reserved for the buddy allocator to serve Xen heap, working alongside the colored one. +config COCO + bool "Enable COnfidential COmputing support for guests" if EXPERT + default n + help + Allows to run guests in private encrypted memory space. endmenu diff --git a/xen/common/Makefile b/xen/common/Makefile index 98f0873056..4409510fc0 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_GENERIC_BUG_FRAME) += bug.o obj-$(CONFIG_HYPFS_CONFIG) += config_data.o obj-$(CONFIG_CORE_PARKING) += core_parking.o obj-y += cpu.o +obj-$(CONFIG_COCO) += coco.o obj-$(CONFIG_DEBUG_TRACE) += debugtrace.o obj-$(CONFIG_HAS_DEVICE_TREE) += device.o obj-$(filter-out $(CONFIG_X86),$(CONFIG_ACPI)) += device.o diff --git a/xen/common/coco.c b/xen/common/coco.c new file mode 100644 index 0000000000..d9bd17628d --- /dev/null +++ b/xen/common/coco.c @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * General confidential computing functions. + */ + +#include <xen/coco.h> +#include <xen/errno.h> +#include <xen/domain.h> +#include <xen/domain_page.h> +#include <xen/guest_access.h> +#include <xen/hypercall.h> +#include <xen/sched.h> +#include <xen/sections.h> +#include <xen/types.h> + +#include <asm/p2m.h> + +#include <public/hvm/coco.h> + +static __ro_after_init struct coco_ops *coco_ops; +__read_mostly struct coco_platform_status platform_status; + +void __init coco_register_ops(struct coco_ops *ops) +{ + coco_ops = ops; +} + +int __init coco_init(void) +{ + int rc = 0; + + if ( coco_ops ) + printk("coco: Using '%s'\n", coco_ops->name); + else + { + printk("coco: No platform found\n"); + return 0; + } + + if ( coco_ops->init ) + { + rc = coco_ops->init(); + + if ( rc ) + { + printk("coco: Unable to initialize coco platform (%d)", rc); + goto err; + } + } + + rc = coco_ops->get_platform_status(&platform_status); + if ( rc ) + { + printk("coco: Unable to get platform status\n"); + goto err; + } + + return 0; + +err: + /* Disable confidential computing if initialization failed. */ + coco_ops = NULL; + return rc; +} + +void coco_set_domain_ops(struct domain *d) +{ + ASSERT(is_coco_domain(d)); + + d->coco_ops = coco_ops->get_domain_ops(d); +} + +int coco_prepare_initial_memory(struct domain *d, gfn_t gfn, size_t page_count) +{ + /* TODO: Check prepare_initial_memory constraints (no dangling mapping). */ + + if ( d->coco_ops->prepare_initial_mem ) + return d->coco_ops->prepare_initial_mem(d, gfn, page_count); + + return 0; +} + +long coco_op_prepare_initial_mem(struct coco_prepare_initial_mem arg) +{ + long rc = 0; + struct domain *d = get_domain_by_id(arg.domid); + + if ( !d ) + return -ENOENT; + + if ( !is_coco_domain(d) ) + { + rc = -EOPNOTSUPP; + goto out; + } + + rc = coco_prepare_initial_memory(d, arg.gfn, arg.count); + +out: + put_domain(d); + return rc; +} + +long do_coco_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) +{ + if ( !is_hardware_domain(current->domain) ) + return -EPERM; + + switch (cmd) + { + case XEN_COCO_platform_status: + { + if ( copy_to_guest(arg, &platform_status, 1) ) + return -EFAULT; + + return 0; + } + + case XEN_COCO_prepare_initial_mem: + { + struct coco_prepare_initial_mem prepare_initial_mem; + + if ( copy_from_guest(&prepare_initial_mem, arg, 1) ) + return -EFAULT; + + return coco_op_prepare_initial_mem(prepare_initial_mem); + } + + default: + return -ENOSYS; + } +} + +__initcall(coco_init); \ No newline at end of file diff --git a/xen/common/domain.c b/xen/common/domain.c index abf1969e60..c29d6efd29 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -4,6 +4,7 @@ * Generic domain-handling functions. */ +#include <xen/coco.h> #include <xen/compat.h> #include <xen/init.h> #include <xen/lib.h> @@ -716,17 +717,51 @@ static int sanitise_domain_config(struct xen_domctl_createdomain *config) bool hap = config->flags & XEN_DOMCTL_CDF_hap; bool iommu = config->flags & XEN_DOMCTL_CDF_iommu; bool vpmu = config->flags & XEN_DOMCTL_CDF_vpmu; + bool coco = config->flags & XEN_DOMCTL_CDF_coco; if ( config->flags & ~(XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap | XEN_DOMCTL_CDF_s3_integrity | XEN_DOMCTL_CDF_oos_off | XEN_DOMCTL_CDF_xs_domain | XEN_DOMCTL_CDF_iommu | - XEN_DOMCTL_CDF_nested_virt | XEN_DOMCTL_CDF_vpmu) ) + XEN_DOMCTL_CDF_nested_virt | XEN_DOMCTL_CDF_vpmu | XEN_DOMCTL_CDF_coco) ) { dprintk(XENLOG_INFO, "Unknown CDF flags %#x\n", config->flags); return -EINVAL; } + if ( coco ) + { + if ( !IS_ENABLED(CONFIG_COCO) ) + { + dprintk(XENLOG_INFO, "COCO support is compiled out\n"); + return -EINVAL; + } + + if ( !coco_is_supported() ) + { + dprintk(XENLOG_INFO, "COCO is not available\n"); + return -EINVAL; + } + + if ( !hvm ) + { + dprintk(XENLOG_INFO, "COCO requested for non-HVM guest\n"); + return -EINVAL; + } + + if ( !hap ) + { + dprintk(XENLOG_INFO, "COCO cannot work without HAP\n"); + return -EINVAL; + } + + if ( config->flags & XEN_DOMCTL_CDF_nested_virt ) + { + dprintk(XENLOG_INFO, "Nested virtualization isn't supported with COCO\n"); + return -EINVAL; + } + } + if ( config->grant_opts & ~XEN_DOMCTL_GRANT_version_mask ) { dprintk(XENLOG_INFO, "Unknown grant options %#x\n", config->grant_opts); @@ -836,6 +871,9 @@ struct domain *domain_create(domid_t domid, /* Holding CDF_* internal flags. */ d->cdf = flags; + if ( is_coco_domain(d) ) + coco_set_domain_ops(d); + TRACE_TIME(TRC_DOM0_DOM_ADD, d->domain_id); lock_profile_register_struct(LOCKPROF_TYPE_PERDOM, d, domid); @@ -1617,6 +1655,7 @@ int domain_unpause_by_systemcontroller(struct domain *d) { d->creation_finished = true; arch_domain_creation_finished(d); + coco_domain_creation_finished(d); /* TODO: or before arch_* ? */ } domain_unpause(d); diff --git a/xen/include/hypercall-defs.c b/xen/include/hypercall-defs.c index 7720a29ade..6c01a9e395 100644 --- a/xen/include/hypercall-defs.c +++ b/xen/include/hypercall-defs.c @@ -209,6 +209,7 @@ hypfs_op(unsigned int cmd, const char *arg1, unsigned long arg2, void *arg3, uns #ifdef CONFIG_X86 xenpmu_op(unsigned int op, xen_pmu_params_t *arg) #endif +coco_op(unsigned int cmd, void *arg) #ifdef CONFIG_PV caller: pv64 @@ -295,5 +296,6 @@ mca do do - - - #ifndef CONFIG_PV_SHIM_EXCLUSIVE paging_domctl_cont do do do do - #endif +coco_op do do do do do #endif /* !CPPCHECK */ diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 5b2063eed9..f4f69556b6 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -67,8 +67,11 @@ struct xen_domctl_createdomain { /* Should we expose the vPMU to the guest? */ #define XEN_DOMCTL_CDF_vpmu (1U << 7) +#define _XEN_DOMCTL_CDF_coco 8 +#define XEN_DOMCTL_CDF_coco (1U << _XEN_DOMCTL_CDF_coco) + /* Max XEN_DOMCTL_CDF_* constant. Used for ABI checking. */ -#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_vpmu +#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_coco uint32_t flags; diff --git a/xen/include/public/hvm/coco.h b/xen/include/public/hvm/coco.h new file mode 100644 index 0000000000..2e23d91e12 --- /dev/null +++ b/xen/include/public/hvm/coco.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __XEN_PUBLIC_HVM_COCO_H__ +#define __XEN_PUBLIC_HVM_COCO_H__ + +#include "../xen.h" + +#define XEN_COCO_platform_status 0 + +/** + * XEN_COCO_platform_status: Get the status of confidential computing platform. + * + * Query informations regarding the current confidential computing platform. + * + * Confidential computing is supposed working as long as COCO_STATUS_FLAG_SUPPORTED bit + * is set, and additionally security-supported only if COCO_STATUS_FLAG_UNSAFE bit + * is cleared. + * + * If COCO_PLATFORM_FLAG_UNSAFE is set but COCO_PLATFORM_FLAG_SUPPORTED is not, + * then confidential computing is explicitly present but intentionally disabled + * or forbidden by policy. + */ +struct coco_platform_status { +#define COCO_PLATFORM_none 0 /* None */ +#define COCO_PLATFORM_amd_sev 1 /* AMD Secure Encrypted Virtualization */ +#define COCO_PLATFORM_intel_tdx 2 /* Intel Trust Domain Extensions */ +#define COCO_PLATFORM_arm_rme 3 /* ARM Realm Management Extension */ + uint32_t platform; /* OUT */ + +#define COCO_PLATFORM_FLAG_sev_es (1 << 0) /* AMD SEV Encrypted State */ +#define COCO_PLATFORM_FLAG_sev_snp (1 << 1) /* AMD SEV Secure Nested Paging */ +#define COCO_PLATFORM_FLAG_sev_tio (1 << 2) /* AMD SEV Trusted I/O */ + uint32_t platform_flags; /* OUT */ + +#define COCO_STATUS_FLAG_supported (1 << 0) /* Confidential computing is supported and usable */ +#define COCO_STATUS_FLAG_unsafe (1 << 1) /* Confidential computing is unsafe (e.g debug mode) */ + uint32_t flags; /* OUT */ + uint32_t features; /* OUT */ + + uint32_t version_major; /* OUT */ + uint32_t version_minor; /* OUT */ +}; +typedef struct coco_platform_status coco_platform_status_t; +DEFINE_XEN_GUEST_HANDLE(coco_platform_status_t); + +#define XEN_COCO_prepare_initial_mem 1 + +/** + * XEN_COCO_prepare_initial_mem: Prepare early memory pages of a guest + * + * During guest construction, the confidential computing platform may require memory + * to be prepared (e.g., encrypted) before the guest is started. + * + * After preparation, any further access to these pages is invalid, as they may be + * encrypted, sealed, or tracked by the platform. + */ +struct coco_prepare_initial_mem { + domid_t domid; /* IN */ + uint16_t _rsvd[3]; /* ZERO */ + uint64_t gfn; /* IN */ + uint64_t count; /* IN */ +}; +typedef struct coco_prepare_initial_mem coco_prepare_initial_mem_t; +DEFINE_XEN_GUEST_HANDLE(coco_prepare_initial_mem_t); + +#endif /* __XEN_PUBLIC_HVM_COCO_H__ */ diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h index 82b9c05a76..e656d6f617 100644 --- a/xen/include/public/xen.h +++ b/xen/include/public/xen.h @@ -118,6 +118,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_ulong_t); #define __HYPERVISOR_xenpmu_op 40 #define __HYPERVISOR_dm_op 41 #define __HYPERVISOR_hypfs_op 42 +#define __HYPERVISOR_coco_op 43 /* Architecture-specific hypercall definitions. */ #define __HYPERVISOR_arch_0 48 diff --git a/xen/include/xen/coco.h b/xen/include/xen/coco.h new file mode 100644 index 0000000000..2ae43995ec --- /dev/null +++ b/xen/include/xen/coco.h @@ -0,0 +1,88 @@ +#ifndef _XEN_COCO_H +#define _XEN_COCO_H + +#include <asm/nospec.h> + +#include <xen/stdint.h> +#include <xen/sched.h> + +#include <public/hvm/coco.h> + +extern __read_mostly struct coco_platform_status platform_status; + +struct coco_domain_ops { + int (*prepare_initial_mem)(struct domain *d, gfn_t gfn, size_t page_count); + /* domain_creation_finished, ... */ + + /* HVM domain hooks */ + int (*domain_initialise)(struct domain *d); + int (*domain_creation_finished)(struct domain *d); + void (*domain_destroy)(struct domain *d); + +#ifdef CONFIG_X86 + /* COCO-specific ASID allocation logic */ + int (*asid_alloc)(struct domain *d, struct hvm_asid *asid); +#endif +}; + +struct coco_ops { + const char *name; + + int (*init)(void); + int (*get_platform_status)(coco_platform_status_t *status); + struct coco_domain_ops *(*get_domain_ops)(struct domain *d); +}; + +void __init coco_register_ops(struct coco_ops *ops); +int __init coco_init(void); +void coco_set_domain_ops(struct domain *d); + +#ifdef CONFIG_COCO +static inline bool coco_is_supported(void) +{ + return evaluate_nospec(platform_status.flags & COCO_STATUS_FLAG_supported); +} + +static inline int coco_domain_initialise(struct domain *d) +{ + if ( d->coco_ops && d->coco_ops->domain_initialise ) + return d->coco_ops->domain_initialise(d); + + return 0; +} + +static inline int coco_domain_creation_finished(struct domain *d) +{ + if ( d->coco_ops && d->coco_ops->domain_creation_finished ) + return d->coco_ops->domain_creation_finished(d); + + return 0; +} + +static inline void coco_domain_destroy(struct domain *d) +{ + if ( d->coco_ops && d->coco_ops->domain_destroy ) + d->coco_ops->domain_destroy(d); +} +#else +static inline bool coco_is_supported(void) +{ + return false; +} + +static inline int coco_domain_initialise(struct domain *d) +{ + return 0; +} + +static inline int coco_domain_creation_finished(struct domain *d) +{ + return 0; +} + +static inline void coco_domain_destroy(struct domain *d) +{ +} +#endif + +#endif /* _XEN_COCO_H */ \ No newline at end of file diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index f2f5a98534..c57bedc30a 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -630,6 +630,10 @@ struct domain struct argo_domain *argo; #endif +#ifdef CONFIG_COCO + struct coco_domain_ops *coco_ops; +#endif + /* * Continuation information for domain_teardown(). All fields entirely * private. @@ -1198,6 +1202,12 @@ static always_inline bool is_hvm_vcpu(const struct vcpu *v) return is_hvm_domain(v->domain); } +static always_inline bool is_coco_domain(const struct domain *d) +{ + return IS_ENABLED(CONFIG_COCO) && + evaluate_nospec(d->options & XEN_DOMCTL_CDF_coco); +} + static always_inline bool hap_enabled(const struct domain *d) { /* sanitise_domain_config() rejects HAP && !HVM */ -- 2.49.0 Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |