xc_kexec utility, for domU kexec support.

Signed-off-by: Gerd Hoffmann <kraxel@suse.de>
---
 tools/xcutils/Makefile                  |   10 
 tools/xcutils/helper/Makefile           |   39 +
 tools/xcutils/helper/console.c          |   69 ++
 tools/xcutils/helper/ctype.c            |   35 +
 tools/xcutils/helper/ctype.h            |   54 +
 tools/xcutils/helper/helper.h           |  107 +++
 tools/xcutils/helper/main.c             |  651 +++++++++++++++++++
 tools/xcutils/helper/make-offsets.c     |   28 
 tools/xcutils/helper/printk.c           | 1051 ++++++++++++++++++++++++++++++++
 tools/xcutils/helper/string.c           |  601 ++++++++++++++++++
 tools/xcutils/helper/vsprintf.c         |  842 +++++++++++++++++++++++++
 tools/xcutils/helper/x86_32/div64.h     |   48 +
 tools/xcutils/helper/x86_32/entry.S     |   49 +
 tools/xcutils/helper/x86_32/hypercall.h |  360 ++++++++++
 tools/xcutils/helper/x86_64/div64.h     |   58 +
 tools/xcutils/helper/x86_64/entry.S     |   50 +
 tools/xcutils/helper/x86_64/hypercall.h |  355 ++++++++++
 tools/xcutils/kexec-syscall.h           |   80 ++
 tools/xcutils/xc_kexec.c                |  503 +++++++++++++++
 19 files changed, 4988 insertions(+), 2 deletions(-)

--- a/tools/xcutils/Makefile
+++ b/tools/xcutils/Makefile
@@ -14,9 +14,9 @@ include $(XEN_ROOT)/tools/Rules.mk
 CFLAGS += -Werror
 CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) $(CFLAGS_libxenstore)
 
-PROGRAMS = xc_restore xc_save readnotes lsevtchn
+PROGRAMS = xc_restore xc_save readnotes lsevtchn xc_kexec
 
-LDLIBS   = $(LDFLAGS_libxenctrl) $(LDFLAGS_libxenguest) $(LDFLAGS_libxenstore)
+LDLIBS   = $(LDFLAGS_libxenctrl) $(LDFLAGS_libxenguest) $(LDFLAGS_libxenstore) -lbz2
 
 .PHONY: all
 all: build
@@ -27,6 +27,11 @@ build: $(PROGRAMS)
 $(PROGRAMS): %: %.o
 	$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@
 
+xc_kexec.o: xc_kexec.c helper/blob.h
+
+helper/blob.h:
+	make -C helper
+
 .PHONY: install
 install: build
 	$(INSTALL_DIR) $(DESTDIR)$(PRIVATE_BINDIR)
@@ -37,5 +42,6 @@ install: build
 clean:
 	$(RM) *.o $(PROGRAMS)
 	$(RM) $(DEPS)
+	make -C helper clean
 
 -include $(DEPS)
--- /dev/null
+++ b/tools/xcutils/helper/Makefile
@@ -0,0 +1,39 @@
+
+XEN_ROOT        = ../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+OBJS	:= $(XEN_TARGET_ARCH)/entry.o
+OBJS	+= main.o console.o vsprintf.o string.o ctype.o
+
+CFLAGS	+= -g -I$(XEN_ROOT)/tools/libxc -I$(XEN_TARGET_ARCH) -I$(XEN_INCLUDE)
+
+ifeq ($(XEN_TARGET_ARCH),x86_32)
+HLP_LDFLAGS := -melf_i386
+endif
+
+HLP_LDFLAGS += --section-start .text=0x10000
+HLP_LDFLAGS += --section-start .data=0x20000
+HLP_LDFLAGS += --emit-relocs
+
+#####################
+# rules
+
+all: blob.h
+
+clean:
+	rm -rf helper.elf blob.h
+	rm -rf $(OBJS) *~
+
+helper.elf: $(OBJS)
+	ld $(HLP_LDFLAGS) -o $@ $^
+
+blob.h: helper.elf
+	hexdump -v -e '1/1 "0x%02x,\n"' $< > $@
+
+$(XEN_TARGET_ARCH)/offsets.h: make-offsets
+	./make-offsets > $@
+
+#####################
+# dependencies
+
+$(XEN_TARGET_ARCH)/entry.o: $(XEN_TARGET_ARCH)/entry.S $(XEN_TARGET_ARCH)/offsets.h
--- /dev/null
+++ b/tools/xcutils/helper/console.c
@@ -0,0 +1,69 @@
+#include <inttypes.h>
+
+#include <xenctrl.h>
+#include <xen/io/console.h>
+#include "hypercall.h"
+
+#include "helper.h"
+
+static inline int notify_remote_via_evtchn(int port)
+{
+	struct evtchn_send send;
+	send.port = port;
+	return HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
+}
+
+static inline struct xencons_interface *xencons_interface(void)
+{
+	return (void*)(console_page);
+}
+
+static int xencons_ring_send(const char *data, unsigned len)
+{
+	int sent = 0;
+	struct xencons_interface *intf = xencons_interface();
+	XENCONS_RING_IDX cons, prod;
+
+	cons = intf->out_cons;
+	prod = intf->out_prod;
+	xen_mb();
+
+	while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
+		intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
+
+	xen_wmb();
+	intf->out_prod = prod;
+
+	if (0 != notify_remote_via_evtchn(console_evtchn))
+		return -1;
+	return sent;
+}
+
+int printk(const char *fmt, ...)
+{
+	va_list args;
+	int r;
+
+	va_start(args, fmt);
+	r = vprintk(fmt, args);
+	va_end(args);
+
+	return r;
+}
+
+int vprintk(const char *fmt, va_list args)
+{
+	static char printk_buf[1024];
+	static char prefix[] = "printk: ";
+	int printed_len;
+
+	/* Emit the output into the temporary buffer */
+	printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
+	if (xencons_ring_send(printk_buf, printed_len) < 0) {
+		/* shouldn't happen, but better have a fallback ;) */
+		HYPERVISOR_console_io(CONSOLEIO_write, strlen(prefix), prefix);
+		HYPERVISOR_console_io(CONSOLEIO_write, printed_len, printk_buf);
+	}
+
+	return printed_len;
+}
--- /dev/null
+++ b/tools/xcutils/helper/ctype.c
@@ -0,0 +1,35 @@
+/*
+ *  linux/lib/ctype.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#include "helper.h"
+
+unsigned char _ctype[] = {
+_C,_C,_C,_C,_C,_C,_C,_C,			/* 0-7 */
+_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,		/* 8-15 */
+_C,_C,_C,_C,_C,_C,_C,_C,			/* 16-23 */
+_C,_C,_C,_C,_C,_C,_C,_C,			/* 24-31 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,			/* 32-39 */
+_P,_P,_P,_P,_P,_P,_P,_P,			/* 40-47 */
+_D,_D,_D,_D,_D,_D,_D,_D,			/* 48-55 */
+_D,_D,_P,_P,_P,_P,_P,_P,			/* 56-63 */
+_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,	/* 64-71 */
+_U,_U,_U,_U,_U,_U,_U,_U,			/* 72-79 */
+_U,_U,_U,_U,_U,_U,_U,_U,			/* 80-87 */
+_U,_U,_U,_P,_P,_P,_P,_P,			/* 88-95 */
+_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,	/* 96-103 */
+_L,_L,_L,_L,_L,_L,_L,_L,			/* 104-111 */
+_L,_L,_L,_L,_L,_L,_L,_L,			/* 112-119 */
+_L,_L,_L,_P,_P,_P,_P,_C,			/* 120-127 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 128-143 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 144-159 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
+_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
+_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
+_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
+_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
+_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */
+
+EXPORT_SYMBOL(_ctype);
--- /dev/null
+++ b/tools/xcutils/helper/ctype.h
@@ -0,0 +1,54 @@
+#ifndef _LINUX_CTYPE_H
+#define _LINUX_CTYPE_H
+
+/*
+ * NOTE! This ctype does not handle EOF like the standard C
+ * library is required to.
+ */
+
+#define _U	0x01	/* upper */
+#define _L	0x02	/* lower */
+#define _D	0x04	/* digit */
+#define _C	0x08	/* cntrl */
+#define _P	0x10	/* punct */
+#define _S	0x20	/* white space (space/lf/tab) */
+#define _X	0x40	/* hex digit */
+#define _SP	0x80	/* hard space (0x20) */
+
+extern unsigned char _ctype[];
+
+#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
+
+#define isalnum(c)	((__ismask(c)&(_U|_L|_D)) != 0)
+#define isalpha(c)	((__ismask(c)&(_U|_L)) != 0)
+#define iscntrl(c)	((__ismask(c)&(_C)) != 0)
+#define isdigit(c)	((__ismask(c)&(_D)) != 0)
+#define isgraph(c)	((__ismask(c)&(_P|_U|_L|_D)) != 0)
+#define islower(c)	((__ismask(c)&(_L)) != 0)
+#define isprint(c)	((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
+#define ispunct(c)	((__ismask(c)&(_P)) != 0)
+#define isspace(c)	((__ismask(c)&(_S)) != 0)
+#define isupper(c)	((__ismask(c)&(_U)) != 0)
+#define isxdigit(c)	((__ismask(c)&(_D|_X)) != 0)
+
+#define isascii(c) (((unsigned char)(c))<=0x7f)
+#define toascii(c) (((unsigned char)(c))&0x7f)
+
+static inline unsigned char __tolower(unsigned char c)
+{
+	if (isupper(c))
+		c -= 'A'-'a';
+	return c;
+}
+
+static inline unsigned char __toupper(unsigned char c)
+{
+	if (islower(c))
+		c -= 'a'-'A';
+	return c;
+}
+
+#define tolower(c) __tolower(c)
+#define toupper(c) __toupper(c)
+
+#endif
--- /dev/null
+++ b/tools/xcutils/helper/helper.h
@@ -0,0 +1,107 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <limits.h>
+#include <inttypes.h>
+
+#if defined(__i386__)
+typedef unsigned int size_t;
+typedef int ptrdiff_t;
+#define BITS_PER_LONG 32
+#elif defined(__x86_64__)
+typedef unsigned long size_t;
+typedef long ptrdiff_t;
+#define BITS_PER_LONG 64
+#else
+#error fixme please: unknown arch
+#endif
+
+/* from linux */
+#include "ctype.h"
+#include "div64.h"
+
+/* some stuff to compile linux kernel sources almost unmodified */
+#define unlikely(x) (x)
+#define WARN_ON(x)
+#define BUG_ON(x)
+#define EXPORT_SYMBOL(x)
+
+#ifndef PAGE_SHIFT
+# define PAGE_SHIFT  12
+# define PAGE_SIZE   (1<<PAGE_SHIFT)
+#endif
+
+#define _PAGE_PRESENT   0x001
+#define _PAGE_RW        0x002
+#define _PAGE_USER      0x004
+#define _PAGE_PWT       0x008
+#define _PAGE_PCD       0x010
+#define _PAGE_ACCESSED  0x020
+#define _PAGE_DIRTY     0x040
+#define _PAGE_PAT       0x080
+#define _PAGE_PSE       0x080
+#define _PAGE_GLOBAL    0x100
+
+/* entry.S: special pages */
+extern char hypercall_page[];
+
+/* entry.S: start kernel */
+extern void _start_kernel(void);
+extern void BUG(void);
+
+/* main.c */
+typedef __attribute__ ((aligned (PAGE_SIZE))) char page_t[PAGE_SIZE];
+extern page_t console_page;
+extern page_t xenstore_page;
+extern unsigned long virt_base;
+extern unsigned long virt_hypercall;
+extern unsigned long console_evtchn;
+extern struct vcpu_guest_context vcpu;
+extern struct start_info *old_info;
+
+void start_helper(void);
+
+/* console.c */
+int printk(const char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
+int vprintk(const char *fmt, va_list args);
+
+/* linux: string.c */
+int strnicmp(const char *s1, const char *s2, size_t len);
+char *strcpy(char *dest, const char *src);
+char *strncpy(char *dest, const char *src, size_t count);
+size_t strlcpy(char *dest, const char *src, size_t size);
+char *strcat(char *dest, const char *src);
+char *strncat(char *dest, const char *src, size_t count);
+size_t strlcat(char *dest, const char *src, size_t count);
+size_t strlcat(char *dest, const char *src, size_t count);
+int strcmp(const char *cs, const char *ct);
+int strncmp(const char *cs, const char *ct, size_t count);
+char *strchr(const char *s, int c);
+char *strrchr(const char *s, int c);
+char *strnchr(const char *s, size_t count, int c);
+size_t strlen(const char *s);
+size_t strnlen(const char *s, size_t count);
+size_t strspn(const char *s, const char *accept);
+size_t strcspn(const char *s, const char *reject);
+char *strpbrk(const char *cs, const char *ct);
+char *strsep(char **s, const char *ct);
+void *memset(void *s, int c, size_t count);
+void *memcpy(void *dest, const void *src, size_t count);
+void *memmove(void *dest, const void *src, size_t count);
+int memcmp(const void *cs, const void *ct, size_t count);
+void *memscan(void *addr, int c, size_t size);
+char *strstr(const char *s1, const char *s2);
+void *memchr(const void *s, int c, size_t n);
+
+/* linux: vsprintf.c */
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base);
+long simple_strtol(const char *cp,char **endp,unsigned int base);
+unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base);
+long long simple_strtoll(const char *cp,char **endp,unsigned int base);
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
+int snprintf(char * buf, size_t size, const char *fmt, ...);
+int scnprintf(char * buf, size_t size, const char *fmt, ...);
+int vsprintf(char *buf, const char *fmt, va_list args);
+int sprintf(char * buf, const char *fmt, ...);
+int vsscanf(const char * buf, const char * fmt, va_list args);
+int sscanf(const char * buf, const char * fmt, ...);
--- /dev/null
+++ b/tools/xcutils/helper/main.c
@@ -0,0 +1,651 @@
+#include <xenctrl.h>
+#include "hypercall.h"
+
+#include "helper.h"
+#undef machine_to_phys_mapping
+
+/* filled by xc_kexec */
+unsigned long debug_level = 0;
+unsigned long virt_base;
+unsigned long virt_hypercall;
+unsigned long console_evtchn;
+#if defined(__i386__)
+unsigned long pae_paging;
+#endif
+struct vcpu_guest_context vcpu;
+
+/* passed by trampoline in %esi */
+struct start_info *old_info;
+
+/* my data */
+static struct start_info *new_info;
+static xen_pfn_t *phys_to_machine_mapping;
+static xen_pfn_t *machine_to_phys_mapping;
+static void (*start_kernel)(void);
+
+/* magic pages */
+page_t console_page;
+page_t xenstore_page;
+static page_t shared_info_page;
+static struct shared_info *shared_info = (void*)shared_info_page;
+
+#define dprintk if (debug_level >= 1) printk
+
+/* ------------------------------------------------------------------ */
+
+static unsigned char xen_features[XENFEAT_NR_SUBMAPS * 32];
+#define xen_feature(flag) (xen_features[flag])
+
+static void setup_xen_features(void)
+{
+        xen_feature_info_t fi;
+        int i, j;
+
+        for (i = 0; i < XENFEAT_NR_SUBMAPS; i++) {
+                fi.submap_idx = i;
+                if (HYPERVISOR_xen_version(XENVER_get_features, &fi) < 0)
+                        break;
+                for (j=0; j<32; j++)
+                        xen_features[i*32+j] = !!(fi.submap & 1<<j);
+        }
+}
+
+#if 0 /* DEBUG */
+#include <errno.h>
+#include <xen/io/xs_wire.h>
+static void xenstore_debug(void)
+{
+	struct xenstore_domain_interface *xs = (void*)xenstore_page;
+
+	printk("xs: req %4d -> %4d\r\n", xs->req_cons, xs->req_prod);
+	printk("xs: rsp %4d -> %4d\r\n", xs->rsp_cons, xs->rsp_prod);
+	if (xs->req_cons != xs->req_prod)
+		return;
+	if (xs->rsp_cons != xs->rsp_prod)
+		return;
+
+	memset(xenstore_page, 0, PAGE_SIZE);
+	xen_wmb();
+	printk("xs: debug fixup [zero page] done\r\n");
+}
+#endif
+
+/* ------------------------------------------------------------------ */
+
+#define INVALID_P2M_ENTRY		(~0UL)
+#define FOREIGN_FRAME_BIT		(1UL<<31)
+#define pfn_to_mfn(pfn)			(phys_to_machine_mapping[pfn] & ~FOREIGN_FRAME_BIT)
+#define mfn_to_pfn(mfn)                 (machine_to_phys_mapping[mfn])
+#define set_phys_to_machine(pfn, mfn)	(phys_to_machine_mapping[pfn] = mfn)
+#define phys_to_machine_mapping_valid(pfn) (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY)
+
+void xen_machphys_update(unsigned long mfn, unsigned long pfn)
+{
+        mmu_update_t u;
+	int rc;
+
+        u.ptr = ((unsigned long long)mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
+        u.val = pfn;
+        rc = HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF);
+	if (0 == rc)
+		return;
+	printk("Oops: HYPERVISOR_mmu_update: rc=%d\r\n",rc);
+}
+
+static void swap_pages_p2m(unsigned long pfn1, unsigned long pfn2)
+{
+	unsigned long mfn1, mfn2;
+
+	mfn1 = phys_to_machine_mapping_valid(pfn1)
+		? pfn_to_mfn(pfn1) : INVALID_P2M_ENTRY;
+	mfn2 = phys_to_machine_mapping_valid(pfn2)
+		? pfn_to_mfn(pfn2) : INVALID_P2M_ENTRY;
+	dprintk("%s: pfn %5lx / mfn %5lx  <=>  pfn %5lx / mfn %5lx\r\n",
+	       __FUNCTION__, pfn1, mfn1, pfn2, mfn2);
+
+	if (mfn1 != INVALID_P2M_ENTRY)
+		xen_machphys_update(mfn1, INVALID_P2M_ENTRY);
+	if (mfn2 != INVALID_P2M_ENTRY)
+		xen_machphys_update(mfn2, INVALID_P2M_ENTRY);
+
+	set_phys_to_machine(pfn2, mfn1);
+	if (mfn1 != INVALID_P2M_ENTRY)
+		xen_machphys_update(mfn1, pfn2);
+
+	set_phys_to_machine(pfn1, mfn2);
+	if (mfn2 != INVALID_P2M_ENTRY)
+		xen_machphys_update(mfn2, pfn1);
+}
+
+static void plug_holes_p2m(void)
+{
+	unsigned long pfns = shared_info->arch.max_pfn;
+	unsigned long take, give;
+	int count = 0;
+
+	take = 0;
+	give = pfns-1;
+
+	for (;;) {
+		while (take < give && phys_to_machine_mapping_valid(take))
+			take++;
+		for (; take < give; give--) {
+			if (!phys_to_machine_mapping_valid(give))
+				continue;
+			break;
+		}
+		if (take >= give)
+			break;
+		swap_pages_p2m(give--,take++);
+		count++;
+	}
+	if (!phys_to_machine_mapping_valid(take))
+	    take--;
+
+	new_info->nr_pages = take+1;
+	dprintk("%s: %d swaps, nr_pages is 0x%lx (0x%lx max)\r\n",
+		__FUNCTION__, count, new_info->nr_pages, pfns);
+}
+
+static void fillup_memory_p2m(void)
+{
+	struct xen_memory_reservation reservation = {
+		.mem_flags = 0,
+		.extent_order = 0,
+		.nr_extents   = 1,
+		.domid        = DOMID_SELF,
+	};
+	unsigned long pfns = shared_info->arch.max_pfn;
+	unsigned long pfn, mfn;
+	int rc, count = 0;
+
+	for (pfn = new_info->nr_pages; pfn < pfns; count++, pfn++) {
+		set_xen_guest_handle(reservation.extent_start, &mfn);
+		rc = HYPERVISOR_memory_op(XENMEM_populate_physmap,
+					  &reservation);
+		if (1 != rc)
+			break;
+		xen_machphys_update(mfn, pfn);
+		set_phys_to_machine(pfn, mfn);
+	}
+
+	new_info->nr_pages = pfn;
+	printk("%s: got %d pages, nr_pages is 0x%lx (0x%lx max)\r\n",
+	       __FUNCTION__, count, new_info->nr_pages, pfns);
+}
+
+#define P2M_ENTRIES (PAGE_SIZE/sizeof(xen_pfn_t))
+#define mfn_to_addr(mfn) ((void*)(mfn_to_pfn(mfn) << PAGE_SHIFT))
+
+static void p2m_copy(void)
+{
+	xen_pfn_t     *mfn_lol = NULL, *mfn_list = NULL;
+	unsigned int  off_lol = 0, off_list = 0;
+	xen_pfn_t     pfn;
+
+	phys_to_machine_mapping = (unsigned long*)(new_info->mfn_list - virt_base);
+	for (pfn = 0; pfn < shared_info->arch.max_pfn; pfn += P2M_ENTRIES) {
+		if (0 == pfn) {
+			mfn_lol = mfn_to_addr(shared_info->arch.pfn_to_mfn_frame_list_list);
+			off_lol = 0;
+		}
+		if (0 == (pfn % (P2M_ENTRIES * P2M_ENTRIES))) {
+			mfn_list = mfn_to_addr(mfn_lol[off_lol++]);
+			off_list = 0;
+		}
+		memcpy(phys_to_machine_mapping + pfn,
+		       mfn_to_addr(mfn_list[off_list++]),
+		       PAGE_SIZE);
+	}
+}
+
+static void xen_tlb_flush(void)
+{
+        struct mmuext_op op;
+        op.cmd = MMUEXT_TLB_FLUSH_LOCAL;
+	HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF);
+}
+
+/* ------------------------------------------------------------------ */
+
+#if defined(__i386__)
+
+static void map_page_32(page_t page, unsigned long mfn, unsigned long flags)
+{
+	unsigned long vaddr = (unsigned long)page;
+	uint32_t *pgd = (void*)old_info->pt_base;
+	uint32_t *pte;
+	unsigned long pfn;
+	int pgd_off, pte_off;
+
+        pgd_off = (vaddr >> 22) & (1024-1);
+        pte_off = (vaddr >> 12) & (1024-1);
+
+	pfn = mfn_to_pfn(pgd[pgd_off] >> PAGE_SHIFT);
+	pte = (void*)(pfn << PAGE_SHIFT);
+
+	pte[pte_off] = (mfn << PAGE_SHIFT) | flags;
+}
+
+static void map_virt_base_32(void)
+{
+        mmu_update_t u;
+	xen_pfn_t pgd_mfn = pfn_to_mfn(old_info->pt_base >> PAGE_SHIFT);
+        uint32_t *pgd_ma = (void*)(pgd_mfn << PAGE_SHIFT);
+	uint32_t *pgd = (void*)old_info->pt_base;
+	uint32_t pgd_virt = virt_base >> 22;
+	uint32_t pgd_low = 0;
+
+	if (pgd_virt << 22 != virt_base) {
+		printk("%s: warning: virt_base is not at pgd entry border,\r\n"
+		       "  that will work only if old and new kernel have\r\n"
+		       "  an identical virt_base.\r\n", __FUNCTION__);
+		return;
+	}
+
+	for (;;) {
+		if (!(pgd[pgd_low] & _PAGE_PRESENT))
+			return;
+		u.ptr = (unsigned long)(pgd_ma + pgd_virt);
+		u.val = pgd[pgd_low];
+		if (HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0) {
+			printk("%s: mmu_update failed [l2 0x%x -> 0x%x]\r\n",
+			       __FUNCTION__, pgd_low, pgd_virt);
+			return;
+		}
+		pgd_virt++;
+		pgd_low++;
+	}
+}
+
+static void map_page_pae(page_t page, unsigned long mfn, unsigned long flags)
+{
+	unsigned long vaddr = (unsigned long)page;
+	uint64_t *pgd = (void*)old_info->pt_base;
+	uint64_t *pmd;
+	uint64_t *pte;
+	unsigned long pfn;
+	int pgd_off, pmd_off, pte_off;
+
+        pgd_off = (vaddr >> 30) & (4-1);
+        pmd_off = (vaddr >> 21) & (512-1);
+        pte_off = (vaddr >> 12) & (512-1);
+
+	pfn = mfn_to_pfn(pgd[pgd_off] >> PAGE_SHIFT);
+	pmd = (void*)(pfn << PAGE_SHIFT);
+	pfn = mfn_to_pfn(pmd[pmd_off] >> PAGE_SHIFT);
+	pte = (void*)(pfn << PAGE_SHIFT);
+
+	pte[pte_off] = (mfn << PAGE_SHIFT) | flags;
+}
+
+static void map_virt_base_pae(void)
+{
+        mmu_update_t u;
+	xen_pfn_t pgd_mfn = pfn_to_mfn(old_info->pt_base >> PAGE_SHIFT);
+        uint64_t *pgd_ma = (void*)(pgd_mfn << PAGE_SHIFT);
+	uint64_t *pgd = (void*)old_info->pt_base;
+	int i;
+
+	for (i = 1; i <= 2; i++) {
+		u.ptr = (unsigned long)(pgd_ma + i);
+		u.val = pgd[0];
+		if (HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0) {
+			printk("%s: mmu_update failed [l3 0 -> %d]\r\n",
+			       __FUNCTION__, i);
+			return;
+		}
+	}
+}
+
+static void map_page(page_t page, unsigned long mfn, unsigned long flags)
+{
+	if (pae_paging)
+		map_page_pae(page, mfn, flags);
+	else
+		map_page_32(page, mfn, flags);
+	xen_tlb_flush();
+	xen_wmb();
+}
+
+static void map_virt_base(void)
+{
+	if (pae_paging)
+		map_virt_base_pae();
+	else
+		map_virt_base_32();
+	xen_tlb_flush();
+	xen_wmb();
+}
+
+static void fixup_pagetables_32(void)
+{
+	uint32_t *pgd = (void*)new_info->pt_base - virt_base;
+	uint32_t *pte;
+	uint32_t flg;
+	unsigned long pfn;
+	int l2, l1;
+
+	dprintk("%s: pgd  at 0x%p\r\n", __FUNCTION__, pgd);
+	for (l2 = 0; l2 < 1024; l2++) {
+		if (!pgd[l2] & 1)
+			continue;
+		flg = pgd[l2] & (PAGE_SIZE-1);
+		pfn = pgd[l2] >> PAGE_SHIFT;
+		pgd[l2] = (pfn_to_mfn(pfn) << PAGE_SHIFT) | flg;
+
+#if 1
+		/* Dirty hack alert: Add identity map for first 4MB,
+		 * so we don't kill ourself when activating the new
+		 * kernel's page tables.  May have the side effect of
+		 * killing the kernel later. */
+		if (!pgd[0])
+			pgd[0] = pgd[l2];
+#endif
+
+		pte = (void*)(pfn << PAGE_SHIFT);
+		dprintk("%s:  pte at 0x%p\r\n", __FUNCTION__, pte);
+		for (l1 = 0; l1 < 1024; l1++) {
+			if (!pte[l1] & 1)
+				continue;
+			flg = pte[l1] & (PAGE_SIZE-1);
+			pfn = pte[l1] >> PAGE_SHIFT;
+			pte[l1] = (pfn_to_mfn(pfn) << PAGE_SHIFT) | flg;
+		}
+	}
+}
+
+static void fixup_pagetables_pae(void)
+{
+	uint64_t *pgd = (void*)new_info->pt_base - virt_base;
+	uint64_t *pmd;
+	uint64_t *pte;
+	uint64_t flg;
+	unsigned long pfn;
+	int l3, l2, l1;
+
+	dprintk("%s: pgd   at 0x%p\r\n", __FUNCTION__, pgd);
+	for (l3 = 0; l3 < 4; l3++) {
+		if (!pgd[l3] & 1)
+			continue;
+		flg = pgd[l3] & (PAGE_SIZE-1);
+		pfn = pgd[l3] >> PAGE_SHIFT;
+		pgd[l3] = (pfn_to_mfn(pfn) << PAGE_SHIFT) | flg;
+
+		pmd = (void*)(pfn << PAGE_SHIFT);
+		dprintk("%s:  pmd  at 0x%p\r\n", __FUNCTION__, pmd);
+		for (l2 = 0; l2 < 512; l2++) {
+			if (!pmd[l2] & 1)
+				continue;
+			flg = pmd[l2] & (PAGE_SIZE-1);
+			pfn = pmd[l2] >> PAGE_SHIFT;
+			pmd[l2] = (pfn_to_mfn(pfn) << PAGE_SHIFT) | flg;
+
+			pte = (void*)(pfn << PAGE_SHIFT);
+			dprintk("%s:   pte at 0x%p\r\n", __FUNCTION__, pte);
+			for (l1 = 0; l1 < 512; l1++) {
+				if (!pte[l1] & 1)
+					continue;
+				flg = pte[l1] & (PAGE_SIZE-1);
+				pfn = pte[l1] >> PAGE_SHIFT;
+				pte[l1] = (pfn_to_mfn(pfn) << PAGE_SHIFT) | flg;
+			}
+		}
+	}
+}
+
+static void fixup_pagetables(void)
+{
+	if (pae_paging)
+		fixup_pagetables_pae();
+	else
+		fixup_pagetables_32();
+}
+
+#endif /* i386 */
+
+#if defined(__x86_64__)
+
+static void map_page(page_t page, unsigned long mfn, unsigned long flags)
+{
+	unsigned long vaddr = (unsigned long)page;
+	uint64_t *pgd = (void*)old_info->pt_base;
+	uint64_t *pud;
+	uint64_t *pmd;
+	uint64_t *pte;
+	xen_pfn_t pfn;
+	int pgd_off, pud_off, pmd_off, pte_off;
+
+        pgd_off = (vaddr >> 39) & (512-1);
+        pud_off = (vaddr >> 30) & (512-1);
+        pmd_off = (vaddr >> 21) & (512-1);
+        pte_off = (vaddr >> 12) & (512-1);
+
+	pfn = mfn_to_pfn(pgd[pgd_off] >> PAGE_SHIFT);
+	pud = (void*)(pfn << PAGE_SHIFT);
+	pfn = mfn_to_pfn(pud[pud_off] >> PAGE_SHIFT);
+	pmd = (void*)(pfn << PAGE_SHIFT);
+	pfn = mfn_to_pfn(pmd[pmd_off] >> PAGE_SHIFT);
+	pte = (void*)(pfn << PAGE_SHIFT);
+
+	pte[pte_off] = (mfn << PAGE_SHIFT) | flags;
+
+	xen_tlb_flush();
+	xen_wmb();
+}
+
+static void map_virt_base(void)
+{
+        mmu_update_t u;
+	xen_pfn_t pgd_mfn = pfn_to_mfn(old_info->pt_base >> PAGE_SHIFT);
+        uint64_t *pgd_ma = (void*)(pgd_mfn << PAGE_SHIFT);
+	uint64_t *pgd = (void*)old_info->pt_base;
+	uint64_t pgd_virt = (virt_base >> 39);
+	uint64_t pgd_low = 0;
+
+	if (pgd_virt << 39 != virt_base) {
+		printk("%s: warning: virt_base is not at pgd entry border,\r\n"
+		       "  that will work only if old and new kernel have\r\n"
+		       "  an identical virt_base.\r\n", __FUNCTION__);
+		return;
+	}
+
+	for (;;) {
+		if (!(pgd[pgd_low] & _PAGE_PRESENT))
+			break;
+		u.ptr = (unsigned long)(pgd_ma + pgd_virt);
+		u.val = pgd[pgd_low];
+		printk("%s: ptr 0x%" PRIx64" val 0x%" PRIx64"\r\n",
+		       __FUNCTION__, u.ptr, u.val);
+		if (HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0) {
+			printk("%s: mmu_update failed [l4 0x%lx -> 0x%lx]\r\n",
+			       __FUNCTION__, pgd_low, pgd_virt);
+			break;
+		}
+		pgd_virt++;
+		pgd_low++;
+	}
+	xen_tlb_flush();
+	xen_wmb();
+}
+
+static void fixup_pagetables(void)
+{
+	uint64_t *pgd = (void*)new_info->pt_base - virt_base;
+	uint64_t *pud;
+	uint64_t *pmd;
+	uint64_t *pte;
+	uint64_t flg;
+	unsigned long pfn;
+	int l4, l3, l2, l1;
+
+	dprintk("%s: pgd    at 0x%p\r\n", __FUNCTION__, pgd);
+	for (l4 = 0; l4 < 512; l4++) {
+		if (!pgd[l4] & 1)
+			continue;
+		flg = pgd[l4] & (PAGE_SIZE-1);
+		pfn = pgd[l4] >> PAGE_SHIFT;
+		pgd[l4] = (pfn_to_mfn(pfn) << PAGE_SHIFT) | flg;
+
+		pud = (void*)(pfn << PAGE_SHIFT);
+		dprintk("%s:  pud   at 0x%p\r\n", __FUNCTION__, pud);
+		for (l3 = 0; l3 < 512; l3++) {
+			if (!pud[l3] & 1)
+				continue;
+			flg = pud[l3] & (PAGE_SIZE-1);
+			pfn = pud[l3] >> PAGE_SHIFT;
+			pud[l3] = (pfn_to_mfn(pfn) << PAGE_SHIFT) | flg;
+
+			pmd = (void*)(pfn << PAGE_SHIFT);
+			dprintk("%s:   pmd  at 0x%p\r\n", __FUNCTION__, pmd);
+			for (l2 = 0; l2 < 512; l2++) {
+				if (!pmd[l2] & 1)
+					continue;
+				flg = pmd[l2] & (PAGE_SIZE-1);
+				pfn = pmd[l2] >> PAGE_SHIFT;
+				pmd[l2] = (pfn_to_mfn(pfn) << PAGE_SHIFT) | flg;
+
+				pte = (void*)(pfn << PAGE_SHIFT);
+				dprintk("%s:    pte at 0x%p\r\n", __FUNCTION__, pte);
+				for (l1 = 0; l1 < 512; l1++) {
+					if (!pte[l1] & 1)
+						continue;
+					flg = pte[l1] & (PAGE_SIZE-1);
+					pfn = pte[l1] >> PAGE_SHIFT;
+					pte[l1] = (pfn_to_mfn(pfn) << PAGE_SHIFT) | flg;
+				}
+			}
+		}
+	}
+}
+
+#endif /* x86_64 */
+
+/* ------------------------------------------------------------------ */
+
+static void print_start_info(char *name, struct start_info *info)
+{
+	if (!debug_level)
+		return;
+	printk("%s start_info page @ %p\r\n", name, info);
+	printk("  magic          \"%s\"\r\n", info->magic);
+	printk("  nr_pages       0x%lx\r\n",  info->nr_pages);
+	printk("  shared_info    0x%lx\r\n",  info->shared_info);
+	printk("  flags          0x%x\r\n",   info->flags);
+	printk("  store_mfn      0x%lx\r\n",  info->store_mfn);
+	printk("  store_evtchn   %d\r\n",     info->store_evtchn);
+	printk("  console.mfn    0x%lx\r\n",  info->console.domU.mfn);
+	printk("  console.evtchn %d\r\n",     info->console.domU.evtchn);
+	printk("  pt_base        0x%lx\r\n",  info->pt_base);
+	printk("  nr_pt_frames   0x%lx\r\n",  info->nr_pt_frames);
+	printk("  mfn_list       0x%lx\r\n",  info->mfn_list);
+	printk("  mod_start      0x%lx\r\n",  info->mod_start);
+	printk("  mod_len        0x%lx\r\n",  info->mod_len);
+	printk("  cmd_line       \"%s\"\r\n", info->cmd_line);
+	printk("\r\n");
+}
+
+void start_helper(void)
+{
+	int shadow_translated;
+	unsigned long cr3_mfn;
+
+	/* find m2p map */
+#if defined(__i386__)
+	if (pae_paging) {
+	    machine_to_phys_mapping = (xen_pfn_t*)0xf5800000;
+	} else {
+	    machine_to_phys_mapping = (xen_pfn_t*)0xfc000000;
+	}
+#endif
+#if defined(__x86_64__)
+	machine_to_phys_mapping = ((xen_pfn_t*)HYPERVISOR_VIRT_START);
+#endif
+
+	/* map magic pages */
+	map_page(console_page, old_info->console.domU.mfn,
+		 _PAGE_PRESENT | _PAGE_RW);
+	map_page(xenstore_page, old_info->store_mfn,
+		 _PAGE_PRESENT | _PAGE_RW);
+	map_page(shared_info_page, old_info->shared_info >> PAGE_SHIFT,
+		 _PAGE_PRESENT | _PAGE_RW);
+
+	/* setup console, say hello world */
+	console_evtchn = old_info->console.domU.evtchn;
+	printk("\r\nHello world from xen kexec helper\r\n\r\n");
+
+	/* print old start info page */
+	print_start_info("old", old_info);
+
+	/* figure and print some info */
+	setup_xen_features();
+	shadow_translated = xen_feature(XENFEAT_auto_translated_physmap);
+	dprintk("shadow_translated  is  %s\r\n",
+		shadow_translated ? "on" : "off");
+#if defined(__i386__)
+	dprintk("pae paging         is  %s\r\n",
+		pae_paging ? "on" : "off");
+#endif
+	dprintk("virtual base       is  0x%lx\r\n", virt_base);
+	if (-1 != virt_hypercall)
+		dprintk("hypercall page at  is  0x%lx\r\n", virt_hypercall);
+	dprintk("kernel entry point is  0x%lx\r\n", (unsigned long)vcpu.user_regs.eip);
+	dprintk("start_info page    is  0x%lx\r\n", (unsigned long)vcpu.user_regs.esi);
+	dprintk("kernel boot stack  is  0x%lx\r\n", (unsigned long)vcpu.user_regs.esp);
+	dprintk("\r\n");
+
+//	xenstore_debug();
+
+	/* fixup new start info page */
+	new_info = (struct start_info*)(vcpu.user_regs.esi - virt_base);
+	new_info->shared_info = old_info->shared_info;
+	new_info->store_mfn = old_info->store_mfn;
+	new_info->store_evtchn = old_info->store_evtchn;
+	new_info->console.domU.mfn = old_info->console.domU.mfn;
+	new_info->console.domU.evtchn = old_info->console.domU.evtchn;
+
+	if (shadow_translated) {
+		printk("TODO: handle magic pages\r\n");
+		cr3_mfn = (new_info->pt_base - virt_base) >> PAGE_SHIFT;
+	} else {
+		/* copy p2m table to final place */
+		dprintk("copy p2m map\r\n");
+		p2m_copy();
+
+		/* move magic pages, page order is important here:
+		 * start_info, xenstore, console */
+		dprintk("setup magic pages: xenstore and console\r\n");
+		swap_pages_p2m(mfn_to_pfn(new_info->store_mfn),
+			       ((unsigned long)new_info >> PAGE_SHIFT)+1);
+		swap_pages_p2m(mfn_to_pfn(new_info->console.domU.mfn),
+			       ((unsigned long)new_info >> PAGE_SHIFT)+2);
+
+		if (-1 != virt_hypercall) {
+			dprintk("setup hypercall page\r\n");
+			memcpy((void*)(virt_hypercall - virt_base),
+			       hypercall_page, PAGE_SIZE);
+		}
+
+		dprintk("setup main memory\r\n");
+		plug_holes_p2m();
+		fillup_memory_p2m();
+
+		dprintk("mirror lowmem at virt_base [0x%lx]\r\n", virt_base);
+		map_virt_base();
+		start_kernel = _start_kernel + virt_base;
+
+		dprintk("setup new kernel's page tables\r\n");
+		fixup_pagetables();
+		cr3_mfn = pfn_to_mfn((new_info->pt_base - virt_base) >> PAGE_SHIFT);
+	}
+	printk("\r\n");
+
+	/* print new start info page */
+	print_start_info("new", new_info);
+
+	/* boot kernel */
+	vcpu.ctrlreg[3] = cr3_mfn << PAGE_SHIFT;
+	printk("All done, bye folks, trying to boot the kernel ...\r\n");
+	printk("\r\n");
+	start_kernel();
+}
--- /dev/null
+++ b/tools/xcutils/helper/make-offsets.c
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <xenctrl.h>
+
+#define vcpu_off(name,elem) printf("#define vcpu_%s 0x%lx\n", name, \
+	(unsigned long)offsetof(struct vcpu_guest_context, elem))
+
+int main(int argc, char **argv)
+{
+    vcpu_off("eax", user_regs.eax);
+    vcpu_off("ebx", user_regs.ebx);
+    vcpu_off("ecx", user_regs.ecx);
+    vcpu_off("edx", user_regs.edx);
+    vcpu_off("esi", user_regs.esi);
+    vcpu_off("edi", user_regs.edi);
+    vcpu_off("ebp", user_regs.ebp);
+    vcpu_off("esp", user_regs.esp);
+
+    vcpu_off("cs",  user_regs.cs);
+    vcpu_off("ds",  user_regs.ds);
+    vcpu_off("es",  user_regs.es);
+    vcpu_off("fs",  user_regs.fs);
+    vcpu_off("gs",  user_regs.gs);
+    vcpu_off("ss",  user_regs.ss);
+
+    vcpu_off("eip", user_regs.eip);
+    vcpu_off("cr3", ctrlreg[3]);
+    return 0;
+}
--- /dev/null
+++ b/tools/xcutils/helper/printk.c
@@ -0,0 +1,1051 @@
+/*
+ *  linux/kernel/printk.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * Modified to make sys_syslog() more flexible: added commands to
+ * return the last 4k of kernel messages, regardless of whether
+ * they've been read or not.  Added option to suppress kernel printk's
+ * to the console.  Added hook for sending the console messages
+ * elsewhere, in preparation for a serial line console (someday).
+ * Ted Ts'o, 2/11/93.
+ * Modified for sysctl support, 1/8/97, Chris Horn.
+ * Fixed SMP synchronization, 08/08/99, Manfred Spraul
+ *     manfreds@colorfullife.com
+ * Rewrote bits to get rid of console_lock
+ *	01Mar01 Andrew Morton <andrewm@uow.edu.au>
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/smp_lock.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>			/* For in_interrupt() */
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <linux/security.h>
+#include <linux/bootmem.h>
+#include <linux/syscalls.h>
+
+#include <asm/uaccess.h>
+
+#define __LOG_BUF_LEN	(1 << CONFIG_LOG_BUF_SHIFT)
+
+/* printk's without a loglevel use this.. */
+#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
+
+/* We show everything that is MORE important than this.. */
+#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
+#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */
+
+DECLARE_WAIT_QUEUE_HEAD(log_wait);
+
+int console_printk[4] = {
+	DEFAULT_CONSOLE_LOGLEVEL,	/* console_loglevel */
+	DEFAULT_MESSAGE_LOGLEVEL,	/* default_message_loglevel */
+	MINIMUM_CONSOLE_LOGLEVEL,	/* minimum_console_loglevel */
+	DEFAULT_CONSOLE_LOGLEVEL,	/* default_console_loglevel */
+};
+
+EXPORT_SYMBOL(console_printk);
+
+/*
+ * Low lever drivers may need that to know if they can schedule in
+ * their unblank() callback or not. So let's export it.
+ */
+int oops_in_progress;
+EXPORT_SYMBOL(oops_in_progress);
+
+/*
+ * console_sem protects the console_drivers list, and also
+ * provides serialisation for access to the entire console
+ * driver system.
+ */
+static DECLARE_MUTEX(console_sem);
+struct console *console_drivers;
+/*
+ * This is used for debugging the mess that is the VT code by
+ * keeping track if we have the console semaphore held. It's
+ * definitely not the perfect debug tool (we don't know if _WE_
+ * hold it are racing, but it helps tracking those weird code
+ * path in the console code where we end up in places I want
+ * locked without the console sempahore held
+ */
+static int console_locked;
+
+/*
+ * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars
+ * It is also used in interesting ways to provide interlocking in
+ * release_console_sem().
+ */
+static DEFINE_SPINLOCK(logbuf_lock);
+
+#define LOG_BUF_MASK	(log_buf_len-1)
+#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
+
+/*
+ * The indices into log_buf are not constrained to log_buf_len - they
+ * must be masked before subscripting
+ */
+static unsigned long log_start;	/* Index into log_buf: next char to be read by syslog() */
+static unsigned long con_start;	/* Index into log_buf: next char to be sent to consoles */
+static unsigned long log_end;	/* Index into log_buf: most-recently-written-char + 1 */
+
+/*
+ *	Array of consoles built from command line options (console=)
+ */
+struct console_cmdline
+{
+	char	name[8];			/* Name of the driver	    */
+	int	index;				/* Minor dev. to use	    */
+	char	*options;			/* Options for the driver   */
+};
+
+#define MAX_CMDLINECONSOLES 8
+
+static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
+static int selected_console = -1;
+static int preferred_console = -1;
+
+/* Flag: console code may call schedule() */
+static int console_may_schedule;
+
+#ifdef CONFIG_PRINTK
+
+static char __log_buf[__LOG_BUF_LEN];
+static char *log_buf = __log_buf;
+static int log_buf_len = __LOG_BUF_LEN;
+static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */
+
+/*
+ *	Setup a list of consoles. Called from init/main.c
+ */
+static int __init console_setup(char *str)
+{
+	char name[sizeof(console_cmdline[0].name)];
+	char *s, *options;
+	int idx;
+
+	/*
+	 *	Decode str into name, index, options.
+	 */
+	if (str[0] >= '0' && str[0] <= '9') {
+		strcpy(name, "ttyS");
+		strncpy(name + 4, str, sizeof(name) - 5);
+	} else
+		strncpy(name, str, sizeof(name) - 1);
+	name[sizeof(name) - 1] = 0;
+	if ((options = strchr(str, ',')) != NULL)
+		*(options++) = 0;
+#ifdef __sparc__
+	if (!strcmp(str, "ttya"))
+		strcpy(name, "ttyS0");
+	if (!strcmp(str, "ttyb"))
+		strcpy(name, "ttyS1");
+#endif
+	for (s = name; *s; s++)
+		if ((*s >= '0' && *s <= '9') || *s == ',')
+			break;
+	idx = simple_strtoul(s, NULL, 10);
+	*s = 0;
+
+	add_preferred_console(name, idx, options);
+	return 1;
+}
+
+__setup("console=", console_setup);
+
+static int __init log_buf_len_setup(char *str)
+{
+	unsigned long size = memparse(str, &str);
+	unsigned long flags;
+
+	if (size)
+		size = roundup_pow_of_two(size);
+	if (size > log_buf_len) {
+		unsigned long start, dest_idx, offset;
+		char *new_log_buf;
+
+		new_log_buf = alloc_bootmem(size);
+		if (!new_log_buf) {
+			printk(KERN_WARNING "log_buf_len: allocation failed\n");
+			goto out;
+		}
+
+		spin_lock_irqsave(&logbuf_lock, flags);
+		log_buf_len = size;
+		log_buf = new_log_buf;
+
+		offset = start = min(con_start, log_start);
+		dest_idx = 0;
+		while (start != log_end) {
+			log_buf[dest_idx] = __log_buf[start & (__LOG_BUF_LEN - 1)];
+			start++;
+			dest_idx++;
+		}
+		log_start -= offset;
+		con_start -= offset;
+		log_end -= offset;
+		spin_unlock_irqrestore(&logbuf_lock, flags);
+
+		printk(KERN_NOTICE "log_buf_len: %d\n", log_buf_len);
+	}
+out:
+	return 1;
+}
+
+__setup("log_buf_len=", log_buf_len_setup);
+
+/*
+ * Commands to do_syslog:
+ *
+ * 	0 -- Close the log.  Currently a NOP.
+ * 	1 -- Open the log. Currently a NOP.
+ * 	2 -- Read from the log.
+ * 	3 -- Read all messages remaining in the ring buffer.
+ * 	4 -- Read and clear all messages remaining in the ring buffer
+ * 	5 -- Clear ring buffer.
+ * 	6 -- Disable printk's to console
+ * 	7 -- Enable printk's to console
+ *	8 -- Set level of messages printed to console
+ *	9 -- Return number of unread characters in the log buffer
+ *     10 -- Return size of the log buffer
+ */
+int do_syslog(int type, char __user *buf, int len)
+{
+	unsigned long i, j, limit, count;
+	int do_clear = 0;
+	char c;
+	int error = 0;
+
+	error = security_syslog(type);
+	if (error)
+		return error;
+
+	switch (type) {
+	case 0:		/* Close log */
+		break;
+	case 1:		/* Open log */
+		break;
+	case 2:		/* Read from log */
+		error = -EINVAL;
+		if (!buf || len < 0)
+			goto out;
+		error = 0;
+		if (!len)
+			goto out;
+		if (!access_ok(VERIFY_WRITE, buf, len)) {
+			error = -EFAULT;
+			goto out;
+		}
+		error = wait_event_interruptible(log_wait,
+							(log_start - log_end));
+		if (error)
+			goto out;
+		i = 0;
+		spin_lock_irq(&logbuf_lock);
+		while (!error && (log_start != log_end) && i < len) {
+			c = LOG_BUF(log_start);
+			log_start++;
+			spin_unlock_irq(&logbuf_lock);
+			error = __put_user(c,buf);
+			buf++;
+			i++;
+			cond_resched();
+			spin_lock_irq(&logbuf_lock);
+		}
+		spin_unlock_irq(&logbuf_lock);
+		if (!error)
+			error = i;
+		break;
+	case 4:		/* Read/clear last kernel messages */
+		do_clear = 1;
+		/* FALL THRU */
+	case 3:		/* Read last kernel messages */
+		error = -EINVAL;
+		if (!buf || len < 0)
+			goto out;
+		error = 0;
+		if (!len)
+			goto out;
+		if (!access_ok(VERIFY_WRITE, buf, len)) {
+			error = -EFAULT;
+			goto out;
+		}
+		count = len;
+		if (count > log_buf_len)
+			count = log_buf_len;
+		spin_lock_irq(&logbuf_lock);
+		if (count > logged_chars)
+			count = logged_chars;
+		if (do_clear)
+			logged_chars = 0;
+		limit = log_end;
+		/*
+		 * __put_user() could sleep, and while we sleep
+		 * printk() could overwrite the messages
+		 * we try to copy to user space. Therefore
+		 * the messages are copied in reverse. <manfreds>
+		 */
+		for (i = 0; i < count && !error; i++) {
+			j = limit-1-i;
+			if (j + log_buf_len < log_end)
+				break;
+			c = LOG_BUF(j);
+			spin_unlock_irq(&logbuf_lock);
+			error = __put_user(c,&buf[count-1-i]);
+			cond_resched();
+			spin_lock_irq(&logbuf_lock);
+		}
+		spin_unlock_irq(&logbuf_lock);
+		if (error)
+			break;
+		error = i;
+		if (i != count) {
+			int offset = count-error;
+			/* buffer overflow during copy, correct user buffer. */
+			for (i = 0; i < error; i++) {
+				if (__get_user(c,&buf[i+offset]) ||
+				    __put_user(c,&buf[i])) {
+					error = -EFAULT;
+					break;
+				}
+				cond_resched();
+			}
+		}
+		break;
+	case 5:		/* Clear ring buffer */
+		logged_chars = 0;
+		break;
+	case 6:		/* Disable logging to console */
+		console_loglevel = minimum_console_loglevel;
+		break;
+	case 7:		/* Enable logging to console */
+		console_loglevel = default_console_loglevel;
+		break;
+	case 8:		/* Set level of messages printed to console */
+		error = -EINVAL;
+		if (len < 1 || len > 8)
+			goto out;
+		if (len < minimum_console_loglevel)
+			len = minimum_console_loglevel;
+		console_loglevel = len;
+		error = 0;
+		break;
+	case 9:		/* Number of chars in the log buffer */
+		error = log_end - log_start;
+		break;
+	case 10:	/* Size of the log buffer */
+		error = log_buf_len;
+		break;
+	default:
+		error = -EINVAL;
+		break;
+	}
+out:
+	return error;
+}
+
+asmlinkage long sys_syslog(int type, char __user *buf, int len)
+{
+	return do_syslog(type, buf, len);
+}
+
+/*
+ * Call the console drivers on a range of log_buf
+ */
+static void __call_console_drivers(unsigned long start, unsigned long end)
+{
+	struct console *con;
+
+	for (con = console_drivers; con; con = con->next) {
+		if ((con->flags & CON_ENABLED) && con->write)
+			con->write(con, &LOG_BUF(start), end - start);
+	}
+}
+
+/*
+ * Write out chars from start to end - 1 inclusive
+ */
+static void _call_console_drivers(unsigned long start,
+				unsigned long end, int msg_log_level)
+{
+	if (msg_log_level < console_loglevel &&
+			console_drivers && start != end) {
+		if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
+			/* wrapped write */
+			__call_console_drivers(start & LOG_BUF_MASK,
+						log_buf_len);
+			__call_console_drivers(0, end & LOG_BUF_MASK);
+		} else {
+			__call_console_drivers(start, end);
+		}
+	}
+}
+
+/*
+ * Call the console drivers, asking them to write out
+ * log_buf[start] to log_buf[end - 1].
+ * The console_sem must be held.
+ */
+static void call_console_drivers(unsigned long start, unsigned long end)
+{
+	unsigned long cur_index, start_print;
+	static int msg_level = -1;
+
+	if (((long)(start - end)) > 0)
+		BUG();
+
+	cur_index = start;
+	start_print = start;
+	while (cur_index != end) {
+		if (msg_level < 0 && ((end - cur_index) > 2) &&
+				LOG_BUF(cur_index + 0) == '<' &&
+				LOG_BUF(cur_index + 1) >= '0' &&
+				LOG_BUF(cur_index + 1) <= '7' &&
+				LOG_BUF(cur_index + 2) == '>') {
+			msg_level = LOG_BUF(cur_index + 1) - '0';
+			cur_index += 3;
+			start_print = cur_index;
+		}
+		while (cur_index != end) {
+			char c = LOG_BUF(cur_index);
+
+			cur_index++;
+			if (c == '\n') {
+				if (msg_level < 0) {
+					/*
+					 * printk() has already given us loglevel tags in
+					 * the buffer.  This code is here in case the
+					 * log buffer has wrapped right round and scribbled
+					 * on those tags
+					 */
+					msg_level = default_message_loglevel;
+				}
+				_call_console_drivers(start_print, cur_index, msg_level);
+				msg_level = -1;
+				start_print = cur_index;
+				break;
+			}
+		}
+	}
+	_call_console_drivers(start_print, end, msg_level);
+}
+
+static void emit_log_char(char c)
+{
+	LOG_BUF(log_end) = c;
+	log_end++;
+	if (log_end - log_start > log_buf_len)
+		log_start = log_end - log_buf_len;
+	if (log_end - con_start > log_buf_len)
+		con_start = log_end - log_buf_len;
+	if (logged_chars < log_buf_len)
+		logged_chars++;
+}
+
+/*
+ * Zap console related locks when oopsing. Only zap at most once
+ * every 10 seconds, to leave time for slow consoles to print a
+ * full oops.
+ */
+static void zap_locks(void)
+{
+	static unsigned long oops_timestamp;
+
+	if (time_after_eq(jiffies, oops_timestamp) &&
+			!time_after(jiffies, oops_timestamp + 30 * HZ))
+		return;
+
+	oops_timestamp = jiffies;
+
+	/* If a crash is occurring, make sure we can't deadlock */
+	spin_lock_init(&logbuf_lock);
+	/* And make sure that we print immediately */
+	init_MUTEX(&console_sem);
+}
+
+#if defined(CONFIG_PRINTK_TIME)
+static int printk_time = 1;
+#else
+static int printk_time = 0;
+#endif
+
+static int __init printk_time_setup(char *str)
+{
+	if (*str)
+		return 0;
+	printk_time = 1;
+	return 1;
+}
+
+__setup("time", printk_time_setup);
+
+__attribute__((weak)) unsigned long long printk_clock(void)
+{
+	return sched_clock();
+}
+
+/**
+ * printk - print a kernel message
+ * @fmt: format string
+ *
+ * This is printk.  It can be called from any context.  We want it to work.
+ *
+ * We try to grab the console_sem.  If we succeed, it's easy - we log the output and
+ * call the console drivers.  If we fail to get the semaphore we place the output
+ * into the log buffer and return.  The current holder of the console_sem will
+ * notice the new output in release_console_sem() and will send it to the
+ * consoles before releasing the semaphore.
+ *
+ * One effect of this deferred printing is that code which calls printk() and
+ * then changes console_loglevel may break. This is because console_loglevel
+ * is inspected when the actual printing occurs.
+ *
+ * See also:
+ * printf(3)
+ */
+
+asmlinkage int printk(const char *fmt, ...)
+{
+	va_list args;
+	int r;
+
+	va_start(args, fmt);
+	r = vprintk(fmt, args);
+	va_end(args);
+
+	return r;
+}
+
+/* cpu currently holding logbuf_lock */
+static volatile unsigned int printk_cpu = UINT_MAX;
+
+asmlinkage int vprintk(const char *fmt, va_list args)
+{
+	unsigned long flags;
+	int printed_len;
+	char *p;
+	static char printk_buf[1024];
+	static int log_level_unknown = 1;
+
+	preempt_disable();
+	if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id())
+		/* If a crash is occurring during printk() on this CPU,
+		 * make sure we can't deadlock */
+		zap_locks();
+
+	/* This stops the holder of console_sem just where we want him */
+	spin_lock_irqsave(&logbuf_lock, flags);
+	printk_cpu = smp_processor_id();
+
+	/* Emit the output into the temporary buffer */
+	printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
+
+	/*
+	 * Copy the output into log_buf.  If the caller didn't provide
+	 * appropriate log level tags, we insert them here
+	 */
+	for (p = printk_buf; *p; p++) {
+		if (log_level_unknown) {
+                        /* log_level_unknown signals the start of a new line */
+			if (printk_time) {
+				int loglev_char;
+				char tbuf[50], *tp;
+				unsigned tlen;
+				unsigned long long t;
+				unsigned long nanosec_rem;
+
+				/*
+				 * force the log level token to be
+				 * before the time output.
+				 */
+				if (p[0] == '<' && p[1] >='0' &&
+				   p[1] <= '7' && p[2] == '>') {
+					loglev_char = p[1];
+					p += 3;
+					printed_len += 3;
+				} else {
+					loglev_char = default_message_loglevel
+						+ '0';
+				}
+				t = printk_clock();
+				nanosec_rem = do_div(t, 1000000000);
+				tlen = sprintf(tbuf,
+						"<%c>[%5lu.%06lu] ",
+						loglev_char,
+						(unsigned long)t,
+						nanosec_rem/1000);
+
+				for (tp = tbuf; tp < tbuf + tlen; tp++)
+					emit_log_char(*tp);
+				printed_len += tlen - 3;
+			} else {
+				if (p[0] != '<' || p[1] < '0' ||
+				   p[1] > '7' || p[2] != '>') {
+					emit_log_char('<');
+					emit_log_char(default_message_loglevel
+						+ '0');
+					emit_log_char('>');
+				}
+				printed_len += 3;
+			}
+			log_level_unknown = 0;
+			if (!*p)
+				break;
+		}
+		emit_log_char(*p);
+		if (*p == '\n')
+			log_level_unknown = 1;
+	}
+
+	if (!cpu_online(smp_processor_id())) {
+		/*
+		 * Some console drivers may assume that per-cpu resources have
+		 * been allocated.  So don't allow them to be called by this
+		 * CPU until it is officially up.  We shouldn't be calling into
+		 * random console drivers on a CPU which doesn't exist yet..
+		 */
+		printk_cpu = UINT_MAX;
+		spin_unlock_irqrestore(&logbuf_lock, flags);
+		goto out;
+	}
+	if (!down_trylock(&console_sem)) {
+		console_locked = 1;
+		/*
+		 * We own the drivers.  We can drop the spinlock and let
+		 * release_console_sem() print the text
+		 */
+		printk_cpu = UINT_MAX;
+		spin_unlock_irqrestore(&logbuf_lock, flags);
+		console_may_schedule = 0;
+		release_console_sem();
+	} else {
+		/*
+		 * Someone else owns the drivers.  We drop the spinlock, which
+		 * allows the semaphore holder to proceed and to call the
+		 * console drivers with the output which we just produced.
+		 */
+		printk_cpu = UINT_MAX;
+		spin_unlock_irqrestore(&logbuf_lock, flags);
+	}
+out:
+	preempt_enable();
+	return printed_len;
+}
+EXPORT_SYMBOL(printk);
+EXPORT_SYMBOL(vprintk);
+
+#else
+
+asmlinkage long sys_syslog(int type, char __user *buf, int len)
+{
+	return 0;
+}
+
+int do_syslog(int type, char __user *buf, int len)
+{
+	return 0;
+}
+
+static void call_console_drivers(unsigned long start, unsigned long end)
+{
+}
+
+#endif
+
+/**
+ * add_preferred_console - add a device to the list of preferred consoles.
+ * @name: device name
+ * @idx: device index
+ * @options: options for this console
+ *
+ * The last preferred console added will be used for kernel messages
+ * and stdin/out/err for init.  Normally this is used by console_setup
+ * above to handle user-supplied console arguments; however it can also
+ * be used by arch-specific code either to override the user or more
+ * commonly to provide a default console (ie from PROM variables) when
+ * the user has not supplied one.
+ */
+int __init add_preferred_console(char *name, int idx, char *options)
+{
+	struct console_cmdline *c;
+	int i;
+
+	/*
+	 *	See if this tty is not yet registered, and
+	 *	if we have a slot free.
+	 */
+	for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
+		if (strcmp(console_cmdline[i].name, name) == 0 &&
+			  console_cmdline[i].index == idx) {
+				selected_console = i;
+				return 0;
+		}
+	if (i == MAX_CMDLINECONSOLES)
+		return -E2BIG;
+	selected_console = i;
+	c = &console_cmdline[i];
+	memcpy(c->name, name, sizeof(c->name));
+	c->name[sizeof(c->name) - 1] = 0;
+	c->options = options;
+	c->index = idx;
+	return 0;
+}
+
+/**
+ * acquire_console_sem - lock the console system for exclusive use.
+ *
+ * Acquires a semaphore which guarantees that the caller has
+ * exclusive access to the console system and the console_drivers list.
+ *
+ * Can sleep, returns nothing.
+ */
+void acquire_console_sem(void)
+{
+	if (in_interrupt())
+		BUG();
+	down(&console_sem);
+	console_locked = 1;
+	console_may_schedule = 1;
+}
+EXPORT_SYMBOL(acquire_console_sem);
+
+int try_acquire_console_sem(void)
+{
+	if (down_trylock(&console_sem))
+		return -1;
+	console_locked = 1;
+	console_may_schedule = 0;
+	return 0;
+}
+EXPORT_SYMBOL(try_acquire_console_sem);
+
+int is_console_locked(void)
+{
+	return console_locked;
+}
+EXPORT_SYMBOL(is_console_locked);
+
+/**
+ * release_console_sem - unlock the console system
+ *
+ * Releases the semaphore which the caller holds on the console system
+ * and the console driver list.
+ *
+ * While the semaphore was held, console output may have been buffered
+ * by printk().  If this is the case, release_console_sem() emits
+ * the output prior to releasing the semaphore.
+ *
+ * If there is output waiting for klogd, we wake it up.
+ *
+ * release_console_sem() may be called from any context.
+ */
+void release_console_sem(void)
+{
+	unsigned long flags;
+	unsigned long _con_start, _log_end;
+	unsigned long wake_klogd = 0;
+
+	for ( ; ; ) {
+		spin_lock_irqsave(&logbuf_lock, flags);
+		wake_klogd |= log_start - log_end;
+		if (con_start == log_end)
+			break;			/* Nothing to print */
+		_con_start = con_start;
+		_log_end = log_end;
+		con_start = log_end;		/* Flush */
+		spin_unlock(&logbuf_lock);
+		call_console_drivers(_con_start, _log_end);
+		local_irq_restore(flags);
+	}
+	console_locked = 0;
+	console_may_schedule = 0;
+	up(&console_sem);
+	spin_unlock_irqrestore(&logbuf_lock, flags);
+	if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait))
+		wake_up_interruptible(&log_wait);
+}
+EXPORT_SYMBOL(release_console_sem);
+
+/**
+ * console_conditional_schedule - yield the CPU if required
+ *
+ * If the console code is currently allowed to sleep, and
+ * if this CPU should yield the CPU to another task, do
+ * so here.
+ *
+ * Must be called within acquire_console_sem().
+ */
+void __sched console_conditional_schedule(void)
+{
+	if (console_may_schedule)
+		cond_resched();
+}
+EXPORT_SYMBOL(console_conditional_schedule);
+
+void console_print(const char *s)
+{
+	printk(KERN_EMERG "%s", s);
+}
+EXPORT_SYMBOL(console_print);
+
+void console_unblank(void)
+{
+	struct console *c;
+
+	/*
+	 * console_unblank can no longer be called in interrupt context unless
+	 * oops_in_progress is set to 1..
+	 */
+	if (oops_in_progress) {
+		if (down_trylock(&console_sem) != 0)
+			return;
+	} else
+		acquire_console_sem();
+
+	console_locked = 1;
+	console_may_schedule = 0;
+	for (c = console_drivers; c != NULL; c = c->next)
+		if ((c->flags & CON_ENABLED) && c->unblank)
+			c->unblank();
+	release_console_sem();
+}
+
+/*
+ * Return the console tty driver structure and its associated index
+ */
+struct tty_driver *console_device(int *index)
+{
+	struct console *c;
+	struct tty_driver *driver = NULL;
+
+	acquire_console_sem();
+	for (c = console_drivers; c != NULL; c = c->next) {
+		if (!c->device)
+			continue;
+		driver = c->device(c, index);
+		if (driver)
+			break;
+	}
+	release_console_sem();
+	return driver;
+}
+
+/*
+ * Prevent further output on the passed console device so that (for example)
+ * serial drivers can disable console output before suspending a port, and can
+ * re-enable output afterwards.
+ */
+void console_stop(struct console *console)
+{
+	acquire_console_sem();
+	console->flags &= ~CON_ENABLED;
+	release_console_sem();
+}
+EXPORT_SYMBOL(console_stop);
+
+void console_start(struct console *console)
+{
+	acquire_console_sem();
+	console->flags |= CON_ENABLED;
+	release_console_sem();
+}
+EXPORT_SYMBOL(console_start);
+
+/*
+ * The console driver calls this routine during kernel initialization
+ * to register the console printing procedure with printk() and to
+ * print any messages that were printed by the kernel before the
+ * console driver was initialized.
+ */
+void register_console(struct console *console)
+{
+	int i;
+	unsigned long flags;
+
+	if (preferred_console < 0)
+		preferred_console = selected_console;
+
+	/*
+	 *	See if we want to use this console driver. If we
+	 *	didn't select a console we take the first one
+	 *	that registers here.
+	 */
+	if (preferred_console < 0) {
+		if (console->index < 0)
+			console->index = 0;
+		if (console->setup == NULL ||
+		    console->setup(console, NULL) == 0) {
+			console->flags |= CON_ENABLED | CON_CONSDEV;
+			preferred_console = 0;
+		}
+	}
+
+	/*
+	 *	See if this console matches one we selected on
+	 *	the command line.
+	 */
+	for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];
+			i++) {
+		if (strcmp(console_cmdline[i].name, console->name) != 0)
+			continue;
+		if (console->index >= 0 &&
+		    console->index != console_cmdline[i].index)
+			continue;
+		if (console->index < 0)
+			console->index = console_cmdline[i].index;
+		if (console->setup &&
+		    console->setup(console, console_cmdline[i].options) != 0)
+			break;
+		console->flags |= CON_ENABLED;
+		console->index = console_cmdline[i].index;
+		if (i == selected_console) {
+			console->flags |= CON_CONSDEV;
+			preferred_console = selected_console;
+		}
+		break;
+	}
+
+	if (!(console->flags & CON_ENABLED))
+		return;
+
+	if (console_drivers && (console_drivers->flags & CON_BOOT)) {
+		unregister_console(console_drivers);
+		console->flags &= ~CON_PRINTBUFFER;
+	}
+
+	/*
+	 *	Put this console in the list - keep the
+	 *	preferred driver at the head of the list.
+	 */
+	acquire_console_sem();
+	if ((console->flags & CON_CONSDEV) || console_drivers == NULL) {
+		console->next = console_drivers;
+		console_drivers = console;
+		if (console->next)
+			console->next->flags &= ~CON_CONSDEV;
+	} else {
+		console->next = console_drivers->next;
+		console_drivers->next = console;
+	}
+	if (console->flags & CON_PRINTBUFFER) {
+		/*
+		 * release_console_sem() will print out the buffered messages
+		 * for us.
+		 */
+		spin_lock_irqsave(&logbuf_lock, flags);
+		con_start = log_start;
+		spin_unlock_irqrestore(&logbuf_lock, flags);
+	}
+	release_console_sem();
+}
+EXPORT_SYMBOL(register_console);
+
+int unregister_console(struct console *console)
+{
+        struct console *a, *b;
+	int res = 1;
+
+	acquire_console_sem();
+	if (console_drivers == console) {
+		console_drivers=console->next;
+		res = 0;
+	} else if (console_drivers) {
+		for (a=console_drivers->next, b=console_drivers ;
+		     a; b=a, a=b->next) {
+			if (a == console) {
+				b->next = a->next;
+				res = 0;
+				break;
+			}
+		}
+	}
+
+	/* If last console is removed, we re-enable picking the first
+	 * one that gets registered. Without that, pmac early boot console
+	 * would prevent fbcon from taking over.
+	 *
+	 * If this isn't the last console and it has CON_CONSDEV set, we
+	 * need to set it on the next preferred console.
+	 */
+	if (console_drivers == NULL)
+		preferred_console = selected_console;
+	else if (console->flags & CON_CONSDEV)
+		console_drivers->flags |= CON_CONSDEV;
+
+	release_console_sem();
+	return res;
+}
+EXPORT_SYMBOL(unregister_console);
+
+/**
+ * tty_write_message - write a message to a certain tty, not just the console.
+ * @tty: the destination tty_struct
+ * @msg: the message to write
+ *
+ * This is used for messages that need to be redirected to a specific tty.
+ * We don't put it into the syslog queue right now maybe in the future if
+ * really needed.
+ */
+void tty_write_message(struct tty_struct *tty, char *msg)
+{
+	if (tty && tty->driver->write)
+		tty->driver->write(tty, msg, strlen(msg));
+	return;
+}
+
+/*
+ * printk rate limiting, lifted from the networking subsystem.
+ *
+ * This enforces a rate limit: not more than one kernel message
+ * every printk_ratelimit_jiffies to make a denial-of-service
+ * attack impossible.
+ */
+int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
+{
+	static DEFINE_SPINLOCK(ratelimit_lock);
+	static unsigned long toks = 10 * 5 * HZ;
+	static unsigned long last_msg;
+	static int missed;
+	unsigned long flags;
+	unsigned long now = jiffies;
+
+	spin_lock_irqsave(&ratelimit_lock, flags);
+	toks += now - last_msg;
+	last_msg = now;
+	if (toks > (ratelimit_burst * ratelimit_jiffies))
+		toks = ratelimit_burst * ratelimit_jiffies;
+	if (toks >= ratelimit_jiffies) {
+		int lost = missed;
+
+		missed = 0;
+		toks -= ratelimit_jiffies;
+		spin_unlock_irqrestore(&ratelimit_lock, flags);
+		if (lost)
+			printk(KERN_WARNING "printk: %d messages suppressed.\n", lost);
+		return 1;
+	}
+	missed++;
+	spin_unlock_irqrestore(&ratelimit_lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL(__printk_ratelimit);
+
+/* minimum time in jiffies between messages */
+int printk_ratelimit_jiffies = 5 * HZ;
+
+/* number of messages we send before ratelimiting */
+int printk_ratelimit_burst = 10;
+
+int printk_ratelimit(void)
+{
+	return __printk_ratelimit(printk_ratelimit_jiffies,
+				printk_ratelimit_burst);
+}
+EXPORT_SYMBOL(printk_ratelimit);
--- /dev/null
+++ b/tools/xcutils/helper/string.c
@@ -0,0 +1,601 @@
+/*
+ *  linux/lib/string.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * stupid library routines.. The optimized versions should generally be found
+ * as inline code in <asm-xx/string.h>
+ *
+ * These are buggy as well..
+ *
+ * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
+ * -  Added strsep() which will replace strtok() soon (because strsep() is
+ *    reentrant and should be faster). Use only strsep() in new code, please.
+ *
+ * * Sat Feb 09 2002, Jason Thomas <jason@topic.com.au>,
+ *                    Matthew Hawkins <matt@mh.dropbear.id.au>
+ * -  Kissed strtok() goodbye
+ */
+
+#include "helper.h"
+
+#ifndef __HAVE_ARCH_STRNICMP
+/**
+ * strnicmp - Case insensitive, length-limited string comparison
+ * @s1: One string
+ * @s2: The other string
+ * @len: the maximum number of characters to compare
+ */
+int strnicmp(const char *s1, const char *s2, size_t len)
+{
+	/* Yes, Virginia, it had better be unsigned */
+	unsigned char c1, c2;
+
+	c1 = c2 = 0;
+	if (len) {
+		do {
+			c1 = *s1;
+			c2 = *s2;
+			s1++;
+			s2++;
+			if (!c1)
+				break;
+			if (!c2)
+				break;
+			if (c1 == c2)
+				continue;
+			c1 = tolower(c1);
+			c2 = tolower(c2);
+			if (c1 != c2)
+				break;
+		} while (--len);
+	}
+	return (int)c1 - (int)c2;
+}
+EXPORT_SYMBOL(strnicmp);
+#endif
+
+#ifndef __HAVE_ARCH_STRCPY
+/**
+ * strcpy - Copy a %NUL terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ */
+#undef strcpy
+char *strcpy(char *dest, const char *src)
+{
+	char *tmp = dest;
+
+	while ((*dest++ = *src++) != '\0')
+		/* nothing */;
+	return tmp;
+}
+EXPORT_SYMBOL(strcpy);
+#endif
+
+#ifndef __HAVE_ARCH_STRNCPY
+/**
+ * strncpy - Copy a length-limited, %NUL-terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: The maximum number of bytes to copy
+ *
+ * The result is not %NUL-terminated if the source exceeds
+ * @count bytes.
+ *
+ * In the case where the length of @src is less than  that  of
+ * count, the remainder of @dest will be padded with %NUL.
+ *
+ */
+char *strncpy(char *dest, const char *src, size_t count)
+{
+	char *tmp = dest;
+
+	while (count) {
+		if ((*tmp = *src) != 0)
+			src++;
+		tmp++;
+		count--;
+	}
+	return dest;
+}
+EXPORT_SYMBOL(strncpy);
+#endif
+
+#ifndef __HAVE_ARCH_STRLCPY
+/**
+ * strlcpy - Copy a %NUL terminated string into a sized buffer
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @size: size of destination buffer
+ *
+ * Compatible with *BSD: the result is always a valid
+ * NUL-terminated string that fits in the buffer (unless,
+ * of course, the buffer size is zero). It does not pad
+ * out the result like strncpy() does.
+ */
+size_t strlcpy(char *dest, const char *src, size_t size)
+{
+	size_t ret = strlen(src);
+
+	if (size) {
+		size_t len = (ret >= size) ? size - 1 : ret;
+		memcpy(dest, src, len);
+		dest[len] = '\0';
+	}
+	return ret;
+}
+EXPORT_SYMBOL(strlcpy);
+#endif
+
+#ifndef __HAVE_ARCH_STRCAT
+/**
+ * strcat - Append one %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ */
+#undef strcat
+char *strcat(char *dest, const char *src)
+{
+	char *tmp = dest;
+
+	while (*dest)
+		dest++;
+	while ((*dest++ = *src++) != '\0')
+		;
+	return tmp;
+}
+EXPORT_SYMBOL(strcat);
+#endif
+
+#ifndef __HAVE_ARCH_STRNCAT
+/**
+ * strncat - Append a length-limited, %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ * @count: The maximum numbers of bytes to copy
+ *
+ * Note that in contrast to strncpy, strncat ensures the result is
+ * terminated.
+ */
+char *strncat(char *dest, const char *src, size_t count)
+{
+	char *tmp = dest;
+
+	if (count) {
+		while (*dest)
+			dest++;
+		while ((*dest++ = *src++) != 0) {
+			if (--count == 0) {
+				*dest = '\0';
+				break;
+			}
+		}
+	}
+	return tmp;
+}
+EXPORT_SYMBOL(strncat);
+#endif
+
+#ifndef __HAVE_ARCH_STRLCAT
+/**
+ * strlcat - Append a length-limited, %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ * @count: The size of the destination buffer.
+ */
+size_t strlcat(char *dest, const char *src, size_t count)
+{
+	size_t dsize = strlen(dest);
+	size_t len = strlen(src);
+	size_t res = dsize + len;
+
+	/* This would be a bug */
+	BUG_ON(dsize >= count);
+
+	dest += dsize;
+	count -= dsize;
+	if (len >= count)
+		len = count-1;
+	memcpy(dest, src, len);
+	dest[len] = 0;
+	return res;
+}
+EXPORT_SYMBOL(strlcat);
+#endif
+
+#ifndef __HAVE_ARCH_STRCMP
+/**
+ * strcmp - Compare two strings
+ * @cs: One string
+ * @ct: Another string
+ */
+#undef strcmp
+int strcmp(const char *cs, const char *ct)
+{
+	signed char __res;
+
+	while (1) {
+		if ((__res = *cs - *ct++) != 0 || !*cs++)
+			break;
+	}
+	return __res;
+}
+EXPORT_SYMBOL(strcmp);
+#endif
+
+#ifndef __HAVE_ARCH_STRNCMP
+/**
+ * strncmp - Compare two length-limited strings
+ * @cs: One string
+ * @ct: Another string
+ * @count: The maximum number of bytes to compare
+ */
+int strncmp(const char *cs, const char *ct, size_t count)
+{
+	signed char __res = 0;
+
+	while (count) {
+		if ((__res = *cs - *ct++) != 0 || !*cs++)
+			break;
+		count--;
+	}
+	return __res;
+}
+EXPORT_SYMBOL(strncmp);
+#endif
+
+#ifndef __HAVE_ARCH_STRCHR
+/**
+ * strchr - Find the first occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char *strchr(const char *s, int c)
+{
+	for (; *s != (char)c; ++s)
+		if (*s == '\0')
+			return NULL;
+	return (char *)s;
+}
+EXPORT_SYMBOL(strchr);
+#endif
+
+#ifndef __HAVE_ARCH_STRRCHR
+/**
+ * strrchr - Find the last occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char *strrchr(const char *s, int c)
+{
+       const char *p = s + strlen(s);
+       do {
+           if (*p == (char)c)
+               return (char *)p;
+       } while (--p >= s);
+       return NULL;
+}
+EXPORT_SYMBOL(strrchr);
+#endif
+
+#ifndef __HAVE_ARCH_STRNCHR
+/**
+ * strnchr - Find a character in a length limited string
+ * @s: The string to be searched
+ * @count: The number of characters to be searched
+ * @c: The character to search for
+ */
+char *strnchr(const char *s, size_t count, int c)
+{
+	for (; count-- && *s != '\0'; ++s)
+		if (*s == (char)c)
+			return (char *)s;
+	return NULL;
+}
+EXPORT_SYMBOL(strnchr);
+#endif
+
+#ifndef __HAVE_ARCH_STRLEN
+/**
+ * strlen - Find the length of a string
+ * @s: The string to be sized
+ */
+size_t strlen(const char *s)
+{
+	const char *sc;
+
+	for (sc = s; *sc != '\0'; ++sc)
+		/* nothing */;
+	return sc - s;
+}
+EXPORT_SYMBOL(strlen);
+#endif
+
+#ifndef __HAVE_ARCH_STRNLEN
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @count: The maximum number of bytes to search
+ */
+size_t strnlen(const char *s, size_t count)
+{
+	const char *sc;
+
+	for (sc = s; count-- && *sc != '\0'; ++sc)
+		/* nothing */;
+	return sc - s;
+}
+EXPORT_SYMBOL(strnlen);
+#endif
+
+#ifndef __HAVE_ARCH_STRSPN
+/**
+ * strspn - Calculate the length of the initial substring of @s which only
+ * 	contain letters in @accept
+ * @s: The string to be searched
+ * @accept: The string to search for
+ */
+size_t strspn(const char *s, const char *accept)
+{
+	const char *p;
+	const char *a;
+	size_t count = 0;
+
+	for (p = s; *p != '\0'; ++p) {
+		for (a = accept; *a != '\0'; ++a) {
+			if (*p == *a)
+				break;
+		}
+		if (*a == '\0')
+			return count;
+		++count;
+	}
+	return count;
+}
+
+EXPORT_SYMBOL(strspn);
+#endif
+
+/**
+ * strcspn - Calculate the length of the initial substring of @s which does
+ * 	not contain letters in @reject
+ * @s: The string to be searched
+ * @reject: The string to avoid
+ */
+size_t strcspn(const char *s, const char *reject)
+{
+	const char *p;
+	const char *r;
+	size_t count = 0;
+
+	for (p = s; *p != '\0'; ++p) {
+		for (r = reject; *r != '\0'; ++r) {
+			if (*p == *r)
+				return count;
+		}
+		++count;
+	}
+	return count;
+}
+EXPORT_SYMBOL(strcspn);
+
+#ifndef __HAVE_ARCH_STRPBRK
+/**
+ * strpbrk - Find the first occurrence of a set of characters
+ * @cs: The string to be searched
+ * @ct: The characters to search for
+ */
+char *strpbrk(const char *cs, const char *ct)
+{
+	const char *sc1, *sc2;
+
+	for (sc1 = cs; *sc1 != '\0'; ++sc1) {
+		for (sc2 = ct; *sc2 != '\0'; ++sc2) {
+			if (*sc1 == *sc2)
+				return (char *)sc1;
+		}
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(strpbrk);
+#endif
+
+#ifndef __HAVE_ARCH_STRSEP
+/**
+ * strsep - Split a string into tokens
+ * @s: The string to be searched
+ * @ct: The characters to search for
+ *
+ * strsep() updates @s to point after the token, ready for the next call.
+ *
+ * It returns empty tokens, too, behaving exactly like the libc function
+ * of that name. In fact, it was stolen from glibc2 and de-fancy-fied.
+ * Same semantics, slimmer shape. ;)
+ */
+char *strsep(char **s, const char *ct)
+{
+	char *sbegin = *s;
+	char *end;
+
+	if (sbegin == NULL)
+		return NULL;
+
+	end = strpbrk(sbegin, ct);
+	if (end)
+		*end++ = '\0';
+	*s = end;
+	return sbegin;
+}
+EXPORT_SYMBOL(strsep);
+#endif
+
+#ifndef __HAVE_ARCH_MEMSET
+/**
+ * memset - Fill a region of memory with the given value
+ * @s: Pointer to the start of the area.
+ * @c: The byte to fill the area with
+ * @count: The size of the area.
+ *
+ * Do not use memset() to access IO space, use memset_io() instead.
+ */
+void *memset(void *s, int c, size_t count)
+{
+	char *xs = s;
+
+	while (count--)
+		*xs++ = c;
+	return s;
+}
+EXPORT_SYMBOL(memset);
+#endif
+
+#ifndef __HAVE_ARCH_MEMCPY
+/**
+ * memcpy - Copy one area of memory to another
+ * @dest: Where to copy to
+ * @src: Where to copy from
+ * @count: The size of the area.
+ *
+ * You should not use this function to access IO space, use memcpy_toio()
+ * or memcpy_fromio() instead.
+ */
+void *memcpy(void *dest, const void *src, size_t count)
+{
+	char *tmp = dest;
+	const char *s = src;
+
+	while (count--)
+		*tmp++ = *s++;
+	return dest;
+}
+EXPORT_SYMBOL(memcpy);
+#endif
+
+#ifndef __HAVE_ARCH_MEMMOVE
+/**
+ * memmove - Copy one area of memory to another
+ * @dest: Where to copy to
+ * @src: Where to copy from
+ * @count: The size of the area.
+ *
+ * Unlike memcpy(), memmove() copes with overlapping areas.
+ */
+void *memmove(void *dest, const void *src, size_t count)
+{
+	char *tmp;
+	const char *s;
+
+	if (dest <= src) {
+		tmp = dest;
+		s = src;
+		while (count--)
+			*tmp++ = *s++;
+	} else {
+		tmp = dest;
+		tmp += count;
+		s = src;
+		s += count;
+		while (count--)
+			*--tmp = *--s;
+	}
+	return dest;
+}
+EXPORT_SYMBOL(memmove);
+#endif
+
+#ifndef __HAVE_ARCH_MEMCMP
+/**
+ * memcmp - Compare two areas of memory
+ * @cs: One area of memory
+ * @ct: Another area of memory
+ * @count: The size of the area.
+ */
+#undef memcmp
+int memcmp(const void *cs, const void *ct, size_t count)
+{
+	const unsigned char *su1, *su2;
+	int res = 0;
+
+	for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+		if ((res = *su1 - *su2) != 0)
+			break;
+	return res;
+}
+EXPORT_SYMBOL(memcmp);
+#endif
+
+#ifndef __HAVE_ARCH_MEMSCAN
+/**
+ * memscan - Find a character in an area of memory.
+ * @addr: The memory area
+ * @c: The byte to search for
+ * @size: The size of the area.
+ *
+ * returns the address of the first occurrence of @c, or 1 byte past
+ * the area if @c is not found
+ */
+void *memscan(void *addr, int c, size_t size)
+{
+	unsigned char *p = addr;
+
+	while (size) {
+		if (*p == c)
+			return (void *)p;
+		p++;
+		size--;
+	}
+  	return (void *)p;
+}
+EXPORT_SYMBOL(memscan);
+#endif
+
+#ifndef __HAVE_ARCH_STRSTR
+/**
+ * strstr - Find the first substring in a %NUL terminated string
+ * @s1: The string to be searched
+ * @s2: The string to search for
+ */
+char *strstr(const char *s1, const char *s2)
+{
+	int l1, l2;
+
+	l2 = strlen(s2);
+	if (!l2)
+		return (char *)s1;
+	l1 = strlen(s1);
+	while (l1 >= l2) {
+		l1--;
+		if (!memcmp(s1, s2, l2))
+			return (char *)s1;
+		s1++;
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(strstr);
+#endif
+
+#ifndef __HAVE_ARCH_MEMCHR
+/**
+ * memchr - Find a character in an area of memory.
+ * @s: The memory area
+ * @c: The byte to search for
+ * @n: The size of the area.
+ *
+ * returns the address of the first occurrence of @c, or %NULL
+ * if @c is not found
+ */
+void *memchr(const void *s, int c, size_t n)
+{
+	const unsigned char *p = s;
+	while (n-- != 0) {
+        	if ((unsigned char)c == *p++) {
+			return (void *)(p - 1);
+		}
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(memchr);
+#endif
--- /dev/null
+++ b/tools/xcutils/helper/vsprintf.c
@@ -0,0 +1,842 @@
+/*
+ *  linux/lib/vsprintf.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
+/*
+ * Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+
+/*
+ * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
+ * - changed to provide snprintf and vsnprintf functions
+ * So Feb  1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
+ * - scnprintf and vscnprintf
+ */
+
+#include "helper.h"
+
+/**
+ * simple_strtoul - convert a string to an unsigned long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+{
+	unsigned long result = 0,value;
+
+	if (!base) {
+		base = 10;
+		if (*cp == '0') {
+			base = 8;
+			cp++;
+			if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
+				cp++;
+				base = 16;
+			}
+		}
+	} else if (base == 16) {
+		if (cp[0] == '0' && toupper(cp[1]) == 'X')
+			cp += 2;
+	}
+	while (isxdigit(*cp) &&
+	       (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
+		result = result*base + value;
+		cp++;
+	}
+	if (endp)
+		*endp = (char *)cp;
+	return result;
+}
+
+EXPORT_SYMBOL(simple_strtoul);
+
+/**
+ * simple_strtol - convert a string to a signed long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long simple_strtol(const char *cp,char **endp,unsigned int base)
+{
+	if(*cp=='-')
+		return -simple_strtoul(cp+1,endp,base);
+	return simple_strtoul(cp,endp,base);
+}
+
+EXPORT_SYMBOL(simple_strtol);
+
+/**
+ * simple_strtoull - convert a string to an unsigned long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
+{
+	unsigned long long result = 0,value;
+
+	if (!base) {
+		base = 10;
+		if (*cp == '0') {
+			base = 8;
+			cp++;
+			if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
+				cp++;
+				base = 16;
+			}
+		}
+	} else if (base == 16) {
+		if (cp[0] == '0' && toupper(cp[1]) == 'X')
+			cp += 2;
+	}
+	while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+	    ? toupper(*cp) : *cp)-'A'+10) < base) {
+		result = result*base + value;
+		cp++;
+	}
+	if (endp)
+		*endp = (char *)cp;
+	return result;
+}
+
+EXPORT_SYMBOL(simple_strtoull);
+
+/**
+ * simple_strtoll - convert a string to a signed long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long long simple_strtoll(const char *cp,char **endp,unsigned int base)
+{
+	if(*cp=='-')
+		return -simple_strtoull(cp+1,endp,base);
+	return simple_strtoull(cp,endp,base);
+}
+
+static int skip_atoi(const char **s)
+{
+	int i=0;
+
+	while (isdigit(**s))
+		i = i*10 + *((*s)++) - '0';
+	return i;
+}
+
+#define ZEROPAD	1		/* pad with zero */
+#define SIGN	2		/* unsigned/signed long */
+#define PLUS	4		/* show plus */
+#define SPACE	8		/* space if plus */
+#define LEFT	16		/* left justified */
+#define SPECIAL	32		/* 0x */
+#define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
+
+static char * number(char * buf, char * end, unsigned long long num, int base, int size, int precision, int type)
+{
+	char c,sign,tmp[66];
+	const char *digits;
+	static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+	static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	int i;
+
+	digits = (type & LARGE) ? large_digits : small_digits;
+	if (type & LEFT)
+		type &= ~ZEROPAD;
+	if (base < 2 || base > 36)
+		return NULL;
+	c = (type & ZEROPAD) ? '0' : ' ';
+	sign = 0;
+	if (type & SIGN) {
+		if ((signed long long) num < 0) {
+			sign = '-';
+			num = - (signed long long) num;
+			size--;
+		} else if (type & PLUS) {
+			sign = '+';
+			size--;
+		} else if (type & SPACE) {
+			sign = ' ';
+			size--;
+		}
+	}
+	if (type & SPECIAL) {
+		if (base == 16)
+			size -= 2;
+		else if (base == 8)
+			size--;
+	}
+	i = 0;
+	if (num == 0)
+		tmp[i++]='0';
+	else while (num != 0)
+		tmp[i++] = digits[do_div(num,base)];
+	if (i > precision)
+		precision = i;
+	size -= precision;
+	if (!(type&(ZEROPAD+LEFT))) {
+		while(size-->0) {
+			if (buf <= end)
+				*buf = ' ';
+			++buf;
+		}
+	}
+	if (sign) {
+		if (buf <= end)
+			*buf = sign;
+		++buf;
+	}
+	if (type & SPECIAL) {
+		if (base==8) {
+			if (buf <= end)
+				*buf = '0';
+			++buf;
+		} else if (base==16) {
+			if (buf <= end)
+				*buf = '0';
+			++buf;
+			if (buf <= end)
+				*buf = digits[33];
+			++buf;
+		}
+	}
+	if (!(type & LEFT)) {
+		while (size-- > 0) {
+			if (buf <= end)
+				*buf = c;
+			++buf;
+		}
+	}
+	while (i < precision--) {
+		if (buf <= end)
+			*buf = '0';
+		++buf;
+	}
+	while (i-- > 0) {
+		if (buf <= end)
+			*buf = tmp[i];
+		++buf;
+	}
+	while (size-- > 0) {
+		if (buf <= end)
+			*buf = ' ';
+		++buf;
+	}
+	return buf;
+}
+
+/**
+ * vsnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The return value is the number of characters which would
+ * be generated for the given input, excluding the trailing
+ * '\0', as per ISO C99. If you want to have the exact
+ * number of characters written into @buf as return value
+ * (not including the trailing '\0'), use vscnprintf. If the
+ * return is greater than or equal to @size, the resulting
+ * string is truncated.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want snprintf instead.
+ */
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+	int len;
+	unsigned long long num;
+	int i, base;
+	char *str, *end, c;
+	const char *s;
+
+	int flags;		/* flags to number() */
+
+	int field_width;	/* width of output field */
+	int precision;		/* min. # of digits for integers; max
+				   number of chars for from string */
+	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
+				/* 'z' support added 23/7/1999 S.H.    */
+				/* 'z' changed to 'Z' --davidm 1/25/99 */
+				/* 't' added for ptrdiff_t */
+
+	/* Reject out-of-range values early */
+	if (unlikely((int) size < 0)) {
+		/* There can be only one.. */
+		static int warn = 1;
+		WARN_ON(warn);
+		warn = 0;
+		return 0;
+	}
+
+	str = buf;
+	end = buf + size - 1;
+
+	if (end < buf - 1) {
+		end = ((void *) -1);
+		size = end - buf + 1;
+	}
+
+	for (; *fmt ; ++fmt) {
+		if (*fmt != '%') {
+			if (str <= end)
+				*str = *fmt;
+			++str;
+			continue;
+		}
+
+		/* process flags */
+		flags = 0;
+		repeat:
+			++fmt;		/* this also skips first '%' */
+			switch (*fmt) {
+				case '-': flags |= LEFT; goto repeat;
+				case '+': flags |= PLUS; goto repeat;
+				case ' ': flags |= SPACE; goto repeat;
+				case '#': flags |= SPECIAL; goto repeat;
+				case '0': flags |= ZEROPAD; goto repeat;
+			}
+
+		/* get field width */
+		field_width = -1;
+		if (isdigit(*fmt))
+			field_width = skip_atoi(&fmt);
+		else if (*fmt == '*') {
+			++fmt;
+			/* it's the next argument */
+			field_width = va_arg(args, int);
+			if (field_width < 0) {
+				field_width = -field_width;
+				flags |= LEFT;
+			}
+		}
+
+		/* get the precision */
+		precision = -1;
+		if (*fmt == '.') {
+			++fmt;
+			if (isdigit(*fmt))
+				precision = skip_atoi(&fmt);
+			else if (*fmt == '*') {
+				++fmt;
+				/* it's the next argument */
+				precision = va_arg(args, int);
+			}
+			if (precision < 0)
+				precision = 0;
+		}
+
+		/* get the conversion qualifier */
+		qualifier = -1;
+		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+		    *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
+			qualifier = *fmt;
+			++fmt;
+			if (qualifier == 'l' && *fmt == 'l') {
+				qualifier = 'L';
+				++fmt;
+			}
+		}
+
+		/* default base */
+		base = 10;
+
+		switch (*fmt) {
+			case 'c':
+				if (!(flags & LEFT)) {
+					while (--field_width > 0) {
+						if (str <= end)
+							*str = ' ';
+						++str;
+					}
+				}
+				c = (unsigned char) va_arg(args, int);
+				if (str <= end)
+					*str = c;
+				++str;
+				while (--field_width > 0) {
+					if (str <= end)
+						*str = ' ';
+					++str;
+				}
+				continue;
+
+			case 's':
+				s = va_arg(args, char *);
+				if ((unsigned long)s < PAGE_SIZE)
+					s = "<NULL>";
+
+				len = strnlen(s, precision);
+
+				if (!(flags & LEFT)) {
+					while (len < field_width--) {
+						if (str <= end)
+							*str = ' ';
+						++str;
+					}
+				}
+				for (i = 0; i < len; ++i) {
+					if (str <= end)
+						*str = *s;
+					++str; ++s;
+				}
+				while (len < field_width--) {
+					if (str <= end)
+						*str = ' ';
+					++str;
+				}
+				continue;
+
+			case 'p':
+				if (field_width == -1) {
+					field_width = 2*sizeof(void *);
+					flags |= ZEROPAD;
+				}
+				str = number(str, end,
+						(unsigned long) va_arg(args, void *),
+						16, field_width, precision, flags);
+				continue;
+
+
+			case 'n':
+				/* FIXME:
+				* What does C99 say about the overflow case here? */
+				if (qualifier == 'l') {
+					long * ip = va_arg(args, long *);
+					*ip = (str - buf);
+				} else if (qualifier == 'Z' || qualifier == 'z') {
+					size_t * ip = va_arg(args, size_t *);
+					*ip = (str - buf);
+				} else {
+					int * ip = va_arg(args, int *);
+					*ip = (str - buf);
+				}
+				continue;
+
+			case '%':
+				if (str <= end)
+					*str = '%';
+				++str;
+				continue;
+
+				/* integer number formats - set up the flags and "break" */
+			case 'o':
+				base = 8;
+				break;
+
+			case 'X':
+				flags |= LARGE;
+			case 'x':
+				base = 16;
+				break;
+
+			case 'd':
+			case 'i':
+				flags |= SIGN;
+			case 'u':
+				break;
+
+			default:
+				if (str <= end)
+					*str = '%';
+				++str;
+				if (*fmt) {
+					if (str <= end)
+						*str = *fmt;
+					++str;
+				} else {
+					--fmt;
+				}
+				continue;
+		}
+		if (qualifier == 'L')
+			num = va_arg(args, long long);
+		else if (qualifier == 'l') {
+			num = va_arg(args, unsigned long);
+			if (flags & SIGN)
+				num = (signed long) num;
+		} else if (qualifier == 'Z' || qualifier == 'z') {
+			num = va_arg(args, size_t);
+		} else if (qualifier == 't') {
+			num = va_arg(args, ptrdiff_t);
+		} else if (qualifier == 'h') {
+			num = (unsigned short) va_arg(args, int);
+			if (flags & SIGN)
+				num = (signed short) num;
+		} else {
+			num = va_arg(args, unsigned int);
+			if (flags & SIGN)
+				num = (signed int) num;
+		}
+		str = number(str, end, num, base,
+				field_width, precision, flags);
+	}
+	if (str <= end)
+		*str = '\0';
+	else if (size > 0)
+		/* don't write out a null byte if the buf size is zero */
+		*end = '\0';
+	/* the trailing null byte doesn't count towards the total
+	* ++str;
+	*/
+	return str-buf;
+}
+
+EXPORT_SYMBOL(vsnprintf);
+
+/**
+ * vscnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The return value is the number of characters which have been written into
+ * the @buf not including the trailing '\0'. If @size is <= 0 the function
+ * returns 0.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want scnprintf instead.
+ */
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+	int i;
+
+	i=vsnprintf(buf,size,fmt,args);
+	return (i >= size) ? (size - 1) : i;
+}
+
+EXPORT_SYMBOL(vscnprintf);
+
+/**
+ * snprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The return value is the number of characters which would be
+ * generated for the given input, excluding the trailing null,
+ * as per ISO C99.  If the return is greater than or equal to
+ * @size, the resulting string is truncated.
+ */
+int snprintf(char * buf, size_t size, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+	i=vsnprintf(buf,size,fmt,args);
+	va_end(args);
+	return i;
+}
+
+EXPORT_SYMBOL(snprintf);
+
+/**
+ * scnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The return value is the number of characters written into @buf not including
+ * the trailing '\0'. If @size is <= 0 the function returns 0. If the return is
+ * greater than or equal to @size, the resulting string is truncated.
+ */
+
+int scnprintf(char * buf, size_t size, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+	i = vsnprintf(buf, size, fmt, args);
+	va_end(args);
+	return (i >= size) ? (size - 1) : i;
+}
+EXPORT_SYMBOL(scnprintf);
+
+/**
+ * vsprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The function returns the number of characters written
+ * into @buf. Use vsnprintf or vscnprintf in order to avoid
+ * buffer overflows.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want sprintf instead.
+ */
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+	return vsnprintf(buf, INT_MAX, fmt, args);
+}
+
+EXPORT_SYMBOL(vsprintf);
+
+/**
+ * sprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The function returns the number of characters written
+ * into @buf. Use snprintf or scnprintf in order to avoid
+ * buffer overflows.
+ */
+int sprintf(char * buf, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+	i=vsnprintf(buf, INT_MAX, fmt, args);
+	va_end(args);
+	return i;
+}
+
+EXPORT_SYMBOL(sprintf);
+
+/**
+ * vsscanf - Unformat a buffer into a list of arguments
+ * @buf:	input buffer
+ * @fmt:	format of buffer
+ * @args:	arguments
+ */
+int vsscanf(const char * buf, const char * fmt, va_list args)
+{
+	const char *str = buf;
+	char *next;
+	char digit;
+	int num = 0;
+	int qualifier;
+	int base;
+	int field_width;
+	int is_sign = 0;
+
+	while(*fmt && *str) {
+		/* skip any white space in format */
+		/* white space in format matchs any amount of
+		 * white space, including none, in the input.
+		 */
+		if (isspace(*fmt)) {
+			while (isspace(*fmt))
+				++fmt;
+			while (isspace(*str))
+				++str;
+		}
+
+		/* anything that is not a conversion must match exactly */
+		if (*fmt != '%' && *fmt) {
+			if (*fmt++ != *str++)
+				break;
+			continue;
+		}
+
+		if (!*fmt)
+			break;
+		++fmt;
+
+		/* skip this conversion.
+		 * advance both strings to next white space
+		 */
+		if (*fmt == '*') {
+			while (!isspace(*fmt) && *fmt)
+				fmt++;
+			while (!isspace(*str) && *str)
+				str++;
+			continue;
+		}
+
+		/* get field width */
+		field_width = -1;
+		if (isdigit(*fmt))
+			field_width = skip_atoi(&fmt);
+
+		/* get conversion qualifier */
+		qualifier = -1;
+		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+		    *fmt == 'Z' || *fmt == 'z') {
+			qualifier = *fmt++;
+			if (unlikely(qualifier == *fmt)) {
+				if (qualifier == 'h') {
+					qualifier = 'H';
+					fmt++;
+				} else if (qualifier == 'l') {
+					qualifier = 'L';
+					fmt++;
+				}
+			}
+		}
+		base = 10;
+		is_sign = 0;
+
+		if (!*fmt || !*str)
+			break;
+
+		switch(*fmt++) {
+		case 'c':
+		{
+			char *s = (char *) va_arg(args,char*);
+			if (field_width == -1)
+				field_width = 1;
+			do {
+				*s++ = *str++;
+			} while (--field_width > 0 && *str);
+			num++;
+		}
+		continue;
+		case 's':
+		{
+			char *s = (char *) va_arg(args, char *);
+			if(field_width == -1)
+				field_width = INT_MAX;
+			/* first, skip leading white space in buffer */
+			while (isspace(*str))
+				str++;
+
+			/* now copy until next white space */
+			while (*str && !isspace(*str) && field_width--) {
+				*s++ = *str++;
+			}
+			*s = '\0';
+			num++;
+		}
+		continue;
+		case 'n':
+			/* return number of characters read so far */
+		{
+			int *i = (int *)va_arg(args,int*);
+			*i = str - buf;
+		}
+		continue;
+		case 'o':
+			base = 8;
+			break;
+		case 'x':
+		case 'X':
+			base = 16;
+			break;
+		case 'i':
+                        base = 0;
+		case 'd':
+			is_sign = 1;
+		case 'u':
+			break;
+		case '%':
+			/* looking for '%' in str */
+			if (*str++ != '%')
+				return num;
+			continue;
+		default:
+			/* invalid format; stop here */
+			return num;
+		}
+
+		/* have some sort of integer conversion.
+		 * first, skip white space in buffer.
+		 */
+		while (isspace(*str))
+			str++;
+
+		digit = *str;
+		if (is_sign && digit == '-')
+			digit = *(str + 1);
+
+		if (!digit
+                    || (base == 16 && !isxdigit(digit))
+                    || (base == 10 && !isdigit(digit))
+                    || (base == 8 && (!isdigit(digit) || digit > '7'))
+                    || (base == 0 && !isdigit(digit)))
+				break;
+
+		switch(qualifier) {
+		case 'H':	/* that's 'hh' in format */
+			if (is_sign) {
+				signed char *s = (signed char *) va_arg(args,signed char *);
+				*s = (signed char) simple_strtol(str,&next,base);
+			} else {
+				unsigned char *s = (unsigned char *) va_arg(args, unsigned char *);
+				*s = (unsigned char) simple_strtoul(str, &next, base);
+			}
+			break;
+		case 'h':
+			if (is_sign) {
+				short *s = (short *) va_arg(args,short *);
+				*s = (short) simple_strtol(str,&next,base);
+			} else {
+				unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
+				*s = (unsigned short) simple_strtoul(str, &next, base);
+			}
+			break;
+		case 'l':
+			if (is_sign) {
+				long *l = (long *) va_arg(args,long *);
+				*l = simple_strtol(str,&next,base);
+			} else {
+				unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
+				*l = simple_strtoul(str,&next,base);
+			}
+			break;
+		case 'L':
+			if (is_sign) {
+				long long *l = (long long*) va_arg(args,long long *);
+				*l = simple_strtoll(str,&next,base);
+			} else {
+				unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
+				*l = simple_strtoull(str,&next,base);
+			}
+			break;
+		case 'Z':
+		case 'z':
+		{
+			size_t *s = (size_t*) va_arg(args,size_t*);
+			*s = (size_t) simple_strtoul(str,&next,base);
+		}
+		break;
+		default:
+			if (is_sign) {
+				int *i = (int *) va_arg(args, int*);
+				*i = (int) simple_strtol(str,&next,base);
+			} else {
+				unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
+				*i = (unsigned int) simple_strtoul(str,&next,base);
+			}
+			break;
+		}
+		num++;
+
+		if (!next)
+			break;
+		str = next;
+	}
+	return num;
+}
+
+EXPORT_SYMBOL(vsscanf);
+
+/**
+ * sscanf - Unformat a buffer into a list of arguments
+ * @buf:	input buffer
+ * @fmt:	formatting of buffer
+ * @...:	resulting arguments
+ */
+int sscanf(const char * buf, const char * fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args,fmt);
+	i = vsscanf(buf,fmt,args);
+	va_end(args);
+	return i;
+}
+
+EXPORT_SYMBOL(sscanf);
--- /dev/null
+++ b/tools/xcutils/helper/x86_32/div64.h
@@ -0,0 +1,48 @@
+#ifndef __I386_DIV64
+#define __I386_DIV64
+
+/*
+ * do_div() is NOT a C function. It wants to return
+ * two values (the quotient and the remainder), but
+ * since that doesn't work very well in C, what it
+ * does is:
+ *
+ * - modifies the 64-bit dividend _in_place_
+ * - returns the 32-bit remainder
+ *
+ * This ends up being the most efficient "calling
+ * convention" on x86.
+ */
+#define do_div(n,base) ({ \
+	unsigned long __upper, __low, __high, __mod, __base; \
+	__base = (base); \
+	asm("":"=a" (__low), "=d" (__high):"A" (n)); \
+	__upper = __high; \
+	if (__high) { \
+		__upper = __high % (__base); \
+		__high = __high / (__base); \
+	} \
+	asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (__base), "0" (__low), "1" (__upper)); \
+	asm("":"=A" (n):"a" (__low),"d" (__high)); \
+	__mod; \
+})
+
+/*
+ * (long)X = ((long long)divs) / (long)div
+ * (long)rem = ((long long)divs) % (long)div
+ *
+ * Warning, this will do an exception if X overflows.
+ */
+#define div_long_long_rem(a,b,c) div_ll_X_l_rem(a,b,c)
+
+static inline long
+div_ll_X_l_rem(long long divs, long div, long *rem)
+{
+	long dum2;
+      __asm__("divl %2":"=a"(dum2), "=d"(*rem)
+      :	"rm"(div), "A"(divs));
+
+	return dum2;
+
+}
+#endif
--- /dev/null
+++ b/tools/xcutils/helper/x86_32/entry.S
@@ -0,0 +1,49 @@
+#include "offsets.h"
+
+/* --- stack -------------------------------------------------------- */
+
+	.data
+stack_bottom:
+	.fill	4096,1,0
+stack_top:
+
+/* --- text --------------------------------------------------------- */
+
+	.text
+	.globl	_start,_start_kernel,BUG,hypercall_page
+
+_start:
+	movl	%esi, old_info
+	lea	stack_top,%esp
+	jmp	start_helper
+
+_start_kernel:
+	movl	vcpu+vcpu_ebx,%ebx	/* load registers */
+	movl	vcpu+vcpu_ecx,%ecx
+	movl	vcpu+vcpu_edx,%edx
+	movl	vcpu+vcpu_esi,%esi
+	movl	vcpu+vcpu_edi,%edi
+	movl	vcpu+vcpu_ebp,%ebp
+	movl	vcpu+vcpu_esp,%esp	/* using new kernels boot stack now */
+
+	movl	vcpu+vcpu_eip,%eax	/* push entry point */
+	push	%eax
+	movl	vcpu+vcpu_eax,%eax	/* push eax */
+	push	%eax
+	movl	vcpu+vcpu_cr3,%eax	/* activate new pagetables */
+	movl	%eax,%cr3
+	pop	%eax			/* reload eax */
+	ret				/* jump to new kernel */
+
+BUG:
+	/* crash the domain, make xen dump registers */
+	ud2
+	jmp	BUG
+
+/* --- hypercall page ----------------------------------------------- */
+
+	.align 4096
+hypercall_page:
+	nop
+	.align	4096
+hypercall_end:
--- /dev/null
+++ b/tools/xcutils/helper/x86_32/hypercall.h
@@ -0,0 +1,359 @@
+/******************************************************************************
+ * hypercall.h
+ *
+ * Linux-specific hypervisor handling.
+ *
+ * Copyright (c) 2002-2004, K A Fraser
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __HYPERCALL_H__
+#define __HYPERCALL_H__
+
+
+#define __STR(x) #x
+#define STR(x) __STR(x)
+
+#define _hypercall0(type, name)			\
+({						\
+	long __res;				\
+	asm volatile (				\
+		"call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\
+		: "=a" (__res)			\
+		:				\
+		: "memory" );			\
+	(type)__res;				\
+})
+
+#define _hypercall1(type, name, a1)				\
+({								\
+	long __res, __ign1;					\
+	asm volatile (						\
+		"call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\
+		: "=a" (__res), "=b" (__ign1)			\
+		: "1" ((long)(a1))				\
+		: "memory" );					\
+	(type)__res;						\
+})
+
+#define _hypercall2(type, name, a1, a2)				\
+({								\
+	long __res, __ign1, __ign2;				\
+	asm volatile (						\
+		"call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\
+		: "=a" (__res), "=b" (__ign1), "=c" (__ign2)	\
+		: "1" ((long)(a1)), "2" ((long)(a2))		\
+		: "memory" );					\
+	(type)__res;						\
+})
+
+#define _hypercall3(type, name, a1, a2, a3)			\
+({								\
+	long __res, __ign1, __ign2, __ign3;			\
+	asm volatile (						\
+		"call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\
+		: "=a" (__res), "=b" (__ign1), "=c" (__ign2), 	\
+		"=d" (__ign3)					\
+		: "1" ((long)(a1)), "2" ((long)(a2)),		\
+		"3" ((long)(a3))				\
+		: "memory" );					\
+	(type)__res;						\
+})
+
+#define _hypercall4(type, name, a1, a2, a3, a4)			\
+({								\
+	long __res, __ign1, __ign2, __ign3, __ign4;		\
+	asm volatile (						\
+		"call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\
+		: "=a" (__res), "=b" (__ign1), "=c" (__ign2),	\
+		"=d" (__ign3), "=S" (__ign4)			\
+		: "1" ((long)(a1)), "2" ((long)(a2)),		\
+		"3" ((long)(a3)), "4" ((long)(a4))		\
+		: "memory" );					\
+	(type)__res;						\
+})
+
+#define _hypercall5(type, name, a1, a2, a3, a4, a5)		\
+({								\
+	long __res, __ign1, __ign2, __ign3, __ign4, __ign5;	\
+	asm volatile (						\
+		"call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\
+		: "=a" (__res), "=b" (__ign1), "=c" (__ign2),	\
+		"=d" (__ign3), "=S" (__ign4), "=D" (__ign5)	\
+		: "1" ((long)(a1)), "2" ((long)(a2)),		\
+		"3" ((long)(a3)), "4" ((long)(a4)),		\
+		"5" ((long)(a5))				\
+		: "memory" );					\
+	(type)__res;						\
+})
+
+static inline int
+HYPERVISOR_set_trap_table(
+	trap_info_t *table)
+{
+	return _hypercall1(int, set_trap_table, table);
+}
+
+static inline int
+HYPERVISOR_mmu_update(
+	mmu_update_t *req, int count, int *success_count, domid_t domid)
+{
+	return _hypercall4(int, mmu_update, req, count, success_count, domid);
+}
+
+static inline int
+HYPERVISOR_mmuext_op(
+	struct mmuext_op *op, int count, int *success_count, domid_t domid)
+{
+	return _hypercall4(int, mmuext_op, op, count, success_count, domid);
+}
+
+static inline int
+HYPERVISOR_set_gdt(
+	unsigned long *frame_list, int entries)
+{
+	return _hypercall2(int, set_gdt, frame_list, entries);
+}
+
+static inline int
+HYPERVISOR_stack_switch(
+	unsigned long ss, unsigned long esp)
+{
+	return _hypercall2(int, stack_switch, ss, esp);
+}
+
+static inline int
+HYPERVISOR_set_callbacks(
+	unsigned long event_selector, unsigned long event_address,
+	unsigned long failsafe_selector, unsigned long failsafe_address)
+{
+	return _hypercall4(int, set_callbacks,
+			   event_selector, event_address,
+			   failsafe_selector, failsafe_address);
+}
+
+static inline int
+HYPERVISOR_fpu_taskswitch(
+	int set)
+{
+	return _hypercall1(int, fpu_taskswitch, set);
+}
+
+static inline int
+HYPERVISOR_sched_op_compat(
+	int cmd, unsigned long arg)
+{
+	return _hypercall2(int, sched_op_compat, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_sched_op(
+	int cmd, void *arg)
+{
+	return _hypercall2(int, sched_op, cmd, arg);
+}
+
+#if 0
+static inline long
+HYPERVISOR_set_timer_op(
+	u64 timeout)
+{
+	unsigned long timeout_hi = (unsigned long)(timeout>>32);
+	unsigned long timeout_lo = (unsigned long)timeout;
+	return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi);
+}
+
+static inline int
+HYPERVISOR_dom0_op(
+	dom0_op_t *dom0_op)
+{
+	dom0_op->interface_version = DOM0_INTERFACE_VERSION;
+	return _hypercall1(int, dom0_op, dom0_op);
+}
+#endif
+
+static inline int
+HYPERVISOR_set_debugreg(
+	int reg, unsigned long value)
+{
+	return _hypercall2(int, set_debugreg, reg, value);
+}
+
+static inline unsigned long
+HYPERVISOR_get_debugreg(
+	int reg)
+{
+	return _hypercall1(unsigned long, get_debugreg, reg);
+}
+
+#if 0
+static inline int
+HYPERVISOR_update_descriptor(
+	u64 ma, u64 desc)
+{
+	return _hypercall4(int, update_descriptor, ma, ma>>32, desc, desc>>32);
+}
+#endif
+
+static inline int
+HYPERVISOR_memory_op(
+	unsigned int cmd, void *arg)
+{
+	return _hypercall2(int, memory_op, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_multicall(
+	void *call_list, int nr_calls)
+{
+	return _hypercall2(int, multicall, call_list, nr_calls);
+}
+
+#if 0
+static inline int
+HYPERVISOR_update_va_mapping(
+	unsigned long va, pte_t new_val, unsigned long flags)
+{
+	unsigned long pte_hi = 0;
+#ifdef CONFIG_X86_PAE
+	pte_hi = new_val.pte_high;
+#endif
+	return _hypercall4(int, update_va_mapping, va,
+			   new_val.pte_low, pte_hi, flags);
+}
+#endif
+
+static inline int
+HYPERVISOR_event_channel_op(
+	int cmd, void *arg)
+{
+	int rc = _hypercall2(int, event_channel_op, cmd, arg);
+	/* FIXME: handle -ENOSYS */
+	return rc;
+}
+
+static inline int
+HYPERVISOR_acm_op(
+	int cmd, void *arg)
+{
+	return _hypercall2(int, acm_op, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_xen_version(
+	int cmd, void *arg)
+{
+	return _hypercall2(int, xen_version, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_console_io(
+	int cmd, int count, char *str)
+{
+	return _hypercall3(int, console_io, cmd, count, str);
+}
+
+static inline int
+HYPERVISOR_physdev_op(
+	int cmd, void *arg)
+{
+	int rc = _hypercall2(int, physdev_op, cmd, arg);
+	/* FIXME: handle -ENOSYS */
+	return rc;
+}
+
+static inline int
+HYPERVISOR_grant_table_op(
+	unsigned int cmd, void *uop, unsigned int count)
+{
+	return _hypercall3(int, grant_table_op, cmd, uop, count);
+}
+
+#if 0
+static inline int
+HYPERVISOR_update_va_mapping_otherdomain(
+	unsigned long va, pte_t new_val, unsigned long flags, domid_t domid)
+{
+	unsigned long pte_hi = 0;
+#ifdef CONFIG_X86_PAE
+	pte_hi = new_val.pte_high;
+#endif
+	return _hypercall5(int, update_va_mapping_otherdomain, va,
+			   new_val.pte_low, pte_hi, flags, domid);
+}
+#endif
+
+static inline int
+HYPERVISOR_vm_assist(
+	unsigned int cmd, unsigned int type)
+{
+	return _hypercall2(int, vm_assist, cmd, type);
+}
+
+static inline int
+HYPERVISOR_vcpu_op(
+	int cmd, int vcpuid, void *extra_args)
+{
+	return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args);
+}
+
+static inline int
+HYPERVISOR_suspend(
+	unsigned long srec)
+{
+	struct sched_shutdown sched_shutdown = {
+		.reason = SHUTDOWN_suspend
+	};
+
+	int rc = _hypercall3(int, sched_op, SCHEDOP_shutdown,
+			     &sched_shutdown, srec);
+	/* FIXME: handle -ENOSYS */
+	return rc;
+}
+
+static inline int
+HYPERVISOR_nmi_op(
+	unsigned long op, void *arg)
+{
+	return _hypercall2(int, nmi_op, op, arg);
+}
+
+static inline int
+HYPERVISOR_callback_op(
+	int cmd, void *arg)
+{
+	return _hypercall2(int, callback_op, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_xenoprof_op(
+	int op, void *arg)
+{
+	return _hypercall2(int, xenoprof_op, op, arg);
+}
+
+
+#endif /* __HYPERCALL_H__ */
--- /dev/null
+++ b/tools/xcutils/helper/x86_64/div64.h
@@ -0,0 +1,57 @@
+#ifndef _ASM_GENERIC_DIV64_H
+#define _ASM_GENERIC_DIV64_H
+/*
+ * Copyright (C) 2003 Bernardo Innocenti <bernie@develer.com>
+ * Based on former asm-ppc/div64.h and asm-m68knommu/div64.h
+ *
+ * The semantics of do_div() are:
+ *
+ * uint32_t do_div(uint64_t *n, uint32_t base)
+ * {
+ * 	uint32_t remainder = *n % base;
+ * 	*n = *n / base;
+ * 	return remainder;
+ * }
+ *
+ * NOTE: macro parameter n is evaluated multiple times,
+ *       beware of side effects!
+ */
+
+#include <linux/types.h>
+
+#if BITS_PER_LONG == 64
+
+# define do_div(n,base) ({					\
+	uint32_t __base = (base);				\
+	uint32_t __rem;						\
+	__rem = ((uint64_t)(n)) % __base;			\
+	(n) = ((uint64_t)(n)) / __base;				\
+	__rem;							\
+ })
+
+#elif BITS_PER_LONG == 32
+
+extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
+
+/* The unnecessary pointer compare is there
+ * to check for type safety (n must be 64bit)
+ */
+# define do_div(n,base) ({				\
+	uint32_t __base = (base);			\
+	uint32_t __rem;					\
+	(void)(((typeof((n)) *)0) == ((uint64_t *)0));	\
+	if (likely(((n) >> 32) == 0)) {			\
+		__rem = (uint32_t)(n) % __base;		\
+		(n) = (uint32_t)(n) / __base;		\
+	} else 						\
+		__rem = __div64_32(&(n), __base);	\
+	__rem;						\
+ })
+
+#else /* BITS_PER_LONG == ?? */
+
+# error do_div() does not yet support the C64
+
+#endif /* BITS_PER_LONG */
+
+#endif /* _ASM_GENERIC_DIV64_H */
--- /dev/null
+++ b/tools/xcutils/helper/x86_64/entry.S
@@ -0,0 +1,50 @@
+#include "offsets.h"
+
+/* --- stack -------------------------------------------------------- */
+
+	.data
+stack_bottom:
+	.fill 4096,1,0
+stack_top:
+
+/* --- text --------------------------------------------------------- */
+
+	.text
+	.globl _start,_start_kernel,hypercall_page,BUG
+
+_start:
+	/* setup stack */
+	movq	%rsi, old_info
+	lea	stack_top,%rsp
+	jmp	start_helper
+
+_start_kernel:
+	movq	vcpu+vcpu_ebx,%rbx	/* load registers */
+	movq	vcpu+vcpu_ecx,%rcx
+	movq	vcpu+vcpu_edx,%rdx
+	movq	vcpu+vcpu_esi,%rsi
+	movq	vcpu+vcpu_edi,%rdi
+	movq	vcpu+vcpu_ebp,%rbp
+	movq	vcpu+vcpu_esp,%rsp	/* using new kernels boot stack now */
+
+	movq	vcpu+vcpu_eip,%rax
+	push	%rax
+	movq	vcpu+vcpu_eax,%rax
+	push	%rax
+	movq	vcpu+vcpu_cr3,%rax
+	movq	%rax,%cr3		/* activate new pagetables */
+	pop	%rax			/* load rax */
+	ret				/* jump to new kernel */
+
+BUG:
+	/* crash the domain, make xen dump registers */
+	ud2
+	jmp	BUG
+
+/* --- hypercall page ----------------------------------------------- */
+
+	.align 4096
+hypercall_page:
+	nop
+	.align	4096
+hypercall_end:
--- /dev/null
+++ b/tools/xcutils/helper/x86_64/hypercall.h
@@ -0,0 +1,354 @@
+/******************************************************************************
+ * hypercall.h
+ *
+ * Linux-specific hypervisor handling.
+ *
+ * Copyright (c) 2002-2004, K A Fraser
+ *
+ * 64-bit updates:
+ *   Benjamin Liu <benjamin.liu@intel.com>
+ *   Jun Nakajima <jun.nakajima@intel.com>
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __HYPERCALL_H__
+#define __HYPERCALL_H__
+
+
+#define __STR(x) #x
+#define STR(x) __STR(x)
+
+#define _hypercall0(type, name)			\
+({						\
+	long __res;				\
+	asm volatile (				\
+		"call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\
+		: "=a" (__res)			\
+		:				\
+		: "memory" );			\
+	(type)__res;				\
+})
+
+#define _hypercall1(type, name, a1)				\
+({								\
+	long __res, __ign1;					\
+	asm volatile (						\
+		"call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\
+		: "=a" (__res), "=D" (__ign1)			\
+		: "1" ((long)(a1))				\
+		: "memory" );					\
+	(type)__res;						\
+})
+
+#define _hypercall2(type, name, a1, a2)				\
+({								\
+	long __res, __ign1, __ign2;				\
+	asm volatile (						\
+		"call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\
+		: "=a" (__res), "=D" (__ign1), "=S" (__ign2)	\
+		: "1" ((long)(a1)), "2" ((long)(a2))		\
+		: "memory" );					\
+	(type)__res;						\
+})
+
+#define _hypercall3(type, name, a1, a2, a3)			\
+({								\
+	long __res, __ign1, __ign2, __ign3;			\
+	asm volatile (						\
+		"call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\
+		: "=a" (__res), "=D" (__ign1), "=S" (__ign2), 	\
+		"=d" (__ign3)					\
+		: "1" ((long)(a1)), "2" ((long)(a2)),		\
+		"3" ((long)(a3))				\
+		: "memory" );					\
+	(type)__res;						\
+})
+
+#define _hypercall4(type, name, a1, a2, a3, a4)			\
+({								\
+	long __res, __ign1, __ign2, __ign3;			\
+	asm volatile (						\
+		"movq %7,%%r10; "				\
+		"call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\
+		: "=a" (__res), "=D" (__ign1), "=S" (__ign2),	\
+		"=d" (__ign3)					\
+		: "1" ((long)(a1)), "2" ((long)(a2)),		\
+		"3" ((long)(a3)), "g" ((long)(a4))		\
+		: "memory", "r10" );				\
+	(type)__res;						\
+})
+
+#define _hypercall5(type, name, a1, a2, a3, a4, a5)		\
+({								\
+	long __res, __ign1, __ign2, __ign3;			\
+	asm volatile (						\
+		"movq %7,%%r10; movq %8,%%r8; "			\
+		"call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"\
+		: "=a" (__res), "=D" (__ign1), "=S" (__ign2),	\
+		"=d" (__ign3)					\
+		: "1" ((long)(a1)), "2" ((long)(a2)),		\
+		"3" ((long)(a3)), "g" ((long)(a4)),		\
+		"g" ((long)(a5))				\
+		: "memory", "r10", "r8" );			\
+	(type)__res;						\
+})
+
+static inline int
+HYPERVISOR_set_trap_table(
+	trap_info_t *table)
+{
+	return _hypercall1(int, set_trap_table, table);
+}
+
+static inline int
+HYPERVISOR_mmu_update(
+	mmu_update_t *req, int count, int *success_count, domid_t domid)
+{
+	return _hypercall4(int, mmu_update, req, count, success_count, domid);
+}
+
+static inline int
+HYPERVISOR_mmuext_op(
+	struct mmuext_op *op, int count, int *success_count, domid_t domid)
+{
+	return _hypercall4(int, mmuext_op, op, count, success_count, domid);
+}
+
+static inline int
+HYPERVISOR_set_gdt(
+	unsigned long *frame_list, int entries)
+{
+	return _hypercall2(int, set_gdt, frame_list, entries);
+}
+
+static inline int
+HYPERVISOR_stack_switch(
+	unsigned long ss, unsigned long esp)
+{
+	return _hypercall2(int, stack_switch, ss, esp);
+}
+
+static inline int
+HYPERVISOR_set_callbacks(
+	unsigned long event_address, unsigned long failsafe_address,
+	unsigned long syscall_address)
+{
+	return _hypercall3(int, set_callbacks,
+			   event_address, failsafe_address, syscall_address);
+}
+
+static inline int
+HYPERVISOR_fpu_taskswitch(
+	int set)
+{
+	return _hypercall1(int, fpu_taskswitch, set);
+}
+
+static inline int
+HYPERVISOR_sched_op_compat(
+	int cmd, unsigned long arg)
+{
+	return _hypercall2(int, sched_op_compat, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_sched_op(
+	int cmd, void *arg)
+{
+	return _hypercall2(int, sched_op, cmd, arg);
+}
+
+#if 0
+static inline long
+HYPERVISOR_set_timer_op(
+	u64 timeout)
+{
+	return _hypercall1(long, set_timer_op, timeout);
+}
+
+static inline int
+HYPERVISOR_dom0_op(
+	dom0_op_t *dom0_op)
+{
+	dom0_op->interface_version = DOM0_INTERFACE_VERSION;
+	return _hypercall1(int, dom0_op, dom0_op);
+}
+#endif
+
+static inline int
+HYPERVISOR_set_debugreg(
+	int reg, unsigned long value)
+{
+	return _hypercall2(int, set_debugreg, reg, value);
+}
+
+static inline unsigned long
+HYPERVISOR_get_debugreg(
+	int reg)
+{
+	return _hypercall1(unsigned long, get_debugreg, reg);
+}
+
+static inline int
+HYPERVISOR_update_descriptor(
+	unsigned long ma, unsigned long word)
+{
+	return _hypercall2(int, update_descriptor, ma, word);
+}
+
+static inline int
+HYPERVISOR_memory_op(
+	unsigned int cmd, void *arg)
+{
+	return _hypercall2(int, memory_op, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_multicall(
+	void *call_list, int nr_calls)
+{
+	return _hypercall2(int, multicall, call_list, nr_calls);
+}
+
+#if 0
+static inline int
+HYPERVISOR_update_va_mapping(
+	unsigned long va, pte_t new_val, unsigned long flags)
+{
+	return _hypercall3(int, update_va_mapping, va, new_val.pte, flags);
+}
+#endif
+
+static inline int
+HYPERVISOR_event_channel_op(
+	int cmd, void *arg)
+{
+	int rc = _hypercall2(int, event_channel_op, cmd, arg);
+	return rc;
+}
+
+static inline int
+HYPERVISOR_acm_op(
+	int cmd, void *arg)
+{
+	return _hypercall2(int, acm_op, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_xen_version(
+	int cmd, void *arg)
+{
+	return _hypercall2(int, xen_version, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_console_io(
+	int cmd, int count, char *str)
+{
+	return _hypercall3(int, console_io, cmd, count, str);
+}
+
+static inline int
+HYPERVISOR_physdev_op(
+	int cmd, void *arg)
+{
+	int rc = _hypercall2(int, physdev_op, cmd, arg);
+	return rc;
+}
+
+static inline int
+HYPERVISOR_grant_table_op(
+	unsigned int cmd, void *uop, unsigned int count)
+{
+	return _hypercall3(int, grant_table_op, cmd, uop, count);
+}
+
+#if 0
+static inline int
+HYPERVISOR_update_va_mapping_otherdomain(
+	unsigned long va, pte_t new_val, unsigned long flags, domid_t domid)
+{
+	return _hypercall4(int, update_va_mapping_otherdomain, va,
+			   new_val.pte, flags, domid);
+}
+#endif
+
+static inline int
+HYPERVISOR_vm_assist(
+	unsigned int cmd, unsigned int type)
+{
+	return _hypercall2(int, vm_assist, cmd, type);
+}
+
+static inline int
+HYPERVISOR_vcpu_op(
+	int cmd, int vcpuid, void *extra_args)
+{
+	return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args);
+}
+
+static inline int
+HYPERVISOR_set_segment_base(
+	int reg, unsigned long value)
+{
+	return _hypercall2(int, set_segment_base, reg, value);
+}
+
+static inline int
+HYPERVISOR_suspend(
+	unsigned long srec)
+{
+	struct sched_shutdown sched_shutdown = {
+		.reason = SHUTDOWN_suspend
+	};
+
+	int rc = _hypercall3(int, sched_op, SCHEDOP_shutdown,
+			     &sched_shutdown, srec);
+	return rc;
+}
+
+static inline int
+HYPERVISOR_nmi_op(
+	unsigned long op, void *arg)
+{
+	return _hypercall2(int, nmi_op, op, arg);
+}
+
+static inline int
+HYPERVISOR_callback_op(
+	int cmd, void *arg)
+{
+	return _hypercall2(int, callback_op, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_xenoprof_op(
+	int op, void *arg)
+{
+	return _hypercall2(int, xenoprof_op, op, arg);
+}
+
+#endif /* __HYPERCALL_H__ */
--- /dev/null
+++ b/tools/xcutils/kexec-syscall.h
@@ -0,0 +1,80 @@
+#ifndef KEXEC_SYSCALL_H
+#define KEXEC_SYSCALL_H
+
+#define __LIBRARY__
+#include <syscall.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#define	LINUX_REBOOT_MAGIC1	0xfee1dead
+#define	LINUX_REBOOT_MAGIC2	672274793
+#define	LINUX_REBOOT_MAGIC2A	85072278
+#define	LINUX_REBOOT_MAGIC2B	369367448
+
+#define	LINUX_REBOOT_CMD_RESTART	0x01234567
+#define	LINUX_REBOOT_CMD_HALT		0xCDEF0123
+#define	LINUX_REBOOT_CMD_CAD_ON		0x89ABCDEF
+#define	LINUX_REBOOT_CMD_CAD_OFF	0x00000000
+#define	LINUX_REBOOT_CMD_POWER_OFF	0x4321FEDC
+#define	LINUX_REBOOT_CMD_RESTART2	0xA1B2C3D4
+#define LINUX_REBOOT_CMD_EXEC_KERNEL    0x18273645
+#define LINUX_REBOOT_CMD_KEXEC_OLD	0x81726354
+#define LINUX_REBOOT_CMD_KEXEC_OLD2	0x18263645
+#define LINUX_REBOOT_CMD_KEXEC		0x45584543
+
+#ifdef __i386__
+#define __NR_kexec_load		283
+#endif
+#ifdef __ia64__
+#define __NR_kexec_load		1268
+#endif
+#ifdef __powerpc64__
+#define __NR_kexec_load		268
+#endif
+#ifdef __powerpc__
+#define __NR_kexec_load		268
+#endif
+#ifdef __x86_64__
+#define __NR_kexec_load		246
+#endif
+#ifdef __s390x__
+#define __NR_kexec_load		277
+#endif
+#ifdef __s390__
+#define __NR_kexec_load		277
+#endif
+#ifndef __NR_kexec_load
+#error Unknown processor architecture.  Needs a kexec_load syscall number.
+#endif
+
+struct kexec_segment;
+
+static inline long kexec_load(void *entry, unsigned long nr_segments,
+			struct kexec_segment *segments, unsigned long flags)
+{
+	return (long) syscall(__NR_kexec_load, entry, nr_segments, segments, flags);
+}
+
+static inline long kexec_reboot(void)
+{
+	return (long) syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_KEXEC, 0);
+}
+
+
+#define KEXEC_ON_CRASH  0x00000001
+#define KEXEC_ARCH_MASK 0xffff0000
+
+/* These values match the ELF architecture values.
+ * Unless there is a good reason that should continue to be the case.
+ */
+#define KEXEC_ARCH_DEFAULT ( 0 << 16)
+#define KEXEC_ARCH_386     ( 3 << 16)
+#define KEXEC_ARCH_X86_64  (62 << 16)
+#define KEXEC_ARCH_PPC     (20 << 16)
+#define KEXEC_ARCH_PPC64   (21 << 16)
+#define KEXEC_ARCH_IA_64   (50 << 16)
+#define KEXEC_ARCH_S390    (22 << 16)
+
+#define KEXEC_MAX_SEGMENTS 16
+
+#endif /* KEXEC_SYSCALL_H */
--- /dev/null
+++ b/tools/xcutils/xc_kexec.c
@@ -0,0 +1,506 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <inttypes.h>
+#include <malloc.h>
+#include <sys/mman.h>
+
+#include <xg_private.h>
+#include <xc_dom.h>
+#include <xen/libelf/libelf.h>
+
+#include "kexec-syscall.h"
+
+/* ------------------------------------------------------------------ */
+
+static unsigned long debug_level;
+
+static char          hypercall_page[PAGE_SIZE];
+static unsigned long max_pfn;
+static unsigned long xen_start_info;
+static start_info_t  start_info;
+
+/* -------------------------------------------------------------------------------- */
+
+static unsigned long kernel_find_symbol(char *name)
+{
+    FILE *file;
+    char line[256], type, symbol[256];
+    unsigned long addr, retval = 0;
+
+    file = fopen("/proc/kallsyms", "r");
+    if (NULL == file) {
+	perror("open /proc/kallsyms");
+	exit(1);
+    }
+    while (NULL != fgets(line, sizeof(line), file)) {
+	if (3 != sscanf(line, "%lx %c %127s", &addr, &type, symbol)) {
+	    fprintf(stderr,"parse error: %s\n", line);
+	    exit(1);
+	}
+	if (0 == strcmp(name, symbol)) {
+	    retval = addr;
+	    break;
+	}
+    }
+    fclose(file);
+    return retval;
+}
+
+static int kernel_core_read(void *dest, off_t start, size_t size)
+{
+    FILE *file;
+    int rc;
+
+    file = fopen("/proc/kcore", "r");
+    if (NULL == file) {
+	perror("open /proc/kcore");
+	exit(1);
+    }
+    rc = fseek(file, start, SEEK_SET);
+    if (rc < 0)
+	goto out;
+    rc = fread(dest, 1, size, file);
+    fclose(file);
+
+ out:
+    return rc;
+}
+
+static off_t kernel_core_offset(unsigned long addr)
+{
+    static void *core_header = NULL;
+    static struct elf_binary elf;
+    ELF_HANDLE_DECL(elf_phdr) phdr;
+    uint64_t p_type;
+    uint64_t p_vaddr;
+    uint64_t p_offset;
+    uint64_t p_filesz;
+    off_t offset = 0;
+    int h;
+
+    if (NULL == core_header) {
+	core_header = malloc(PAGE_SIZE);
+	if (PAGE_SIZE != kernel_core_read(core_header, 0, PAGE_SIZE))
+	    goto out;
+	elf_init(&elf, core_header, PAGE_SIZE);
+    }
+
+    for (h = 0; h < elf_uval(&elf, elf.ehdr, e_phnum); h++) {
+        phdr     = elf_phdr_by_index(&elf, h);
+	p_type   = elf_uval(&elf, phdr, p_type);
+	p_vaddr  = elf_uval(&elf, phdr, p_vaddr);
+	p_offset = elf_uval(&elf, phdr, p_offset);
+	p_filesz = elf_uval(&elf, phdr, p_filesz);
+        if (p_type != PT_LOAD)
+            continue;
+	if (addr > p_vaddr && addr < p_vaddr + p_filesz)
+	    offset = p_offset + (addr - p_vaddr);
+    }
+
+ out:
+    return offset;
+}
+
+static int kernel_core_by_addr(void *dest, unsigned long addr, size_t size)
+{
+    off_t offset;
+    int rc = 0;
+
+    offset = kernel_core_offset(addr);
+    if (0 == addr) {
+	fprintf(stderr, "%s: addr 0x%lx not in /proc/kcore\n",
+		__FUNCTION__, addr);
+	goto out;
+    }
+    rc = kernel_core_read(dest, offset, size);
+    if (debug_level)
+	fprintf(stderr, "%s: vaddr %lx, offset %lx, %d bytes\n",
+		__FUNCTION__, addr, (unsigned long)offset, rc);
+
+ out:
+    return rc;
+}
+
+static int kernel_core_by_name(void *dest, char *name, size_t size)
+{
+    unsigned long addr;
+    off_t offset;
+    int rc = 0;
+
+    addr = kernel_find_symbol(name);
+    if (0 == addr) {
+	fprintf(stderr, "%s: can't find symbol \"%s\" in /proc/kallsyms\n",
+		__FUNCTION__, name);
+	fprintf(stderr, "%s: try CONFIG_KALLSYMS_ALL=y\n", __FUNCTION__);
+	goto out;
+    }
+
+    offset = kernel_core_offset(addr);
+    if (0 == addr) {
+	fprintf(stderr, "%s: symbol \"%s\" (0x%lx) not in /proc/kcore\n",
+		__FUNCTION__, name, addr);
+	goto out;
+    }
+    rc = kernel_core_read(dest, offset, size);
+    if (debug_level)
+	fprintf(stderr, "%s: vaddr %lx, offset %lx, %d bytes (%s)\n",
+		__FUNCTION__, addr, (unsigned long)offset, rc, name);
+
+ out:
+    return rc;
+}
+
+/* ------------------------------------------------------------------ */
+
+struct kexec_segment {
+    const void *buf;
+    size_t bufsz;
+    const void *mem;
+    size_t memsz;
+};
+
+struct kexec_segment segments[KEXEC_MAX_SEGMENTS];
+static unsigned int nsegments;
+static void *entry;
+
+static void kexec_add_segment(struct xc_dom_image *dom,
+			      struct xc_dom_seg *xc_seg,
+			      struct kexec_segment *kseg)
+{
+    if (0 == xc_seg->vend - xc_seg->vstart)
+	return;
+
+    kseg->buf   = xc_dom_seg_to_ptr(dom, xc_seg);
+    kseg->bufsz = xc_seg->vend - xc_seg->vstart;
+    kseg->mem   = (void*)(xc_seg->pfn << PAGE_SHIFT);
+    kseg->memsz = kseg->bufsz;
+    if (debug_level)
+	fprintf(stderr,"   kexec segment: 0x%08lx-0x%08lx (+0x%08lx)\n",
+		(unsigned long)kseg->mem,
+		(unsigned long)(kseg->mem+kseg->memsz-1),
+		(unsigned long)kseg->memsz);
+}
+
+static void kexec_add_page(struct xc_dom_image *dom, xen_pfn_t pfn,
+			   struct kexec_segment *kseg)
+{
+    if (0 == pfn)
+	return;
+
+    kseg->buf   = xc_dom_pfn_to_ptr(dom, pfn, 1);
+    kseg->bufsz = PAGE_SIZE;
+    kseg->mem   = (void*)(pfn << PAGE_SHIFT);
+    kseg->memsz = kseg->bufsz;
+    if (debug_level)
+	fprintf(stderr,"   kexec page   : 0x%08lx-0x%08lx\n",
+		(unsigned long)kseg->mem,
+		(unsigned long)(kseg->mem+kseg->memsz-1));
+}
+
+/* ------------------------------------------------------------------ */
+
+static const char helper_blob[] = {
+#include "helper/blob.h"
+};
+
+static void helper_parse(struct xc_dom_image *dom,
+			 struct elf_binary *elf)
+{
+    if (debug_level)
+	fprintf(stderr, "%s\n", __FUNCTION__);
+    elf_init(elf, helper_blob, sizeof(helper_blob));
+    if (debug_level)
+	elf_set_logfile(elf, stderr, debug_level);
+    elf_parse_binary(elf);
+    elf->pstart = elf->pstart & PAGE_MASK;
+    elf->pend   = (elf->pend + PAGE_SIZE - 1) & PAGE_MASK;
+
+    dom->extra_pages = (elf->pend - elf->pstart) >> PAGE_SHIFT;
+}
+
+static void *helper_load(struct xc_dom_image *dom,
+			 struct elf_binary *elf)
+{
+    struct xc_dom_seg seg;
+    xen_pfn_t pages;
+    uint64_t entry;
+
+    if (debug_level)
+	fprintf(stderr, "%s\n", __FUNCTION__);
+
+    xc_dom_alloc_segment(dom, &seg, "kexec", 0, elf->pend - elf->pstart);
+    elf->dest_base = xc_dom_seg_to_ptr_pages(dom, &seg, &pages);
+    elf->dest_size = pages * XC_DOM_PAGE_SIZE(dom);
+    elf->reloc_offset = seg.vstart - dom->parms.virt_base - elf->pstart;
+    if (debug_level)
+	fprintf(stderr,"%s: relocation offset: 0x%" PRIx64 "\n",
+		__FUNCTION__, elf->reloc_offset);
+
+    if (NULL == elf->dest_base)
+	goto err;
+    elf_load_binary(elf);
+    if (-1 == elf_reloc(elf))
+	goto err;
+    kexec_add_segment(dom, &seg, &segments[nsegments++]);
+
+    entry = elf_uval(elf, elf->ehdr, e_entry);
+    return (void*)((intptr_t)(entry + elf->reloc_offset));
+
+ err:
+    exit(1);
+}
+
+static elf_ptrval ptr_symbol(struct elf_binary *elf, const char *symbol)
+{
+    unsigned long addr;
+
+    addr = elf_lookup_addr(elf, symbol);
+    if (-1 == addr)
+	exit(1);
+    return elf_get_ptr(elf, addr);
+}
+
+static void helper_pass_info(struct xc_dom_image *dom, struct elf_binary *elf)
+{
+    struct vcpu_guest_context ctxt;
+    elf_ptrval addr;
+
+    if (debug_level)
+	fprintf(stderr, "%s\n", __FUNCTION__);
+    dom->arch_hooks->vcpu(dom, &ctxt);
+    addr = ptr_symbol(elf, "vcpu");
+    if (elf_access_ok(elf, addr, sizeof(ctxt)))
+        memcpy(ELF_UNSAFE_PTR(addr), &ctxt, sizeof(ctxt));
+    addr = ptr_symbol(elf, "virt_base");
+    elf_store_val(elf, unsigned long, addr, dom->parms.virt_base);
+    addr = ptr_symbol(elf, "virt_hypercall");
+    elf_store_val(elf, unsigned long, addr, dom->parms.virt_hypercall);
+#if defined(__i386__)
+    addr = ptr_symbol(elf, "pae_paging");
+    elf_store_val(elf, unsigned long, addr, dom->parms.pae);
+#endif
+    addr = ptr_symbol(elf, "debug_level");
+    elf_store_val(elf, unsigned long, addr, debug_level);
+    addr = ptr_symbol(elf, "hypercall_page");
+    if (elf_access_ok(elf, addr, PAGE_SIZE))
+        memcpy(ELF_UNSAFE_PTR(addr), hypercall_page, PAGE_SIZE);
+}
+
+/* ------------------------------------------------------------------ */
+
+static char *kernel_name  = "/boot/vmlinuz-xen";
+static char *ramdisk_name;
+static char *cmdline;
+static char *features; //     = "auto_translated_physmap";
+static int do_exec = 0;
+static int do_load = 1;
+static int do_type = 0;
+
+static void usage(FILE *fp)
+{
+    fprintf(fp,
+	    "\n"
+	    "This is a xen kexec loader.\n"
+	    "\n"
+	    "usage: xen-kexec [ options ]\n"
+	    "options:\n"
+	    "  -h           print this text\n"
+	    "  -d           enable debug messages\n"
+	    "  -e           boot loaded kernel     [%s]\n"
+	    "  -l           load kernel            [%s]\n"
+	    "    -k <file>  kernel image           [%s]\n"
+	    "    -i <file>  initrd                 [%s]\n"
+	    "    -c <args>  kernel command line    [%s]\n"
+	    "    -f <feat>  xen features           [%s]\n"
+	    "  -t           print kernel type\n"
+	    "\n"
+	    "(c) 2006 Gerd Hoffmann <kraxel@suse.de>\n",
+	    do_exec ? "yes" : "no",
+	    do_load ? "yes" : "no",
+	    kernel_name, ramdisk_name,
+	    cmdline  ? : "-",
+	    features ? : "-");
+}
+
+static void print_type(char *filename)
+{
+    struct xc_dom_image *dom;
+
+    dom = xc_dom_allocate(cmdline, features);
+    if (0 != xc_dom_kernel_file(dom, filename)) {
+	fprintf(stderr, "can't open %s: %s\n", filename, strerror(errno));
+	goto done;
+    }
+    if (0 != xc_dom_parse_image(dom)) {
+	printf("unknown-kernel\n");
+	goto done;
+    }
+#if defined(__i386__) || defined(__x86_64__)
+    if ( ELF_PTRVAL_INVALID(dom->parms.elf_note_start) &&
+         ELF_PTRVAL_INVALID(dom->parms.guest_info) ) {
+	printf("other-elf-kernel\n");
+	goto done;
+    }
+#endif
+    printf("%s\n", dom->guest_type);
+
+ done:
+    xc_dom_release(dom);
+}
+
+int main(int argc, char *argv[])
+{
+    struct xc_dom_image *dom = NULL;
+    struct elf_binary helper;
+    int fd,rc,c,xc;
+
+    /* figure defaults */
+    fd = open("/proc/cmdline", O_RDONLY);
+    if (-1 != fd) {
+	cmdline = malloc(1024);
+	rc = read(fd,cmdline,1024);
+	cmdline[rc-1] = 0;
+	close(fd);
+    }
+
+    /* parse args */
+    for (;;) {
+        if (-1 == (c = getopt(argc, argv, "hdletk:i:c:f:")))
+            break;
+        switch (c) {
+        case 'k':
+	    kernel_name = optarg;
+            break;
+        case 'i':
+	    if (strlen(optarg))
+		ramdisk_name = optarg;
+	    else
+		ramdisk_name = NULL;
+            break;
+        case 'c':
+	    cmdline = optarg;
+            break;
+        case 'f':
+	    features = optarg;
+            break;
+	case 'd':
+	    debug_level++;
+	    break;
+
+	case 'e':
+	    do_exec = 1;
+	    do_load = 0;
+	    do_type = 0;
+	    break;
+	case 'l':
+	    do_exec = 0;
+	    do_load = 1;
+	    do_type = 0;
+	    break;
+	case 't':
+	    do_exec = 0;
+	    do_load = 0;
+	    do_type = 1;
+	    break;
+
+        case 'h':
+            usage(stdout);
+            exit(0);
+        default:
+            usage(stderr);
+            exit(1);
+        }
+    }
+
+    if (do_exec) {
+	kexec_reboot();
+	perror("kexec_reboot");
+	exit(1);
+    }
+
+    /* logging */
+    if (debug_level)
+	xc_dom_logfile = stderr;
+
+    if (do_type) {
+	print_type(kernel_name);
+	exit(0);
+    }
+
+    if (!do_load)
+	exit(0);
+
+    xc = xc_interface_open();
+    if (-1 == xc)
+	exit(1);
+
+    /* get info from kernel */
+    if (kernel_core_by_name(hypercall_page, "hypercall_page", PAGE_SIZE) <= 0)
+	goto out;
+    if (kernel_core_by_name(&max_pfn, "max_pfn", sizeof(max_pfn)) <= 0)
+	goto out;
+    if (kernel_core_by_name(&xen_start_info, "xen_start_info", sizeof(xen_start_info)) <= 0)
+	goto out;
+    if (kernel_core_by_addr(&start_info, xen_start_info, sizeof(start_info)) <= 0)
+	goto out;
+
+    /* build image */
+    dom = xc_dom_allocate(cmdline, features);
+    dom->xen_version = xc_version(xc, XENVER_version, NULL);
+    strcpy(dom->xen_caps, start_info.magic);
+
+    if (0 != (rc = xc_dom_kernel_file(dom, kernel_name)))
+	goto out;
+    if (ramdisk_name && strlen(ramdisk_name))
+	if (0 != (rc = xc_dom_ramdisk_file(dom, ramdisk_name)))
+	    goto out;
+    if (0 != (rc = xc_dom_parse_image(dom)))
+	goto out;
+    if (0 != strcmp(start_info.magic, dom->guest_type)) {
+	fprintf(stderr,"incompatible kernel (need guest_type \"%s\")\n",
+		start_info.magic);
+	goto out;
+    }
+    helper_parse(dom, &helper);
+
+    if (0 != (rc = xc_dom_mem_init(dom, max_pfn >> (20 - PAGE_SHIFT))))
+	goto out;
+    if (0 != (rc = xc_dom_build_image(dom)))
+	goto out;
+    entry = helper_load(dom, &helper);
+    if (0 != (rc = dom->arch_hooks->setup_pgtables(dom)))
+	goto out;
+    dom->arch_hooks->start_info(dom);
+
+    /* setup kexec structs */
+    kexec_add_segment(dom, &dom->kernel_seg,    &segments[nsegments++]);
+    kexec_add_segment(dom, &dom->ramdisk_seg,   &segments[nsegments++]);
+    kexec_add_segment(dom, &dom->p2m_seg,       &segments[nsegments++]);
+    kexec_add_page(dom,    dom->start_info_pfn, &segments[nsegments++]);
+    kexec_add_segment(dom, &dom->pgtables_seg,  &segments[nsegments++]);
+
+    dom->flags = start_info.flags;
+    dom->console_evtchn  = start_info.console.domU.evtchn;
+    dom->xenstore_evtchn = start_info.store_evtchn;
+
+    /* setup helper code */
+    helper_pass_info(dom, &helper);
+
+    rc = kexec_load(entry, nsegments, segments, 0);
+    if (0 != rc) {
+	perror("kexec_load");
+	exit(1);
+    }
+    if (debug_level)
+	fprintf(stderr,"kexec_load ok [%p]\n", entry);
+
+    xc_dom_release(dom);
+    exit(0);
+
+ out:
+    if (dom)
+	xc_dom_release(dom);
+    exit(1);
+}
