Interception of the PTF instruction depending on the new
KVM_CAP_S390_CPU_TOPOLOGY KVM extension.
A global value is used to remember if a Topology change occured since
the last interception of a PTF instruction with function code 0.
Signed-off-by: Pierre Morel <pmorel@linux.ibm.com>
---
hw/s390x/cpu-topology.c | 19 +++++++++++
include/hw/s390x/cpu-topology.h | 8 +++++
include/hw/s390x/s390-virtio-ccw.h | 1 +
target/s390x/cpu.c | 4 +++
target/s390x/cpu.h | 1 +
target/s390x/kvm/kvm.c | 52 ++++++++++++++++++++++++++++++
6 files changed, 85 insertions(+)
diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c
index 1224137f56..5e1cac9529 100644
--- a/hw/s390x/cpu-topology.c
+++ b/hw/s390x/cpu-topology.c
@@ -19,12 +19,25 @@
#include "qemu/typedefs.h"
#include "hw/s390x/s390-virtio-ccw.h"
+int s390_topology_changed(void)
+{
+ const MachineState *ms = MACHINE(qdev_get_machine());
+ S390CcwMachineState *s390ms = S390_CCW_MACHINE(ms);
+
+ if (s390ms->topology_changed) {
+ s390ms->topology_changed = 0;
+ return 1;
+ }
+ return 0;
+}
+
static S390TopologyCores *s390_create_cores(S390TopologySocket *socket,
int origin)
{
DeviceState *dev;
S390TopologyCores *cores;
const MachineState *ms = MACHINE(qdev_get_machine());
+ S390CcwMachineState *s390ms = S390_CCW_MACHINE(ms);
if (socket->bus->num_children >= ms->smp.cores) {
return NULL;
@@ -36,6 +49,7 @@ static S390TopologyCores *s390_create_cores(S390TopologySocket *socket,
cores = S390_TOPOLOGY_CORES(dev);
cores->origin = origin;
socket->cnt += 1;
+ s390ms->topology_changed = 1;
return cores;
}
@@ -45,6 +59,7 @@ static S390TopologySocket *s390_create_socket(S390TopologyBook *book, int id)
DeviceState *dev;
S390TopologySocket *socket;
const MachineState *ms = MACHINE(qdev_get_machine());
+ S390CcwMachineState *s390ms = S390_CCW_MACHINE(ms);
if (book->bus->num_children >= ms->smp.sockets) {
return NULL;
@@ -56,6 +71,7 @@ static S390TopologySocket *s390_create_socket(S390TopologyBook *book, int id)
socket = S390_TOPOLOGY_SOCKET(dev);
socket->socket_id = id;
book->cnt++;
+ s390ms->topology_changed = 1;
return socket;
}
@@ -77,6 +93,7 @@ static S390TopologyBook *s390_create_book(S390TopologyDrawer *drawer, int id)
book = S390_TOPOLOGY_BOOK(dev);
book->book_id = id;
drawer->cnt++;
+ s390ms->topology_changed = 1;
return book;
}
@@ -98,6 +115,7 @@ static S390TopologyDrawer *s390_create_drawer(S390TopologyNode *node, int id)
drawer = S390_TOPOLOGY_DRAWER(dev);
drawer->drawer_id = id;
node->cnt++;
+ s390ms->topology_changed = 1;
return drawer;
}
@@ -210,6 +228,7 @@ void s390_topology_new_cpu(int core_id)
bit = 63 - (core_id - origin);
set_bit(bit, &cores->mask);
cores->origin = origin;
+ s390ms->topology_changed = 1;
}
/*
diff --git a/include/hw/s390x/cpu-topology.h b/include/hw/s390x/cpu-topology.h
index 64424cb457..549a3e9a19 100644
--- a/include/hw/s390x/cpu-topology.h
+++ b/include/hw/s390x/cpu-topology.h
@@ -12,6 +12,7 @@
#include "hw/qdev-core.h"
#include "qom/object.h"
+#include "include/hw/sysbus.h"
#define S390_TOPOLOGY_CPU_TYPE 0x03
@@ -88,4 +89,11 @@ S390TopologyNode *s390_get_topology(void);
void s390_topology_setup(MachineState *ms);
void s390_topology_new_cpu(int core_id);
+#define S390_PTF_REASON_NONE (0x00 << 8)
+#define S390_PTF_REASON_DONE (0x01 << 8)
+#define S390_PTF_REASON_BUSY (0x02 << 8)
+extern int s390_topology_changed(void);
+
+#define S390_TOPO_FC_MASK 0xffUL
+
#endif
diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h
index fb3c3a50ce..a091468c79 100644
--- a/include/hw/s390x/s390-virtio-ccw.h
+++ b/include/hw/s390x/s390-virtio-ccw.h
@@ -30,6 +30,7 @@ struct S390CcwMachineState {
uint8_t loadparm[8];
int drawers;
int books;
+ int topology_changed;
};
struct S390CcwMachineClass {
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index 7b7b05f1d3..ac7b161190 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -35,6 +35,7 @@
#include "fpu/softfloat-helpers.h"
#include "disas/capstone.h"
#include "sysemu/tcg.h"
+#include "hw/s390x/cpu-topology.h"
#define CR0_RESET 0xE0UL
#define CR14_RESET 0xC2000000UL;
@@ -154,6 +155,9 @@ static void s390_cpu_reset(CPUState *s, cpu_reset_type type)
env->pfault_token = -1UL;
env->bpbc = false;
+#if !defined(CONFIG_USER_ONLY)
+ s390_topology_changed();
+#endif
break;
default:
g_assert_not_reached();
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index d573ba205e..4eacd06c59 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -901,4 +901,5 @@ typedef S390CPU ArchCPU;
#include "exec/cpu-all.h"
+int s390_handle_ptf(S390CPU *cpu, uint8_t r1, uintptr_t ra);
#endif
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index d78261c089..7c3594d793 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -98,6 +98,7 @@
#define PRIV_B9_EQBS 0x9c
#define PRIV_B9_CLP 0xa0
+#define PRIV_B9_PTF 0xa2
#define PRIV_B9_PCISTG 0xd0
#define PRIV_B9_PCILG 0xd2
#define PRIV_B9_RPCIT 0xd3
@@ -1453,6 +1454,54 @@ static int kvm_mpcifc_service_call(S390CPU *cpu, struct kvm_run *run)
}
}
+int s390_handle_ptf(S390CPU *cpu, uint8_t r1, uintptr_t ra)
+{
+ CPUS390XState *env = &cpu->env;
+ uint64_t reg = env->regs[r1];
+ uint8_t fc = reg & S390_TOPO_FC_MASK;
+
+ if (!s390_has_feat(S390_FEAT_CONFIGURATION_TOPOLOGY)) {
+ s390_program_interrupt(env, PGM_OPERAND, ra);
+ return 0;
+ }
+
+ if (env->psw.mask & PSW_MASK_PSTATE) {
+ s390_program_interrupt(env, PGM_PRIVILEGED, ra);
+ return 0;
+ }
+
+ if (reg & ~S390_TOPO_FC_MASK) {
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ return 0;
+ }
+
+ switch (fc) {
+ case 0: /* Horizontal polarization is already set */
+ env->regs[r1] = S390_PTF_REASON_DONE;
+ return 2;
+ case 1: /* Vertical polarization is not supported */
+ env->regs[r1] = S390_PTF_REASON_NONE;
+ return 2;
+ case 2: /* Report if a topology change report is pending */
+ return s390_topology_changed();
+ default:
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ break;
+ }
+
+ return 0;
+}
+
+static int kvm_handle_ptf(S390CPU *cpu, struct kvm_run *run)
+{
+ uint8_t r1 = (run->s390_sieic.ipb >> 20) & 0x0f;
+ uint8_t ret;
+
+ ret = s390_handle_ptf(cpu, r1, RA_IGNORED);
+ setcc(cpu, ret);
+ return 0;
+}
+
static int handle_b9(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
{
int r = 0;
@@ -1470,6 +1519,9 @@ static int handle_b9(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
case PRIV_B9_RPCIT:
r = kvm_rpcit_service_call(cpu, run);
break;
+ case PRIV_B9_PTF:
+ r = kvm_handle_ptf(cpu, run);
+ break;
case PRIV_B9_EQBS:
/* just inject exception */
r = -1;
--
2.25.1
On Wed, Jul 14 2021, Pierre Morel <pmorel@linux.ibm.com> wrote: > Interception of the PTF instruction depending on the new > KVM_CAP_S390_CPU_TOPOLOGY KVM extension. Wasn't that the capability that you dropped? Is PTF supposed to be always intercepting? If that isn't configurable, wouldn't older QEMUs generate exceptions for it? I'm a bit confused. > > A global value is used to remember if a Topology change occured since > the last interception of a PTF instruction with function code 0. > > Signed-off-by: Pierre Morel <pmorel@linux.ibm.com> > --- > hw/s390x/cpu-topology.c | 19 +++++++++++ > include/hw/s390x/cpu-topology.h | 8 +++++ > include/hw/s390x/s390-virtio-ccw.h | 1 + > target/s390x/cpu.c | 4 +++ > target/s390x/cpu.h | 1 + > target/s390x/kvm/kvm.c | 52 ++++++++++++++++++++++++++++++ > 6 files changed, 85 insertions(+)
On 7/16/21 11:22 AM, Cornelia Huck wrote: > On Wed, Jul 14 2021, Pierre Morel <pmorel@linux.ibm.com> wrote: > >> Interception of the PTF instruction depending on the new >> KVM_CAP_S390_CPU_TOPOLOGY KVM extension. > > Wasn't that the capability that you dropped? yes, > > Is PTF supposed to be always intercepting? If that isn't configurable, > wouldn't older QEMUs generate exceptions for it? I'm a bit confused. Yes, PTF generated an OPERATION exception on old QEMU, but was not used by the guest if it has not the topology facility 11. So just as for STSI, I think we need the KVM_CAP_S390_CPU_TOPOLOGY I dropped because otherwise, now that the kernel will advertise facility 11, the guest will use it and it will get the exception that it should not get. Regards, Pierre > >> >> A global value is used to remember if a Topology change occured since >> the last interception of a PTF instruction with function code 0. >> >> Signed-off-by: Pierre Morel <pmorel@linux.ibm.com> >> --- >> hw/s390x/cpu-topology.c | 19 +++++++++++ >> include/hw/s390x/cpu-topology.h | 8 +++++ >> include/hw/s390x/s390-virtio-ccw.h | 1 + >> target/s390x/cpu.c | 4 +++ >> target/s390x/cpu.h | 1 + >> target/s390x/kvm/kvm.c | 52 ++++++++++++++++++++++++++++++ >> 6 files changed, 85 insertions(+) > -- Pierre Morel IBM Lab Boeblingen
On Fri, Jul 16 2021, Pierre Morel <pmorel@linux.ibm.com> wrote: > On 7/16/21 11:22 AM, Cornelia Huck wrote: >> On Wed, Jul 14 2021, Pierre Morel <pmorel@linux.ibm.com> wrote: >> >>> Interception of the PTF instruction depending on the new >>> KVM_CAP_S390_CPU_TOPOLOGY KVM extension. >> >> Wasn't that the capability that you dropped? > > yes, > >> >> Is PTF supposed to be always intercepting? If that isn't configurable, >> wouldn't older QEMUs generate exceptions for it? I'm a bit confused. > > Yes, PTF generated an OPERATION exception on old QEMU, but was not used > by the guest if it has not the topology facility 11. > > So just as for STSI, I think we need the KVM_CAP_S390_CPU_TOPOLOGY I > dropped because otherwise, now that the kernel will advertise facility > 11, the guest will use it and it will get the exception that it should > not get. Ok, makes sense.
© 2016 - 2026 Red Hat, Inc.