From 56918a126ae25383cb0c2c74a6f0f784a6d59ac1 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 19 Jul 2021 19:21:04 +0800 Subject: memory: Add RAM_PROTECTED flag to skip IOMMU mappings Add a new RAMBlock flag to denote "protected" memory, i.e. memory that looks and acts like RAM but is inaccessible via normal mechanisms, including DMA. Use the flag to skip protected memory regions when mapping RAM for DMA in VFIO. Signed-off-by: Sean Christopherson Signed-off-by: Yang Zhong Signed-off-by: Paolo Bonzini --- include/exec/memory.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/exec/memory.h b/include/exec/memory.h index c3d417d317..9446874d21 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -190,6 +190,9 @@ typedef struct IOMMUTLBEvent { */ #define RAM_NORESERVE (1 << 7) +/* RAM that isn't accessible through normal means. */ +#define RAM_PROTECTED (1 << 8) + static inline void iommu_notifier_init(IOMMUNotifier *n, IOMMUNotify fn, IOMMUNotifierFlag flags, hwaddr start, hwaddr end, @@ -1267,7 +1270,7 @@ void memory_region_init_ram_from_file(MemoryRegion *mr, * @name: the name of the region. * @size: size of the region. * @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_PMEM, - * RAM_NORESERVE. + * RAM_NORESERVE, RAM_PROTECTED. * @fd: the fd to mmap. * @offset: offset within the file referenced by fd * @errp: pointer to Error*, to store an error if it happens. @@ -1568,6 +1571,16 @@ static inline bool memory_region_is_romd(MemoryRegion *mr) return mr->rom_device && mr->romd_mode; } +/** + * memory_region_is_protected: check whether a memory region is protected + * + * Returns %true if a memory region is protected RAM and cannot be accessed + * via standard mechanisms, e.g. DMA. + * + * @mr: the memory region being queried + */ +bool memory_region_is_protected(MemoryRegion *mr); + /** * memory_region_get_iommu: check whether a memory region is an iommu * -- cgit v1.2.3 From c6c023200045fc9d61574cb157d368707e18efd5 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 19 Jul 2021 19:21:05 +0800 Subject: hostmem: Add hostmem-epc as a backend for SGX EPC EPC (Enclave Page Cahe) is a specialized type of memory used by Intel SGX (Software Guard Extensions). The SDM desribes EPC as: The Enclave Page Cache (EPC) is the secure storage used to store enclave pages when they are a part of an executing enclave. For an EPC page, hardware performs additional access control checks to restrict access to the page. After the current page access checks and translations are performed, the hardware checks that the EPC page is accessible to the program currently executing. Generally an EPC page is only accessed by the owner of the executing enclave or an instruction which is setting up an EPC page. Because of its unique requirements, Linux manages EPC separately from normal memory. Similar to memfd, the device /dev/sgx_vepc can be opened to obtain a file descriptor which can in turn be used to mmap() EPC memory. Signed-off-by: Sean Christopherson Signed-off-by: Yang Zhong Message-Id: <20210719112136.57018-3-yang.zhong@intel.com> Signed-off-by: Paolo Bonzini --- include/hw/i386/hostmem-epc.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 include/hw/i386/hostmem-epc.h (limited to 'include') diff --git a/include/hw/i386/hostmem-epc.h b/include/hw/i386/hostmem-epc.h new file mode 100644 index 0000000000..846c726085 --- /dev/null +++ b/include/hw/i386/hostmem-epc.h @@ -0,0 +1,28 @@ +/* + * SGX EPC backend + * + * Copyright (C) 2019 Intel Corporation + * + * Authors: + * Sean Christopherson + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef QEMU_HOSTMEM_EPC_H +#define QEMU_HOSTMEM_EPC_H + +#include "sysemu/hostmem.h" + +#define TYPE_MEMORY_BACKEND_EPC "memory-backend-epc" + +#define MEMORY_BACKEND_EPC(obj) \ + OBJECT_CHECK(HostMemoryBackendEpc, (obj), TYPE_MEMORY_BACKEND_EPC) + +typedef struct HostMemoryBackendEpc HostMemoryBackendEpc; + +struct HostMemoryBackendEpc { + HostMemoryBackend parent_obj; +}; + +#endif -- cgit v1.2.3 From 80509c5557a152f876aec524e8136f309583b2cd Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 19 Jul 2021 19:21:07 +0800 Subject: i386: Add 'sgx-epc' device to expose EPC sections to guest SGX EPC is enumerated through CPUID, i.e. EPC "devices" need to be realized prior to realizing the vCPUs themselves, which occurs long before generic devices are parsed and realized. Because of this, do not allow 'sgx-epc' devices to be instantiated after vCPUS have been created. The 'sgx-epc' device is essentially a placholder at this time, it will be fully implemented in a future patch along with a dedicated command to create 'sgx-epc' devices. Signed-off-by: Sean Christopherson Signed-off-by: Yang Zhong Message-Id: <20210719112136.57018-5-yang.zhong@intel.com> Signed-off-by: Paolo Bonzini --- include/hw/i386/sgx-epc.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 include/hw/i386/sgx-epc.h (limited to 'include') diff --git a/include/hw/i386/sgx-epc.h b/include/hw/i386/sgx-epc.h new file mode 100644 index 0000000000..cf3ed5c0cd --- /dev/null +++ b/include/hw/i386/sgx-epc.h @@ -0,0 +1,44 @@ +/* + * SGX EPC device + * + * Copyright (C) 2019 Intel Corporation + * + * Authors: + * Sean Christopherson + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef QEMU_SGX_EPC_H +#define QEMU_SGX_EPC_H + +#include "hw/i386/hostmem-epc.h" + +#define TYPE_SGX_EPC "sgx-epc" +#define SGX_EPC(obj) \ + OBJECT_CHECK(SGXEPCDevice, (obj), TYPE_SGX_EPC) +#define SGX_EPC_CLASS(oc) \ + OBJECT_CLASS_CHECK(SGXEPCDeviceClass, (oc), TYPE_SGX_EPC) +#define SGX_EPC_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SGXEPCDeviceClass, (obj), TYPE_SGX_EPC) + +#define SGX_EPC_ADDR_PROP "addr" +#define SGX_EPC_SIZE_PROP "size" +#define SGX_EPC_MEMDEV_PROP "memdev" + +/** + * SGXEPCDevice: + * @addr: starting guest physical address, where @SGXEPCDevice is mapped. + * Default value: 0, means that address is auto-allocated. + * @hostmem: host memory backend providing memory for @SGXEPCDevice + */ +typedef struct SGXEPCDevice { + /* private */ + DeviceState parent_obj; + + /* public */ + uint64_t addr; + HostMemoryBackendEpc *hostmem; +} SGXEPCDevice; + +#endif -- cgit v1.2.3 From dfce81f1b931352af0fcfe966c115a09646bd15a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 28 Sep 2021 10:40:58 +0200 Subject: vl: Add sgx compound properties to expose SGX EPC sections to guest Because SGX EPC is enumerated through CPUID, EPC "devices" need to be realized prior to realizing the vCPUs themselves, i.e. long before generic devices are parsed and realized. From a virtualization perspective, the CPUID aspect also means that EPC sections cannot be hotplugged without paravirtualizing the guest kernel (hardware does not support hotplugging as EPC sections must be locked down during pre-boot to provide EPC's security properties). So even though EPC sections could be realized through the generic -devices command, they need to be created much earlier for them to actually be usable by the guest. Place all EPC sections in a contiguous block, somewhat arbitrarily starting after RAM above 4g. Ensuring EPC is in a contiguous region simplifies calculations, e.g. device memory base, PCI hole, etc..., allows dynamic calculation of the total EPC size, e.g. exposing EPC to guests does not require -maxmem, and last but not least allows all of EPC to be enumerated in a single ACPI entry, which is expected by some kernels, e.g. Windows 7 and 8. The new compound properties command for sgx like below: ...... -object memory-backend-epc,id=mem1,size=28M,prealloc=on \ -object memory-backend-epc,id=mem2,size=10M \ -M sgx-epc.0.memdev=mem1,sgx-epc.1.memdev=mem2 Signed-off-by: Sean Christopherson Signed-off-by: Yang Zhong Message-Id: <20210719112136.57018-6-yang.zhong@intel.com> Signed-off-by: Paolo Bonzini --- include/hw/i386/pc.h | 3 +++ include/hw/i386/sgx-epc.h | 14 ++++++++++++++ include/hw/i386/x86.h | 1 + 3 files changed, 18 insertions(+) (limited to 'include') diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 4d2e35a152..668e48be8a 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -12,6 +12,7 @@ #include "hw/acpi/acpi_dev_interface.h" #include "hw/hotplug.h" #include "qom/object.h" +#include "hw/i386/sgx-epc.h" #define HPET_INTCAP "hpet-intcap" @@ -49,6 +50,8 @@ typedef struct PCMachineState { /* ACPI Memory hotplug IO base address */ hwaddr memhp_io_base; + + SGXEPCState sgx_epc; } PCMachineState; #define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device" diff --git a/include/hw/i386/sgx-epc.h b/include/hw/i386/sgx-epc.h index cf3ed5c0cd..83269972e0 100644 --- a/include/hw/i386/sgx-epc.h +++ b/include/hw/i386/sgx-epc.h @@ -41,4 +41,18 @@ typedef struct SGXEPCDevice { HostMemoryBackendEpc *hostmem; } SGXEPCDevice; +/* + * @base: address in guest physical address space where EPC regions start + * @mr: address space container for memory devices + */ +typedef struct SGXEPCState { + uint64_t base; + uint64_t size; + + MemoryRegion mr; + + struct SGXEPCDevice **sections; + int nr_sections; +} SGXEPCState; + #endif diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h index 6e9244a82c..23267a3674 100644 --- a/include/hw/i386/x86.h +++ b/include/hw/i386/x86.h @@ -62,6 +62,7 @@ struct X86MachineState { unsigned pci_irq_mask; unsigned apic_id_limit; uint16_t boot_cpus; + SgxEPCList *sgx_epc_list; OnOffAuto smm; OnOffAuto acpi; -- cgit v1.2.3 From 1dec2e1f19fdb39a0340356ec2d77233837b3d68 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 19 Jul 2021 19:21:15 +0800 Subject: i386: Update SGX CPUID info according to hardware/KVM/user input Expose SGX to the guest if and only if KVM is enabled and supports virtualization of SGX. While the majority of ENCLS can be emulated to some degree, because SGX uses a hardware-based root of trust, the attestation aspects of SGX cannot be emulated in software, i.e. ultimately emulation will fail as software cannot generate a valid quote/report. The complexity of partially emulating SGX in Qemu far outweighs the value added, e.g. an SGX specific simulator for userspace applications can emulate SGX for development and testing purposes. Note, access to the PROVISIONKEY is not yet advertised to the guest as KVM blocks access to the PROVISIONKEY by default and requires userspace to provide additional credentials (via ioctl()) to expose PROVISIONKEY. Signed-off-by: Sean Christopherson Signed-off-by: Yang Zhong Message-Id: <20210719112136.57018-13-yang.zhong@intel.com> Signed-off-by: Paolo Bonzini --- include/hw/i386/pc.h | 3 +++ include/hw/i386/sgx-epc.h | 2 ++ 2 files changed, 5 insertions(+) (limited to 'include') diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 668e48be8a..5748d7c55f 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -195,6 +195,9 @@ void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size); void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, const CPUArchIdList *apic_ids, GArray *entry); +/* sgx.c */ +void pc_machine_init_sgx_epc(PCMachineState *pcms); + extern GlobalProperty pc_compat_6_1[]; extern const size_t pc_compat_6_1_len; diff --git a/include/hw/i386/sgx-epc.h b/include/hw/i386/sgx-epc.h index 83269972e0..75b19f464c 100644 --- a/include/hw/i386/sgx-epc.h +++ b/include/hw/i386/sgx-epc.h @@ -55,4 +55,6 @@ typedef struct SGXEPCState { int nr_sections; } SGXEPCState; +int sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size); + #endif -- cgit v1.2.3 From 0cf4ce00d2255ef48d560d36559e7a4cda41748b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 19 Jul 2021 19:21:20 +0800 Subject: hw/i386/pc: Account for SGX EPC sections when calculating device memory Add helpers to detect if SGX EPC exists above 4g, and if so, where SGX EPC above 4g ends. Use the helpers to adjust the device memory range if SGX EPC exists above 4g. For multiple virtual EPC sections, we just put them together physically contiguous for the simplicity because we don't support EPC NUMA affinity now. Once the SGX EPC NUMA support in the kernel SGX driver, we will support this in the future. Note that SGX EPC is currently hardcoded to reside above 4g. Signed-off-by: Sean Christopherson Signed-off-by: Yang Zhong Message-Id: <20210719112136.57018-18-yang.zhong@intel.com> Signed-off-by: Paolo Bonzini --- include/hw/i386/sgx-epc.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include') diff --git a/include/hw/i386/sgx-epc.h b/include/hw/i386/sgx-epc.h index 75b19f464c..65a68ca753 100644 --- a/include/hw/i386/sgx-epc.h +++ b/include/hw/i386/sgx-epc.h @@ -57,4 +57,11 @@ typedef struct SGXEPCState { int sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size); +static inline uint64_t sgx_epc_above_4g_end(SGXEPCState *sgx_epc) +{ + assert(sgx_epc != NULL && sgx_epc->base >= 0x100000000ULL); + + return sgx_epc->base + sgx_epc->size; +} + #endif -- cgit v1.2.3 From 57d874c4c7a0acbaa076a166e3da093b6edbdb0f Mon Sep 17 00:00:00 2001 From: Yang Zhong Date: Fri, 10 Sep 2021 18:22:56 +0800 Subject: target/i386: Add HMP and QMP interfaces for SGX The QMP and HMP interfaces can be used by monitor or QMP tools to retrieve the SGX information from VM side when SGX is enabled on Intel platform. Signed-off-by: Yang Zhong Message-Id: <20210910102258.46648-2-yang.zhong@intel.com> Signed-off-by: Paolo Bonzini --- include/hw/i386/sgx.h | 11 +++++++++++ include/monitor/hmp-target.h | 1 + 2 files changed, 12 insertions(+) create mode 100644 include/hw/i386/sgx.h (limited to 'include') diff --git a/include/hw/i386/sgx.h b/include/hw/i386/sgx.h new file mode 100644 index 0000000000..2bf90b3f4f --- /dev/null +++ b/include/hw/i386/sgx.h @@ -0,0 +1,11 @@ +#ifndef QEMU_SGX_H +#define QEMU_SGX_H + +#include "qom/object.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qapi/qapi-types-misc-target.h" + +SGXInfo *sgx_get_info(Error **errp); + +#endif diff --git a/include/monitor/hmp-target.h b/include/monitor/hmp-target.h index 60fc92722a..dc53add7ee 100644 --- a/include/monitor/hmp-target.h +++ b/include/monitor/hmp-target.h @@ -49,5 +49,6 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict); void hmp_mce(Monitor *mon, const QDict *qdict); void hmp_info_local_apic(Monitor *mon, const QDict *qdict); void hmp_info_io_apic(Monitor *mon, const QDict *qdict); +void hmp_info_sgx(Monitor *mon, const QDict *qdict); #endif /* MONITOR_HMP_TARGET_H */ -- cgit v1.2.3 From 0205c4fa1ea35d569b4c2f63adacef438c1e8f53 Mon Sep 17 00:00:00 2001 From: Yang Zhong Date: Fri, 10 Sep 2021 18:22:57 +0800 Subject: target/i386: Add the query-sgx-capabilities QMP command Libvirt can use query-sgx-capabilities to get the host sgx capabilities to decide how to allocate SGX EPC size to VM. Signed-off-by: Yang Zhong Message-Id: <20210910102258.46648-3-yang.zhong@intel.com> Signed-off-by: Paolo Bonzini --- include/hw/i386/sgx.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/hw/i386/sgx.h b/include/hw/i386/sgx.h index 2bf90b3f4f..16fc25725c 100644 --- a/include/hw/i386/sgx.h +++ b/include/hw/i386/sgx.h @@ -7,5 +7,6 @@ #include "qapi/qapi-types-misc-target.h" SGXInfo *sgx_get_info(Error **errp); +SGXInfo *sgx_get_capabilities(Error **errp); #endif -- cgit v1.2.3 From 142518bda515c132a46ce5826e73fbd2a5b154d9 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Mon, 16 Aug 2021 21:35:52 -0400 Subject: memory: Name all the memory listeners Provide a name field for all the memory listeners. It can be used to identify which memory listener is which. Signed-off-by: Peter Xu Reviewed-by: David Hildenbrand Message-Id: <20210817013553.30584-2-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- include/exec/memory.h | 8 ++++++++ include/sysemu/kvm_int.h | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/exec/memory.h b/include/exec/memory.h index 9446874d21..a185b6dcb8 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -982,6 +982,14 @@ struct MemoryListener { */ unsigned priority; + /** + * @name: + * + * Name of the listener. It can be used in contexts where we'd like to + * identify one memory listener with the rest. + */ + const char *name; + /* private: */ AddressSpace *address_space; QTAILQ_ENTRY(MemoryListener) link; diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h index c788452cd9..1f5487d9b7 100644 --- a/include/sysemu/kvm_int.h +++ b/include/sysemu/kvm_int.h @@ -37,7 +37,7 @@ typedef struct KVMMemoryListener { } KVMMemoryListener; void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml, - AddressSpace *as, int as_id); + AddressSpace *as, int as_id, const char *name); void kvm_set_max_memslot_size(hwaddr max_slot_size); -- cgit v1.2.3