xen/tools-xc_kexec.diff
Charles Arnold 0c76f22ef1 - Update to Xen 4.0.2 rc2-pre, changeset 21443
- bnc#633573 - System fail to boot after running several warm
  reboot tests
  22749-vtd-workarounds.patch
- Upstream patches from Jan
  22744-ept-pod-locking.patch
  22777-vtd-ats-fixes.patch
  22781-pod-hap-logdirty.patch
  22782-x86-emul-smsw.patch
  22789-i386-no-x2apic.patch
  22790-svm-resume-migrate-pirqs.patch
  22816-x86-pirq-drop-priv-check.patch

OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=94
2011-02-04 21:19:54 +00:00

5125 lines
129 KiB
Diff

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(-)
Index: xen-4.0.2-testing/tools/xcutils/Makefile
===================================================================
--- xen-4.0.2-testing.orig/tools/xcutils/Makefile
+++ xen-4.0.2-testing/tools/xcutils/Makefile
@@ -14,7 +14,7 @@ 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)
@@ -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)
Index: xen-4.0.2-testing/tools/xcutils/helper/Makefile
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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
Index: xen-4.0.2-testing/tools/xcutils/helper/console.c
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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;
+}
Index: xen-4.0.2-testing/tools/xcutils/helper/ctype.c
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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);
Index: xen-4.0.2-testing/tools/xcutils/helper/ctype.h
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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
Index: xen-4.0.2-testing/tools/xcutils/helper/helper.h
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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, ...);
Index: xen-4.0.2-testing/tools/xcutils/helper/main.c
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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();
+}
Index: xen-4.0.2-testing/tools/xcutils/helper/make-offsets.c
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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;
+}
Index: xen-4.0.2-testing/tools/xcutils/helper/printk.c
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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);
Index: xen-4.0.2-testing/tools/xcutils/helper/string.c
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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
Index: xen-4.0.2-testing/tools/xcutils/helper/vsprintf.c
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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);
Index: xen-4.0.2-testing/tools/xcutils/helper/x86_32/div64.h
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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
Index: xen-4.0.2-testing/tools/xcutils/helper/x86_32/entry.S
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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:
Index: xen-4.0.2-testing/tools/xcutils/helper/x86_32/hypercall.h
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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__ */
Index: xen-4.0.2-testing/tools/xcutils/helper/x86_64/div64.h
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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 */
Index: xen-4.0.2-testing/tools/xcutils/helper/x86_64/entry.S
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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:
Index: xen-4.0.2-testing/tools/xcutils/helper/x86_64/hypercall.h
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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__ */
Index: xen-4.0.2-testing/tools/xcutils/kexec-syscall.h
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/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 */
Index: xen-4.0.2-testing/tools/xcutils/xc_kexec.c
===================================================================
--- /dev/null
+++ xen-4.0.2-testing/tools/xcutils/xc_kexec.c
@@ -0,0 +1,503 @@
+#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;
+ const 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;
+ 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 = xc_dom_seg_to_ptr(dom, &seg);
+ 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)
+ 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 void* 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;
+ struct vcpu_guest_context *vcpu;
+ unsigned long *addr;
+ void *page;
+
+ if (debug_level)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+ dom->arch_hooks->vcpu(dom, &ctxt);
+ vcpu = ptr_symbol(elf, "vcpu");
+ *vcpu = ctxt;
+ addr = ptr_symbol(elf, "virt_base");
+ *addr = dom->parms.virt_base;
+ addr = ptr_symbol(elf, "virt_hypercall");
+ *addr = dom->parms.virt_hypercall;
+#if defined(__i386__)
+ addr = ptr_symbol(elf, "pae_paging");
+ *addr = dom->parms.pae;
+#endif
+ addr = ptr_symbol(elf, "debug_level");
+ *addr = debug_level;
+ page = ptr_symbol(elf, "hypercall_page");
+ memcpy(page, 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 (NULL == dom->parms.elf_note_start && NULL == 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);
+}