|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH RFC 11/18] OvmfPkg/XenbusDxe: Add XenStore client implementation
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.
Origin: FreeBSD 10.0
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx>
---
OvmfPkg/Include/Protocol/Xenbus.h | 28 +
OvmfPkg/XenbusDxe/XenbusDxe.c | 5 +
OvmfPkg/XenbusDxe/XenbusDxe.inf | 2 +
OvmfPkg/XenbusDxe/Xenstore.c | 1313 +++++++++++++++++++++++++++++++++++++
OvmfPkg/XenbusDxe/Xenstore.h | 281 ++++++++
5 files changed, 1629 insertions(+)
create mode 100644 OvmfPkg/XenbusDxe/Xenstore.c
create mode 100644 OvmfPkg/XenbusDxe/Xenstore.h
diff --git a/OvmfPkg/Include/Protocol/Xenbus.h
b/OvmfPkg/Include/Protocol/Xenbus.h
index 191cee1..1e0d01d 100644
--- a/OvmfPkg/Include/Protocol/Xenbus.h
+++ b/OvmfPkg/Include/Protocol/Xenbus.h
@@ -21,6 +21,34 @@
///
typedef struct _XENBUS_PROTOCOL XENBUS_PROTOCOL;
+typedef enum xenbus_state XenbusState;
+
+typedef struct
+{
+ UINT32 Id;
+} XENSTORE_TRANSACTION;
+
+#define XST_NIL ((XENSTORE_TRANSACTION) { 0 })
+
+typedef enum {
+ XENSTORE_STATUS_SUCCESS = 0,
+ XENSTORE_STATUS_EINVAL,
+ XENSTORE_STATUS_EACCES,
+ XENSTORE_STATUS_EEXIST,
+ XENSTORE_STATUS_EISDIR,
+ XENSTORE_STATUS_ENOENT,
+ XENSTORE_STATUS_ENOMEM,
+ XENSTORE_STATUS_ENOSPC,
+ XENSTORE_STATUS_EIO,
+ XENSTORE_STATUS_ENOTEMPTY,
+ XENSTORE_STATUS_ENOSYS,
+ XENSTORE_STATUS_EROFS,
+ XENSTORE_STATUS_EBUSY,
+ XENSTORE_STATUS_EAGAIN,
+ XENSTORE_STATUS_EISCONN,
+ XENSTORE_STATUS_E2BIG
+} XENSTORE_STATUS;
+
#include <IndustryStandard/Xen/grant_table.h>
diff --git a/OvmfPkg/XenbusDxe/XenbusDxe.c b/OvmfPkg/XenbusDxe/XenbusDxe.c
index b19055d..2c85d5e 100644
--- a/OvmfPkg/XenbusDxe/XenbusDxe.c
+++ b/OvmfPkg/XenbusDxe/XenbusDxe.c
@@ -18,6 +18,7 @@
#include "XenHypercall.h"
#include "GrantTable.h"
+#include "Xenstore.h"
///
/// Driver Binding Protocol instance
@@ -330,6 +331,9 @@ XenbusDxeDriverBindingStart (
XenGrantTableInit (Dev, MmioAddr);
+ Status = XenstoreInit (Dev);
+ ASSERT_EFI_ERROR (Status);
+
Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
NotifyExitBoot,
(VOID*) Dev,
@@ -378,6 +382,7 @@ XenbusDxeDriverBindingStop (
XENBUS_DEVICE *Dev = mMyDevice;
gBS->CloseEvent (Dev->ExitBootEvent);
+ // XXX xenstore cleanup
XenGrantTableDeinit (Dev);
gBS->CloseProtocol(ControllerHandle, &gEfiPciIoProtocolGuid,
diff --git a/OvmfPkg/XenbusDxe/XenbusDxe.inf b/OvmfPkg/XenbusDxe/XenbusDxe.inf
index dc27c13..6c8260f 100644
--- a/OvmfPkg/XenbusDxe/XenbusDxe.inf
+++ b/OvmfPkg/XenbusDxe/XenbusDxe.inf
@@ -38,6 +38,8 @@
GrantTable.h
EventChannel.c
EventChannel.h
+ Xenstore.c
+ Xenstore.h
[Sources.X64]
X64/hypercall.S
diff --git a/OvmfPkg/XenbusDxe/Xenstore.c b/OvmfPkg/XenbusDxe/Xenstore.c
new file mode 100644
index 0000000..2252c4f
--- /dev/null
+++ b/OvmfPkg/XenbusDxe/Xenstore.c
@@ -0,0 +1,1313 @@
+/******************************************************************************
+ * xenstore.c
+ *
+ * Low-level kernel interface to the XenStore.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2009,2010 Spectra Logic Corporation
+ *
+ * This file may be distributed separately from the Linux kernel, or
+ * incorporated into other software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "Xenstore.h"
+
+#include <Library/PrintLib.h>
+
+#include <IndustryStandard/Xen/hvm/params.h>
+
+#include "XenHypercall.h"
+#include "EventChannel.h"
+
+/**
+ * \file xenstore.c
+ * \brief XenStore interface
+ *
+ * The XenStore interface is a simple storage system that is a means of
+ * communicating state and configuration data between the Xen Domain 0
+ * and the various guest domains. All configuration data other than
+ * a small amount of essential information required during the early
+ * boot process of launching a Xen aware guest, is managed using the
+ * XenStore.
+ *
+ * The XenStore is ASCII string based, and has a structure and semantics
+ * similar to a filesystem. There are files and directories, the directories
+ * able to contain files or other directories. The depth of the hierachy
+ * is only limited by the XenStore's maximum path length.
+ *
+ * The communication channel between the XenStore service and other
+ * domains is via two, guest specific, ring buffers in a shared memory
+ * area. One ring buffer is used for communicating in each direction.
+ * The grant table references for this shared memory are given to the
+ * guest either via the xen_start_info structure for a fully para-
+ * virtualized guest, or via HVM hypercalls for a hardware virtualized
+ * guest.
+ *
+ * The XenStore communication relies on an event channel and thus
+ * interrupts. For this reason, the attachment of the XenStore
+ * relies on an interrupt driven configuration hook to hold off
+ * boot processing until communication with the XenStore service
+ * can be established.
+ *
+ * Several Xen services depend on the XenStore, most notably the
+ * XenBus used to discover and manage Xen devices. These services
+ * are implemented as NewBus child attachments to a bus exported
+ * by this XenStore driver.
+ */
+
+/*-------------------------- Private Data Structures ------------------------*/
+
+typedef struct {
+ CONST VOID *Data;
+ UINTN Len;
+} WRITE_REQUEST;
+
+/* Register callback to watch subtree (node) in the XenStore. */
+#define XENSTORE_WATCH_SIGNATURE SIGNATURE_32 ('X','S','w','a')
+struct _XENSTORE_WATCH
+{
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ /* Path being watched. */
+ CHAR8 *Node;
+};
+
+#define XENSTORE_WATCH_FROM_LINK(l) \
+ CR (l, XENSTORE_WATCH, Link, XENSTORE_WATCH_SIGNATURE)
+
+
+/**
+ * Structure capturing messages received from the XenStore service.
+ */
+#define XENSTORE_MESSAGE_SIGNATURE SIGNATURE_32 ('X', 'S', 's', 'm')
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ struct xsd_sockmsg Header;
+
+ union {
+ /* Queued replies. */
+ struct {
+ CHAR8 *Body;
+ } Reply;
+
+ /* Queued watch events. */
+ struct {
+ XENSTORE_WATCH *Handle;
+ CONST CHAR8 **Vector;
+ UINT32 VectorSize;
+ } Watch;
+ } u;
+} XENSTORE_MESSAGE;
+#define XENSTORE_MESSAGE_FROM_LINK(r) \
+ CR (r, XENSTORE_MESSAGE, Link, XENSTORE_MESSAGE_SIGNATURE)
+
+/**
+ * Container for all XenStore related state.
+ */
+typedef struct {
+ /**
+ * Pointer to shared memory communication structures allowing us
+ * to communicate with the XenStore service.
+ */
+ struct xenstore_domain_interface *Xenstore;
+
+ XENBUS_DEVICE *Dev;
+
+ /**
+ * Lock serializing access to ring producer/consumer
+ * indexes. Use of this lock guarantees that wakeups
+ * of blocking readers/writers are not missed due to
+ * races with the XenStore service.
+ */
+ // might need an other way of locking, more ovmf
+ //SPIN_LOCK ring_lock;
+
+ /*
+ * Mutex used to insure exclusive access to the outgoing
+ * communication ring. We use a lock type that can be
+ * held while sleeping so that xs_write() can block waiting
+ * for space in the ring to free up, without allowing another
+ * writer to come in and corrupt a partial message write.
+ */
+ //struct sx request_mutex;
+
+ /**
+ * A list of replies to our requests.
+ *
+ * The reply list is filled by xs_rcv_thread(). It
+ * is consumed by the context that issued the request
+ * to which a reply is made. The requester blocks in
+ * XenstoreReadReply ().
+ *
+ * /note Only one requesting context can be active at a time.
+ * This is guaranteed by the request_mutex and insures
+ * that the requester sees replies matching the order
+ * of its requests.
+ */
+ LIST_ENTRY ReplyList;
+
+ /** Lock protecting the reply list. */
+ EFI_LOCK ReplyLock;
+
+ /**
+ * List of registered watches.
+ */
+ LIST_ENTRY RegisteredWatches;
+
+ /** Lock protecting the registered watches list. */
+ EFI_LOCK RegisteredWatchesLock;
+
+ /**
+ * List of pending watch callback events.
+ */
+ LIST_ENTRY WatchEvents;
+
+ /** Lock protecting the watch calback list. */
+ EFI_LOCK WatchEventsLock;
+
+ /**
+ * The event channel for communicating with the
+ * XenStore service.
+ */
+ UINT32 EventChannel;
+
+ /** Handle for XenStore events. */
+ EFI_EVENT EventChannelEvent;
+} XENSTORE_PRIVATE;
+
+/*-------------------------------- Global Data ------------------------------*/
+static XENSTORE_PRIVATE xs;
+
+/*------------------------- Private Utility Functions -----------------------*/
+/**
+ * Count and optionally record pointers to a number of NUL terminated
+ * strings in a buffer.
+ *
+ * \param strings A pointer to a contiguous buffer of NUL terminated strings.
+ * \param len The length of the buffer pointed to by strings.
+ * \param dest An array to store pointers to each string found in strings.
+ *
+ * \return A count of the number of strings found.
+ */
+STATIC
+UINT32
+ExtractStrings (
+ IN CONST CHAR8 *Strings,
+ IN UINTN Len,
+ OUT CONST CHAR8 **Dst OPTIONAL
+ )
+{
+ UINT32 Num = 0;
+ CONST CHAR8 *Ptr;
+
+ for (Ptr = Strings; Ptr < Strings + Len; Ptr += AsciiStrSize (Ptr)) {
+ if (Dst != NULL) {
+ *Dst++ = Ptr;
+ }
+ Num++;
+ }
+
+ return Num;
+}
+
+/**
+ * Convert a contiguous buffer containing a series of NUL terminated
+ * strings into an array of pointers to strings.
+ *
+ * The returned pointer references the array of string pointers which
+ * is followed by the storage for the string data. It is the client's
+ * responsibility to free this storage.
+ *
+ * The storage addressed by strings is free'd prior to Split returning.
+ *
+ * \param strings A pointer to a contiguous buffer of NUL terminated strings.
+ * \param len The length of the buffer pointed to by strings.
+ * \param num The number of strings found and returned in the strings
+ * array.
+ *
+ * \return An array of pointers to the strings found in the input buffer.
+ */
+STATIC
+CONST CHAR8 **
+Split (
+ IN CHAR8 *Strings,
+ IN UINTN Len,
+ OUT UINT32 *NumPtr
+ )
+{
+ // XXX Why const and later a cast to not const?
+ CONST CHAR8 **Dst;
+
+ ASSERT(NumPtr != NULL);
+ ASSERT(Strings != NULL);
+
+ /* Protect against unterminated buffers. */
+ if (Len > 0) {
+ Strings[Len - 1] = '\0';
+ }
+
+ /* Count the Strings. */
+ *NumPtr = ExtractStrings (Strings, Len, NULL);
+
+ /* Transfer to one big alloc for easy freeing by the caller. */
+ Dst = AllocatePool (*NumPtr * sizeof (CHAR8 *) + Len);
+ // XXX is Dst + *NumPtr better ?
+ CopyMem (&Dst[*NumPtr], Strings, Len);
+ FreePool (Strings);
+
+ /* Extract pointers to newly allocated array. */
+ Strings = (CHAR8 *) &Dst[*NumPtr];
+ ExtractStrings (Strings, Len, Dst);
+
+ return (Dst);
+}
+
+/**
+ * Convert from watch token (unique identifier) to the associated
+ * internal tracking structure for this watch.
+ *
+ * \param tocken The unique identifier for the watch to find.
+ *
+ * \return A pointer to the found watch structure or NULL.
+ */
+STATIC
+XENSTORE_WATCH *
+XenstoreFindWatch (
+ IN CONST CHAR8 *Token
+ )
+{
+ XENSTORE_WATCH *Watch, *WantedWatch;
+ LIST_ENTRY *Entry;
+
+ WantedWatch = (VOID *) AsciiStrHexToUintn (Token);
+
+ if (IsListEmpty (&xs.RegisteredWatches)) {
+ return NULL;
+ }
+ for (Entry = GetFirstNode (&xs.RegisteredWatches);
+ !IsNull (&xs.RegisteredWatches, Entry);
+ Entry = GetNextNode (&xs.RegisteredWatches, Entry)) {
+ Watch = XENSTORE_WATCH_FROM_LINK (Entry);
+ if (Watch == WantedWatch)
+ return Watch;
+ }
+
+ return NULL;
+}
+
+/*------------------------- Public Utility Functions ----------------------*/
+/*------- API comments for these methods can be found in Xenstore.h -------*/
+CHAR8 *
+XenstoreJoin (
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node
+ )
+{
+ CHAR8 *Buf;
+
+ /* +1 for '/' and +1 for '\0' */
+ Buf = AllocateZeroPool (
+ AsciiStrLen (DirectoryPath) + AsciiStrLen (Node) + 2);
+ AsciiStrCat (Buf, DirectoryPath);
+ if (Node[0] != '\0') {
+ AsciiStrCat (Buf, "/");
+ AsciiStrCat (Buf, Node);
+ }
+
+ return Buf;
+}
+
+/*-------------------- Low Level Communication Management
--------------------*/
+/**
+ * Verify that the indexes for a ring are valid.
+ *
+ * The difference between the producer and consumer cannot
+ * exceed the size of the ring.
+ *
+ * \param cons The consumer index for the ring to test.
+ * \param prod The producer index for the ring to test.
+ *
+ * \retval 1 If indexes are in range.
+ * \retval 0 If the indexes are out of range.
+ */
+STATIC
+BOOLEAN
+XenstoreCheckIndexes (
+ XENSTORE_RING_IDX Cons,
+ XENSTORE_RING_IDX Prod
+ )
+{
+ return ((Prod - Cons) <= XENSTORE_RING_SIZE);
+}
+
+/**
+ * Return a pointer to, and the length of, the contiguous
+ * free region available for output in a ring buffer.
+ *
+ * \param cons The consumer index for the ring.
+ * \param prod The producer index for the ring.
+ * \param buf The base address of the ring's storage.
+ * \param len The amount of contiguous storage available.
+ *
+ * \return A pointer to the start location of the free region.
+ */
+STATIC
+VOID *
+XenstoreGetOutputChunk (
+ XENSTORE_RING_IDX Cons,
+ XENSTORE_RING_IDX Prod,
+ CHAR8 *Buffer,
+ UINT32 *LenPtr
+ )
+{
+ UINT32 Len;
+ Len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(Prod);
+ if ((XENSTORE_RING_SIZE - (Prod - Cons)) < Len) {
+ Len = XENSTORE_RING_SIZE - (Prod - Cons);
+ }
+ *LenPtr = Len;
+ return (Buffer + MASK_XENSTORE_IDX(Prod));
+}
+
+/**
+ * Return a pointer to, and the length of, the contiguous
+ * data available to read from a ring buffer.
+ *
+ * \param cons The consumer index for the ring.
+ * \param prod The producer index for the ring.
+ * \param buf The base address of the ring's storage.
+ * \param len The amount of contiguous data available to read.
+ *
+ * \return A pointer to the start location of the available data.
+ */
+STATIC
+CONST VOID *
+XenstoreGetInputChunk (
+ XENSTORE_RING_IDX Cons,
+ XENSTORE_RING_IDX Prod,
+ CONST CHAR8 *Buffer,
+ UINT32 *LenPtr
+ )
+{
+ UINT32 Len;
+
+ Len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(Cons);
+ if ((Prod - Cons) < Len) {
+ Len = Prod - Cons;
+ }
+ *LenPtr = Len;
+ return (Buffer + MASK_XENSTORE_IDX(Cons));
+}
+
+/**
+ * Transmit data to the XenStore service.
+ *
+ * \param tdata A pointer to the contiguous data to send.
+ * \param len The amount of data to send.
+ *
+ * \return On success 0, otherwise an errno value indicating the
+ * cause of failure.
+ *
+ * \invariant Called from thread context.
+ * \invariant The buffer pointed to by tdata is at least len bytes
+ * in length.
+ * \invariant xs.request_mutex exclusively locked.
+ */
+STATIC
+XENSTORE_STATUS
+XenstoreWriteStore (
+ CONST VOID *tdata,
+ UINTN Len
+ )
+{
+ XENSTORE_RING_IDX Cons, Prod;
+ CONST CHAR8 *Data = (CONST CHAR8 *)tdata;
+
+ // an assert that check if it's still a locket mutex
+ // sx_assert(&xs.request_mutex, SX_XLOCKED);
+ while (Len != 0) {
+ void *Dest;
+ UINT32 Available;
+
+ /* Hold lock so we can't miss wakeups should we block. */
+ //AcquireSpinLock(&xs.ring_lock);
+ Cons = xs.Xenstore->req_cons;
+ Prod = xs.Xenstore->req_prod;
+ if ((Prod - Cons) == XENSTORE_RING_SIZE) {
+ /*
+ * Output ring is full. Wait for a ring event.
+ *
+ * Note that the events from both queues are combined, so being woken
+ * does not guarantee that data exist in the read ring.
+ */
+ UINTN Index;
+ EFI_STATUS Status;
+
+ Status = gBS->WaitForEvent (1, &xs.EventChannelEvent, &Index);
+ ASSERT (Status != EFI_INVALID_PARAMETER);
+ if (Status == EFI_UNSUPPORTED) {
+ // see XenstoreReadStore
+ }
+
+ /* Try again. */
+ continue;
+ }
+ //mtx_unlock(&xs.ring_lock);
+
+ /* Verify queue sanity. */
+ if (!XenstoreCheckIndexes (Cons, Prod)) {
+ xs.Xenstore->req_cons = xs.Xenstore->req_prod = 0;
+ return XENSTORE_STATUS_EIO;
+ }
+
+ Dest = XenstoreGetOutputChunk (Cons, Prod, xs.Xenstore->req, &Available);
+ if (Available > Len) {
+ Available = Len;
+ }
+
+ CopyMem (Dest, Data, Available);
+ Data += Available;
+ Len -= Available;
+
+ /*
+ * The store to the producer index, which indicates
+ * to the other side that new data has arrived, must
+ * be visible only after our copy of the data into the
+ * ring has completed.
+ */
+ MemoryFence ();
+ xs.Xenstore->req_prod += Available;
+
+ /*
+ * The other side will see the change to req_prod at the time of the
+ * interrupt.
+ */
+ MemoryFence ();
+ XenEventChannelNotify (xs.Dev, xs.EventChannel);
+ }
+
+ return XENSTORE_STATUS_SUCCESS;
+}
+
+/**
+ * Receive data from the XenStore service.
+ *
+ * \param tdata A pointer to the contiguous buffer to receive the data.
+ * \param len The amount of data to receive.
+ *
+ * \return On success 0, otherwise an errno value indicating the
+ * cause of failure.
+ *
+ * \invariant Called from thread context.
+ * \invariant The buffer pointed to by tdata is at least len bytes
+ * in length.
+ *
+ * \note xs_read does not perform any internal locking to guarantee
+ * serial access to the incoming ring buffer. However, there
+ * is only one context processing reads: xs_rcv_thread().
+ */
+STATIC
+XENSTORE_STATUS
+XenstoreReadStore (
+ OUT VOID *tdata,
+ IN UINTN Len
+ )
+{
+ XENSTORE_RING_IDX Cons, Prod;
+ CHAR8 *Data = (CHAR8 *)tdata;
+
+ while (Len != 0) {
+ UINT32 Available;
+ CONST CHAR8 *Src;
+
+ /* Hold lock so we can't miss wakeups should we block. */
+ //mtx_lock(&xs.ring_lock); //SpinLock ?
+ Cons = xs.Xenstore->rsp_cons;
+ Prod = xs.Xenstore->rsp_prod;
+ if (Cons == Prod) {
+ /*
+ * Nothing to read. Wait for a ring event.
+ *
+ * Note that the events from both queues are combined, so being woken
+ * does not guarantee that data exist in the read ring.
+ */
+ UINTN Index;
+ EFI_STATUS Status;
+
+ Status = gBS->WaitForEvent (1, &xs.EventChannelEvent, &Index);
+ ASSERT (Status != EFI_INVALID_PARAMETER);
+ if (Status == EFI_UNSUPPORTED) {
+ // The current TPL is not TPL_APPLICATION.
+ // could:
+ // this could happen when the device is deinitialized
+ // from the ExitBootServices notification
+ /* OldTpl = EfiGetCurrentTpl(); */
+ /* gBS->RestoreTPL (TPL_APPLICATION); */
+ /* gBS->WaitForEvent (XXX); */
+ /* gBS->RaiseTPL (OldTpl); */
+ }
+ continue;
+ }
+ //mtx_unlock(&xs.ring_lock);
+
+ /* Verify queue sanity. */
+ if (!XenstoreCheckIndexes (Cons, Prod)) {
+ xs.Xenstore->rsp_cons = xs.Xenstore->rsp_prod = 0;
+ return XENSTORE_STATUS_EIO;
+ }
+
+ Src = XenstoreGetInputChunk (Cons, Prod, xs.Xenstore->rsp, &Available);
+ if (Available > Len) {
+ Available = Len;
+ }
+
+ /*
+ * Insure the data we read is related to the indexes
+ * we read above.
+ */
+ MemoryFence ();
+
+ CopyMem (Data, Src, Available);
+ Data += Available;
+ Len -= Available;
+
+ /*
+ * Insure that the producer of this ring does not see
+ * the ring space as free until after we have copied it
+ * out.
+ */
+ MemoryFence ();
+ xs.Xenstore->rsp_cons += Available;
+
+ /*
+ * The producer will see the updated consumer index when the event is
+ * delivered.
+ */
+ MemoryFence ();
+ XenEventChannelNotify (xs.Dev, xs.EventChannel);
+ }
+
+ return XENSTORE_STATUS_SUCCESS;
+}
+
+/*----------------------- Received Message Processing
------------------------*/
+/**
+ * Block reading the next message from the XenStore service and
+ * process the result.
+ *
+ * \param type The returned type of the XenStore message received.
+ *
+ * \return 0 on success. Otherwise an errno value indicating the
+ * type of failure encountered.
+ */
+STATIC
+XENSTORE_STATUS
+XenstoreProcessMessage (
+ VOID
+ )
+{
+ XENSTORE_MESSAGE *Message;
+ CHAR8 *Body;
+ XENSTORE_STATUS Status;
+
+ Message = AllocateZeroPool (sizeof (XENSTORE_MESSAGE));
+ Message->Signature = XENSTORE_MESSAGE_SIGNATURE;
+ Status = XenstoreReadStore (&Message->Header, sizeof (Message->Header));
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ FreePool (Message);
+ DEBUG ((EFI_D_ERROR, "%a %d, error read store %d\n",
+ __func__, __LINE__, Status));
+ return Status;
+ }
+
+ Body = AllocatePool (Message->Header.len + 1);
+ Status = XenstoreReadStore (Body, Message->Header.len);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ FreePool (Body);
+ FreePool (Message);
+ DEBUG ((EFI_D_ERROR, "%a %d, error read store %d\n",
+ __func__, __LINE__, Status));
+ return Status;
+ }
+ Body[Message->Header.len] = '\0';
+
+ if (Message->Header.type == XS_WATCH_EVENT) {
+ Message->u.Watch.Vector = Split(Body, Message->Header.len,
+ &Message->u.Watch.VectorSize);
+
+ EfiAcquireLock (&xs.RegisteredWatchesLock);
+ Message->u.Watch.Handle =
+ XenstoreFindWatch (Message->u.Watch.Vector[XS_WATCH_TOKEN]);
+ DEBUG ((EFI_D_INFO, "%a %d, watch event %a\n", __func__, __LINE__,
+ Message->u.Watch.Vector[XS_WATCH_TOKEN]));
+ if (Message->u.Watch.Handle != NULL) {
+ EfiAcquireLock (&xs.WatchEventsLock);
+ InsertHeadList (&xs.WatchEvents, &Message->Link);
+ EfiReleaseLock (&xs.WatchEventsLock);
+ } else {
+ DEBUG ((EFI_D_WARN, "%a %d, watch handle %a not found\n",
+ __func__, __LINE__, Message->u.Watch.Vector[XS_WATCH_TOKEN]));
+ FreePool(Message->u.Watch.Vector);
+ FreePool(Message);
+ }
+ EfiReleaseLock (&xs.RegisteredWatchesLock);
+ } else {
+ Message->u.Reply.Body = Body;
+ EfiAcquireLock (&xs.ReplyLock);
+ InsertTailList (&xs.ReplyList, &Message->Link);
+ EfiReleaseLock (&xs.ReplyLock);
+ }
+
+ return XENSTORE_STATUS_SUCCESS;
+}
+
+/*---------------- XenStore Message Request/Reply Processing
-----------------*/
+
+
+/**
+ * Convert a XenStore error string into an errno number.
+ *
+ * \param errorstring The error string to convert.
+ *
+ * \return The errno best matching the input string.
+ *
+ * \note Unknown error strings are converted to EINVAL.
+ */
+
+typedef struct {
+ XENSTORE_STATUS Status;
+ CONST CHAR8 *ErrorStr;
+} XenstoreErrors;
+
+static XenstoreErrors gXenstoreErrors[] = {
+ { XENSTORE_STATUS_EINVAL, "EINVAL" },
+ { XENSTORE_STATUS_EACCES, "EACCES" },
+ { XENSTORE_STATUS_EEXIST, "EEXIST" },
+ { XENSTORE_STATUS_EISDIR, "EISDIR" },
+ { XENSTORE_STATUS_ENOENT, "ENOENT" },
+ { XENSTORE_STATUS_ENOMEM, "ENOMEM" },
+ { XENSTORE_STATUS_ENOSPC, "ENOSPC" },
+ { XENSTORE_STATUS_EIO, "EIO" },
+ { XENSTORE_STATUS_ENOTEMPTY, "ENOTEMPTY" },
+ { XENSTORE_STATUS_ENOSYS, "ENOSYS" },
+ { XENSTORE_STATUS_EROFS, "EROFS" },
+ { XENSTORE_STATUS_EBUSY, "EBUSY" },
+ { XENSTORE_STATUS_EAGAIN, "EAGAIN" },
+ { XENSTORE_STATUS_EISCONN, "EISCONN" },
+ { XENSTORE_STATUS_E2BIG, "E2BIG" }
+};
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+STATIC
+XENSTORE_STATUS
+XenstoreGetError (
+ CONST CHAR8 *ErrorStr
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < ARRAY_SIZE(gXenstoreErrors); Index++) {
+ if (!AsciiStrCmp (ErrorStr, gXenstoreErrors[Index].ErrorStr)) {
+ return gXenstoreErrors[Index].Status;
+ }
+ }
+ DEBUG ((EFI_D_WARN, "Xenstore gave unknown error %a\n", ErrorStr));
+ return XENSTORE_STATUS_EINVAL;
+}
+
+/**
+ * Block waiting for a reply to a message request.
+ *
+ * \param type The returned type of the reply.
+ * \param len The returned body length of the reply.
+ * \param result The returned body of the reply.
+ *
+ * \return 0 on success. Otherwise an errno indicating the
+ * cause of failure.
+ */
+STATIC
+VOID
+XenstoreReadReply (
+ OUT enum xsd_sockmsg_type *type,
+ OUT UINT32 *LenPtr OPTIONAL,
+ OUT VOID **Result
+ )
+{
+ XENSTORE_MESSAGE *Message;
+ LIST_ENTRY *Entry;
+ CHAR8 *Body;
+
+ while (IsListEmpty (&xs.ReplyList)) {
+ XenstoreProcessMessage ();
+ }
+ EfiAcquireLock (&xs.ReplyLock);
+ Entry = GetFirstNode (&xs.ReplyList);
+ Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
+ RemoveEntryList (Entry);
+ EfiReleaseLock (&xs.ReplyLock);
+
+ *type = Message->Header.type;
+ if (LenPtr != NULL) {
+ *LenPtr = Message->Header.len;
+ }
+ Body = Message->u.Reply.Body;
+
+ FreePool (Message);
+ *Result = Body;
+}
+
+/**
+ * Send a message with an optionally muti-part body to the XenStore service.
+ *
+ * \param Transaction The transaction to use for this request.
+ * \param request_type The type of message to send.
+ * \param iovec Pointers to the body sections of the request.
+ * \param NumRequests The number of body sections in the request.
+ * \param LenPtr The returned length of the reply.
+ * \param ResultPtr The returned body of the reply.
+ *
+ * \return 0 on success. Otherwise an errno indicating
+ * the cause of failure.
+ *
+ * \note The returned result is provided in malloced storage and thus
+ * must be free'd by the caller with 'free(*result, M_XENSTORE);
+ */
+STATIC
+XENSTORE_STATUS
+XenstoreTalkv (
+ IN XENSTORE_TRANSACTION Transaction,
+ IN enum xsd_sockmsg_type RequestType,
+ IN CONST WRITE_REQUEST *WriteRequest,
+ IN UINT32 NumRequests,
+ OUT UINT32 *LenPtr OPTIONAL,
+ OUT VOID **ResultPtr OPTIONAL
+ )
+{
+ struct xsd_sockmsg Message;
+ void *Return = NULL;
+ UINT32 Index;
+ XENSTORE_STATUS Status;
+
+ Message.tx_id = Transaction.Id;
+ Message.req_id = 0;
+ Message.type = RequestType;
+ Message.len = 0;
+ for (Index = 0; Index < NumRequests; Index++) {
+ Message.len += WriteRequest[Index].Len;
+ }
+
+ //sx_xlock(&xs.request_mutex);
+ Status = XenstoreWriteStore (&Message, sizeof (Message));
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "XenstoreTalkv failed %d\n", Status));
+ goto ErrorLockHeld;
+ }
+
+ for (Index = 0; Index < NumRequests; Index++) {
+ Status = XenstoreWriteStore (WriteRequest[Index].Data,
WriteRequest[Index].Len);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "XenstoreTalkv failed %d\n", Status));
+ goto ErrorLockHeld;
+ }
+ }
+
+ XenstoreReadReply (&Message.type, LenPtr, &Return);
+
+ErrorLockHeld:
+ //sx_xunlock(&xs.request_mutex);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ return Status;
+ }
+
+ if (Message.type == XS_ERROR) {
+ Status = XenstoreGetError (Return);
+ FreePool (Return);
+ return Status;
+ }
+
+ /* Reply is either error or an echo of our request message type. */
+ ASSERT (Message.type == RequestType);
+
+ if (ResultPtr) {
+ *ResultPtr = Return;
+ } else {
+ FreePool (Return);
+ }
+
+ return XENSTORE_STATUS_SUCCESS;
+}
+
+/**
+ * Wrapper for XenstoreTalkv allowing easy transmission of a message with
+ * a single, contiguous, message body.
+ *
+ * \param Transaction The transaction to use for this request.
+ * \param request_type The type of message to send.
+ * \param Body The body of the request.
+ * \param len The returned length of the reply.
+ * \param result The returned body of the reply.
+ *
+ * \return 0 on success. Otherwise an errno indicating
+ * the cause of failure.
+ *
+ * \note The returned result is provided in malloced storage and thus
+ * must be free'd by the caller with 'free(*result, M_XENSTORE);
+ */
+STATIC
+XENSTORE_STATUS
+XenstoreSingle (
+ IN XENSTORE_TRANSACTION Transaction,
+ IN enum xsd_sockmsg_type RequestType,
+ IN CONST CHAR8 *Body,
+ OUT UINT32 *LenPtr OPTIONAL,
+ OUT VOID **Result OPTIONAL
+ )
+{
+ WRITE_REQUEST WriteRequest;
+
+ WriteRequest.Data = (VOID *) Body;
+ WriteRequest.Len = AsciiStrSize (Body);
+
+ return XenstoreTalkv (Transaction, RequestType, &WriteRequest, 1,
+ LenPtr, Result);
+}
+
+/*------------------------- XenStore Watch Support
---------------------------*/
+/**
+ * Transmit a watch request to the XenStore service.
+ *
+ * \param path The path in the XenStore to watch.
+ * \param tocken A unique identifier for this watch.
+ *
+ * \return 0 on success. Otherwise an errno indicating the
+ * cause of failure.
+ */
+STATIC
+XENSTORE_STATUS
+XenstoreWatch (
+ CONST CHAR8 *Path,
+ CONST CHAR8 *Token
+ )
+{
+ WRITE_REQUEST WriteRequest[2];
+
+ WriteRequest[0].Data = (VOID *) Path;
+ WriteRequest[0].Len = AsciiStrSize (Path);
+ WriteRequest[1].Data = (VOID *) Token;
+ WriteRequest[1].Len = AsciiStrSize (Token);
+
+ return XenstoreTalkv (XST_NIL, XS_WATCH, WriteRequest, 2, NULL, NULL);
+}
+
+/**
+ * Transmit an uwatch request to the XenStore service.
+ *
+ * \param Path The path in the XenStore to watch.
+ * \param Tocken A unique identifier for this watch.
+ *
+ * \return 0 on success. Otherwise an errno indicating the
+ * cause of failure.
+ */
+STATIC
+XENSTORE_STATUS
+XenstoreUnwatch (
+ CONST CHAR8 *Path,
+ CONST CHAR8 *Token
+ )
+{
+ WRITE_REQUEST WriteRequest[2];
+
+ WriteRequest[0].Data = (VOID *) Path;
+ WriteRequest[0].Len = AsciiStrSize (Path);
+ WriteRequest[1].Data = (VOID *) Token;
+ WriteRequest[1].Len = AsciiStrSize (Token);
+
+ return XenstoreTalkv (XST_NIL, XS_UNWATCH, WriteRequest, 2, NULL, NULL);
+}
+
+VOID
+EFIAPI
+NotifyEventChannelCheckForEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ XENSTORE_PRIVATE *xs;
+ xs = (XENSTORE_PRIVATE *)Context;
+ if (TestAndClearBit (xs->EventChannel, xs->Dev->SharedInfo->evtchn_pending))
{
+ gBS->SignalEvent (Event);
+ }
+}
+
+/*----------- XenStore Configuration, Initialization, and Control
------------*/
+/**
+ * Setup communication channels with the XenStore service.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ */
+STATIC
+EFI_STATUS
+XenstoreInitComms (
+ XENSTORE_PRIVATE *xs
+ )
+{
+ EFI_STATUS Status;
+ struct xenstore_domain_interface *Xenstore = xs->Xenstore;
+
+ if (Xenstore->rsp_prod != Xenstore->rsp_cons) {
+ DEBUG ((EFI_D_WARN, "XENSTORE response ring is not quiescent "
+ "(%08x:%08x): fixing up\n",
+ Xenstore->rsp_cons, Xenstore->rsp_prod));
+ Xenstore->rsp_cons = Xenstore->rsp_prod;
+ }
+
+ Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_NOTIFY,
+ NotifyEventChannelCheckForEvent, xs,
+ &xs->EventChannelEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/*------------------ Private Device Attachment Functions
--------------------*/
+/**
+ * Attach to the XenStore.
+ *
+ * This routine also prepares for the probe/attach of drivers that rely
+ * on the XenStore.
+ */
+EFI_STATUS
+XenstoreInit (
+ XENBUS_DEVICE *Dev
+ )
+{
+ EFI_STATUS Status;
+ /**
+ * The HVM guest pseudo-physical frame number. This is Xen's mapping
+ * of the true machine frame number into our "physical address space".
+ */
+ UINTN XenstoreGpfn;
+
+ xs.Dev = Dev;
+
+ xs.EventChannel = XenHypercallHvmGetParam (Dev, HVM_PARAM_STORE_EVTCHN);
+ XenstoreGpfn = XenHypercallHvmGetParam (Dev, HVM_PARAM_STORE_PFN);
+ xs.Xenstore = (VOID *) (XenstoreGpfn << EFI_PAGE_SHIFT);
+ DEBUG ((EFI_D_INFO, "XenbusInit: Xenbus rings @0x%lx, event channel %ld\n",
+ (UINTN) xs.Xenstore, (UINTN) xs.EventChannel));
+
+ InitializeListHead (&xs.ReplyList);
+ InitializeListHead (&xs.WatchEvents);
+ InitializeListHead (&xs.RegisteredWatches);
+
+ //mtx_init(&xs.ring_lock, "ring lock", NULL, MTX_DEF);
+ EfiInitializeLock (&xs.ReplyLock, TPL_NOTIFY);
+ //sx_init(&xs.request_mutex, "xenstore request");
+ EfiInitializeLock (&xs.RegisteredWatchesLock, TPL_NOTIFY);
+ EfiInitializeLock (&xs.WatchEventsLock, TPL_NOTIFY);
+
+ /* Initialize the shared memory rings to talk to xenstored */
+ Status = XenstoreInitComms (&xs);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return Status;
+}
+
+/*-------------------------------- Public API -----------------------------*/
+/*------- API comments for these methods can be found in Xenstore.h -------*/
+XENSTORE_STATUS
+XenstoreListDirectory (
+ IN XENSTORE_TRANSACTION Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ OUT UINT32 *DirectoryCountPtr,
+ OUT CONST CHAR8 ***DirectoryListPtr
+ )
+{
+ CHAR8 *Path;
+ CHAR8 *TempStr;
+ UINT32 Len = 0;
+ XENSTORE_STATUS Status;
+
+ Path = XenstoreJoin (DirectoryPath, Node);
+ Status = XenstoreSingle (Transaction, XS_DIRECTORY, Path, &Len,
+ (VOID **) &TempStr);
+ FreePool (Path);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ return Status;
+ }
+
+ *DirectoryListPtr = Split (TempStr, Len, DirectoryCountPtr);
+
+ return (0);
+}
+
+BOOLEAN
+XenstorePathExists (
+ IN XENSTORE_TRANSACTION Transaction,
+ IN CONST CHAR8 *Directory,
+ IN CONST CHAR8 *Node
+ )
+{
+ CONST CHAR8 **TempStr;
+ XENSTORE_STATUS Status;
+ UINT32 TempNum;
+
+ Status = XenstoreListDirectory (Transaction, Directory, Node,
+ &TempNum, &TempStr);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ return FALSE;
+ }
+ FreePool (TempStr);
+ return TRUE;
+}
+
+XENSTORE_STATUS
+XenstoreRead (
+ IN XENSTORE_TRANSACTION Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ OUT UINT32 *LenPtr OPTIONAL,
+ OUT VOID **Result
+ )
+{
+ CHAR8 *Path;
+ VOID *Value;
+ XENSTORE_STATUS Status;
+
+ Path = XenstoreJoin (DirectoryPath, Node);
+ Status = XenstoreSingle (Transaction, XS_READ, Path, LenPtr, &Value);
+ FreePool (Path);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ return Status;
+ }
+
+ *Result = Value;
+ return XENSTORE_STATUS_SUCCESS;
+}
+
+XENSTORE_STATUS
+XenstoreWrite (
+ XENSTORE_TRANSACTION Transaction,
+ CONST CHAR8 *DirectoryPath,
+ CONST CHAR8 *Node,
+ CONST CHAR8 *Str
+ )
+{
+ CHAR8 *Path;
+ WRITE_REQUEST WriteRequest[2];
+ XENSTORE_STATUS Status;
+
+ Path = XenstoreJoin (DirectoryPath, Node);
+
+ WriteRequest[0].Data = (VOID *) Path;
+ WriteRequest[0].Len = AsciiStrSize (Path);
+ WriteRequest[1].Data = (VOID *) Str;
+ WriteRequest[1].Len = AsciiStrLen (Str);
+
+ Status = XenstoreTalkv (Transaction, XS_WRITE, WriteRequest, 2, NULL, NULL);
+ FreePool (Path);
+
+ return Status;
+}
+
+XENSTORE_STATUS
+XenstoreRemove (
+ IN XENSTORE_TRANSACTION Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node
+ )
+{
+ CHAR8 *Path;
+ XENSTORE_STATUS Status;
+
+ Path = XenstoreJoin (DirectoryPath, Node);
+ Status = XenstoreSingle (Transaction, XS_RM, Path, NULL, NULL);
+ FreePool (Path);
+
+ return Status;
+}
+
+XENSTORE_STATUS
+XenstoreTransactionStart (
+ OUT XENSTORE_TRANSACTION *Transaction
+ )
+{
+ CHAR8 *IdStr;
+ XENSTORE_STATUS Status;
+
+ Status = XenstoreSingle (XST_NIL, XS_TRANSACTION_START, "", NULL,
+ (VOID **) &IdStr);
+ if (Status == XENSTORE_STATUS_SUCCESS) {
+ Transaction->Id = AsciiStrDecimalToUintn (IdStr);
+ FreePool (IdStr);
+ }
+
+ return Status;
+}
+
+XENSTORE_STATUS
+XenstoreTransactionEnd (
+ IN XENSTORE_TRANSACTION Transaction,
+ IN BOOLEAN Abort
+ )
+{
+ CHAR8 AbortStr[2];
+
+ if (Abort) {
+ AsciiStrCpy (AbortStr, "F");
+ } else {
+ AsciiStrCpy (AbortStr, "T");
+ }
+
+ return XenstoreSingle (Transaction, XS_TRANSACTION_END, AbortStr, NULL,
NULL);
+}
+
+XENSTORE_STATUS
+XenstoreVSPrint (
+ IN XENSTORE_TRANSACTION Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ IN CONST CHAR8 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ CHAR8 *Buf;
+ XENSTORE_STATUS Status;
+ UINTN BufSize;
+
+ BufSize = SPrintLengthAsciiFormat (FormatString, Marker) + 1;
+ Buf = AllocateZeroPool (BufSize);
+ AsciiVSPrint (Buf, BufSize, FormatString, Marker);
+ Status = XenstoreWrite (Transaction, DirectoryPath, Node, Buf);
+ FreePool (Buf);
+
+ return Status;
+}
+
+XENSTORE_STATUS
+EFIAPI
+XenstoreSPrint (
+ IN XENSTORE_TRANSACTION Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ IN CONST CHAR8 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+ XENSTORE_STATUS Status;
+
+ VA_START (Marker, FormatString);
+ Status = XenstoreVSPrint (Transaction, DirectoryPath, Node, FormatString,
Marker);
+ VA_END (Marker);
+
+ return Status;
+}
+
+XENSTORE_STATUS
+XenstoreRegisterWatch (
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ OUT XENSTORE_WATCH **WatchPtr
+ )
+{
+ /* Pointer in ascii is the token. */
+ CHAR8 Token[sizeof (XENSTORE_WATCH) * 2 + 1];
+ XENSTORE_STATUS Status;
+ XENSTORE_WATCH *Watch;
+
+ Watch = AllocateZeroPool (sizeof (XENSTORE_WATCH));
+ Watch->Signature = XENSTORE_WATCH_SIGNATURE;
+ Watch->Node = XenstoreJoin (DirectoryPath, Node);
+
+ EfiAcquireLock (&xs.RegisteredWatchesLock);
+ InsertTailList (&xs.RegisteredWatches, &Watch->Link);
+ EfiReleaseLock (&xs.RegisteredWatchesLock);
+
+ AsciiSPrint (Token, sizeof (Token), "%p", (VOID*) Watch);
+ Status = XenstoreWatch (Watch->Node, Token);
+
+ /* Ignore errors due to multiple registration. */
+ if (Status == XENSTORE_STATUS_EEXIST) {
+ Status = XENSTORE_STATUS_SUCCESS;
+ }
+
+ if (Status == XENSTORE_STATUS_SUCCESS) {
+ *WatchPtr = Watch;
+ } else {
+ EfiAcquireLock (&xs.RegisteredWatchesLock);
+ RemoveEntryList (&Watch->Link);
+ EfiReleaseLock (&xs.RegisteredWatchesLock);
+ FreePool (Watch->Node);
+ FreePool (Watch);
+ }
+
+ return Status;
+}
+
+VOID
+XenstoreUnregisterWatch (
+ IN XENSTORE_WATCH *Watch
+ )
+{
+ CHAR8 Token[sizeof (Watch) * 2 + 1];
+ XENSTORE_STATUS Status;
+ LIST_ENTRY *Entry;
+
+ ASSERT (Watch->Signature == XENSTORE_WATCH_SIGNATURE);
+
+ AsciiSPrint (Token, sizeof (Token), "%p", (VOID *) Watch);
+ // XXX do I need a lock ?
+ if (XenstoreFindWatch (Token) == NULL) {
+ return;
+ }
+ // XXX need cleaning (remove from two list, free everything)
+
+ EfiAcquireLock (&xs.RegisteredWatchesLock);
+ RemoveEntryList (&Watch->Link);
+ EfiReleaseLock (&xs.RegisteredWatchesLock);
+
+ Status = XenstoreUnwatch (Watch->Node, Token);
+
+ /* Cancel pending watch events. */
+ EfiAcquireLock (&xs.WatchEventsLock);
+ Entry = GetFirstNode (&xs.WatchEvents);
+ while (!IsNull (&xs.WatchEvents, Entry)) {
+ XENSTORE_MESSAGE *Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
+ Entry = GetNextNode (&xs.WatchEvents, Entry);
+ if (Message->u.Watch.Handle == Watch) {
+ RemoveEntryList (&Message->Link);
+ FreePool (Message->u.Watch.Vector);
+ FreePool (Message);
+ }
+ }
+ EfiReleaseLock (&xs.WatchEventsLock);
+
+ FreePool (Watch->Node);
+ FreePool (Watch);
+}
diff --git a/OvmfPkg/XenbusDxe/Xenstore.h b/OvmfPkg/XenbusDxe/Xenstore.h
new file mode 100644
index 0000000..3a056c0
--- /dev/null
+++ b/OvmfPkg/XenbusDxe/Xenstore.h
@@ -0,0 +1,281 @@
+/******************************************************************************
+ * Xenstore.h
+ *
+ * Method declarations and structures for accessing the Xenstore
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 XenSource Ltd.
+ * Copyright (C) 2009,2010 Spectra Logic Corporation
+ *
+ * This file may be distributed separately from the Linux kernel, or
+ * incorporated into other software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * $FreeBSD: release/10.0.0/sys/xen/xenstore/xenstorevar.h 255040 2013-08-29
19:52:18Z gibbs $
+ */
+
+#ifndef _XEN_XENSTORE_XENSTOREVAR_H
+#define _XEN_XENSTORE_XENSTOREVAR_H
+
+#include "XenbusDxe.h"
+
+#include <IndustryStandard/Xen/io/xs_wire.h>
+
+typedef struct _XENSTORE_WATCH XENSTORE_WATCH;
+
+/**
+ * Fetch the contents of a directory in the XenStore.
+ *
+ * \param Transaction The XenStore transaction covering this request.
+ * \param dir The dirname of the path to read.
+ * \param node The basename of the path to read.
+ * \param num The returned number of directory entries.
+ * \param result An array of directory entry strings.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ *
+ * \note The results buffer is malloced and should be free'd by the
+ * caller with 'free(*result, M_XENSTORE)'.
+ */
+XENSTORE_STATUS
+XenstoreListDirectory (
+ IN XENSTORE_TRANSACTION Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ OUT UINT32 *DirectoryCountPtr,
+ OUT CONST CHAR8 ***DirectoryListPtr
+ );
+
+/**
+ * Determine if a path exists in the XenStore.
+ *
+ * \param Transaction The XenStore transaction covering this request.
+ * \param dir The dirname of the path to read.
+ * \param node The basename of the path to read.
+ *
+ * \retval 1 The path exists.
+ * \retval 0 The path does not exist or an error occurred attempting
+ * to make that determination.
+ */
+BOOLEAN
+XenstorePathExists (
+ IN XENSTORE_TRANSACTION Transaction,
+ IN CONST CHAR8 *Directory,
+ IN CONST CHAR8 *Node
+ );
+
+/**
+ * Get the contents of a single "file". Returns the contents in
+ * *result which should be freed with free(*result, M_XENSTORE) after
+ * use. The length of the value in bytes is returned in *len.
+ *
+ * \param Transaction The XenStore transaction covering this request.
+ * \param dir The dirname of the file to read.
+ * \param node The basename of the file to read.
+ * \param len The amount of data read.
+ * \param result The returned contents from this file.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ *
+ * \note The results buffer is malloced and should be free'd by the
+ * caller with 'free(*result, M_XENSTORE)'.
+ */
+XENSTORE_STATUS
+XenstoreRead (
+ IN XENSTORE_TRANSACTION Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ OUT UINT32 *LenPtr OPTIONAL,
+ OUT VOID **Result
+ );
+
+/**
+ * Write to a single file.
+ *
+ * \param Transaction The XenStore transaction covering this request.
+ * \param dir The dirname of the file to write.
+ * \param node The basename of the file to write.
+ * \param string The NUL terminated string of data to write.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ */
+XENSTORE_STATUS
+XenstoreWrite (
+ XENSTORE_TRANSACTION Transaction,
+ CONST CHAR8 *DirectoryPath,
+ CONST CHAR8 *Node,
+ CONST CHAR8 *Str
+ );
+
+/**
+ * Remove a file or directory (directories must be empty).
+ *
+ * \param Transaction The XenStore transaction covering this request.
+ * \param dir The dirname of the directory to remove.
+ * \param node The basename of the directory to remove.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ */
+XENSTORE_STATUS
+XenstoreRemove (
+ IN XENSTORE_TRANSACTION Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node
+ );
+
+/**
+ * Start a transaction.
+ *
+ * Changes by others will not be seen during the lifetime of this
+ * transaction, and changes will not be visible to others until it
+ * is committed (xs_transaction_end).
+ *
+ * \param Transaction The returned transaction.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ */
+XENSTORE_STATUS
+XenstoreTransactionStart (
+ OUT XENSTORE_TRANSACTION *Transaction
+ );
+
+/**
+ * End a transaction.
+ *
+ * \param Transaction The transaction to end/commit.
+ * \param abort If non-zero, the transaction is discarded
+ * instead of committed.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ */
+XENSTORE_STATUS
+XenstoreTransactionEnd (
+ IN XENSTORE_TRANSACTION Transaction,
+ IN BOOLEAN Abort
+ );
+
+/**
+ * Printf formatted write to a XenStore file.
+ *
+ * \param Transaction The XenStore transaction covering this request.
+ * \param dir The dirname of the path to read.
+ * \param node The basename of the path to read.
+ * \param fmt Printf format string followed by a variable number of
+ * printf arguments.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of write failure.
+ */
+XENSTORE_STATUS
+EFIAPI
+XenstoreSPrint (
+ IN XENSTORE_TRANSACTION Transaction,
+ IN CONST CHAR8 *dir,
+ IN CONST CHAR8 *node,
+ IN CONST CHAR8 *FormatString,
+ ...
+ );
+
+/**
+ * va_list version of xenbus_printf().
+ *
+ * \param Transaction The XenStore transaction covering this request.
+ * \param dir The dirname of the path to read.
+ * \param node The basename of the path to read.
+ * \param fmt Printf format string.
+ * \param ap Va_list of printf arguments.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of write failure.
+ */
+XENSTORE_STATUS
+XenstoreVSPrint (
+ IN XENSTORE_TRANSACTION Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ IN CONST CHAR8 *FormatString,
+ IN VA_LIST Marker
+ );
+
+/**
+ * Register a XenStore watch.
+ *
+ * XenStore watches allow a client to be notified via a callback (embedded
+ * within the watch object) of changes to an object in the XenStore.
+ *
+ * \param watch An XENSTORE_WATCH struct with it's node and callback fields
+ * properly initialized.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of write failure. EEXIST errors from the XenStore
+ * are supressed, allowing multiple, physically different,
+ * xenbus_watch objects, to watch the same path in the XenStore.
+ */
+XENSTORE_STATUS
+XenstoreRegisterWatch (
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ OUT XENSTORE_WATCH **WatchPtr
+ );
+
+/**
+ * Unregister a XenStore watch.
+ *
+ * \param watch An XENSTORE_WATCH object previously used in a successful call
+ * to XenstoreRegisterWatch ().
+ *
+ * The XENSTORE_WATCH object's node field is not altered by this call.
+ * It is the caller's responsibility to properly dispose of both the
+ * watch object and the data pointed to by watch->node.
+ */
+VOID
+XenstoreUnregisterWatch (
+ IN XENSTORE_WATCH *Watch
+ );
+
+/**
+ * Allocate and return an sbuf containing the XenStore path string
+ * <dir>/<name>. If name is the NUL string, the returned sbuf contains
+ * the path string <dir>.
+ *
+ * \param dir The NUL terminated directory prefix for new path.
+ * \param name The NUL terminated basename for the new path.
+ *
+ * \return A buffer containing the joined path.
+ */
+CHAR8 *
+XenstoreJoin (
+ CONST CHAR8 *DirectoryPath,
+ CONST CHAR8 *Node
+ );
+
+
+EFI_STATUS
+XenstoreInit (
+ XENBUS_DEVICE *Dev
+ );
+
+#endif /* _XEN_XENSTORE_XENSTOREVAR_H */
--
Anthony PERARD
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |