This change demonstrates how to generate an xSplice ELF payload.

The idea here is that we want to patch in the hypervisor
the 'xen_version_extra' function with an function that will
return 'Hello World'. The 'xl info | grep extraversion'
will reflect the new value after the patching.

To generate this ELF payload file we need:
 - C code of the new code.
 - C code generating the .xsplice.func structure.
 - The address of the old code (xen_extra_version). We
   do it by using 'nm' but that is a bit of hack.

The linker script file:
 - Discards .debug* and .comments* sections.
 - Changes the name of .data.local.xsplice_hello_world to
   .xsplice.func
 - Figures out the size of the new code.

Also if you are curious on the input/output sections
magic the linker does, add these to the GCC line:
  -Wl,-M  -Wl,-t -Wl,-verbose
which are: print linking map, provide trace and be verbose.

The use-case is simple:

$xen-xsplice load /usr/lib/xen/bin/xen_hello_world.xsplice
$xen-xsplice list
 ID                                     | status
----------------------------------------+------------
xen_hello_world                           APPLIED
$xl info | grep extra
xen_extra              : Hello World
$xen-xsplice revert xen_hello_world
Performing revert: completed
$xen-xsplice unload xen_hello_world
Performing unload: completed
$xl info | grep extra
xen_extra              : -unstable

Note that it does not build under a 32-bit toolstack as
there is no access to the hypervisor (xen-syms).

We also force it to be built every time - as the hypervisor
may have been rebuilt.

Signed-off-by: Konrad Rzeszutek Wilk <konrad.w...@oracle.com>
---
 docs/misc/xsplice.markdown   | 50 ++++++++++++++++++++++++++++++++++++++++++++
 tools/misc/Makefile          | 25 +++++++++++++++++++++-
 tools/misc/xen_hello_world.c | 15 +++++++++++++
 tools/misc/xsplice.h         | 12 +++++++++++
 tools/misc/xsplice.lds       | 11 ++++++++++
 5 files changed, 112 insertions(+), 1 deletion(-)
 create mode 100644 tools/misc/xen_hello_world.c
 create mode 100644 tools/misc/xsplice.h
 create mode 100644 tools/misc/xsplice.lds

diff --git a/docs/misc/xsplice.markdown b/docs/misc/xsplice.markdown
index beb452e..e2cdcff 100644
--- a/docs/misc/xsplice.markdown
+++ b/docs/misc/xsplice.markdown
@@ -312,11 +312,61 @@ size.
 
 When applying the patch the hypervisor iterates over each `xsplice_patch_func`
 structure and the core code inserts a trampoline at `old_addr` to `new_addr`.
+The `new_addr` is altered when the ELF payload is loaded.
 
 When reverting a patch, the hypervisor iterates over each `xsplice_patch_func`
 and the core code copies the data from the undo buffer (private internal copy)
 to `old_addr`.
 
+### Example
+
+A simple example of what a payload file can be:
+
+<pre>
+/* MUST be in sync with hypervisor. */  
+struct xsplice_patch_func {  
+    const char *name;  
+    unsigned long new_addr;  
+    const unsigned long old_addr;  
+    uint32_t new_size;  
+    const uint32_t old_size;  
+    uint8_t pad[32];  
+};  
+
+/* Our replacement function for xen_extra_version. */  
+const char *xen_hello_world(void)  
+{  
+    return "Hello World";  
+}  
+
+struct xsplice_patch_func xsplice_hello_world = {  
+    .name = "xen_extra_version",  
+    .new_addr = &xen_hello_world,  
+    .old_addr = 0xffff82d08013963c, /* Extracted from xen-syms. */  
+    .new_size = 13, /* To be be computed by scripts. */  
+    .old_size = 13, /* -----------""---------------  */  
+};  
+</pre>
+
+With the linker script as follow to change the `xsplice_hello_world`
+do be `.xsplice.funcs` :
+
+<pre>
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")  
+OUTPUT_ARCH(i386:x86-64)  
+ENTRY(xsplice_hello_world)  
+SECTIONS  
+{  
+    /* The hypervisor expects ".xsplice.func", so change  
+     * the ".data.xsplice_hello_world" to it. */  
+
+    .xsplice.funcs : { *(*.xsplice_hello_world) }  
+    }  
+}  
+</pre>
+
+Code must be compiled with -fPIC.
+
 ## Hypercalls
 
 We will employ the sub operations of the system management hypercall (sysctl).
diff --git a/tools/misc/Makefile b/tools/misc/Makefile
index c46873e..8385830 100644
--- a/tools/misc/Makefile
+++ b/tools/misc/Makefile
@@ -36,6 +36,10 @@ INSTALL_SBIN += $(INSTALL_SBIN-y)
 # Everything to be installed in a private bin/
 INSTALL_PRIVBIN                += xenpvnetboot
 
+# We need the hypervisor - and only 64-bit builds have it.
+ifeq ($(XEN_COMPILE_ARCH),x86_64)
+INSTALL_PRIVBIN                += xen_hello_world.xsplice
+endif
 # Everything to be installed
 TARGETS_ALL := $(INSTALL_BIN) $(INSTALL_SBIN) $(INSTALL_PRIVBIN)
 
@@ -49,7 +53,7 @@ TARGETS_COPY += xenpvnetboot
 # Everything which needs to be built
 TARGETS_BUILD := $(filter-out $(TARGETS_COPY),$(TARGETS_ALL))
 
-.PHONY: all build
+.PHONY: all build xsplice
 all build: $(TARGETS_BUILD)
 
 .PHONY: install
@@ -111,4 +115,23 @@ gtraceview: gtraceview.o
 xencov: xencov.o
        $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS)
 
+.PHONY: xsplice
+xsplice:
+ifeq ($(XEN_COMPILE_ARCH),x86_64)
+       # We MUST regenerate the file everytime we build - in case the 
hypervisor
+       # is rebuilt too.
+       $(RM) *.xplice
+       $(MAKE) xen_hello_world.xsplice
+endif
+
+XEN_EXTRA_VERSION_ADDR=$(shell nm --defined $(XEN_ROOT)/xen/xen-syms | grep 
xen_extra_version | awk '{print "0x"$$1}')
+
+xen_hello_world.xsplice: xen_hello_world.c
+       $(CC) -DOLD_CODE=$(XEN_EXTRA_VERSION_ADDR) -I$(XEN_ROOT)/tools/include \
+               -fPIC -Wl,--emit-relocs \
+               -Wl,-r -Wl,--entry=xsplice_hello_world \
+               -fdata-sections -ffunction-sections \
+               -nostdlib -Txsplice.lds \
+               -o $@ $<
+       @objdump -x --section=.xsplice.funcs $@
 -include $(DEPS)
diff --git a/tools/misc/xen_hello_world.c b/tools/misc/xen_hello_world.c
new file mode 100644
index 0000000..8c24d8f
--- /dev/null
+++ b/tools/misc/xen_hello_world.c
@@ -0,0 +1,15 @@
+#include "xsplice.h"
+
+/* Our replacement function for xen_extra_version. */
+const char *xen_hello_world(void)
+{
+    return "Hello World";
+}
+
+struct xsplice_patch_func xsplice_hello_world = {
+    .name = "xen_extra_version",
+    .new_addr = &xen_hello_world,
+    .old_addr = OLD_CODE,
+    .new_size = 13, /* TODO: Compute. */
+    .old_size = 13, /* TODO: Compute. */
+};
diff --git a/tools/misc/xsplice.h b/tools/misc/xsplice.h
new file mode 100644
index 0000000..6ce8bae
--- /dev/null
+++ b/tools/misc/xsplice.h
@@ -0,0 +1,12 @@
+#include <stdint.h>
+#include <sys/types.h>
+
+/* MUST be in sync with hypervisor. */
+struct xsplice_patch_func {
+    const char *name;
+    unsigned long new_addr;
+    const unsigned long old_addr;
+    uint32_t new_size;
+    const uint32_t old_size;
+    uint8_t pad[32];
+};
diff --git a/tools/misc/xsplice.lds b/tools/misc/xsplice.lds
new file mode 100644
index 0000000..f52eb8c
--- /dev/null
+++ b/tools/misc/xsplice.lds
@@ -0,0 +1,11 @@
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(xsplice_hello_world)
+SECTIONS
+{
+    /* The hypervisor expects ".xsplice.func", so change
+     * the ".data.xsplice_hello_world" to it. */
+
+    .xsplice.funcs : { *(*.xsplice_hello_world) }
+
+}
-- 
2.1.0


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

Reply via email to