]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg/XenBusDxe: Add XenStore client implementation
authorAnthony PERARD <anthony.perard@citrix.com>
Wed, 29 Oct 2014 06:50:50 +0000 (06:50 +0000)
committerjljusten <jljusten@Edk2>
Wed, 29 Oct 2014 06:50:50 +0000 (06:50 +0000)
XenStore is a key/value database, which is running on another virtual
machine. It can be accessed through shared memory. This is a client
implementation.

Change in V3:
- moving xs_wire.h from patch #1 to this patch
- fix return value of XenStoreListDirectory
- Use a timeout to print a debug message if the other side of the
  xenstore ring does not notify through the event channel.
  This is done with the new XenStoreWaitForEvent function.
- Have XenStoreReadReply check status of XenStoreProcessMessage and
  return an error if needed.
- Have XenStoreTalkv return the status of XenStoreReadReply.
- Have a loop to check for the quiescent of the response ring in the
  XenStoreInitComms function. (with a timeout of 5 seconds)
- use the recently introduced XenStore 'closing' feature.

Change in V2:
- Change comment style, from freebsd to ovmf
- Fix type of EventChannel
- Fix debug print, no more cast
- Implement XenStoreDeinit.
- Clean up comments
- Fix few codding style issue
- Add FAIL xenstore status value.

Origin: FreeBSD 10.0
License: This patch adds several files under the MIT licence.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Acked-by: Jordan Justen <jordan.l.justen@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16267 6f19259b-4bc3-4df7-8a09-765794883524

OvmfPkg/Include/IndustryStandard/Xen/io/xs_wire.h [new file with mode: 0644]
OvmfPkg/Include/Protocol/XenBus.h
OvmfPkg/XenBusDxe/XenBusDxe.c
OvmfPkg/XenBusDxe/XenBusDxe.inf
OvmfPkg/XenBusDxe/XenStore.c [new file with mode: 0644]
OvmfPkg/XenBusDxe/XenStore.h [new file with mode: 0644]

diff --git a/OvmfPkg/Include/IndustryStandard/Xen/io/xs_wire.h b/OvmfPkg/Include/IndustryStandard/Xen/io/xs_wire.h
new file mode 100644 (file)
index 0000000..6f302d1
--- /dev/null
@@ -0,0 +1,149 @@
+/*\r
+ * Details of the "wire" protocol between Xen Store Daemon and client\r
+ * library or guest kernel.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a copy\r
+ * of this software and associated documentation files (the "Software"), to\r
+ * deal in the Software without restriction, including without limitation the\r
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\r
+ * sell copies of the Software, and to permit persons to whom the Software is\r
+ * furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in\r
+ * all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\r
+ * DEALINGS IN THE SOFTWARE.\r
+ *\r
+ * Copyright (C) 2005 Rusty Russell IBM Corporation\r
+ */\r
+\r
+#ifndef _XS_WIRE_H\r
+#define _XS_WIRE_H\r
+\r
+enum xsd_sockmsg_type\r
+{\r
+    XS_DEBUG,\r
+    XS_DIRECTORY,\r
+    XS_READ,\r
+    XS_GET_PERMS,\r
+    XS_WATCH,\r
+    XS_UNWATCH,\r
+    XS_TRANSACTION_START,\r
+    XS_TRANSACTION_END,\r
+    XS_INTRODUCE,\r
+    XS_RELEASE,\r
+    XS_GET_DOMAIN_PATH,\r
+    XS_WRITE,\r
+    XS_MKDIR,\r
+    XS_RM,\r
+    XS_SET_PERMS,\r
+    XS_WATCH_EVENT,\r
+    XS_ERROR,\r
+    XS_IS_DOMAIN_INTRODUCED,\r
+    XS_RESUME,\r
+    XS_SET_TARGET,\r
+    XS_RESTRICT,\r
+    XS_RESET_WATCHES,\r
+\r
+    XS_INVALID = 0xffff /* Guaranteed to remain an invalid type */\r
+};\r
+\r
+#define XS_WRITE_NONE "NONE"\r
+#define XS_WRITE_CREATE "CREATE"\r
+#define XS_WRITE_CREATE_EXCL "CREATE|EXCL"\r
+\r
+/* We hand errors as strings, for portability. */\r
+struct xsd_errors\r
+{\r
+    INT32 errnum;\r
+    const CHAR8 *errstring;\r
+};\r
+#ifdef EINVAL\r
+#define XSD_ERROR(x) { x, #x }\r
+/* LINTED: static unused */\r
+static struct xsd_errors xsd_errors[]\r
+#if defined(__GNUC__)\r
+__attribute__((unused))\r
+#endif\r
+    = {\r
+    XSD_ERROR(EINVAL),\r
+    XSD_ERROR(EACCES),\r
+    XSD_ERROR(EEXIST),\r
+    XSD_ERROR(EISDIR),\r
+    XSD_ERROR(ENOENT),\r
+    XSD_ERROR(ENOMEM),\r
+    XSD_ERROR(ENOSPC),\r
+    XSD_ERROR(EIO),\r
+    XSD_ERROR(ENOTEMPTY),\r
+    XSD_ERROR(ENOSYS),\r
+    XSD_ERROR(EROFS),\r
+    XSD_ERROR(EBUSY),\r
+    XSD_ERROR(EAGAIN),\r
+    XSD_ERROR(EISCONN),\r
+    XSD_ERROR(E2BIG)\r
+};\r
+#endif\r
+\r
+struct xsd_sockmsg\r
+{\r
+    UINT32 type;  /* XS_??? */\r
+    UINT32 req_id;/* Request identifier, echoed in daemon's response.  */\r
+    UINT32 tx_id; /* Transaction id (0 if not related to a transaction). */\r
+    UINT32 len;   /* Length of data following this. */\r
+\r
+    /* Generally followed by nul-terminated string(s). */\r
+};\r
+\r
+enum xs_watch_type\r
+{\r
+    XS_WATCH_PATH = 0,\r
+    XS_WATCH_TOKEN\r
+};\r
+\r
+/*\r
+ * `incontents 150 xenstore_struct XenStore wire protocol.\r
+ *\r
+ * Inter-domain shared memory communications. */\r
+#define XENSTORE_RING_SIZE 1024\r
+typedef UINT32 XENSTORE_RING_IDX;\r
+#define MASK_XENSTORE_IDX(idx) ((idx) & (XENSTORE_RING_SIZE-1))\r
+struct xenstore_domain_interface {\r
+    CHAR8 req[XENSTORE_RING_SIZE]; /* Requests to xenstore daemon. */\r
+    CHAR8 rsp[XENSTORE_RING_SIZE]; /* Replies and async watch events. */\r
+    XENSTORE_RING_IDX req_cons, req_prod;\r
+    XENSTORE_RING_IDX rsp_cons, rsp_prod;\r
+    UINT32 server_features; /* Bitmap of features supported by the server */\r
+    UINT32 connection;\r
+};\r
+\r
+/* Violating this is very bad.  See docs/misc/xenstore.txt. */\r
+#define XENSTORE_PAYLOAD_MAX 4096\r
+\r
+/* Violating these just gets you an error back */\r
+#define XENSTORE_ABS_PATH_MAX 3072\r
+#define XENSTORE_REL_PATH_MAX 2048\r
+\r
+/* The ability to reconnect a ring */\r
+#define XENSTORE_SERVER_FEATURE_RECONNECTION 1\r
+\r
+/* Valid values for the connection field */\r
+#define XENSTORE_CONNECTED 0 /* the steady-state */\r
+#define XENSTORE_RECONNECT 1 /* guest has initiated a reconnect */\r
+\r
+#endif /* _XS_WIRE_H */\r
+\r
+/*\r
+ * Local variables:\r
+ * mode: C\r
+ * c-file-style: "BSD"\r
+ * c-basic-offset: 4\r
+ * tab-width: 4\r
+ * indent-tabs-mode: nil\r
+ * End:\r
+ */\r
index 89bf74fbc5bd96612a97573e08b6580771c86921..565d491db697a9831879b157f88e7132899ca73d 100644 (file)
 ///\r
 typedef struct _XENBUS_PROTOCOL XENBUS_PROTOCOL;\r
 \r
+typedef enum xenbus_state XenBusState;\r
+\r
+typedef struct\r
+{\r
+  UINT32 Id;\r
+} XENSTORE_TRANSACTION;\r
+\r
+#define XST_NIL ((XENSTORE_TRANSACTION) { 0 })\r
+\r
+typedef enum {\r
+  XENSTORE_STATUS_SUCCESS = 0,\r
+  XENSTORE_STATUS_FAIL,\r
+  XENSTORE_STATUS_EINVAL,\r
+  XENSTORE_STATUS_EACCES,\r
+  XENSTORE_STATUS_EEXIST,\r
+  XENSTORE_STATUS_EISDIR,\r
+  XENSTORE_STATUS_ENOENT,\r
+  XENSTORE_STATUS_ENOMEM,\r
+  XENSTORE_STATUS_ENOSPC,\r
+  XENSTORE_STATUS_EIO,\r
+  XENSTORE_STATUS_ENOTEMPTY,\r
+  XENSTORE_STATUS_ENOSYS,\r
+  XENSTORE_STATUS_EROFS,\r
+  XENSTORE_STATUS_EBUSY,\r
+  XENSTORE_STATUS_EAGAIN,\r
+  XENSTORE_STATUS_EISCONN,\r
+  XENSTORE_STATUS_E2BIG\r
+} XENSTORE_STATUS;\r
+\r
 \r
 #include <IndustryStandard/Xen/grant_table.h>\r
 \r
index edeb20ef381766383dc015fba2ee17323e193791..679fe3b592e5274d13d0a2aa2d954d50c3e4bf68 100644 (file)
@@ -31,6 +31,7 @@
 \r
 #include "XenHypercall.h"\r
 #include "GrantTable.h"\r
+#include "XenStore.h"\r
 \r
 \r
 ///\r
@@ -346,6 +347,9 @@ XenBusDxeDriverBindingStart (
 \r
   XenGrantTableInit (Dev, MmioAddr);\r
 \r
+  Status = XenStoreInit (Dev);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
   Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,\r
                              NotifyExitBoot,\r
                              (VOID*) Dev,\r
@@ -399,6 +403,7 @@ XenBusDxeDriverBindingStop (
   XENBUS_DEVICE *Dev = mMyDevice;\r
 \r
   gBS->CloseEvent (Dev->ExitBootEvent);\r
+  XenStoreDeinit (Dev);\r
   XenGrantTableDeinit (Dev);\r
 \r
   gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid,\r
index 742b7c615b5ba1f6f0e239bd11cf9bed59a1fa1d..1343808ae3d884850b38775ee24b5693bcc0c27a 100644 (file)
@@ -42,6 +42,8 @@
   GrantTable.h\r
   EventChannel.c\r
   EventChannel.h\r
+  XenStore.c\r
+  XenStore.h\r
 \r
 [Sources.IA32]\r
   Ia32/hypercall.S\r
diff --git a/OvmfPkg/XenBusDxe/XenStore.c b/OvmfPkg/XenBusDxe/XenStore.c
new file mode 100644 (file)
index 0000000..4b99c9c
--- /dev/null
@@ -0,0 +1,1386 @@
+/** @file\r
+  Low-level kernel interface to the XenStore.\r
+\r
+  The XenStore interface is a simple storage system that is a means of\r
+  communicating state and configuration data between the Xen Domain 0\r
+  and the various guest domains.  All configuration data other than\r
+  a small amount of essential information required during the early\r
+  boot process of launching a Xen aware guest, is managed using the\r
+  XenStore.\r
+\r
+  The XenStore is ASCII string based, and has a structure and semantics\r
+  similar to a filesystem.  There are files and directories, the directories\r
+  able to contain files or other directories.  The depth of the hierachy\r
+  is only limited by the XenStore's maximum path length.\r
+\r
+  The communication channel between the XenStore service and other\r
+  domains is via two, guest specific, ring buffers in a shared memory\r
+  area.  One ring buffer is used for communicating in each direction.\r
+  The grant table references for this shared memory are given to the\r
+  guest either via the xen_start_info structure for a fully para-\r
+  virtualized guest, or via HVM hypercalls for a hardware virtualized\r
+  guest.\r
+\r
+  The XenStore communication relies on an event channel and thus\r
+  interrupts.  But under OVMF this XenStore client will pull the\r
+  state of the event channel.\r
+\r
+  Several Xen services depend on the XenStore, most notably the\r
+  XenBus used to discover and manage Xen devices.\r
+\r
+  Copyright (C) 2005 Rusty Russell, IBM Corporation\r
+  Copyright (C) 2009,2010 Spectra Logic Corporation\r
+  Copyright (C) 2014, Citrix Ltd.\r
+\r
+  This file may be distributed separately from the Linux kernel, or\r
+  incorporated into other software packages, subject to the following license:\r
+\r
+  Permission is hereby granted, free of charge, to any person obtaining a copy\r
+  of this source file (the "Software"), to deal in the Software without\r
+  restriction, including without limitation the rights to use, copy, modify,\r
+  merge, publish, distribute, sublicense, and/or sell copies of the Software,\r
+  and to permit persons to whom the Software is furnished to do so, subject to\r
+  the following conditions:\r
+\r
+  The above copyright notice and this permission notice shall be included in\r
+  all copies or substantial portions of the Software.\r
+\r
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\r
+  IN THE SOFTWARE.\r
+**/\r
+\r
+#include "XenStore.h"\r
+\r
+#include <Library/PrintLib.h>\r
+\r
+#include <IndustryStandard/Xen/hvm/params.h>\r
+\r
+#include "XenHypercall.h"\r
+#include "EventChannel.h"\r
+\r
+//\r
+// Private Data Structures\r
+//\r
+\r
+typedef struct {\r
+  CONST VOID  *Data;\r
+  UINTN       Len;\r
+} WRITE_REQUEST;\r
+\r
+/* Register callback to watch subtree (node) in the XenStore. */\r
+#define XENSTORE_WATCH_SIGNATURE SIGNATURE_32 ('X','S','w','a')\r
+struct _XENSTORE_WATCH\r
+{\r
+  UINT32      Signature;\r
+  LIST_ENTRY  Link;\r
+\r
+  /* Path being watched. */\r
+  CHAR8       *Node;\r
+};\r
+\r
+#define XENSTORE_WATCH_FROM_LINK(l) \\r
+  CR (l, XENSTORE_WATCH, Link, XENSTORE_WATCH_SIGNATURE)\r
+\r
+\r
+/**\r
+ * Structure capturing messages received from the XenStore service.\r
+ */\r
+#define XENSTORE_MESSAGE_SIGNATURE SIGNATURE_32 ('X', 'S', 's', 'm')\r
+typedef struct {\r
+  UINT32 Signature;\r
+  LIST_ENTRY Link;\r
+\r
+  struct xsd_sockmsg Header;\r
+\r
+  union {\r
+    /* Queued replies. */\r
+    struct {\r
+      CHAR8 *Body;\r
+    } Reply;\r
+\r
+    /* Queued watch events. */\r
+    struct {\r
+      XENSTORE_WATCH *Handle;\r
+      CONST CHAR8 **Vector;\r
+      UINT32 VectorSize;\r
+    } Watch;\r
+  } u;\r
+} XENSTORE_MESSAGE;\r
+#define XENSTORE_MESSAGE_FROM_LINK(r) \\r
+  CR (r, XENSTORE_MESSAGE, Link, XENSTORE_MESSAGE_SIGNATURE)\r
+\r
+/**\r
+ * Container for all XenStore related state.\r
+ */\r
+typedef struct {\r
+  /**\r
+   * Pointer to shared memory communication structures allowing us\r
+   * to communicate with the XenStore service.\r
+   */\r
+  struct xenstore_domain_interface *XenStore;\r
+\r
+  XENBUS_DEVICE *Dev;\r
+\r
+  /**\r
+   * A list of replies to our requests.\r
+   *\r
+   * The reply list is filled by xs_rcv_thread().  It\r
+   * is consumed by the context that issued the request\r
+   * to which a reply is made.  The requester blocks in\r
+   * XenStoreReadReply ().\r
+   *\r
+   * /note Only one requesting context can be active at a time.\r
+   */\r
+  LIST_ENTRY ReplyList;\r
+\r
+  /** Lock protecting the reply list. */\r
+  EFI_LOCK ReplyLock;\r
+\r
+  /**\r
+   * List of registered watches.\r
+   */\r
+  LIST_ENTRY RegisteredWatches;\r
+\r
+  /** Lock protecting the registered watches list. */\r
+  EFI_LOCK RegisteredWatchesLock;\r
+\r
+  /**\r
+   * List of pending watch callback events.\r
+   */\r
+  LIST_ENTRY WatchEvents;\r
+\r
+  /** Lock protecting the watch calback list. */\r
+  EFI_LOCK WatchEventsLock;\r
+\r
+  /**\r
+   * The event channel for communicating with the\r
+   * XenStore service.\r
+   */\r
+  evtchn_port_t EventChannel;\r
+\r
+  /** Handle for XenStore events. */\r
+  EFI_EVENT EventChannelEvent;\r
+} XENSTORE_PRIVATE;\r
+\r
+//\r
+// Global Data\r
+//\r
+static XENSTORE_PRIVATE xs;\r
+\r
+\r
+//\r
+// Private Utility Functions\r
+//\r
+\r
+/**\r
+  Count and optionally record pointers to a number of NUL terminated\r
+  strings in a buffer.\r
+\r
+  @param Strings  A pointer to a contiguous buffer of NUL terminated strings.\r
+  @param Len      The length of the buffer pointed to by strings.\r
+  @param Dst      An array to store pointers to each string found in strings.\r
+\r
+  @return  A count of the number of strings found.\r
+**/\r
+STATIC\r
+UINT32\r
+ExtractStrings (\r
+  IN  CONST CHAR8 *Strings,\r
+  IN  UINTN       Len,\r
+  OUT CONST CHAR8 **Dst OPTIONAL\r
+  )\r
+{\r
+  UINT32 Num = 0;\r
+  CONST CHAR8 *Ptr;\r
+\r
+  for (Ptr = Strings; Ptr < Strings + Len; Ptr += AsciiStrSize (Ptr)) {\r
+    if (Dst != NULL) {\r
+      *Dst++ = Ptr;\r
+    }\r
+    Num++;\r
+  }\r
+\r
+  return Num;\r
+}\r
+\r
+/**\r
+  Convert a contiguous buffer containing a series of NUL terminated\r
+  strings into an array of pointers to strings.\r
+\r
+  The returned pointer references the array of string pointers which\r
+  is followed by the storage for the string data.  It is the client's\r
+  responsibility to free this storage.\r
+\r
+  The storage addressed by Strings is free'd prior to Split returning.\r
+\r
+  @param Strings  A pointer to a contiguous buffer of NUL terminated strings.\r
+  @param Len      The length of the buffer pointed to by strings.\r
+  @param NumPtr   The number of strings found and returned in the strings\r
+                  array.\r
+\r
+  @return  An array of pointers to the strings found in the input buffer.\r
+**/\r
+STATIC\r
+CONST CHAR8 **\r
+Split (\r
+  IN  CHAR8   *Strings,\r
+  IN  UINTN   Len,\r
+  OUT UINT32  *NumPtr\r
+  )\r
+{\r
+  CONST CHAR8 **Dst;\r
+\r
+  ASSERT(NumPtr != NULL);\r
+  ASSERT(Strings != NULL);\r
+\r
+  /* Protect against unterminated buffers. */\r
+  if (Len > 0) {\r
+    Strings[Len - 1] = '\0';\r
+  }\r
+\r
+  /* Count the Strings. */\r
+  *NumPtr = ExtractStrings (Strings, Len, NULL);\r
+\r
+  /* Transfer to one big alloc for easy freeing by the caller. */\r
+  Dst = AllocatePool (*NumPtr * sizeof (CHAR8 *) + Len);\r
+  CopyMem (&Dst[*NumPtr], Strings, Len);\r
+  FreePool (Strings);\r
+\r
+  /* Extract pointers to newly allocated array. */\r
+  Strings = (CHAR8 *) &Dst[*NumPtr];\r
+  ExtractStrings (Strings, Len, Dst);\r
+\r
+  return (Dst);\r
+}\r
+\r
+/**\r
+  Convert from watch token (unique identifier) to the associated\r
+  internal tracking structure for this watch.\r
+\r
+  @param Tocken  The unique identifier for the watch to find.\r
+\r
+  @return  A pointer to the found watch structure or NULL.\r
+**/\r
+STATIC\r
+XENSTORE_WATCH *\r
+XenStoreFindWatch (\r
+  IN CONST CHAR8 *Token\r
+  )\r
+{\r
+  XENSTORE_WATCH *Watch, *WantedWatch;\r
+  LIST_ENTRY *Entry;\r
+\r
+  WantedWatch = (VOID *) AsciiStrHexToUintn (Token);\r
+\r
+  if (IsListEmpty (&xs.RegisteredWatches)) {\r
+    return NULL;\r
+  }\r
+  for (Entry = GetFirstNode (&xs.RegisteredWatches);\r
+       !IsNull (&xs.RegisteredWatches, Entry);\r
+       Entry = GetNextNode (&xs.RegisteredWatches, Entry)) {\r
+    Watch = XENSTORE_WATCH_FROM_LINK (Entry);\r
+    if (Watch == WantedWatch)\r
+      return Watch;\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+//\r
+// Public Utility Functions\r
+// API comments for these methods can be found in XenStore.h\r
+//\r
+\r
+CHAR8 *\r
+XenStoreJoin (\r
+  IN CONST CHAR8 *DirectoryPath,\r
+  IN CONST CHAR8 *Node\r
+  )\r
+{\r
+  CHAR8 *Buf;\r
+\r
+  /* +1 for '/' and +1 for '\0' */\r
+  Buf = AllocateZeroPool (\r
+          AsciiStrLen (DirectoryPath) + AsciiStrLen (Node) + 2);\r
+  AsciiStrCat (Buf, DirectoryPath);\r
+  if (Node[0] != '\0') {\r
+    AsciiStrCat (Buf, "/");\r
+    AsciiStrCat (Buf, Node);\r
+  }\r
+\r
+  return Buf;\r
+}\r
+\r
+//\r
+// Low Level Communication Management\r
+//\r
+\r
+/**\r
+  Verify that the indexes for a ring are valid.\r
+\r
+  The difference between the producer and consumer cannot\r
+  exceed the size of the ring.\r
+\r
+  @param Cons  The consumer index for the ring to test.\r
+  @param Prod  The producer index for the ring to test.\r
+\r
+  @retval TRUE   If indexes are in range.\r
+  @retval FALSE  If the indexes are out of range.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+XenStoreCheckIndexes (\r
+  XENSTORE_RING_IDX Cons,\r
+  XENSTORE_RING_IDX Prod\r
+  )\r
+{\r
+  return ((Prod - Cons) <= XENSTORE_RING_SIZE);\r
+}\r
+\r
+/**\r
+  Return a pointer to, and the length of, the contiguous\r
+  free region available for output in a ring buffer.\r
+\r
+  @param Cons    The consumer index for the ring.\r
+  @param Prod    The producer index for the ring.\r
+  @param Buffer  The base address of the ring's storage.\r
+  @param LenPtr  The amount of contiguous storage available.\r
+\r
+  @return  A pointer to the start location of the free region.\r
+**/\r
+STATIC\r
+VOID *\r
+XenStoreGetOutputChunk (\r
+  IN  XENSTORE_RING_IDX Cons,\r
+  IN  XENSTORE_RING_IDX Prod,\r
+  IN  CHAR8             *Buffer,\r
+  OUT UINT32            *LenPtr\r
+  )\r
+{\r
+  UINT32 Len;\r
+  Len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX (Prod);\r
+  if ((XENSTORE_RING_SIZE - (Prod - Cons)) < Len) {\r
+    Len = XENSTORE_RING_SIZE - (Prod - Cons);\r
+  }\r
+  *LenPtr = Len;\r
+  return (Buffer + MASK_XENSTORE_IDX (Prod));\r
+}\r
+\r
+/**\r
+  Return a pointer to, and the length of, the contiguous\r
+  data available to read from a ring buffer.\r
+\r
+  @param Cons    The consumer index for the ring.\r
+  @param Prod    The producer index for the ring.\r
+  @param Buffer  The base address of the ring's storage.\r
+  @param LenPtr  The amount of contiguous data available to read.\r
+\r
+  @return  A pointer to the start location of the available data.\r
+**/\r
+STATIC\r
+CONST VOID *\r
+XenStoreGetInputChunk (\r
+  IN  XENSTORE_RING_IDX Cons,\r
+  IN  XENSTORE_RING_IDX Prod,\r
+  IN  CONST CHAR8       *Buffer,\r
+  OUT UINT32            *LenPtr\r
+  )\r
+{\r
+  UINT32 Len;\r
+\r
+  Len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX (Cons);\r
+  if ((Prod - Cons) < Len) {\r
+    Len = Prod - Cons;\r
+  }\r
+  *LenPtr = Len;\r
+  return (Buffer + MASK_XENSTORE_IDX (Cons));\r
+}\r
+\r
+/**\r
+  Wait for an event or timeout.\r
+\r
+  @param Event    Event to wait for.\r
+  @param Timeout  A timeout value in 100ns units.\r
+\r
+  @retval EFI_SUCCESS   Event have been triggered or the current TPL is not\r
+                        TPL_APPLICATION.\r
+  @retval EFI_TIMEOUT   Timeout have expired.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+XenStoreWaitForEvent (\r
+  IN EFI_EVENT Event,\r
+  IN UINT64    Timeout\r
+  )\r
+{\r
+  UINTN Index;\r
+  EFI_STATUS Status;\r
+  EFI_EVENT TimerEvent;\r
+  EFI_EVENT WaitList[2];\r
+\r
+  gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
+  gBS->SetTimer (TimerEvent, TimerRelative, Timeout);\r
+\r
+  WaitList[0] = xs.EventChannelEvent;\r
+  WaitList[1] = TimerEvent;\r
+  Status = gBS->WaitForEvent (2, WaitList, &Index);\r
+  ASSERT (Status != EFI_INVALID_PARAMETER);\r
+  gBS->CloseEvent (TimerEvent);\r
+  if (Status == EFI_UNSUPPORTED) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  if (Index == 1) {\r
+    return EFI_TIMEOUT;\r
+  } else {\r
+    return EFI_SUCCESS;\r
+  }\r
+}\r
+\r
+/**\r
+  Transmit data to the XenStore service.\r
+\r
+  The buffer pointed to by DataPtr is at least Len bytes in length.\r
+\r
+  @param DataPtr  A pointer to the contiguous data to send.\r
+  @param Len      The amount of data to send.\r
+\r
+  @return  On success 0, otherwise an errno value indicating the\r
+           cause of failure.\r
+**/\r
+STATIC\r
+XENSTORE_STATUS\r
+XenStoreWriteStore (\r
+  IN CONST VOID *DataPtr,\r
+  IN UINTN      Len\r
+  )\r
+{\r
+  XENSTORE_RING_IDX Cons, Prod;\r
+  CONST CHAR8 *Data = (CONST CHAR8 *)DataPtr;\r
+\r
+  while (Len != 0) {\r
+    void *Dest;\r
+    UINT32 Available;\r
+\r
+    Cons = xs.XenStore->req_cons;\r
+    Prod = xs.XenStore->req_prod;\r
+    if ((Prod - Cons) == XENSTORE_RING_SIZE) {\r
+      /*\r
+       * Output ring is full. Wait for a ring event.\r
+       *\r
+       * Note that the events from both queues are combined, so being woken\r
+       * does not guarantee that data exist in the read ring.\r
+       */\r
+      EFI_STATUS Status;\r
+\r
+      Status = XenStoreWaitForEvent (xs.EventChannelEvent,\r
+                                     EFI_TIMER_PERIOD_SECONDS (1));\r
+      if (Status == EFI_TIMEOUT) {\r
+        DEBUG ((EFI_D_WARN, "XenStore Write, waiting for a ring event.\n"));\r
+      }\r
+      continue;\r
+    }\r
+\r
+    /* Verify queue sanity. */\r
+    if (!XenStoreCheckIndexes (Cons, Prod)) {\r
+      xs.XenStore->req_cons = xs.XenStore->req_prod = 0;\r
+      return XENSTORE_STATUS_EIO;\r
+    }\r
+\r
+    Dest = XenStoreGetOutputChunk (Cons, Prod, xs.XenStore->req, &Available);\r
+    if (Available > Len) {\r
+      Available = Len;\r
+    }\r
+\r
+    CopyMem (Dest, Data, Available);\r
+    Data += Available;\r
+    Len -= Available;\r
+\r
+    /*\r
+     * The store to the producer index, which indicates\r
+     * to the other side that new data has arrived, must\r
+     * be visible only after our copy of the data into the\r
+     * ring has completed.\r
+     */\r
+    MemoryFence ();\r
+    xs.XenStore->req_prod += Available;\r
+\r
+    /*\r
+     * The other side will see the change to req_prod at the time of the\r
+     * interrupt.\r
+     */\r
+    MemoryFence ();\r
+    XenEventChannelNotify (xs.Dev, xs.EventChannel);\r
+  }\r
+\r
+  return XENSTORE_STATUS_SUCCESS;\r
+}\r
+\r
+/**\r
+  Receive data from the XenStore service.\r
+\r
+  The buffer pointed to by DataPtr is at least Len bytes in length.\r
+\r
+  @param DataPtr  A pointer to the contiguous buffer to receive the data.\r
+  @param Len      The amount of data to receive.\r
+\r
+  @return  On success 0, otherwise an errno value indicating the\r
+           cause of failure.\r
+**/\r
+STATIC\r
+XENSTORE_STATUS\r
+XenStoreReadStore (\r
+  OUT VOID *DataPtr,\r
+  IN  UINTN Len\r
+  )\r
+{\r
+  XENSTORE_RING_IDX Cons, Prod;\r
+  CHAR8 *Data = (CHAR8 *) DataPtr;\r
+\r
+  while (Len != 0) {\r
+    UINT32 Available;\r
+    CONST CHAR8 *Src;\r
+\r
+    Cons = xs.XenStore->rsp_cons;\r
+    Prod = xs.XenStore->rsp_prod;\r
+    if (Cons == Prod) {\r
+      /*\r
+       * Nothing to read. Wait for a ring event.\r
+       *\r
+       * Note that the events from both queues are combined, so being woken\r
+       * does not guarantee that data exist in the read ring.\r
+       */\r
+      EFI_STATUS Status;\r
+\r
+      Status = XenStoreWaitForEvent (xs.EventChannelEvent,\r
+                                     EFI_TIMER_PERIOD_SECONDS (1));\r
+      if (Status == EFI_TIMEOUT) {\r
+        DEBUG ((EFI_D_WARN, "XenStore Read, waiting for a ring event.\n"));\r
+      }\r
+      continue;\r
+    }\r
+\r
+    /* Verify queue sanity. */\r
+    if (!XenStoreCheckIndexes (Cons, Prod)) {\r
+      xs.XenStore->rsp_cons = xs.XenStore->rsp_prod = 0;\r
+      return XENSTORE_STATUS_EIO;\r
+    }\r
+\r
+    Src = XenStoreGetInputChunk (Cons, Prod, xs.XenStore->rsp, &Available);\r
+    if (Available > Len) {\r
+      Available = Len;\r
+    }\r
+\r
+    /*\r
+     * Insure the data we read is related to the indexes\r
+     * we read above.\r
+     */\r
+    MemoryFence ();\r
+\r
+    CopyMem (Data, Src, Available);\r
+    Data += Available;\r
+    Len -= Available;\r
+\r
+    /*\r
+     * Insure that the producer of this ring does not see\r
+     * the ring space as free until after we have copied it\r
+     * out.\r
+     */\r
+    MemoryFence ();\r
+    xs.XenStore->rsp_cons += Available;\r
+\r
+    /*\r
+     * The producer will see the updated consumer index when the event is\r
+     * delivered.\r
+     */\r
+    MemoryFence ();\r
+    XenEventChannelNotify (xs.Dev, xs.EventChannel);\r
+  }\r
+\r
+  return XENSTORE_STATUS_SUCCESS;\r
+}\r
+\r
+//\r
+// Received Message Processing\r
+//\r
+\r
+/**\r
+  Block reading the next message from the XenStore service and\r
+  process the result.\r
+\r
+  @return  XENSTORE_STATUS_SUCCESS on success.  Otherwise an errno value\r
+           indicating the type of failure encountered.\r
+**/\r
+STATIC\r
+XENSTORE_STATUS\r
+XenStoreProcessMessage (\r
+  VOID\r
+  )\r
+{\r
+  XENSTORE_MESSAGE *Message;\r
+  CHAR8 *Body;\r
+  XENSTORE_STATUS Status;\r
+\r
+  Message = AllocateZeroPool (sizeof (XENSTORE_MESSAGE));\r
+  Message->Signature = XENSTORE_MESSAGE_SIGNATURE;\r
+  Status = XenStoreReadStore (&Message->Header, sizeof (Message->Header));\r
+  if (Status != XENSTORE_STATUS_SUCCESS) {\r
+    FreePool (Message);\r
+    DEBUG ((EFI_D_ERROR, "XenStore: Error read store (%d)\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Body = AllocatePool (Message->Header.len + 1);\r
+  Status = XenStoreReadStore (Body, Message->Header.len);\r
+  if (Status != XENSTORE_STATUS_SUCCESS) {\r
+    FreePool (Body);\r
+    FreePool (Message);\r
+    DEBUG ((EFI_D_ERROR, "XenStore: Error read store (%d)\n", Status));\r
+    return Status;\r
+  }\r
+  Body[Message->Header.len] = '\0';\r
+\r
+  if (Message->Header.type == XS_WATCH_EVENT) {\r
+    Message->u.Watch.Vector = Split(Body, Message->Header.len,\r
+                                    &Message->u.Watch.VectorSize);\r
+\r
+    EfiAcquireLock (&xs.RegisteredWatchesLock);\r
+    Message->u.Watch.Handle =\r
+      XenStoreFindWatch (Message->u.Watch.Vector[XS_WATCH_TOKEN]);\r
+    DEBUG ((EFI_D_INFO, "XenStore: Watch event %a\n",\r
+            Message->u.Watch.Vector[XS_WATCH_TOKEN]));\r
+    if (Message->u.Watch.Handle != NULL) {\r
+      EfiAcquireLock (&xs.WatchEventsLock);\r
+      InsertHeadList (&xs.WatchEvents, &Message->Link);\r
+      EfiReleaseLock (&xs.WatchEventsLock);\r
+    } else {\r
+      DEBUG ((EFI_D_WARN, "XenStore: Watch handle %a not found\n",\r
+              Message->u.Watch.Vector[XS_WATCH_TOKEN]));\r
+      FreePool(Message->u.Watch.Vector);\r
+      FreePool(Message);\r
+    }\r
+    EfiReleaseLock (&xs.RegisteredWatchesLock);\r
+  } else {\r
+    Message->u.Reply.Body = Body;\r
+    EfiAcquireLock (&xs.ReplyLock);\r
+    InsertTailList (&xs.ReplyList, &Message->Link);\r
+    EfiReleaseLock (&xs.ReplyLock);\r
+  }\r
+\r
+  return XENSTORE_STATUS_SUCCESS;\r
+}\r
+\r
+//\r
+// XenStore Message Request/Reply Processing\r
+//\r
+\r
+/**\r
+  Convert a XenStore error string into an errno number.\r
+\r
+  Unknown error strings are converted to EINVAL.\r
+\r
+  @param errorstring  The error string to convert.\r
+\r
+  @return  The errno best matching the input string.\r
+\r
+**/\r
+typedef struct {\r
+  XENSTORE_STATUS Status;\r
+  CONST CHAR8 *ErrorStr;\r
+} XenStoreErrors;\r
+\r
+static XenStoreErrors gXenStoreErrors[] = {\r
+  { XENSTORE_STATUS_EINVAL, "EINVAL" },\r
+  { XENSTORE_STATUS_EACCES, "EACCES" },\r
+  { XENSTORE_STATUS_EEXIST, "EEXIST" },\r
+  { XENSTORE_STATUS_EISDIR, "EISDIR" },\r
+  { XENSTORE_STATUS_ENOENT, "ENOENT" },\r
+  { XENSTORE_STATUS_ENOMEM, "ENOMEM" },\r
+  { XENSTORE_STATUS_ENOSPC, "ENOSPC" },\r
+  { XENSTORE_STATUS_EIO, "EIO" },\r
+  { XENSTORE_STATUS_ENOTEMPTY, "ENOTEMPTY" },\r
+  { XENSTORE_STATUS_ENOSYS, "ENOSYS" },\r
+  { XENSTORE_STATUS_EROFS, "EROFS" },\r
+  { XENSTORE_STATUS_EBUSY, "EBUSY" },\r
+  { XENSTORE_STATUS_EAGAIN, "EAGAIN" },\r
+  { XENSTORE_STATUS_EISCONN, "EISCONN" },\r
+  { XENSTORE_STATUS_E2BIG, "E2BIG" }\r
+};\r
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))\r
+\r
+STATIC\r
+XENSTORE_STATUS\r
+XenStoreGetError (\r
+  CONST CHAR8 *ErrorStr\r
+  )\r
+{\r
+  UINT32 Index;\r
+\r
+  for (Index = 0; Index < ARRAY_SIZE(gXenStoreErrors); Index++) {\r
+    if (!AsciiStrCmp (ErrorStr, gXenStoreErrors[Index].ErrorStr)) {\r
+      return gXenStoreErrors[Index].Status;\r
+    }\r
+  }\r
+  DEBUG ((EFI_D_WARN, "XenStore gave unknown error %a\n", ErrorStr));\r
+  return XENSTORE_STATUS_EINVAL;\r
+}\r
+\r
+/**\r
+  Block waiting for a reply to a message request.\r
+\r
+  @param TypePtr The returned type of the reply.\r
+  @param LenPtr  The returned body length of the reply.\r
+  @param Result  The returned body of the reply.\r
+**/\r
+STATIC\r
+XENSTORE_STATUS\r
+XenStoreReadReply (\r
+  OUT enum xsd_sockmsg_type *TypePtr,\r
+  OUT UINT32 *LenPtr OPTIONAL,\r
+  OUT VOID **Result\r
+  )\r
+{\r
+  XENSTORE_MESSAGE *Message;\r
+  LIST_ENTRY *Entry;\r
+  CHAR8 *Body;\r
+\r
+  while (IsListEmpty (&xs.ReplyList)) {\r
+    XENSTORE_STATUS Status;\r
+    Status = XenStoreProcessMessage ();\r
+    if (Status != XENSTORE_STATUS_SUCCESS && Status != XENSTORE_STATUS_EAGAIN) {\r
+      DEBUG ((EFI_D_ERROR, "XenStore, error while reading the ring (%d).",\r
+              Status));\r
+      return Status;\r
+    }\r
+  }\r
+  EfiAcquireLock (&xs.ReplyLock);\r
+  Entry = GetFirstNode (&xs.ReplyList);\r
+  Message = XENSTORE_MESSAGE_FROM_LINK (Entry);\r
+  RemoveEntryList (Entry);\r
+  EfiReleaseLock (&xs.ReplyLock);\r
+\r
+  *TypePtr = Message->Header.type;\r
+  if (LenPtr != NULL) {\r
+    *LenPtr = Message->Header.len;\r
+  }\r
+  Body = Message->u.Reply.Body;\r
+\r
+  FreePool (Message);\r
+  *Result = Body;\r
+  return XENSTORE_STATUS_SUCCESS;\r
+}\r
+\r
+/**\r
+  Send a message with an optionally muti-part body to the XenStore service.\r
+\r
+  @param Transaction    The transaction to use for this request.\r
+  @param RequestType    The type of message to send.\r
+  @param WriteRequest   Pointers to the body sections of the request.\r
+  @param NumRequests    The number of body sections in the request.\r
+  @param LenPtr         The returned length of the reply.\r
+  @param ResultPtr      The returned body of the reply.\r
+\r
+  @return  XENSTORE_STATUS_SUCCESS on success.  Otherwise an errno indicating\r
+           the cause of failure.\r
+**/\r
+STATIC\r
+XENSTORE_STATUS\r
+XenStoreTalkv (\r
+  IN  XENSTORE_TRANSACTION    Transaction,\r
+  IN  enum xsd_sockmsg_type   RequestType,\r
+  IN  CONST WRITE_REQUEST     *WriteRequest,\r
+  IN  UINT32                  NumRequests,\r
+  OUT UINT32                  *LenPtr OPTIONAL,\r
+  OUT VOID                    **ResultPtr OPTIONAL\r
+  )\r
+{\r
+  struct xsd_sockmsg Message;\r
+  void *Return = NULL;\r
+  UINT32 Index;\r
+  XENSTORE_STATUS Status;\r
+\r
+  Message.tx_id = Transaction.Id;\r
+  Message.req_id = 0;\r
+  Message.type = RequestType;\r
+  Message.len = 0;\r
+  for (Index = 0; Index < NumRequests; Index++) {\r
+    Message.len += WriteRequest[Index].Len;\r
+  }\r
+\r
+  Status = XenStoreWriteStore (&Message, sizeof (Message));\r
+  if (Status != XENSTORE_STATUS_SUCCESS) {\r
+    DEBUG ((EFI_D_ERROR, "XenStoreTalkv failed %d\n", Status));\r
+    goto Error;\r
+  }\r
+\r
+  for (Index = 0; Index < NumRequests; Index++) {\r
+    Status = XenStoreWriteStore (WriteRequest[Index].Data, WriteRequest[Index].Len);\r
+    if (Status != XENSTORE_STATUS_SUCCESS) {\r
+      DEBUG ((EFI_D_ERROR, "XenStoreTalkv failed %d\n", Status));\r
+      goto Error;\r
+    }\r
+  }\r
+\r
+  Status = XenStoreReadReply (&Message.type, LenPtr, &Return);\r
+\r
+Error:\r
+  if (Status != XENSTORE_STATUS_SUCCESS) {\r
+    return Status;\r
+  }\r
+\r
+  if (Message.type == XS_ERROR) {\r
+    Status = XenStoreGetError (Return);\r
+    FreePool (Return);\r
+    return Status;\r
+  }\r
+\r
+  /* Reply is either error or an echo of our request message type. */\r
+  ASSERT (Message.type == RequestType);\r
+\r
+  if (ResultPtr) {\r
+    *ResultPtr = Return;\r
+  } else {\r
+    FreePool (Return);\r
+  }\r
+\r
+  return XENSTORE_STATUS_SUCCESS;\r
+}\r
+\r
+/**\r
+  Wrapper for XenStoreTalkv allowing easy transmission of a message with\r
+  a single, contiguous, message body.\r
+\r
+  The returned result is provided in malloced storage and thus must be free'd\r
+  by the caller.\r
+\r
+  @param Transaction    The transaction to use for this request.\r
+  @param RequestType    The type of message to send.\r
+  @param Body           The body of the request.\r
+  @param LenPtr         The returned length of the reply.\r
+  @param Result         The returned body of the reply.\r
+\r
+  @return  0 on success.  Otherwise an errno indicating\r
+           the cause of failure.\r
+**/\r
+STATIC\r
+XENSTORE_STATUS\r
+XenStoreSingle (\r
+  IN  XENSTORE_TRANSACTION    Transaction,\r
+  IN  enum xsd_sockmsg_type   RequestType,\r
+  IN  CONST CHAR8             *Body,\r
+  OUT UINT32                  *LenPtr OPTIONAL,\r
+  OUT VOID                    **Result OPTIONAL\r
+  )\r
+{\r
+  WRITE_REQUEST WriteRequest;\r
+\r
+  WriteRequest.Data = (VOID *) Body;\r
+  WriteRequest.Len = AsciiStrSize (Body);\r
+\r
+  return XenStoreTalkv (Transaction, RequestType, &WriteRequest, 1,\r
+                        LenPtr, Result);\r
+}\r
+\r
+//\r
+// XenStore Watch Support\r
+//\r
+\r
+/**\r
+  Transmit a watch request to the XenStore service.\r
+\r
+  @param Path    The path in the XenStore to watch.\r
+  @param Tocken  A unique identifier for this watch.\r
+\r
+  @return  XENSTORE_STATUS_SUCCESS on success.  Otherwise an errno indicating the\r
+           cause of failure.\r
+**/\r
+STATIC\r
+XENSTORE_STATUS\r
+XenStoreWatch (\r
+  CONST CHAR8 *Path,\r
+  CONST CHAR8 *Token\r
+  )\r
+{\r
+  WRITE_REQUEST WriteRequest[2];\r
+\r
+  WriteRequest[0].Data = (VOID *) Path;\r
+  WriteRequest[0].Len = AsciiStrSize (Path);\r
+  WriteRequest[1].Data = (VOID *) Token;\r
+  WriteRequest[1].Len = AsciiStrSize (Token);\r
+\r
+  return XenStoreTalkv (XST_NIL, XS_WATCH, WriteRequest, 2, NULL, NULL);\r
+}\r
+\r
+/**\r
+  Transmit an uwatch request to the XenStore service.\r
+\r
+  @param Path    The path in the XenStore to watch.\r
+  @param Tocken  A unique identifier for this watch.\r
+\r
+  @return  XENSTORE_STATUS_SUCCESS on success.  Otherwise an errno indicating\r
+           the cause of failure.\r
+**/\r
+STATIC\r
+XENSTORE_STATUS\r
+XenStoreUnwatch (\r
+  CONST CHAR8 *Path,\r
+  CONST CHAR8 *Token\r
+  )\r
+{\r
+  WRITE_REQUEST WriteRequest[2];\r
+\r
+  WriteRequest[0].Data = (VOID *) Path;\r
+  WriteRequest[0].Len = AsciiStrSize (Path);\r
+  WriteRequest[1].Data = (VOID *) Token;\r
+  WriteRequest[1].Len = AsciiStrSize (Token);\r
+\r
+  return XenStoreTalkv (XST_NIL, XS_UNWATCH, WriteRequest, 2, NULL, NULL);\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+NotifyEventChannelCheckForEvent (\r
+  IN EFI_EVENT Event,\r
+  IN VOID *Context\r
+  )\r
+{\r
+  XENSTORE_PRIVATE *xs;\r
+  xs = (XENSTORE_PRIVATE *)Context;\r
+  if (TestAndClearBit (xs->EventChannel, xs->Dev->SharedInfo->evtchn_pending)) {\r
+    gBS->SignalEvent (Event);\r
+  }\r
+}\r
+\r
+/**\r
+  Setup communication channels with the XenStore service.\r
+\r
+  @retval EFI_SUCCESS if everything went well.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+XenStoreInitComms (\r
+  XENSTORE_PRIVATE *xs\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+  EFI_EVENT TimerEvent;\r
+  struct xenstore_domain_interface *XenStore = xs->XenStore;\r
+\r
+  Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
+  Status = gBS->SetTimer (TimerEvent, TimerRelative,\r
+                          EFI_TIMER_PERIOD_SECONDS (5));\r
+  while (XenStore->rsp_prod != XenStore->rsp_cons) {\r
+    Status = gBS->CheckEvent (TimerEvent);\r
+    if (!EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_WARN, "XENSTORE response ring is not quiescent "\r
+              "(%08x:%08x): fixing up\n",\r
+              XenStore->rsp_cons, XenStore->rsp_prod));\r
+      XenStore->rsp_cons = XenStore->rsp_prod;\r
+    }\r
+  }\r
+  gBS->CloseEvent (TimerEvent);\r
+\r
+  Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_NOTIFY,\r
+                             NotifyEventChannelCheckForEvent, xs,\r
+                             &xs->EventChannelEvent);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Initialize XenStore.\r
+\r
+  @param Dev  A XENBUS_DEVICE instance.\r
+\r
+  @retval EFI_SUCCESS if everything went well.\r
+**/\r
+EFI_STATUS\r
+XenStoreInit (\r
+  XENBUS_DEVICE *Dev\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+  /**\r
+   * The HVM guest pseudo-physical frame number.  This is Xen's mapping\r
+   * of the true machine frame number into our "physical address space".\r
+   */\r
+  UINTN XenStoreGpfn;\r
+\r
+  xs.Dev = Dev;\r
+\r
+  xs.EventChannel = XenHypercallHvmGetParam (Dev, HVM_PARAM_STORE_EVTCHN);\r
+  XenStoreGpfn = XenHypercallHvmGetParam (Dev, HVM_PARAM_STORE_PFN);\r
+  xs.XenStore = (VOID *) (XenStoreGpfn << EFI_PAGE_SHIFT);\r
+  DEBUG ((EFI_D_INFO, "XenBusInit: XenBus rings @%p, event channel %x\n",\r
+          xs.XenStore, xs.EventChannel));\r
+\r
+  InitializeListHead (&xs.ReplyList);\r
+  InitializeListHead (&xs.WatchEvents);\r
+  InitializeListHead (&xs.RegisteredWatches);\r
+\r
+  EfiInitializeLock (&xs.ReplyLock, TPL_NOTIFY);\r
+  EfiInitializeLock (&xs.RegisteredWatchesLock, TPL_NOTIFY);\r
+  EfiInitializeLock (&xs.WatchEventsLock, TPL_NOTIFY);\r
+\r
+  /* Initialize the shared memory rings to talk to xenstored */\r
+  Status = XenStoreInitComms (&xs);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+VOID\r
+XenStoreDeinit (\r
+  IN XENBUS_DEVICE *Dev\r
+  )\r
+{\r
+  //\r
+  // Emptying the list RegisteredWatches, but this list should already be\r
+  // empty. Every driver that is using Watches should unregister them when\r
+  // it is stopped.\r
+  //\r
+  if (!IsListEmpty (&xs.RegisteredWatches)) {\r
+    XENSTORE_WATCH *Watch;\r
+    LIST_ENTRY *Entry;\r
+    DEBUG ((EFI_D_WARN, "XenStore: RegisteredWatches is not empty, cleaning up..."));\r
+    Entry = GetFirstNode (&xs.RegisteredWatches);\r
+    while (!IsNull (&xs.RegisteredWatches, Entry)) {\r
+      Watch = XENSTORE_WATCH_FROM_LINK (Entry);\r
+      Entry = GetNextNode (&xs.RegisteredWatches, Entry);\r
+\r
+      XenStoreUnregisterWatch (Watch);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Emptying the list WatchEvents, but this list should already be empty after\r
+  // having cleanup the list RegisteredWatches.\r
+  //\r
+  if (!IsListEmpty (&xs.WatchEvents)) {\r
+    LIST_ENTRY *Entry;\r
+    DEBUG ((EFI_D_WARN, "XenStore: WatchEvents is not empty, cleaning up..."));\r
+    Entry = GetFirstNode (&xs.WatchEvents);\r
+    while (!IsNull (&xs.WatchEvents, Entry)) {\r
+      XENSTORE_MESSAGE *Message = XENSTORE_MESSAGE_FROM_LINK (Entry);\r
+      Entry = GetNextNode (&xs.WatchEvents, Entry);\r
+      RemoveEntryList (&Message->Link);\r
+      FreePool (Message->u.Watch.Vector);\r
+      FreePool (Message);\r
+    }\r
+  }\r
+\r
+  if (!IsListEmpty (&xs.ReplyList)) {\r
+    XENSTORE_MESSAGE *Message;\r
+    LIST_ENTRY *Entry;\r
+    Entry = GetFirstNode (&xs.ReplyList);\r
+    while (!IsNull (&xs.ReplyList, Entry)) {\r
+      Message = XENSTORE_MESSAGE_FROM_LINK (Entry);\r
+      Entry = GetNextNode (&xs.ReplyList, Entry);\r
+      RemoveEntryList (&Message->Link);\r
+      FreePool (Message->u.Reply.Body);\r
+      FreePool (Message);\r
+    }\r
+  }\r
+\r
+  gBS->CloseEvent (xs.EventChannelEvent);\r
+\r
+  if (xs.XenStore->server_features & XENSTORE_SERVER_FEATURE_RECONNECTION) {\r
+    xs.XenStore->connection = XENSTORE_RECONNECT;\r
+    XenEventChannelNotify (xs.Dev, xs.EventChannel);\r
+    while (*(volatile UINT32*)&xs.XenStore->connection == XENSTORE_RECONNECT) {\r
+      XenStoreWaitForEvent (xs.EventChannelEvent, EFI_TIMER_PERIOD_MILLISECONDS (100));\r
+    }\r
+  } else {\r
+    /* If the backend reads the state while we're erasing it then the\r
+     * ring state will become corrupted, preventing guest frontends from\r
+     * connecting. This is rare. To help diagnose the failure, we fill\r
+     * the ring with XS_INVALID packets. */\r
+    SetMem (xs.XenStore->req, XENSTORE_RING_SIZE, 0xff);\r
+    SetMem (xs.XenStore->rsp, XENSTORE_RING_SIZE, 0xff);\r
+    xs.XenStore->req_cons = xs.XenStore->req_prod = 0;\r
+    xs.XenStore->rsp_cons = xs.XenStore->rsp_prod = 0;\r
+  }\r
+  xs.XenStore = NULL;\r
+}\r
+\r
+//\r
+// Public API\r
+// API comments for these methods can be found in XenStore.h\r
+//\r
+\r
+XENSTORE_STATUS\r
+XenStoreListDirectory (\r
+  IN  XENSTORE_TRANSACTION  Transaction,\r
+  IN  CONST CHAR8           *DirectoryPath,\r
+  IN  CONST CHAR8           *Node,\r
+  OUT UINT32                *DirectoryCountPtr,\r
+  OUT CONST CHAR8           ***DirectoryListPtr\r
+  )\r
+{\r
+  CHAR8 *Path;\r
+  CHAR8 *TempStr;\r
+  UINT32 Len = 0;\r
+  XENSTORE_STATUS Status;\r
+\r
+  Path = XenStoreJoin (DirectoryPath, Node);\r
+  Status = XenStoreSingle (Transaction, XS_DIRECTORY, Path, &Len,\r
+                           (VOID **) &TempStr);\r
+  FreePool (Path);\r
+  if (Status != XENSTORE_STATUS_SUCCESS) {\r
+    return Status;\r
+  }\r
+\r
+  *DirectoryListPtr = Split (TempStr, Len, DirectoryCountPtr);\r
+\r
+  return XENSTORE_STATUS_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+XenStorePathExists (\r
+  IN XENSTORE_TRANSACTION  Transaction,\r
+  IN CONST CHAR8           *Directory,\r
+  IN CONST CHAR8           *Node\r
+  )\r
+{\r
+  CONST CHAR8 **TempStr;\r
+  XENSTORE_STATUS Status;\r
+  UINT32 TempNum;\r
+\r
+  Status = XenStoreListDirectory (Transaction, Directory, Node,\r
+                                  &TempNum, &TempStr);\r
+  if (Status != XENSTORE_STATUS_SUCCESS) {\r
+    return FALSE;\r
+  }\r
+  FreePool (TempStr);\r
+  return TRUE;\r
+}\r
+\r
+XENSTORE_STATUS\r
+XenStoreRead (\r
+  IN  XENSTORE_TRANSACTION    Transaction,\r
+  IN  CONST CHAR8             *DirectoryPath,\r
+  IN  CONST CHAR8             *Node,\r
+  OUT UINT32                  *LenPtr OPTIONAL,\r
+  OUT VOID                    **Result\r
+  )\r
+{\r
+  CHAR8 *Path;\r
+  VOID *Value;\r
+  XENSTORE_STATUS Status;\r
+\r
+  Path = XenStoreJoin (DirectoryPath, Node);\r
+  Status = XenStoreSingle (Transaction, XS_READ, Path, LenPtr, &Value);\r
+  FreePool (Path);\r
+  if (Status != XENSTORE_STATUS_SUCCESS) {\r
+    return Status;\r
+  }\r
+\r
+  *Result = Value;\r
+  return XENSTORE_STATUS_SUCCESS;\r
+}\r
+\r
+XENSTORE_STATUS\r
+XenStoreWrite (\r
+  IN XENSTORE_TRANSACTION  Transaction,\r
+  IN CONST CHAR8           *DirectoryPath,\r
+  IN CONST CHAR8           *Node,\r
+  IN CONST CHAR8           *Str\r
+  )\r
+{\r
+  CHAR8 *Path;\r
+  WRITE_REQUEST WriteRequest[2];\r
+  XENSTORE_STATUS Status;\r
+\r
+  Path = XenStoreJoin (DirectoryPath, Node);\r
+\r
+  WriteRequest[0].Data = (VOID *) Path;\r
+  WriteRequest[0].Len = AsciiStrSize (Path);\r
+  WriteRequest[1].Data = (VOID *) Str;\r
+  WriteRequest[1].Len = AsciiStrLen (Str);\r
+\r
+  Status = XenStoreTalkv (Transaction, XS_WRITE, WriteRequest, 2, NULL, NULL);\r
+  FreePool (Path);\r
+\r
+  return Status;\r
+}\r
+\r
+XENSTORE_STATUS\r
+XenStoreRemove (\r
+  IN XENSTORE_TRANSACTION   Transaction,\r
+  IN CONST CHAR8            *DirectoryPath,\r
+  IN CONST CHAR8            *Node\r
+  )\r
+{\r
+  CHAR8 *Path;\r
+  XENSTORE_STATUS Status;\r
+\r
+  Path = XenStoreJoin (DirectoryPath, Node);\r
+  Status = XenStoreSingle (Transaction, XS_RM, Path, NULL, NULL);\r
+  FreePool (Path);\r
+\r
+  return Status;\r
+}\r
+\r
+XENSTORE_STATUS\r
+XenStoreTransactionStart (\r
+  OUT XENSTORE_TRANSACTION  *Transaction\r
+  )\r
+{\r
+  CHAR8 *IdStr;\r
+  XENSTORE_STATUS Status;\r
+\r
+  Status = XenStoreSingle (XST_NIL, XS_TRANSACTION_START, "", NULL,\r
+                           (VOID **) &IdStr);\r
+  if (Status == XENSTORE_STATUS_SUCCESS) {\r
+    Transaction->Id = AsciiStrDecimalToUintn (IdStr);\r
+    FreePool (IdStr);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+XENSTORE_STATUS\r
+XenStoreTransactionEnd (\r
+  IN XENSTORE_TRANSACTION   Transaction,\r
+  IN BOOLEAN                Abort\r
+  )\r
+{\r
+  CHAR8 AbortStr[2];\r
+\r
+  if (Abort) {\r
+    AsciiStrCpy (AbortStr, "F");\r
+  } else {\r
+    AsciiStrCpy (AbortStr, "T");\r
+  }\r
+\r
+  return XenStoreSingle (Transaction, XS_TRANSACTION_END, AbortStr, NULL, NULL);\r
+}\r
+\r
+XENSTORE_STATUS\r
+XenStoreVSPrint (\r
+  IN XENSTORE_TRANSACTION  Transaction,\r
+  IN CONST CHAR8           *DirectoryPath,\r
+  IN CONST CHAR8           *Node,\r
+  IN CONST CHAR8           *FormatString,\r
+  IN VA_LIST               Marker\r
+  )\r
+{\r
+  CHAR8 *Buf;\r
+  XENSTORE_STATUS Status;\r
+  UINTN BufSize;\r
+\r
+  BufSize = SPrintLengthAsciiFormat (FormatString, Marker) + 1;\r
+  Buf = AllocateZeroPool (BufSize);\r
+  AsciiVSPrint (Buf, BufSize, FormatString, Marker);\r
+  Status = XenStoreWrite (Transaction, DirectoryPath, Node, Buf);\r
+  FreePool (Buf);\r
+\r
+  return Status;\r
+}\r
+\r
+XENSTORE_STATUS\r
+EFIAPI\r
+XenStoreSPrint (\r
+  IN XENSTORE_TRANSACTION   Transaction,\r
+  IN CONST CHAR8            *DirectoryPath,\r
+  IN CONST CHAR8            *Node,\r
+  IN CONST CHAR8            *FormatString,\r
+  ...\r
+  )\r
+{\r
+  VA_LIST Marker;\r
+  XENSTORE_STATUS Status;\r
+\r
+  VA_START (Marker, FormatString);\r
+  Status = XenStoreVSPrint (Transaction, DirectoryPath, Node, FormatString, Marker);\r
+  VA_END (Marker);\r
+\r
+  return Status;\r
+}\r
+\r
+XENSTORE_STATUS\r
+XenStoreRegisterWatch (\r
+  IN CONST CHAR8      *DirectoryPath,\r
+  IN CONST CHAR8      *Node,\r
+  OUT XENSTORE_WATCH  **WatchPtr\r
+  )\r
+{\r
+  /* Pointer in ascii is the token. */\r
+  CHAR8 Token[sizeof (XENSTORE_WATCH) * 2 + 1];\r
+  XENSTORE_STATUS Status;\r
+  XENSTORE_WATCH *Watch;\r
+\r
+  Watch = AllocateZeroPool (sizeof (XENSTORE_WATCH));\r
+  Watch->Signature = XENSTORE_WATCH_SIGNATURE;\r
+  Watch->Node = XenStoreJoin (DirectoryPath, Node);\r
+\r
+  EfiAcquireLock (&xs.RegisteredWatchesLock);\r
+  InsertTailList (&xs.RegisteredWatches, &Watch->Link);\r
+  EfiReleaseLock (&xs.RegisteredWatchesLock);\r
+\r
+  AsciiSPrint (Token, sizeof (Token), "%p", (VOID*) Watch);\r
+  Status = XenStoreWatch (Watch->Node, Token);\r
+\r
+  /* Ignore errors due to multiple registration. */\r
+  if (Status == XENSTORE_STATUS_EEXIST) {\r
+    Status = XENSTORE_STATUS_SUCCESS;\r
+  }\r
+\r
+  if (Status == XENSTORE_STATUS_SUCCESS) {\r
+    *WatchPtr = Watch;\r
+  } else {\r
+    EfiAcquireLock (&xs.RegisteredWatchesLock);\r
+    RemoveEntryList (&Watch->Link);\r
+    EfiReleaseLock (&xs.RegisteredWatchesLock);\r
+    FreePool (Watch->Node);\r
+    FreePool (Watch);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+VOID\r
+XenStoreUnregisterWatch (\r
+  IN XENSTORE_WATCH *Watch\r
+  )\r
+{\r
+  CHAR8 Token[sizeof (Watch) * 2 + 1];\r
+  LIST_ENTRY *Entry;\r
+\r
+  ASSERT (Watch->Signature == XENSTORE_WATCH_SIGNATURE);\r
+\r
+  AsciiSPrint (Token, sizeof (Token), "%p", (VOID *) Watch);\r
+  if (XenStoreFindWatch (Token) == NULL) {\r
+    return;\r
+  }\r
+\r
+  EfiAcquireLock (&xs.RegisteredWatchesLock);\r
+  RemoveEntryList (&Watch->Link);\r
+  EfiReleaseLock (&xs.RegisteredWatchesLock);\r
+\r
+  XenStoreUnwatch (Watch->Node, Token);\r
+\r
+  /* Cancel pending watch events. */\r
+  EfiAcquireLock (&xs.WatchEventsLock);\r
+  Entry = GetFirstNode (&xs.WatchEvents);\r
+  while (!IsNull (&xs.WatchEvents, Entry)) {\r
+    XENSTORE_MESSAGE *Message = XENSTORE_MESSAGE_FROM_LINK (Entry);\r
+    Entry = GetNextNode (&xs.WatchEvents, Entry);\r
+    if (Message->u.Watch.Handle == Watch) {\r
+      RemoveEntryList (&Message->Link);\r
+      FreePool (Message->u.Watch.Vector);\r
+      FreePool (Message);\r
+    }\r
+  }\r
+  EfiReleaseLock (&xs.WatchEventsLock);\r
+\r
+  FreePool (Watch->Node);\r
+  FreePool (Watch);\r
+}\r
diff --git a/OvmfPkg/XenBusDxe/XenStore.h b/OvmfPkg/XenBusDxe/XenStore.h
new file mode 100644 (file)
index 0000000..1503ed0
--- /dev/null
@@ -0,0 +1,292 @@
+/** @file\r
+  Method declarations and structures for accessing the XenStore\r
+\r
+  Copyright (C) 2005 Rusty Russell, IBM Corporation\r
+  Copyright (C) 2005 XenSource Ltd.\r
+  Copyright (C) 2009,2010 Spectra Logic Corporation\r
+  Copyright (C) 2014, Citrix Ltd.\r
+\r
+  This file may be distributed separately from the Linux kernel, or\r
+  incorporated into other software packages, subject to the following license:\r
+\r
+  Permission is hereby granted, free of charge, to any person obtaining a copy\r
+  of this source file (the "Software"), to deal in the Software without\r
+  restriction, including without limitation the rights to use, copy, modify,\r
+  merge, publish, distribute, sublicense, and/or sell copies of the Software,\r
+  and to permit persons to whom the Software is furnished to do so, subject to\r
+  the following conditions:\r
+\r
+  The above copyright notice and this permission notice shall be included in\r
+  all copies or substantial portions of the Software.\r
+\r
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\r
+  IN THE SOFTWARE.\r
+**/\r
+\r
+#ifndef _XEN_XENSTORE_XENSTOREVAR_H\r
+#define _XEN_XENSTORE_XENSTOREVAR_H\r
+\r
+#include "XenBusDxe.h"\r
+\r
+#include <IndustryStandard/Xen/io/xs_wire.h>\r
+\r
+typedef struct _XENSTORE_WATCH XENSTORE_WATCH;\r
+\r
+/**\r
+  Fetch the contents of a directory in the XenStore.\r
+\r
+  @param Transaction        The XenStore transaction covering this request.\r
+  @param DirectoryPath      The dirname of the path to read.\r
+  @param Node               The basename of the path to read.\r
+  @param DirectoryCountPtr  The returned number of directory entries.\r
+  @param DirectoryListPtr   An array of directory entry strings.\r
+\r
+  @return  On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r
+           indicating the type of failure.\r
+\r
+  @note The results buffer is alloced and should be free'd by the\r
+        caller.\r
+**/\r
+XENSTORE_STATUS\r
+XenStoreListDirectory (\r
+  IN  XENSTORE_TRANSACTION  Transaction,\r
+  IN  CONST CHAR8           *DirectoryPath,\r
+  IN  CONST CHAR8           *Node,\r
+  OUT UINT32                *DirectoryCountPtr,\r
+  OUT CONST CHAR8           ***DirectoryListPtr\r
+  );\r
+\r
+/**\r
+  Determine if a path exists in the XenStore.\r
+\r
+  @param Transaction  The XenStore transaction covering this request.\r
+  @param Directory    The dirname of the path to read.\r
+  @param Node         The basename of the path to read.\r
+\r
+  @retval TRUE  The path exists.\r
+  @retval FALSE The path does not exist or an error occurred attempting\r
+                to make that determination.\r
+**/\r
+BOOLEAN\r
+XenStorePathExists (\r
+  IN XENSTORE_TRANSACTION  Transaction,\r
+  IN CONST CHAR8 *Directory,\r
+  IN CONST CHAR8 *Node\r
+  );\r
+\r
+/**\r
+  Get the contents of a single "file".  Returns the contents in *Result which\r
+  should be freed after use.  The length of the value in bytes is returned in\r
+  *LenPtr.\r
+\r
+  @param Transaction    The XenStore transaction covering this request.\r
+  @param DirectoryPath  The dirname of the file to read.\r
+  @param Node           The basename of the file to read.\r
+  @param LenPtr         The amount of data read.\r
+  @param Result         The returned contents from this file.\r
+\r
+  @return  On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r
+           indicating the type of failure.\r
+\r
+  @note The results buffer is malloced and should be free'd by the\r
+        caller.\r
+**/\r
+XENSTORE_STATUS\r
+XenStoreRead (\r
+  IN  XENSTORE_TRANSACTION    Transaction,\r
+  IN  CONST CHAR8             *DirectoryPath,\r
+  IN  CONST CHAR8             *Node,\r
+  OUT UINT32                  *LenPtr OPTIONAL,\r
+  OUT VOID                    **Result\r
+  );\r
+\r
+/**\r
+  Write to a single file.\r
+\r
+  @param Transaction    The XenStore transaction covering this request.\r
+  @param DirectoryPath  The dirname of the file to write.\r
+  @param Node           The basename of the file to write.\r
+  @param Str            The NUL terminated string of data to write.\r
+\r
+  @return  On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r
+           indicating the type of failure.\r
+**/\r
+XENSTORE_STATUS\r
+XenStoreWrite (\r
+  IN XENSTORE_TRANSACTION  Transaction,\r
+  IN CONST CHAR8           *DirectoryPath,\r
+  IN CONST CHAR8           *Node,\r
+  IN CONST CHAR8           *Str\r
+  );\r
+\r
+/**\r
+  Remove a file or directory (directories must be empty).\r
+\r
+  @param Transaction    The XenStore transaction covering this request.\r
+  @param DirectoryPath  The dirname of the directory to remove.\r
+  @param Node           The basename of the directory to remove.\r
+\r
+  @return  On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r
+           indicating the type of failure.\r
+**/\r
+XENSTORE_STATUS\r
+XenStoreRemove (\r
+  IN XENSTORE_TRANSACTION   Transaction,\r
+  IN CONST CHAR8            *DirectoryPath,\r
+  IN CONST CHAR8            *Node\r
+  );\r
+\r
+/**\r
+  Start a transaction.\r
+\r
+  Changes by others will not be seen during the lifetime of this\r
+  transaction, and changes will not be visible to others until it\r
+  is committed (XenStoreTransactionEnd).\r
+\r
+  @param Transaction  The returned transaction.\r
+\r
+  @return  On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r
+           indicating the type of failure.\r
+**/\r
+XENSTORE_STATUS\r
+XenStoreTransactionStart (\r
+  OUT XENSTORE_TRANSACTION  *Transaction\r
+  );\r
+\r
+/**\r
+  End a transaction.\r
+\r
+  @param Transaction  The transaction to end/commit.\r
+  @param Abort        If TRUE, the transaction is discarded\r
+                      instead of committed.\r
+\r
+  @return  On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r
+           indicating the type of failure.\r
+**/\r
+XENSTORE_STATUS\r
+XenStoreTransactionEnd (\r
+  IN XENSTORE_TRANSACTION   Transaction,\r
+  IN BOOLEAN                Abort\r
+  );\r
+\r
+/**\r
+  Printf formatted write to a XenStore file.\r
+\r
+  @param Transaction      The XenStore transaction covering this request.\r
+  @param DirectoryPath    The dirname of the path to read.\r
+  @param Node             The basename of the path to read.\r
+  @param FormatString     AsciiSPrint format string followed by a variable number\r
+                          of arguments.\r
+\r
+  @return  On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r
+           indicating the type of write failure.\r
+**/\r
+XENSTORE_STATUS\r
+EFIAPI\r
+XenStoreSPrint (\r
+  IN XENSTORE_TRANSACTION   Transaction,\r
+  IN CONST CHAR8            *DirectoryPath,\r
+  IN CONST CHAR8            *Node,\r
+  IN CONST CHAR8            *FormatString,\r
+  ...\r
+  );\r
+\r
+/**\r
+  VA_LIST version of XenStoreSPrint().\r
+\r
+  @param Transaction    The XenStore transaction covering this request.\r
+  @param DirectoryPath  The dirname of the path to read.\r
+  @param Node           The basename of the path to read.\r
+  @param FormatString   Printf format string.\r
+  @param Marker         VA_LIST of printf arguments.\r
+\r
+  @return  On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r
+           indicating the type of write failure.\r
+**/\r
+XENSTORE_STATUS\r
+XenStoreVSPrint (\r
+  IN XENSTORE_TRANSACTION  Transaction,\r
+  IN CONST CHAR8           *DirectoryPath,\r
+  IN CONST CHAR8           *Node,\r
+  IN CONST CHAR8           *FormatString,\r
+  IN VA_LIST               Marker\r
+  );\r
+\r
+/**\r
+  Register a XenStore watch.\r
+\r
+  XenStore watches allow a client to be notified via a callback (embedded\r
+  within the watch object) of changes to an object in the XenStore.\r
+\r
+  @param DirectoryPath  The dirname of the path to watch.\r
+  @param Node           The basename of the path to watch.\r
+  @param WatchPtr       A returned XENSTORE_WATCH pointer.\r
+\r
+  @return  On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r
+           indicating the type of write failure.  EEXIST errors from the\r
+           XenStore are supressed, allowing multiple, physically different,\r
+           xenbus_watch objects, to watch the same path in the XenStore.\r
+**/\r
+XENSTORE_STATUS\r
+XenStoreRegisterWatch (\r
+  IN  CONST CHAR8     *DirectoryPath,\r
+  IN  CONST CHAR8     *Node,\r
+  OUT XENSTORE_WATCH  **WatchPtr\r
+  );\r
+\r
+/**\r
+  Unregister a XenStore watch.\r
+\r
+  @param Watch  An XENSTORE_WATCH object previously returned by a successful\r
+                call to XenStoreRegisterWatch ().\r
+**/\r
+VOID\r
+XenStoreUnregisterWatch (\r
+  IN XENSTORE_WATCH *Watch\r
+  );\r
+\r
+/**\r
+  Allocate and return the XenStore path string <DirectoryPath>/<Node>.  If name\r
+  is the NUL string, the returned value contains the path string\r
+  <DirectoryPath>.\r
+\r
+  @param DirectoryPath The NUL terminated directory prefix for new path.\r
+  @param Node           The NUL terminated basename for the new path.\r
+\r
+  @return  A buffer containing the joined path.\r
+ */\r
+CHAR8 *\r
+XenStoreJoin (\r
+  IN CONST CHAR8 *DirectoryPath,\r
+  IN CONST CHAR8 *Node\r
+  );\r
+\r
+\r
+/**\r
+  Initialize the XenStore states and rings.\r
+\r
+  @param Dev  A pointer to a XENBUS_DEVICE instance.\r
+\r
+  @return     EFI_SUCCESS if everything went smoothly.\r
+**/\r
+EFI_STATUS\r
+XenStoreInit (\r
+  XENBUS_DEVICE *Dev\r
+  );\r
+\r
+/**\r
+  Deinitialize the XenStore states and rings.\r
+\r
+  @param Dev  A pointer to a XENBUS_DEVICE instance.\r
+**/\r
+VOID\r
+XenStoreDeinit (\r
+  IN XENBUS_DEVICE *Dev\r
+  );\r
+\r
+#endif /* _XEN_XENSTORE_XENSTOREVAR_H */\r