diff mbox series

[v3,2/4] s390x: kvm: topology: interception of PTF instruction

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

Commit Message

Pierre Morel Sept. 16, 2021, 1:50 p.m. UTC
When the host supports the CPU topology facility, the PTF
instruction with function code 2 is interpreted by the SIE,
provided that the userland hypervizor activates the interpretation
by using the KVM_CAP_S390_CPU_TOPOLOGY KVM extension.

The PTF instructions with function code 0 and 1 are intercepted
and must be emulated by the userland hypervizor.

Signed-off-by: Pierre Morel <pmorel@linux.ibm.com>
---
 hw/s390x/s390-virtio-ccw.c         | 36 ++++++++++++++++++++++++++++++
 include/hw/s390x/s390-virtio-ccw.h |  6 +++++
 target/s390x/kvm/kvm.c             | 15 +++++++++++++
 3 files changed, 57 insertions(+)

Comments

Thomas Huth Oct. 13, 2021, 7:25 a.m. UTC | #1
On 16/09/2021 15.50, Pierre Morel wrote:
> When the host supports the CPU topology facility, the PTF
> instruction with function code 2 is interpreted by the SIE,
> provided that the userland hypervizor activates the interpretation
> by using the KVM_CAP_S390_CPU_TOPOLOGY KVM extension.
> 
> The PTF instructions with function code 0 and 1 are intercepted
> and must be emulated by the userland hypervizor.
> 
> Signed-off-by: Pierre Morel <pmorel@linux.ibm.com>
> ---
>   hw/s390x/s390-virtio-ccw.c         | 36 ++++++++++++++++++++++++++++++
>   include/hw/s390x/s390-virtio-ccw.h |  6 +++++
>   target/s390x/kvm/kvm.c             | 15 +++++++++++++
>   3 files changed, 57 insertions(+)
> 
> diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
> index 61aeccb163..894f013139 100644
> --- a/hw/s390x/s390-virtio-ccw.c
> +++ b/hw/s390x/s390-virtio-ccw.c
> @@ -404,6 +404,42 @@ static void s390_pv_prepare_reset(S390CcwMachineState *ms)
>       s390_pv_prep_reset();
>   }
>   

Could you please add a comment in front of this function, with some 
explanations? If I've got that right, it's currently rather only a "dummy" 
function, rejecting FC 0 and 1, and FC 2 is always handled by the SIE, right?

> +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_OPERATION, 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;
> +    default:
> +        /* Note that fc == 2 is interpreted by the SIE */
> +        s390_program_interrupt(env, PGM_SPECIFICATION, ra);
> +    }
> +
> +    return 0;
> +}
> +
>   static void s390_machine_reset(MachineState *machine)
>   {
>       S390CcwMachineState *ms = S390_CCW_MACHINE(machine);
> diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h
> index 3331990e02..ac4b4a92e7 100644
> --- a/include/hw/s390x/s390-virtio-ccw.h
> +++ b/include/hw/s390x/s390-virtio-ccw.h
> @@ -30,6 +30,12 @@ struct S390CcwMachineState {
>       uint8_t loadparm[8];
>   };
>   
> +#define S390_PTF_REASON_NONE (0x00 << 8)
> +#define S390_PTF_REASON_DONE (0x01 << 8)
> +#define S390_PTF_REASON_BUSY (0x02 << 8)
> +#define S390_TOPO_FC_MASK 0xffUL
> +int s390_handle_ptf(S390CPU *cpu, uint8_t r1, uintptr_t ra);
> +
>   struct S390CcwMachineClass {
>       /*< private >*/
>       MachineClass parent_class;
> diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
> index 5b1fdb55c4..dd036961fe 100644
> --- a/target/s390x/kvm/kvm.c
> +++ b/target/s390x/kvm/kvm.c
> @@ -97,6 +97,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
> @@ -362,6 +363,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
>       kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0);
>       kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0);
>       kvm_vm_enable_cap(s, KVM_CAP_S390_USER_STSI, 0);
> +    kvm_vm_enable_cap(s, KVM_CAP_S390_CPU_TOPOLOGY, 0);

Should this maybe rather be done in the last patch, to avoid a state where 
PTF is available, but STSI 15 is not implemented yet (when bisecting through 
these commits later)?

  Thomas
Pierre Morel Oct. 13, 2021, 7:55 a.m. UTC | #2
On 10/13/21 09:25, Thomas Huth wrote:
> On 16/09/2021 15.50, Pierre Morel wrote:
>> When the host supports the CPU topology facility, the PTF
>> instruction with function code 2 is interpreted by the SIE,
>> provided that the userland hypervizor activates the interpretation
>> by using the KVM_CAP_S390_CPU_TOPOLOGY KVM extension.
>>
>> The PTF instructions with function code 0 and 1 are intercepted
>> and must be emulated by the userland hypervizor.
>>
>> Signed-off-by: Pierre Morel <pmorel@linux.ibm.com>
>> ---
>>   hw/s390x/s390-virtio-ccw.c         | 36 ++++++++++++++++++++++++++++++
>>   include/hw/s390x/s390-virtio-ccw.h |  6 +++++
>>   target/s390x/kvm/kvm.c             | 15 +++++++++++++
>>   3 files changed, 57 insertions(+)
>>
>> diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
>> index 61aeccb163..894f013139 100644
>> --- a/hw/s390x/s390-virtio-ccw.c
>> +++ b/hw/s390x/s390-virtio-ccw.c
>> @@ -404,6 +404,42 @@ static void 
>> s390_pv_prepare_reset(S390CcwMachineState *ms)
>>       s390_pv_prep_reset();
>>   }
> 
> Could you please add a comment in front of this function, with some 
> explanations? If I've got that right, it's currently rather only a 
> "dummy" function, rejecting FC 0 and 1, and FC 2 is always handled by 
> the SIE, right?
> 
>> +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_OPERATION, 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;
>> +    default:
>> +        /* Note that fc == 2 is interpreted by the SIE */
>> +        s390_program_interrupt(env, PGM_SPECIFICATION, ra);
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>>   static void s390_machine_reset(MachineState *machine)
>>   {
>>       S390CcwMachineState *ms = S390_CCW_MACHINE(machine);
>> diff --git a/include/hw/s390x/s390-virtio-ccw.h 
>> b/include/hw/s390x/s390-virtio-ccw.h
>> index 3331990e02..ac4b4a92e7 100644
>> --- a/include/hw/s390x/s390-virtio-ccw.h
>> +++ b/include/hw/s390x/s390-virtio-ccw.h
>> @@ -30,6 +30,12 @@ struct S390CcwMachineState {
>>       uint8_t loadparm[8];
>>   };
>> +#define S390_PTF_REASON_NONE (0x00 << 8)
>> +#define S390_PTF_REASON_DONE (0x01 << 8)
>> +#define S390_PTF_REASON_BUSY (0x02 << 8)
>> +#define S390_TOPO_FC_MASK 0xffUL
>> +int s390_handle_ptf(S390CPU *cpu, uint8_t r1, uintptr_t ra);
>> +
>>   struct S390CcwMachineClass {
>>       /*< private >*/
>>       MachineClass parent_class;
>> diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
>> index 5b1fdb55c4..dd036961fe 100644
>> --- a/target/s390x/kvm/kvm.c
>> +++ b/target/s390x/kvm/kvm.c
>> @@ -97,6 +97,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
>> @@ -362,6 +363,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
>>       kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0);
>>       kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0);
>>       kvm_vm_enable_cap(s, KVM_CAP_S390_USER_STSI, 0);
>> +    kvm_vm_enable_cap(s, KVM_CAP_S390_CPU_TOPOLOGY, 0);
> 
> Should this maybe rather be done in the last patch, to avoid a state 
> where PTF is available, but STSI 15 is not implemented yet (when 
> bisecting through these commits later)?
> 
>   Thomas
> 

Yes you are right, thanks.
Pierre
Thomas Huth Oct. 13, 2021, 9:11 a.m. UTC | #3
On 13/10/2021 09.55, Pierre Morel wrote:
> 
> 
> On 10/13/21 09:25, Thomas Huth wrote:
>> On 16/09/2021 15.50, Pierre Morel wrote:
>>> When the host supports the CPU topology facility, the PTF
>>> instruction with function code 2 is interpreted by the SIE,
>>> provided that the userland hypervizor activates the interpretation
>>> by using the KVM_CAP_S390_CPU_TOPOLOGY KVM extension.
>>>
>>> The PTF instructions with function code 0 and 1 are intercepted
>>> and must be emulated by the userland hypervizor.
>>>
>>> Signed-off-by: Pierre Morel <pmorel@linux.ibm.com>
>>> ---
...
>>> diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
>>> index 5b1fdb55c4..dd036961fe 100644
>>> --- a/target/s390x/kvm/kvm.c
>>> +++ b/target/s390x/kvm/kvm.c
>>> @@ -97,6 +97,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
>>> @@ -362,6 +363,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
>>>       kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0);
>>>       kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0);
>>>       kvm_vm_enable_cap(s, KVM_CAP_S390_USER_STSI, 0);
>>> +    kvm_vm_enable_cap(s, KVM_CAP_S390_CPU_TOPOLOGY, 0);
>>
>> Should this maybe rather be done in the last patch, to avoid a state where 
>> PTF is available, but STSI 15 is not implemented yet (when bisecting 
>> through these commits later)?
>>
>>   Thomas
>>
> 
> Yes you are right, thanks.

I'm also still a little bit surprised that there is really no migration code 
involved here yet. What if a guest gets started on a system with 
KVM_CAP_S390_CPU_TOPOLOGY support and later migrated to a system without 
KVM_CAP_S390_CPU_TOPOLOGY support? Is there already some magic in place that 
rejects such a migration? If not, the guest might first learn that it could 
use the PTF instruction, but suddenly it is then not available anymore? Does 
Linux cope right with PTF becoming unavailable during runtime? But even if 
it does, I think it's likely not in the sense of the architecture if certain 
instructions might disappear during runtime? Or do I miss something?

  Thomas
Pierre Morel Oct. 14, 2021, 8:09 a.m. UTC | #4
On 10/13/21 11:11, Thomas Huth wrote:
> On 13/10/2021 09.55, Pierre Morel wrote:
>>
>>
>> On 10/13/21 09:25, Thomas Huth wrote:
>>> On 16/09/2021 15.50, Pierre Morel wrote:
>>>> When the host supports the CPU topology facility, the PTF
>>>> instruction with function code 2 is interpreted by the SIE,
>>>> provided that the userland hypervizor activates the interpretation
>>>> by using the KVM_CAP_S390_CPU_TOPOLOGY KVM extension.
>>>>
>>>> The PTF instructions with function code 0 and 1 are intercepted
>>>> and must be emulated by the userland hypervizor.
>>>>
>>>> Signed-off-by: Pierre Morel <pmorel@linux.ibm.com>
>>>> ---
> ...
>>>> diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
>>>> index 5b1fdb55c4..dd036961fe 100644
>>>> --- a/target/s390x/kvm/kvm.c
>>>> +++ b/target/s390x/kvm/kvm.c
>>>> @@ -97,6 +97,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
>>>> @@ -362,6 +363,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
>>>>       kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0);
>>>>       kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0);
>>>>       kvm_vm_enable_cap(s, KVM_CAP_S390_USER_STSI, 0);
>>>> +    kvm_vm_enable_cap(s, KVM_CAP_S390_CPU_TOPOLOGY, 0);
>>>
>>> Should this maybe rather be done in the last patch, to avoid a state 
>>> where PTF is available, but STSI 15 is not implemented yet (when 
>>> bisecting through these commits later)?
>>>
>>>   Thomas
>>>
>>
>> Yes you are right, thanks.
> 
> I'm also still a little bit surprised that there is really no migration 
> code involved here yet. What if a guest gets started on a system with 
> KVM_CAP_S390_CPU_TOPOLOGY support and later migrated to a system without 
> KVM_CAP_S390_CPU_TOPOLOGY support? Is there already some magic in place 
> that rejects such a migration? If not, the guest might first learn that 
> it could use the PTF instruction, but suddenly it is then not available 
> anymore? Does Linux cope right with PTF becoming unavailable during 
> runtime? But even if it does, I think it's likely not in the sense of 
> the architecture if certain instructions might disappear during runtime? 
> Or do I miss something?
> 
>   Thomas
> 


I check on this and take the consequences.

Pierre
Pierre Morel Oct. 21, 2021, 8:44 a.m. UTC | #5
On 10/14/21 10:09, Pierre Morel wrote:
> 
> 
> On 10/13/21 11:11, Thomas Huth wrote:
>> On 13/10/2021 09.55, Pierre Morel wrote:
>>>
>>>
>>> On 10/13/21 09:25, Thomas Huth wrote:
>>>> On 16/09/2021 15.50, Pierre Morel wrote:
>>>>> When the host supports the CPU topology facility, the PTF
>>>>> instruction with function code 2 is interpreted by the SIE,
>>>>> provided that the userland hypervizor activates the interpretation
>>>>> by using the KVM_CAP_S390_CPU_TOPOLOGY KVM extension.
>>>>>
>>>>> The PTF instructions with function code 0 and 1 are intercepted
>>>>> and must be emulated by the userland hypervizor.
>>>>>
>>>>> Signed-off-by: Pierre Morel <pmorel@linux.ibm.com>
>>>>> ---
>> ...
>>>>> diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
>>>>> index 5b1fdb55c4..dd036961fe 100644
>>>>> --- a/target/s390x/kvm/kvm.c
>>>>> +++ b/target/s390x/kvm/kvm.c
>>>>> @@ -97,6 +97,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
>>>>> @@ -362,6 +363,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
>>>>>       kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0);
>>>>>       kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0);
>>>>>       kvm_vm_enable_cap(s, KVM_CAP_S390_USER_STSI, 0);
>>>>> +    kvm_vm_enable_cap(s, KVM_CAP_S390_CPU_TOPOLOGY, 0);
>>>>
>>>> Should this maybe rather be done in the last patch, to avoid a state 
>>>> where PTF is available, but STSI 15 is not implemented yet (when 
>>>> bisecting through these commits later)?
>>>>
>>>>   Thomas
>>>>
>>>
>>> Yes you are right, thanks.
>>
>> I'm also still a little bit surprised that there is really no 
>> migration code involved here yet. What if a guest gets started on a 
>> system with KVM_CAP_S390_CPU_TOPOLOGY support and later migrated to a 
>> system without KVM_CAP_S390_CPU_TOPOLOGY support? Is there already 
>> some magic in place that rejects such a migration? If not, the guest 
>> might first learn that it could use the PTF instruction, but suddenly 
>> it is then not available anymore? Does Linux cope right with PTF 
>> becoming unavailable during runtime? But even if it does, I think it's 
>> likely not in the sense of the architecture if certain instructions 
>> might disappear during runtime? Or do I miss something?
>>
>>   Thomas
>>
> 
> 
> I check on this and take the consequences.
> 
> Pierre
> 

I can use a solution using pre_save/postload migration entries to verify 
that both side of the migration use PTF and STSI_15 the same way.

Seems this direction OK ?

Regards,
Pierre
Pierre Morel Nov. 17, 2021, 1:06 p.m. UTC | #6
On 10/13/21 09:25, Thomas Huth wrote:
> On 16/09/2021 15.50, Pierre Morel wrote:
>> When the host supports the CPU topology facility, the PTF
>> instruction with function code 2 is interpreted by the SIE,
>> provided that the userland hypervizor activates the interpretation
>> by using the KVM_CAP_S390_CPU_TOPOLOGY KVM extension.
>>
>> The PTF instructions with function code 0 and 1 are intercepted
>> and must be emulated by the userland hypervizor.
>>
>> Signed-off-by: Pierre Morel <pmorel@linux.ibm.com>
>> ---
>>   hw/s390x/s390-virtio-ccw.c         | 36 ++++++++++++++++++++++++++++++
>>   include/hw/s390x/s390-virtio-ccw.h |  6 +++++
>>   target/s390x/kvm/kvm.c             | 15 +++++++++++++
>>   3 files changed, 57 insertions(+)
>>
>> diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
>> index 61aeccb163..894f013139 100644
>> --- a/hw/s390x/s390-virtio-ccw.c
>> +++ b/hw/s390x/s390-virtio-ccw.c
>> @@ -404,6 +404,42 @@ static void 
>> s390_pv_prepare_reset(S390CcwMachineState *ms)
>>       s390_pv_prep_reset();
>>   }
> 
> Could you please add a comment in front of this function, with some 
> explanations? If I've got that right, it's currently rather only a 
> "dummy" function, rejecting FC 0 and 1, and FC 2 is always handled by 
> the SIE, right?

I just saw I did not answer this question.

Yes function code 2 is handled by the SIE but it is not really a dummy 
function as without it PTF 0 or 1 would trigger a program check.

I will add a comment basically:

"We assume horizontal topology, the only one supported currently by 
Linux consequently we answer to function code 0 requesting horizontal 
polarization that it is already the current polarization and reject 
vertical polarization request without further explanation."


regards,
Pierre
diff mbox series

Patch

diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 61aeccb163..894f013139 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -404,6 +404,42 @@  static void s390_pv_prepare_reset(S390CcwMachineState *ms)
     s390_pv_prep_reset();
 }
 
+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_OPERATION, 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;
+    default:
+        /* Note that fc == 2 is interpreted by the SIE */
+        s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+
+    return 0;
+}
+
 static void s390_machine_reset(MachineState *machine)
 {
     S390CcwMachineState *ms = S390_CCW_MACHINE(machine);
diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h
index 3331990e02..ac4b4a92e7 100644
--- a/include/hw/s390x/s390-virtio-ccw.h
+++ b/include/hw/s390x/s390-virtio-ccw.h
@@ -30,6 +30,12 @@  struct S390CcwMachineState {
     uint8_t loadparm[8];
 };
 
+#define S390_PTF_REASON_NONE (0x00 << 8)
+#define S390_PTF_REASON_DONE (0x01 << 8)
+#define S390_PTF_REASON_BUSY (0x02 << 8)
+#define S390_TOPO_FC_MASK 0xffUL
+int s390_handle_ptf(S390CPU *cpu, uint8_t r1, uintptr_t ra);
+
 struct S390CcwMachineClass {
     /*< private >*/
     MachineClass parent_class;
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index 5b1fdb55c4..dd036961fe 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -97,6 +97,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
@@ -362,6 +363,7 @@  int kvm_arch_init(MachineState *ms, KVMState *s)
     kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0);
     kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0);
     kvm_vm_enable_cap(s, KVM_CAP_S390_USER_STSI, 0);
+    kvm_vm_enable_cap(s, KVM_CAP_S390_CPU_TOPOLOGY, 0);
     if (ri_allowed()) {
         if (kvm_vm_enable_cap(s, KVM_CAP_S390_RI, 0) == 0) {
             cap_ri = 1;
@@ -1452,6 +1454,16 @@  static int kvm_mpcifc_service_call(S390CPU *cpu, struct kvm_run *run)
     }
 }
 
+static int kvm_handle_ptf(S390CPU *cpu, struct kvm_run *run)
+{
+    uint8_t r1 = (run->s390_sieic.ipb >> 20) & 0x0f;
+    int 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;
@@ -1469,6 +1481,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;