diff mbox series

[v2,1/2] s390x/tcg: wire up pci instructions

Message ID 20180131181742.2037-2-cohuck@redhat.com
State New
Headers show
Series s390x: support zpci in tcg | expand

Commit Message

Cornelia Huck Jan. 31, 2018, 6:17 p.m. UTC
On s390x, pci support is implemented via a set of instructions
(no mmio). Unfortunately, none of them are documented in the
PoP; the code is based upon the existing implementation for KVM
and the Linux zpci driver.

Signed-off-by: Cornelia Huck <cohuck@redhat.com>
---
 target/s390x/helper.h      |   9 ++++
 target/s390x/insn-data.def |  15 +++++++
 target/s390x/misc_helper.c | 109 +++++++++++++++++++++++++++++++++++++++++++++
 target/s390x/translate.c   | 101 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 234 insertions(+)

Comments

Pierre Morel Feb. 1, 2018, 10 a.m. UTC | #1
On 31/01/2018 19:17, Cornelia Huck wrote:
> On s390x, pci support is implemented via a set of instructions
> (no mmio). Unfortunately, none of them are documented in the
> PoP; the code is based upon the existing implementation for KVM
> and the Linux zpci driver.
>
> Signed-off-by: Cornelia Huck <cohuck@redhat.com>
> ---
>   target/s390x/helper.h      |   9 ++++
>   target/s390x/insn-data.def |  15 +++++++
>   target/s390x/misc_helper.c | 109 +++++++++++++++++++++++++++++++++++++++++++++
>   target/s390x/translate.c   | 101 +++++++++++++++++++++++++++++++++++++++++
>   4 files changed, 234 insertions(+)
>
> diff --git a/target/s390x/helper.h b/target/s390x/helper.h
> index 59a1d9869b..9887efbb3a 100644
> --- a/target/s390x/helper.h
> +++ b/target/s390x/helper.h
> @@ -172,4 +172,13 @@ DEF_HELPER_2(stcrw, void, env, i64)
>   DEF_HELPER_3(stsch, void, env, i64, i64)
>   DEF_HELPER_3(tsch, void, env, i64, i64)
>   DEF_HELPER_2(chsc, void, env, i64)
> +
> +DEF_HELPER_2(clp, void, env, i32)
> +DEF_HELPER_3(pcilg, void, env, i32, i32)
> +DEF_HELPER_3(pcistg, void, env, i32, i32)
> +DEF_HELPER_4(stpcifc, void, env, i32, i64, i32)
> +DEF_HELPER_3(sic, void, env, i64, i64)
> +DEF_HELPER_3(rpcit, void, env, i32, i32)
> +DEF_HELPER_5(pcistb, void, env, i32, i32, i64, i32)
> +DEF_HELPER_4(mpcifc, void, env, i32, i64, i32)
>   #endif
> diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def
> index 11ee43dcbc..b9841631a8 100644
> --- a/target/s390x/insn-data.def
> +++ b/target/s390x/insn-data.def
> @@ -1067,4 +1067,19 @@
>       /* ??? Not listed in PoO ninth edition, but there's a linux driver that
>          uses it: "A CHSC subchannel is usually present on LPAR only."  */
>       C(0xb25f, CHSC,  RRE,     Z,   0, insn, 0, 0, chsc, 0)
> +
> +/* zPCI Instructions */
> +    /* None of these instructions are documented in the PoP, so this is all
> +       based upon target/s390x/kvm.c and Linux code and likely incomplete */
> +    C(0xebd0, PCISTB, RSY_a, PCI, la2, 0, 0, 0, pcistb, 0)
> +    /* SIC does not really depend on pci, but it is unclear from the code
> +       with which facility it becomes available */
> +    C(0xebd1, SIC, RSY_a, Z, r1, r3, 0, 0, sic, 0)
> +    C(0xb9a0, CLP, RRF_c, PCI, 0, 0, 0, 0, clp, 0)
> +    C(0xb9d0, PCISTG, RRE, PCI, 0, 0, 0, 0, pcistg, 0)
> +    C(0xb9d2, PCILG, RRE, PCI, 0, 0, 0, 0, pcilg, 0)
> +    C(0xb9d3, RPCIT, RRE, PCI, 0, 0, 0, 0, rpcit, 0)
> +    C(0xe3d0, MPCIFC, RXY_a, PCI, la2, 0, 0, 0, mpcifc, 0)
> +    C(0xe3d4, STPCIFC, RXY_a, PCI, la2, 0, 0, 0, stpcifc, 0)
> +
>   #endif /* CONFIG_USER_ONLY */
> diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c
> index 86da6aab7e..6f5103f3b5 100644
> --- a/target/s390x/misc_helper.c
> +++ b/target/s390x/misc_helper.c
> @@ -36,6 +36,7 @@
>   #include "hw/s390x/ebcdic.h"
>   #include "hw/s390x/s390-virtio-hcall.h"
>   #include "hw/s390x/sclp.h"
> +#include "hw/s390x/s390-pci-inst.h"
>   #endif
>
>   /* #define DEBUG_HELPER */
> @@ -560,3 +561,111 @@ uint32_t HELPER(stfle)(CPUS390XState *env, uint64_t addr)
>       env->regs[0] = deposit64(env->regs[0], 0, 8, (max_bytes / 8) - 1);
>       return count_bytes >= max_bytes ? 0 : 3;
>   }
> +
> +#ifndef CONFIG_USER_ONLY
> +void HELPER(clp)(CPUS390XState *env, uint32_t r2)
> +{
> +    S390CPU *cpu = s390_env_get_cpu(env);
> +    int r;
> +
> +    qemu_mutex_lock_iothread();
> +    r = clp_service_call(cpu, r2, GETPC());
> +    qemu_mutex_unlock_iothread();
> +    if (r) {
> +        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
> +    }
> +}
> +
> +void HELPER(pcilg)(CPUS390XState *env, uint32_t r1, uint32_t r2)
> +{
> +    S390CPU *cpu = s390_env_get_cpu(env);
> +    int r;
> +
> +    qemu_mutex_lock_iothread();
> +    r = pcilg_service_call(cpu, r1, r2, GETPC());
> +    qemu_mutex_unlock_iothread();
> +    if (r) {
> +        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
> +    }
> +}
> +
> +void HELPER(pcistg)(CPUS390XState *env, uint32_t r1, uint32_t r2)
> +{
> +    S390CPU *cpu = s390_env_get_cpu(env);
> +    int r;
> +
> +    qemu_mutex_lock_iothread();
> +    r = pcistg_service_call(cpu, r1, r2, GETPC());
> +    qemu_mutex_unlock_iothread();
> +    if (r) {
> +        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
> +    }
> +}
> +
> +void HELPER(stpcifc)(CPUS390XState *env, uint32_t r1, uint64_t fiba,
> +                     uint32_t ar)
> +{
> +    S390CPU *cpu = s390_env_get_cpu(env);
> +    int r;
> +
> +    qemu_mutex_lock_iothread();
> +    r = stpcifc_service_call(cpu, r1, fiba, ar, GETPC());
> +    qemu_mutex_unlock_iothread();
> +    if (r) {
> +        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
> +    }
> +}
> +
> +void HELPER(sic)(CPUS390XState *env, uint64_t r1, uint64_t r3)
> +{
> +    int r;
> +
> +    qemu_mutex_lock_iothread();
> +    r = css_do_sic(env, r1 & 0xffff, (r3 >> 27) & 0x7);
> +    qemu_mutex_unlock_iothread();
> +    if (r) {
> +        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
> +    }
> +}
> +
> +void HELPER(rpcit)(CPUS390XState *env, uint32_t r1, uint32_t r2)
> +{
> +    S390CPU *cpu = s390_env_get_cpu(env);
> +    int r;
> +
> +    qemu_mutex_lock_iothread();
> +    r = rpcit_service_call(cpu, r1, r2, GETPC());
> +    qemu_mutex_unlock_iothread();
> +    if (r) {
> +        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
> +    }
> +}
> +
> +void HELPER(pcistb)(CPUS390XState *env, uint32_t r1, uint32_t r3,
> +                    uint64_t gaddr, uint32_t ar)
> +{
> +    S390CPU *cpu = s390_env_get_cpu(env);
> +    int r;
> +
> +    qemu_mutex_lock_iothread();
> +    r = pcistb_service_call(cpu, r1, r3, gaddr, ar, GETPC());
> +    qemu_mutex_unlock_iothread();
> +    if (r) {
> +        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
> +    }
> +}
> +
> +void HELPER(mpcifc)(CPUS390XState *env, uint32_t r1, uint64_t fiba,
> +                    uint32_t ar)
> +{
> +    S390CPU *cpu = s390_env_get_cpu(env);
> +    int r;
> +
> +    qemu_mutex_lock_iothread();
> +    r = mpcifc_service_call(cpu, r1, fiba, ar, GETPC());
> +    qemu_mutex_unlock_iothread();
> +    if (r) {
> +        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
> +    }
> +}
> +#endif
> diff --git a/target/s390x/translate.c b/target/s390x/translate.c
> index df0b41606d..2a3314601a 100644
> --- a/target/s390x/translate.c
> +++ b/target/s390x/translate.c
> @@ -4777,6 +4777,106 @@ static ExitStatus op_zero2(DisasContext *s, DisasOps *o)
>       return NO_EXIT;
>   }
>
> +#ifndef CONFIG_USER_ONLY
> +static ExitStatus op_clp(DisasContext *s, DisasOps *o)
> +{
> +    TCGv_i32 r2 = tcg_const_i32(get_field(s->fields, r2));
> +
> +    check_privileged(s);
> +    gen_helper_clp(cpu_env, r2);
> +    tcg_temp_free_i32(r2);
> +    set_cc_static(s);
> +    return NO_EXIT;
> +}
> +
> +static ExitStatus op_pcilg(DisasContext *s, DisasOps *o)
> +{
> +    TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
> +    TCGv_i32 r2 = tcg_const_i32(get_field(s->fields, r2));
> +
> +    check_privileged(s);
> +    gen_helper_pcilg(cpu_env, r1, r2);
> +    tcg_temp_free_i32(r1);
> +    tcg_temp_free_i32(r2);
> +    set_cc_static(s);
> +    return NO_EXIT;
> +}
> +
> +static ExitStatus op_pcistg(DisasContext *s, DisasOps *o)
> +{
> +    TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
> +    TCGv_i32 r2 = tcg_const_i32(get_field(s->fields, r2));
> +
> +    check_privileged(s);
> +    gen_helper_pcistg(cpu_env, r1, r2);
> +    tcg_temp_free_i32(r1);
> +    tcg_temp_free_i32(r2);
> +    set_cc_static(s);
> +    return NO_EXIT;
> +}
> +
> +static ExitStatus op_stpcifc(DisasContext *s, DisasOps *o)
> +{
> +    TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
> +    TCGv_i32 ar = tcg_const_i32(get_field(s->fields, b2));
> +
> +    check_privileged(s);
> +    gen_helper_stpcifc(cpu_env, r1, o->addr1, ar);
> +    tcg_temp_free_i32(ar);
> +    tcg_temp_free_i32(r1);
> +    set_cc_static(s);
> +    return NO_EXIT;
> +}
> +
> +static ExitStatus op_sic(DisasContext *s, DisasOps *o)
> +{
> +    check_privileged(s);
> +    gen_helper_sic(cpu_env, o->in1, o->in2);
> +    return NO_EXIT;
> +}
> +
> +static ExitStatus op_rpcit(DisasContext *s, DisasOps *o)
> +{
> +    TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
> +    TCGv_i32 r2 = tcg_const_i32(get_field(s->fields, r2));
> +
> +    check_privileged(s);
> +    gen_helper_rpcit(cpu_env, r1, r2);
> +    tcg_temp_free_i32(r1);
> +    tcg_temp_free_i32(r2);
> +    set_cc_static(s);
> +    return NO_EXIT;
> +}
> +
> +static ExitStatus op_pcistb(DisasContext *s, DisasOps *o)
> +{
> +    TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
> +    TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3));
> +    TCGv_i32 ar = tcg_const_i32(get_field(s->fields, b2));
> +
> +    check_privileged(s);
> +    gen_helper_pcistb(cpu_env, r1, r3, o->addr1, ar);
> +    tcg_temp_free_i32(ar);
> +    tcg_temp_free_i32(r1);
> +    tcg_temp_free_i32(r3);
> +    set_cc_static(s);
> +    return NO_EXIT;
> +}
> +
> +static ExitStatus op_mpcifc(DisasContext *s, DisasOps *o)
> +{
> +    TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
> +    TCGv_i32 ar = tcg_const_i32(get_field(s->fields, b2));
> +
> +    check_privileged(s);
> +    gen_helper_mpcifc(cpu_env, r1, o->addr1, ar);
> +    tcg_temp_free_i32(ar);
> +    tcg_temp_free_i32(r1);
> +    set_cc_static(s);
> +    return NO_EXIT;
> +}
> +#endif
> +
>   /* ====================================================================== */
>   /* The "Cc OUTput" generators.  Given the generated output (and in some cases
>      the original inputs), update the various cc data structures in order to
> @@ -5708,6 +5808,7 @@ enum DisasInsnEnum {
>   #define FAC_MSA4        S390_FEAT_MSA_EXT_4 /* msa-extension-4 facility */
>   #define FAC_MSA5        S390_FEAT_MSA_EXT_5 /* msa-extension-5 facility */
>   #define FAC_ECT         S390_FEAT_EXTRACT_CPU_TIME
> +#define FAC_PCI         S390_FEAT_ZPCI /* z/PCI facility */
>
>   static const DisasInsn insn_info[] = {
>   #include "insn-data.def"

Hi,

I am not an expert for TCG but the patches are looking clean to me.

And since I also rapidly tested with multibus, virtio_pci_block, and all 
went good so:

Reviewed-by: Pierre Morel <pmorel@linux.vnet.ibm.com>

Regards,

Pierre
David Hildenbrand Feb. 1, 2018, 12:42 p.m. UTC | #2
On 31.01.2018 19:17, Cornelia Huck wrote:
> On s390x, pci support is implemented via a set of instructions
> (no mmio). Unfortunately, none of them are documented in the
> PoP; the code is based upon the existing implementation for KVM
> and the Linux zpci driver.
> 
> Signed-off-by: Cornelia Huck <cohuck@redhat.com>
> ---
>  target/s390x/helper.h      |   9 ++++
>  target/s390x/insn-data.def |  15 +++++++
>  target/s390x/misc_helper.c | 109 +++++++++++++++++++++++++++++++++++++++++++++
>  target/s390x/translate.c   | 101 +++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 234 insertions(+)
> 
> diff --git a/target/s390x/helper.h b/target/s390x/helper.h
> index 59a1d9869b..9887efbb3a 100644
> --- a/target/s390x/helper.h
> +++ b/target/s390x/helper.h
> @@ -172,4 +172,13 @@ DEF_HELPER_2(stcrw, void, env, i64)
>  DEF_HELPER_3(stsch, void, env, i64, i64)
>  DEF_HELPER_3(tsch, void, env, i64, i64)
>  DEF_HELPER_2(chsc, void, env, i64)
> +
> +DEF_HELPER_2(clp, void, env, i32)
> +DEF_HELPER_3(pcilg, void, env, i32, i32)
> +DEF_HELPER_3(pcistg, void, env, i32, i32)
> +DEF_HELPER_4(stpcifc, void, env, i32, i64, i32)
> +DEF_HELPER_3(sic, void, env, i64, i64)
> +DEF_HELPER_3(rpcit, void, env, i32, i32)
> +DEF_HELPER_5(pcistb, void, env, i32, i32, i64, i32)
> +DEF_HELPER_4(mpcifc, void, env, i32, i64, i32)
>  #endif
> diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def
> index 11ee43dcbc..b9841631a8 100644
> --- a/target/s390x/insn-data.def
> +++ b/target/s390x/insn-data.def
> @@ -1067,4 +1067,19 @@
>      /* ??? Not listed in PoO ninth edition, but there's a linux driver that
>         uses it: "A CHSC subchannel is usually present on LPAR only."  */
>      C(0xb25f, CHSC,  RRE,     Z,   0, insn, 0, 0, chsc, 0)
> +
> +/* zPCI Instructions */
> +    /* None of these instructions are documented in the PoP, so this is all
> +       based upon target/s390x/kvm.c and Linux code and likely incomplete */

I'd drop this comment and rather move it to the patch description.

> +    C(0xebd0, PCISTB, RSY_a, PCI, la2, 0, 0, 0, pcistb, 0)
> +    /* SIC does not really depend on pci, but it is unclear from the code
> +       with which facility it becomes available */> +    C(0xebd1, SIC, RSY_a, Z, r1, r3, 0, 0, sic, 0)
> +    C(0xb9a0, CLP, RRF_c, PCI, 0, 0, 0, 0, clp, 0)
> +    C(0xb9d0, PCISTG, RRE, PCI, 0, 0, 0, 0, pcistg, 0)
> +    C(0xb9d2, PCILG, RRE, PCI, 0, 0, 0, 0, pcilg, 0)
> +    C(0xb9d3, RPCIT, RRE, PCI, 0, 0, 0, 0, rpcit, 0)
> +    C(0xe3d0, MPCIFC, RXY_a, PCI, la2, 0, 0, 0, mpcifc, 0)
> +    C(0xe3d4, STPCIFC, RXY_a, PCI, la2, 0, 0, 0, stpcifc, 0)
> +
>  #endif /* CONFIG_USER_ONLY */
> diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c
> index 86da6aab7e..6f5103f3b5 100644
> --- a/target/s390x/misc_helper.c
> +++ b/target/s390x/misc_helper.c
> @@ -36,6 +36,7 @@
>  #include "hw/s390x/ebcdic.h"
>  #include "hw/s390x/s390-virtio-hcall.h"
>  #include "hw/s390x/sclp.h"
> +#include "hw/s390x/s390-pci-inst.h"
>  #endif
>  
>  /* #define DEBUG_HELPER */
> @@ -560,3 +561,111 @@ uint32_t HELPER(stfle)(CPUS390XState *env, uint64_t addr)
>      env->regs[0] = deposit64(env->regs[0], 0, 8, (max_bytes / 8) - 1);
>      return count_bytes >= max_bytes ? 0 : 3;
>  }
> +
> +#ifndef CONFIG_USER_ONLY
> +void HELPER(clp)(CPUS390XState *env, uint32_t r2)
> +{
> +    S390CPU *cpu = s390_env_get_cpu(env);
> +    int r;
> +
> +    qemu_mutex_lock_iothread();
> +    r = clp_service_call(cpu, r2, GETPC());
> +    qemu_mutex_unlock_iothread();
> +    if (r) {
> +        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
> +    }

We don't need the if (r) ... so I suggest dropping all these. (as I
said, will be handled later via the generic flag checking in translation
code). We can ignore any error from these functions.

A sane guest will newer trigger this. (if we have no CONFIG_PCI, the
also the ZPCI feature will not be available)

Makes the code even shorter :)
Cornelia Huck Feb. 1, 2018, 12:48 p.m. UTC | #3
On Thu, 1 Feb 2018 13:42:52 +0100
David Hildenbrand <david@redhat.com> wrote:

> On 31.01.2018 19:17, Cornelia Huck wrote:

> > +#ifndef CONFIG_USER_ONLY
> > +void HELPER(clp)(CPUS390XState *env, uint32_t r2)
> > +{
> > +    S390CPU *cpu = s390_env_get_cpu(env);
> > +    int r;
> > +
> > +    qemu_mutex_lock_iothread();
> > +    r = clp_service_call(cpu, r2, GETPC());
> > +    qemu_mutex_unlock_iothread();
> > +    if (r) {
> > +        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
> > +    }  
> 
> We don't need the if (r) ... so I suggest dropping all these. (as I
> said, will be handled later via the generic flag checking in translation
> code). We can ignore any error from these functions.

I did not check the instruction implementations in detail... was the
error really only for the !CONFIG_PCI case?

(I really should know that...)

> A sane guest will newer trigger this. (if we have no CONFIG_PCI, the
> also the ZPCI feature will not be available)

Hopefully we can also handle non-sane guests correctly...

> 
> Makes the code even shorter :)
>
David Hildenbrand Feb. 1, 2018, 12:59 p.m. UTC | #4
On 01.02.2018 13:48, Cornelia Huck wrote:
> On Thu, 1 Feb 2018 13:42:52 +0100
> David Hildenbrand <david@redhat.com> wrote:
> 
>> On 31.01.2018 19:17, Cornelia Huck wrote:
> 
>>> +#ifndef CONFIG_USER_ONLY
>>> +void HELPER(clp)(CPUS390XState *env, uint32_t r2)
>>> +{
>>> +    S390CPU *cpu = s390_env_get_cpu(env);
>>> +    int r;
>>> +
>>> +    qemu_mutex_lock_iothread();
>>> +    r = clp_service_call(cpu, r2, GETPC());
>>> +    qemu_mutex_unlock_iothread();
>>> +    if (r) {
>>> +        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
>>> +    }  
>>
>> We don't need the if (r) ... so I suggest dropping all these. (as I
>> said, will be handled later via the generic flag checking in translation
>> code). We can ignore any error from these functions.
> 
> I did not check the instruction implementations in detail... was the
> error really only for the !CONFIG_PCI case?

!FEATURE_ZPCI (which includes !CONFIG_PCI)

Yes, that's how I remember.

> 
> (I really should know that...)
> 
>> A sane guest will newer trigger this. (if we have no CONFIG_PCI, the
>> also the ZPCI feature will not be available)
> 
> Hopefully we can also handle non-sane guests correctly...

Usually, if you call instructions that are not indicated via STFL, there
is no guarantee what will happen. Some time in the future, we will
handle this globally (but haven't done so to allow new applications to
run with old CPU models - which was necessary before we bumped the CPU
model to a z12).

If you don't want to wait until that support is added, you should be
save with something like this:


diff --git a/target/s390x/translate.c b/target/s390x/translate.c
index 02cd4b2627..a5db014730 100644
--- a/target/s390x/translate.c
+++ b/target/s390x/translate.c
@@ -5907,6 +5907,10 @@ static ExitStatus translate_one(CPUS390XState
*env, DisasContext *s)
         gen_illegal_opcode(s);
         return EXIT_NORETURN;
     }
+    if (insn->fac == FAC_PCI && !s390_has_feat(FAC_PCI)) {
+        gen_illegal_opcode(s);
+        return EXIT_NORETURN;
+    }

 #ifndef CONFIG_USER_ONLY
     if (s->tb->flags & FLAG_MASK_PER) {
Cornelia Huck Feb. 1, 2018, 2:23 p.m. UTC | #5
On Thu, 1 Feb 2018 11:00:09 +0100
Pierre Morel <pmorel@linux.vnet.ibm.com> wrote:

> On 31/01/2018 19:17, Cornelia Huck wrote:
> > On s390x, pci support is implemented via a set of instructions
> > (no mmio). Unfortunately, none of them are documented in the
> > PoP; the code is based upon the existing implementation for KVM
> > and the Linux zpci driver.
> >
> > Signed-off-by: Cornelia Huck <cohuck@redhat.com>
> > ---
> >   target/s390x/helper.h      |   9 ++++
> >   target/s390x/insn-data.def |  15 +++++++
> >   target/s390x/misc_helper.c | 109 +++++++++++++++++++++++++++++++++++++++++++++
> >   target/s390x/translate.c   | 101 +++++++++++++++++++++++++++++++++++++++++
> >   4 files changed, 234 insertions(+)

> Hi,
> 
> I am not an expert for TCG but the patches are looking clean to me.
> 
> And since I also rapidly tested with multibus, virtio_pci_block, and all 
> went good so:
> 
> Reviewed-by: Pierre Morel <pmorel@linux.vnet.ibm.com>

Thanks!

Out of curiousity, do you have some scripts or instructions for testing
you can share?
Cornelia Huck Feb. 1, 2018, 2:47 p.m. UTC | #6
On Wed, 31 Jan 2018 19:17:41 +0100
Cornelia Huck <cohuck@redhat.com> wrote:

> +void HELPER(sic)(CPUS390XState *env, uint64_t r1, uint64_t r3)
> +{
> +    int r;
> +
> +    qemu_mutex_lock_iothread();
> +    r = css_do_sic(env, r1 & 0xffff, (r3 >> 27) & 0x7);

Here, the arguments have to be swapped around...

> +    qemu_mutex_unlock_iothread();
> +    if (r) {
> +        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());

...and here we have to pass -r instead of PGM_OPERATION. (Thanks to
David for spotting those!)

> +    }
> +}

With that fixed (and rebased upon current s390-next, which contains
David's latest changes), I can also turn on ais for tcg (which means
pre-4.15 kernels can see pci devices as well.)
Cornelia Huck Feb. 1, 2018, 4:05 p.m. UTC | #7
On Thu, 1 Feb 2018 13:59:13 +0100
David Hildenbrand <david@redhat.com> wrote:

> On 01.02.2018 13:48, Cornelia Huck wrote:
> > On Thu, 1 Feb 2018 13:42:52 +0100
> > David Hildenbrand <david@redhat.com> wrote:
> >   
> >> On 31.01.2018 19:17, Cornelia Huck wrote:  
> >   
> >>> +#ifndef CONFIG_USER_ONLY
> >>> +void HELPER(clp)(CPUS390XState *env, uint32_t r2)
> >>> +{
> >>> +    S390CPU *cpu = s390_env_get_cpu(env);
> >>> +    int r;
> >>> +
> >>> +    qemu_mutex_lock_iothread();
> >>> +    r = clp_service_call(cpu, r2, GETPC());
> >>> +    qemu_mutex_unlock_iothread();
> >>> +    if (r) {
> >>> +        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
> >>> +    }    
> >>
> >> We don't need the if (r) ... so I suggest dropping all these. (as I
> >> said, will be handled later via the generic flag checking in translation
> >> code). We can ignore any error from these functions.  
> > 
> > I did not check the instruction implementations in detail... was the
> > error really only for the !CONFIG_PCI case?  
> 
> !FEATURE_ZPCI (which includes !CONFIG_PCI)
> 
> Yes, that's how I remember.
> 
> > 
> > (I really should know that...)
> >   
> >> A sane guest will newer trigger this. (if we have no CONFIG_PCI, the
> >> also the ZPCI feature will not be available)  
> > 
> > Hopefully we can also handle non-sane guests correctly...  
> 
> Usually, if you call instructions that are not indicated via STFL, there
> is no guarantee what will happen. Some time in the future, we will
> handle this globally (but haven't done so to allow new applications to
> run with old CPU models - which was necessary before we bumped the CPU
> model to a z12).
> 
> If you don't want to wait until that support is added, you should be
> save with something like this:
> 
> 
> diff --git a/target/s390x/translate.c b/target/s390x/translate.c
> index 02cd4b2627..a5db014730 100644
> --- a/target/s390x/translate.c
> +++ b/target/s390x/translate.c
> @@ -5907,6 +5907,10 @@ static ExitStatus translate_one(CPUS390XState
> *env, DisasContext *s)
>          gen_illegal_opcode(s);
>          return EXIT_NORETURN;
>      }
> +    if (insn->fac == FAC_PCI && !s390_has_feat(FAC_PCI)) {
> +        gen_illegal_opcode(s);
> +        return EXIT_NORETURN;
> +    }
> 
>  #ifndef CONFIG_USER_ONLY
>      if (s->tb->flags & FLAG_MASK_PER) {
> 

I think I'll just keep it (the instructions won't do anything, as no
pci devices can be added without FEATURE_ZPCI) and just add a comment.
diff mbox series

Patch

diff --git a/target/s390x/helper.h b/target/s390x/helper.h
index 59a1d9869b..9887efbb3a 100644
--- a/target/s390x/helper.h
+++ b/target/s390x/helper.h
@@ -172,4 +172,13 @@  DEF_HELPER_2(stcrw, void, env, i64)
 DEF_HELPER_3(stsch, void, env, i64, i64)
 DEF_HELPER_3(tsch, void, env, i64, i64)
 DEF_HELPER_2(chsc, void, env, i64)
+
+DEF_HELPER_2(clp, void, env, i32)
+DEF_HELPER_3(pcilg, void, env, i32, i32)
+DEF_HELPER_3(pcistg, void, env, i32, i32)
+DEF_HELPER_4(stpcifc, void, env, i32, i64, i32)
+DEF_HELPER_3(sic, void, env, i64, i64)
+DEF_HELPER_3(rpcit, void, env, i32, i32)
+DEF_HELPER_5(pcistb, void, env, i32, i32, i64, i32)
+DEF_HELPER_4(mpcifc, void, env, i32, i64, i32)
 #endif
diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def
index 11ee43dcbc..b9841631a8 100644
--- a/target/s390x/insn-data.def
+++ b/target/s390x/insn-data.def
@@ -1067,4 +1067,19 @@ 
     /* ??? Not listed in PoO ninth edition, but there's a linux driver that
        uses it: "A CHSC subchannel is usually present on LPAR only."  */
     C(0xb25f, CHSC,  RRE,     Z,   0, insn, 0, 0, chsc, 0)
+
+/* zPCI Instructions */
+    /* None of these instructions are documented in the PoP, so this is all
+       based upon target/s390x/kvm.c and Linux code and likely incomplete */
+    C(0xebd0, PCISTB, RSY_a, PCI, la2, 0, 0, 0, pcistb, 0)
+    /* SIC does not really depend on pci, but it is unclear from the code
+       with which facility it becomes available */
+    C(0xebd1, SIC, RSY_a, Z, r1, r3, 0, 0, sic, 0)
+    C(0xb9a0, CLP, RRF_c, PCI, 0, 0, 0, 0, clp, 0)
+    C(0xb9d0, PCISTG, RRE, PCI, 0, 0, 0, 0, pcistg, 0)
+    C(0xb9d2, PCILG, RRE, PCI, 0, 0, 0, 0, pcilg, 0)
+    C(0xb9d3, RPCIT, RRE, PCI, 0, 0, 0, 0, rpcit, 0)
+    C(0xe3d0, MPCIFC, RXY_a, PCI, la2, 0, 0, 0, mpcifc, 0)
+    C(0xe3d4, STPCIFC, RXY_a, PCI, la2, 0, 0, 0, stpcifc, 0)
+
 #endif /* CONFIG_USER_ONLY */
diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c
index 86da6aab7e..6f5103f3b5 100644
--- a/target/s390x/misc_helper.c
+++ b/target/s390x/misc_helper.c
@@ -36,6 +36,7 @@ 
 #include "hw/s390x/ebcdic.h"
 #include "hw/s390x/s390-virtio-hcall.h"
 #include "hw/s390x/sclp.h"
+#include "hw/s390x/s390-pci-inst.h"
 #endif
 
 /* #define DEBUG_HELPER */
@@ -560,3 +561,111 @@  uint32_t HELPER(stfle)(CPUS390XState *env, uint64_t addr)
     env->regs[0] = deposit64(env->regs[0], 0, 8, (max_bytes / 8) - 1);
     return count_bytes >= max_bytes ? 0 : 3;
 }
+
+#ifndef CONFIG_USER_ONLY
+void HELPER(clp)(CPUS390XState *env, uint32_t r2)
+{
+    S390CPU *cpu = s390_env_get_cpu(env);
+    int r;
+
+    qemu_mutex_lock_iothread();
+    r = clp_service_call(cpu, r2, GETPC());
+    qemu_mutex_unlock_iothread();
+    if (r) {
+        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
+    }
+}
+
+void HELPER(pcilg)(CPUS390XState *env, uint32_t r1, uint32_t r2)
+{
+    S390CPU *cpu = s390_env_get_cpu(env);
+    int r;
+
+    qemu_mutex_lock_iothread();
+    r = pcilg_service_call(cpu, r1, r2, GETPC());
+    qemu_mutex_unlock_iothread();
+    if (r) {
+        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
+    }
+}
+
+void HELPER(pcistg)(CPUS390XState *env, uint32_t r1, uint32_t r2)
+{
+    S390CPU *cpu = s390_env_get_cpu(env);
+    int r;
+
+    qemu_mutex_lock_iothread();
+    r = pcistg_service_call(cpu, r1, r2, GETPC());
+    qemu_mutex_unlock_iothread();
+    if (r) {
+        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
+    }
+}
+
+void HELPER(stpcifc)(CPUS390XState *env, uint32_t r1, uint64_t fiba,
+                     uint32_t ar)
+{
+    S390CPU *cpu = s390_env_get_cpu(env);
+    int r;
+
+    qemu_mutex_lock_iothread();
+    r = stpcifc_service_call(cpu, r1, fiba, ar, GETPC());
+    qemu_mutex_unlock_iothread();
+    if (r) {
+        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
+    }
+}
+
+void HELPER(sic)(CPUS390XState *env, uint64_t r1, uint64_t r3)
+{
+    int r;
+
+    qemu_mutex_lock_iothread();
+    r = css_do_sic(env, r1 & 0xffff, (r3 >> 27) & 0x7);
+    qemu_mutex_unlock_iothread();
+    if (r) {
+        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
+    }
+}
+
+void HELPER(rpcit)(CPUS390XState *env, uint32_t r1, uint32_t r2)
+{
+    S390CPU *cpu = s390_env_get_cpu(env);
+    int r;
+
+    qemu_mutex_lock_iothread();
+    r = rpcit_service_call(cpu, r1, r2, GETPC());
+    qemu_mutex_unlock_iothread();
+    if (r) {
+        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
+    }
+}
+
+void HELPER(pcistb)(CPUS390XState *env, uint32_t r1, uint32_t r3,
+                    uint64_t gaddr, uint32_t ar)
+{
+    S390CPU *cpu = s390_env_get_cpu(env);
+    int r;
+
+    qemu_mutex_lock_iothread();
+    r = pcistb_service_call(cpu, r1, r3, gaddr, ar, GETPC());
+    qemu_mutex_unlock_iothread();
+    if (r) {
+        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
+    }
+}
+
+void HELPER(mpcifc)(CPUS390XState *env, uint32_t r1, uint64_t fiba,
+                    uint32_t ar)
+{
+    S390CPU *cpu = s390_env_get_cpu(env);
+    int r;
+
+    qemu_mutex_lock_iothread();
+    r = mpcifc_service_call(cpu, r1, fiba, ar, GETPC());
+    qemu_mutex_unlock_iothread();
+    if (r) {
+        s390_program_interrupt(env, PGM_OPERATION, 4, GETPC());
+    }
+}
+#endif
diff --git a/target/s390x/translate.c b/target/s390x/translate.c
index df0b41606d..2a3314601a 100644
--- a/target/s390x/translate.c
+++ b/target/s390x/translate.c
@@ -4777,6 +4777,106 @@  static ExitStatus op_zero2(DisasContext *s, DisasOps *o)
     return NO_EXIT;
 }
 
+#ifndef CONFIG_USER_ONLY
+static ExitStatus op_clp(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r2 = tcg_const_i32(get_field(s->fields, r2));
+
+    check_privileged(s);
+    gen_helper_clp(cpu_env, r2);
+    tcg_temp_free_i32(r2);
+    set_cc_static(s);
+    return NO_EXIT;
+}
+
+static ExitStatus op_pcilg(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
+    TCGv_i32 r2 = tcg_const_i32(get_field(s->fields, r2));
+
+    check_privileged(s);
+    gen_helper_pcilg(cpu_env, r1, r2);
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r2);
+    set_cc_static(s);
+    return NO_EXIT;
+}
+
+static ExitStatus op_pcistg(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
+    TCGv_i32 r2 = tcg_const_i32(get_field(s->fields, r2));
+
+    check_privileged(s);
+    gen_helper_pcistg(cpu_env, r1, r2);
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r2);
+    set_cc_static(s);
+    return NO_EXIT;
+}
+
+static ExitStatus op_stpcifc(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
+    TCGv_i32 ar = tcg_const_i32(get_field(s->fields, b2));
+
+    check_privileged(s);
+    gen_helper_stpcifc(cpu_env, r1, o->addr1, ar);
+    tcg_temp_free_i32(ar);
+    tcg_temp_free_i32(r1);
+    set_cc_static(s);
+    return NO_EXIT;
+}
+
+static ExitStatus op_sic(DisasContext *s, DisasOps *o)
+{
+    check_privileged(s);
+    gen_helper_sic(cpu_env, o->in1, o->in2);
+    return NO_EXIT;
+}
+
+static ExitStatus op_rpcit(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
+    TCGv_i32 r2 = tcg_const_i32(get_field(s->fields, r2));
+
+    check_privileged(s);
+    gen_helper_rpcit(cpu_env, r1, r2);
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r2);
+    set_cc_static(s);
+    return NO_EXIT;
+}
+
+static ExitStatus op_pcistb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
+    TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3));
+    TCGv_i32 ar = tcg_const_i32(get_field(s->fields, b2));
+
+    check_privileged(s);
+    gen_helper_pcistb(cpu_env, r1, r3, o->addr1, ar);
+    tcg_temp_free_i32(ar);
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r3);
+    set_cc_static(s);
+    return NO_EXIT;
+}
+
+static ExitStatus op_mpcifc(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
+    TCGv_i32 ar = tcg_const_i32(get_field(s->fields, b2));
+
+    check_privileged(s);
+    gen_helper_mpcifc(cpu_env, r1, o->addr1, ar);
+    tcg_temp_free_i32(ar);
+    tcg_temp_free_i32(r1);
+    set_cc_static(s);
+    return NO_EXIT;
+}
+#endif
+
 /* ====================================================================== */
 /* The "Cc OUTput" generators.  Given the generated output (and in some cases
    the original inputs), update the various cc data structures in order to
@@ -5708,6 +5808,7 @@  enum DisasInsnEnum {
 #define FAC_MSA4        S390_FEAT_MSA_EXT_4 /* msa-extension-4 facility */
 #define FAC_MSA5        S390_FEAT_MSA_EXT_5 /* msa-extension-5 facility */
 #define FAC_ECT         S390_FEAT_EXTRACT_CPU_TIME
+#define FAC_PCI         S390_FEAT_ZPCI /* z/PCI facility */
 
 static const DisasInsn insn_info[] = {
 #include "insn-data.def"