void arch_livepatch_revert(const struct livepatch_func *func) { uint32_t *new_ptr; unsigned int len; new_ptr = func->old_addr - (void *)_start + vmap_of_xen_text; len = livepatch_insn_len(func); memcpy(new_ptr, func->opaque, len); clean_and_invalidate_dcache_va_range(new_ptr, len); }
void arch_livepatch_apply(struct livepatch_func *func) { uint32_t insn; uint32_t *new_ptr; unsigned int i, len; BUILD_BUG_ON(ARCH_PATCH_INSN_SIZE > sizeof(func->opaque)); BUILD_BUG_ON(ARCH_PATCH_INSN_SIZE != sizeof(insn)); ASSERT(vmap_of_xen_text); len = livepatch_insn_len(func); if ( !len ) return; /* Save old ones. */ memcpy(func->opaque, func->old_addr, len); if ( func->new_addr ) { s32 delta; /* * PC is current address (old_addr) + 8 bytes. The semantics for a * unconditional branch is to jump to PC + imm32 (offset). * * ARM DDI 0406C.c, see A2.3 (pg 45) and A8.8.18 pg (pg 334,335) * */ delta = (s32)func->new_addr - (s32)(func->old_addr + 8); /* The arch_livepatch_symbol_ok should have caught it. */ ASSERT(delta >= -(s32)ARCH_LIVEPATCH_RANGE || delta < (s32)ARCH_LIVEPATCH_RANGE); /* CPU shifts by two (left) when decoding, so we shift right by two. */ delta = delta >> 2; /* Lets not modify the cond. */ delta &= 0x00FFFFFF; insn = 0xea000000 | delta; }