diff options
Diffstat (limited to 'target')
-rw-r--r-- | target/arm/cpu.c | 22 | ||||
-rw-r--r-- | target/arm/monitor.c | 8 | ||||
-rw-r--r-- | target/i386/hax-posix.c | 33 | ||||
-rw-r--r-- | target/i386/hax-windows.c | 33 | ||||
-rw-r--r-- | target/i386/sev.c | 106 | ||||
-rw-r--r-- | target/i386/whp-dispatch.h | 9 | ||||
-rw-r--r-- | target/i386/whpx-all.c | 162 | ||||
-rw-r--r-- | target/ppc/cpu-qom.h | 1 | ||||
-rw-r--r-- | target/ppc/cpu.h | 28 | ||||
-rw-r--r-- | target/ppc/excp_helper.c | 79 | ||||
-rw-r--r-- | target/ppc/kvm.c | 5 | ||||
-rw-r--r-- | target/ppc/kvm_ppc.h | 7 | ||||
-rw-r--r-- | target/ppc/mmu-hash64.c | 319 | ||||
-rw-r--r-- | target/ppc/translate.c | 20 | ||||
-rw-r--r-- | target/ppc/translate_init.inc.c | 116 | ||||
-rw-r--r-- | target/s390x/ioinst.c | 2 |
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 |