get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/807390/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 807390,
    "url": "http://patchwork.ozlabs.org/api/patches/807390/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/1504066360-30128-3-git-send-email-paulus@ozlabs.org/",
    "project": {
        "id": 2,
        "url": "http://patchwork.ozlabs.org/api/projects/2/?format=api",
        "name": "Linux PPC development",
        "link_name": "linuxppc-dev",
        "list_id": "linuxppc-dev.lists.ozlabs.org",
        "list_email": "linuxppc-dev@lists.ozlabs.org",
        "web_url": "https://github.com/linuxppc/wiki/wiki",
        "scm_url": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git",
        "webscm_url": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git/",
        "list_archive_url": "https://lore.kernel.org/linuxppc-dev/",
        "list_archive_url_format": "https://lore.kernel.org/linuxppc-dev/{}/",
        "commit_url_format": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git/commit/?id={}"
    },
    "msgid": "<1504066360-30128-3-git-send-email-paulus@ozlabs.org>",
    "list_archive_url": "https://lore.kernel.org/linuxppc-dev/1504066360-30128-3-git-send-email-paulus@ozlabs.org/",
    "date": "2017-08-30T04:12:25",
    "name": "[v3,02/17] powerpc: Change analyse_instr so it doesn't modify *regs",
    "commit_ref": "3cdfcbfd32b9d1c0d4a6fa80ee9c390927aab948",
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "8539dd64ebdcd057ddc800973ba884582f06a093",
    "submitter": {
        "id": 67079,
        "url": "http://patchwork.ozlabs.org/api/people/67079/?format=api",
        "name": "Paul Mackerras",
        "email": "paulus@ozlabs.org"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/1504066360-30128-3-git-send-email-paulus@ozlabs.org/mbox/",
    "series": [
        {
            "id": 522,
            "url": "http://patchwork.ozlabs.org/api/series/522/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/linuxppc-dev/list/?series=522",
            "date": "2017-08-30T04:12:25",
            "name": "powerpc: Do alignment fixups using analyse_instr etc.",
            "version": 3,
            "mbox": "http://patchwork.ozlabs.org/series/522/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/807390/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/807390/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org>",
        "X-Original-To": [
            "patchwork-incoming@ozlabs.org",
            "linuxppc-dev@lists.ozlabs.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@ozlabs.org",
            "linuxppc-dev@lists.ozlabs.org",
            "linuxppc-dev@ozlabs.org"
        ],
        "Received": [
            "from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68])\n\t(using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xhsb56DMJz9sNc\n\tfor <patchwork-incoming@ozlabs.org>;\n\tWed, 30 Aug 2017 14:14:25 +1000 (AEST)",
            "from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3])\n\tby lists.ozlabs.org (Postfix) with ESMTP id 3xhsb5519XzDqKl\n\tfor <patchwork-incoming@ozlabs.org>;\n\tWed, 30 Aug 2017 14:14:25 +1000 (AEST)",
            "from ozlabs.org (bilbo.ozlabs.org [103.22.144.67])\n\t(using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby lists.ozlabs.org (Postfix) with ESMTPS id 3xhsYG04XNzDqGW\n\tfor <linuxppc-dev@lists.ozlabs.org>;\n\tWed, 30 Aug 2017 14:12:50 +1000 (AEST)",
            "by ozlabs.org (Postfix)\n\tid 3xhsYF6b5Dz9sQl; Wed, 30 Aug 2017 14:12:49 +1000 (AEST)",
            "from authenticated.ozlabs.org (localhost [127.0.0.1])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPSA id 3xhsYF4Tvwz9sPt\n\tfor <linuxppc-dev@ozlabs.org>; Wed, 30 Aug 2017 14:12:49 +1000 (AEST)"
        ],
        "Authentication-Results": [
            "ozlabs.org; dkim=pass (2048-bit key;\n\tsecure) header.d=ozlabs.org header.i=@ozlabs.org header.b=\"b0LjJbBw\";\n\tdkim-atps=neutral",
            "lists.ozlabs.org; dkim=pass (2048-bit key;\n\tsecure) header.d=ozlabs.org header.i=@ozlabs.org header.b=\"b0LjJbBw\";\n\tdkim-atps=neutral",
            "lists.ozlabs.org; dkim=pass (2048-bit key;\n\tsecure) header.d=ozlabs.org header.i=@ozlabs.org header.b=\"b0LjJbBw\"; \n\tdkim-atps=neutral"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ozlabs.org; s=201707; \n\tt=1504066369; bh=45ATXxK7YUq4s8tlagCZCtagW8XfS+su1RE3bakSGXk=;\n\th=From:To:Subject:Date:In-Reply-To:References:From;\n\tb=b0LjJbBwAljgcV6E5FZNlHGA2bEJPAV6/jLrBzLnb1y+ORVb/iXnRfo+qcfMxvdIx\n\tZixPqZBsY7VLtUJpNChjjTT7zlFp51a1stc4t3jmLGzK5RlX9TkoBSNDf4QhCpOiA9\n\tTbR6lu4uEadWcUHHaYGc7JRmI8cjLf04hmyUrOCWTEqBo6L+cD/pe8tNupNJ2wMCcx\n\t73efOz1sueF3fg9gG2H/eEidjCcB29PvHylWl9Cn9BcSmRgYnc46yYBpDgSawQa64N\n\taFiJ0P/LiX1R1jMTfkkSbZp0AFFBgrcd131iUJFG6I5AykPCFnIfKuoSV66KqLzsXc\n\thgCJ/Lg5RsDxA==",
        "From": "Paul Mackerras <paulus@ozlabs.org>",
        "To": "linuxppc-dev@ozlabs.org",
        "Subject": "[PATCH v3 02/17] powerpc: Change analyse_instr so it doesn't modify\n\t*regs",
        "Date": "Wed, 30 Aug 2017 14:12:25 +1000",
        "Message-Id": "<1504066360-30128-3-git-send-email-paulus@ozlabs.org>",
        "X-Mailer": "git-send-email 2.7.4",
        "In-Reply-To": "<1504066360-30128-1-git-send-email-paulus@ozlabs.org>",
        "References": "<1504066360-30128-1-git-send-email-paulus@ozlabs.org>",
        "X-BeenThere": "linuxppc-dev@lists.ozlabs.org",
        "X-Mailman-Version": "2.1.23",
        "Precedence": "list",
        "List-Id": "Linux on PowerPC Developers Mail List\n\t<linuxppc-dev.lists.ozlabs.org>",
        "List-Unsubscribe": "<https://lists.ozlabs.org/options/linuxppc-dev>,\n\t<mailto:linuxppc-dev-request@lists.ozlabs.org?subject=unsubscribe>",
        "List-Archive": "<http://lists.ozlabs.org/pipermail/linuxppc-dev/>",
        "List-Post": "<mailto:linuxppc-dev@lists.ozlabs.org>",
        "List-Help": "<mailto:linuxppc-dev-request@lists.ozlabs.org?subject=help>",
        "List-Subscribe": "<https://lists.ozlabs.org/listinfo/linuxppc-dev>,\n\t<mailto:linuxppc-dev-request@lists.ozlabs.org?subject=subscribe>",
        "Errors-To": "linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org",
        "Sender": "\"Linuxppc-dev\"\n\t<linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org>"
    },
    "content": "The analyse_instr function currently doesn't just work out what an\ninstruction does, it also executes those instructions whose effect\nis only to update CPU registers that are stored in struct pt_regs.\nThis is undesirable because optprobes uses analyse_instr to work out\nif an instruction could be successfully emulated in future.\n\nThis changes analyse_instr so it doesn't modify *regs; instead it\nstores information in the instruction_op structure to indicate what\nregisters (GPRs, CR, XER, LR) would be set and what value they would\nbe set to.  A companion function called emulate_update_regs() can\nthen use that information to update a pt_regs struct appropriately.\n\nAs a minor cleanup, this replaces inline asm using the cntlzw and\ncntlzd instructions with calls to __builtin_clz() and __builtin_clzl().\n\nSigned-off-by: Paul Mackerras <paulus@ozlabs.org>\n---\n arch/powerpc/include/asm/sstep.h |  52 +++-\n arch/powerpc/lib/sstep.c         | 601 +++++++++++++++++++++++----------------\n 2 files changed, 396 insertions(+), 257 deletions(-)",
    "diff": "diff --git a/arch/powerpc/include/asm/sstep.h b/arch/powerpc/include/asm/sstep.h\nindex d3a42cc..442e636 100644\n--- a/arch/powerpc/include/asm/sstep.h\n+++ b/arch/powerpc/include/asm/sstep.h\n@@ -23,9 +23,6 @@ struct pt_regs;\n #define IS_RFID(instr)\t\t(((instr) & 0xfc0007fe) == 0x4c000024)\n #define IS_RFI(instr)\t\t(((instr) & 0xfc0007fe) == 0x4c000064)\n \n-/* Emulate instructions that cause a transfer of control. */\n-extern int emulate_step(struct pt_regs *regs, unsigned int instr);\n-\n enum instruction_type {\n \tCOMPUTE,\t\t/* arith/logical/CR op, etc. */\n \tLOAD,\n@@ -55,11 +52,29 @@ enum instruction_type {\n \n #define INSTR_TYPE_MASK\t0x1f\n \n+/* Compute flags, ORed in with type */\n+#define SETREG\t\t0x20\n+#define SETCC\t\t0x40\n+#define SETXER\t\t0x80\n+\n+/* Branch flags, ORed in with type */\n+#define SETLK\t\t0x20\n+#define BRTAKEN\t\t0x40\n+#define DECCTR\t\t0x80\n+\n /* Load/store flags, ORed in with type */\n #define SIGNEXT\t\t0x20\n #define UPDATE\t\t0x40\t/* matches bit in opcode 31 instructions */\n #define BYTEREV\t\t0x80\n \n+/* Barrier type field, ORed in with type */\n+#define BARRIER_MASK\t0xe0\n+#define BARRIER_SYNC\t0x00\n+#define BARRIER_ISYNC\t0x20\n+#define BARRIER_EIEIO\t0x40\n+#define BARRIER_LWSYNC\t0x60\n+#define BARRIER_PTESYNC\t0x80\n+\n /* Cacheop values, ORed in with type */\n #define CACHEOP_MASK\t0x700\n #define DCBST\t\t0\n@@ -83,7 +98,36 @@ struct instruction_op {\n \tint update_reg;\n \t/* For MFSPR */\n \tint spr;\n+\tu32 ccval;\n+\tu32 xerval;\n };\n \n-extern int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n+/*\n+ * Decode an instruction, and return information about it in *op\n+ * without changing *regs.\n+ *\n+ * Return value is 1 if the instruction can be emulated just by\n+ * updating *regs with the information in *op, -1 if we need the\n+ * GPRs but *regs doesn't contain the full register set, or 0\n+ * otherwise.\n+ */\n+extern int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,\n \t\t\t unsigned int instr);\n+\n+/*\n+ * Emulate an instruction that can be executed just by updating\n+ * fields in *regs.\n+ */\n+void emulate_update_regs(struct pt_regs *reg, struct instruction_op *op);\n+\n+/*\n+ * Emulate instructions that cause a transfer of control,\n+ * arithmetic/logical instructions, loads and stores,\n+ * cache operations and barriers.\n+ *\n+ * Returns 1 if the instruction was emulated successfully,\n+ * 0 if it could not be emulated, or -1 for an instruction that\n+ * should not be emulated (rfid, mtmsrd clearing MSR_RI, etc.).\n+ */\n+extern int emulate_step(struct pt_regs *regs, unsigned int instr);\n+\ndiff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c\nindex a85b82c..8e581c6 100644\n--- a/arch/powerpc/lib/sstep.c\n+++ b/arch/powerpc/lib/sstep.c\n@@ -62,15 +62,17 @@ static nokprobe_inline unsigned long truncate_if_32bit(unsigned long msr,\n /*\n  * Determine whether a conditional branch instruction would branch.\n  */\n-static nokprobe_inline int branch_taken(unsigned int instr, struct pt_regs *regs)\n+static nokprobe_inline int branch_taken(unsigned int instr,\n+\t\t\t\t\tconst struct pt_regs *regs,\n+\t\t\t\t\tstruct instruction_op *op)\n {\n \tunsigned int bo = (instr >> 21) & 0x1f;\n \tunsigned int bi;\n \n \tif ((bo & 4) == 0) {\n \t\t/* decrement counter */\n-\t\t--regs->ctr;\n-\t\tif (((bo >> 1) & 1) ^ (regs->ctr == 0))\n+\t\top->type |= DECCTR;\n+\t\tif (((bo >> 1) & 1) ^ (regs->ctr == 1))\n \t\t\treturn 0;\n \t}\n \tif ((bo & 0x10) == 0) {\n@@ -92,7 +94,8 @@ static nokprobe_inline long address_ok(struct pt_regs *regs, unsigned long ea, i\n /*\n  * Calculate effective address for a D-form instruction\n  */\n-static nokprobe_inline unsigned long dform_ea(unsigned int instr, struct pt_regs *regs)\n+static nokprobe_inline unsigned long dform_ea(unsigned int instr,\n+\t\t\t\t\t      const struct pt_regs *regs)\n {\n \tint ra;\n \tunsigned long ea;\n@@ -109,7 +112,8 @@ static nokprobe_inline unsigned long dform_ea(unsigned int instr, struct pt_regs\n /*\n  * Calculate effective address for a DS-form instruction\n  */\n-static nokprobe_inline unsigned long dsform_ea(unsigned int instr, struct pt_regs *regs)\n+static nokprobe_inline unsigned long dsform_ea(unsigned int instr,\n+\t\t\t\t\t       const struct pt_regs *regs)\n {\n \tint ra;\n \tunsigned long ea;\n@@ -127,7 +131,7 @@ static nokprobe_inline unsigned long dsform_ea(unsigned int instr, struct pt_reg\n  * Calculate effective address for an X-form instruction\n  */\n static nokprobe_inline unsigned long xform_ea(unsigned int instr,\n-\t\t\t\t\t\tstruct pt_regs *regs)\n+\t\t\t\t\t      const struct pt_regs *regs)\n {\n \tint ra, rb;\n \tunsigned long ea;\n@@ -526,24 +530,27 @@ static nokprobe_inline int do_vsx_store(int rn, int (*func)(int, unsigned long),\n \t\t: \"=r\" (err)\t\t\t\t\\\n \t\t: \"r\" (addr), \"i\" (-EFAULT), \"0\" (err))\n \n-static nokprobe_inline void set_cr0(struct pt_regs *regs, int rd)\n+static nokprobe_inline void set_cr0(const struct pt_regs *regs,\n+\t\t\t\t    struct instruction_op *op, int rd)\n {\n \tlong val = regs->gpr[rd];\n \n-\tregs->ccr = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000);\n+\top->type |= SETCC;\n+\top->ccval = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000);\n #ifdef __powerpc64__\n \tif (!(regs->msr & MSR_64BIT))\n \t\tval = (int) val;\n #endif\n \tif (val < 0)\n-\t\tregs->ccr |= 0x80000000;\n+\t\top->ccval |= 0x80000000;\n \telse if (val > 0)\n-\t\tregs->ccr |= 0x40000000;\n+\t\top->ccval |= 0x40000000;\n \telse\n-\t\tregs->ccr |= 0x20000000;\n+\t\top->ccval |= 0x20000000;\n }\n \n-static nokprobe_inline void add_with_carry(struct pt_regs *regs, int rd,\n+static nokprobe_inline void add_with_carry(const struct pt_regs *regs,\n+\t\t\t\t     struct instruction_op *op, int rd,\n \t\t\t\t     unsigned long val1, unsigned long val2,\n \t\t\t\t     unsigned long carry_in)\n {\n@@ -551,24 +558,29 @@ static nokprobe_inline void add_with_carry(struct pt_regs *regs, int rd,\n \n \tif (carry_in)\n \t\t++val;\n-\tregs->gpr[rd] = val;\n+\top->type = COMPUTE + SETREG + SETXER;\n+\top->reg = rd;\n+\top->val = val;\n #ifdef __powerpc64__\n \tif (!(regs->msr & MSR_64BIT)) {\n \t\tval = (unsigned int) val;\n \t\tval1 = (unsigned int) val1;\n \t}\n #endif\n+\top->xerval = regs->xer;\n \tif (val < val1 || (carry_in && val == val1))\n-\t\tregs->xer |= XER_CA;\n+\t\top->xerval |= XER_CA;\n \telse\n-\t\tregs->xer &= ~XER_CA;\n+\t\top->xerval &= ~XER_CA;\n }\n \n-static nokprobe_inline void do_cmp_signed(struct pt_regs *regs, long v1, long v2,\n-\t\t\t\t    int crfld)\n+static nokprobe_inline void do_cmp_signed(const struct pt_regs *regs,\n+\t\t\t\t\t  struct instruction_op *op,\n+\t\t\t\t\t  long v1, long v2, int crfld)\n {\n \tunsigned int crval, shift;\n \n+\top->type = COMPUTE + SETCC;\n \tcrval = (regs->xer >> 31) & 1;\t\t/* get SO bit */\n \tif (v1 < v2)\n \t\tcrval |= 8;\n@@ -577,14 +589,17 @@ static nokprobe_inline void do_cmp_signed(struct pt_regs *regs, long v1, long v2\n \telse\n \t\tcrval |= 2;\n \tshift = (7 - crfld) * 4;\n-\tregs->ccr = (regs->ccr & ~(0xf << shift)) | (crval << shift);\n+\top->ccval = (regs->ccr & ~(0xf << shift)) | (crval << shift);\n }\n \n-static nokprobe_inline void do_cmp_unsigned(struct pt_regs *regs, unsigned long v1,\n-\t\t\t\t      unsigned long v2, int crfld)\n+static nokprobe_inline void do_cmp_unsigned(const struct pt_regs *regs,\n+\t\t\t\t\t    struct instruction_op *op,\n+\t\t\t\t\t    unsigned long v1,\n+\t\t\t\t\t    unsigned long v2, int crfld)\n {\n \tunsigned int crval, shift;\n \n+\top->type = COMPUTE + SETCC;\n \tcrval = (regs->xer >> 31) & 1;\t\t/* get SO bit */\n \tif (v1 < v2)\n \t\tcrval |= 8;\n@@ -593,11 +608,12 @@ static nokprobe_inline void do_cmp_unsigned(struct pt_regs *regs, unsigned long\n \telse\n \t\tcrval |= 2;\n \tshift = (7 - crfld) * 4;\n-\tregs->ccr = (regs->ccr & ~(0xf << shift)) | (crval << shift);\n+\top->ccval = (regs->ccr & ~(0xf << shift)) | (crval << shift);\n }\n \n-static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1,\n-\t\t\t\tunsigned long v2, int rd)\n+static nokprobe_inline void do_cmpb(const struct pt_regs *regs,\n+\t\t\t\t    struct instruction_op *op,\n+\t\t\t\t    unsigned long v1, unsigned long v2)\n {\n \tunsigned long long out_val, mask;\n \tint i;\n@@ -608,16 +624,16 @@ static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1,\n \t\tif ((v1 & mask) == (v2 & mask))\n \t\t\tout_val |= mask;\n \t}\n-\n-\tregs->gpr[rd] = out_val;\n+\top->val = out_val;\n }\n \n /*\n  * The size parameter is used to adjust the equivalent popcnt instruction.\n  * popcntb = 8, popcntw = 32, popcntd = 64\n  */\n-static nokprobe_inline void do_popcnt(struct pt_regs *regs, unsigned long v1,\n-\t\t\t\tint size, int ra)\n+static nokprobe_inline void do_popcnt(const struct pt_regs *regs,\n+\t\t\t\t      struct instruction_op *op,\n+\t\t\t\t      unsigned long v1, int size)\n {\n \tunsigned long long out = v1;\n \n@@ -626,23 +642,24 @@ static nokprobe_inline void do_popcnt(struct pt_regs *regs, unsigned long v1,\n \tout = (out + (out >> 4)) & 0x0f0f0f0f0f0f0f0f;\n \n \tif (size == 8) {\t/* popcntb */\n-\t\tregs->gpr[ra] = out;\n+\t\top->val = out;\n \t\treturn;\n \t}\n \tout += out >> 8;\n \tout += out >> 16;\n \tif (size == 32) {\t/* popcntw */\n-\t\tregs->gpr[ra] = out & 0x0000003f0000003f;\n+\t\top->val = out & 0x0000003f0000003f;\n \t\treturn;\n \t}\n \n \tout = (out + (out >> 32)) & 0x7f;\n-\tregs->gpr[ra] = out;\t/* popcntd */\n+\top->val = out;\t/* popcntd */\n }\n \n #ifdef CONFIG_PPC64\n-static nokprobe_inline void do_bpermd(struct pt_regs *regs, unsigned long v1,\n-\t\t\t\tunsigned long v2, int ra)\n+static nokprobe_inline void do_bpermd(const struct pt_regs *regs,\n+\t\t\t\t      struct instruction_op *op,\n+\t\t\t\t      unsigned long v1, unsigned long v2)\n {\n \tunsigned char perm, idx;\n \tunsigned int i;\n@@ -654,26 +671,27 @@ static nokprobe_inline void do_bpermd(struct pt_regs *regs, unsigned long v1,\n \t\t\tif (v2 & PPC_BIT(idx))\n \t\t\t\tperm |= 1 << i;\n \t}\n-\tregs->gpr[ra] = perm;\n+\top->val = perm;\n }\n #endif /* CONFIG_PPC64 */\n /*\n  * The size parameter adjusts the equivalent prty instruction.\n  * prtyw = 32, prtyd = 64\n  */\n-static nokprobe_inline void do_prty(struct pt_regs *regs, unsigned long v,\n-\t\t\t\tint size, int ra)\n+static nokprobe_inline void do_prty(const struct pt_regs *regs,\n+\t\t\t\t    struct instruction_op *op,\n+\t\t\t\t    unsigned long v, int size)\n {\n \tunsigned long long res = v ^ (v >> 8);\n \n \tres ^= res >> 16;\n \tif (size == 32) {\t\t/* prtyw */\n-\t\tregs->gpr[ra] = res & 0x0000000100000001;\n+\t\top->val = res & 0x0000000100000001;\n \t\treturn;\n \t}\n \n \tres ^= res >> 32;\n-\tregs->gpr[ra] = res & 1;\t/*prtyd */\n+\top->val = res & 1;\t/*prtyd */\n }\n \n static nokprobe_inline int trap_compare(long v1, long v2)\n@@ -709,14 +727,18 @@ static nokprobe_inline int trap_compare(long v1, long v2)\n #define ROTATE(x, n)\t((n) ? (((x) << (n)) | ((x) >> (8 * sizeof(long) - (n)))) : (x))\n \n /*\n- * Decode an instruction, and execute it if that can be done just by\n- * modifying *regs (i.e. integer arithmetic and logical instructions,\n- * branches, and barrier instructions).\n- * Returns 1 if the instruction has been executed, or 0 if not.\n- * Sets *op to indicate what the instruction does.\n+ * Decode an instruction, and return information about it in *op\n+ * without changing *regs.\n+ * Integer arithmetic and logical instructions, branches, and barrier\n+ * instructions can be emulated just using the information in *op.\n+ *\n+ * Return value is 1 if the instruction can be emulated just by\n+ * updating *regs with the information in *op, -1 if we need the\n+ * GPRs but *regs doesn't contain the full register set, or 0\n+ * otherwise.\n  */\n-int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n-\t\t\t    unsigned int instr)\n+int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,\n+\t\t  unsigned int instr)\n {\n \tunsigned int opcode, ra, rb, rd, spr, u;\n \tunsigned long int imm;\n@@ -733,12 +755,11 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n \t\timm = (signed short)(instr & 0xfffc);\n \t\tif ((instr & 2) == 0)\n \t\t\timm += regs->nip;\n-\t\tregs->nip += 4;\n-\t\tregs->nip = truncate_if_32bit(regs->msr, regs->nip);\n+\t\top->val = truncate_if_32bit(regs->msr, imm);\n \t\tif (instr & 1)\n-\t\t\tregs->link = regs->nip;\n-\t\tif (branch_taken(instr, regs))\n-\t\t\tregs->nip = truncate_if_32bit(regs->msr, imm);\n+\t\t\top->type |= SETLK;\n+\t\tif (branch_taken(instr, regs, op))\n+\t\t\top->type |= BRTAKEN;\n \t\treturn 1;\n #ifdef CONFIG_PPC64\n \tcase 17:\t/* sc */\n@@ -749,38 +770,37 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n \t\treturn 0;\n #endif\n \tcase 18:\t/* b */\n-\t\top->type = BRANCH;\n+\t\top->type = BRANCH | BRTAKEN;\n \t\timm = instr & 0x03fffffc;\n \t\tif (imm & 0x02000000)\n \t\t\timm -= 0x04000000;\n \t\tif ((instr & 2) == 0)\n \t\t\timm += regs->nip;\n+\t\top->val = truncate_if_32bit(regs->msr, imm);\n \t\tif (instr & 1)\n-\t\t\tregs->link = truncate_if_32bit(regs->msr, regs->nip + 4);\n-\t\timm = truncate_if_32bit(regs->msr, imm);\n-\t\tregs->nip = imm;\n+\t\t\top->type |= SETLK;\n \t\treturn 1;\n \tcase 19:\n \t\tswitch ((instr >> 1) & 0x3ff) {\n \t\tcase 0:\t\t/* mcrf */\n+\t\t\top->type = COMPUTE + SETCC;\n \t\t\trd = 7 - ((instr >> 23) & 0x7);\n \t\t\tra = 7 - ((instr >> 18) & 0x7);\n \t\t\trd *= 4;\n \t\t\tra *= 4;\n \t\t\tval = (regs->ccr >> ra) & 0xf;\n-\t\t\tregs->ccr = (regs->ccr & ~(0xfUL << rd)) | (val << rd);\n-\t\t\tgoto instr_done;\n+\t\t\top->ccval = (regs->ccr & ~(0xfUL << rd)) | (val << rd);\n+\t\t\treturn 1;\n \n \t\tcase 16:\t/* bclr */\n \t\tcase 528:\t/* bcctr */\n \t\t\top->type = BRANCH;\n \t\t\timm = (instr & 0x400)? regs->ctr: regs->link;\n-\t\t\tregs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);\n-\t\t\timm = truncate_if_32bit(regs->msr, imm);\n+\t\t\top->val = truncate_if_32bit(regs->msr, imm);\n \t\t\tif (instr & 1)\n-\t\t\t\tregs->link = regs->nip;\n-\t\t\tif (branch_taken(instr, regs))\n-\t\t\t\tregs->nip = imm;\n+\t\t\t\top->type |= SETLK;\n+\t\t\tif (branch_taken(instr, regs, op))\n+\t\t\t\top->type |= BRTAKEN;\n \t\t\treturn 1;\n \n \t\tcase 18:\t/* rfid, scary */\n@@ -790,9 +810,8 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n \t\t\treturn 0;\n \n \t\tcase 150:\t/* isync */\n-\t\t\top->type = BARRIER;\n-\t\t\tisync();\n-\t\t\tgoto instr_done;\n+\t\t\top->type = BARRIER | BARRIER_ISYNC;\n+\t\t\treturn 1;\n \n \t\tcase 33:\t/* crnor */\n \t\tcase 129:\t/* crandc */\n@@ -802,45 +821,47 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n \t\tcase 289:\t/* creqv */\n \t\tcase 417:\t/* crorc */\n \t\tcase 449:\t/* cror */\n+\t\t\top->type = COMPUTE + SETCC;\n \t\t\tra = (instr >> 16) & 0x1f;\n \t\t\trb = (instr >> 11) & 0x1f;\n \t\t\trd = (instr >> 21) & 0x1f;\n \t\t\tra = (regs->ccr >> (31 - ra)) & 1;\n \t\t\trb = (regs->ccr >> (31 - rb)) & 1;\n \t\t\tval = (instr >> (6 + ra * 2 + rb)) & 1;\n-\t\t\tregs->ccr = (regs->ccr & ~(1UL << (31 - rd))) |\n+\t\t\top->ccval = (regs->ccr & ~(1UL << (31 - rd))) |\n \t\t\t\t(val << (31 - rd));\n-\t\t\tgoto instr_done;\n+\t\t\treturn 1;\n+\t\tdefault:\n+\t\t\top->type = UNKNOWN;\n+\t\t\treturn 0;\n \t\t}\n \t\tbreak;\n \tcase 31:\n \t\tswitch ((instr >> 1) & 0x3ff) {\n \t\tcase 598:\t/* sync */\n-\t\t\top->type = BARRIER;\n+\t\t\top->type = BARRIER + BARRIER_SYNC;\n #ifdef __powerpc64__\n \t\t\tswitch ((instr >> 21) & 3) {\n \t\t\tcase 1:\t\t/* lwsync */\n-\t\t\t\tasm volatile(\"lwsync\" : : : \"memory\");\n-\t\t\t\tgoto instr_done;\n+\t\t\t\top->type = BARRIER + BARRIER_LWSYNC;\n+\t\t\t\tbreak;\n \t\t\tcase 2:\t\t/* ptesync */\n-\t\t\t\tasm volatile(\"ptesync\" : : : \"memory\");\n-\t\t\t\tgoto instr_done;\n+\t\t\t\top->type = BARRIER + BARRIER_PTESYNC;\n+\t\t\t\tbreak;\n \t\t\t}\n #endif\n-\t\t\tmb();\n-\t\t\tgoto instr_done;\n+\t\t\treturn 1;\n \n \t\tcase 854:\t/* eieio */\n-\t\t\top->type = BARRIER;\n-\t\t\teieio();\n-\t\t\tgoto instr_done;\n+\t\t\top->type = BARRIER + BARRIER_EIEIO;\n+\t\t\treturn 1;\n \t\t}\n \t\tbreak;\n \t}\n \n \t/* Following cases refer to regs->gpr[], so we need all regs */\n \tif (!FULL_REGS(regs))\n-\t\treturn 0;\n+\t\treturn -1;\n \n \trd = (instr >> 21) & 0x1f;\n \tra = (instr >> 16) & 0x1f;\n@@ -851,21 +872,21 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n \tcase 2:\t\t/* tdi */\n \t\tif (rd & trap_compare(regs->gpr[ra], (short) instr))\n \t\t\tgoto trap;\n-\t\tgoto instr_done;\n+\t\treturn 1;\n #endif\n \tcase 3:\t\t/* twi */\n \t\tif (rd & trap_compare((int)regs->gpr[ra], (short) instr))\n \t\t\tgoto trap;\n-\t\tgoto instr_done;\n+\t\treturn 1;\n \n \tcase 7:\t\t/* mulli */\n-\t\tregs->gpr[rd] = regs->gpr[ra] * (short) instr;\n-\t\tgoto instr_done;\n+\t\top->val = regs->gpr[ra] * (short) instr;\n+\t\tgoto compute_done;\n \n \tcase 8:\t\t/* subfic */\n \t\timm = (short) instr;\n-\t\tadd_with_carry(regs, rd, ~regs->gpr[ra], imm, 1);\n-\t\tgoto instr_done;\n+\t\tadd_with_carry(regs, op, rd, ~regs->gpr[ra], imm, 1);\n+\t\treturn 1;\n \n \tcase 10:\t/* cmpli */\n \t\timm = (unsigned short) instr;\n@@ -874,8 +895,8 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n \t\tif ((rd & 1) == 0)\n \t\t\tval = (unsigned int) val;\n #endif\n-\t\tdo_cmp_unsigned(regs, val, imm, rd >> 2);\n-\t\tgoto instr_done;\n+\t\tdo_cmp_unsigned(regs, op, val, imm, rd >> 2);\n+\t\treturn 1;\n \n \tcase 11:\t/* cmpi */\n \t\timm = (short) instr;\n@@ -884,47 +905,47 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n \t\tif ((rd & 1) == 0)\n \t\t\tval = (int) val;\n #endif\n-\t\tdo_cmp_signed(regs, val, imm, rd >> 2);\n-\t\tgoto instr_done;\n+\t\tdo_cmp_signed(regs, op, val, imm, rd >> 2);\n+\t\treturn 1;\n \n \tcase 12:\t/* addic */\n \t\timm = (short) instr;\n-\t\tadd_with_carry(regs, rd, regs->gpr[ra], imm, 0);\n-\t\tgoto instr_done;\n+\t\tadd_with_carry(regs, op, rd, regs->gpr[ra], imm, 0);\n+\t\treturn 1;\n \n \tcase 13:\t/* addic. */\n \t\timm = (short) instr;\n-\t\tadd_with_carry(regs, rd, regs->gpr[ra], imm, 0);\n-\t\tset_cr0(regs, rd);\n-\t\tgoto instr_done;\n+\t\tadd_with_carry(regs, op, rd, regs->gpr[ra], imm, 0);\n+\t\tset_cr0(regs, op, rd);\n+\t\treturn 1;\n \n \tcase 14:\t/* addi */\n \t\timm = (short) instr;\n \t\tif (ra)\n \t\t\timm += regs->gpr[ra];\n-\t\tregs->gpr[rd] = imm;\n-\t\tgoto instr_done;\n+\t\top->val = imm;\n+\t\tgoto compute_done;\n \n \tcase 15:\t/* addis */\n \t\timm = ((short) instr) << 16;\n \t\tif (ra)\n \t\t\timm += regs->gpr[ra];\n-\t\tregs->gpr[rd] = imm;\n-\t\tgoto instr_done;\n+\t\top->val = imm;\n+\t\tgoto compute_done;\n \n \tcase 20:\t/* rlwimi */\n \t\tmb = (instr >> 6) & 0x1f;\n \t\tme = (instr >> 1) & 0x1f;\n \t\tval = DATA32(regs->gpr[rd]);\n \t\timm = MASK32(mb, me);\n-\t\tregs->gpr[ra] = (regs->gpr[ra] & ~imm) | (ROTATE(val, rb) & imm);\n+\t\top->val = (regs->gpr[ra] & ~imm) | (ROTATE(val, rb) & imm);\n \t\tgoto logical_done;\n \n \tcase 21:\t/* rlwinm */\n \t\tmb = (instr >> 6) & 0x1f;\n \t\tme = (instr >> 1) & 0x1f;\n \t\tval = DATA32(regs->gpr[rd]);\n-\t\tregs->gpr[ra] = ROTATE(val, rb) & MASK32(mb, me);\n+\t\top->val = ROTATE(val, rb) & MASK32(mb, me);\n \t\tgoto logical_done;\n \n \tcase 23:\t/* rlwnm */\n@@ -932,40 +953,37 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n \t\tme = (instr >> 1) & 0x1f;\n \t\trb = regs->gpr[rb] & 0x1f;\n \t\tval = DATA32(regs->gpr[rd]);\n-\t\tregs->gpr[ra] = ROTATE(val, rb) & MASK32(mb, me);\n+\t\top->val = ROTATE(val, rb) & MASK32(mb, me);\n \t\tgoto logical_done;\n \n \tcase 24:\t/* ori */\n-\t\timm = (unsigned short) instr;\n-\t\tregs->gpr[ra] = regs->gpr[rd] | imm;\n-\t\tgoto instr_done;\n+\t\top->val = regs->gpr[rd] | (unsigned short) instr;\n+\t\tgoto logical_done_nocc;\n \n \tcase 25:\t/* oris */\n \t\timm = (unsigned short) instr;\n-\t\tregs->gpr[ra] = regs->gpr[rd] | (imm << 16);\n-\t\tgoto instr_done;\n+\t\top->val = regs->gpr[rd] | (imm << 16);\n+\t\tgoto logical_done_nocc;\n \n \tcase 26:\t/* xori */\n-\t\timm = (unsigned short) instr;\n-\t\tregs->gpr[ra] = regs->gpr[rd] ^ imm;\n-\t\tgoto instr_done;\n+\t\top->val = regs->gpr[rd] ^ (unsigned short) instr;\n+\t\tgoto logical_done_nocc;\n \n \tcase 27:\t/* xoris */\n \t\timm = (unsigned short) instr;\n-\t\tregs->gpr[ra] = regs->gpr[rd] ^ (imm << 16);\n-\t\tgoto instr_done;\n+\t\top->val = regs->gpr[rd] ^ (imm << 16);\n+\t\tgoto logical_done_nocc;\n \n \tcase 28:\t/* andi. */\n-\t\timm = (unsigned short) instr;\n-\t\tregs->gpr[ra] = regs->gpr[rd] & imm;\n-\t\tset_cr0(regs, ra);\n-\t\tgoto instr_done;\n+\t\top->val = regs->gpr[rd] & (unsigned short) instr;\n+\t\tset_cr0(regs, op, ra);\n+\t\tgoto logical_done_nocc;\n \n \tcase 29:\t/* andis. */\n \t\timm = (unsigned short) instr;\n-\t\tregs->gpr[ra] = regs->gpr[rd] & (imm << 16);\n-\t\tset_cr0(regs, ra);\n-\t\tgoto instr_done;\n+\t\top->val = regs->gpr[rd] & (imm << 16);\n+\t\tset_cr0(regs, op, ra);\n+\t\tgoto logical_done_nocc;\n \n #ifdef __powerpc64__\n \tcase 30:\t/* rld* */\n@@ -976,34 +994,36 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n \t\t\tval = ROTATE(val, sh);\n \t\t\tswitch ((instr >> 2) & 3) {\n \t\t\tcase 0:\t\t/* rldicl */\n-\t\t\t\tregs->gpr[ra] = val & MASK64_L(mb);\n-\t\t\t\tgoto logical_done;\n+\t\t\t\tval &= MASK64_L(mb);\n+\t\t\t\tbreak;\n \t\t\tcase 1:\t\t/* rldicr */\n-\t\t\t\tregs->gpr[ra] = val & MASK64_R(mb);\n-\t\t\t\tgoto logical_done;\n+\t\t\t\tval &= MASK64_R(mb);\n+\t\t\t\tbreak;\n \t\t\tcase 2:\t\t/* rldic */\n-\t\t\t\tregs->gpr[ra] = val & MASK64(mb, 63 - sh);\n-\t\t\t\tgoto logical_done;\n+\t\t\t\tval &= MASK64(mb, 63 - sh);\n+\t\t\t\tbreak;\n \t\t\tcase 3:\t\t/* rldimi */\n \t\t\t\timm = MASK64(mb, 63 - sh);\n-\t\t\t\tregs->gpr[ra] = (regs->gpr[ra] & ~imm) |\n+\t\t\t\tval = (regs->gpr[ra] & ~imm) |\n \t\t\t\t\t(val & imm);\n-\t\t\t\tgoto logical_done;\n \t\t\t}\n+\t\t\top->val = val;\n+\t\t\tgoto logical_done;\n \t\t} else {\n \t\t\tsh = regs->gpr[rb] & 0x3f;\n \t\t\tval = ROTATE(val, sh);\n \t\t\tswitch ((instr >> 1) & 7) {\n \t\t\tcase 0:\t\t/* rldcl */\n-\t\t\t\tregs->gpr[ra] = val & MASK64_L(mb);\n+\t\t\t\top->val = val & MASK64_L(mb);\n \t\t\t\tgoto logical_done;\n \t\t\tcase 1:\t\t/* rldcr */\n-\t\t\t\tregs->gpr[ra] = val & MASK64_R(mb);\n+\t\t\t\top->val = val & MASK64_R(mb);\n \t\t\t\tgoto logical_done;\n \t\t\t}\n \t\t}\n #endif\n-\tbreak; /* illegal instruction */\n+\t\top->type = UNKNOWN;\t/* illegal instruction */\n+\t\treturn 0;\n \n \tcase 31:\n \t\tswitch ((instr >> 1) & 0x3ff) {\n@@ -1012,12 +1032,12 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n \t\t\t    (rd & trap_compare((int)regs->gpr[ra],\n \t\t\t\t\t       (int)regs->gpr[rb])))\n \t\t\t\tgoto trap;\n-\t\t\tgoto instr_done;\n+\t\t\treturn 1;\n #ifdef __powerpc64__\n \t\tcase 68:\t/* td */\n \t\t\tif (rd & trap_compare(regs->gpr[ra], regs->gpr[rb]))\n \t\t\t\tgoto trap;\n-\t\t\tgoto instr_done;\n+\t\t\treturn 1;\n #endif\n \t\tcase 83:\t/* mfmsr */\n \t\t\tif (regs->msr & MSR_PR)\n@@ -1046,74 +1066,50 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n #endif\n \n \t\tcase 19:\t/* mfcr */\n+\t\t\timm = 0xffffffffUL;\n \t\t\tif ((instr >> 20) & 1) {\n \t\t\t\timm = 0xf0000000UL;\n \t\t\t\tfor (sh = 0; sh < 8; ++sh) {\n-\t\t\t\t\tif (instr & (0x80000 >> sh)) {\n-\t\t\t\t\t\tregs->gpr[rd] = regs->ccr & imm;\n+\t\t\t\t\tif (instr & (0x80000 >> sh))\n \t\t\t\t\t\tbreak;\n-\t\t\t\t\t}\n \t\t\t\t\timm >>= 4;\n \t\t\t\t}\n-\n-\t\t\t\tgoto instr_done;\n \t\t\t}\n-\n-\t\t\tregs->gpr[rd] = regs->ccr;\n-\t\t\tregs->gpr[rd] &= 0xffffffffUL;\n-\t\t\tgoto instr_done;\n+\t\t\top->val = regs->ccr & imm;\n+\t\t\tgoto compute_done;\n \n \t\tcase 144:\t/* mtcrf */\n+\t\t\top->type = COMPUTE + SETCC;\n \t\t\timm = 0xf0000000UL;\n \t\t\tval = regs->gpr[rd];\n+\t\t\top->val = regs->ccr;\n \t\t\tfor (sh = 0; sh < 8; ++sh) {\n \t\t\t\tif (instr & (0x80000 >> sh))\n-\t\t\t\t\tregs->ccr = (regs->ccr & ~imm) |\n+\t\t\t\t\top->val = (op->val & ~imm) |\n \t\t\t\t\t\t(val & imm);\n \t\t\t\timm >>= 4;\n \t\t\t}\n-\t\t\tgoto instr_done;\n+\t\t\treturn 1;\n \n \t\tcase 339:\t/* mfspr */\n \t\t\tspr = ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0);\n-\t\t\tswitch (spr) {\n-\t\t\tcase SPRN_XER:\t/* mfxer */\n-\t\t\t\tregs->gpr[rd] = regs->xer;\n-\t\t\t\tregs->gpr[rd] &= 0xffffffffUL;\n-\t\t\t\tgoto instr_done;\n-\t\t\tcase SPRN_LR:\t/* mflr */\n-\t\t\t\tregs->gpr[rd] = regs->link;\n-\t\t\t\tgoto instr_done;\n-\t\t\tcase SPRN_CTR:\t/* mfctr */\n-\t\t\t\tregs->gpr[rd] = regs->ctr;\n-\t\t\t\tgoto instr_done;\n-\t\t\tdefault:\n-\t\t\t\top->type = MFSPR;\n-\t\t\t\top->reg = rd;\n-\t\t\t\top->spr = spr;\n-\t\t\t\treturn 0;\n-\t\t\t}\n-\t\t\tbreak;\n+\t\t\top->type = MFSPR;\n+\t\t\top->reg = rd;\n+\t\t\top->spr = spr;\n+\t\t\tif (spr == SPRN_XER || spr == SPRN_LR ||\n+\t\t\t    spr == SPRN_CTR)\n+\t\t\t\treturn 1;\n+\t\t\treturn 0;\n \n \t\tcase 467:\t/* mtspr */\n \t\t\tspr = ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0);\n-\t\t\tswitch (spr) {\n-\t\t\tcase SPRN_XER:\t/* mtxer */\n-\t\t\t\tregs->xer = (regs->gpr[rd] & 0xffffffffUL);\n-\t\t\t\tgoto instr_done;\n-\t\t\tcase SPRN_LR:\t/* mtlr */\n-\t\t\t\tregs->link = regs->gpr[rd];\n-\t\t\t\tgoto instr_done;\n-\t\t\tcase SPRN_CTR:\t/* mtctr */\n-\t\t\t\tregs->ctr = regs->gpr[rd];\n-\t\t\t\tgoto instr_done;\n-\t\t\tdefault:\n-\t\t\t\top->type = MTSPR;\n-\t\t\t\top->val = regs->gpr[rd];\n-\t\t\t\top->spr = spr;\n-\t\t\t\treturn 0;\n-\t\t\t}\n-\t\t\tbreak;\n+\t\t\top->type = MTSPR;\n+\t\t\top->val = regs->gpr[rd];\n+\t\t\top->spr = spr;\n+\t\t\tif (spr == SPRN_XER || spr == SPRN_LR ||\n+\t\t\t    spr == SPRN_CTR)\n+\t\t\t\treturn 1;\n+\t\t\treturn 0;\n \n /*\n  * Compare instructions\n@@ -1128,8 +1124,8 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n \t\t\t\tval2 = (int) val2;\n \t\t\t}\n #endif\n-\t\t\tdo_cmp_signed(regs, val, val2, rd >> 2);\n-\t\t\tgoto instr_done;\n+\t\t\tdo_cmp_signed(regs, op, val, val2, rd >> 2);\n+\t\t\treturn 1;\n \n \t\tcase 32:\t/* cmpl */\n \t\t\tval = regs->gpr[ra];\n@@ -1141,113 +1137,113 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n \t\t\t\tval2 = (unsigned int) val2;\n \t\t\t}\n #endif\n-\t\t\tdo_cmp_unsigned(regs, val, val2, rd >> 2);\n-\t\t\tgoto instr_done;\n+\t\t\tdo_cmp_unsigned(regs, op, val, val2, rd >> 2);\n+\t\t\treturn 1;\n \n \t\tcase 508: /* cmpb */\n-\t\t\tdo_cmpb(regs, regs->gpr[rd], regs->gpr[rb], ra);\n-\t\t\tgoto instr_done;\n+\t\t\tdo_cmpb(regs, op, regs->gpr[rd], regs->gpr[rb]);\n+\t\t\tgoto logical_done_nocc;\n \n /*\n  * Arithmetic instructions\n  */\n \t\tcase 8:\t/* subfc */\n-\t\t\tadd_with_carry(regs, rd, ~regs->gpr[ra],\n+\t\t\tadd_with_carry(regs, op, rd, ~regs->gpr[ra],\n \t\t\t\t       regs->gpr[rb], 1);\n \t\t\tgoto arith_done;\n #ifdef __powerpc64__\n \t\tcase 9:\t/* mulhdu */\n-\t\t\tasm(\"mulhdu %0,%1,%2\" : \"=r\" (regs->gpr[rd]) :\n+\t\t\tasm(\"mulhdu %0,%1,%2\" : \"=r\" (op->val) :\n \t\t\t    \"r\" (regs->gpr[ra]), \"r\" (regs->gpr[rb]));\n \t\t\tgoto arith_done;\n #endif\n \t\tcase 10:\t/* addc */\n-\t\t\tadd_with_carry(regs, rd, regs->gpr[ra],\n+\t\t\tadd_with_carry(regs, op, rd, regs->gpr[ra],\n \t\t\t\t       regs->gpr[rb], 0);\n \t\t\tgoto arith_done;\n \n \t\tcase 11:\t/* mulhwu */\n-\t\t\tasm(\"mulhwu %0,%1,%2\" : \"=r\" (regs->gpr[rd]) :\n+\t\t\tasm(\"mulhwu %0,%1,%2\" : \"=r\" (op->val) :\n \t\t\t    \"r\" (regs->gpr[ra]), \"r\" (regs->gpr[rb]));\n \t\t\tgoto arith_done;\n \n \t\tcase 40:\t/* subf */\n-\t\t\tregs->gpr[rd] = regs->gpr[rb] - regs->gpr[ra];\n+\t\t\top->val = regs->gpr[rb] - regs->gpr[ra];\n \t\t\tgoto arith_done;\n #ifdef __powerpc64__\n \t\tcase 73:\t/* mulhd */\n-\t\t\tasm(\"mulhd %0,%1,%2\" : \"=r\" (regs->gpr[rd]) :\n+\t\t\tasm(\"mulhd %0,%1,%2\" : \"=r\" (op->val) :\n \t\t\t    \"r\" (regs->gpr[ra]), \"r\" (regs->gpr[rb]));\n \t\t\tgoto arith_done;\n #endif\n \t\tcase 75:\t/* mulhw */\n-\t\t\tasm(\"mulhw %0,%1,%2\" : \"=r\" (regs->gpr[rd]) :\n+\t\t\tasm(\"mulhw %0,%1,%2\" : \"=r\" (op->val) :\n \t\t\t    \"r\" (regs->gpr[ra]), \"r\" (regs->gpr[rb]));\n \t\t\tgoto arith_done;\n \n \t\tcase 104:\t/* neg */\n-\t\t\tregs->gpr[rd] = -regs->gpr[ra];\n+\t\t\top->val = -regs->gpr[ra];\n \t\t\tgoto arith_done;\n \n \t\tcase 136:\t/* subfe */\n-\t\t\tadd_with_carry(regs, rd, ~regs->gpr[ra], regs->gpr[rb],\n-\t\t\t\t       regs->xer & XER_CA);\n+\t\t\tadd_with_carry(regs, op, rd, ~regs->gpr[ra],\n+\t\t\t\t       regs->gpr[rb], regs->xer & XER_CA);\n \t\t\tgoto arith_done;\n \n \t\tcase 138:\t/* adde */\n-\t\t\tadd_with_carry(regs, rd, regs->gpr[ra], regs->gpr[rb],\n-\t\t\t\t       regs->xer & XER_CA);\n+\t\t\tadd_with_carry(regs, op, rd, regs->gpr[ra],\n+\t\t\t\t       regs->gpr[rb], regs->xer & XER_CA);\n \t\t\tgoto arith_done;\n \n \t\tcase 200:\t/* subfze */\n-\t\t\tadd_with_carry(regs, rd, ~regs->gpr[ra], 0L,\n+\t\t\tadd_with_carry(regs, op, rd, ~regs->gpr[ra], 0L,\n \t\t\t\t       regs->xer & XER_CA);\n \t\t\tgoto arith_done;\n \n \t\tcase 202:\t/* addze */\n-\t\t\tadd_with_carry(regs, rd, regs->gpr[ra], 0L,\n+\t\t\tadd_with_carry(regs, op, rd, regs->gpr[ra], 0L,\n \t\t\t\t       regs->xer & XER_CA);\n \t\t\tgoto arith_done;\n \n \t\tcase 232:\t/* subfme */\n-\t\t\tadd_with_carry(regs, rd, ~regs->gpr[ra], -1L,\n+\t\t\tadd_with_carry(regs, op, rd, ~regs->gpr[ra], -1L,\n \t\t\t\t       regs->xer & XER_CA);\n \t\t\tgoto arith_done;\n #ifdef __powerpc64__\n \t\tcase 233:\t/* mulld */\n-\t\t\tregs->gpr[rd] = regs->gpr[ra] * regs->gpr[rb];\n+\t\t\top->val = regs->gpr[ra] * regs->gpr[rb];\n \t\t\tgoto arith_done;\n #endif\n \t\tcase 234:\t/* addme */\n-\t\t\tadd_with_carry(regs, rd, regs->gpr[ra], -1L,\n+\t\t\tadd_with_carry(regs, op, rd, regs->gpr[ra], -1L,\n \t\t\t\t       regs->xer & XER_CA);\n \t\t\tgoto arith_done;\n \n \t\tcase 235:\t/* mullw */\n-\t\t\tregs->gpr[rd] = (unsigned int) regs->gpr[ra] *\n+\t\t\top->val = (unsigned int) regs->gpr[ra] *\n \t\t\t\t(unsigned int) regs->gpr[rb];\n \t\t\tgoto arith_done;\n \n \t\tcase 266:\t/* add */\n-\t\t\tregs->gpr[rd] = regs->gpr[ra] + regs->gpr[rb];\n+\t\t\top->val = regs->gpr[ra] + regs->gpr[rb];\n \t\t\tgoto arith_done;\n #ifdef __powerpc64__\n \t\tcase 457:\t/* divdu */\n-\t\t\tregs->gpr[rd] = regs->gpr[ra] / regs->gpr[rb];\n+\t\t\top->val = regs->gpr[ra] / regs->gpr[rb];\n \t\t\tgoto arith_done;\n #endif\n \t\tcase 459:\t/* divwu */\n-\t\t\tregs->gpr[rd] = (unsigned int) regs->gpr[ra] /\n+\t\t\top->val = (unsigned int) regs->gpr[ra] /\n \t\t\t\t(unsigned int) regs->gpr[rb];\n \t\t\tgoto arith_done;\n #ifdef __powerpc64__\n \t\tcase 489:\t/* divd */\n-\t\t\tregs->gpr[rd] = (long int) regs->gpr[ra] /\n+\t\t\top->val = (long int) regs->gpr[ra] /\n \t\t\t\t(long int) regs->gpr[rb];\n \t\t\tgoto arith_done;\n #endif\n \t\tcase 491:\t/* divw */\n-\t\t\tregs->gpr[rd] = (int) regs->gpr[ra] /\n+\t\t\top->val = (int) regs->gpr[ra] /\n \t\t\t\t(int) regs->gpr[rb];\n \t\t\tgoto arith_done;\n \n@@ -1260,85 +1256,83 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n \t\t\tval = (regs->ccr >> (31 - mb)) & 1;\n \t\t\tval2 = (ra) ? regs->gpr[ra] : 0;\n \n-\t\t\tregs->gpr[rd] = (val) ? val2 : regs->gpr[rb];\n-\t\t\tgoto logical_done;\n+\t\t\top->val = (val) ? val2 : regs->gpr[rb];\n+\t\t\tgoto compute_done;\n \n \t\tcase 26:\t/* cntlzw */\n-\t\t\tasm(\"cntlzw %0,%1\" : \"=r\" (regs->gpr[ra]) :\n-\t\t\t    \"r\" (regs->gpr[rd]));\n+\t\t\top->val = __builtin_clz((unsigned int) regs->gpr[rd]);\n \t\t\tgoto logical_done;\n #ifdef __powerpc64__\n \t\tcase 58:\t/* cntlzd */\n-\t\t\tasm(\"cntlzd %0,%1\" : \"=r\" (regs->gpr[ra]) :\n-\t\t\t    \"r\" (regs->gpr[rd]));\n+\t\t\top->val = __builtin_clzl(regs->gpr[rd]);\n \t\t\tgoto logical_done;\n #endif\n \t\tcase 28:\t/* and */\n-\t\t\tregs->gpr[ra] = regs->gpr[rd] & regs->gpr[rb];\n+\t\t\top->val = regs->gpr[rd] & regs->gpr[rb];\n \t\t\tgoto logical_done;\n \n \t\tcase 60:\t/* andc */\n-\t\t\tregs->gpr[ra] = regs->gpr[rd] & ~regs->gpr[rb];\n+\t\t\top->val = regs->gpr[rd] & ~regs->gpr[rb];\n \t\t\tgoto logical_done;\n \n \t\tcase 122:\t/* popcntb */\n-\t\t\tdo_popcnt(regs, regs->gpr[rd], 8, ra);\n+\t\t\tdo_popcnt(regs, op, regs->gpr[rd], 8);\n \t\t\tgoto logical_done;\n \n \t\tcase 124:\t/* nor */\n-\t\t\tregs->gpr[ra] = ~(regs->gpr[rd] | regs->gpr[rb]);\n+\t\t\top->val = ~(regs->gpr[rd] | regs->gpr[rb]);\n \t\t\tgoto logical_done;\n \n \t\tcase 154:\t/* prtyw */\n-\t\t\tdo_prty(regs, regs->gpr[rd], 32, ra);\n+\t\t\tdo_prty(regs, op, regs->gpr[rd], 32);\n \t\t\tgoto logical_done;\n \n \t\tcase 186:\t/* prtyd */\n-\t\t\tdo_prty(regs, regs->gpr[rd], 64, ra);\n+\t\t\tdo_prty(regs, op, regs->gpr[rd], 64);\n \t\t\tgoto logical_done;\n #ifdef CONFIG_PPC64\n \t\tcase 252:\t/* bpermd */\n-\t\t\tdo_bpermd(regs, regs->gpr[rd], regs->gpr[rb], ra);\n+\t\t\tdo_bpermd(regs, op, regs->gpr[rd], regs->gpr[rb]);\n \t\t\tgoto logical_done;\n #endif\n \t\tcase 284:\t/* xor */\n-\t\t\tregs->gpr[ra] = ~(regs->gpr[rd] ^ regs->gpr[rb]);\n+\t\t\top->val = ~(regs->gpr[rd] ^ regs->gpr[rb]);\n \t\t\tgoto logical_done;\n \n \t\tcase 316:\t/* xor */\n-\t\t\tregs->gpr[ra] = regs->gpr[rd] ^ regs->gpr[rb];\n+\t\t\top->val = regs->gpr[rd] ^ regs->gpr[rb];\n \t\t\tgoto logical_done;\n \n \t\tcase 378:\t/* popcntw */\n-\t\t\tdo_popcnt(regs, regs->gpr[rd], 32, ra);\n+\t\t\tdo_popcnt(regs, op, regs->gpr[rd], 32);\n \t\t\tgoto logical_done;\n \n \t\tcase 412:\t/* orc */\n-\t\t\tregs->gpr[ra] = regs->gpr[rd] | ~regs->gpr[rb];\n+\t\t\top->val = regs->gpr[rd] | ~regs->gpr[rb];\n \t\t\tgoto logical_done;\n \n \t\tcase 444:\t/* or */\n-\t\t\tregs->gpr[ra] = regs->gpr[rd] | regs->gpr[rb];\n+\t\t\top->val = regs->gpr[rd] | regs->gpr[rb];\n \t\t\tgoto logical_done;\n \n \t\tcase 476:\t/* nand */\n-\t\t\tregs->gpr[ra] = ~(regs->gpr[rd] & regs->gpr[rb]);\n+\t\t\top->val = ~(regs->gpr[rd] & regs->gpr[rb]);\n \t\t\tgoto logical_done;\n #ifdef CONFIG_PPC64\n \t\tcase 506:\t/* popcntd */\n-\t\t\tdo_popcnt(regs, regs->gpr[rd], 64, ra);\n+\t\t\tdo_popcnt(regs, op, regs->gpr[rd], 64);\n \t\t\tgoto logical_done;\n #endif\n \t\tcase 922:\t/* extsh */\n-\t\t\tregs->gpr[ra] = (signed short) regs->gpr[rd];\n+\t\t\top->val = (signed short) regs->gpr[rd];\n \t\t\tgoto logical_done;\n \n \t\tcase 954:\t/* extsb */\n-\t\t\tregs->gpr[ra] = (signed char) regs->gpr[rd];\n+\t\t\top->val = (signed char) regs->gpr[rd];\n \t\t\tgoto logical_done;\n #ifdef __powerpc64__\n \t\tcase 986:\t/* extsw */\n-\t\t\tregs->gpr[ra] = (signed int) regs->gpr[rd];\n+\t\t\top->val = (signed int) regs->gpr[rd];\n \t\t\tgoto logical_done;\n #endif\n \n@@ -1348,75 +1342,83 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n \t\tcase 24:\t/* slw */\n \t\t\tsh = regs->gpr[rb] & 0x3f;\n \t\t\tif (sh < 32)\n-\t\t\t\tregs->gpr[ra] = (regs->gpr[rd] << sh) & 0xffffffffUL;\n+\t\t\t\top->val = (regs->gpr[rd] << sh) & 0xffffffffUL;\n \t\t\telse\n-\t\t\t\tregs->gpr[ra] = 0;\n+\t\t\t\top->val = 0;\n \t\t\tgoto logical_done;\n \n \t\tcase 536:\t/* srw */\n \t\t\tsh = regs->gpr[rb] & 0x3f;\n \t\t\tif (sh < 32)\n-\t\t\t\tregs->gpr[ra] = (regs->gpr[rd] & 0xffffffffUL) >> sh;\n+\t\t\t\top->val = (regs->gpr[rd] & 0xffffffffUL) >> sh;\n \t\t\telse\n-\t\t\t\tregs->gpr[ra] = 0;\n+\t\t\t\top->val = 0;\n \t\t\tgoto logical_done;\n \n \t\tcase 792:\t/* sraw */\n+\t\t\top->type = COMPUTE + SETREG + SETXER;\n \t\t\tsh = regs->gpr[rb] & 0x3f;\n \t\t\tival = (signed int) regs->gpr[rd];\n-\t\t\tregs->gpr[ra] = ival >> (sh < 32 ? sh : 31);\n+\t\t\top->val = ival >> (sh < 32 ? sh : 31);\n+\t\t\top->xerval = regs->xer;\n \t\t\tif (ival < 0 && (sh >= 32 || (ival & ((1ul << sh) - 1)) != 0))\n-\t\t\t\tregs->xer |= XER_CA;\n+\t\t\t\top->xerval |= XER_CA;\n \t\t\telse\n-\t\t\t\tregs->xer &= ~XER_CA;\n+\t\t\t\top->xerval &= ~XER_CA;\n \t\t\tgoto logical_done;\n \n \t\tcase 824:\t/* srawi */\n+\t\t\top->type = COMPUTE + SETREG + SETXER;\n \t\t\tsh = rb;\n \t\t\tival = (signed int) regs->gpr[rd];\n-\t\t\tregs->gpr[ra] = ival >> sh;\n+\t\t\top->val = ival >> sh;\n+\t\t\top->xerval = regs->xer;\n \t\t\tif (ival < 0 && (ival & ((1ul << sh) - 1)) != 0)\n-\t\t\t\tregs->xer |= XER_CA;\n+\t\t\t\top->xerval |= XER_CA;\n \t\t\telse\n-\t\t\t\tregs->xer &= ~XER_CA;\n+\t\t\t\top->xerval &= ~XER_CA;\n \t\t\tgoto logical_done;\n \n #ifdef __powerpc64__\n \t\tcase 27:\t/* sld */\n \t\t\tsh = regs->gpr[rb] & 0x7f;\n \t\t\tif (sh < 64)\n-\t\t\t\tregs->gpr[ra] = regs->gpr[rd] << sh;\n+\t\t\t\top->val = regs->gpr[rd] << sh;\n \t\t\telse\n-\t\t\t\tregs->gpr[ra] = 0;\n+\t\t\t\top->val = 0;\n \t\t\tgoto logical_done;\n \n \t\tcase 539:\t/* srd */\n \t\t\tsh = regs->gpr[rb] & 0x7f;\n \t\t\tif (sh < 64)\n-\t\t\t\tregs->gpr[ra] = regs->gpr[rd] >> sh;\n+\t\t\t\top->val = regs->gpr[rd] >> sh;\n \t\t\telse\n-\t\t\t\tregs->gpr[ra] = 0;\n+\t\t\t\top->val = 0;\n \t\t\tgoto logical_done;\n \n \t\tcase 794:\t/* srad */\n+\t\t\top->type = COMPUTE + SETREG + SETXER;\n \t\t\tsh = regs->gpr[rb] & 0x7f;\n \t\t\tival = (signed long int) regs->gpr[rd];\n-\t\t\tregs->gpr[ra] = ival >> (sh < 64 ? sh : 63);\n+\t\t\top->val = ival >> (sh < 64 ? sh : 63);\n+\t\t\top->xerval = regs->xer;\n \t\t\tif (ival < 0 && (sh >= 64 || (ival & ((1ul << sh) - 1)) != 0))\n-\t\t\t\tregs->xer |= XER_CA;\n+\t\t\t\top->xerval |= XER_CA;\n \t\t\telse\n-\t\t\t\tregs->xer &= ~XER_CA;\n+\t\t\t\top->xerval &= ~XER_CA;\n \t\t\tgoto logical_done;\n \n \t\tcase 826:\t/* sradi with sh_5 = 0 */\n \t\tcase 827:\t/* sradi with sh_5 = 1 */\n+\t\t\top->type = COMPUTE + SETREG + SETXER;\n \t\t\tsh = rb | ((instr & 2) << 4);\n \t\t\tival = (signed long int) regs->gpr[rd];\n-\t\t\tregs->gpr[ra] = ival >> sh;\n+\t\t\top->val = ival >> sh;\n+\t\t\top->xerval = regs->xer;\n \t\t\tif (ival < 0 && (ival & ((1ul << sh) - 1)) != 0)\n-\t\t\t\tregs->xer |= XER_CA;\n+\t\t\t\top->xerval |= XER_CA;\n \t\t\telse\n-\t\t\t\tregs->xer &= ~XER_CA;\n+\t\t\t\top->xerval &= ~XER_CA;\n \t\t\tgoto logical_done;\n #endif /* __powerpc64__ */\n \n@@ -1787,15 +1789,18 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,\n \n  logical_done:\n \tif (instr & 1)\n-\t\tset_cr0(regs, ra);\n-\tgoto instr_done;\n+\t\tset_cr0(regs, op, ra);\n+ logical_done_nocc:\n+\top->reg = ra;\n+\top->type |= SETREG;\n+\treturn 1;\n \n  arith_done:\n \tif (instr & 1)\n-\t\tset_cr0(regs, rd);\n-\n- instr_done:\n-\tregs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);\n+\t\tset_cr0(regs, op, rd);\n+ compute_done:\n+\top->reg = rd;\n+\top->type |= SETREG;\n \treturn 1;\n \n  priv:\n@@ -1887,6 +1892,92 @@ static nokprobe_inline void do_byterev(unsigned long *valp, int size)\n }\n \n /*\n+ * Emulate an instruction that can be executed just by updating\n+ * fields in *regs.\n+ */\n+void emulate_update_regs(struct pt_regs *regs, struct instruction_op *op)\n+{\n+\tunsigned long next_pc;\n+\n+\tnext_pc = truncate_if_32bit(regs->msr, regs->nip + 4);\n+\tswitch (op->type & INSTR_TYPE_MASK) {\n+\tcase COMPUTE:\n+\t\tif (op->type & SETREG)\n+\t\t\tregs->gpr[op->reg] = op->val;\n+\t\tif (op->type & SETCC)\n+\t\t\tregs->ccr = op->ccval;\n+\t\tif (op->type & SETXER)\n+\t\t\tregs->xer = op->xerval;\n+\t\tbreak;\n+\n+\tcase BRANCH:\n+\t\tif (op->type & SETLK)\n+\t\t\tregs->link = next_pc;\n+\t\tif (op->type & BRTAKEN)\n+\t\t\tnext_pc = op->val;\n+\t\tif (op->type & DECCTR)\n+\t\t\t--regs->ctr;\n+\t\tbreak;\n+\n+\tcase BARRIER:\n+\t\tswitch (op->type & BARRIER_MASK) {\n+\t\tcase BARRIER_SYNC:\n+\t\t\tmb();\n+\t\t\tbreak;\n+\t\tcase BARRIER_ISYNC:\n+\t\t\tisync();\n+\t\t\tbreak;\n+\t\tcase BARRIER_EIEIO:\n+\t\t\teieio();\n+\t\t\tbreak;\n+\t\tcase BARRIER_LWSYNC:\n+\t\t\tasm volatile(\"lwsync\" : : : \"memory\");\n+\t\t\tbreak;\n+\t\tcase BARRIER_PTESYNC:\n+\t\t\tasm volatile(\"ptesync\" : : : \"memory\");\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase MFSPR:\n+\t\tswitch (op->spr) {\n+\t\tcase SPRN_XER:\n+\t\t\tregs->gpr[op->reg] = regs->xer & 0xffffffffUL;\n+\t\t\tbreak;\n+\t\tcase SPRN_LR:\n+\t\t\tregs->gpr[op->reg] = regs->link;\n+\t\t\tbreak;\n+\t\tcase SPRN_CTR:\n+\t\t\tregs->gpr[op->reg] = regs->ctr;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tWARN_ON_ONCE(1);\n+\t\t}\n+\t\tbreak;\n+\n+\tcase MTSPR:\n+\t\tswitch (op->spr) {\n+\t\tcase SPRN_XER:\n+\t\t\tregs->xer = op->val & 0xffffffffUL;\n+\t\t\tbreak;\n+\t\tcase SPRN_LR:\n+\t\t\tregs->link = op->val;\n+\t\t\tbreak;\n+\t\tcase SPRN_CTR:\n+\t\t\tregs->ctr = op->val;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tWARN_ON_ONCE(1);\n+\t\t}\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tWARN_ON_ONCE(1);\n+\t}\n+\tregs->nip = next_pc;\n+}\n+\n+/*\n  * Emulate instructions that cause a transfer of control,\n  * loads and stores, and a few other instructions.\n  * Returns 1 if the step was emulated, 0 if not,\n@@ -1902,8 +1993,12 @@ int emulate_step(struct pt_regs *regs, unsigned int instr)\n \tint i, rd, nb;\n \n \tr = analyse_instr(&op, regs, instr);\n-\tif (r != 0)\n+\tif (r < 0)\n \t\treturn r;\n+\tif (r > 0) {\n+\t\temulate_update_regs(regs, &op);\n+\t\treturn 0;\n+\t}\n \n \terr = 0;\n \tsize = GETSIZE(op.type);\n",
    "prefixes": [
        "v3",
        "02/17"
    ]
}