diff mbox series

[v1,6/9] s390x: kvm: topology: interception of PTF instruction

Message ID 1626281596-31061-7-git-send-email-pmorel@linux.ibm.com (mailing list archive)
State New, archived
Headers show
Series s390x: CPU Topology | expand

Commit Message

Pierre Morel July 14, 2021, 4:53 p.m. UTC
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(+)

Comments

Cornelia Huck July 16, 2021, 9:22 a.m. UTC | #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(+)
Pierre Morel July 16, 2021, 11:23 a.m. UTC | #2
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(+)
>
Cornelia Huck July 16, 2021, 11:56 a.m. UTC | #3
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.
diff mbox series

Patch

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;