get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 817581,
    "url": "http://patchwork.ozlabs.org/api/patches/817581/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/1506092407-26985-20-git-send-email-peter.maydell@linaro.org/",
    "project": {
        "id": 14,
        "url": "http://patchwork.ozlabs.org/api/projects/14/?format=api",
        "name": "QEMU Development",
        "link_name": "qemu-devel",
        "list_id": "qemu-devel.nongnu.org",
        "list_email": "qemu-devel@nongnu.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<1506092407-26985-20-git-send-email-peter.maydell@linaro.org>",
    "list_archive_url": null,
    "date": "2017-09-22T15:00:06",
    "name": "[19/20] target/arm: Implement secure function return",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "f08b7393e0c5fb67efefc9c032659113e28e9d43",
    "submitter": {
        "id": 5111,
        "url": "http://patchwork.ozlabs.org/api/people/5111/?format=api",
        "name": "Peter Maydell",
        "email": "peter.maydell@linaro.org"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/1506092407-26985-20-git-send-email-peter.maydell@linaro.org/mbox/",
    "series": [
        {
            "id": 4650,
            "url": "http://patchwork.ozlabs.org/api/series/4650/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=4650",
            "date": "2017-09-22T14:59:47",
            "name": "ARM v8M: exception entry, exit and security",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/4650/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/817581/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/817581/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org",
        "Authentication-Results": "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=nongnu.org\n\t(client-ip=2001:4830:134:3::11; helo=lists.gnu.org;\n\tenvelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n\treceiver=<UNKNOWN>)",
        "Received": [
            "from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11])\n\t(using TLSv1 with cipher AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xzHG22v28z9s82\n\tfor <incoming@patchwork.ozlabs.org>;\n\tSat, 23 Sep 2017 01:19:38 +1000 (AEST)",
            "from localhost ([::1]:59429 helo=lists.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.71) (envelope-from\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1dvPjs-00008D-Go\n\tfor incoming@patchwork.ozlabs.org; Fri, 22 Sep 2017 11:19:36 -0400",
            "from eggs.gnu.org ([2001:4830:134:3::10]:47336)\n\tby lists.gnu.org with esmtp (Exim 4.71)\n\t(envelope-from <pm215@archaic.org.uk>) id 1dvPQm-0008AK-Lh\n\tfor qemu-devel@nongnu.org; Fri, 22 Sep 2017 10:59:54 -0400",
            "from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)\n\t(envelope-from <pm215@archaic.org.uk>) id 1dvPQk-0004M2-SE\n\tfor qemu-devel@nongnu.org; Fri, 22 Sep 2017 10:59:52 -0400",
            "from orth.archaic.org.uk ([2001:8b0:1d0::2]:37588)\n\tby eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)\n\t(Exim 4.71) (envelope-from <pm215@archaic.org.uk>)\n\tid 1dvPQe-0004EW-Aw; Fri, 22 Sep 2017 10:59:44 -0400",
            "from pm215 by orth.archaic.org.uk with local (Exim 4.89)\n\t(envelope-from <pm215@archaic.org.uk>)\n\tid 1dvPQd-0007GK-1I; Fri, 22 Sep 2017 15:59:43 +0100"
        ],
        "From": "Peter Maydell <peter.maydell@linaro.org>",
        "To": "qemu-arm@nongnu.org,\n\tqemu-devel@nongnu.org",
        "Date": "Fri, 22 Sep 2017 16:00:06 +0100",
        "Message-Id": "<1506092407-26985-20-git-send-email-peter.maydell@linaro.org>",
        "X-Mailer": "git-send-email 2.7.4",
        "In-Reply-To": "<1506092407-26985-1-git-send-email-peter.maydell@linaro.org>",
        "References": "<1506092407-26985-1-git-send-email-peter.maydell@linaro.org>",
        "X-detected-operating-system": "by eggs.gnu.org: Genre and OS details not\n\trecognized.",
        "X-Received-From": "2001:8b0:1d0::2",
        "Subject": "[Qemu-devel] [PATCH 19/20] target/arm: Implement secure function\n\treturn",
        "X-BeenThere": "qemu-devel@nongnu.org",
        "X-Mailman-Version": "2.1.21",
        "Precedence": "list",
        "List-Id": "<qemu-devel.nongnu.org>",
        "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>",
        "List-Archive": "<http://lists.nongnu.org/archive/html/qemu-devel/>",
        "List-Post": "<mailto:qemu-devel@nongnu.org>",
        "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>",
        "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=subscribe>",
        "Cc": "patches@linaro.org",
        "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org",
        "Sender": "\"Qemu-devel\"\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>"
    },
    "content": "Secure function return happens when a non-secure function has been\ncalled using BLXNS and so has a particular magic LR value (either\n0xfefffffe or 0xfeffffff). The function return via BX behaves\nspecially when the new PC value is this magic value, in the same\nway that exception returns are handled.\n\nAdjust our BX excret guards so that they recognize the function\nreturn magic number as well, and perform the function-return\nunstacking in do_v7m_exception_exit().\n\nSigned-off-by: Peter Maydell <peter.maydell@linaro.org>\n---\n target/arm/internals.h |   7 +++\n target/arm/helper.c    | 115 +++++++++++++++++++++++++++++++++++++++++++++----\n target/arm/translate.c |  14 +++++-\n 3 files changed, 126 insertions(+), 10 deletions(-)",
    "diff": "diff --git a/target/arm/internals.h b/target/arm/internals.h\nindex 1746737..43106a2 100644\n--- a/target/arm/internals.h\n+++ b/target/arm/internals.h\n@@ -72,6 +72,13 @@ FIELD(V7M_EXCRET, DCRS, 5, 1)\n FIELD(V7M_EXCRET, S, 6, 1)\n FIELD(V7M_EXCRET, RES1, 7, 25) /* including the must-be-1 prefix */\n \n+/* Minimum value which is a magic number for exception return */\n+#define EXC_RETURN_MIN_MAGIC 0xff000000\n+/* Minimum number which is a magic number for function or exception return\n+ * when using v8M security extension\n+ */\n+#define FNC_RETURN_MIN_MAGIC 0xfefffffe\n+\n /* We use a few fake FSR values for internal purposes in M profile.\n  * M profile cores don't have A/R format FSRs, but currently our\n  * get_phys_addr() code assumes A/R profile and reports failures via\ndiff --git a/target/arm/helper.c b/target/arm/helper.c\nindex 30dc2a9..888fe0a 100644\n--- a/target/arm/helper.c\n+++ b/target/arm/helper.c\n@@ -6167,7 +6167,17 @@ void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)\n      *  - if the return value is a magic value, do exception return (like BX)\n      *  - otherwise bit 0 of the return value is the target security state\n      */\n-    if (dest >= 0xff000000) {\n+    uint32_t min_magic;\n+\n+    if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {\n+        /* Covers FNC_RETURN and EXC_RETURN magic */\n+        min_magic = FNC_RETURN_MIN_MAGIC;\n+    } else {\n+        /* EXC_RETURN magic only */\n+        min_magic = EXC_RETURN_MIN_MAGIC;\n+    }\n+\n+    if (dest >= min_magic) {\n         /* This is an exception return magic value; put it where\n          * do_v7m_exception_exit() expects and raise EXCEPTION_EXIT.\n          * Note that if we ever add gen_ss_advance() singlestep support to\n@@ -6460,12 +6470,19 @@ static void do_v7m_exception_exit(ARMCPU *cpu)\n     bool exc_secure = false;\n     bool return_to_secure;\n \n-    /* We can only get here from an EXCP_EXCEPTION_EXIT, and\n-     * gen_bx_excret() enforces the architectural rule\n-     * that jumps to magic addresses don't have magic behaviour unless\n-     * we're in Handler mode (compare pseudocode BXWritePC()).\n+    /* If we're not in Handler mode then jumps to magic exception-exit\n+     * addresses don't have magic behaviour. However for the v8M\n+     * security extensions the magic secure-function-return has to\n+     * work in thread mode too, so to avoid doing an extra check in\n+     * the generated code we allow exception-exit magic to also cause the\n+     * internal exception and bring us here in thread mode. Correct code\n+     * will never try to do this (the following insn fetch will always\n+     * fault) so we the overhead of having taken an unnecessary exception\n+     * doesn't matter.\n      */\n-    assert(arm_v7m_is_handler_mode(env));\n+    if (!arm_v7m_is_handler_mode(env)) {\n+        return;\n+    }\n \n     /* In the spec pseudocode ExceptionReturn() is called directly\n      * from BXWritePC() and gets the full target PC value including\n@@ -6753,6 +6770,78 @@ static void do_v7m_exception_exit(ARMCPU *cpu)\n     qemu_log_mask(CPU_LOG_INT, \"...successful exception return\\n\");\n }\n \n+static bool do_v7m_function_return(ARMCPU *cpu)\n+{\n+    /* v8M security extensions magic function return.\n+     * We may either:\n+     *  (1) throw an exception (longjump)\n+     *  (2) return true if we successfully handled the function return\n+     *  (3) return false if we failed a consistency check and have\n+     *      pended a UsageFault that needs to be taken now\n+     *\n+     * At this point the magic return value is split between env->regs[15]\n+     * and env->thumb. We don't bother to reconstitute it because we don't\n+     * need it (all values are handled the same way).\n+     */\n+    CPUARMState *env = &cpu->env;\n+    uint32_t newpc, newpsr, newpsr_exc;\n+\n+    qemu_log_mask(CPU_LOG_INT, \"...really v7M secure function return\\n\");\n+\n+    {\n+        bool threadmode, spsel;\n+        TCGMemOpIdx oi;\n+        ARMMMUIdx mmu_idx;\n+        uint32_t *frame_sp_p;\n+        uint32_t frameptr;\n+\n+        /* Pull the return address and IPSR from the Secure stack */\n+        threadmode = !arm_v7m_is_handler_mode(env);\n+        spsel = env->v7m.control[M_REG_S] & R_V7M_CONTROL_SPSEL_MASK;\n+\n+        frame_sp_p = get_v7m_sp_ptr(env, true, threadmode, spsel);\n+        frameptr = *frame_sp_p;\n+\n+        /* These loads may throw an exception (for MPU faults). We want to\n+         * do them as secure, so work out what MMU index that is.\n+         */\n+        mmu_idx = arm_v7m_mmu_idx_for_secstate(env, true);\n+        oi = make_memop_idx(MO_LE, arm_to_core_mmu_idx(mmu_idx));\n+        newpc = helper_le_ldul_mmu(env, frameptr, oi, 0);\n+        newpsr = helper_le_ldul_mmu(env, frameptr + 4, oi, 0);\n+\n+        /* Consistency checks on new IPSR */\n+        newpsr_exc = newpsr & XPSR_EXCP;\n+        if (!((env->v7m.exception == 0 && newpsr_exc == 0) ||\n+              (env->v7m.exception == 1 && newpsr_exc != 0))) {\n+            /* Pend the fault and tell our caller to take it */\n+            env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;\n+            armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,\n+                                    env->v7m.secure);\n+            qemu_log_mask(CPU_LOG_INT,\n+                          \"...taking INVPC UsageFault: \"\n+                          \"IPSR consistency check failed\\n\");\n+            return false;\n+        }\n+\n+        *frame_sp_p = frameptr + 8;\n+    }\n+\n+    /* This invalidates frame_sp_p */\n+    switch_v7m_security_state(env, true);\n+    env->v7m.exception = newpsr_exc;\n+    env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;\n+    if (newpsr & XPSR_SFPA) {\n+        env->v7m.control[M_REG_S] |= R_V7M_CONTROL_SFPA_MASK;\n+    }\n+    xpsr_write(env, 0, XPSR_IT);\n+    env->thumb = newpc & 1;\n+    env->regs[15] = newpc & ~1;\n+\n+    qemu_log_mask(CPU_LOG_INT, \"...function return successful\\n\");\n+    return true;\n+}\n+\n static void arm_log_exception(int idx)\n {\n     if (qemu_loglevel_mask(CPU_LOG_INT)) {\n@@ -7034,8 +7123,18 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)\n     case EXCP_IRQ:\n         break;\n     case EXCP_EXCEPTION_EXIT:\n-        do_v7m_exception_exit(cpu);\n-        return;\n+        if (env->regs[15] < EXC_RETURN_MIN_MAGIC) {\n+            /* Must be v8M security extension function return */\n+            assert(env->regs[15] >= FNC_RETURN_MIN_MAGIC);\n+            assert(arm_feature(env, ARM_FEATURE_M_SECURITY));\n+            if (do_v7m_function_return(cpu)) {\n+                return;\n+            }\n+        } else {\n+            do_v7m_exception_exit(cpu);\n+            return;\n+        }\n+        break;\n     default:\n         cpu_abort(cs, \"Unhandled exception 0x%x\\n\", cs->exception_index);\n         return; /* Never happens.  Keep compiler happy.  */\ndiff --git a/target/arm/translate.c b/target/arm/translate.c\nindex 53694bb..f5cca07 100644\n--- a/target/arm/translate.c\n+++ b/target/arm/translate.c\n@@ -960,7 +960,8 @@ static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var)\n      * s->base.is_jmp that we need to do the rest of the work later.\n      */\n     gen_bx(s, var);\n-    if (s->v7m_handler_mode && arm_dc_feature(s, ARM_FEATURE_M)) {\n+    if (arm_dc_feature(s, ARM_FEATURE_M_SECURITY) ||\n+        (s->v7m_handler_mode && arm_dc_feature(s, ARM_FEATURE_M))) {\n         s->base.is_jmp = DISAS_BX_EXCRET;\n     }\n }\n@@ -969,9 +970,18 @@ static inline void gen_bx_excret_final_code(DisasContext *s)\n {\n     /* Generate the code to finish possible exception return and end the TB */\n     TCGLabel *excret_label = gen_new_label();\n+    uint32_t min_magic;\n+\n+    if (arm_dc_feature(s, ARM_FEATURE_M_SECURITY)) {\n+        /* Covers FNC_RETURN and EXC_RETURN magic */\n+        min_magic = FNC_RETURN_MIN_MAGIC;\n+    } else {\n+        /* EXC_RETURN magic only */\n+        min_magic = EXC_RETURN_MIN_MAGIC;\n+    }\n \n     /* Is the new PC value in the magic range indicating exception return? */\n-    tcg_gen_brcondi_i32(TCG_COND_GEU, cpu_R[15], 0xff000000, excret_label);\n+    tcg_gen_brcondi_i32(TCG_COND_GEU, cpu_R[15], min_magic, excret_label);\n     /* No: end the TB as we would for a DISAS_JMP */\n     if (is_singlestepping(s)) {\n         gen_singlestep_exception(s);\n",
    "prefixes": [
        "19/20"
    ]
}