[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen master] xen/arm32: Introduce alternative runtime patching



commit 41630eb1b615158af42f4468236457fd3f8a6819
Author:     Wei Chen <Wei.Chen@xxxxxxx>
AuthorDate: Fri Mar 31 15:07:25 2017 +0800
Commit:     Stefano Stabellini <sstabellini@xxxxxxxxxx>
CommitDate: Fri Mar 31 11:17:12 2017 -0700

    xen/arm32: Introduce alternative runtime patching
    
    This patch is based on the implementation of ARM64, it introduces
    alternative runtime patching to ARM32. This allows to patch assembly
    instruction at runtime to either fix hardware bugs or optimize for
    certain hardware features on ARM32 platform.
    
    Xen hypervisor is using ARM execution state only on ARM32 platform,
    Thumb is not used. So, the Thumb only branch instructions (CBZ, CBNZ,
    TBB and TBH) are not considered in alternatives.
    
    The left ARM32 branch instructions are BX, BLX, BL and B. The
    instruction BX is taking a register in parameter, so we don't need to
    rewrite it. The instructions BLX, BL and B are using the similar
    encoding for the offset and will avoid specific case when extracting
    and updating the offset.
    
    In this patch, we include alternative.h header file to livepatch.c
    directly for ARM32 compilation issues. When the alternative patching
    config is enabled, the livepatch.c will use the alternative functions.
    In this case, we should include the alternative header file to this
    file. But for ARM64, it does not include this header file directly.
    It includes this header file indirectly through:
    sched.h->domain.h->page.h->alternative.h.
    But, unfortunately, the page.h of ARM32 doesn't include alternative.h,
    and we don't have the reason to include it to ARM32 page.h now. So we
    have to include the alternative.h directly in livepatch.c.
    
    Signed-off-by: Wei Chen <Wei.Chen@xxxxxxx>
    Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
    Reviewed-by: Julien Grall <julien.grall@xxxxxxx>
---
 xen/arch/arm/Kconfig             |  2 +-
 xen/arch/arm/arm32/Makefile      |  1 +
 xen/arch/arm/arm32/insn.c        | 91 ++++++++++++++++++++++++++++++++++++++++
 xen/common/livepatch.c           |  1 +
 xen/include/asm-arm/arm32/insn.h | 71 +++++++++++++++++++++++++++++++
 xen/include/asm-arm/insn.h       |  2 +
 6 files changed, 167 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index 2e023d1..43123e6 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -12,11 +12,11 @@ config ARM_32
 config ARM_64
        def_bool y
        depends on 64BIT
-       select HAS_ALTERNATIVE
        select HAS_GICV3
 
 config ARM
        def_bool y
+       select HAS_ALTERNATIVE
        select HAS_ARM_HDLCD
        select HAS_DEVICE_TREE
        select HAS_MEM_ACCESS
diff --git a/xen/arch/arm/arm32/Makefile b/xen/arch/arm/arm32/Makefile
index 4395693..0ac254f 100644
--- a/xen/arch/arm/arm32/Makefile
+++ b/xen/arch/arm/arm32/Makefile
@@ -4,6 +4,7 @@ obj-$(EARLY_PRINTK) += debug.o
 obj-y += domctl.o
 obj-y += domain.o
 obj-y += entry.o
+obj-y += insn.o
 obj-$(CONFIG_LIVEPATCH) += livepatch.o
 obj-y += proc-v7.o proc-caxx.o
 obj-y += smpboot.o
diff --git a/xen/arch/arm/arm32/insn.c b/xen/arch/arm/arm32/insn.c
new file mode 100644
index 0000000..7a5dbc5
--- /dev/null
+++ b/xen/arch/arm/arm32/insn.c
@@ -0,0 +1,91 @@
+/*
+  * Copyright (C) 2017 ARM Ltd.
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License version 2 as
+  * published by the Free Software Foundation.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+#include <xen/lib.h>
+#include <xen/bitops.h>
+#include <xen/sizes.h>
+#include <asm/insn.h>
+
+/* Mask of branch instructions' immediate. */
+#define BRANCH_INSN_IMM_MASK    GENMASK(23, 0)
+/* Shift of branch instructions' immediate. */
+#define BRANCH_INSN_IMM_SHIFT   0
+
+static uint32_t branch_insn_encode_immediate(uint32_t insn, int32_t offset)
+{
+    uint32_t imm;
+
+    /*
+     * Encode the offset to imm. All ARM32 instructions must be word aligned.
+     * Therefore the offset value's bits [1:0] equal to zero.
+     * (see ARM DDI 0406C.c A8.8.18/A8.8.25 for more encode/decode details
+     * about ARM32 branch instructions)
+     */
+    imm = ((offset >> 2) & BRANCH_INSN_IMM_MASK) << BRANCH_INSN_IMM_SHIFT;
+
+    /* Update the immediate field. */
+    insn &= ~(BRANCH_INSN_IMM_MASK << BRANCH_INSN_IMM_SHIFT);
+    insn |= imm;
+
+    return insn;
+}
+
+/*
+ * Decode the branch offset from a branch instruction's imm field.
+ * The branch offset is a signed value, so it can be used to compute
+ * a new branch target.
+ */
+int32_t aarch32_get_branch_offset(uint32_t insn)
+{
+    uint32_t imm;
+
+    /* Retrieve imm from branch instruction. */
+    imm = ( insn >> BRANCH_INSN_IMM_SHIFT ) & BRANCH_INSN_IMM_MASK;
+
+    /*
+     * Check the imm signed bit. If the imm is a negative value, we
+     * have to extend the imm to a full 32 bit negative value.
+     */
+    if ( imm & BIT(23) )
+        imm |= GENMASK(31, 24);
+
+    return (int32_t)(imm << 2);
+}
+
+/*
+ * Encode the displacement of a branch in the imm field and return the
+ * updated instruction.
+ */
+uint32_t aarch32_set_branch_offset(uint32_t insn, int32_t offset)
+{
+    /* B/BL support [-32M, 32M) offset (see ARM DDI 0406C.c A4.3). */
+    if ( offset < -SZ_32M || offset >= SZ_32M )
+    {
+        printk(XENLOG_ERR
+               "%s: new branch offset out of range.\n", __func__);
+        return BUG_OPCODE;
+    }
+
+    return branch_insn_encode_immediate(insn, offset);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c
index 246e673..f14bcbc 100644
--- a/xen/common/livepatch.c
+++ b/xen/common/livepatch.c
@@ -25,6 +25,7 @@
 #include <xen/livepatch.h>
 #include <xen/livepatch_payload.h>
 
+#include <asm/alternative.h>
 #include <asm/event.h>
 
 /*
diff --git a/xen/include/asm-arm/arm32/insn.h b/xen/include/asm-arm/arm32/insn.h
new file mode 100644
index 0000000..c800cbf
--- /dev/null
+++ b/xen/include/asm-arm/arm32/insn.h
@@ -0,0 +1,71 @@
+/*
+  * Copyright (C) 2017 ARM Ltd.
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License version 2 as
+  * published by the Free Software Foundation.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+#ifndef __ARCH_ARM_ARM32_INSN
+#define __ARCH_ARM_ARM32_INSN
+
+#include <xen/types.h>
+
+int32_t aarch32_get_branch_offset(uint32_t insn);
+uint32_t aarch32_set_branch_offset(uint32_t insn, int32_t offset);
+
+/* Wrapper for common code */
+static inline bool insn_is_branch_imm(uint32_t insn)
+{
+    /*
+     * Xen is using ARM execution state only on ARM32 platform. So, the
+     * Thumb branch instructions (CBZ, CBNZ, TBB and TBH) will not be used
+     * in Xen. The left ARM32 branch instructions are BX, BLX, BL and B.
+     * BX is using register as parameter, we don't need to rewrite it. So,
+     * we only need to check BLX, BL and B encodings in this function.
+     *
+     * From ARM DDI 0406C.c Section A8.8.18 and A8.8.25, we can see these
+     * three branch instructions' encodings:
+     * - b   cccc1010xxxxxxxxxxxxxxxxxxxxxxxx
+     * - bl  cccc1011xxxxxxxxxxxxxxxxxxxxxxxx
+     * - blx 1111101Hxxxxxxxxxxxxxxxxxxxxxxxx
+     *
+     * The H bit of blx can be 0 or 1, it depends on the Instruction Sets of
+     * target instruction. Regardless, if we mask the conditional bits and
+     * bit 24 (H bit of blx), we can see all above branch instructions have
+     * the same value 0x0A000000.
+     *
+     * And from ARM DDI 0406C.c Section A5.7 Table A5-23, we can see that the
+     * blx is the only one unconditional instruction has the same value as
+     * conditional branch instructions. So, mask the conditional bits will not
+     * make other unconditional instruction to hit this check.
+     */
+    return ( (insn & 0x0E000000) == 0x0A000000 );
+}
+
+static inline int32_t insn_get_branch_offset(uint32_t insn)
+{
+    return aarch32_get_branch_offset(insn);
+}
+
+static inline uint32_t insn_set_branch_offset(uint32_t insn, int32_t offset)
+{
+    return aarch32_set_branch_offset(insn, offset);
+}
+
+#endif /* !__ARCH_ARM_ARM32_INSN */
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-arm/insn.h b/xen/include/asm-arm/insn.h
index a205ceb..3489179 100644
--- a/xen/include/asm-arm/insn.h
+++ b/xen/include/asm-arm/insn.h
@@ -5,6 +5,8 @@
 
 #if defined(CONFIG_ARM_64)
 # include <asm/arm64/insn.h>
+#elif defined(CONFIG_ARM_32)
+# include <asm/arm32/insn.h>
 #else
 # error "unknown ARM variant"
 #endif
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.