summaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/arm/kvm.c1
-rw-r--r--target/i386/cpu.c167
-rw-r--r--target/i386/cpu.h16
-rw-r--r--target/i386/hax/hax-mem.c1
-rw-r--r--target/i386/kvm/kvm.c77
-rw-r--r--target/i386/kvm/kvm_i386.h2
-rw-r--r--target/i386/machine.c20
-rw-r--r--target/i386/monitor.c32
-rw-r--r--target/i386/nvmm/nvmm-all.c1
-rw-r--r--target/i386/sev.c2
-rw-r--r--target/i386/whpx/whpx-all.c1
-rw-r--r--target/ppc/cpu.h1
-rw-r--r--target/ppc/excp_helper.c38
-rw-r--r--target/ppc/helper_regs.c3
-rw-r--r--target/ppc/int_helper.c61
-rw-r--r--target/ppc/trace-events8
-rw-r--r--target/ppc/translate.c28
17 files changed, 408 insertions, 51 deletions
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 94b970bbf9..bbf1ce7ba3 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -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,
};
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 6b029f1bdf..cacec605bf 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -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)
{
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index c2954c71ea..29552dc2a7 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -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;
diff --git a/target/i386/hax/hax-mem.c b/target/i386/hax/hax-mem.c
index 8d44edbffd..a226d174d8 100644
--- a/target/i386/hax/hax-mem.c
+++ b/target/i386/hax/hax-mem.c
@@ -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,
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 500d2e0e68..7f1b060e6d 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -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;
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index 54667b35f0..a978509d50 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -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
diff --git a/target/i386/machine.c b/target/i386/machine.c
index b0943118d1..4367931623 100644
--- a/target/i386/machine.c
+++ b/target/i386/machine.c
@@ -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
}
};
diff --git a/target/i386/monitor.c b/target/i386/monitor.c
index 119211f0b0..196c1c9e77 100644
--- a/target/i386/monitor.c
+++ b/target/i386/monitor.c
@@ -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);
+}
diff --git a/target/i386/nvmm/nvmm-all.c b/target/i386/nvmm/nvmm-all.c
index a488b00e90..14c996f968 100644
--- a/target/i386/nvmm/nvmm-all.c
+++ b/target/i386/nvmm/nvmm-all.c
@@ -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,
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 0b2c8f594a..fa7210473a 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -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)) {
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index 3e925b9da7..ef896da0a2 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -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,
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 01d3773bc7..baa4e7c34d 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -600,6 +600,7 @@ enum {
HFLAGS_64 = 2, /* computed from MSR_CE and MSR_SF */
HFLAGS_GTSE = 3, /* computed from SPR_LPCR[GTSE] */
HFLAGS_DR = 4, /* MSR_DR */
+ HFLAGS_HR = 5, /* computed from SPR_LPCR[HR] */
HFLAGS_SPE = 6, /* from MSR_SPE if cpu has SPE; avoid overlap w/ MSR_VR */
HFLAGS_TM = 8, /* computed from MSR_TM */
HFLAGS_BE = 9, /* MSR_BE -- from elsewhere on embedded ppc */
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index d7e32ee107..b7d1767920 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -23,20 +23,14 @@
#include "internal.h"
#include "helper_regs.h"
+#include "trace.h"
+
#ifdef CONFIG_TCG
#include "exec/helper-proto.h"
#include "exec/cpu_ldst.h"
#endif
-/* #define DEBUG_OP */
/* #define DEBUG_SOFTWARE_TLB */
-/* #define DEBUG_EXCEPTIONS */
-
-#ifdef DEBUG_EXCEPTIONS
-# define LOG_EXCP(...) qemu_log(__VA_ARGS__)
-#else
-# define LOG_EXCP(...) do { } while (0)
-#endif
/*****************************************************************************/
/* Exception processing */
@@ -414,12 +408,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
}
break;
case POWERPC_EXCP_DSI: /* Data storage exception */
- LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
- "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+ trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
break;
case POWERPC_EXCP_ISI: /* Instruction storage exception */
- LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
- "\n", msr, env->nip);
+ trace_ppc_excp_isi(msr, env->nip);
msr |= env->error_code;
break;
case POWERPC_EXCP_EXTERNAL: /* External input */
@@ -474,7 +466,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
switch (env->error_code & ~0xF) {
case POWERPC_EXCP_FP:
if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
- LOG_EXCP("Ignore floating point exception\n");
+ trace_ppc_excp_fp_ignore();
cs->exception_index = POWERPC_EXCP_NONE;
env->error_code = 0;
return;
@@ -489,7 +481,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
env->spr[SPR_BOOKE_ESR] = ESR_FP;
break;
case POWERPC_EXCP_INVAL:
- LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
+ trace_ppc_excp_inval(env->nip);
msr |= 0x00080000;
env->spr[SPR_BOOKE_ESR] = ESR_PIL;
break;
@@ -547,10 +539,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
break;
case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
/* FIT on 4xx */
- LOG_EXCP("FIT exception\n");
+ trace_ppc_excp_print("FIT");
break;
case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
- LOG_EXCP("WDT exception\n");
+ trace_ppc_excp_print("WDT");
switch (excp_model) {
case POWERPC_EXCP_BOOKE:
srr0 = SPR_BOOKE_CSRR0;
@@ -657,7 +649,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
#endif
break;
case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
- LOG_EXCP("PIT exception\n");
+ trace_ppc_excp_print("PIT");
break;
case POWERPC_EXCP_IO: /* IO error exception */
/* XXX: TODO */
@@ -1115,14 +1107,6 @@ bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
#endif /* !CONFIG_USER_ONLY */
-#if defined(DEBUG_OP)
-static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
-{
- qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
- TARGET_FMT_lx "\n", RA, msr);
-}
-#endif
-
/*****************************************************************************/
/* Exceptions processing helpers */
@@ -1221,9 +1205,7 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
/* XXX: beware: this is false if VLE is supported */
env->nip = nip & ~((target_ulong)0x00000003);
hreg_store_msr(env, msr, 1);
-#if defined(DEBUG_OP)
- cpu_dump_rfi(env->nip, env->msr);
-#endif
+ trace_ppc_excp_rfi(env->nip, env->msr);
/*
* No need to raise an exception here, as rfi is always the last
* insn of a TB
diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
index 405450d863..1bfb480ecf 100644
--- a/target/ppc/helper_regs.c
+++ b/target/ppc/helper_regs.c
@@ -106,6 +106,9 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
if (env->spr[SPR_LPCR] & LPCR_GTSE) {
hflags |= 1 << HFLAGS_GTSE;
}
+ if (env->spr[SPR_LPCR] & LPCR_HR) {
+ hflags |= 1 << HFLAGS_HR;
+ }
#ifndef CONFIG_USER_ONLY
if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) {
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index c2d3248d1e..f5dac3aa87 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -2480,10 +2480,26 @@ uint32_t helper_bcdctz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
return cr;
}
+/**
+ * Compare 2 128-bit unsigned integers, passed in as unsigned 64-bit pairs
+ *
+ * Returns:
+ * > 0 if ahi|alo > bhi|blo,
+ * 0 if ahi|alo == bhi|blo,
+ * < 0 if ahi|alo < bhi|blo
+ */
+static inline int ucmp128(uint64_t alo, uint64_t ahi,
+ uint64_t blo, uint64_t bhi)
+{
+ return (ahi == bhi) ?
+ (alo > blo ? 1 : (alo == blo ? 0 : -1)) :
+ (ahi > bhi ? 1 : -1);
+}
+
uint32_t helper_bcdcfsq(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
{
int i;
- int cr = 0;
+ int cr;
uint64_t lo_value;
uint64_t hi_value;
ppc_avr_t ret = { .u64 = { 0, 0 } };
@@ -2492,28 +2508,47 @@ uint32_t helper_bcdcfsq(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
lo_value = -b->VsrSD(1);
hi_value = ~b->VsrD(0) + !lo_value;
bcd_put_digit(&ret, 0xD, 0);
+
+ cr = CRF_LT;
} else {
lo_value = b->VsrD(1);
hi_value = b->VsrD(0);
bcd_put_digit(&ret, bcd_preferred_sgn(0, ps), 0);
- }
- if (divu128(&lo_value, &hi_value, 1000000000000000ULL) ||
- lo_value > 9999999999999999ULL) {
- cr = CRF_SO;
+ if (hi_value == 0 && lo_value == 0) {
+ cr = CRF_EQ;
+ } else {
+ cr = CRF_GT;
+ }
}
- for (i = 1; i < 16; hi_value /= 10, i++) {
- bcd_put_digit(&ret, hi_value % 10, i);
- }
+ /*
+ * Check src limits: abs(src) <= 10^31 - 1
+ *
+ * 10^31 - 1 = 0x0000007e37be2022 c0914b267fffffff
+ */
+ if (ucmp128(lo_value, hi_value,
+ 0xc0914b267fffffffULL, 0x7e37be2022ULL) > 0) {
+ cr |= CRF_SO;
- for (; i < 32; lo_value /= 10, i++) {
- bcd_put_digit(&ret, lo_value % 10, i);
- }
+ /*
+ * According to the ISA, if src wouldn't fit in the destination
+ * register, the result is undefined.
+ * In that case, we leave r unchanged.
+ */
+ } else {
+ divu128(&lo_value, &hi_value, 1000000000000000ULL);
- cr |= bcd_cmp_zero(&ret);
+ for (i = 1; i < 16; hi_value /= 10, i++) {
+ bcd_put_digit(&ret, hi_value % 10, i);
+ }
- *r = ret;
+ for (; i < 32; lo_value /= 10, i++) {
+ bcd_put_digit(&ret, lo_value % 10, i);
+ }
+
+ *r = ret;
+ }
return cr;
}
diff --git a/target/ppc/trace-events b/target/ppc/trace-events
index c88cfccf8d..53b107f56e 100644
--- a/target/ppc/trace-events
+++ b/target/ppc/trace-events
@@ -28,3 +28,11 @@ kvm_handle_epr(void) "handle epr"
kvm_handle_watchdog_expiry(void) "handle watchdog expiry"
kvm_handle_debug_exception(void) "handle debug exception"
kvm_handle_nmi_exception(void) "handle NMI exception"
+
+# excp_helper.c
+ppc_excp_rfi(uint64_t nip, uint64_t msr) "Return from exception at 0x%" PRIx64 " with flags 0x%016" PRIx64
+ppc_excp_dsi(uint64_t dsisr, uint64_t dar) "DSI exception: DSISR=0x%" PRIx64 " DAR=0x%" PRIx64
+ppc_excp_isi(uint64_t msr, uint64_t nip) "ISI exception: msr=0x%016" PRIx64 " nip=0x%" PRIx64
+ppc_excp_fp_ignore(void) "Ignore floating point exception"
+ppc_excp_inval(uint64_t nip) "Invalid instruction at 0x%" PRIx64
+ppc_excp_print(const char *excp) "%s exception"
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 5d8b06bd80..b985e9e55b 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -175,6 +175,7 @@ struct DisasContext {
bool spe_enabled;
bool tm_enabled;
bool gtse;
+ bool hr;
ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
int singlestep_enabled;
uint32_t flags;
@@ -5516,7 +5517,15 @@ static void gen_tlbiel(DisasContext *ctx)
#if defined(CONFIG_USER_ONLY)
GEN_PRIV;
#else
- CHK_SV;
+ bool psr = (ctx->opcode >> 17) & 0x1;
+
+ if (ctx->pr || (!ctx->hv && !psr && ctx->hr)) {
+ /*
+ * tlbiel is privileged except when PSR=0 and HR=1, making it
+ * hypervisor privileged.
+ */
+ GEN_PRIV;
+ }
gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]);
#endif /* defined(CONFIG_USER_ONLY) */
@@ -5528,12 +5537,20 @@ static void gen_tlbie(DisasContext *ctx)
#if defined(CONFIG_USER_ONLY)
GEN_PRIV;
#else
+ bool psr = (ctx->opcode >> 17) & 0x1;
TCGv_i32 t1;
- if (ctx->gtse) {
- CHK_SV; /* If gtse is set then tlbie is supervisor privileged */
- } else {
- CHK_HV; /* Else hypervisor privileged */
+ if (ctx->pr) {
+ /* tlbie is privileged... */
+ GEN_PRIV;
+ } else if (!ctx->hv) {
+ if (!ctx->gtse || (!psr && ctx->hr)) {
+ /*
+ * ... except when GTSE=0 or when PSR=0 and HR=1, making it
+ * hypervisor privileged.
+ */
+ GEN_PRIV;
+ }
}
if (NARROW_MODE(ctx)) {
@@ -8539,6 +8556,7 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->vsx_enabled = (hflags >> HFLAGS_VSX) & 1;
ctx->tm_enabled = (hflags >> HFLAGS_TM) & 1;
ctx->gtse = (hflags >> HFLAGS_GTSE) & 1;
+ ctx->hr = (hflags >> HFLAGS_HR) & 1;
ctx->singlestep_enabled = 0;
if ((hflags >> HFLAGS_SE) & 1) {