* SGX implementation for x86

* Miscellaneous bugfixes
 * Fix dependencies from ROMs to qtests
 -----BEGIN PGP SIGNATURE-----
 
 iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmFVu/sUHHBib256aW5p
 QHJlZGhhdC5jb20ACgkQv/vSX3jHroNFUgf+OexjKqJw4qzbDdQrxWqw3upoFblk
 y4OrmrhCyCKDwPghnjHUEVGHnNKqKpCLoIvtvFZ7xX/qezpMtZxVUliOVNQGmioR
 MZU/DbdlvVL/t8yKjfz1ljshk55hnSJ7rAv8LBA+B3uNzyJ+LZU9+Kbvmei5oyex
 nenCtXnoVNBJMvTBE/KfJbp0UasEb1OTvPBa0Y7mHyDub28FDPKr9WZbloCLUtE+
 uXwbZ34VRDsxbLnXh+BJ+ljOQLdsJErAkiPKTnW1/3W8Ti7PzOzvLpbSIVdBv/9A
 U1qOEm48BjCrG/tFJvTUm0ZM7AHmqYfvmwpenDpL0FhReohMdUa3pycQ9g==
 =Hicy
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/bonzini-gitlab/tags/for-upstream' into staging

* SGX implementation for x86
* Miscellaneous bugfixes
* Fix dependencies from ROMs to qtests

# gpg: Signature made Thu 30 Sep 2021 14:30:35 BST
# gpg:                using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg:                issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full]
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>" [full]
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4  E2F7 7E15 100C CD36 69B1
#      Subkey fingerprint: F133 3857 4B66 2389 866C  7682 BFFB D25F 78C7 AE83

* remotes/bonzini-gitlab/tags/for-upstream: (33 commits)
  meson_options.txt: Switch the default value for the vnc option to 'auto'
  build-sys: add HAVE_IPPROTO_MPTCP
  memory: Add tracepoint for dirty sync
  memory: Name all the memory listeners
  target/i386: Fix memory leak in sev_read_file_base64()
  tests: qtest: bios-tables-test depends on the unpacked edk2 ROMs
  meson: unpack edk2 firmware even if --disable-blobs
  target/i386: Add the query-sgx-capabilities QMP command
  target/i386: Add HMP and QMP interfaces for SGX
  docs/system: Add SGX documentation to the system manual
  sgx-epc: Add the fill_device_info() callback support
  i440fx: Add support for SGX EPC
  q35: Add support for SGX EPC
  i386: acpi: Add SGX EPC entry to ACPI tables
  i386/pc: Add e820 entry for SGX EPC section(s)
  hw/i386/pc: Account for SGX EPC sections when calculating device memory
  hw/i386/fw_cfg: Set SGX bits in feature control fw_cfg accordingly
  Adjust min CPUID level to 0x12 when SGX is enabled
  i386: Propagate SGX CPUID sub-leafs to KVM
  i386: kvm: Add support for exposing PROVISIONKEY to guest
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-09-30 17:38:30 +01:00
commit 0021c4765a
64 changed files with 1397 additions and 38 deletions

View File

@ -295,6 +295,7 @@ static void hvf_region_del(MemoryListener *listener,
}
static MemoryListener hvf_memory_listener = {
.name = "hvf",
.priority = 10,
.region_add = hvf_region_add,
.region_del = hvf_region_del,

View File

@ -1129,6 +1129,7 @@ static void kvm_coalesce_pio_del(MemoryListener *listener,
}
static MemoryListener kvm_coalesced_pio_listener = {
.name = "kvm-coalesced-pio",
.coalesced_io_add = kvm_coalesce_pio_add,
.coalesced_io_del = kvm_coalesce_pio_del,
};
@ -1633,7 +1634,7 @@ static void kvm_io_ioeventfd_del(MemoryListener *listener,
}
void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
AddressSpace *as, int as_id)
AddressSpace *as, int as_id, const char *name)
{
int i;
@ -1649,6 +1650,7 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
kml->listener.log_start = kvm_log_start;
kml->listener.log_stop = kvm_log_stop;
kml->listener.priority = 10;
kml->listener.name = name;
if (s->kvm_dirty_ring_size) {
kml->listener.log_sync_global = kvm_log_sync_global;
@ -1669,6 +1671,7 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
}
static MemoryListener kvm_io_listener = {
.name = "kvm-io",
.eventfd_add = kvm_io_ioeventfd_add,
.eventfd_del = kvm_io_ioeventfd_del,
.priority = 10,
@ -2579,7 +2582,7 @@ static int kvm_init(MachineState *ms)
s->memory_listener.listener.coalesced_io_del = kvm_uncoalesce_mmio_region;
kvm_memory_listener_register(s, &s->memory_listener,
&address_space_memory, 0);
&address_space_memory, 0, "kvm-memory");
if (kvm_eventfds_allowed) {
memory_listener_register(&kvm_io_listener,
&address_space_io);

82
backends/hostmem-epc.c Normal file
View File

@ -0,0 +1,82 @@
/*
* QEMU host SGX EPC memory backend
*
* Copyright (C) 2019 Intel Corporation
*
* Authors:
* Sean Christopherson <sean.j.christopherson@intel.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include <sys/ioctl.h>
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qom/object_interfaces.h"
#include "qapi/error.h"
#include "sysemu/hostmem.h"
#include "hw/i386/hostmem-epc.h"
static void
sgx_epc_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
{
uint32_t ram_flags;
char *name;
int fd;
if (!backend->size) {
error_setg(errp, "can't create backend with size 0");
return;
}
fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
if (fd < 0) {
error_setg_errno(errp, errno,
"failed to open /dev/sgx_vepc to alloc SGX EPC");
return;
}
name = object_get_canonical_path(OBJECT(backend));
ram_flags = (backend->share ? RAM_SHARED : 0) | RAM_PROTECTED;
memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
name, backend->size, ram_flags,
fd, 0, errp);
g_free(name);
}
static void sgx_epc_backend_instance_init(Object *obj)
{
HostMemoryBackend *m = MEMORY_BACKEND(obj);
m->share = true;
m->merge = false;
m->dump = false;
}
static void sgx_epc_backend_class_init(ObjectClass *oc, void *data)
{
HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
bc->alloc = sgx_epc_backend_memory_alloc;
}
static const TypeInfo sgx_epc_backed_info = {
.name = TYPE_MEMORY_BACKEND_EPC,
.parent = TYPE_MEMORY_BACKEND,
.instance_init = sgx_epc_backend_instance_init,
.class_init = sgx_epc_backend_class_init,
.instance_size = sizeof(HostMemoryBackendEpc),
};
static void register_types(void)
{
int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
if (fd >= 0) {
close(fd);
type_register_static(&sgx_epc_backed_info);
}
}
type_init(register_types);

View File

@ -16,5 +16,6 @@ softmmu_ss.add(when: ['CONFIG_VHOST_USER', 'CONFIG_VIRTIO'], if_true: files('vho
softmmu_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('cryptodev-vhost.c'))
softmmu_ss.add(when: ['CONFIG_VIRTIO_CRYPTO', 'CONFIG_VHOST_CRYPTO'], if_true: files('cryptodev-vhost-user.c'))
softmmu_ss.add(when: 'CONFIG_GIO', if_true: [files('dbus-vmstate.c'), gio])
softmmu_ss.add(when: 'CONFIG_SGX', if_true: files('hostmem-epc.c'))
subdir('tpm')

View File

@ -22,6 +22,7 @@
#CONFIG_TPM_CRB=n
#CONFIG_TPM_TIS_ISA=n
#CONFIG_VTD=n
#CONFIG_SGX=n
# Boards:
#

165
docs/system/i386/sgx.rst Normal file
View File

@ -0,0 +1,165 @@
Software Guard eXtensions (SGX)
===============================
Overview
--------
Intel Software Guard eXtensions (SGX) is a set of instructions and mechanisms
for memory accesses in order to provide security accesses for sensitive
applications and data. SGX allows an application to use it's pariticular
address space as an *enclave*, which is a protected area provides confidentiality
and integrity even in the presence of privileged malware. Accesses to the
enclave memory area from any software not resident in the enclave are prevented,
including those from privileged software.
Virtual SGX
-----------
SGX feature is exposed to guest via SGX CPUID. Looking at SGX CPUID, we can
report the same CPUID info to guest as on host for most of SGX CPUID. With
reporting the same CPUID guest is able to use full capacity of SGX, and KVM
doesn't need to emulate those info.
The guest's EPC base and size are determined by Qemu, and KVM needs Qemu to
notify such info to it before it can initialize SGX for guest.
Virtual EPC
~~~~~~~~~~~
By default, Qemu does not assign EPC to a VM, i.e. fully enabling SGX in a VM
requires explicit allocation of EPC to the VM. Similar to other specialized
memory types, e.g. hugetlbfs, EPC is exposed as a memory backend.
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. This limitation means that EPC does not
require -maxmem as EPC is not treated as {cold,hot}plugged memory.
Qemu does not artificially restrict the number of EPC sections exposed to a
guest, e.g. Qemu will happily allow you to create 64 1M EPC sections. Be aware
that some kernels may not recognize all EPC sections, e.g. the Linux SGX driver
is hardwired to support only 8 EPC sections.
The following Qemu snippet creates two EPC sections, with 64M pre-allocated
to the VM and an additional 28M mapped but not allocated::
-object memory-backend-epc,id=mem1,size=64M,prealloc=on \
-object memory-backend-epc,id=mem2,size=28M \
-M sgx-epc.0.memdev=mem1,sgx-epc.1.memdev=mem2
Note:
The size and location of the virtual EPC are far less restricted compared
to physical EPC. Because physical EPC is protected via range registers,
the size of the physical EPC must be a power of two (though software sees
a subset of the full EPC, e.g. 92M or 128M) and the EPC must be naturally
aligned. KVM SGX's virtual EPC is purely a software construct and only
requires the size and location to be page aligned. Qemu enforces the EPC
size is a multiple of 4k and will ensure the base of the EPC is 4k aligned.
To simplify the implementation, EPC is always located above 4g in the guest
physical address space.
Migration
~~~~~~~~~
Qemu/KVM doesn't prevent live migrating SGX VMs, although from hardware's
perspective, SGX doesn't support live migration, since both EPC and the SGX
key hierarchy are bound to the physical platform. However live migration
can be supported in the sense if guest software stack can support recreating
enclaves when it suffers sudden lose of EPC; and if guest enclaves can detect
SGX keys being changed, and handle gracefully. For instance, when ERESUME fails
with #PF.SGX, guest software can gracefully detect it and recreate enclaves;
and when enclave fails to unseal sensitive information from outside, it can
detect such error and sensitive information can be provisioned to it again.
CPUID
~~~~~
Due to its myriad dependencies, SGX is currently not listed as supported
in any of Qemu's built-in CPU configuration. To expose SGX (and SGX Launch
Control) to a guest, you must either use `-cpu host` to pass-through the
host CPU model, or explicitly enable SGX when using a built-in CPU model,
e.g. via `-cpu <model>,+sgx` or `-cpu <model>,+sgx,+sgxlc`.
All SGX sub-features enumerated through CPUID, e.g. SGX2, MISCSELECT,
ATTRIBUTES, etc... can be restricted via CPUID flags. Be aware that enforcing
restriction of MISCSELECT, ATTRIBUTES and XFRM requires intercepting ECREATE,
i.e. may marginally reduce SGX performance in the guest. All SGX sub-features
controlled via -cpu are prefixed with "sgx", e.g.::
$ qemu-system-x86_64 -cpu help | xargs printf "%s\n" | grep sgx
sgx
sgx-debug
sgx-encls-c
sgx-enclv
sgx-exinfo
sgx-kss
sgx-mode64
sgx-provisionkey
sgx-tokenkey
sgx1
sgx2
sgxlc
The following Qemu snippet passes through the host CPU but restricts access to
the provision and EINIT token keys::
-cpu host,-sgx-provisionkey,-sgx-tokenkey
SGX sub-features cannot be emulated, i.e. sub-features that are not present
in hardware cannot be forced on via '-cpu'.
Virtualize SGX Launch Control
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Qemu SGX support for Launch Control (LC) is passive, in the sense that it
does not actively change the LC configuration. Qemu SGX provides the user
the ability to set/clear the CPUID flag (and by extension the associated
IA32_FEATURE_CONTROL MSR bit in fw_cfg) and saves/restores the LE Hash MSRs
when getting/putting guest state, but Qemu does not add new controls to
directly modify the LC configuration. Similar to hardware behavior, locking
the LC configuration to a non-Intel value is left to guest firmware. Unlike
host bios setting for SGX launch control(LC), there is no special bios setting
for SGX guest by our design. If host is in locked mode, we can still allow
creating VM with SGX.
Feature Control
~~~~~~~~~~~~~~~
Qemu SGX updates the `etc/msr_feature_control` fw_cfg entry to set the SGX
(bit 18) and SGX LC (bit 17) flags based on their respective CPUID support,
i.e. existing guest firmware will automatically set SGX and SGX LC accordingly,
assuming said firmware supports fw_cfg.msr_feature_control.
Launching a guest
-----------------
To launch a SGX guest:
.. parsed-literal::
|qemu_system_x86| \\
-cpu host,+sgx-provisionkey \\
-object memory-backend-epc,id=mem1,size=64M,prealloc=on \\
-object memory-backend-epc,id=mem2,size=28M \\
-M sgx-epc.0.memdev=mem1,sgx-epc.1.memdev=mem2
Utilizing SGX in the guest requires a kernel/OS with SGX support.
The support can be determined in guest by::
$ grep sgx /proc/cpuinfo
and SGX epc info by::
$ dmesg | grep sgx
[ 1.242142] sgx: EPC section 0x180000000-0x181bfffff
[ 1.242319] sgx: EPC section 0x181c00000-0x1837fffff
References
----------
- `SGX Homepage <https://software.intel.com/sgx>`__
- `SGX SDK <https://github.com/intel/linux-sgx.git>`__
- SGX specification: Intel SDM Volume 3

View File

@ -26,6 +26,7 @@ Architectural features
:maxdepth: 1
i386/cpu
i386/sgx
.. _pcsys_005freq:

View File

@ -877,3 +877,18 @@ SRST
``info dirty_rate``
Display the vcpu dirty rate information.
ERST
#if defined(TARGET_I386)
{
.name = "sgx",
.args_type = "",
.params = "",
.help = "show intel SGX information",
.cmd = hmp_info_sgx,
},
#endif
SRST
``info sgx``
Show intel SGX information.
ERST

View File

@ -6,6 +6,10 @@ config SEV
select X86_FW_OVMF
depends on KVM
config SGX
bool
depends on KVM
config PC
bool
imply APPLESMC
@ -21,6 +25,7 @@ config PC
imply PVPANIC_ISA
imply QXL
imply SEV
imply SGX
imply SGA
imply TEST_DEVICES
imply TPM_CRB

View File

@ -1841,6 +1841,28 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
}
#endif
if (pcms->sgx_epc.size != 0) {
uint64_t epc_base = pcms->sgx_epc.base;
uint64_t epc_size = pcms->sgx_epc.size;
dev = aml_device("EPC");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("INT0E0C")));
aml_append(dev, aml_name_decl("_STR",
aml_unicode("Enclave Page Cache 1.0")));
crs = aml_resource_template();
aml_append(crs,
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED,
AML_MAX_FIXED, AML_NON_CACHEABLE,
AML_READ_WRITE, 0, epc_base,
epc_base + epc_size - 1, 0, epc_size));
aml_append(dev, aml_name_decl("_CRS", crs));
method = aml_method("_STA", 0, AML_NOTSERIALIZED);
aml_append(method, aml_return(aml_int(0x0f)));
aml_append(dev, method);
aml_append(sb_scope, dev);
}
aml_append(dsdt, sb_scope);
/* copy AML table into ACPI tables blob and patch header there */

View File

@ -159,7 +159,7 @@ void fw_cfg_build_feature_control(MachineState *ms, FWCfgState *fw_cfg)
{
X86CPU *cpu = X86_CPU(ms->possible_cpus->cpus[0].cpu);
CPUX86State *env = &cpu->env;
uint32_t unused, ecx, edx;
uint32_t unused, ebx, ecx, edx;
uint64_t feature_control_bits = 0;
uint64_t *val;
@ -174,6 +174,16 @@ void fw_cfg_build_feature_control(MachineState *ms, FWCfgState *fw_cfg)
feature_control_bits |= FEATURE_CONTROL_LMCE;
}
if (env->cpuid_level >= 7) {
cpu_x86_cpuid(env, 0x7, 0, &unused, &ebx, &ecx, &unused);
if (ebx & CPUID_7_0_EBX_SGX) {
feature_control_bits |= FEATURE_CONTROL_SGX;
}
if (ecx & CPUID_7_0_ECX_SGX_LC) {
feature_control_bits |= FEATURE_CONTROL_SGX_LC;
}
}
if (!feature_control_bits) {
return;
}

View File

@ -16,6 +16,8 @@ i386_ss.add(when: 'CONFIG_Q35', if_true: files('pc_q35.c'))
i386_ss.add(when: 'CONFIG_VMMOUSE', if_true: files('vmmouse.c'))
i386_ss.add(when: 'CONFIG_VMPORT', if_true: files('vmport.c'))
i386_ss.add(when: 'CONFIG_VTD', if_true: files('intel_iommu.c'))
i386_ss.add(when: 'CONFIG_SGX', if_true: files('sgx-epc.c','sgx.c'),
if_false: files('sgx-stub.c'))
i386_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-common.c'))
i386_ss.add(when: 'CONFIG_ACPI_HW_REDUCED', if_true: files('generic_event_device_x86.c'))

View File

@ -889,6 +889,10 @@ void pc_memory_init(PCMachineState *pcms,
e820_add_entry(0x100000000ULL, x86ms->above_4g_mem_size, E820_RAM);
}
if (pcms->sgx_epc.size != 0) {
e820_add_entry(pcms->sgx_epc.base, pcms->sgx_epc.size, E820_RESERVED);
}
if (!pcmc->has_reserved_memory &&
(machine->ram_slots ||
(machine->maxram_size > machine->ram_size))) {
@ -919,8 +923,15 @@ void pc_memory_init(PCMachineState *pcms,
exit(EXIT_FAILURE);
}
if (pcms->sgx_epc.size != 0) {
machine->device_memory->base = sgx_epc_above_4g_end(&pcms->sgx_epc);
} else {
machine->device_memory->base =
ROUND_UP(0x100000000ULL + x86ms->above_4g_mem_size, 1 * GiB);
0x100000000ULL + x86ms->above_4g_mem_size;
}
machine->device_memory->base =
ROUND_UP(machine->device_memory->base, 1 * GiB);
if (pcmc->enforce_aligned_dimm) {
/* size device region assuming 1G page max alignment per slot */
@ -1005,6 +1016,8 @@ uint64_t pc_pci_hole64_start(void)
if (!pcmc->broken_reserved_end) {
hole64_start += memory_region_size(&ms->device_memory->mr);
}
} else if (pcms->sgx_epc.size != 0) {
hole64_start = sgx_epc_above_4g_end(&pcms->sgx_epc);
} else {
hole64_start = 0x100000000ULL + x86ms->above_4g_mem_size;
}

View File

@ -153,6 +153,7 @@ static void pc_init1(MachineState *machine,
}
}
pc_machine_init_sgx_epc(pcms);
x86_cpus_init(x86ms, pcmc->default_cpu_version);
if (pcmc->kvmclock_enabled) {

View File

@ -177,6 +177,7 @@ static void pc_q35_init(MachineState *machine)
x86ms->below_4g_mem_size = machine->ram_size;
}
pc_machine_init_sgx_epc(pcms);
x86_cpus_init(x86ms, pcmc->default_cpu_version);
kvmclock_create(pcmc->kvmclock_create_always);

184
hw/i386/sgx-epc.c Normal file
View File

@ -0,0 +1,184 @@
/*
* SGX EPC device
*
* Copyright (C) 2019 Intel Corporation
*
* Authors:
* Sean Christopherson <sean.j.christopherson@intel.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "hw/i386/pc.h"
#include "hw/i386/sgx-epc.h"
#include "hw/mem/memory-device.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "target/i386/cpu.h"
#include "exec/address-spaces.h"
static Property sgx_epc_properties[] = {
DEFINE_PROP_UINT64(SGX_EPC_ADDR_PROP, SGXEPCDevice, addr, 0),
DEFINE_PROP_LINK(SGX_EPC_MEMDEV_PROP, SGXEPCDevice, hostmem,
TYPE_MEMORY_BACKEND_EPC, HostMemoryBackendEpc *),
DEFINE_PROP_END_OF_LIST(),
};
static void sgx_epc_get_size(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
Error *local_err = NULL;
uint64_t value;
value = memory_device_get_region_size(MEMORY_DEVICE(obj), &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
visit_type_uint64(v, name, &value, errp);
}
static void sgx_epc_init(Object *obj)
{
object_property_add(obj, SGX_EPC_SIZE_PROP, "uint64", sgx_epc_get_size,
NULL, NULL, NULL);
}
static void sgx_epc_realize(DeviceState *dev, Error **errp)
{
PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
X86MachineState *x86ms = X86_MACHINE(pcms);
MemoryDeviceState *md = MEMORY_DEVICE(dev);
SGXEPCState *sgx_epc = &pcms->sgx_epc;
SGXEPCDevice *epc = SGX_EPC(dev);
HostMemoryBackend *hostmem;
const char *path;
if (x86ms->boot_cpus != 0) {
error_setg(errp, "'" TYPE_SGX_EPC "' can't be created after vCPUs,"
"e.g. via -device");
return;
}
if (!epc->hostmem) {
error_setg(errp, "'" SGX_EPC_MEMDEV_PROP "' property is not set");
return;
}
hostmem = MEMORY_BACKEND(epc->hostmem);
if (host_memory_backend_is_mapped(hostmem)) {
path = object_get_canonical_path_component(OBJECT(hostmem));
error_setg(errp, "can't use already busy memdev: %s", path);
return;
}
epc->addr = sgx_epc->base + sgx_epc->size;
memory_region_add_subregion(&sgx_epc->mr, epc->addr - sgx_epc->base,
host_memory_backend_get_memory(hostmem));
host_memory_backend_set_mapped(hostmem, true);
sgx_epc->sections = g_renew(SGXEPCDevice *, sgx_epc->sections,
sgx_epc->nr_sections + 1);
sgx_epc->sections[sgx_epc->nr_sections++] = epc;
sgx_epc->size += memory_device_get_region_size(md, errp);
}
static void sgx_epc_unrealize(DeviceState *dev)
{
SGXEPCDevice *epc = SGX_EPC(dev);
HostMemoryBackend *hostmem = MEMORY_BACKEND(epc->hostmem);
host_memory_backend_set_mapped(hostmem, false);
}
static uint64_t sgx_epc_md_get_addr(const MemoryDeviceState *md)
{
const SGXEPCDevice *epc = SGX_EPC(md);
return epc->addr;
}
static void sgx_epc_md_set_addr(MemoryDeviceState *md, uint64_t addr,
Error **errp)
{
object_property_set_uint(OBJECT(md), SGX_EPC_ADDR_PROP, addr, errp);
}
static uint64_t sgx_epc_md_get_plugged_size(const MemoryDeviceState *md,
Error **errp)
{
return 0;
}
static MemoryRegion *sgx_epc_md_get_memory_region(MemoryDeviceState *md,
Error **errp)
{
SGXEPCDevice *epc = SGX_EPC(md);
HostMemoryBackend *hostmem;
if (!epc->hostmem) {
error_setg(errp, "'" SGX_EPC_MEMDEV_PROP "' property must be set");
return NULL;
}
hostmem = MEMORY_BACKEND(epc->hostmem);
return host_memory_backend_get_memory(hostmem);
}
static void sgx_epc_md_fill_device_info(const MemoryDeviceState *md,
MemoryDeviceInfo *info)
{
SgxEPCDeviceInfo *se = g_new0(SgxEPCDeviceInfo, 1);
SGXEPCDevice *epc = SGX_EPC(md);
se->memaddr = epc->addr;
se->size = object_property_get_uint(OBJECT(epc), SGX_EPC_SIZE_PROP,
NULL);
se->memdev = object_get_canonical_path(OBJECT(epc->hostmem));
info->u.sgx_epc.data = se;
info->type = MEMORY_DEVICE_INFO_KIND_SGX_EPC;
}
static void sgx_epc_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc);
dc->hotpluggable = false;
dc->realize = sgx_epc_realize;
dc->unrealize = sgx_epc_unrealize;
dc->desc = "SGX EPC section";
device_class_set_props(dc, sgx_epc_properties);
mdc->get_addr = sgx_epc_md_get_addr;
mdc->set_addr = sgx_epc_md_set_addr;
mdc->get_plugged_size = sgx_epc_md_get_plugged_size;
mdc->get_memory_region = sgx_epc_md_get_memory_region;
mdc->fill_device_info = sgx_epc_md_fill_device_info;
}
static TypeInfo sgx_epc_info = {
.name = TYPE_SGX_EPC,
.parent = TYPE_DEVICE,
.instance_size = sizeof(SGXEPCDevice),
.instance_init = sgx_epc_init,
.class_init = sgx_epc_class_init,
.class_size = sizeof(DeviceClass),
.interfaces = (InterfaceInfo[]) {
{ TYPE_MEMORY_DEVICE },
{ }
},
};
static void sgx_epc_register_types(void)
{
type_register_static(&sgx_epc_info);
}
type_init(sgx_epc_register_types)

26
hw/i386/sgx-stub.c Normal file
View File

@ -0,0 +1,26 @@
#include "qemu/osdep.h"
#include "hw/i386/pc.h"
#include "hw/i386/sgx-epc.h"
#include "hw/i386/sgx.h"
SGXInfo *sgx_get_info(Error **errp)
{
error_setg(errp, "SGX support is not compiled in");
return NULL;
}
SGXInfo *sgx_get_capabilities(Error **errp)
{
error_setg(errp, "SGX support is not compiled in");
return NULL;
}
void pc_machine_init_sgx_epc(PCMachineState *pcms)
{
memset(&pcms->sgx_epc, 0, sizeof(SGXEPCState));
}
int sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size)
{
g_assert_not_reached();
}

170
hw/i386/sgx.c Normal file
View File

@ -0,0 +1,170 @@
/*
* SGX common code
*
* Copyright (C) 2021 Intel Corporation
*
* Authors:
* Yang Zhong<yang.zhong@intel.com>
* Sean Christopherson <sean.j.christopherson@intel.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "hw/i386/pc.h"
#include "hw/i386/sgx-epc.h"
#include "hw/mem/memory-device.h"
#include "monitor/qdev.h"
#include "qapi/error.h"
#include "exec/address-spaces.h"
#include "hw/i386/sgx.h"
#include "sysemu/hw_accel.h"
#define SGX_MAX_EPC_SECTIONS 8
#define SGX_CPUID_EPC_INVALID 0x0
/* A valid EPC section. */
#define SGX_CPUID_EPC_SECTION 0x1
#define SGX_CPUID_EPC_MASK 0xF
static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high)
{
return (low & MAKE_64BIT_MASK(12, 20)) +
((high & MAKE_64BIT_MASK(0, 20)) << 32);
}
static uint64_t sgx_calc_host_epc_section_size(void)
{
uint32_t i, type;
uint32_t eax, ebx, ecx, edx;
uint64_t size = 0;
for (i = 0; i < SGX_MAX_EPC_SECTIONS; i++) {
host_cpuid(0x12, i + 2, &eax, &ebx, &ecx, &edx);
type = eax & SGX_CPUID_EPC_MASK;
if (type == SGX_CPUID_EPC_INVALID) {
break;
}
if (type != SGX_CPUID_EPC_SECTION) {
break;
}
size += sgx_calc_section_metric(ecx, edx);
}
return size;
}
SGXInfo *sgx_get_capabilities(Error **errp)
{
SGXInfo *info = NULL;
uint32_t eax, ebx, ecx, edx;
int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
if (fd < 0) {
error_setg(errp, "SGX is not enabled in KVM");
return NULL;
}
info = g_new0(SGXInfo, 1);
host_cpuid(0x7, 0, &eax, &ebx, &ecx, &edx);
info->sgx = ebx & (1U << 2) ? true : false;
info->flc = ecx & (1U << 30) ? true : false;
host_cpuid(0x12, 0, &eax, &ebx, &ecx, &edx);
info->sgx1 = eax & (1U << 0) ? true : false;
info->sgx2 = eax & (1U << 1) ? true : false;
info->section_size = sgx_calc_host_epc_section_size();
close(fd);
return info;
}
SGXInfo *sgx_get_info(Error **errp)
{
SGXInfo *info = NULL;
X86MachineState *x86ms;
PCMachineState *pcms =
(PCMachineState *)object_dynamic_cast(qdev_get_machine(),
TYPE_PC_MACHINE);
if (!pcms) {
error_setg(errp, "SGX is only supported on PC machines");
return NULL;
}
x86ms = X86_MACHINE(pcms);
if (!x86ms->sgx_epc_list) {
error_setg(errp, "No EPC regions defined, SGX not available");
return NULL;
}
SGXEPCState *sgx_epc = &pcms->sgx_epc;
info = g_new0(SGXInfo, 1);
info->sgx = true;
info->sgx1 = true;
info->sgx2 = true;
info->flc = true;
info->section_size = sgx_epc->size;
return info;
}
int sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size)
{
PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
SGXEPCDevice *epc;
if (pcms->sgx_epc.size == 0 || pcms->sgx_epc.nr_sections <= section_nr) {
return 1;
}
epc = pcms->sgx_epc.sections[section_nr];
*addr = epc->addr;
*size = memory_device_get_region_size(MEMORY_DEVICE(epc), &error_fatal);
return 0;
}
void pc_machine_init_sgx_epc(PCMachineState *pcms)
{
SGXEPCState *sgx_epc = &pcms->sgx_epc;
X86MachineState *x86ms = X86_MACHINE(pcms);
SgxEPCList *list = NULL;
Object *obj;
memset(sgx_epc, 0, sizeof(SGXEPCState));
if (!x86ms->sgx_epc_list) {
return;
}
sgx_epc->base = 0x100000000ULL + x86ms->above_4g_mem_size;
memory_region_init(&sgx_epc->mr, OBJECT(pcms), "sgx-epc", UINT64_MAX);
memory_region_add_subregion(get_system_memory(), sgx_epc->base,
&sgx_epc->mr);
for (list = x86ms->sgx_epc_list; list; list = list->next) {
obj = object_new("sgx-epc");
/* set the memdev link with memory backend */
object_property_parse(obj, SGX_EPC_MEMDEV_PROP, list->value->memdev,
&error_fatal);
object_property_set_bool(obj, "realized", true, &error_fatal);
object_unref(obj);
}
if ((sgx_epc->base + sgx_epc->size) < sgx_epc->base) {
error_report("Size of all 'sgx-epc' =0x%"PRIu64" causes EPC to wrap",
sgx_epc->size);
exit(EXIT_FAILURE);
}
memory_region_set_size(&sgx_epc->mr, sgx_epc->size);
}

View File

@ -30,6 +30,8 @@
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
#include "qapi/qapi-visit-common.h"
#include "qapi/clone-visitor.h"
#include "qapi/qapi-visit-machine.h"
#include "qapi/visitor.h"
#include "sysemu/qtest.h"
#include "sysemu/whpx.h"
@ -1263,6 +1265,27 @@ static void x86_machine_set_bus_lock_ratelimit(Object *obj, Visitor *v,
visit_type_uint64(v, name, &x86ms->bus_lock_ratelimit, errp);
}
static void machine_get_sgx_epc(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
X86MachineState *x86ms = X86_MACHINE(obj);
SgxEPCList *list = x86ms->sgx_epc_list;
visit_type_SgxEPCList(v, name, &list, errp);
}
static void machine_set_sgx_epc(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
X86MachineState *x86ms = X86_MACHINE(obj);
SgxEPCList *list;
list = x86ms->sgx_epc_list;
visit_type_SgxEPCList(v, name, &x86ms->sgx_epc_list, errp);
qapi_free_SgxEPCList(list);
}
static void x86_machine_initfn(Object *obj)
{
X86MachineState *x86ms = X86_MACHINE(obj);
@ -1322,6 +1345,12 @@ static void x86_machine_class_init(ObjectClass *oc, void *data)
x86_machine_set_bus_lock_ratelimit, NULL, NULL);
object_class_property_set_description(oc, X86_MACHINE_BUS_LOCK_RATELIMIT,
"Set the ratelimit for the bus locks acquired in VMs");
object_class_property_add(oc, "sgx-epc", "SgxEPC",
machine_get_sgx_epc, machine_set_sgx_epc,
NULL, NULL);
object_class_property_set_description(oc, "sgx-epc",
"SGX EPC device");
}
static const TypeInfo x86_machine_info = {

View File

@ -721,6 +721,7 @@ static void xen_log_global_stop(MemoryListener *listener)
}
static MemoryListener xen_memory_listener = {
.name = "xen-memory",
.region_add = xen_region_add,
.region_del = xen_region_del,
.log_start = xen_log_start,
@ -732,6 +733,7 @@ static MemoryListener xen_memory_listener = {
};
static MemoryListener xen_io_listener = {
.name = "xen-io",
.region_add = xen_io_add,
.region_del = xen_io_del,
.priority = 10,

View File

@ -234,6 +234,7 @@ static void kvm_openpic_realize(DeviceState *dev, Error **errp)
opp->mem_listener.region_add = kvm_openpic_region_add;
opp->mem_listener.region_del = kvm_openpic_region_del;
opp->mem_listener.name = "openpic-kvm";
memory_listener_register(&opp->mem_listener, &address_space_memory);
/* indicate pic capabilities */

View File

@ -219,6 +219,7 @@ void proxy_memory_listener_configure(ProxyMemoryListener *proxy_listener,
proxy_listener->listener.region_add = proxy_memory_listener_region_addnop;
proxy_listener->listener.region_nop = proxy_memory_listener_region_addnop;
proxy_listener->listener.priority = 10;
proxy_listener->listener.name = "proxy";
memory_listener_register(&proxy_listener->listener,
&address_space_memory);

View File

@ -562,6 +562,7 @@ static bool vfio_listener_skipped_section(MemoryRegionSection *section)
{
return (!memory_region_is_ram(section->mr) &&
!memory_region_is_iommu(section->mr)) ||
memory_region_is_protected(section->mr) ||
/*
* Sizing an enabled 64-bit BAR can cause spurious mappings to
* addresses in the upper part of the 64-bit address space. These
@ -1434,6 +1435,7 @@ static void vfio_listener_log_sync(MemoryListener *listener,
}
static const MemoryListener vfio_memory_listener = {
.name = "vfio",
.region_add = vfio_listener_region_add,
.region_del = vfio_listener_region_del,
.log_global_start = vfio_listener_log_global_start,

View File

@ -136,6 +136,7 @@ static void vfio_prereg_listener_region_del(MemoryListener *listener,
}
const MemoryListener vfio_prereg_listener = {
.name = "vfio-pre-reg",
.region_add = vfio_prereg_listener_region_add,
.region_del = vfio_prereg_listener_region_del,
};

View File

@ -246,6 +246,7 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener,
* depends on the addnop().
*/
static const MemoryListener vhost_vdpa_memory_listener = {
.name = "vhost-vdpa",
.commit = vhost_vdpa_listener_commit,
.region_add = vhost_vdpa_listener_region_add,
.region_del = vhost_vdpa_listener_region_del,

View File

@ -1366,6 +1366,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
hdev->features = features;
hdev->memory_listener = (MemoryListener) {
.name = "vhost",
.begin = vhost_begin,
.commit = vhost_commit,
.region_add = vhost_region_addnop,
@ -1381,6 +1382,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
};
hdev->iommu_listener = (MemoryListener) {
.name = "vhost-iommu",
.region_add = vhost_iommu_region_add,
.region_del = vhost_iommu_region_del,
};

View File

@ -3670,6 +3670,7 @@ static void virtio_device_realize(DeviceState *dev, Error **errp)
}
vdev->listener.commit = virtio_memory_listener_commit;
vdev->listener.name = "virtio";
memory_listener_register(&vdev->listener, vdev->dma_as);
}

View File

@ -689,12 +689,14 @@ static void xen_pt_io_region_del(MemoryListener *l, MemoryRegionSection *sec)
}
static const MemoryListener xen_pt_memory_listener = {
.name = "xen-pt-mem",
.region_add = xen_pt_region_add,
.region_del = xen_pt_region_del,
.priority = 10,
};
static const MemoryListener xen_pt_io_listener = {
.name = "xen-pt-io",
.region_add = xen_pt_io_region_add,
.region_del = xen_pt_io_region_del,
.priority = 10,

View File

@ -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,
@ -979,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;
@ -1267,7 +1278,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 +1579,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
*

View File

@ -0,0 +1,28 @@
/*
* SGX EPC backend
*
* Copyright (C) 2019 Intel Corporation
*
* Authors:
* Sean Christopherson <sean.j.christopherson@intel.com>
*
* 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

View File

@ -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"
@ -192,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;

67
include/hw/i386/sgx-epc.h Normal file
View File

@ -0,0 +1,67 @@
/*
* SGX EPC device
*
* Copyright (C) 2019 Intel Corporation
*
* Authors:
* Sean Christopherson <sean.j.christopherson@intel.com>
*
* 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;
/*
* @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;
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

12
include/hw/i386/sgx.h Normal file
View File

@ -0,0 +1,12 @@
#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);
SGXInfo *sgx_get_capabilities(Error **errp);
#endif

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -122,7 +122,7 @@ static int qio_dns_resolver_lookup_sync_inet(QIODNSResolver *resolver,
.ipv4 = iaddr->ipv4,
.has_ipv6 = iaddr->has_ipv6,
.ipv6 = iaddr->ipv6,
#ifdef IPPROTO_MPTCP
#ifdef HAVE_IPPROTO_MPTCP
.has_mptcp = iaddr->has_mptcp,
.mptcp = iaddr->mptcp,
#endif

View File

@ -106,14 +106,14 @@ if targetos != 'darwin'
endif
edk2_targets = [ 'arm-softmmu', 'aarch64-softmmu', 'i386-softmmu', 'x86_64-softmmu' ]
install_edk2_blobs = false
if get_option('install_blobs')
foreach target : target_dirs
install_edk2_blobs = install_edk2_blobs or target in edk2_targets
endforeach
unpack_edk2_blobs = false
foreach target : edk2_targets
if target in target_dirs
bzip2 = find_program('bzip2', required: get_option('install_blobs'))
unpack_edk2_blobs = bzip2.found()
break
endif
bzip2 = find_program('bzip2', required: install_edk2_blobs)
endforeach
##################
# Compiler flags #
@ -1374,6 +1374,8 @@ config_host_data.set('HAVE_OPTRESET',
cc.has_header_symbol('getopt.h', 'optreset'))
config_host_data.set('HAVE_UTMPX',
cc.has_header_symbol('utmpx.h', 'struct utmpx'))
config_host_data.set('HAVE_IPPROTO_MPTCP',
cc.has_header_symbol('netinet/in.h', 'IPPROTO_MPTCP'))
# has_member
config_host_data.set('HAVE_SIGEV_NOTIFY_THREAD_ID',

View File

@ -120,7 +120,7 @@ option('usb_redir', type : 'feature', value : 'auto',
description: 'libusbredir support')
option('virglrenderer', type : 'feature', value : 'auto',
description: 'virgl rendering support')
option('vnc', type : 'feature', value : 'enabled',
option('vnc', type : 'feature', value : 'auto',
description: 'VNC server')
option('vnc_jpeg', type : 'feature', value : 'auto',
description: 'JPEG lossy compression for VNC server')

View File

@ -1823,6 +1823,7 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
VirtioMEMDeviceInfo *vmi;
MemoryDeviceInfo *value;
PCDIMMDeviceInfo *di;
SgxEPCDeviceInfo *se;
for (info = info_list; info; info = info->next) {
value = info->value;
@ -1870,6 +1871,15 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
vmi->block_size);
monitor_printf(mon, " memdev: %s\n", vmi->memdev);
break;
case MEMORY_DEVICE_INFO_KIND_SGX_EPC:
se = value->u.sgx_epc.data;
monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
MemoryDeviceInfoKind_str(value->type),
se->id ? se->id : "");
monitor_printf(mon, " memaddr: 0x%" PRIx64 "\n", se->memaddr);
monitor_printf(mon, " size: %" PRIu64 "\n", se->size);
monitor_printf(mon, " memdev: %s\n", se->memdev);
break;
default:
g_assert_not_reached();
}

View File

@ -1,4 +1,4 @@
if install_edk2_blobs
if unpack_edk2_blobs and get_option('install_blobs')
foreach f: [
'50-edk2-i386-secure.json',
'50-edk2-x86_64-secure.json',
@ -10,7 +10,7 @@ if install_edk2_blobs
configure_file(input: files(f),
output: f,
configuration: {'DATADIR': get_option('prefix') / qemu_datadir},
install: get_option('install_blobs'),
install: true,
install_dir: qemu_datadir / 'firmware')
endforeach
endif

View File

@ -1,4 +1,5 @@
if install_edk2_blobs
roms = []
if unpack_edk2_blobs
fds = [
'edk2-aarch64-code.fd',
'edk2-arm-code.fd',
@ -11,7 +12,7 @@ if install_edk2_blobs
]
foreach f : fds
custom_target(f,
roms += custom_target(f,
build_by_default: have_system,
output: f,
input: '@0@.bz2'.format(f),

View File

@ -1194,13 +1194,36 @@
}
}
##
# @SgxEPCDeviceInfo:
#
# Sgx EPC state information
#
# @id: device's ID
#
# @memaddr: physical address in memory, where device is mapped
#
# @size: size of memory that the device provides
#
# @memdev: memory backend linked with device
#
# Since: 6.2
##
{ 'struct': 'SgxEPCDeviceInfo',
'data': { '*id': 'str',
'memaddr': 'size',
'size': 'size',
'memdev': 'str'
}
}
##
# @MemoryDeviceInfoKind:
#
# Since: 2.1
##
{ 'enum': 'MemoryDeviceInfoKind',
'data': [ 'dimm', 'nvdimm', 'virtio-pmem', 'virtio-mem' ] }
'data': [ 'dimm', 'nvdimm', 'virtio-pmem', 'virtio-mem', 'sgx-epc' ] }
##
# @PCDIMMDeviceInfoWrapper:
@ -1226,13 +1249,21 @@
{ 'struct': 'VirtioMEMDeviceInfoWrapper',
'data': { 'data': 'VirtioMEMDeviceInfo' } }
##
# @SgxEPCDeviceInfoWrapper:
#
# Since: 6.2
##
{ 'struct': 'SgxEPCDeviceInfoWrapper',
'data': { 'data': 'SgxEPCDeviceInfo' } }
##
# @MemoryDeviceInfo:
#
# Union containing information about a memory device
#
# nvdimm is included since 2.12. virtio-pmem is included since 4.1.
# virtio-mem is included since 5.1.
# virtio-mem is included since 5.1. sgx-epc is included since 6.2.
#
# Since: 2.1
##
@ -1242,10 +1273,36 @@
'data': { 'dimm': 'PCDIMMDeviceInfoWrapper',
'nvdimm': 'PCDIMMDeviceInfoWrapper',
'virtio-pmem': 'VirtioPMEMDeviceInfoWrapper',
'virtio-mem': 'VirtioMEMDeviceInfoWrapper'
'virtio-mem': 'VirtioMEMDeviceInfoWrapper',
'sgx-epc': 'SgxEPCDeviceInfoWrapper'
}
}
##
# @SgxEPC:
#
# Sgx EPC cmdline information
#
# @memdev: memory backend linked with device
#
# Since: 6.2
##
{ 'struct': 'SgxEPC',
'data': { 'memdev': 'str' } }
##
# @SgxEPCProperties:
#
# SGX properties of machine types.
#
# @sgx-epc: list of ids of memory-backend-epc objects.
#
# Since: 6.2
##
{ 'struct': 'SgxEPCProperties',
'data': { 'sgx-epc': ['SgxEPC'] }
}
##
# @query-memory-devices:
#

View File

@ -333,3 +333,64 @@
{ 'command': 'query-sev-attestation-report', 'data': { 'mnonce': 'str' },
'returns': 'SevAttestationReport',
'if': 'TARGET_I386' }
##
# @SGXInfo:
#
# Information about intel Safe Guard eXtension (SGX) support
#
# @sgx: true if SGX is supported
#
# @sgx1: true if SGX1 is supported
#
# @sgx2: true if SGX2 is supported
#
# @flc: true if FLC is supported
#
# @section-size: The EPC section size for guest
#
# Since: 6.2
##
{ 'struct': 'SGXInfo',
'data': { 'sgx': 'bool',
'sgx1': 'bool',
'sgx2': 'bool',
'flc': 'bool',
'section-size': 'uint64'},
'if': 'TARGET_I386' }
##
# @query-sgx:
#
# Returns information about SGX
#
# Returns: @SGXInfo
#
# Since: 6.2
#
# Example:
#
# -> { "execute": "query-sgx" }
# <- { "return": { "sgx": true, "sgx1" : true, "sgx2" : true,
# "flc": true, "section-size" : 0 } }
#
##
{ 'command': 'query-sgx', 'returns': 'SGXInfo', 'if': 'TARGET_I386' }
##
# @query-sgx-capabilities:
#
# Returns information from host SGX capabilities
#
# Returns: @SGXInfo
#
# Since: 6.2
#
# Example:
#
# -> { "execute": "query-sgx-capabilities" }
# <- { "return": { "sgx": true, "sgx1" : true, "sgx2" : true,
# "flc": true, "section-size" : 0 } }
#
##
{ 'command': 'query-sgx-capabilities', 'returns': 'SGXInfo', 'if': 'TARGET_I386' }

View File

@ -647,6 +647,23 @@
'*hugetlbsize': 'size',
'*seal': 'bool' } }
##
# @MemoryBackendEpcProperties:
#
# Properties for memory-backend-epc objects.
#
# The @share boolean option is true by default with epc
#
# The @merge boolean option is false by default with epc
#
# The @dump boolean option is false by default with epc
#
# Since: 6.2
##
{ 'struct': 'MemoryBackendEpcProperties',
'base': 'MemoryBackendProperties',
'data': {} }
##
# @PrManagerHelperProperties:
#
@ -797,6 +814,7 @@
{ 'name': 'memory-backend-memfd',
'if': 'CONFIG_LINUX' },
'memory-backend-ram',
'memory-backend-epc',
'pef-guest',
'pr-manager-helper',
'qtest',
@ -855,6 +873,7 @@
'memory-backend-memfd': { 'type': 'MemoryBackendMemfdProperties',
'if': 'CONFIG_LINUX' },
'memory-backend-ram': 'MemoryBackendProperties',
'memory-backend-epc': 'MemoryBackendEpcProperties',
'pr-manager-helper': 'PrManagerHelperProperties',
'qtest': 'QtestProperties',
'rng-builtin': 'RngProperties',

View File

@ -69,7 +69,7 @@
'*ipv4': 'bool',
'*ipv6': 'bool',
'*keep-alive': 'bool',
'*mptcp': { 'type': 'bool', 'if': 'IPPROTO_MPTCP' } } }
'*mptcp': { 'type': 'bool', 'if': 'HAVE_IPPROTO_MPTCP' } } }
##
# @UnixSocketAddress:

View File

@ -126,8 +126,14 @@ SRST
-m 512M
ERST
HXCOMM Deprecated by -machine
DEF("M", HAS_ARG, QEMU_OPTION_M, "", QEMU_ARCH_ALL)
DEF("M", HAS_ARG, QEMU_OPTION_M,
" sgx-epc.0.memdev=memid\n",
QEMU_ARCH_ALL)
SRST
``sgx-epc.0.memdev=@var{memid}``
Define an SGX EPC section.
ERST
DEF("cpu", HAS_ARG, QEMU_OPTION_cpu,
"-cpu cpu select CPU ('-cpu help' for list)\n", QEMU_ARCH_ALL)

View File

@ -1811,6 +1811,11 @@ bool memory_region_is_ram_device(MemoryRegion *mr)
return mr->ram_device;
}
bool memory_region_is_protected(MemoryRegion *mr)
{
return mr->ram && (mr->ram_block->flags & RAM_PROTECTED);
}
uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr)
{
uint8_t mask = mr->dirty_log_mask;
@ -2149,6 +2154,7 @@ static void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
}
}
flatview_unref(view);
trace_memory_region_sync_dirty(mr ? mr->name : "(all)", listener->name, 0);
} else if (listener->log_sync_global) {
/*
* No matter whether MR is specified, what we can do here
@ -2156,6 +2162,7 @@ static void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
* sync in a finer granularity.
*/
listener->log_sync_global(listener);
trace_memory_region_sync_dirty(mr ? mr->name : "(all)", listener->name, 1);
}
}
}

View File

@ -756,6 +756,7 @@ void cpu_address_space_init(CPUState *cpu, int asidx,
if (tcg_enabled()) {
newas->tcg_as_listener.log_global_after_sync = tcg_log_global_after_sync;
newas->tcg_as_listener.commit = tcg_commit;
newas->tcg_as_listener.name = "tcg";
memory_listener_register(&newas->tcg_as_listener, as);
}
}
@ -2055,7 +2056,8 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
int64_t file_size, file_align;
/* Just support these ram flags by now. */
assert((ram_flags & ~(RAM_SHARED | RAM_PMEM | RAM_NORESERVE)) == 0);
assert((ram_flags & ~(RAM_SHARED | RAM_PMEM | RAM_NORESERVE |
RAM_PROTECTED)) == 0);
if (xen_enabled()) {
error_setg(errp, "-mem-path not supported with Xen");

View File

@ -15,6 +15,7 @@ memory_region_subpage_read(int cpu_index, void *mr, uint64_t offset, uint64_t va
memory_region_subpage_write(int cpu_index, void *mr, uint64_t offset, uint64_t value, unsigned size) "cpu %d mr %p offset 0x%"PRIx64" value 0x%"PRIx64" size %u"
memory_region_ram_device_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
memory_region_ram_device_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
memory_region_sync_dirty(const char *mr, const char *listener, int global) "mr '%s' listener '%s' synced (global=%d)"
flatview_new(void *view, void *root) "%p (root %p)"
flatview_destroy(void *view, void *root) "%p (root %p)"
flatview_destroy_rcu(void *view, void *root) "%p (root %p)"

View File

@ -335,6 +335,7 @@ static void kvm_arm_devlistener_del(MemoryListener *listener,
}
static MemoryListener devlistener = {
.name = "kvm-arm",
.region_add = kvm_arm_devlistener_add,
.region_del = kvm_arm_devlistener_del,
};

View File

@ -36,6 +36,7 @@
#ifndef CONFIG_USER_ONLY
#include "exec/address-spaces.h"
#include "hw/boards.h"
#include "hw/i386/sgx-epc.h"
#endif
#include "disas/capstone.h"
@ -654,6 +655,9 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
/* missing:
CPUID_XSAVE_XSAVEC, CPUID_XSAVE_XSAVES */
#define TCG_14_0_ECX_FEATURES 0
#define TCG_SGX_12_0_EAX_FEATURES 0
#define TCG_SGX_12_0_EBX_FEATURES 0
#define TCG_SGX_12_1_EAX_FEATURES 0
FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
[FEAT_1_EDX] = {
@ -795,7 +799,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
[FEAT_7_0_EBX] = {
.type = CPUID_FEATURE_WORD,
.feat_names = {
"fsgsbase", "tsc-adjust", NULL, "bmi1",
"fsgsbase", "tsc-adjust", "sgx", "bmi1",
"hle", "avx2", NULL, "smep",
"bmi2", "erms", "invpcid", "rtm",
NULL, NULL, "mpx", NULL,
@ -821,7 +825,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
"la57", NULL, NULL, NULL,
NULL, NULL, "rdpid", NULL,
"bus-lock-detect", "cldemote", NULL, "movdiri",
"movdir64b", NULL, NULL, "pks",
"movdir64b", NULL, "sgxlc", "pks",
},
.cpuid = {
.eax = 7,
@ -1182,6 +1186,65 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
.tcg_features = TCG_14_0_ECX_FEATURES,
},
[FEAT_SGX_12_0_EAX] = {
.type = CPUID_FEATURE_WORD,
.feat_names = {
"sgx1", "sgx2", NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
},
.cpuid = {
.eax = 0x12,
.needs_ecx = true, .ecx = 0,
.reg = R_EAX,
},
.tcg_features = TCG_SGX_12_0_EAX_FEATURES,
},
[FEAT_SGX_12_0_EBX] = {
.type = CPUID_FEATURE_WORD,
.feat_names = {
"sgx-exinfo" , NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
},
.cpuid = {
.eax = 0x12,
.needs_ecx = true, .ecx = 0,
.reg = R_EBX,
},
.tcg_features = TCG_SGX_12_0_EBX_FEATURES,
},
[FEAT_SGX_12_1_EAX] = {
.type = CPUID_FEATURE_WORD,
.feat_names = {
NULL, "sgx-debug", "sgx-mode64", NULL,
"sgx-provisionkey", "sgx-tokenkey", NULL, "sgx-kss",
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
},
.cpuid = {
.eax = 0x12,
.needs_ecx = true, .ecx = 1,
.reg = R_EAX,
},
.tcg_features = TCG_SGX_12_1_EAX_FEATURES,
},
};
typedef struct FeatureMask {
@ -5272,6 +5335,25 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ecx |= CPUID_7_0_ECX_OSPKE;
}
*edx = env->features[FEAT_7_0_EDX]; /* Feature flags */
/*
* SGX cannot be emulated in software. If hardware does not
* support enabling SGX and/or SGX flexible launch control,
* then we need to update the VM's CPUID values accordingly.
*/
if ((*ebx & CPUID_7_0_EBX_SGX) &&
(!kvm_enabled() ||
!(kvm_arch_get_supported_cpuid(cs->kvm_state, 0x7, 0, R_EBX) &
CPUID_7_0_EBX_SGX))) {
*ebx &= ~CPUID_7_0_EBX_SGX;
}
if ((*ecx & CPUID_7_0_ECX_SGX_LC) &&
(!(*ebx & CPUID_7_0_EBX_SGX) || !kvm_enabled() ||
!(kvm_arch_get_supported_cpuid(cs->kvm_state, 0x7, 0, R_ECX) &
CPUID_7_0_ECX_SGX_LC))) {
*ecx &= ~CPUID_7_0_ECX_SGX_LC;
}
} else if (count == 1) {
*eax = env->features[FEAT_7_1_EAX];
*ebx = 0;
@ -5407,6 +5489,66 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
}
break;
}
case 0x12:
#ifndef CONFIG_USER_ONLY
if (!kvm_enabled() ||
!(env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_SGX)) {
*eax = *ebx = *ecx = *edx = 0;
break;
}
/*
* SGX sub-leafs CPUID.0x12.{0x2..N} enumerate EPC sections. Retrieve
* the EPC properties, e.g. confidentiality and integrity, from the
* host's first EPC section, i.e. assume there is one EPC section or
* that all EPC sections have the same security properties.
*/
if (count > 1) {
uint64_t epc_addr, epc_size;
if (sgx_epc_get_section(count - 2, &epc_addr, &epc_size)) {
*eax = *ebx = *ecx = *edx = 0;
break;
}
host_cpuid(index, 2, eax, ebx, ecx, edx);
*eax = (uint32_t)(epc_addr & 0xfffff000) | 0x1;
*ebx = (uint32_t)(epc_addr >> 32);
*ecx = (uint32_t)(epc_size & 0xfffff000) | (*ecx & 0xf);
*edx = (uint32_t)(epc_size >> 32);
break;
}
/*
* SGX sub-leafs CPUID.0x12.{0x0,0x1} are heavily dependent on hardware
* and KVM, i.e. QEMU cannot emulate features to override what KVM
* supports. Features can be further restricted by userspace, but not
* made more permissive.
*/
*eax = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x12, count, R_EAX);
*ebx = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x12, count, R_EBX);
*ecx = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x12, count, R_ECX);
*edx = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x12, count, R_EDX);
if (count == 0) {
*eax &= env->features[FEAT_SGX_12_0_EAX];
*ebx &= env->features[FEAT_SGX_12_0_EBX];
} else {
*eax &= env->features[FEAT_SGX_12_1_EAX];
*ebx &= 0; /* ebx reserve */
*ecx &= env->features[FEAT_XSAVE_COMP_LO];
*edx &= env->features[FEAT_XSAVE_COMP_HI];
/* FP and SSE are always allowed regardless of XSAVE/XCR0. */
*ecx |= XSTATE_FP_MASK | XSTATE_SSE_MASK;
/* Access to PROVISIONKEY requires additional credentials. */
if ((*eax & (1U << 4)) &&
!kvm_enable_sgx_provisioning(cs->kvm_state)) {
*eax &= ~(1U << 4);
}
}
#endif
break;
case 0x14: {
/* Intel Processor Trace Enumeration */
*eax = 0;
@ -5638,6 +5780,17 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
}
}
static void x86_cpu_set_sgxlepubkeyhash(CPUX86State *env)
{
#ifndef CONFIG_USER_ONLY
/* Those default values are defined in Skylake HW */
env->msr_ia32_sgxlepubkeyhash[0] = 0xa6053e051270b7acULL;
env->msr_ia32_sgxlepubkeyhash[1] = 0x6cfbe8ba8b3b413dULL;
env->msr_ia32_sgxlepubkeyhash[2] = 0xc4916d99f2b3735dULL;
env->msr_ia32_sgxlepubkeyhash[3] = 0xd4f8c05909f9bb3bULL;
#endif
}
static void x86_cpu_reset(DeviceState *dev)
{
CPUState *s = CPU(dev);
@ -5770,6 +5923,8 @@ static void x86_cpu_reset(DeviceState *dev)
if (kvm_enabled()) {
kvm_arch_reset_vcpu(cpu);
}
x86_cpu_set_sgxlepubkeyhash(env);
#endif
}
@ -5999,6 +6154,11 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
if (sev_enabled()) {
x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel, 0x8000001F);
}
/* SGX requires CPUID[0x12] for EPC enumeration */
if (env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_SGX) {
x86_cpu_adjust_level(cpu, &env->cpuid_min_level, 0x12);
}
}
/* Set cpuid_*level* based on cpuid_min_*level, if not explicitly set */
@ -6152,6 +6312,8 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
& CPUID_EXT2_AMD_ALIASES);
}
x86_cpu_set_sgxlepubkeyhash(env);
/*
* note: the call to the framework needs to happen after feature expansion,
* but before the checks/modifications to ucode_rev, mwait, phys_bits.
@ -6839,7 +7001,6 @@ static const TypeInfo x86_cpu_type_info = {
.class_init = x86_cpu_common_class_init,
};
/* "base" CPU model, used by query-cpu-model-expansion */
static void x86_cpu_base_class_init(ObjectClass *oc, void *data)
{

View File

@ -389,9 +389,17 @@ typedef enum X86Seg {
#define MSR_IA32_PKRS 0x6e1
#define FEATURE_CONTROL_LOCKED (1<<0)
#define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1ULL << 1)
#define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX (1<<2)
#define FEATURE_CONTROL_SGX_LC (1ULL << 17)
#define FEATURE_CONTROL_SGX (1ULL << 18)
#define FEATURE_CONTROL_LMCE (1<<20)
#define MSR_IA32_SGXLEPUBKEYHASH0 0x8c
#define MSR_IA32_SGXLEPUBKEYHASH1 0x8d
#define MSR_IA32_SGXLEPUBKEYHASH2 0x8e
#define MSR_IA32_SGXLEPUBKEYHASH3 0x8f
#define MSR_P6_PERFCTR0 0xc1
#define MSR_IA32_SMBASE 0x9e
@ -570,6 +578,9 @@ typedef enum FeatureWord {
FEAT_VMX_BASIC,
FEAT_VMX_VMFUNC,
FEAT_14_0_ECX,
FEAT_SGX_12_0_EAX, /* CPUID[EAX=0x12,ECX=0].EAX (SGX) */
FEAT_SGX_12_0_EBX, /* CPUID[EAX=0x12,ECX=0].EBX (SGX MISCSELECT[31:0]) */
FEAT_SGX_12_1_EAX, /* CPUID[EAX=0x12,ECX=1].EAX (SGX ATTRIBUTES[31:0]) */
FEATURE_WORDS,
} FeatureWord;
@ -718,6 +729,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS];
/* Support RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE */
#define CPUID_7_0_EBX_FSGSBASE (1U << 0)
/* Support SGX */
#define CPUID_7_0_EBX_SGX (1U << 2)
/* 1st Group of Advanced Bit Manipulation Extensions */
#define CPUID_7_0_EBX_BMI1 (1U << 3)
/* Hardware Lock Elision */
@ -805,6 +818,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS];
#define CPUID_7_0_ECX_MOVDIRI (1U << 27)
/* Move 64 Bytes as Direct Store Instruction */
#define CPUID_7_0_ECX_MOVDIR64B (1U << 28)
/* Support SGX Launch Control */
#define CPUID_7_0_ECX_SGX_LC (1U << 30)
/* Protection Keys for Supervisor-mode Pages */
#define CPUID_7_0_ECX_PKS (1U << 31)
@ -1501,6 +1516,7 @@ typedef struct CPUX86State {
uint64_t mcg_status;
uint64_t msr_ia32_misc_enable;
uint64_t msr_ia32_feature_control;
uint64_t msr_ia32_sgxlepubkeyhash[4];
uint64_t msr_fixed_ctr_ctrl;
uint64_t msr_global_ctrl;

View File

@ -285,6 +285,7 @@ static void hax_log_sync(MemoryListener *listener,
}
static MemoryListener hax_memory_listener = {
.name = "hax",
.begin = hax_transaction_begin,
.commit = hax_transaction_commit,
.region_add = hax_region_add,

View File

@ -1703,6 +1703,25 @@ int kvm_arch_init_vcpu(CPUState *cs)
}
break;
case 0x7:
case 0x12:
for (j = 0; ; j++) {
c->function = i;
c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
c->index = j;
cpu_x86_cpuid(env, i, j, &c->eax, &c->ebx, &c->ecx, &c->edx);
if (j > 1 && (c->eax & 0xf) != 1) {
break;
}
if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
fprintf(stderr, "cpuid_data is full, no space for "
"cpuid(eax:0x12,ecx:0x%x)\n", j);
abort();
}
c = &cpuid_data.entries[cpuid_i++];
}
break;
case 0x14: {
uint32_t times;
@ -1877,6 +1896,11 @@ int kvm_arch_init_vcpu(CPUState *cs)
!!(c->ecx & CPUID_EXT_SMX);
}
c = cpuid_find_entry(&cpuid_data.cpuid, 7, 0);
if (c && (c->ebx & CPUID_7_0_EBX_SGX)) {
has_msr_feature_control = true;
}
if (env->mcg_cap & MCG_LMCE_P) {
has_msr_mcg_ext_ctl = has_msr_feature_control = true;
}
@ -2224,7 +2248,7 @@ static void register_smram_listener(Notifier *n, void *unused)
address_space_init(&smram_address_space, &smram_as_root, "KVM-SMRAM");
kvm_memory_listener_register(kvm_state, &smram_listener,
&smram_address_space, 1);
&smram_address_space, 1, "kvm-smram");
}
int kvm_arch_init(MachineState *ms, KVMState *s)
@ -3107,6 +3131,17 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
}
}
if (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_SGX_LC) {
kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH0,
env->msr_ia32_sgxlepubkeyhash[0]);
kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH1,
env->msr_ia32_sgxlepubkeyhash[1]);
kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH2,
env->msr_ia32_sgxlepubkeyhash[2]);
kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH3,
env->msr_ia32_sgxlepubkeyhash[3]);
}
/* Note: MSR_IA32_FEATURE_CONTROL is written separately, see
* kvm_put_msr_feature_control. */
}
@ -3446,6 +3481,13 @@ static int kvm_get_msrs(X86CPU *cpu)
}
}
if (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_SGX_LC) {
kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH0, 0);
kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH1, 0);
kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH2, 0);
kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH3, 0);
}
ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, cpu->kvm_msr_buf);
if (ret < 0) {
return ret;
@ -3735,6 +3777,10 @@ static int kvm_get_msrs(X86CPU *cpu)
case MSR_IA32_RTIT_ADDR0_A ... MSR_IA32_RTIT_ADDR3_B:
env->msr_rtit_addrs[index - MSR_IA32_RTIT_ADDR0_A] = msrs[i].data;
break;
case MSR_IA32_SGXLEPUBKEYHASH0 ... MSR_IA32_SGXLEPUBKEYHASH3:
env->msr_ia32_sgxlepubkeyhash[index - MSR_IA32_SGXLEPUBKEYHASH0] =
msrs[i].data;
break;
}
}
@ -4617,6 +4663,35 @@ void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
}
}
static bool has_sgx_provisioning;
static bool __kvm_enable_sgx_provisioning(KVMState *s)
{
int fd, ret;
if (!kvm_vm_check_extension(s, KVM_CAP_SGX_ATTRIBUTE)) {
return false;
}
fd = qemu_open_old("/dev/sgx_provision", O_RDONLY);
if (fd < 0) {
return false;
}
ret = kvm_vm_enable_cap(s, KVM_CAP_SGX_ATTRIBUTE, 0, fd);
if (ret) {
error_report("Could not enable SGX PROVISIONKEY: %s", strerror(-ret));
exit(1);
}
close(fd);
return true;
}
bool kvm_enable_sgx_provisioning(KVMState *s)
{
return MEMORIZE(__kvm_enable_sgx_provisioning(s), has_sgx_provisioning);
}
static bool host_supports_vmx(void)
{
uint32_t ecx, unused;

View File

@ -51,4 +51,6 @@ bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp);
uint64_t kvm_swizzle_msi_ext_dest_id(uint64_t address);
bool kvm_enable_sgx_provisioning(KVMState *s);
#endif

View File

@ -1415,6 +1415,25 @@ static const VMStateDescription vmstate_msr_tsx_ctrl = {
}
};
static bool intel_sgx_msrs_needed(void *opaque)
{
X86CPU *cpu = opaque;
CPUX86State *env = &cpu->env;
return !!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_SGX_LC);
}
static const VMStateDescription vmstate_msr_intel_sgx = {
.name = "cpu/intel_sgx",
.version_id = 1,
.minimum_version_id = 1,
.needed = intel_sgx_msrs_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT64_ARRAY(env.msr_ia32_sgxlepubkeyhash, X86CPU, 4),
VMSTATE_END_OF_LIST()
}
};
const VMStateDescription vmstate_x86_cpu = {
.name = "cpu",
.version_id = 12,
@ -1551,6 +1570,7 @@ const VMStateDescription vmstate_x86_cpu = {
&vmstate_nested_state,
#endif
&vmstate_msr_tsx_ctrl,
&vmstate_msr_intel_sgx,
NULL
}
};

View File

@ -35,6 +35,7 @@
#include "qapi/qapi-commands-misc-target.h"
#include "qapi/qapi-commands-misc.h"
#include "hw/i386/pc.h"
#include "hw/i386/sgx.h"
/* Perform linear address sign extension */
static hwaddr addr_canonical(CPUArchState *env, hwaddr addr)
@ -763,3 +764,34 @@ qmp_query_sev_attestation_report(const char *mnonce, Error **errp)
{
return sev_get_attestation_report(mnonce, errp);
}
SGXInfo *qmp_query_sgx(Error **errp)
{
return sgx_get_info(errp);
}
void hmp_info_sgx(Monitor *mon, const QDict *qdict)
{
Error *err = NULL;
g_autoptr(SGXInfo) info = qmp_query_sgx(&err);
if (err) {
error_report_err(err);
return;
}
monitor_printf(mon, "SGX support: %s\n",
info->sgx ? "enabled" : "disabled");
monitor_printf(mon, "SGX1 support: %s\n",
info->sgx1 ? "enabled" : "disabled");
monitor_printf(mon, "SGX2 support: %s\n",
info->sgx2 ? "enabled" : "disabled");
monitor_printf(mon, "FLC support: %s\n",
info->flc ? "enabled" : "disabled");
monitor_printf(mon, "size: %" PRIu64 "\n",
info->section_size);
}
SGXInfo *qmp_query_sgx_capabilities(Error **errp)
{
return sgx_get_capabilities(errp);
}

View File

@ -1123,6 +1123,7 @@ nvmm_log_sync(MemoryListener *listener, MemoryRegionSection *section)
}
static MemoryListener nvmm_memory_listener = {
.name = "nvmm",
.begin = nvmm_transaction_begin,
.commit = nvmm_transaction_commit,
.region_add = nvmm_region_add,

View File

@ -565,7 +565,7 @@ static int
sev_read_file_base64(const char *filename, guchar **data, gsize *len)
{
gsize sz;
gchar *base64;
g_autofree gchar *base64 = NULL;
GError *error = NULL;
if (!g_file_get_contents(filename, &base64, &sz, &error)) {

View File

@ -1598,6 +1598,7 @@ static void whpx_log_sync(MemoryListener *listener,
}
static MemoryListener whpx_memory_listener = {
.name = "whpx",
.begin = whpx_transaction_begin,
.commit = whpx_transaction_commit,
.region_add = whpx_region_add,

View File

@ -68,12 +68,12 @@ qtests_i386 = \
(config_all_devices.has_key('CONFIG_RTL8139_PCI') ? ['rtl8139-test'] : []) + \
(config_all_devices.has_key('CONFIG_E1000E_PCI_EXPRESS') ? ['fuzz-e1000e-test'] : []) + \
(config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-test'] : []) + \
(unpack_edk2_blobs ? ['bios-tables-test'] : []) + \
qtests_pci + \
['fdc-test',
'ide-test',
'hd-geo-test',
'boot-order-test',
'bios-tables-test',
'rtc-test',
'i440fx-test',
'fw_cfg-test',
@ -180,7 +180,7 @@ qtests_arm = \
# TODO: once aarch64 TCG is fixed on ARM 32 bit host, make bios-tables-test unconditional
qtests_aarch64 = \
(cpu != 'arm' ? ['bios-tables-test'] : []) + \
(cpu != 'arm' and unpack_edk2_blobs ? ['bios-tables-test'] : []) + \
(config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-test'] : []) + \
(config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-swtpm-test'] : []) + \
['arm-cpu-features',
@ -269,7 +269,7 @@ foreach dir : target_dirs
qtest_emulator = emulators['qemu-system-' + target_base]
target_qtests = get_variable('qtests_' + target_base, []) + qtests_generic
test_deps = []
test_deps = roms
qtest_env = environment()
if have_tools
qtest_env.set('QTEST_QEMU_IMG', './qemu-img')

View File

@ -100,6 +100,8 @@ static bool query_is_ignored(const char *cmd)
/* Success depends on Host or Hypervisor SEV support */
"query-sev",
"query-sev-capabilities",
"query-sgx",
"query-sgx-capabilities",
NULL
};
int i;

View File

@ -278,7 +278,7 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
/* create socket + bind/listen */
for (e = res; e != NULL; e = e->ai_next) {
#ifdef IPPROTO_MPTCP
#ifdef HAVE_IPPROTO_MPTCP
if (saddr->has_mptcp && saddr->mptcp) {
e->ai_protocol = IPPROTO_MPTCP;
}
@ -462,7 +462,7 @@ int inet_connect_saddr(InetSocketAddress *saddr, Error **errp)
error_free(local_err);
local_err = NULL;
#ifdef IPPROTO_MPTCP
#ifdef HAVE_IPPROTO_MPTCP
if (saddr->has_mptcp && saddr->mptcp) {
e->ai_protocol = IPPROTO_MPTCP;
}
@ -699,7 +699,7 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp)
}
addr->has_keep_alive = true;
}
#ifdef IPPROTO_MPTCP
#ifdef HAVE_IPPROTO_MPTCP
begin = strstr(optstr, ",mptcp");
if (begin) {
if (inet_parse_flag("mptcp", begin + strlen(",mptcp"),