* 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:
commit
0021c4765a
@ -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,
|
||||
|
@ -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
82
backends/hostmem-epc.c
Normal 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);
|
@ -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')
|
||||
|
@ -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
165
docs/system/i386/sgx.rst
Normal 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
|
@ -26,6 +26,7 @@ Architectural features
|
||||
:maxdepth: 1
|
||||
|
||||
i386/cpu
|
||||
i386/sgx
|
||||
|
||||
.. _pcsys_005freq:
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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'))
|
||||
|
15
hw/i386/pc.c
15
hw/i386/pc.c
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
184
hw/i386/sgx-epc.c
Normal 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
26
hw/i386/sgx-stub.c
Normal 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
170
hw/i386/sgx.c
Normal 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);
|
||||
}
|
@ -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 = {
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
*
|
||||
|
28
include/hw/i386/hostmem-epc.h
Normal file
28
include/hw/i386/hostmem-epc.h
Normal 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
|
@ -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
67
include/hw/i386/sgx-epc.h
Normal 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
12
include/hw/i386/sgx.h
Normal 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
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
16
meson.build
16
meson.build
@ -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',
|
||||
|
@ -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')
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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:
|
||||
#
|
||||
|
@ -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' }
|
||||
|
@ -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',
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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)"
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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)) {
|
||||
|
@ -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,
|
||||
|
@ -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')
|
||||
|
@ -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;
|
||||
|
@ -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"),
|
||||
|
Loading…
Reference in New Issue
Block a user