Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:12.2
xen
tools-xc_kexec.diff
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File tools-xc_kexec.diff of Package xen
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.1.0-testing/tools/xcutils/Makefile =================================================================== --- xen-4.1.0-testing.orig/tools/xcutils/Makefile +++ xen-4.1.0-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 = $(LDLIBS_libxenctrl) $(LDLIBS_libxenguest) $(LDLIBS_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.1.0-testing/tools/xcutils/helper/Makefile =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/helper/console.c =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/helper/ctype.c =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/helper/ctype.h =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/helper/helper.h =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/helper/main.c =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/helper/make-offsets.c =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/helper/printk.c =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/helper/string.c =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/helper/vsprintf.c =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/helper/x86_32/div64.h =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/helper/x86_32/entry.S =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/helper/x86_32/hypercall.h =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/helper/x86_64/div64.h =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/helper/x86_64/entry.S =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/helper/x86_64/hypercall.h =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/kexec-syscall.h =================================================================== --- /dev/null +++ xen-4.1.0-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.1.0-testing/tools/xcutils/xc_kexec.c =================================================================== --- /dev/null +++ xen-4.1.0-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); +}
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor