As part of Google Summer of Code we are in the process to add Block PV-drivers to Seabios, in order to this, first we have to be able to communicate with xenstore so we can exchange information before the front and back ends connect. To communicate with xenstore we need to make seabios Xen-friendly so support for hypercalls has been added to Seabios. In the next month, Seabios will become a front-end for the block devices, connecting to dom0 back-end block device when used with Xen.
There is an issue, if you issue a query and the ring did not prepare the answer fast enough, after the event signal hypercall, the ring will force a ring wait for an event that will never arrive. For now this is solved by doing a dprintf after the hypercall, this gives enough time to the ring.
This patch should be applied to Seabios and must be used with qemu-upstream with xen4.1, please follow this guide for this: http://wiki.xensource.com/xenwiki/QEMUUpstream
Some more documentation on this can be found here: http://wiki.xensource.com/xenwiki/SeaBIOS
Daniel Castro (10): Xen: Guest Handlers and Copyrights Move PAGE_SHIFT to memmap.h Xen: Use PAGE_SHIFT as a constant Xen: Support for interdomain event channel Xen: Support for HVM_op Hypercall Xen: Support for memory_op Hypercall Xen: Support for sched_op hypercall Xen: Shared info for CPU yield support and xenbus protocol Xen: Xenstore communication via xenbus Xen: Xenstore example -do not apply
Makefile | 2 +- src/bitops.h | 14 ++ src/memmap.h | 2 + src/post.c | 2 + src/virtio-ring.h | 2 +- src/xen-xs.c | 251 +++++++++++++++++++++++++++++++++++++ src/xen-xs.h | 9 ++ src/xen.c | 20 +++- src/xen.h | 357 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 9 files changed, 653 insertions(+), 6 deletions(-) create mode 100644 src/bitops.h create mode 100644 src/xen-xs.c create mode 100644 src/xen-xs.h
These are used as part of the Xen hypercall interfaces.
Signed-off-by: Daniel Castro evil.dani@gmail.com --- src/xen.h | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 58 insertions(+), 3 deletions(-)
diff --git a/src/xen.h b/src/xen.h index 0ed1e9f..f65078a 100644 --- a/src/xen.h +++ b/src/xen.h @@ -17,6 +17,8 @@ static inline int usingXen(void) { }
unsigned long xen_hypercall_page; +typedef unsigned long xen_ulong_t; +typedef unsigned long xen_pfn_t;
#define _hypercall0(type, name) \ ({ \ @@ -121,15 +123,68 @@ unsigned long xen_hypercall_page; * DEALINGS IN THE SOFTWARE. */
-/* xen.h */ +/****************************************************************************** + * arch-x86/xen.h + * + * Guest OS interface to x86 Xen. + * + * Copyright (c) 2004-2006, K A Fraser + */
-#define __HYPERVISOR_xen_version 17
-/* version.h */ +/* Structural guest handles introduced in 0x00030201. */ +#define ___DEFINE_XEN_GUEST_HANDLE(name, type) \ + typedef struct { type *p; } __guest_handle_ ## name + +#define __DEFINE_XEN_GUEST_HANDLE(name, type) \ + ___DEFINE_XEN_GUEST_HANDLE(name, type); \ + ___DEFINE_XEN_GUEST_HANDLE(const_##name, const type) +#define DEFINE_XEN_GUEST_HANDLE(name) __DEFINE_XEN_GUEST_HANDLE(name, name) +#define __XEN_GUEST_HANDLE(name) __guest_handle_ ## name +#define XEN_GUEST_HANDLE(name) __XEN_GUEST_HANDLE(name) +#define set_xen_guest_handle_raw(hnd, val) do { (hnd).p = val; } while (0) +#define set_xen_guest_handle(hnd, val) set_xen_guest_handle_raw(hnd, val) + +/****************************************************************************** + * version.h + * + * Xen version, type, and compile information. + * + * Copyright (c) 2005, Nguyen Anh Quynh aquynh@gmail.com + * Copyright (c) 2005, Keir Fraser keir@xensource.com + */
/* arg == xen_extraversion_t. */ #define XENVER_extraversion 1 typedef char xen_extraversion_t[16]; #define XEN_EXTRAVERSION_LEN (sizeof(xen_extraversion_t))
+/****************************************************************************** + * xen.h + * + * Guest OS interface to Xen. + * + * Copyright (c) 2004, K A Fraser + */ + +#define DOMID_SELF (0x7FF0U) + +/* Guest handles for primitive C types. */ +DEFINE_XEN_GUEST_HANDLE(char); +__DEFINE_XEN_GUEST_HANDLE(uchar, unsigned char); +DEFINE_XEN_GUEST_HANDLE(int); +__DEFINE_XEN_GUEST_HANDLE(uint, unsigned int); +DEFINE_XEN_GUEST_HANDLE(long); +__DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long); +DEFINE_XEN_GUEST_HANDLE(void); + +DEFINE_XEN_GUEST_HANDLE(u64); +DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); + +__DEFINE_XEN_GUEST_HANDLE(u8, u8); +__DEFINE_XEN_GUEST_HANDLE(u16, u16); +__DEFINE_XEN_GUEST_HANDLE(u32, u32); + +#define __HYPERVISOR_xen_version 17 + #endif
PAGE_SHIFT is used by both Virtio and Xen as a contant when moving addresses from guest space to machine space, in order to have a single definition PAGE_SHIFT has been moved to memmap.h. This has no impact on neither virtio or xen.
Signed-off-by: Daniel Castro evil.dani@gmail.com --- src/memmap.h | 2 ++ src/virtio-ring.h | 2 +- 2 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/src/memmap.h b/src/memmap.h index 01c7ddb..8674168 100644 --- a/src/memmap.h +++ b/src/memmap.h @@ -21,6 +21,8 @@ void memmap_finalize(void);
// A typical OS page size #define PAGE_SIZE 4096 +//Used by Virtio and Xen +#define PAGE_SHIFT 12
// e820 map storage (defined in system.c) extern struct e820entry e820_list[]; diff --git a/src/virtio-ring.h b/src/virtio-ring.h index b7a7aaf..fd30778 100644 --- a/src/virtio-ring.h +++ b/src/virtio-ring.h @@ -4,7 +4,7 @@ #include "types.h" // u64 #include "memmap.h" // PAGE_SIZE
-#define PAGE_SHIFT 12 + #define PAGE_MASK (PAGE_SIZE-1)
#define virt_to_phys(v) (unsigned long)(v)
PAGE_SHIFT can now be used as a contant instead of "<< 12".
Signed-off-by: Daniel Castro evil.dani@gmail.com --- src/xen.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/xen.c b/src/xen.c index 4072793..5e93a41 100644 --- a/src/xen.c +++ b/src/xen.c @@ -96,7 +96,7 @@ void xen_init_hypercalls(void)
dprintf(1, "Allocated Xen hypercall page at %lx\n", xen_hypercall_page); for ( i = 0; i < eax; i++ ) - wrmsr(ebx, xen_hypercall_page + (i << 12) + i); + wrmsr(ebx, xen_hypercall_page + (i << PAGE_SHIFT) + i);
/* Print version information. */ cpuid(xen_cpuid_base + 1, &eax, &ebx, &ecx, &edx);
Added support for interdomain event_channels headers
Signed-off-by: Daniel Castro evil.dani@gmail.com --- src/xen.h | 27 +++++++++++++++++++++++++++ 1 files changed, 27 insertions(+), 0 deletions(-)
diff --git a/src/xen.h b/src/xen.h index f65078a..b6b72b9 100644 --- a/src/xen.h +++ b/src/xen.h @@ -99,6 +99,7 @@ typedef unsigned long xen_pfn_t; (type)__res; \ })
+ /****************************************************************************** * * The following interface definitions are taken from Xen and have the @@ -186,5 +187,31 @@ __DEFINE_XEN_GUEST_HANDLE(u16, u16); __DEFINE_XEN_GUEST_HANDLE(u32, u32);
#define __HYPERVISOR_xen_version 17 +#define __HYPERVISOR_event_channel_op 32 + +/****************************************************************************** + * event_channel.h + * + * Event channels between domains. + * + * Copyright (c) 2003-2004, K A Fraser. + */ + +typedef u32 evtchn_port_t; +DEFINE_XEN_GUEST_HANDLE(evtchn_port_t); + +#define EVTCHNOP_send 4 +struct evtchn_send { + /* IN parameters. */ + evtchn_port_t port; +}; +typedef struct evtchn_send evtchn_send_t;
+/* + * Wrappers for hypercalls + */ +static inline int hypercall_event_channel_op(int cmd, void *arg) +{ + return _hypercall2(int, event_channel_op, cmd, arg); +} #endif
Added support for hvm_op and hvm_params hypercalls.
Signed-off-by: Daniel Castro evil.dani@gmail.com --- src/xen.h | 31 +++++++++++++++++++++++++++++++ 1 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/src/xen.h b/src/xen.h index b6b72b9..9e218fc 100644 --- a/src/xen.h +++ b/src/xen.h @@ -188,6 +188,33 @@ __DEFINE_XEN_GUEST_HANDLE(u32, u32);
#define __HYPERVISOR_xen_version 17 #define __HYPERVISOR_event_channel_op 32 +#define __HYPERVISOR_hvm_op 34 + +/* + * from: xen/include/public/hvm/hvm_op.h + */ + +/* + * in an HVM guest you find your xenstore ring and evtchn via hvmparams, + * HVM_PARAM_STORE_PFN and HVM_PARAM_STORE_EVTCHN. + * it's a hypercall (type) hvmop, subcommand HVMOP_get_param (this is the hypercall actually) with this: + * Get/set subcommands: extra argument == pointer to xen_hvm_param struct. +*/ +#define HVMOP_set_param 0 +#define HVMOP_get_param 1 + +/* + * from: include/public/hvm/params.h + */ + +#define HVM_PARAM_STORE_PFN 1 //pass as index +#define HVM_PARAM_STORE_EVTCHN 2 //pass as index + +struct xen_hvm_param { + u32 domid; //IN + u32 index; //IN + u64 value; //IN/OUT +};
/****************************************************************************** * event_channel.h @@ -210,6 +237,10 @@ typedef struct evtchn_send evtchn_send_t; /* * Wrappers for hypercalls */ +static inline int hypercall_hvm_op(int cmd, void *arg) +{ + return _hypercall2(int, hvm_op, cmd, arg); +} static inline int hypercall_event_channel_op(int cmd, void *arg) { return _hypercall2(int, event_channel_op, cmd, arg);
Adds support via hypercalls to change memory mapping, get shared_info and get the grant table from the hypervisor.
Signed-off-by: Daniel Castro evil.dani@gmail.com --- src/xen.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 41 insertions(+), 0 deletions(-)
diff --git a/src/xen.h b/src/xen.h index 9e218fc..de2b1ef 100644 --- a/src/xen.h +++ b/src/xen.h @@ -186,6 +186,7 @@ __DEFINE_XEN_GUEST_HANDLE(u8, u8); __DEFINE_XEN_GUEST_HANDLE(u16, u16); __DEFINE_XEN_GUEST_HANDLE(u32, u32);
+#define __HYPERVISOR_memory_op 12 #define __HYPERVISOR_xen_version 17 #define __HYPERVISOR_event_channel_op 32 #define __HYPERVISOR_hvm_op 34 @@ -234,6 +235,41 @@ struct evtchn_send { }; typedef struct evtchn_send evtchn_send_t;
+/****************************************************************************** + * memory.h + * + * Memory reservation and information. + * + * Copyright (c) 2005, Keir Fraser keir@xensource.com + */ +/* + * Sets the GPFN at which a particular page appears in the specified guest's + * pseudophysical address space. + * arg == addr of xen_add_to_physmap_t. + */ +#define XENMEM_add_to_physmap 7 +struct xen_add_to_physmap { + /* Which domain to change the mapping for. */ + u64 domid; + + /* Source mapping space. */ +#define XENMAPSPACE_shared_info 0 /* shared info page */ +#define XENMAPSPACE_grant_table 1 /* grant table page */ +#define XENMAPSPACE_gmfn 2 /* GMFN */ + unsigned int space; + +#define XENMAPIDX_grant_table_status 0x80000000 + + /* Index into source mapping space. */ + xen_ulong_t idx; + + /* GPFN where the source mapping page should appear. */ + xen_pfn_t gpfn; +}; +typedef struct xen_add_to_physmap xen_add_to_physmap_t; +DEFINE_XEN_GUEST_HANDLE(xen_add_to_physmap_t); + + /* * Wrappers for hypercalls */ @@ -245,4 +281,9 @@ static inline int hypercall_event_channel_op(int cmd, void *arg) { return _hypercall2(int, event_channel_op, cmd, arg); } +static inline int hypercall_memory_op(int cmd ,void *arg) +{ + return _hypercall2(int, memory_op, cmd ,arg); +} + #endif
Adds support for CPU yield operation until event arrives.
Signed-off-by: Daniel Castro evil.dani@gmail.com --- src/xen.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 41 insertions(+), 0 deletions(-)
diff --git a/src/xen.h b/src/xen.h index de2b1ef..b70593a 100644 --- a/src/xen.h +++ b/src/xen.h @@ -188,6 +188,7 @@ __DEFINE_XEN_GUEST_HANDLE(u32, u32);
#define __HYPERVISOR_memory_op 12 #define __HYPERVISOR_xen_version 17 +#define __HYPERVISOR_sched_op 29 #define __HYPERVISOR_event_channel_op 32 #define __HYPERVISOR_hvm_op 34
@@ -236,6 +237,42 @@ struct evtchn_send { typedef struct evtchn_send evtchn_send_t;
/****************************************************************************** + * sched.h + * + * Scheduler state interactions + * + * Copyright (c) 2005, Keir Fraser keir@xensource.com + */ + + + +/* + * Poll a set of event-channel ports. Return when one or more are pending. An + * optional timeout may be specified. + * @arg == pointer to sched_poll structure. + */ +#define SCHEDOP_poll 3 +struct sched_poll { + XEN_GUEST_HANDLE(evtchn_port_t) ports; + unsigned int nr_ports; + u64 timeout; +}; +typedef struct sched_poll sched_poll_t; +DEFINE_XEN_GUEST_HANDLE(sched_poll_t); + +/* + * Error base + */ +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define EIO 5 /* I/O error */ +#define EACCES 13 /* Permission denied */ +#define EINVAL 22 /* Invalid argument */ +#define ENOSYS 38 /* Function not implemented */ +#define EISCONN 106 /* Transport endpoint is already connected */ + + +/****************************************************************************** * memory.h * * Memory reservation and information. @@ -285,5 +322,9 @@ static inline int hypercall_memory_op(int cmd ,void *arg) { return _hypercall2(int, memory_op, cmd ,arg); } +static inline int hypercall_sched_op(int cmd, void *arg) +{ + return _hypercall2(int, sched_op, cmd, arg); +}
#endif
Shared info page added to complete the functionality to yield the CPU while waiting for event arrival this is used in xenbus.
Xenbus protocol are the structs needed for a xenbus implementation, they are defined in this patch but will be used later on.
Signed-off-by: Daniel Castro evil.dani@gmail.com --- src/bitops.h | 14 +++++ src/xen.c | 18 +++++++ src/xen.h | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 188 insertions(+), 0 deletions(-) create mode 100644 src/bitops.h
diff --git a/src/bitops.h b/src/bitops.h new file mode 100644 index 0000000..550edbb --- /dev/null +++ b/src/bitops.h @@ -0,0 +1,14 @@ +#ifndef _BIT_OPS_H +#define _BIT_OPS_H + +static inline int test_and_clear_bit(int nr, volatile void *addr) +{ + int oldbit; + asm volatile ( + "lock ; btrl %2,%1 ; sbbl %0,%0" + : "=r" (oldbit), "=m" (*(volatile long *)addr) + : "Ir" (nr), "m" (*(volatile long *)addr) : "memory"); + return oldbit; +} + +#endif diff --git a/src/xen.c b/src/xen.c index 5e93a41..9e6c669 100644 --- a/src/xen.c +++ b/src/xen.c @@ -147,3 +147,21 @@ void xen_setup(void) RamSize = maxram; RamSizeOver4G = maxram_over4G; } + +struct shared_info *get_shared_info(void) +{ + static struct shared_info *shared_info = NULL; + struct xen_add_to_physmap xatp; + + if (shared_info != NULL) + return shared_info; + + xatp.domid = DOMID_SELF; + xatp.space = XENMAPSPACE_shared_info; + xatp.idx = 0; + xatp.gpfn = 0xfffffu; + shared_info = (struct shared_info *)(xatp.gpfn << PAGE_SHIFT); + if (hypercall_memory_op(XENMEM_add_to_physmap, &xatp) != 0) + panic("MAP info page fail"); + return shared_info; +} diff --git a/src/xen.h b/src/xen.h index b70593a..06c87b0 100644 --- a/src/xen.h +++ b/src/xen.h @@ -2,6 +2,7 @@ #define __XEN_H
#include "util.h" +#include "config.h"
extern u32 xen_cpuid_base;
@@ -146,6 +147,80 @@ typedef unsigned long xen_pfn_t; #define set_xen_guest_handle_raw(hnd, val) do { (hnd).p = val; } while (0) #define set_xen_guest_handle(hnd, val) set_xen_guest_handle_raw(hnd, val)
+/**** + * This is needed to get the shared info page + ****/ + + +struct arch_shared_info { + unsigned long max_pfn; /* max pfn that appears in table */ + /* Frame containing list of mfns containing list of mfns containing p2m. */ + xen_pfn_t pfn_to_mfn_frame_list_list; + unsigned long nmi_reason; + u64 pad[32]; +}; +typedef struct arch_shared_info arch_shared_info_t; + +struct arch_vcpu_info { + unsigned long cr2; + unsigned long pad[5]; /* sizeof(vcpu_info_t) == 64 */ +}; +typedef struct arch_vcpu_info arch_vcpu_info_t; + +struct vcpu_time_info { + /* + * Updates to the following values are preceded and followed by an + * increment of 'version'. The guest can therefore detect updates by + * looking for changes to 'version'. If the least-significant bit of + * the version number is set then an update is in progress and the guest + * must wait to read a consistent set of values. + * The correct way to interact with the version number is similar to + * Linux's seqlock: see the implementations of read_seqbegin/read_seqretry. + */ + u32 version; + u32 pad0; + u64 tsc_timestamp; /* TSC at last update of time vals. */ + u64 system_time; /* Time, in nanosecs, since boot. */ + /* + * Current system time: + * system_time + + * ((((tsc - tsc_timestamp) << tsc_shift) * tsc_to_system_mul) >> 32) + * CPU frequency (Hz): + * ((10^9 << 32) / tsc_to_system_mul) >> tsc_shift + */ + u32 tsc_to_system_mul; + u8 tsc_shift; + u8 pad1[3]; +}; /* 32 bytes */ +typedef struct vcpu_time_info vcpu_time_info_t; + + +struct vcpu_info { + u8 evtchn_upcall_pending; + u8 evtchn_upcall_mask; + unsigned long evtchn_pending_sel; + struct arch_vcpu_info arch; + struct vcpu_time_info time; +}; /*64 bytes (x86)*/ + +#define XEN_LEGACY_MAX_VCPUS 32 + +struct shared_info { + struct vcpu_info vcpu_info[XEN_LEGACY_MAX_VCPUS]; + unsigned long evtchn_pending[sizeof(unsigned long) * 8]; + unsigned long evtchn_mask[sizeof(unsigned long) * 8]; + u32 wc_version; /* Version counter: see vcpu_time_info_t. */ + u32 wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */ + u32 wc_nsec; /* Nsecs 00:00:00 UTC, Jan 1, 1970. */ + + struct arch_shared_info arch; + +}; +typedef struct shared_info shared_info_t; + + +struct shared_info *get_shared_info(void); + /****************************************************************************** * version.h * @@ -218,6 +293,7 @@ struct xen_hvm_param { u64 value; //IN/OUT };
+ /****************************************************************************** * event_channel.h * @@ -271,6 +347,86 @@ DEFINE_XEN_GUEST_HANDLE(sched_poll_t); #define ENOSYS 38 /* Function not implemented */ #define EISCONN 106 /* Transport endpoint is already connected */
+/* + * xs_wire.h + * Details of the "wire" protocol between Xen Store Daemon and client + * library or guest kernel. + * + * Copyright (C) 2005 Rusty Russell IBM Corporation + */ +#define XENSTORE_PAYLOAD_MAX 4096 + +enum xsd_sockmsg_type +{ + XS_DEBUG, + XS_DIRECTORY, + XS_READ, + XS_GET_PERMS, + XS_WATCH, + XS_UNWATCH, + XS_TRANSACTION_START, + XS_TRANSACTION_END, + XS_INTRODUCE, + XS_RELEASE, + XS_GET_DOMAIN_PATH, + XS_WRITE, + XS_MKDIR, + XS_RM, + XS_SET_PERMS, + XS_WATCH_EVENT, + XS_ERROR, + XS_IS_DOMAIN_INTRODUCED, + XS_RESUME, + XS_SET_TARGET, + XS_RESTRICT +}; + +#define XS_WRITE_NONE "NONE" +#define XS_WRITE_CREATE "CREATE" +#define XS_WRITE_CREATE_EXCL "CREATE|EXCL" + +/* We hand errors as strings, for portability. */ +struct xsd_errors +{ + int errnum; + const char *errstring; +}; + +struct xsd_sockmsg +{ + u32 type; /* XS_??? */ + u32 req_id;/* Request identifier, echoed in daemon's response. */ + u32 tx_id; /* Transaction id (0 if not related to a transaction). */ + u32 len; /* Length of data following this. */ + + /* Generally followed by nul-terminated string(s). */ +}; + +enum xs_watch_type +{ + XS_WATCH_PATH = 0, + XS_WATCH_TOKEN +}; + +/* Inter-domain shared memory communications. */ +#define XENSTORE_RING_SIZE 1024 +typedef u32 XENSTORE_RING_IDX; +#define MASK_XENSTORE_IDX(idx) ((idx) & (XENSTORE_RING_SIZE-1)) +struct xenstore_domain_interface { + char req[XENSTORE_RING_SIZE]; /* Requests to xenstore daemon. */ + char rsp[XENSTORE_RING_SIZE]; /* Replies and async watch events. */ + XENSTORE_RING_IDX req_cons, req_prod; + XENSTORE_RING_IDX rsp_cons, rsp_prod; +}; + +#define XSD_ERROR(x) { x, #x } +static struct xsd_errors __attribute__ ((unused)) xsd_errors[] + = { + XSD_ERROR(EINVAL), + XSD_ERROR(EACCES), + XSD_ERROR(EIO), + XSD_ERROR(EISCONN) +};
/****************************************************************************** * memory.h
Communication with Xenstore is now possible via xenbus. Initially only xenstore_read and xenstore_directory are provided, but more operations will be added. Xenbus rings are initialized on post.c hardware init.
Signed-off-by: Daniel Castro evil.dani@gmail.com --- Makefile | 2 +- src/post.c | 2 + src/xen-xs.c | 243 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/xen-xs.h | 8 ++ 4 files changed, 254 insertions(+), 1 deletions(-) create mode 100644 src/xen-xs.c create mode 100644 src/xen-xs.h
diff --git a/Makefile b/Makefile index 109091b..e4dd814 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ SRC16=$(SRCBOTH) system.c disk.c font.c SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \ acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \ lzmadecode.c bootsplash.c jpeg.c usb-hub.c paravirt.c \ - biostables.c xen.c bmp.c + biostables.c xen.c bmp.c xen-xs.c SRC32SEG=util.c output.c pci.c pcibios.c apm.c stacks.c
cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \ diff --git a/src/post.c b/src/post.c index e195e89..be8f5ed 100644 --- a/src/post.c +++ b/src/post.c @@ -26,6 +26,7 @@ #include "xen.h" // xen_probe_hvm_info #include "ps2port.h" // ps2port_setup #include "virtio-blk.h" // virtio_blk_setup +#include "xen-xs.h"
/**************************************************************** @@ -190,6 +191,7 @@ init_hw(void) cbfs_payload_setup(); ramdisk_setup(); virtio_blk_setup(); + xenbus_setup(); }
// Begin the boot process by invoking an int0x19 in 16bit mode. diff --git a/src/xen-xs.c b/src/xen-xs.c new file mode 100644 index 0000000..d4b6b26 --- /dev/null +++ b/src/xen-xs.c @@ -0,0 +1,243 @@ +/* + * xenbus.c: static, synchronous, read-only xenbus client for hvmloader. + * + * Copyright (c) 2009 Tim Deegan, Citrix Systems (R&D) Ltd. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "xen.h" // hypercalls +#include "config.h" // CONFIG_* +#include "util.h" +#include "bitops.h" +#include "memmap.h" + + +static struct xenstore_domain_interface *rings; /* Shared ring with dom0 */ +static evtchn_port_t event; /* Event-channel to dom0 */ +static char payload[XENSTORE_PAYLOAD_MAX + 1]; /* Unmarshalling area */ + + +/* + * Connect our xenbus client to the backend. + * Call once, before any other xenbus actions. + */ +void xenbus_setup(void) +{ + struct xen_hvm_param param; + if (!CONFIG_XEN) + return; + + /* Ask Xen where the xenbus shared page is. */ + param.domid = DOMID_SELF; + param.index = HVM_PARAM_STORE_PFN; + if (hypercall_hvm_op(HVMOP_get_param, ¶m)) + panic("Error on setup"); + rings = (void *) (unsigned long) (param.value << PAGE_SHIFT); + + /* Ask Xen where the xenbus event channel is. */ + param.domid = DOMID_SELF; + param.index = HVM_PARAM_STORE_EVTCHN; + if (hypercall_hvm_op(HVMOP_get_param, ¶m)) + panic("error on hypercall to define rings and channel"); + event = param.value; + dprintf(1,"Xenbus rings @0x%lx, event channel %lu\n", + (unsigned long) rings, (unsigned long) event); +} + +/* + * Reset the xenbus connection + */ +void xenbus_shutdown(void) +{ + if (rings == NULL) + panic("rings not defined"); + memset(rings, 0, sizeof *rings); + memset(get_shared_info(), 0, 1024); + rings = NULL; +} + +/* + * 1. Get xen shared info + * 2. get the guest event handle + * 3. while no events pending + * 4 .issue a yield to the CPU until event arrives + */ +static void ring_wait(void) +{ + struct shared_info *shinfo = get_shared_info(); + struct sched_poll poll; + + memset(&poll, 0, sizeof(poll)); + set_xen_guest_handle(poll.ports, &event); + poll.nr_ports = 1; + + while (!test_and_clear_bit(event, shinfo->evtchn_pending)) + hypercall_sched_op(SCHEDOP_poll, &poll); +} + +/* + * Writes data to xenstore ring + */ +static void ring_write(char *data, u32 len) +{ + u32 part; + + if (len >= XENSTORE_PAYLOAD_MAX) + panic("Write Error on RINGS, more data than available buffer"); + + while (len) + { + while ((part = (XENSTORE_RING_SIZE - 1) - + MASK_XENSTORE_IDX(rings->req_prod - rings->req_cons)) == 0) { + ring_wait(); + //The ring is not empty or not ready + } + if (part > (XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(rings->req_prod))) + part = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(rings->req_prod); + + if (part > len) /* Don't write more than we were asked for */ + part = len; + memcpy(rings->req + MASK_XENSTORE_IDX(rings->req_prod), data, part); + barrier(); + rings->req_prod += part; + len -= part; + } +} + +/* + * reads response from xenstore ring + */ +static void ring_read(char *data, u32 len) +{ + u32 part; + + if (len >= XENSTORE_PAYLOAD_MAX) + panic("RING READ ERROR, more data that buffer space on rings"); + + while (len) { + while ((part = MASK_XENSTORE_IDX(rings->rsp_prod -rings->rsp_cons)) == 0) { + ring_wait(); //The ring is not ready or not empty + } + /* Don't overrun the end of the ring */ + if (part > (XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(rings->rsp_cons))) + part = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(rings->rsp_cons); + + if (part > len) /* Don't read more than we were asked for */ + part = len; + memcpy(data, rings->rsp + MASK_XENSTORE_IDX(rings->rsp_cons), part); + barrier(); + rings->rsp_cons += part; + len -= part; + } +} + + +/* + * Send a request and wait for the answer. + * Returns 0 for success, or an errno for error. + */ +static int xenbus_send(u32 type, u32 len, char *data, + u32 *reply_len, char **reply_data) +{ + struct xsd_sockmsg hdr; + evtchn_send_t send; + int i,ret; + + /* Not acceptable to use xenbus before setting it up */ + if (rings == NULL) + panic("XENBUS rings not defined\n"); + + /* Put the request on the ring */ + hdr.type = type; + /* We only ever issue one request at a time */ + hdr.req_id = 222; + /* We never use transactions */ + hdr.tx_id = 0; + hdr.len = len; + ring_write((char *) &hdr, sizeof hdr); + ring_write(data, len); + /* Tell the other end about the request */ + send.port = event; + ret = hypercall_event_channel_op(EVTCHNOP_send, &send); + dprintf(1,"Hypercall event channel notification %d\n",ret); + /* Properly we should poll the event channel now but that involves + * mapping the shared-info page and handling the bitmaps. */ + /* Pull the reply off the ring */ + ring_read((char *) &hdr, sizeof(hdr)); + ring_read(payload, hdr.len); + /* For sanity's sake, nul-terminate the answer */ + payload[hdr.len] = '\0'; + /* Handle errors */ + if ( hdr.type == XS_ERROR ) + { + *reply_len = 0; + for ( i = 0; i < ((sizeof xsd_errors) / (sizeof xsd_errors[0])); i++ ){ + if ( !strcmp(xsd_errors[i].errstring, payload) ){ + return xsd_errors[i].errnum; + } + } + return EIO; + } + *reply_data = payload; + *reply_len = hdr.len; + return hdr.type; +} + + +/* + * Read a xenstore key. Returns a nul-terminated string (even if the XS + * data wasn't nul-terminated) or NULL. The returned string is in a + * static buffer, so only valid until the next xenstore/xenbus operation. + */ +char * xenstore_read(char *path){ + if (rings == NULL) + panic("rings not defined"); + u32 len = 0; + char *answer = NULL; + + /* Include the nul in the request */ + if ( xenbus_send(XS_READ, strlen(path)+1, path, &len, &answer)== XS_ERROR ){ + return NULL; + } + /* We know xenbus_send() nul-terminates its answer, so just pass it on. */ + return answer; +} + +/* + * Read a xenstore directory. Returns a nul-separeted and nul-terminated string (even if the XS + * data wasn't nul-terminated) or NULL. The returned string is in a + * static buffer, so only valid until the next xenstore/xenbus operation. + * ans_len will tell the caller the length of the response + */ +char * xenstore_directory(char *path, u32 *ans_len){ + if (rings == NULL) + panic("rings not defined"); + char *answer = NULL; + + /* Include the nul in the request */ + if ( xenbus_send(XS_DIRECTORY, strlen(path)+1, path, ans_len, &answer)== XS_ERROR ){ + return NULL; + } + /* We know xenbus_send() nul-terminates its answer, so just pass it on. */ + return answer; +} diff --git a/src/xen-xs.h b/src/xen-xs.h new file mode 100644 index 0000000..91e8da0 --- /dev/null +++ b/src/xen-xs.h @@ -0,0 +1,8 @@ +#ifndef _XEN_XS_H +#define _XEN_XS_H + +void xenbus_setup(void); +char * xenstore_read(char *path); +char * xenstore_directory(char *path, u32 *ans_len); + +#endif
Here is a simple example of xenstore query functionality. Please do not apply this patch.
After the xenbus ring initialization we issue a directory query for the list of virtual block devices attached to the current guest. The answer is displayed in the console. For simplicity we only print the first vbd but we leave a clue that there may be more.
Signed-off-by: Daniel Castro evil.dani@gmail.com --- src/xen-xs.c | 10 +++++++++- src/xen-xs.h | 1 + 2 files changed, 10 insertions(+), 1 deletions(-)
diff --git a/src/xen-xs.c b/src/xen-xs.c index d4b6b26..1173ce2 100644 --- a/src/xen-xs.c +++ b/src/xen-xs.c @@ -36,7 +36,7 @@ static struct xenstore_domain_interface *rings; /* Shared ring with dom0 */ static evtchn_port_t event; /* Event-channel to dom0 */ static char payload[XENSTORE_PAYLOAD_MAX + 1]; /* Unmarshalling area */
- +void test_xenstore(void); /* * Connect our xenbus client to the backend. * Call once, before any other xenbus actions. @@ -62,6 +62,7 @@ void xenbus_setup(void) event = param.value; dprintf(1,"Xenbus rings @0x%lx, event channel %lu\n", (unsigned long) rings, (unsigned long) event); + test_xenstore(); }
/* @@ -241,3 +242,10 @@ char * xenstore_directory(char *path, u32 *ans_len){ /* We know xenbus_send() nul-terminates its answer, so just pass it on. */ return answer; } + +void test_xenstore(void){ + char path[11] = {'d','e','v','i','c','e','/','v','b','d','\0'}; + u32 ans_len; + char * res = xenstore_directory(path,&ans_len); + dprintf(1,"length: %d strlen: %d vdb-id: %s .\n",ans_len,strlen(res),res); +} diff --git a/src/xen-xs.h b/src/xen-xs.h index 91e8da0..6957031 100644 --- a/src/xen-xs.h +++ b/src/xen-xs.h @@ -4,5 +4,6 @@ void xenbus_setup(void); char * xenstore_read(char *path); char * xenstore_directory(char *path, u32 *ans_len); +void test_xenstore(void);
#endif
On Fri, Aug 19, 2011 at 01:08:57AM +0900, Daniel Castro wrote:
As part of Google Summer of Code we are in the process to add Block PV-drivers to Seabios, in order to this, first we have to be able to communicate with xenstore so we can exchange information before the front and back ends connect. To communicate with xenstore we need to make seabios Xen-friendly so support for hypercalls has been added to Seabios. In the next month, Seabios will become a front-end for the block devices, connecting to dom0 back-end block device when used with Xen.
Thanks Daniel.
It looks to me like this patch series adds capabilities that a later patch series will use. The patch series itself looks okay to me (though, I do find the multiple copyright statements in the middle of xen.h confusing). However, I'd like to see the code with the end results before committing the framework code.
-Kevin
On Tue, 2011-08-23 at 21:10 -0400, Kevin O'Connor wrote:
On Fri, Aug 19, 2011 at 01:08:57AM +0900, Daniel Castro wrote:
As part of Google Summer of Code we are in the process to add Block PV-drivers to Seabios, in order to this, first we have to be able to communicate with xenstore so we can exchange information before the front and back ends connect. To communicate with xenstore we need to make seabios Xen-friendly so support for hypercalls has been added to Seabios. In the next month, Seabios will become a front-end for the block devices, connecting to dom0 back-end block device when used with Xen.
Thanks Daniel.
It looks to me like this patch series adds capabilities that a later patch series will use. The patch series itself looks okay to me (though, I do find the multiple copyright statements in the middle of xen.h confusing).
That is a consequence of mashing bits of multiple Xen public headers into a single xen.h. We could fracture it into xen/*.h instead if that would be preferable?
However, I'd like to see the code with the end results before committing the framework code.
-Kevin
SeaBIOS mailing list SeaBIOS@seabios.org http://www.seabios.org/mailman/listinfo/seabios
On Wed, Aug 24, 2011 at 10:10 AM, Kevin O'Connor kevin@koconnor.net wrote:
On Fri, Aug 19, 2011 at 01:08:57AM +0900, Daniel Castro wrote:
As part of Google Summer of Code we are in the process to add Block PV-drivers to Seabios, in order to this, first we have to be able to communicate with xenstore so we can exchange information before the front and back ends connect. To communicate with xenstore we need to make seabios Xen-friendly so support for hypercalls has been added to Seabios. In the next month, Seabios will become a front-end for the block devices, connecting to dom0 back-end block device when used with Xen.
Thanks Daniel.
It looks to me like this patch series adds capabilities that a later patch series will use. The patch series itself looks okay to me (though, I do find the multiple copyright statements in the middle of xen.h confusing). However, I'd like to see the code with the end results before committing the framework code.
Thanks Kevin for your feedback, this is just a milestone we have, this is still a work in progress and hopefully we can submit the whole change soon.
Daniel
-Kevin