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

[Xen-devel] [PATCH v1 6/9] livepatch: Initial ARM64 support.



As compared to x86 the va of the hypervisor .text
is locked down - we cannot modify the running pagetables
to have the .ro flag unset. We borrow the same idea that
alternative patching has - which is to vmap the entire
.text region and use the alternative virtual address
for patching.

Since we are doing vmap we may fail, hence the
arch_livepatch_quiesce is changed to return an error value
which will be bubbled in payload->rc and provided to the
user (along with messages in the ring buffer).

And the livepatch virtual address space (where the
new functions are) needs to be close to the hypervisor virtual address
so that the trampoline can reach it. As such we re-use
the BOOT_RELOC_VIRT_START which is not used after bootup
(alternatively we can also use the space after the _end to
FIXMAP_ADDR(0), but that may be too small).

The ELF relocation engine at the start was coded from
the "ELF for the ARM 64-bit Architecture (AArch64)"
(http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf)
but after a while of trying to write the correct bit shifting
and masking from scratch I ended up borrowing from Linux, the
'reloc_insn_imm' (Linux v4.7 arch/arm64/kernel/module.c function.
See 257cb251925f854da435cbf79b140984413871ac "arm64: Loadable modules")

In the livepatch payload loading code we tweak the #ifdef to
only exclude ARM_32. The exceptions are not part of ARM 32/64 hence
they are still behind the #ifdef.

We also expand the MAINTAINERS file to include the arm64 and arm32
platform specific livepatch file.

Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>

---
Cc: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
Cc: Stefano Stabellini <sstabellini@xxxxxxxxxx>
Cc: Julien Grall <julien.grall@xxxxxxx>
Cc  Jan Beulich <jbeulich@xxxxxxxx>
Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>

RFC: Wholy cow! It works!
v1: Finished the various TODOs and reviews outlined by Julien in RFC.
---
 MAINTAINERS                    |   1 +
 xen/arch/arm/Makefile          |  13 ++-
 xen/arch/arm/arm32/Makefile    |   2 +-
 xen/arch/arm/arm32/livepatch.c |  55 +++++++++
 xen/arch/arm/arm64/Makefile    |   1 +
 xen/arch/arm/arm64/livepatch.c | 247 +++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/domain.c          |   6 +
 xen/arch/arm/livepatch.c       |  99 +++++++++++++----
 xen/arch/arm/livepatch.h       |  28 +++++
 xen/arch/x86/livepatch.c       |   4 +-
 xen/common/Kconfig             |   2 +-
 xen/common/livepatch.c         |  25 ++++-
 xen/include/asm-arm/config.h   |   8 +-
 xen/include/asm-arm/current.h  |   7 ++
 xen/include/xen/elfstructs.h   |  40 ++++++-
 xen/include/xen/livepatch.h    |   2 +-
 16 files changed, 503 insertions(+), 37 deletions(-)
 create mode 100644 xen/arch/arm/arm32/livepatch.c
 create mode 100644 xen/arch/arm/arm64/livepatch.c
 create mode 100644 xen/arch/arm/livepatch.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 97720a8..ae0b6bc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -269,6 +269,7 @@ S:  Supported
 F:  docs/misc/livepatch.markdown
 F:  tools/misc/xen-livepatch.c
 F:  xen/arch/*/livepatch*
+F:  xen/arch/*/*/livepatch*
 F:  xen/common/livepatch*
 F:  xen/include/xen/livepatch*
 
diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 0a96713..9f75c5c 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -58,6 +58,15 @@ ALL_OBJS := $(TARGET_SUBARCH)/head.o $(ALL_OBJS)
 
 DEPS += $(TARGET_SUBARCH)/.head.o.d
 
+ifdef CONFIG_LIVEPATCH
+all_symbols = --all-symbols
+ifdef CONFIG_FAST_SYMBOL_LOOKUP
+all_symbols = --all-symbols --sort-by-name
+endif
+else
+all_symbols =
+endif
+
 $(TARGET): $(TARGET)-syms $(TARGET).axf
        $(OBJCOPY) -O binary -S $< $@
 ifeq ($(CONFIG_ARM_64),y)
@@ -93,12 +102,12 @@ $(TARGET)-syms: prelink.o xen.lds 
$(BASEDIR)/common/symbols-dummy.o
        $(LD) $(LDFLAGS) -T xen.lds -N prelink.o \
            $(BASEDIR)/common/symbols-dummy.o -o $(@D)/.$(@F).0
        $(NM) -pa --format=sysv $(@D)/.$(@F).0 \
-               | $(BASEDIR)/tools/symbols --sysv --sort >$(@D)/.$(@F).0.S
+               | $(BASEDIR)/tools/symbols $(all_symbols) --sysv --sort 
>$(@D)/.$(@F).0.S
        $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).0.o
        $(LD) $(LDFLAGS) -T xen.lds -N prelink.o \
            $(@D)/.$(@F).0.o -o $(@D)/.$(@F).1
        $(NM) -pa --format=sysv $(@D)/.$(@F).1 \
-               | $(BASEDIR)/tools/symbols --sysv --sort >$(@D)/.$(@F).1.S
+               | $(BASEDIR)/tools/symbols $(all_symbols) --sysv --sort 
>$(@D)/.$(@F).1.S
        $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).1.o
        $(LD) $(LDFLAGS) -T xen.lds -N prelink.o $(build_id_linker) \
            $(@D)/.$(@F).1.o -o $@
diff --git a/xen/arch/arm/arm32/Makefile b/xen/arch/arm/arm32/Makefile
index b20db64..5966de0 100644
--- a/xen/arch/arm/arm32/Makefile
+++ b/xen/arch/arm/arm32/Makefile
@@ -4,8 +4,8 @@ obj-$(EARLY_PRINTK) += debug.o
 obj-y += domctl.o
 obj-y += domain.o
 obj-y += entry.o
+obj-$(CONFIG_LIVEPATCH) += livepatch.o
 obj-y += proc-v7.o proc-caxx.o
 obj-y += smpboot.o
 obj-y += traps.o
 obj-y += vfp.o
-
diff --git a/xen/arch/arm/arm32/livepatch.c b/xen/arch/arm/arm32/livepatch.c
new file mode 100644
index 0000000..89ee2f5
--- /dev/null
+++ b/xen/arch/arm/arm32/livepatch.c
@@ -0,0 +1,55 @@
+/*
+ *  Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <xen/errno.h>
+#include <xen/lib.h>
+#include <xen/livepatch_elf.h>
+#include <xen/livepatch.h>
+
+void arch_livepatch_apply_jmp(struct livepatch_func *func)
+{
+}
+
+void arch_livepatch_revert_jmp(const struct livepatch_func *func)
+{
+}
+
+int arch_livepatch_verify_elf(const struct livepatch_elf *elf)
+{
+    const Elf_Ehdr *hdr = elf->hdr;
+
+    if ( hdr->e_machine != EM_ARM ||
+         hdr->e_ident[EI_CLASS] != ELFCLASS32 )
+    {
+        dprintk(XENLOG_ERR, LIVEPATCH "%s: Unsupported ELF Machine type!\n",
+                elf->name);
+        return -EOPNOTSUPP;
+    }
+
+    if ( (hdr->e_flags & EF_ARM_EABI_MASK) != EF_ARM_EABI_VER5 )
+    {
+        dprintk(XENLOG_ERR, LIVEPATCH "%s: Unsupported ELF EABI(%x)!\n",
+                elf->name, hdr->e_flags);
+        return -EOPNOTSUPP;
+    }
+
+    return 0;
+}
+
+int arch_livepatch_perform_rela(struct livepatch_elf *elf,
+                                const struct livepatch_elf_sec *base,
+                                const struct livepatch_elf_sec *rela)
+{
+    return -ENOSYS;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/arm64/Makefile b/xen/arch/arm/arm64/Makefile
index c1fa43f..149b6b3 100644
--- a/xen/arch/arm/arm64/Makefile
+++ b/xen/arch/arm/arm64/Makefile
@@ -6,6 +6,7 @@ obj-y += domctl.o
 obj-y += domain.o
 obj-y += entry.o
 obj-y += insn.o
+obj-$(CONFIG_LIVEPATCH) += livepatch.o
 obj-y += smpboot.o
 obj-y += traps.o
 obj-y += vfp.o
diff --git a/xen/arch/arm/arm64/livepatch.c b/xen/arch/arm/arm64/livepatch.c
new file mode 100644
index 0000000..e348942
--- /dev/null
+++ b/xen/arch/arm/arm64/livepatch.c
@@ -0,0 +1,247 @@
+/*
+ *  Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include "../livepatch.h"
+#include <xen/bitops.h>
+#include <xen/errno.h>
+#include <xen/lib.h>
+#include <xen/livepatch_elf.h>
+#include <xen/livepatch.h>
+#include <xen/mm.h>
+#include <xen/vmap.h>
+
+#include <asm/bitops.h>
+#include <asm/byteorder.h>
+#include <asm/insn.h>
+
+void arch_livepatch_apply_jmp(struct livepatch_func *func)
+{
+    uint32_t insn;
+    uint32_t *old_ptr;
+    uint32_t *new_ptr;
+
+    BUILD_BUG_ON(PATCH_INSN_SIZE > sizeof(func->opaque));
+    BUILD_BUG_ON(PATCH_INSN_SIZE != sizeof(insn));
+
+    ASSERT(vmap_of_xen_text);
+
+    /* Save old one. */
+    old_ptr = func->old_addr;
+    memcpy(func->opaque, old_ptr, PATCH_INSN_SIZE);
+
+    if ( func->new_size )
+        insn = aarch64_insn_gen_branch_imm((unsigned long)func->old_addr,
+                                           (unsigned long)func->new_addr,
+                                           AARCH64_INSN_BRANCH_NOLINK);
+    else
+        insn = aarch64_insn_gen_nop();
+
+    new_ptr = func->old_addr - (void *)_start + vmap_of_xen_text;
+
+    /* PATCH! */
+    *(new_ptr) = cpu_to_le32(insn);
+
+    clean_and_invalidate_dcache_va_range(new_ptr, sizeof(*new_ptr));
+}
+
+void arch_livepatch_revert_jmp(const struct livepatch_func *func)
+{
+    uint32_t *new_ptr;
+    uint32_t insn;
+
+    memcpy(&insn, func->opaque, PATCH_INSN_SIZE);
+
+    new_ptr = (uint32_t *)func->old_addr - (u32 *)_start + vmap_of_xen_text;
+
+    /* PATCH! */
+    *(new_ptr) = cpu_to_le32(insn);
+
+    clean_and_invalidate_dcache_va_range(new_ptr, sizeof(*new_ptr));
+}
+
+int arch_livepatch_verify_elf(const struct livepatch_elf *elf)
+{
+    const Elf_Ehdr *hdr = elf->hdr;
+
+    if ( hdr->e_machine != EM_AARCH64 ||
+         hdr->e_ident[EI_CLASS] != ELFCLASS64 )
+    {
+        dprintk(XENLOG_ERR, LIVEPATCH "%s: Unsupported ELF Machine type!\n",
+                elf->name);
+        return -EOPNOTSUPP;
+    }
+
+    return 0;
+}
+
+static int reloc_insn_imm(void *dest, u64 val, int lsb, int len,
+                          enum aarch64_insn_imm_type imm_type)
+{
+    u64 imm, imm_mask;
+    s64 sval = val;
+    u32 insn = *(u32 *)dest;
+
+    /* Calculate the relocation value. */
+    sval >>= lsb;
+
+    /* Extract the value bits and shift them to bit 0. */
+    imm_mask = (BIT(lsb + len) - 1) >> lsb;
+    imm = sval & imm_mask;
+
+    /* Update the instruction's immediate field. */
+    insn = aarch64_insn_encode_immediate(imm_type, insn, imm);
+    *(u32 *)dest = insn;
+
+    /*
+     * Extract the upper value bits (including the sign bit) and
+     * shift them to bit 0.
+     */
+    sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1);
+
+    /*
+     * Overflow has occurred if the upper bits are not all equal to
+     * the sign bit of the value.
+     */
+    if ((u64)(sval + 1) >= 2)
+        return -EOVERFLOW;
+    return 0;
+}
+
+int arch_livepatch_perform_rela(struct livepatch_elf *elf,
+                                const struct livepatch_elf_sec *base,
+                                const struct livepatch_elf_sec *rela)
+{
+    const Elf_RelA *r;
+    unsigned int symndx, i;
+    uint64_t val;
+    void *dest;
+
+    for ( i = 0; i < (rela->sec->sh_size / rela->sec->sh_entsize); i++ )
+    {
+        int err = 0;
+
+        r = rela->data + i * rela->sec->sh_entsize;
+
+        symndx = ELF64_R_SYM(r->r_info);
+
+        if ( symndx > elf->nsym )
+        {
+            dprintk(XENLOG_ERR, LIVEPATCH "%s: Relative relocation wants 
symbol@%u which is past end!\n",
+                    elf->name, symndx);
+            return -EINVAL;
+        }
+
+        dest = base->load_addr + r->r_offset; /* P */
+        val = elf->sym[symndx].sym->st_value +  r->r_addend; /* S+A */
+
+        /* ARM64 operations at minimum are always 32-bit. */
+        if ( r->r_offset >= base->sec->sh_size ||
+            (r->r_offset + sizeof(uint32_t)) > base->sec->sh_size )
+            goto bad_offset;
+
+        switch ( ELF64_R_TYPE(r->r_info) ) {
+        /* Data */
+        case R_AARCH64_ABS64:
+            if ( r->r_offset + sizeof(uint64_t) > base->sec->sh_size )
+                goto bad_offset;
+            *(int64_t *)dest = val;
+            break;
+
+        case R_AARCH64_ABS32:
+            *(int32_t *)dest = val;
+            if ( (int64_t)val !=  *(int32_t *)dest )
+                err = -EOVERFLOW;
+            break;
+
+        case R_AARCH64_PREL64:
+            if ( r->r_offset + sizeof(uint64_t) > base->sec->sh_size )
+                goto bad_offset;
+
+            val -= (uint64_t)dest;
+            *(int64_t *)dest = val;
+            break;
+
+        case R_AARCH64_PREL32:
+            val -= (uint64_t)dest;
+            *(int32_t *)dest = val;
+            if ( (int64_t)val !=  *(int32_t *)dest )
+                err = -EOVERFLOW;
+            break;
+
+        /* Instructions. */
+        case R_AARCH64_ADR_PREL_LO21:
+            val -= (uint64_t)dest;
+            err = reloc_insn_imm(dest, val, 0, 21, AARCH64_INSN_IMM_ADR);
+            break;
+
+        case R_AARCH64_ADR_PREL_PG_HI21:
+            val = (val & ~0xfff) - ((u64)dest & ~0xfff);
+            err = reloc_insn_imm(dest, val, 12, 21, AARCH64_INSN_IMM_ADR);
+            break;
+
+        case R_AARCH64_LDST8_ABS_LO12_NC:
+        case R_AARCH64_ADD_ABS_LO12_NC:
+            err = reloc_insn_imm(dest, val, 0, 12, AARCH64_INSN_IMM_12);
+            if ( err == -EOVERFLOW )
+                err = 0;
+            break;
+
+        case R_AARCH64_LDST16_ABS_LO12_NC:
+            err = reloc_insn_imm(dest, val, 1, 11, AARCH64_INSN_IMM_12);
+            if ( err == -EOVERFLOW )
+                err = 0;
+            break;
+
+        case R_AARCH64_LDST32_ABS_LO12_NC:
+            err = reloc_insn_imm(dest, val, 2, 10, AARCH64_INSN_IMM_12);
+            if ( err == -EOVERFLOW )
+                err = 0;
+            break;
+
+        case R_AARCH64_LDST64_ABS_LO12_NC:
+            err = reloc_insn_imm(dest, val, 3, 9, AARCH64_INSN_IMM_12);
+            if ( err == -EOVERFLOW )
+                err = 0;
+            break;
+
+        case R_AARCH64_CONDBR19:
+            err = reloc_insn_imm(dest, val, 2, 19, AARCH64_INSN_IMM_19);
+            break;
+
+        case R_AARCH64_JUMP26:
+        case R_AARCH64_CALL26:
+            val -= (uint64_t)dest;
+            err = reloc_insn_imm(dest, val, 2, 26, AARCH64_INSN_IMM_26);
+            break;
+
+        default:
+            dprintk(XENLOG_ERR, LIVEPATCH "%s: Unhandled relocation %lu\n",
+                    elf->name, ELF64_R_TYPE(r->r_info));
+             return -EOPNOTSUPP;
+        }
+
+        if ( err )
+        {
+            dprintk(XENLOG_ERR, LIVEPATCH "%s: Overflow in relocation %u in %s 
for %s!\n",
+                    elf->name, i, rela->name, base->name);
+            return err;
+        }
+    }
+    return 0;
+
+ bad_offset:
+    dprintk(XENLOG_ERR, LIVEPATCH "%s: Relative relocation offset is past %s 
section!\n",
+            elf->name, base->name);
+    return -EINVAL;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 20bb2ba..607ee59 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -13,6 +13,7 @@
 #include <xen/hypercall.h>
 #include <xen/init.h>
 #include <xen/lib.h>
+#include <xen/livepatch.h>
 #include <xen/sched.h>
 #include <xen/softirq.h>
 #include <xen/wait.h>
@@ -55,6 +56,11 @@ void idle_loop(void)
 
         do_tasklet();
         do_softirq();
+        /*
+         * We MUST be last (or before dsb, wfi). Otherwise after we get the
+         * softirq we would execute dsb,wfi (and sleep) and not patch.
+         */
+        check_for_livepatch_work();
     }
 }
 
diff --git a/xen/arch/arm/livepatch.c b/xen/arch/arm/livepatch.c
index 3093554..19f6033 100644
--- a/xen/arch/arm/livepatch.c
+++ b/xen/arch/arm/livepatch.c
@@ -1,56 +1,93 @@
 /*
  *  Copyright (C) 2016 Citrix Systems R&D Ltd.
  */
+
+#include "livepatch.h"
 #include <xen/errno.h>
 #include <xen/init.h>
 #include <xen/lib.h>
 #include <xen/livepatch_elf.h>
 #include <xen/livepatch.h>
+#include <xen/vmap.h>
+
+#include <asm/mm.h>
 
-/* On ARM32,64 instructions are always 4 bytes long. */
-#define PATCH_INSN_SIZE 4
+void *vmap_of_xen_text;
 
 int arch_verify_insn_length(unsigned long len)
 {
     return len != PATCH_INSN_SIZE;
 }
 
-void arch_livepatch_quiesce(void)
+int arch_livepatch_quiesce(void)
 {
+    mfn_t text_mfn;
+    unsigned int text_order;
+
+    if ( vmap_of_xen_text )
+        return -EINVAL;
+
+    text_mfn = _mfn(virt_to_mfn(_stext));
+    text_order = get_order_from_bytes(_end - _start);
+
+    /*
+     * The text section is read-only. So re-map Xen to be able to patch
+     * the code.
+     */
+    vmap_of_xen_text = __vmap(&text_mfn, 1 << text_order, 1, 1, 
PAGE_HYPERVISOR,
+                              VMAP_DEFAULT);
+
+    if ( !vmap_of_xen_text )
+    {
+        printk(XENLOG_ERR LIVEPATCH "Failed to setup vmap of hypervisor! 
(order=%u)\n",
+               text_order);
+        return -ENOMEM;
+    }
+    return 0;
 }
 
 void arch_livepatch_revive(void)
 {
+    /*
+     * Nuke the instruction cache. It has been cleaned before in
+     * arch_livepatch_apply_jmp.
+     */
+    invalidate_icache();
+
+    if ( vmap_of_xen_text )
+        vunmap(vmap_of_xen_text);
+
+    vmap_of_xen_text = NULL;
+
+    /*
+     * Need to flush the branch predicator for ARMv7 as it may be
+     * architecturally visible to the software (see B2.2.4 in ARM DDI 0406C.b).
+     */
+    flush_xen_text_tlb_local();
 }
 
 int arch_livepatch_verify_func(const struct livepatch_func *func)
 {
-    return -ENOSYS;
-}
-
-void arch_livepatch_apply_jmp(struct livepatch_func *func)
-{
-}
+    if ( func->old_size < PATCH_INSN_SIZE )
+        return -EINVAL;
 
-void arch_livepatch_revert_jmp(const struct livepatch_func *func)
-{
+    return 0;
 }
 
 void arch_livepatch_post_action(void)
 {
+    /* arch_livepatch_revive has nuked the instruction cache. */
 }
 
 void arch_livepatch_mask(void)
 {
+    /* Mask System Error (SError) */
+    local_abort_disable();
 }
 
 void arch_livepatch_unmask(void)
 {
-}
-
-int arch_livepatch_verify_elf(const struct livepatch_elf *elf)
-{
-    return -ENOSYS;
+    local_abort_enable();
 }
 
 int arch_livepatch_perform_rel(struct livepatch_elf *elf,
@@ -60,20 +97,34 @@ int arch_livepatch_perform_rel(struct livepatch_elf *elf,
     return -ENOSYS;
 }
 
-int arch_livepatch_perform_rela(struct livepatch_elf *elf,
-                                const struct livepatch_elf_sec *base,
-                                const struct livepatch_elf_sec *rela)
-{
-    return -ENOSYS;
-}
-
 int arch_livepatch_secure(const void *va, unsigned int pages, enum va_type 
type)
 {
-    return -ENOSYS;
+    unsigned long start = (unsigned long)va;
+    unsigned int flags;
+
+    ASSERT(va);
+    ASSERT(pages);
+
+    if ( type == LIVEPATCH_VA_RX )
+        flags = PTE_RO; /* R set, NX clear */
+    else if ( type == LIVEPATCH_VA_RW )
+        flags = PTE_NX; /* R clear, NX set */
+    else
+        flags = PTE_NX | PTE_RO; /* R set, NX set */
+
+    modify_xen_mappings(start, start + pages * PAGE_SIZE, flags);
+
+    return 0;
 }
 
 void __init arch_livepatch_init(void)
 {
+    void *start, *end;
+
+    start = (void *)LIVEPATCH_VMAP;
+    end = start + MB(2);
+
+    vm_init_type(VMAP_XEN, start, end);
 }
 
 /*
diff --git a/xen/arch/arm/livepatch.h b/xen/arch/arm/livepatch.h
new file mode 100644
index 0000000..8c8d625
--- /dev/null
+++ b/xen/arch/arm/livepatch.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
+ *
+ */
+
+#ifndef __XEN_ARM_LIVEPATCH_H__
+#define __XEN_ARM_LIVEPATCH_H__
+
+/* On ARM32,64 instructions are always 4 bytes long. */
+#define PATCH_INSN_SIZE 4
+
+/*
+ * The va of the hypervisor .text region. We need this as the
+ * normal va are write protected.
+ */
+extern void *vmap_of_xen_text;
+
+#endif /* __XEN_ARM_LIVEPATCH_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/x86/livepatch.c b/xen/arch/x86/livepatch.c
index 06c67bc..e3f3f37 100644
--- a/xen/arch/x86/livepatch.c
+++ b/xen/arch/x86/livepatch.c
@@ -15,10 +15,12 @@
 
 #define PATCH_INSN_SIZE 5
 
-void arch_livepatch_quiesce(void)
+int arch_livepatch_quiesce(void)
 {
     /* Disable WP to allow changes to read-only pages. */
     write_cr0(read_cr0() & ~X86_CR0_WP);
+
+    return 0;
 }
 
 void arch_livepatch_revive(void)
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index 51afa24..2fc76b6 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -222,7 +222,7 @@ endmenu
 config LIVEPATCH
        bool "Live patching support (TECH PREVIEW)"
        default n
-       depends on X86 && HAS_BUILD_ID = "y"
+       depends on (X86 || ARM_64) && HAS_BUILD_ID = "y"
        ---help---
          Allows a running Xen hypervisor to be dynamically patched using
          binary patches without rebooting. This is primarily used to binarily
diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c
index 9c45270..af9443d 100644
--- a/xen/common/livepatch.c
+++ b/xen/common/livepatch.c
@@ -682,7 +682,7 @@ static int prepare_payload(struct payload *payload,
                                   sizeof(*region->frame[i].bugs);
     }
 
-#ifndef CONFIG_ARM
+#ifndef CONFIG_ARM_32
     sec = livepatch_elf_sec_by_name(elf, ".altinstructions");
     if ( sec )
     {
@@ -711,9 +711,15 @@ static int prepare_payload(struct payload *payload,
                 return -EINVAL;
             }
         }
+#ifndef CONFIG_ARM
         apply_alternatives_nocheck(start, end);
+#else
+        apply_alternatives(start, sec->sec->sh_size);
+#endif
     }
+#endif
 
+#ifndef CONFIG_ARM
     sec = livepatch_elf_sec_by_name(elf, ".ex_table");
     if ( sec )
     {
@@ -1083,12 +1089,17 @@ static int livepatch_list(xen_sysctl_livepatch_list_t 
*list)
 static int apply_payload(struct payload *data)
 {
     unsigned int i;
+    int rc;
 
     printk(XENLOG_INFO LIVEPATCH "%s: Applying %u functions\n",
             data->name, data->nfuncs);
 
-    arch_livepatch_quiesce();
-
+    rc = arch_livepatch_quiesce();
+    if ( rc )
+    {
+        printk(XENLOG_ERR LIVEPATCH "%s: unable to quiesce!\n", data->name);
+        return rc;
+    }
     /*
      * Since we are running with IRQs disabled and the hooks may call common
      * code - which expects the spinlocks to run with IRQs enabled - we 
temporarly
@@ -1119,10 +1130,16 @@ static int apply_payload(struct payload *data)
 static int revert_payload(struct payload *data)
 {
     unsigned int i;
+    int rc;
 
     printk(XENLOG_INFO LIVEPATCH "%s: Reverting\n", data->name);
 
-    arch_livepatch_quiesce();
+    rc = arch_livepatch_quiesce();
+    if ( rc )
+    {
+        printk(XENLOG_ERR LIVEPATCH "%s: unable to quiesce!\n", data->name);
+        return rc;
+    }
 
     for ( i = 0; i < data->nfuncs; i++ )
         arch_livepatch_revert_jmp(&data->funcs[i]);
diff --git a/xen/include/asm-arm/config.h b/xen/include/asm-arm/config.h
index a96f845..8d876f6 100644
--- a/xen/include/asm-arm/config.h
+++ b/xen/include/asm-arm/config.h
@@ -80,9 +80,10 @@
  *   4M -   6M   Fixmap: special-purpose 4K mapping slots
  *   6M -   8M   Early boot mapping of FDT
  *   8M -  10M   Early relocation address (used when relocating Xen)
+ *               and later for livepatch vmap (if compiled in)
  *
  * ARM32 layout:
- *   0  -   8M   <COMMON>
+ *   0  -  10M   <COMMON>
  *
  *  32M - 128M   Frametable: 24 bytes per page for 16GB of RAM
  * 256M -   1G   VMAP: ioremap and early_ioremap use this virtual address
@@ -93,7 +94,7 @@
  *
  * ARM64 layout:
  * 0x0000000000000000 - 0x0000007fffffffff (512GB, L0 slot [0])
- *   0  -   8M   <COMMON>
+ *   0  -  10M   <COMMON>
  *
  *   1G -   2G   VMAP: ioremap and early_ioremap
  *
@@ -113,6 +114,9 @@
 #define FIXMAP_ADDR(n)        (_AT(vaddr_t,0x00400000) + (n) * PAGE_SIZE)
 #define BOOT_FDT_VIRT_START    _AT(vaddr_t,0x00600000)
 #define BOOT_RELOC_VIRT_START  _AT(vaddr_t,0x00800000)
+#ifdef CONFIG_LIVEPATCH
+#define LIVEPATCH_VMAP         _AT(vaddr_t,0x00800000)
+#endif
 
 #define HYPERVISOR_VIRT_START  XEN_VIRT_START
 
diff --git a/xen/include/asm-arm/current.h b/xen/include/asm-arm/current.h
index 65c0cdf..f4fcfd6 100644
--- a/xen/include/asm-arm/current.h
+++ b/xen/include/asm-arm/current.h
@@ -33,8 +33,15 @@ static inline struct cpu_info *get_cpu_info(void)
 
 #define guest_cpu_user_regs() (&get_cpu_info()->guest_cpu_user_regs)
 
+#ifdef CONFIG_LIVEPATCH
+#define switch_stack_and_jump(stack, fn)                                \
+    asm volatile ("mov sp,%0;"                                          \
+                  "bl check_for_livepatch_work;"                        \
+                  "b " STR(fn) : : "r" (stack) : "memory" )
+#else
 #define switch_stack_and_jump(stack, fn)                                \
     asm volatile ("mov sp,%0; b " STR(fn) : : "r" (stack) : "memory" )
+#endif
 
 #define reset_stack_and_jump(fn) switch_stack_and_jump(get_cpu_info(), fn)
 
diff --git a/xen/include/xen/elfstructs.h b/xen/include/xen/elfstructs.h
index 5f2082e..a68874b 100644
--- a/xen/include/xen/elfstructs.h
+++ b/xen/include/xen/elfstructs.h
@@ -103,6 +103,15 @@ typedef uint64_t   Elf64_Xword;
                       (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
                       (ehdr).e_ident[EI_MAG3] == ELFMAG3)
 
+/* e_flags */
+#define EF_ARM_EABI_MASK       0xff000000
+#define EF_ARM_EABI_UNKNOWN    0x00000000
+#define EF_ARM_EABI_VER1       0x01000000
+#define EF_ARM_EABI_VER2       0x02000000
+#define EF_ARM_EABI_VER3       0x03000000
+#define EF_ARM_EABI_VER4       0x04000000
+#define EF_ARM_EABI_VER5       0x05000000
+
 /* ELF Header */
 typedef struct elfhdr {
        unsigned char   e_ident[EI_NIDENT]; /* ELF Identification */
@@ -171,6 +180,7 @@ typedef struct {
 #define EM_PPC         20              /* PowerPC */
 #define EM_PPC64       21              /* PowerPC 64-bit */
 #define EM_ARM         40              /* Advanced RISC Machines ARM */
+#define EM_AARCH64     183             /* ARM 64-bit */
 #define EM_ALPHA       41              /* DEC ALPHA */
 #define EM_SPARCV9     43              /* SPARC version 9 */
 #define EM_ALPHA_EXP   0x9026          /* DEC ALPHA */
@@ -353,12 +363,40 @@ typedef struct {
 #define        ELF64_R_TYPE(info)      ((info) & 0xFFFFFFFF)
 #define ELF64_R_INFO(s,t)      (((s) << 32) + (u_int32_t)(t))
 
-/* x86-64 relocation types. We list only the ones Live Patch implements. */
+/*
+ * Relocation types for x86_64 and ARM 64. We list only the ones Live Patch
+ * implements.
+ */
 #define R_X86_64_NONE          0       /* No reloc */
 #define R_X86_64_64            1       /* Direct 64 bit  */
 #define R_X86_64_PC32          2       /* PC relative 32 bit signed */
 #define R_X86_64_PLT32         4       /* 32 bit PLT address */
 
+/*
+ * S - address of symbol.
+ * A - addend for relocation (r_addend)
+ * P - address of the dest being relocated (derieved from r_offset)
+ * NC -  No check for overflow.
+ *
+ * The defines also use _PREL for PC-relative address, and _NC is No Check.
+ */
+#define R_AARCH64_ABS64                        257 /* Direct 64 bit. S+A, NC*/
+#define R_AARCH64_ABS32                        258 /* Direct 32 bit. S+A */
+#define R_AARCH64_PREL64               260 /* S+A-P, NC */
+#define R_AARCH64_PREL32               261 /* S+A-P */
+
+#define R_AARCH64_ADR_PREL_LO21                274 /* ADR imm, [20:0]. S+A-P */
+#define R_AARCH64_ADR_PREL_PG_HI21     275 /* ADRP imm, [32:12]. Page(S+A) - 
Page(P).*/
+#define R_AARCH64_ADD_ABS_LO12_NC      277 /* ADD imm. [11:0]. S+A, NC */
+
+#define R_AARCH64_CONDBR19             280 /* Bits 20:2, S+A-P */
+#define R_AARCH64_JUMP26               282 /* Bits 27:2, S+A-P */
+#define R_AARCH64_CALL26               283 /* Bits 27:2, S+A-P */
+#define R_AARCH64_LDST16_ABS_LO12_NC   284 /* LD/ST to bits 11:1, S+A, NC */
+#define R_AARCH64_LDST32_ABS_LO12_NC   285 /* LD/ST to bits 11:2, S+A, NC */
+#define R_AARCH64_LDST64_ABS_LO12_NC   286 /* LD/ST to bits 11:3, S+A, NC */
+#define R_AARCH64_LDST8_ABS_LO12_NC    278 /* LD/ST to bits 11:0, S+A, NC */
+
 /* Program Header */
 typedef struct {
        Elf32_Word      p_type;         /* segment type */
diff --git a/xen/include/xen/livepatch.h b/xen/include/xen/livepatch.h
index 2e64686..6f30c0d 100644
--- a/xen/include/xen/livepatch.h
+++ b/xen/include/xen/livepatch.h
@@ -72,7 +72,7 @@ int arch_livepatch_verify_func(const struct livepatch_func 
*func);
  * These functions are called around the critical region patching live code,
  * for an architecture to take make appropratie global state adjustments.
  */
-void arch_livepatch_quiesce(void);
+int arch_livepatch_quiesce(void);
 void arch_livepatch_revive(void);
 
 void arch_livepatch_apply_jmp(struct livepatch_func *func);
-- 
2.4.11


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

 


Rackspace

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