F: tools/misc/xen-livepatch.c
F: xen/arch/*/livepatch*
F: xen/common/livepatch*
+F: xen/include/asm-*/livepatch.h
F: xen/include/xen/livepatch*
MACHINE CHECK (MCA) & RAS
payload generation time if hypervisor function address is known. If unknown,
the value *MUST* be zero and the hypervisor will attempt to resolve the address.
-* `new_addr` is the address of the function that is replacing the old
- function. The address is filled in during relocation. The value **MUST** be
- the address of the new function in the file.
+* `new_addr` can either have a non-zero value or be zero.
+ * If there is a non-zero value, then it is the address of the function that is
+ replacing the old function and the address is recomputed during relocation.
+ The value **MUST** be the address of the new function in the payload file.
-* `old_size` and `new_size` contain the sizes of the respective functions in bytes.
+ * If the value is zero, then we NOPing out at the `old_addr` location
+ `new_size` bytes.
+
+* `old_size` contains the sizes of the respective `old_addr` function in bytes.
The value of `old_size` **MUST** not be zero.
+* `new_size` depends on what `new_addr` contains:
+ * If `new_addr` contains an non-zero value, then `new_size` has the size of
+ the new function (which will replace the one at `old_addr`) in bytes.
+ * If the value of `new_addr` is zero then `new_size` determines how many
+ instruction bytes to NOP (up to opaque size modulo smallest platform
+ instruction - 1 byte x86 and 4 bytes on ARM).
+
* `version` is to be one.
* `opaque` **MUST** be zero.
Please note there is a small limitation for trampolines in
function entries: The target function (+ trailing padding) must be able
to accomodate the trampoline. On x86 with +-2 GB relative jumps,
-this means 5 bytes are required.
+this means 5 bytes are required which means that `old_size` **MUST** be
+at least five bytes if patching in trampoline.
Depending on compiler settings, there are several functions in Xen that
are smaller (without inter-function padding).
}
/* Use this to add nops to a buffer, then text_poke the whole buffer. */
-static void init_or_livepatch add_nops(void *insns, unsigned int len)
+void init_or_livepatch add_nops(void *insns, unsigned int len)
{
while ( len > 0 )
{
#include <xen/livepatch.h>
#include <asm/nmi.h>
-
-#define PATCH_INSN_SIZE 5
+#include <asm/livepatch.h>
int arch_livepatch_quiesce(void)
{
int arch_livepatch_verify_func(const struct livepatch_func *func)
{
- /* No NOP patching yet. */
- if ( !func->new_size )
- return -EOPNOTSUPP;
+ /* If NOPing.. */
+ if ( !func->new_addr )
+ {
+ /* Only do up to maximum amount we can put in the ->opaque. */
+ if ( func->new_size > sizeof(func->opaque) )
+ return -EOPNOTSUPP;
- if ( func->old_size < PATCH_INSN_SIZE )
+ if ( func->old_size < func->new_size )
+ return -EINVAL;
+ }
+ else if ( func->old_size < ARCH_PATCH_INSN_SIZE )
return -EINVAL;
return 0;
void arch_livepatch_apply_jmp(struct livepatch_func *func)
{
- int32_t val;
uint8_t *old_ptr;
-
- BUILD_BUG_ON(PATCH_INSN_SIZE > sizeof(func->opaque));
- BUILD_BUG_ON(PATCH_INSN_SIZE != (1 + sizeof(val)));
+ uint8_t insn[sizeof(func->opaque)];
+ unsigned int len;
old_ptr = func->old_addr;
- memcpy(func->opaque, old_ptr, PATCH_INSN_SIZE);
+ len = livepatch_insn_len(func);
+ if ( !len )
+ return;
+
+ memcpy(func->opaque, old_ptr, len);
+ if ( func->new_addr )
+ {
+ int32_t val;
+
+ BUILD_BUG_ON(ARCH_PATCH_INSN_SIZE != (1 + sizeof(val)));
+
+ insn[0] = 0xe9; /* Relative jump. */
+ val = func->new_addr - func->old_addr - ARCH_PATCH_INSN_SIZE;
+
+ memcpy(&insn[1], &val, sizeof(val));
+ }
+ else
+ add_nops(insn, len);
- *old_ptr++ = 0xe9; /* Relative jump */
- val = func->new_addr - func->old_addr - PATCH_INSN_SIZE;
- memcpy(old_ptr, &val, sizeof(val));
+ memcpy(old_ptr, insn, len);
}
void arch_livepatch_revert_jmp(const struct livepatch_func *func)
{
- memcpy(func->old_addr, func->opaque, PATCH_INSN_SIZE);
+ memcpy(func->old_addr, func->opaque, livepatch_insn_len(func));
}
/* Serialise the CPU pipeline. */
return -EOPNOTSUPP;
}
- if ( !f->new_addr || !f->new_size )
+ /* 'old_addr', 'new_addr', 'new_size' can all be zero. */
+ if ( !f->old_size )
{
dprintk(XENLOG_ERR, LIVEPATCH "%s: Address or size fields are zero!\n",
elf->name);
#define ALT_ORIG_PTR(a) __ALT_PTR(a, instr_offset)
#define ALT_REPL_PTR(a) __ALT_PTR(a, repl_offset)
+extern void add_nops(void *insns, unsigned int len);
/* Similar to alternative_instructions except it can be run with IRQs enabled. */
extern void apply_alternatives(const struct alt_instr *start,
const struct alt_instr *end);
--- /dev/null
+/*
+ * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
+ *
+ */
+
+#ifndef __XEN_X86_LIVEPATCH_H__
+#define __XEN_X86_LIVEPATCH_H__
+
+#define ARCH_PATCH_INSN_SIZE 5
+
+#endif /* __XEN_X86_LIVEPATCH_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
void arch_livepatch_init(void);
#include <public/sysctl.h> /* For struct livepatch_func. */
+#include <asm/livepatch.h>
int arch_livepatch_verify_func(const struct livepatch_func *func);
+
+static inline
+unsigned int livepatch_insn_len(const struct livepatch_func *func)
+{
+ if ( !func->new_addr )
+ return func->new_size;
+
+ return ARCH_PATCH_INSN_SIZE;
+}
/*
* These functions are called around the critical region patching live code,
* for an architecture to take make appropratie global state adjustments.