aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/arm/cpu.c22
-rw-r--r--target/arm/monitor.c8
-rw-r--r--target/i386/hax-posix.c33
-rw-r--r--target/i386/hax-windows.c33
-rw-r--r--target/i386/sev.c106
-rw-r--r--target/i386/whp-dispatch.h9
-rw-r--r--target/i386/whpx-all.c162
-rw-r--r--target/ppc/cpu-qom.h1
-rw-r--r--target/ppc/cpu.h28
-rw-r--r--target/ppc/excp_helper.c79
-rw-r--r--target/ppc/kvm.c5
-rw-r--r--target/ppc/kvm_ppc.h7
-rw-r--r--target/ppc/mmu-hash64.c319
-rw-r--r--target/ppc/translate.c20
-rw-r--r--target/ppc/translate_init.inc.c116
-rw-r--r--target/s390x/ioinst.c2
16 files changed, 398 insertions, 552 deletions
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 0909ce86a1..3a5d1379cf 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1154,22 +1154,6 @@ static void arm_set_pmu(Object *obj, bool value, Error **errp)
cpu->has_pmu = value;
}
-static void arm_get_init_svtor(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- ARMCPU *cpu = ARM_CPU(obj);
-
- visit_type_uint32(v, name, &cpu->init_svtor, errp);
-}
-
-static void arm_set_init_svtor(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- ARMCPU *cpu = ARM_CPU(obj);
-
- visit_type_uint32(v, name, &cpu->init_svtor, errp);
-}
-
unsigned int gt_cntfrq_period_ns(ARMCPU *cpu)
{
/*
@@ -1289,9 +1273,9 @@ void arm_cpu_post_init(Object *obj)
* a simple DEFINE_PROP_UINT32 for this because we want to permit
* the property to be set after realize.
*/
- object_property_add(obj, "init-svtor", "uint32",
- arm_get_init_svtor, arm_set_init_svtor,
- NULL, NULL, &error_abort);
+ object_property_add_uint32_ptr(obj, "init-svtor",
+ &cpu->init_svtor,
+ OBJ_PROP_FLAG_READWRITE, &error_abort);
}
qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property);
diff --git a/target/arm/monitor.c b/target/arm/monitor.c
index c2dc7908de..ea6598c412 100644
--- a/target/arm/monitor.c
+++ b/target/arm/monitor.c
@@ -206,9 +206,7 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
return NULL;
}
} else {
- Error *err = NULL;
- arm_cpu_finalize_features(ARM_CPU(obj), &err);
- assert(err == NULL);
+ arm_cpu_finalize_features(ARM_CPU(obj), &error_abort);
}
expansion_info = g_new0(CpuModelExpansionInfo, 1);
@@ -221,12 +219,10 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
while ((name = cpu_model_advertised_features[i++]) != NULL) {
ObjectProperty *prop = object_property_find(obj, name, NULL);
if (prop) {
- Error *err = NULL;
QObject *value;
assert(prop->get);
- value = object_property_get_qobject(obj, name, &err);
- assert(!err);
+ value = object_property_get_qobject(obj, name, &error_abort);
qdict_put_obj(qdict_out, name, value);
}
diff --git a/target/i386/hax-posix.c b/target/i386/hax-posix.c
index a5426a6dac..3bad89f133 100644
--- a/target/i386/hax-posix.c
+++ b/target/i386/hax-posix.c
@@ -108,41 +108,12 @@ int hax_mod_version(struct hax_state *hax, struct hax_module_version *version)
static char *hax_vm_devfs_string(int vm_id)
{
- char *name;
-
- if (vm_id > MAX_VM_ID) {
- fprintf(stderr, "Too big VM id\n");
- return NULL;
- }
-
-#define HAX_VM_DEVFS "/dev/hax_vm/vmxx"
- name = g_strdup(HAX_VM_DEVFS);
- if (!name) {
- return NULL;
- }
-
- snprintf(name, sizeof HAX_VM_DEVFS, "/dev/hax_vm/vm%02d", vm_id);
- return name;
+ return g_strdup_printf("/dev/hax_vm/vm%02d", vm_id);
}
static char *hax_vcpu_devfs_string(int vm_id, int vcpu_id)
{
- char *name;
-
- if (vm_id > MAX_VM_ID || vcpu_id > MAX_VCPU_ID) {
- fprintf(stderr, "Too big vm id %x or vcpu id %x\n", vm_id, vcpu_id);
- return NULL;
- }
-
-#define HAX_VCPU_DEVFS "/dev/hax_vmxx/vcpuxx"
- name = g_strdup(HAX_VCPU_DEVFS);
- if (!name) {
- return NULL;
- }
-
- snprintf(name, sizeof HAX_VCPU_DEVFS, "/dev/hax_vm%02d/vcpu%02d",
- vm_id, vcpu_id);
- return name;
+ return g_strdup_printf("/dev/hax_vm%02d/vcpu%02d", vm_id, vcpu_id);
}
int hax_host_create_vm(struct hax_state *hax, int *vmid)
diff --git a/target/i386/hax-windows.c b/target/i386/hax-windows.c
index 5729ad9b48..0ba488c468 100644
--- a/target/i386/hax-windows.c
+++ b/target/i386/hax-windows.c
@@ -185,41 +185,12 @@ int hax_mod_version(struct hax_state *hax, struct hax_module_version *version)
static char *hax_vm_devfs_string(int vm_id)
{
- char *name;
-
- if (vm_id > MAX_VM_ID) {
- fprintf(stderr, "Too big VM id\n");
- return NULL;
- }
-
-#define HAX_VM_DEVFS "\\\\.\\hax_vmxx"
- name = g_strdup(HAX_VM_DEVFS);
- if (!name) {
- return NULL;
- }
-
- snprintf(name, sizeof HAX_VM_DEVFS, "\\\\.\\hax_vm%02d", vm_id);
- return name;
+ return g_strdup_printf("/dev/hax_vm/vm%02d", vm_id);
}
static char *hax_vcpu_devfs_string(int vm_id, int vcpu_id)
{
- char *name;
-
- if (vm_id > MAX_VM_ID || vcpu_id > MAX_VCPU_ID) {
- fprintf(stderr, "Too big vm id %x or vcpu id %x\n", vm_id, vcpu_id);
- return NULL;
- }
-
-#define HAX_VCPU_DEVFS "\\\\.\\hax_vmxx_vcpuxx"
- name = g_strdup(HAX_VCPU_DEVFS);
- if (!name) {
- return NULL;
- }
-
- snprintf(name, sizeof HAX_VCPU_DEVFS, "\\\\.\\hax_vm%02d_vcpu%02d",
- vm_id, vcpu_id);
- return name;
+ return g_strdup_printf("/dev/hax_vm%02d/vcpu%02d", vm_id, vcpu_id);
}
int hax_host_create_vm(struct hax_state *hax, int *vmid)
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 024bb24e51..846018a12d 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -267,109 +267,21 @@ qsev_guest_class_init(ObjectClass *oc, void *data)
}
static void
-qsev_guest_set_handle(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
- uint32_t value;
-
- visit_type_uint32(v, name, &value, errp);
- sev->handle = value;
-}
-
-static void
-qsev_guest_set_policy(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
- uint32_t value;
-
- visit_type_uint32(v, name, &value, errp);
- sev->policy = value;
-}
-
-static void
-qsev_guest_set_cbitpos(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
- uint32_t value;
-
- visit_type_uint32(v, name, &value, errp);
- sev->cbitpos = value;
-}
-
-static void
-qsev_guest_set_reduced_phys_bits(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
- uint32_t value;
-
- visit_type_uint32(v, name, &value, errp);
- sev->reduced_phys_bits = value;
-}
-
-static void
-qsev_guest_get_policy(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- uint32_t value;
- QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
-
- value = sev->policy;
- visit_type_uint32(v, name, &value, errp);
-}
-
-static void
-qsev_guest_get_handle(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- uint32_t value;
- QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
-
- value = sev->handle;
- visit_type_uint32(v, name, &value, errp);
-}
-
-static void
-qsev_guest_get_cbitpos(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- uint32_t value;
- QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
-
- value = sev->cbitpos;
- visit_type_uint32(v, name, &value, errp);
-}
-
-static void
-qsev_guest_get_reduced_phys_bits(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- uint32_t value;
- QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
-
- value = sev->reduced_phys_bits;
- visit_type_uint32(v, name, &value, errp);
-}
-
-static void
qsev_guest_init(Object *obj)
{
QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
sev->policy = DEFAULT_GUEST_POLICY;
- object_property_add(obj, "policy", "uint32", qsev_guest_get_policy,
- qsev_guest_set_policy, NULL, NULL, NULL);
- object_property_add(obj, "handle", "uint32", qsev_guest_get_handle,
- qsev_guest_set_handle, NULL, NULL, NULL);
- object_property_add(obj, "cbitpos", "uint32", qsev_guest_get_cbitpos,
- qsev_guest_set_cbitpos, NULL, NULL, NULL);
- object_property_add(obj, "reduced-phys-bits", "uint32",
- qsev_guest_get_reduced_phys_bits,
- qsev_guest_set_reduced_phys_bits, NULL, NULL, NULL);
+ object_property_add_uint32_ptr(obj, "policy", &sev->policy,
+ OBJ_PROP_FLAG_READWRITE, NULL);
+ object_property_add_uint32_ptr(obj, "handle", &sev->handle,
+ OBJ_PROP_FLAG_READWRITE, NULL);
+ object_property_add_uint32_ptr(obj, "cbitpos", &sev->cbitpos,
+ OBJ_PROP_FLAG_READWRITE, NULL);
+ object_property_add_uint32_ptr(obj, "reduced-phys-bits",
+ &sev->reduced_phys_bits,
+ OBJ_PROP_FLAG_READWRITE, NULL);
}
/* sev guest info */
diff --git a/target/i386/whp-dispatch.h b/target/i386/whp-dispatch.h
index 87d049ceab..e4695c349f 100644
--- a/target/i386/whp-dispatch.h
+++ b/target/i386/whp-dispatch.h
@@ -23,6 +23,12 @@
X(HRESULT, WHvGetVirtualProcessorRegisters, (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, const WHV_REGISTER_NAME* RegisterNames, UINT32 RegisterCount, WHV_REGISTER_VALUE* RegisterValues)) \
X(HRESULT, WHvSetVirtualProcessorRegisters, (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, const WHV_REGISTER_NAME* RegisterNames, UINT32 RegisterCount, const WHV_REGISTER_VALUE* RegisterValues)) \
+/*
+ * These are supplemental functions that may not be present
+ * on all versions and are not critical for basic functionality.
+ */
+#define LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(X) \
+ X(HRESULT, WHvSuspendPartitionTime, (WHV_PARTITION_HANDLE Partition)) \
#define LIST_WINHVEMULATION_FUNCTIONS(X) \
X(HRESULT, WHvEmulatorCreateEmulator, (const WHV_EMULATOR_CALLBACKS* Callbacks, WHV_EMULATOR_HANDLE* Emulator)) \
@@ -40,10 +46,12 @@
/* Define function typedef */
LIST_WINHVPLATFORM_FUNCTIONS(WHP_DEFINE_TYPE)
LIST_WINHVEMULATION_FUNCTIONS(WHP_DEFINE_TYPE)
+LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(WHP_DEFINE_TYPE)
struct WHPDispatch {
LIST_WINHVPLATFORM_FUNCTIONS(WHP_DECLARE_MEMBER)
LIST_WINHVEMULATION_FUNCTIONS(WHP_DECLARE_MEMBER)
+ LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(WHP_DECLARE_MEMBER)
};
extern struct WHPDispatch whp_dispatch;
@@ -53,6 +61,7 @@ bool init_whp_dispatch(void);
typedef enum WHPFunctionList {
WINHV_PLATFORM_FNS_DEFAULT,
WINHV_EMULATION_FNS_DEFAULT,
+ WINHV_PLATFORM_FNS_SUPPLEMENTAL
} WHPFunctionList;
#endif /* WHP_DISPATCH_H */
diff --git a/target/i386/whpx-all.c b/target/i386/whpx-all.c
index 683d49d217..c78baac6df 100644
--- a/target/i386/whpx-all.c
+++ b/target/i386/whpx-all.c
@@ -114,7 +114,6 @@ static const WHV_REGISTER_NAME whpx_register_names[] = {
WHvX64RegisterXmmControlStatus,
/* X64 MSRs */
- WHvX64RegisterTsc,
WHvX64RegisterEfer,
#ifdef TARGET_X86_64
WHvX64RegisterKernelGsBase,
@@ -215,7 +214,44 @@ static SegmentCache whpx_seg_h2q(const WHV_X64_SEGMENT_REGISTER *hs)
return qs;
}
-static void whpx_set_registers(CPUState *cpu)
+static int whpx_set_tsc(CPUState *cpu)
+{
+ struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
+ WHV_REGISTER_NAME tsc_reg = WHvX64RegisterTsc;
+ WHV_REGISTER_VALUE tsc_val;
+ HRESULT hr;
+ struct whpx_state *whpx = &whpx_global;
+
+ /*
+ * Suspend the partition prior to setting the TSC to reduce the variance
+ * in TSC across vCPUs. When the first vCPU runs post suspend, the
+ * partition is automatically resumed.
+ */
+ if (whp_dispatch.WHvSuspendPartitionTime) {
+
+ /*
+ * Unable to suspend partition while setting TSC is not a fatal
+ * error. It just increases the likelihood of TSC variance between
+ * vCPUs and some guest OS are able to handle that just fine.
+ */
+ hr = whp_dispatch.WHvSuspendPartitionTime(whpx->partition);
+ if (FAILED(hr)) {
+ warn_report("WHPX: Failed to suspend partition, hr=%08lx", hr);
+ }
+ }
+
+ tsc_val.Reg64 = env->tsc;
+ hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
+ whpx->partition, cpu->cpu_index, &tsc_reg, 1, &tsc_val);
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to set TSC, hr=%08lx", hr);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void whpx_set_registers(CPUState *cpu, int level)
{
struct whpx_state *whpx = &whpx_global;
struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
@@ -230,6 +266,14 @@ static void whpx_set_registers(CPUState *cpu)
assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
+ /*
+ * Following MSRs have side effects on the guest or are too heavy for
+ * runtime. Limit them to full state update.
+ */
+ if (level >= WHPX_SET_RESET_STATE) {
+ whpx_set_tsc(cpu);
+ }
+
memset(&vcxt, 0, sizeof(struct whpx_register_set));
v86 = (env->eflags & VM_MASK);
@@ -330,8 +374,6 @@ static void whpx_set_registers(CPUState *cpu)
idx += 1;
/* MSRs */
- assert(whpx_register_names[idx] == WHvX64RegisterTsc);
- vcxt.values[idx++].Reg64 = env->tsc;
assert(whpx_register_names[idx] == WHvX64RegisterEfer);
vcxt.values[idx++].Reg64 = env->efer;
#ifdef TARGET_X86_64
@@ -379,6 +421,25 @@ static void whpx_set_registers(CPUState *cpu)
return;
}
+static int whpx_get_tsc(CPUState *cpu)
+{
+ struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
+ WHV_REGISTER_NAME tsc_reg = WHvX64RegisterTsc;
+ WHV_REGISTER_VALUE tsc_val;
+ HRESULT hr;
+ struct whpx_state *whpx = &whpx_global;
+
+ hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
+ whpx->partition, cpu->cpu_index, &tsc_reg, 1, &tsc_val);
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to get TSC, hr=%08lx", hr);
+ return -1;
+ }
+
+ env->tsc = tsc_val.Reg64;
+ return 0;
+}
+
static void whpx_get_registers(CPUState *cpu)
{
struct whpx_state *whpx = &whpx_global;
@@ -394,6 +455,11 @@ static void whpx_get_registers(CPUState *cpu)
assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
+ if (!env->tsc_valid) {
+ whpx_get_tsc(cpu);
+ env->tsc_valid = !runstate_is_running();
+ }
+
hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
whpx->partition, cpu->cpu_index,
whpx_register_names,
@@ -492,8 +558,6 @@ static void whpx_get_registers(CPUState *cpu)
idx += 1;
/* MSRs */
- assert(whpx_register_names[idx] == WHvX64RegisterTsc);
- env->tsc = vcxt.values[idx++].Reg64;
assert(whpx_register_names[idx] == WHvX64RegisterEfer);
env->efer = vcxt.values[idx++].Reg64;
#ifdef TARGET_X86_64
@@ -841,9 +905,8 @@ static void whpx_vcpu_process_async_events(CPUState *cpu)
if ((cpu->interrupt_request & CPU_INTERRUPT_INIT) &&
!(env->hflags & HF_SMM_MASK)) {
-
+ whpx_cpu_synchronize_state(cpu);
do_cpu_init(x86_cpu);
- cpu->vcpu_dirty = true;
vcpu->interruptable = true;
}
@@ -859,17 +922,13 @@ static void whpx_vcpu_process_async_events(CPUState *cpu)
}
if (cpu->interrupt_request & CPU_INTERRUPT_SIPI) {
- if (!cpu->vcpu_dirty) {
- whpx_get_registers(cpu);
- }
+ whpx_cpu_synchronize_state(cpu);
do_cpu_sipi(x86_cpu);
}
if (cpu->interrupt_request & CPU_INTERRUPT_TPR) {
cpu->interrupt_request &= ~CPU_INTERRUPT_TPR;
- if (!cpu->vcpu_dirty) {
- whpx_get_registers(cpu);
- }
+ whpx_cpu_synchronize_state(cpu);
apic_handle_tpr_access_report(x86_cpu->apic_state, env->eip,
env->tpr_access_type);
}
@@ -896,7 +955,7 @@ static int whpx_vcpu_run(CPUState *cpu)
do {
if (cpu->vcpu_dirty) {
- whpx_set_registers(cpu);
+ whpx_set_registers(cpu, WHPX_SET_RUNTIME_STATE);
cpu->vcpu_dirty = false;
}
@@ -980,38 +1039,32 @@ static int whpx_vcpu_run(CPUState *cpu)
WHV_REGISTER_VALUE reg_values[5];
WHV_REGISTER_NAME reg_names[5];
UINT32 reg_count = 5;
- UINT64 rip, rax, rcx, rdx, rbx;
+ UINT64 cpuid_fn, rip = 0, rax = 0, rcx = 0, rdx = 0, rbx = 0;
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
memset(reg_values, 0, sizeof(reg_values));
rip = vcpu->exit_ctx.VpContext.Rip +
vcpu->exit_ctx.VpContext.InstructionLength;
- switch (vcpu->exit_ctx.CpuidAccess.Rax) {
- case 1:
- rax = vcpu->exit_ctx.CpuidAccess.DefaultResultRax;
- /* Advertise that we are running on a hypervisor */
- rcx =
- vcpu->exit_ctx.CpuidAccess.DefaultResultRcx |
- CPUID_EXT_HYPERVISOR;
-
- rdx = vcpu->exit_ctx.CpuidAccess.DefaultResultRdx;
- rbx = vcpu->exit_ctx.CpuidAccess.DefaultResultRbx;
- break;
+ cpuid_fn = vcpu->exit_ctx.CpuidAccess.Rax;
+
+ /*
+ * Ideally, these should be supplied to the hypervisor during VCPU
+ * initialization and it should be able to satisfy this request.
+ * But, currently, WHPX doesn't support setting CPUID values in the
+ * hypervisor once the partition has been setup, which is too late
+ * since VCPUs are realized later. For now, use the values from
+ * QEMU to satisfy these requests, until WHPX adds support for
+ * being able to set these values in the hypervisor at runtime.
+ */
+ cpu_x86_cpuid(env, cpuid_fn, 0, (UINT32 *)&rax, (UINT32 *)&rbx,
+ (UINT32 *)&rcx, (UINT32 *)&rdx);
+ switch (cpuid_fn) {
case 0x80000001:
- rax = vcpu->exit_ctx.CpuidAccess.DefaultResultRax;
/* Remove any support of OSVW */
- rcx =
- vcpu->exit_ctx.CpuidAccess.DefaultResultRcx &
- ~CPUID_EXT3_OSVW;
-
- rdx = vcpu->exit_ctx.CpuidAccess.DefaultResultRdx;
- rbx = vcpu->exit_ctx.CpuidAccess.DefaultResultRbx;
+ rcx &= ~CPUID_EXT3_OSVW;
break;
- default:
- rax = vcpu->exit_ctx.CpuidAccess.DefaultResultRax;
- rcx = vcpu->exit_ctx.CpuidAccess.DefaultResultRcx;
- rdx = vcpu->exit_ctx.CpuidAccess.DefaultResultRdx;
- rbx = vcpu->exit_ctx.CpuidAccess.DefaultResultRbx;
}
reg_names[0] = WHvX64RegisterRip;
@@ -1067,21 +1120,23 @@ static int whpx_vcpu_run(CPUState *cpu)
static void do_whpx_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
{
- whpx_get_registers(cpu);
- cpu->vcpu_dirty = true;
+ if (!cpu->vcpu_dirty) {
+ whpx_get_registers(cpu);
+ cpu->vcpu_dirty = true;
+ }
}
static void do_whpx_cpu_synchronize_post_reset(CPUState *cpu,
run_on_cpu_data arg)
{
- whpx_set_registers(cpu);
+ whpx_set_registers(cpu, WHPX_SET_RESET_STATE);
cpu->vcpu_dirty = false;
}
static void do_whpx_cpu_synchronize_post_init(CPUState *cpu,
run_on_cpu_data arg)
{
- whpx_set_registers(cpu);
+ whpx_set_registers(cpu, WHPX_SET_FULL_STATE);
cpu->vcpu_dirty = false;
}
@@ -1123,6 +1178,15 @@ void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu)
static Error *whpx_migration_blocker;
+static void whpx_cpu_update_state(void *opaque, int running, RunState state)
+{
+ CPUX86State *env = opaque;
+
+ if (running) {
+ env->tsc_valid = false;
+ }
+}
+
int whpx_init_vcpu(CPUState *cpu)
{
HRESULT hr;
@@ -1178,6 +1242,7 @@ int whpx_init_vcpu(CPUState *cpu)
cpu->vcpu_dirty = true;
cpu->hax_vcpu = (struct hax_vcpu_state *)vcpu;
+ qemu_add_vm_change_state_handler(whpx_cpu_update_state, cpu->env_ptr);
return 0;
}
@@ -1367,6 +1432,10 @@ static bool load_whp_dispatch_fns(HMODULE *handle,
#define WINHV_PLATFORM_DLL "WinHvPlatform.dll"
#define WINHV_EMULATION_DLL "WinHvEmulation.dll"
+ #define WHP_LOAD_FIELD_OPTIONAL(return_type, function_name, signature) \
+ whp_dispatch.function_name = \
+ (function_name ## _t)GetProcAddress(hLib, #function_name); \
+
#define WHP_LOAD_FIELD(return_type, function_name, signature) \
whp_dispatch.function_name = \
(function_name ## _t)GetProcAddress(hLib, #function_name); \
@@ -1394,6 +1463,11 @@ static bool load_whp_dispatch_fns(HMODULE *handle,
WHP_LOAD_LIB(WINHV_EMULATION_DLL, hLib)
LIST_WINHVEMULATION_FUNCTIONS(WHP_LOAD_FIELD)
break;
+
+ case WINHV_PLATFORM_FNS_SUPPLEMENTAL:
+ WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib)
+ LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(WHP_LOAD_FIELD_OPTIONAL)
+ break;
}
*handle = hLib;
@@ -1554,6 +1628,8 @@ bool init_whp_dispatch(void)
goto error;
}
+ assert(load_whp_dispatch_fns(&hWinHvPlatform,
+ WINHV_PLATFORM_FNS_SUPPLEMENTAL));
whp_dispatch_initialized = true;
return true;
diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h
index e499575dc8..15d6b54a7d 100644
--- a/target/ppc/cpu-qom.h
+++ b/target/ppc/cpu-qom.h
@@ -177,6 +177,7 @@ typedef struct PowerPCCPUClass {
uint64_t insns_flags;
uint64_t insns_flags2;
uint64_t msr_mask;
+ uint64_t lpcr_mask; /* Available bits in the LPCR */
uint64_t lpcr_pm; /* Power-saving mode Exit Cause Enable bits */
powerpc_mmu_t mmu_model;
powerpc_excp_t excp_model;
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 5fd081573e..88d9449555 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -24,8 +24,6 @@
#include "exec/cpu-defs.h"
#include "cpu-qom.h"
-/* #define PPC_EMULATE_32BITS_HYPV */
-
#define TCG_GUEST_DEFAULT_MO 0
#define TARGET_PAGE_BITS_64K 16
@@ -300,13 +298,12 @@ typedef struct ppc_v3_pate_t {
#define MSR_SF 63 /* Sixty-four-bit mode hflags */
#define MSR_TAG 62 /* Tag-active mode (POWERx ?) */
#define MSR_ISF 61 /* Sixty-four-bit interrupt mode on 630 */
-#define MSR_SHV 60 /* hypervisor state hflags */
+#define MSR_HV 60 /* hypervisor state hflags */
#define MSR_TS0 34 /* Transactional state, 2 bits (Book3s) */
#define MSR_TS1 33
#define MSR_TM 32 /* Transactional Memory Available (Book3s) */
#define MSR_CM 31 /* Computation mode for BookE hflags */
#define MSR_ICM 30 /* Interrupt computation mode for BookE */
-#define MSR_THV 29 /* hypervisor state for 32 bits PowerPC hflags */
#define MSR_GS 28 /* guest state for BookE */
#define MSR_UCLE 26 /* User-mode cache lock enable for BookE */
#define MSR_VR 25 /* altivec available x hflags */
@@ -401,10 +398,13 @@ typedef struct ppc_v3_pate_t {
#define msr_sf ((env->msr >> MSR_SF) & 1)
#define msr_isf ((env->msr >> MSR_ISF) & 1)
-#define msr_shv ((env->msr >> MSR_SHV) & 1)
+#if defined(TARGET_PPC64)
+#define msr_hv ((env->msr >> MSR_HV) & 1)
+#else
+#define msr_hv (0)
+#endif
#define msr_cm ((env->msr >> MSR_CM) & 1)
#define msr_icm ((env->msr >> MSR_ICM) & 1)
-#define msr_thv ((env->msr >> MSR_THV) & 1)
#define msr_gs ((env->msr >> MSR_GS) & 1)
#define msr_ucle ((env->msr >> MSR_UCLE) & 1)
#define msr_vr ((env->msr >> MSR_VR) & 1)
@@ -449,16 +449,9 @@ typedef struct ppc_v3_pate_t {
/* Hypervisor bit is more specific */
#if defined(TARGET_PPC64)
-#define MSR_HVB (1ULL << MSR_SHV)
-#define msr_hv msr_shv
-#else
-#if defined(PPC_EMULATE_32BITS_HYPV)
-#define MSR_HVB (1ULL << MSR_THV)
-#define msr_hv msr_thv
+#define MSR_HVB (1ULL << MSR_HV)
#else
#define MSR_HVB (0ULL)
-#define msr_hv (0)
-#endif
#endif
/* DSISR */
@@ -1051,10 +1044,6 @@ struct CPUPPCState {
uint32_t flags;
uint64_t insns_flags;
uint64_t insns_flags2;
-#if defined(TARGET_PPC64)
- ppc_slb_t vrma_slb;
- target_ulong rmls;
-#endif
int error_code;
uint32_t pending_interrupts;
@@ -1231,7 +1220,8 @@ int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, void *opaque);
#ifndef CONFIG_USER_ONLY
-void ppc_cpu_do_system_reset(CPUState *cs);
+void ppc_cpu_do_system_reset(CPUState *cs, target_ulong vector);
+void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector);
extern const VMStateDescription vmstate_ppc_cpu;
#endif
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 027f54c0ed..08bc885ca6 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -128,6 +128,37 @@ static uint64_t ppc_excp_vector_offset(CPUState *cs, int ail)
return offset;
}
+static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
+ target_ulong vector, target_ulong msr)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+
+ /*
+ * We don't use hreg_store_msr here as already have treated any
+ * special case that could occur. Just store MSR and update hflags
+ *
+ * Note: We *MUST* not use hreg_store_msr() as-is anyway because it
+ * will prevent setting of the HV bit which some exceptions might need
+ * to do.
+ */
+ env->msr = msr & env->msr_mask;
+ hreg_compute_hflags(env);
+ env->nip = vector;
+ /* Reset exception state */
+ cs->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
+
+ /* Reset the reservation */
+ env->reserve_addr = -1;
+
+ /*
+ * Any interrupt is context synchronizing, check if TCG TLB needs
+ * a delayed flush on ppc64
+ */
+ check_tlb_flush(env, false);
+}
+
/*
* Note that this function should be greatly optimized when called
* with a constant excp, from ppc_hw_interrupt
@@ -768,29 +799,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
}
}
#endif
- /*
- * We don't use hreg_store_msr here as already have treated any
- * special case that could occur. Just store MSR and update hflags
- *
- * Note: We *MUST* not use hreg_store_msr() as-is anyway because it
- * will prevent setting of the HV bit which some exceptions might need
- * to do.
- */
- env->msr = new_msr & env->msr_mask;
- hreg_compute_hflags(env);
- env->nip = vector;
- /* Reset exception state */
- cs->exception_index = POWERPC_EXCP_NONE;
- env->error_code = 0;
- /* Reset the reservation */
- env->reserve_addr = -1;
-
- /*
- * Any interrupt is context synchronizing, check if TCG TLB needs
- * a delayed flush on ppc64
- */
- check_tlb_flush(env, false);
+ powerpc_set_excp_state(cpu, vector, new_msr);
}
void ppc_cpu_do_interrupt(CPUState *cs)
@@ -951,12 +961,35 @@ static void ppc_hw_interrupt(CPUPPCState *env)
}
}
-void ppc_cpu_do_system_reset(CPUState *cs)
+void ppc_cpu_do_system_reset(CPUState *cs, target_ulong vector)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
+ if (vector != -1) {
+ env->nip = vector;
+ }
+}
+
+void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ target_ulong msr = 0;
+
+ /*
+ * Set MSR and NIP for the handler, SRR0/1, DAR and DSISR have already
+ * been set by KVM.
+ */
+ msr = (1ULL << MSR_ME);
+ msr |= env->msr & (1ULL << MSR_SF);
+ if (!(*pcc->interrupts_big_endian)(cpu)) {
+ msr |= (1ULL << MSR_LE);
+ }
+
+ powerpc_set_excp_state(cpu, vector, msr);
}
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 7f44b1aa1a..597f72be1b 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -2113,7 +2113,7 @@ void kvmppc_error_append_smt_possible_hint(Error *const *errp)
#ifdef TARGET_PPC64
-uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift)
+uint64_t kvmppc_vrma_limit(unsigned int hash_shift)
{
struct kvm_ppc_smmu_info info;
long rampagesize, best_page_shift;
@@ -2140,8 +2140,7 @@ uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift)
}
}
- return MIN(current_size,
- 1ULL << (best_page_shift + hash_shift - 7));
+ return 1ULL << (best_page_shift + hash_shift - 7);
}
#endif
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index 9e4f2357cc..332fa0aa1c 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -47,7 +47,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t page_shift,
int *pfd, bool need_vfio);
int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
int kvmppc_reset_htab(int shift_hint);
-uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift);
+uint64_t kvmppc_vrma_limit(unsigned int hash_shift);
bool kvmppc_has_cap_spapr_vfio(void);
#endif /* !CONFIG_USER_ONLY */
bool kvmppc_has_cap_epr(void);
@@ -255,10 +255,9 @@ static inline int kvmppc_reset_htab(int shift_hint)
return 0;
}
-static inline uint64_t kvmppc_rma_size(uint64_t current_size,
- unsigned int hash_shift)
+static inline uint64_t kvmppc_vrma_limit(unsigned int hash_shift)
{
- return ram_size;
+ g_assert_not_reached();
}
static inline bool kvmppc_hpt_needs_host_contiguous_pages(void)
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index da8966ccf5..34f6009b1e 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -18,6 +18,7 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
@@ -668,6 +669,21 @@ unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
return 0;
}
+static bool ppc_hash64_use_vrma(CPUPPCState *env)
+{
+ switch (env->mmu_model) {
+ case POWERPC_MMU_3_00:
+ /*
+ * ISAv3.0 (POWER9) always uses VRMA, the VPM0 field and RMOR
+ * register no longer exist
+ */
+ return true;
+
+ default:
+ return !!(env->spr[SPR_LPCR] & LPCR_VPM0);
+ }
+}
+
static void ppc_hash64_set_isi(CPUState *cs, uint64_t error_code)
{
CPUPPCState *env = &POWERPC_CPU(cs)->env;
@@ -676,15 +692,7 @@ static void ppc_hash64_set_isi(CPUState *cs, uint64_t error_code)
if (msr_ir) {
vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
} else {
- switch (env->mmu_model) {
- case POWERPC_MMU_3_00:
- /* Field deprecated in ISAv3.00 - interrupts always go to hyperv */
- vpm = true;
- break;
- default:
- vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
- break;
- }
+ vpm = ppc_hash64_use_vrma(env);
}
if (vpm && !msr_hv) {
cs->exception_index = POWERPC_EXCP_HISI;
@@ -702,15 +710,7 @@ static void ppc_hash64_set_dsi(CPUState *cs, uint64_t dar, uint64_t dsisr)
if (msr_dr) {
vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
} else {
- switch (env->mmu_model) {
- case POWERPC_MMU_3_00:
- /* Field deprecated in ISAv3.00 - interrupts always go to hyperv */
- vpm = true;
- break;
- default:
- vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
- break;
- }
+ vpm = ppc_hash64_use_vrma(env);
}
if (vpm && !msr_hv) {
cs->exception_index = POWERPC_EXCP_HDSI;
@@ -758,11 +758,67 @@ static void ppc_hash64_set_c(PowerPCCPU *cpu, hwaddr ptex, uint64_t pte1)
stb_phys(CPU(cpu)->as, base + offset, (pte1 & 0xff) | 0x80);
}
+static target_ulong rmls_limit(PowerPCCPU *cpu)
+{
+ CPUPPCState *env = &cpu->env;
+ /*
+ * In theory the meanings of RMLS values are implementation
+ * dependent. In practice, this seems to have been the set from
+ * POWER4+..POWER8, and RMLS is no longer supported in POWER9.
+ *
+ * Unsupported values mean the OS has shot itself in the
+ * foot. Return a 0-sized RMA in this case, which we expect
+ * to trigger an immediate DSI or ISI
+ */
+ static const target_ulong rma_sizes[16] = {
+ [0] = 256 * GiB,
+ [1] = 16 * GiB,
+ [2] = 1 * GiB,
+ [3] = 64 * MiB,
+ [4] = 256 * MiB,
+ [7] = 128 * MiB,
+ [8] = 32 * MiB,
+ };
+ target_ulong rmls = (env->spr[SPR_LPCR] & LPCR_RMLS) >> LPCR_RMLS_SHIFT;
+
+ return rma_sizes[rmls];
+}
+
+static int build_vrma_slbe(PowerPCCPU *cpu, ppc_slb_t *slb)
+{
+ CPUPPCState *env = &cpu->env;
+ target_ulong lpcr = env->spr[SPR_LPCR];
+ uint32_t vrmasd = (lpcr & LPCR_VRMASD) >> LPCR_VRMASD_SHIFT;
+ target_ulong vsid = SLB_VSID_VRMA | ((vrmasd << 4) & SLB_VSID_LLP_MASK);
+ int i;
+
+ for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) {
+ const PPCHash64SegmentPageSizes *sps = &cpu->hash64_opts->sps[i];
+
+ if (!sps->page_shift) {
+ break;
+ }
+
+ if ((vsid & SLB_VSID_LLP_MASK) == sps->slb_enc) {
+ slb->esid = SLB_ESID_V;
+ slb->vsid = vsid;
+ slb->sps = sps;
+ return 0;
+ }
+ }
+
+ error_report("Bad page size encoding in LPCR[VRMASD]; LPCR=0x"
+ TARGET_FMT_lx"\n", lpcr);
+
+ return -1;
+}
+
int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
int rwx, int mmu_idx)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
+ ppc_slb_t vrma_slbe;
ppc_slb_t *slb;
unsigned apshift;
hwaddr ptex;
@@ -789,27 +845,32 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
*/
raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
- /* In HV mode, add HRMOR if top EA bit is clear */
- if (msr_hv || !env->has_hv_mode) {
+ if (cpu->vhyp) {
+ /*
+ * In virtual hypervisor mode, there's nothing to do:
+ * EA == GPA == qemu guest address
+ */
+ } else if (msr_hv || !env->has_hv_mode) {
+ /* In HV mode, add HRMOR if top EA bit is clear */
if (!(eaddr >> 63)) {
raddr |= env->spr[SPR_HRMOR];
}
- } else {
- /* Otherwise, check VPM for RMA vs VRMA */
- if (env->spr[SPR_LPCR] & LPCR_VPM0) {
- slb = &env->vrma_slb;
- if (slb->sps) {
- goto skip_slb_search;
- }
- /* Not much else to do here */
+ } else if (ppc_hash64_use_vrma(env)) {
+ /* Emulated VRMA mode */
+ slb = &vrma_slbe;
+ if (build_vrma_slbe(cpu, slb) != 0) {
+ /* Invalid VRMA setup, machine check */
cs->exception_index = POWERPC_EXCP_MCHECK;
env->error_code = 0;
return 1;
- } else if (raddr < env->rmls) {
- /* RMA. Check bounds in RMLS */
- raddr |= env->spr[SPR_RMOR];
- } else {
- /* The access failed, generate the approriate interrupt */
+ }
+
+ goto skip_slb_search;
+ } else {
+ target_ulong limit = rmls_limit(cpu);
+
+ /* Emulated old-style RMO mode, bounds check against RMLS */
+ if (raddr >= limit) {
if (rwx == 2) {
ppc_hash64_set_isi(cs, SRR1_PROTFAULT);
} else {
@@ -821,6 +882,8 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
}
return 1;
}
+
+ raddr |= env->spr[SPR_RMOR];
}
tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
@@ -943,6 +1006,7 @@ skip_slb_search:
hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
{
CPUPPCState *env = &cpu->env;
+ ppc_slb_t vrma_slbe;
ppc_slb_t *slb;
hwaddr ptex, raddr;
ppc_hash_pte64_t pte;
@@ -953,22 +1017,29 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
/* In real mode the top 4 effective address bits are ignored */
raddr = addr & 0x0FFFFFFFFFFFFFFFULL;
- /* In HV mode, add HRMOR if top EA bit is clear */
- if ((msr_hv || !env->has_hv_mode) && !(addr >> 63)) {
+ if (cpu->vhyp) {
+ /*
+ * In virtual hypervisor mode, there's nothing to do:
+ * EA == GPA == qemu guest address
+ */
+ return raddr;
+ } else if ((msr_hv || !env->has_hv_mode) && !(addr >> 63)) {
+ /* In HV mode, add HRMOR if top EA bit is clear */
return raddr | env->spr[SPR_HRMOR];
- }
+ } else if (ppc_hash64_use_vrma(env)) {
+ /* Emulated VRMA mode */
+ slb = &vrma_slbe;
+ if (build_vrma_slbe(cpu, slb) != 0) {
+ return -1;
+ }
+ } else {
+ target_ulong limit = rmls_limit(cpu);
- /* Otherwise, check VPM for RMA vs VRMA */
- if (env->spr[SPR_LPCR] & LPCR_VPM0) {
- slb = &env->vrma_slb;
- if (!slb->sps) {
+ /* Emulated old-style RMO mode, bounds check against RMLS */
+ if (raddr >= limit) {
return -1;
}
- } else if (raddr < env->rmls) {
- /* RMA. Check bounds in RMLS */
return raddr | env->spr[SPR_RMOR];
- } else {
- return -1;
}
} else {
slb = slb_lookup(cpu, addr);
@@ -997,168 +1068,12 @@ void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex,
cpu->env.tlb_need_flush = TLB_NEED_GLOBAL_FLUSH | TLB_NEED_LOCAL_FLUSH;
}
-static void ppc_hash64_update_rmls(PowerPCCPU *cpu)
-{
- CPUPPCState *env = &cpu->env;
- uint64_t lpcr = env->spr[SPR_LPCR];
-
- /*
- * This is the full 4 bits encoding of POWER8. Previous
- * CPUs only support a subset of these but the filtering
- * is done when writing LPCR
- */
- switch ((lpcr & LPCR_RMLS) >> LPCR_RMLS_SHIFT) {
- case 0x8: /* 32MB */
- env->rmls = 0x2000000ull;
- break;
- case 0x3: /* 64MB */
- env->rmls = 0x4000000ull;
- break;
- case 0x7: /* 128MB */
- env->rmls = 0x8000000ull;
- break;
- case 0x4: /* 256MB */
- env->rmls = 0x10000000ull;
- break;
- case 0x2: /* 1GB */
- env->rmls = 0x40000000ull;
- break;
- case 0x1: /* 16GB */
- env->rmls = 0x400000000ull;
- break;
- default:
- /* What to do here ??? */
- env->rmls = 0;
- }
-}
-
-static void ppc_hash64_update_vrma(PowerPCCPU *cpu)
-{
- CPUPPCState *env = &cpu->env;
- const PPCHash64SegmentPageSizes *sps = NULL;
- target_ulong esid, vsid, lpcr;
- ppc_slb_t *slb = &env->vrma_slb;
- uint32_t vrmasd;
- int i;
-
- /* First clear it */
- slb->esid = slb->vsid = 0;
- slb->sps = NULL;
-
- /* Is VRMA enabled ? */
- lpcr = env->spr[SPR_LPCR];
- if (!(lpcr & LPCR_VPM0)) {
- return;
- }
-
- /*
- * Make one up. Mostly ignore the ESID which will not be needed
- * for translation
- */
- vsid = SLB_VSID_VRMA;
- vrmasd = (lpcr & LPCR_VRMASD) >> LPCR_VRMASD_SHIFT;
- vsid |= (vrmasd << 4) & (SLB_VSID_L | SLB_VSID_LP);
- esid = SLB_ESID_V;
-
- for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) {
- const PPCHash64SegmentPageSizes *sps1 = &cpu->hash64_opts->sps[i];
-
- if (!sps1->page_shift) {
- break;
- }
-
- if ((vsid & SLB_VSID_LLP_MASK) == sps1->slb_enc) {
- sps = sps1;
- break;
- }
- }
-
- if (!sps) {
- error_report("Bad page size encoding esid 0x"TARGET_FMT_lx
- " vsid 0x"TARGET_FMT_lx, esid, vsid);
- return;
- }
-
- slb->vsid = vsid;
- slb->esid = esid;
- slb->sps = sps;
-}
-
void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
{
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
CPUPPCState *env = &cpu->env;
- uint64_t lpcr = 0;
-
- /* Filter out bits */
- switch (env->mmu_model) {
- case POWERPC_MMU_64B: /* 970 */
- if (val & 0x40) {
- lpcr |= LPCR_LPES0;
- }
- if (val & 0x8000000000000000ull) {
- lpcr |= LPCR_LPES1;
- }
- if (val & 0x20) {
- lpcr |= (0x4ull << LPCR_RMLS_SHIFT);
- }
- if (val & 0x4000000000000000ull) {
- lpcr |= (0x2ull << LPCR_RMLS_SHIFT);
- }
- if (val & 0x2000000000000000ull) {
- lpcr |= (0x1ull << LPCR_RMLS_SHIFT);
- }
- env->spr[SPR_RMOR] = ((lpcr >> 41) & 0xffffull) << 26;
- /*
- * XXX We could also write LPID from HID4 here
- * but since we don't tag any translation on it
- * it doesn't actually matter
- *
- * XXX For proper emulation of 970 we also need
- * to dig HRMOR out of HID5
- */
- break;
- case POWERPC_MMU_2_03: /* P5p */
- lpcr = val & (LPCR_RMLS | LPCR_ILE |
- LPCR_LPES0 | LPCR_LPES1 |
- LPCR_RMI | LPCR_HDICE);
- break;
- case POWERPC_MMU_2_06: /* P7 */
- lpcr = val & (LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_DPFD |
- LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
- LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2 |
- LPCR_MER | LPCR_TC |
- LPCR_LPES0 | LPCR_LPES1 | LPCR_HDICE);
- break;
- case POWERPC_MMU_2_07: /* P8 */
- lpcr = val & (LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV |
- LPCR_DPFD | LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
- LPCR_AIL | LPCR_ONL | LPCR_P8_PECE0 | LPCR_P8_PECE1 |
- LPCR_P8_PECE2 | LPCR_P8_PECE3 | LPCR_P8_PECE4 |
- LPCR_MER | LPCR_TC | LPCR_LPES0 | LPCR_HDICE);
- break;
- case POWERPC_MMU_3_00: /* P9 */
- lpcr = val & (LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
- (LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
- LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | LPCR_LD |
- (LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE |
- LPCR_DEE | LPCR_OEE)) | LPCR_MER | LPCR_GTSE | LPCR_TC |
- LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE);
- /*
- * If we have a virtual hypervisor, we need to bring back RMLS. It
- * doesn't exist on an actual P9 but that's all we know how to
- * configure with softmmu at the moment
- */
- if (cpu->vhyp) {
- lpcr |= (val & LPCR_RMLS);
- }
- break;
- default:
- ;
- }
- env->spr[SPR_LPCR] = lpcr;
- ppc_hash64_update_rmls(cpu);
- ppc_hash64_update_vrma(cpu);
+ env->spr[SPR_LPCR] = val & pcc->lpcr_mask;
}
void helper_store_lpcr(CPUPPCState *env, target_ulong val)
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 36fa27367c..127c82a24e 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -1938,15 +1938,17 @@ static void gen_rlwinm(DisasContext *ctx)
me += 32;
#endif
mask = MASK(mb, me);
- if (sh == 0) {
- tcg_gen_andi_tl(t_ra, t_rs, mask);
- } else if (mask <= 0xffffffffu) {
- TCGv_i32 t0 = tcg_temp_new_i32();
- tcg_gen_trunc_tl_i32(t0, t_rs);
- tcg_gen_rotli_i32(t0, t0, sh);
- tcg_gen_andi_i32(t0, t0, mask);
- tcg_gen_extu_i32_tl(t_ra, t0);
- tcg_temp_free_i32(t0);
+ if (mask <= 0xffffffffu) {
+ if (sh == 0) {
+ tcg_gen_andi_tl(t_ra, t_rs, mask);
+ } else {
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ tcg_gen_trunc_tl_i32(t0, t_rs);
+ tcg_gen_rotli_i32(t0, t0, sh);
+ tcg_gen_andi_i32(t0, t0, mask);
+ tcg_gen_extu_i32_tl(t_ra, t0);
+ tcg_temp_free_i32(t0);
+ }
} else {
#if defined(TARGET_PPC64)
tcg_gen_deposit_i64(t_ra, t_rs, t_rs, 32, 32);
diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c
index 04ad54cff6..997c8b0b4b 100644
--- a/target/ppc/translate_init.inc.c
+++ b/target/ppc/translate_init.inc.c
@@ -7895,25 +7895,21 @@ static void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn)
{
gen_helper_store_lpcr(cpu_env, cpu_gpr[gprn]);
}
-
-static void spr_write_970_hid4(DisasContext *ctx, int sprn, int gprn)
-{
-#if defined(TARGET_PPC64)
- spr_write_generic(ctx, sprn, gprn);
- gen_helper_store_lpcr(cpu_env, cpu_gpr[gprn]);
-#endif
-}
-
#endif /* !defined(CONFIG_USER_ONLY) */
static void gen_spr_970_lpar(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
- /* Logical partitionning */
- /* PPC970: HID4 is effectively the LPCR */
+ /*
+ * PPC970: HID4 covers things later controlled by the LPCR and
+ * RMOR in later CPUs, but with a different encoding. We only
+ * support the 970 in "Apple mode" which has all hypervisor
+ * facilities disabled by strapping, so we can basically just
+ * ignore it
+ */
spr_register(env, SPR_970_HID4, "HID4",
SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_970_hid4,
+ &spr_read_generic, &spr_write_generic,
0x00000000);
#endif
}
@@ -8019,12 +8015,16 @@ static void gen_spr_book3s_ids(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
- spr_register_hv(env, SPR_RMOR, "RMOR",
+ spr_register_hv(env, SPR_HRMOR, "HRMOR",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
- spr_register_hv(env, SPR_HRMOR, "HRMOR",
+}
+
+static void gen_spr_rmor(CPUPPCState *env)
+{
+ spr_register_hv(env, SPR_RMOR, "RMOR",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
@@ -8476,6 +8476,8 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
(1ull << MSR_DR) |
(1ull << MSR_PMM) |
(1ull << MSR_RI);
+ pcc->lpcr_mask = LPCR_RMLS | LPCR_ILE | LPCR_LPES0 | LPCR_LPES1 |
+ LPCR_RMI | LPCR_HDICE;
pcc->mmu_model = POWERPC_MMU_2_03;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
@@ -8492,44 +8494,6 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
pcc->l1_icache_size = 0x10000;
}
-/*
- * The CPU used to have a "compat" property which set the
- * compatibility mode PVR. However, this was conceptually broken - it
- * only makes sense on the pseries machine type (otherwise the guest
- * owns the PCR and can control the compatibility mode itself). It's
- * been replaced with the 'max-cpu-compat' property on the pseries
- * machine type. For backwards compatibility, pseries specially
- * parses the -cpu parameter and converts old compat= parameters into
- * the appropriate machine parameters. This stub implementation of
- * the parameter catches any uses on explicitly created CPUs.
- */
-static void getset_compat_deprecated(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- QNull *null = NULL;
-
- if (!qtest_enabled()) {
- warn_report("CPU 'compat' property is deprecated and has no effect; "
- "use max-cpu-compat machine property instead");
- }
- visit_type_null(v, name, &null, NULL);
- qobject_unref(null);
-}
-
-static const PropertyInfo ppc_compat_deprecated_propinfo = {
- .name = "str",
- .description = "compatibility mode (deprecated)",
- .get = getset_compat_deprecated,
- .set = getset_compat_deprecated,
-};
-static Property powerpc_servercpu_properties[] = {
- {
- .name = "compat",
- .info = &ppc_compat_deprecated_propinfo,
- },
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void init_proc_POWER7(CPUPPCState *env)
{
/* Common Registers */
@@ -8539,6 +8503,7 @@ static void init_proc_POWER7(CPUPPCState *env)
/* POWER7 Specific Registers */
gen_spr_book3s_ids(env);
+ gen_spr_rmor(env);
gen_spr_amr(env);
gen_spr_book3s_purr(env);
gen_spr_power5p_common(env);
@@ -8611,7 +8576,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
dc->fw_name = "PowerPC,POWER7";
dc->desc = "POWER7";
- device_class_set_props(dc, powerpc_servercpu_properties);
pcc->pvr_match = ppc_pvr_match_power7;
pcc->pcr_mask = PCR_VEC_DIS | PCR_VSX_DIS | PCR_COMPAT_2_05;
pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
@@ -8652,6 +8616,12 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
(1ull << MSR_PMM) |
(1ull << MSR_RI) |
(1ull << MSR_LE);
+ pcc->lpcr_mask = LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_DPFD |
+ LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
+ LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2 |
+ LPCR_MER | LPCR_TC |
+ LPCR_LPES0 | LPCR_LPES1 | LPCR_HDICE;
+ pcc->lpcr_pm = LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2;
pcc->mmu_model = POWERPC_MMU_2_06;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
@@ -8668,7 +8638,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
- pcc->lpcr_pm = LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2;
}
static void init_proc_POWER8(CPUPPCState *env)
@@ -8680,6 +8649,7 @@ static void init_proc_POWER8(CPUPPCState *env)
/* POWER8 Specific Registers */
gen_spr_book3s_ids(env);
+ gen_spr_rmor(env);
gen_spr_amr(env);
gen_spr_iamr(env);
gen_spr_book3s_purr(env);
@@ -8776,7 +8746,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
dc->fw_name = "PowerPC,POWER8";
dc->desc = "POWER8";
- device_class_set_props(dc, powerpc_servercpu_properties);
pcc->pvr_match = ppc_pvr_match_power8;
pcc->pcr_mask = PCR_TM_DIS | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
@@ -8804,7 +8773,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
PPC2_TM | PPC2_PM_ISA206;
pcc->msr_mask = (1ull << MSR_SF) |
- (1ull << MSR_SHV) |
+ (1ull << MSR_HV) |
(1ull << MSR_TM) |
(1ull << MSR_VR) |
(1ull << MSR_VSX) |
@@ -8823,6 +8792,13 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
(1ull << MSR_TS0) |
(1ull << MSR_TS1) |
(1ull << MSR_LE);
+ pcc->lpcr_mask = LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV |
+ LPCR_DPFD | LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
+ LPCR_AIL | LPCR_ONL | LPCR_P8_PECE0 | LPCR_P8_PECE1 |
+ LPCR_P8_PECE2 | LPCR_P8_PECE3 | LPCR_P8_PECE4 |
+ LPCR_MER | LPCR_TC | LPCR_LPES0 | LPCR_HDICE;
+ pcc->lpcr_pm = LPCR_P8_PECE0 | LPCR_P8_PECE1 | LPCR_P8_PECE2 |
+ LPCR_P8_PECE3 | LPCR_P8_PECE4;
pcc->mmu_model = POWERPC_MMU_2_07;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
@@ -8840,8 +8816,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
- pcc->lpcr_pm = LPCR_P8_PECE0 | LPCR_P8_PECE1 | LPCR_P8_PECE2 |
- LPCR_P8_PECE3 | LPCR_P8_PECE4;
}
#ifdef CONFIG_SOFTMMU
@@ -8988,7 +8962,6 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
dc->fw_name = "PowerPC,POWER9";
dc->desc = "POWER9";
- device_class_set_props(dc, powerpc_servercpu_properties);
pcc->pvr_match = ppc_pvr_match_power9;
pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06 | PCR_COMPAT_2_07;
pcc->pcr_supported = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 |
@@ -9017,7 +8990,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL;
pcc->msr_mask = (1ull << MSR_SF) |
- (1ull << MSR_SHV) |
+ (1ull << MSR_HV) |
(1ull << MSR_TM) |
(1ull << MSR_VR) |
(1ull << MSR_VSX) |
@@ -9034,6 +9007,14 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
(1ull << MSR_PMM) |
(1ull << MSR_RI) |
(1ull << MSR_LE);
+ pcc->lpcr_mask = LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
+ (LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
+ LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | LPCR_LD |
+ (LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE |
+ LPCR_DEE | LPCR_OEE))
+ | LPCR_MER | LPCR_GTSE | LPCR_TC |
+ LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE;
+ pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
pcc->mmu_model = POWERPC_MMU_3_00;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc64_v3_handle_mmu_fault;
@@ -9053,7 +9034,6 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
- pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
}
#ifdef CONFIG_SOFTMMU
@@ -9198,7 +9178,6 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
dc->fw_name = "PowerPC,POWER10";
dc->desc = "POWER10";
- device_class_set_props(dc, powerpc_servercpu_properties);
pcc->pvr_match = ppc_pvr_match_power10;
pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06 | PCR_COMPAT_2_07 |
PCR_COMPAT_3_00;
@@ -9228,7 +9207,7 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL;
pcc->msr_mask = (1ull << MSR_SF) |
- (1ull << MSR_SHV) |
+ (1ull << MSR_HV) |
(1ull << MSR_TM) |
(1ull << MSR_VR) |
(1ull << MSR_VSX) |
@@ -9245,6 +9224,14 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
(1ull << MSR_PMM) |
(1ull << MSR_RI) |
(1ull << MSR_LE);
+ pcc->lpcr_mask = LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
+ (LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
+ LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | LPCR_LD |
+ (LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE |
+ LPCR_DEE | LPCR_OEE))
+ | LPCR_MER | LPCR_GTSE | LPCR_TC |
+ LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE;
+ pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
pcc->mmu_model = POWERPC_MMU_3_00;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc64_v3_handle_mmu_fault;
@@ -9263,7 +9250,6 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
- pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
}
#if !defined(CONFIG_USER_ONLY)
@@ -10492,6 +10478,8 @@ static void ppc_cpu_parse_featurestr(const char *type, char *features,
*s = '\0';
for (i = 0; inpieces[i]; i++) {
if (g_str_has_prefix(inpieces[i], "compat=")) {
+ warn_report_once("CPU 'compat' property is deprecated; "
+ "use max-cpu-compat machine property instead");
compat_str = inpieces[i];
continue;
}
diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c
index c437a1d8c6..0e840cc579 100644
--- a/target/s390x/ioinst.c
+++ b/target/s390x/ioinst.c
@@ -347,7 +347,7 @@ typedef struct ChscResp {
uint16_t len;
uint16_t code;
uint32_t param;
- char data[0];
+ char data[];
} QEMU_PACKED ChscResp;
#define CHSC_MIN_RESP_LEN 0x0008