aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc/spapr_hcall.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/ppc/spapr_hcall.c')
-rw-r--r--hw/ppc/spapr_hcall.c70
1 files changed, 29 insertions, 41 deletions
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index c5e7e8c995..7c46d4625b 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -11,6 +11,7 @@
#include "trace.h"
#include "sysemu/kvm.h"
#include "kvm_ppc.h"
+#include "hw/ppc/spapr_ovec.h"
struct SPRSyncState {
int spr;
@@ -880,32 +881,6 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return ret;
}
-/*
- * Return the offset to the requested option vector @vector in the
- * option vector table @table.
- */
-static target_ulong cas_get_option_vector(int vector, target_ulong table)
-{
- int i;
- char nr_vectors, nr_entries;
-
- if (!table) {
- return 0;
- }
-
- nr_vectors = (ldl_phys(&address_space_memory, table) >> 24) + 1;
- if (!vector || vector > nr_vectors) {
- return 0;
- }
- table++; /* skip nr option vectors */
-
- for (i = 0; i < vector - 1; i++) {
- nr_entries = ldl_phys(&address_space_memory, table) >> 24;
- table += nr_entries + 2;
- }
- return table;
-}
-
typedef struct {
uint32_t cpu_version;
Error *err;
@@ -961,23 +936,21 @@ static void cas_handle_compat_cpu(PowerPCCPUClass *pcc, uint32_t pvr,
}
}
-#define OV5_DRCONF_MEMORY 0x20
-
static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
sPAPRMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
target_ulong list = ppc64_phys_to_real(args[0]);
- target_ulong ov_table, ov5;
+ target_ulong ov_table;
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu_);
CPUState *cs;
- bool cpu_match = false, cpu_update = true, memory_update = false;
+ bool cpu_match = false, cpu_update = true;
unsigned old_cpu_version = cpu_->cpu_version;
unsigned compat_lvl = 0, cpu_version = 0;
unsigned max_lvl = get_compat_level(cpu_->max_compat);
int counter;
- char ov5_byte2;
+ sPAPROptionVector *ov5_guest, *ov5_cas_old, *ov5_updates;
/* Parse PVR list */
for (counter = 0; counter < 512; ++counter) {
@@ -1033,19 +1006,34 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
/* For the future use: here @ov_table points to the first option vector */
ov_table = list;
- ov5 = cas_get_option_vector(5, ov_table);
- if (!ov5) {
- return H_SUCCESS;
- }
+ ov5_guest = spapr_ovec_parse_vector(ov_table, 5);
+
+ /* NOTE: there are actually a number of ov5 bits where input from the
+ * guest is always zero, and the platform/QEMU enables them independently
+ * of guest input. To model these properly we'd want some sort of mask,
+ * but since they only currently apply to memory migration as defined
+ * by LoPAPR 1.1, 14.5.4.8, which QEMU doesn't implement, we don't need
+ * to worry about this for now.
+ */
+ ov5_cas_old = spapr_ovec_clone(spapr->ov5_cas);
+ /* full range of negotiated ov5 capabilities */
+ spapr_ovec_intersect(spapr->ov5_cas, spapr->ov5, ov5_guest);
+ spapr_ovec_cleanup(ov5_guest);
+ /* capabilities that have been added since CAS-generated guest reset.
+ * if capabilities have since been removed, generate another reset
+ */
+ ov5_updates = spapr_ovec_new();
+ spapr->cas_reboot = spapr_ovec_diff(ov5_updates,
+ ov5_cas_old, spapr->ov5_cas);
- /* @list now points to OV 5 */
- ov5_byte2 = ldub_phys(&address_space_memory, ov5 + 2);
- if (ov5_byte2 & OV5_DRCONF_MEMORY) {
- memory_update = true;
+ if (!spapr->cas_reboot) {
+ spapr->cas_reboot =
+ (spapr_h_cas_compose_response(spapr, args[1], args[2], cpu_update,
+ ov5_updates) != 0);
}
+ spapr_ovec_cleanup(ov5_updates);
- if (spapr_h_cas_compose_response(spapr, args[1], args[2],
- cpu_update, memory_update)) {
+ if (spapr->cas_reboot) {
qemu_system_reset_request();
}