On Aug 8, 2011, at 5:26 PM, Jimi Xenidis wrote:

> This patch adds a fault handler that responds to illegal Coprocessor
> types.  Currently all CTs are treated and illegal.  There are two ways
> to report the fault back to the application.  If the application used
> the record form ("icswx.") then the architected "reject" is emulated.
> If the application did not used the record form ("icswx") then it is
> selectable by config whether the failure is silent (as architected) or
> a SIGILL is generated.
> 
> In all cases pr_warn() is used to log the bad CT.
> 
> Signed-off-by: Jimi Xenidis <ji...@pobox.com>
> ---
> arch/powerpc/mm/fault.c                |   16 +++++
> arch/powerpc/mm/icswx.c                |  114 ++++++++++++++++++++++++++++++++
> arch/powerpc/mm/icswx.h                |   34 ++++++++++
> arch/powerpc/platforms/Kconfig.cputype |   11 +++
> 4 files changed, 175 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
> index 5efe8c9..88abe70 100644
> --- a/arch/powerpc/mm/fault.c
> +++ b/arch/powerpc/mm/fault.c
> @@ -43,6 +43,7 @@
> #include <asm/tlbflush.h>
> #include <asm/siginfo.h>
> #include <mm/mmu_decl.h>
> +#include <mm/icswx.h>
> 
> #ifdef CONFIG_KPROBES
> static inline int notify_page_fault(struct pt_regs *regs)
> @@ -143,6 +144,21 @@ int __kprobes do_page_fault(struct pt_regs *regs, 
> unsigned long address,
>       is_write = error_code & ESR_DST;
> #endif /* CONFIG_4xx || CONFIG_BOOKE */
> 
> +#ifdef CONFIG_PPC_ICSWX
> +     /*
> +      * we need to do this early because this "data storage
> +      * interrupt" does not update the DAR/DEAR so we don't want to
> +      * look at it
> +      */
> +     if (error_code & ICSWX_DSI_UCT) {
> +             int ret;
> +
> +             ret = acop_handle_fault(regs, address, error_code);
> +             if (ret)
> +                     return ret;
> +     }
> +#endif
> +
>       if (notify_page_fault(regs))
>               return 0;
> 
> diff --git a/arch/powerpc/mm/icswx.c b/arch/powerpc/mm/icswx.c
> index 667330e..fbf71b4 100644
> --- a/arch/powerpc/mm/icswx.c
> +++ b/arch/powerpc/mm/icswx.c
> @@ -17,6 +17,9 @@
> #include <linux/mm.h>
> #include <linux/spinlock.h>
> #include <linux/module.h>
> +
> +#include <asm/uaccess.h>
> +
> #include "icswx.h"
> 
> 
> @@ -161,3 +164,114 @@ void drop_cop(unsigned long acop, struct mm_struct *mm)
>       up_read(&mm->mmap_sem);
> }
> EXPORT_SYMBOL_GPL(drop_cop);
> +
> +static int acop_use_cop(int ct)
> +{
> +     /* todo */
> +     return -1;
> +}
> +
> +/*
> + * Get the instruction word at the NIP
> + */
> +static u32 acop_get_inst(struct pt_regs *regs)
> +{
> +     u32 inst;
> +     u32 __user *p;
> +
> +     p = (u32 __user *)regs->nip;
> +     if (!access_ok(VERIFY_READ, p, sizeof(*p)))
> +             return 0;
> +
> +     if (__get_user(inst, p))
> +             return 0;
> +
> +     return inst;
> +}
> +
> +/**
> + * @regs: regsiters at time of interrupt
> + * @address: storage address
> + * @error_code: Fault code, usually the DSISR or ESR depending on
> + *           processor type
> + *
> + * Return 0 if we are able to resolve the data storage fault that
> + * results from a CT miss in the ACOP register.
> + */
> +int acop_handle_fault(struct pt_regs *regs, unsigned long address,
> +                   unsigned long error_code)
> +{
> +     int ct;
> +     u32 inst = 0;
> +
> +     if (!cpu_has_feature(CPU_FTR_ICSWX)) {
> +             pr_info("No coprocessors available");
> +             _exception(SIGILL, regs, ILL_ILLOPN, address);
> +     }
> +
> +     if (!user_mode(regs)) {
> +             /* this could happen if the HV denies the
> +              * kernel access, for now we just die */
> +             die("ICSWX from kernel failed", regs, SIGSEGV);
> +     }
> +
> +     /* Some implementations leave us a hint for the CT */
> +     ct = ICSWX_GET_CT_HINT(error_code);
> +     if (ct < 0) {
> +             /* we have to peek at the instruction work to figure out CT */
> +             union cop_ccw ccw;

don't use a union, we don't do this for any other place we decode instructions 
(just use shift/mask).  Utilize ppc-opcode.h

> +             u32 rs;
> +
> +             inst = acop_get_inst(regs);
> +             if (inst == 0)
> +                     return -1;
> +
> +             rs = (inst >> (31 - 10)) & 0x1f;
> +             ccw._val = regs->gpr[rs];
> +             ct = ccw.ct;
> +     }
> +
> +     if (!acop_use_cop(ct))
> +             return 0;
> +
> +     /* at this point the CT is unknown to the system */
> +     pr_warn("%s[%d]: Coprocessor %d is unavailable",
> +             current->comm, current->pid, ct);
> +
> +     /* get inst if we don't already have it */
> +     if (inst == 0) {
> +             inst = acop_get_inst(regs);
> +             if (inst == 0)
> +                     return -1;
> +     }
> +
> +     /* Check if the instruction is the "record form" */
> +     if (inst & 1) {
> +             /* 
> +              * the instruction is "record" form so we can reject
> +              * using CR0
> +              */
> +             regs->ccr &= ~(0xful << 28);
> +             regs->ccr |= ICSWX_RC_NOT_FOUND << 28;
> +
> +             /* Move on to the next instruction */
> +             regs->nip += 4;
> +     } else {
> +             /*
> +              * There is no architected mechanism to report a bad
> +              * CT so we could either SIGILL or report nothing.
> +              * Since the non-record version should only bu used
> +              * for "hints" or "don't care" we should probably do
> +              * nothing.  However, I could see how some people
> +              * might want an SIGILL so it here if you want it.
> +              */
> +#ifdef CONFIG_ICSWX_USE_SIGILL
> +             _exception(SIGILL, regs, ILL_ILLOPN, address);

Where is CONFIG_ICSWX_USE_SIGILL defined? You have PPC_ICSWX_USE_SIGILL

> +#else
> +             regs->nip += 4;
> +#endif
> +     }
> +
> +     return 0;
> +}
> +EXPORT_SYMBOL_GPL(acop_handle_fault);
> diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h
> index 5121ddd..920d9f3 100644
> --- a/arch/powerpc/mm/icswx.h
> +++ b/arch/powerpc/mm/icswx.h
> @@ -32,3 +32,37 @@ extern void free_cop_pid(int free_pid);
> #define disable_cop_pid(m) (COP_PID_NONE)
> #define free_cop_pid(p)
> #endif
> +
> +/*
> + * These are implementation bits for architected registers.  If this
> + * ever becomes architecture the should be moved to reg.h et. al.
> + */
> +/* UCT is the same bit for Server and Embedded */
> +#define ICSWX_DSI_UCT                0x00004000  /* Unavailable Coprocessor 
> Type */
> +
> +#ifdef CONFIG_BOOKE
> +/* Embedded implementation gives us no hits as to what the CT is */
> +#define ICSWX_GET_CT_HINT(x) (-1)
> +#else
> +/* Server implementation contains the CT value in the DSISR */
> +#define ICSWX_DSISR_CTMASK   0x00003f00
> +#define ICSWX_GET_CT_HINT(x) (((x) & ICSWX_DSISR_CTMASK) >> 8)
> +#endif
> +
> +union cop_ccw {
> +     u32 _val;
> +     struct {
> +             u32 msb:8;
> +             u32 reserved:2;
> +             u32 ct:6;
> +             u32 cd:16;
> +     };
> +};

kill the union, move some of the opcode stuff into ppc-opcode.h

> +
> +#define ICSWX_RC_STARTED     0x8     /* The request has been started */
> +#define ICSWX_RC_NOT_IDLE    0x4     /* No coprocessor found idle */
> +#define ICSWX_RC_NOT_FOUND   0x2     /* No coprocessor found */
> +#define ICSWX_RC_UNDEFINED   0x1     /* Reserved */
> +
> +extern int acop_handle_fault(struct pt_regs *regs, unsigned long address,
> +                          unsigned long error_code);
> diff --git a/arch/powerpc/platforms/Kconfig.cputype 
> b/arch/powerpc/platforms/Kconfig.cputype
> index 3cd22e5..817d723 100644
> --- a/arch/powerpc/platforms/Kconfig.cputype
> +++ b/arch/powerpc/platforms/Kconfig.cputype
> @@ -258,6 +258,17 @@ config PPC_ICSWX_PID
>         PID register in server is used explicitly for ICSWX.  In
>         embedded systems PID managment is done by the system.
> 
> +config PPC_ICSWX_USE_SIGILL
> +     bool "Should a bad CT cause a SIGILL?"

Is there some reason to even have this cfg option?

> +     depends on PPC_ICSWX
> +     default n
> +     ---help---
> +       Should a bad CT used for "non-record form ICSWX" cause an
> +       illegal intruction signal or should it be silent as
> +       architected.
> +
> +       If in doubt, say N here.
> +
> config SPE
>       bool "SPE Support"
>       depends on E200 || (E500 && !PPC_E500MC)
> -- 
> 1.7.0.4
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to