[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v2 11/18] OvmfPkg/XenBusDxe: Add XenStore client implementation



On Wed, Sep 10, 2014 at 04:48:50PM -0400, Konrad Rzeszutek Wilk wrote:
> On Thu, Sep 04, 2014 at 05:51:06PM +0100, Anthony PERARD wrote:
> > 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.
> 
> You should really take from patch #1 the io/xs_wire.h and have
> it as part of this patch.

Ok, will do.

> I have some comments, but overall this looks good. If you want to
> fix them up, you can tack on Reviewed-by: Konrad Rzeszutek Wilk 
> <konrad.wilk@xxxxxxxxxx>
> 
> 
> > 
> > Origin: FreeBSD 10.0
> > 
> > Contributed-under: TianoCore Contribution Agreement 1.0
> > Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx>
> > 
> > ---
> > 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.
> > ---
> >  OvmfPkg/Include/Protocol/XenBus.h |   29 +
> >  OvmfPkg/XenBusDxe/XenBusDxe.c     |    5 +
> >  OvmfPkg/XenBusDxe/XenBusDxe.inf   |    2 +
> >  OvmfPkg/XenBusDxe/XenStore.c      | 1320 
> > +++++++++++++++++++++++++++++++++++++
> >  OvmfPkg/XenBusDxe/XenStore.h      |  292 ++++++++
> >  5 files changed, 1648 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 bf4a69f..b10c143 100644
> > --- a/OvmfPkg/Include/Protocol/XenBus.h
> > +++ b/OvmfPkg/Include/Protocol/XenBus.h
> > @@ -45,6 +45,35 @@
> >  ///
> >  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_FAIL,
> > +  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 29aadb1..76ea67c 100644
> > --- a/OvmfPkg/XenBusDxe/XenBusDxe.c
> > +++ b/OvmfPkg/XenBusDxe/XenBusDxe.c
> > @@ -47,6 +47,7 @@
> >  
> >  #include "XenHypercall.h"
> >  #include "GrantTable.h"
> > +#include "XenStore.h"
> >  
> >  
> >  ///
> > @@ -344,6 +345,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,
> > @@ -398,6 +402,7 @@ XenBusDxeDriverBindingStop (
> >    XENBUS_DEVICE *Dev = mMyDevice;
> >  
> >    gBS->CloseEvent (Dev->ExitBootEvent);
> > +  XenStoreDeinit (Dev);
> >    XenGrantTableDeinit (Dev);
> >  
> >    gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid,
> > diff --git a/OvmfPkg/XenBusDxe/XenBusDxe.inf 
> > b/OvmfPkg/XenBusDxe/XenBusDxe.inf
> > index e8f362a..9052967 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..bcf6e1c
> > --- /dev/null
> > +++ b/OvmfPkg/XenBusDxe/XenStore.c
> > @@ -0,0 +1,1320 @@
> > +/** @file
> > +  Low-level kernel interface to the XenStore.
> > +
> > +  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.  But under OVMF this XenStore client will pull the
> > +  state of the event channel.
> > +
> > +  Several Xen services depend on the XenStore, most notably the
> > +  XenBus used to discover and manage Xen devices.
> > +
> > +  Copyright (C) 2005 Rusty Russell, IBM Corporation
> > +  Copyright (C) 2009,2010 Spectra Logic Corporation
> > +  Copyright (C) 2014, Citrix Ltd.
> > +
> > +  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"
> > +
> > +//
> > +// 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;
> > +
> > +  /**
> > +   * 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.
> > +   */
> > +  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.
> > +   */
> > +  evtchn_port_t 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 Dst      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 NumPtr   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
> > +  )
> > +{
> > +  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);
> > +  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 TRUE   If indexes are in range.
> > +  @retval FALSE  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 Buffer  The base address of the ring's storage.
> > +  @param LenPtr  The amount of contiguous storage available.
> > +
> > +  @return  A pointer to the start location of the free region.
> > +**/
> > +STATIC
> > +VOID *
> > +XenStoreGetOutputChunk (
> > +  IN  XENSTORE_RING_IDX Cons,
> > +  IN  XENSTORE_RING_IDX Prod,
> > +  IN  CHAR8             *Buffer,
> > +  OUT 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 Buffer  The base address of the ring's storage.
> > +  @param LenPtr  The amount of contiguous data available to read.
> > +
> > +  @return  A pointer to the start location of the available data.
> > +**/
> > +STATIC
> > +CONST VOID *
> > +XenStoreGetInputChunk (
> > +  IN  XENSTORE_RING_IDX Cons,
> > +  IN  XENSTORE_RING_IDX Prod,
> > +  IN  CONST CHAR8       *Buffer,
> > +  OUT 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.
> > +
> > +  The buffer pointed to by DataPtr is at least Len bytes in length.
> > +
> > +  @param DataPtr  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.
> > +**/
> > +STATIC
> > +XENSTORE_STATUS
> > +XenStoreWriteStore (
> > +  IN CONST VOID *DataPtr,
> > +  IN UINTN      Len
> > +  )
> > +{
> > +  XENSTORE_RING_IDX Cons, Prod;
> > +  CONST CHAR8 *Data = (CONST CHAR8 *)DataPtr;
> > +
> > +  while (Len != 0) {
> > +    void *Dest;
> > +    UINT32 Available;
> > +
> > +    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);
> > +
> > +      /* Try again. */
> > +      continue;
> > +    }
> > +
> > +    /* 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.
> > +
> > +  The buffer pointed to by DataPtr is at least Len bytes in length.
> > +
> > +  @param DataPtr  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.
> > +**/
> > +STATIC
> > +XENSTORE_STATUS
> > +XenStoreReadStore (
> > +  OUT VOID *DataPtr,
> > +  IN  UINTN Len
> > +  )
> > +{
> > +  XENSTORE_RING_IDX Cons, Prod;
> > +  CHAR8 *Data = (CHAR8 *) DataPtr;
> > +
> > +  while (Len != 0) {
> > +    UINT32 Available;
> > +    CONST CHAR8 *Src;
> > +
> > +    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);
> 
> Ouch. That if done incorrectly (say the other side does not notify) could 
> stop this whole thing right here.
> 
> Perhaps you can add debug printk so at least we know where it might be stuck?

Actually, I could had a timeout here.

So, we could wait 3second, and check the ring again, maybe 2 more time.
If the ring is empty, we could just return an error (EIO). That would be
around 9second, but after that, the firmware could do something else.

And in case of timeout, have a printk.

> Ditto for the other WaitForEvent call site.

ok.


> > +      ASSERT (Status != EFI_INVALID_PARAMETER);
> > +      continue;
> > +    }
> > +
> > +    /* 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.
> > +
> > +  @return  XENSTORE_STATUS_SUCCESS 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, "XenStore: Error read store (%d)\n", 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, "XenStore: Error read store (%d)\n", 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, "XenStore: Watch event %a\n",
> > +            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, "XenStore: Watch handle %a not found\n",
> > +              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.
> > +
> > +  Unknown error strings are converted to EINVAL.
> > +
> > +  @param errorstring  The error string to convert.
> > +
> > +  @return  The errno best matching the input string.
> > +
> > +**/
> > +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 TypePtr The returned type of the reply.
> > +  @param LenPtr  The returned body length of the reply.
> > +  @param Result  The returned body of the reply.
> > +**/
> > +STATIC
> > +VOID
> > +XenStoreReadReply (
> > +  OUT enum xsd_sockmsg_type *TypePtr,
> > +  OUT UINT32 *LenPtr OPTIONAL,
> > +  OUT VOID **Result
> > +  )
> > +{
> > +  XENSTORE_MESSAGE *Message;
> > +  LIST_ENTRY *Entry;
> > +  CHAR8 *Body;
> > +
> > +  while (IsListEmpty (&xs.ReplyList)) {
> > +    XenStoreProcessMessage ();
> 
> You ignore the return value it gives you. Should there be a check for that 
> and if there is an issue throttle down the spinning?

I can't really throttle down here. But I should check for "hardware"
error, and return an error as well, maybe.

> > +  }
> > +  EfiAcquireLock (&xs.ReplyLock);
> > +  Entry = GetFirstNode (&xs.ReplyList);
> > +  Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
> > +  RemoveEntryList (Entry);
> > +  EfiReleaseLock (&xs.ReplyLock);
> > +
> > +  *TypePtr = 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 RequestType    The type of message to send.
> > +  @param WriteRequest   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  XENSTORE_STATUS_SUCCESS on success.  Otherwise an errno 
> > indicating
> > +           the cause of failure.
> > +**/
> > +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;
> > +  }
> > +
> > +  Status = XenStoreWriteStore (&Message, sizeof (Message));
> > +  if (Status != XENSTORE_STATUS_SUCCESS) {
> > +    DEBUG ((EFI_D_ERROR, "XenStoreTalkv failed %d\n", Status));
> > +    goto Error;
> > +  }
> > +
> > +  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 Error;
> > +    }
> > +  }
> > +
> > +  XenStoreReadReply (&Message.type, LenPtr, &Return);
> > +
> > +Error:
> > +  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.
> > +
> > +  The returned result is provided in malloced storage and thus must be 
> > free'd
> > +  by the caller.
> > +
> > +  @param Transaction    The transaction to use for this request.
> > +  @param RequestType    The type of message to send.
> > +  @param Body           The body of the request.
> > +  @param LenPtr         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.
> > +**/
> > +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  XENSTORE_STATUS_SUCCESS 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  XENSTORE_STATUS_SUCCESS 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);
> > +  }
> > +}
> > +
> > +/**
> > +  Setup communication channels with the XenStore service.
> > +
> > +  @retval EFI_SUCCESS if everything went well.
> > +**/
> > +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;
> > +  }
> 
> Perhaps that should be in a while loop in case it takes longer to become 
> quiet?

OK, that can be done.

> > +
> > +  Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_NOTIFY,
> > +                             NotifyEventChannelCheckForEvent, xs,
> > +                             &xs->EventChannelEvent);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Initialize XenStore.
> > +
> > +  @param Dev  A XENBUS_DEVICE instance.
> > +
> > +  @retval EFI_SUCCESS if everything went well.
> > +**/
> > +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 @%p, event channel %x\n",
> > +          xs.XenStore, xs.EventChannel));
> > +
> > +  InitializeListHead (&xs.ReplyList);
> > +  InitializeListHead (&xs.WatchEvents);
> > +  InitializeListHead (&xs.RegisteredWatches);
> > +
> > +  EfiInitializeLock (&xs.ReplyLock, TPL_NOTIFY);
> > +  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;
> > +}
> > +
> > +VOID
> > +XenStoreDeinit (
> > +  IN XENBUS_DEVICE *Dev
> > +  )
> > +{
> > +  //
> > +  // Emptying the list RegisteredWatches, but this list should already be
> > +  // empty. Every driver that is using Watches should unregister them when
> > +  // it is stopped.
> > +  //
> > +  if (!IsListEmpty (&xs.RegisteredWatches)) {
> > +    XENSTORE_WATCH *Watch;
> > +    LIST_ENTRY *Entry;
> > +    DEBUG ((EFI_D_WARN, "XenStore: RegisteredWatches is not empty, 
> > cleaning up..."));
> > +    Entry = GetFirstNode (&xs.RegisteredWatches);
> > +    while (!IsNull (&xs.RegisteredWatches, Entry)) {
> > +      Watch = XENSTORE_WATCH_FROM_LINK (Entry);
> > +      Entry = GetNextNode (&xs.RegisteredWatches, Entry);
> > +
> > +      XenStoreUnregisterWatch (Watch);
> > +    }
> > +  }
> > +
> > +  //
> > +  // Emptying the list WatchEvents, but this list should already be empty 
> > after
> > +  // having cleanup the list RegisteredWatches.
> > +  //
> > +  if (!IsListEmpty (&xs.WatchEvents)) {
> > +    LIST_ENTRY *Entry;
> > +    DEBUG ((EFI_D_WARN, "XenStore: WatchEvents is not empty, cleaning 
> > up..."));
> > +    Entry = GetFirstNode (&xs.WatchEvents);
> > +    while (!IsNull (&xs.WatchEvents, Entry)) {
> > +      XENSTORE_MESSAGE *Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
> > +      Entry = GetNextNode (&xs.WatchEvents, Entry);
> > +      RemoveEntryList (&Message->Link);
> > +      FreePool (Message->u.Watch.Vector);
> > +      FreePool (Message);
> > +    }
> > +  }
> > +
> > +  if (!IsListEmpty (&xs.ReplyList)) {
> > +    XENSTORE_MESSAGE *Message;
> > +    LIST_ENTRY *Entry;
> > +    Entry = GetFirstNode (&xs.ReplyList);
> > +    while (!IsNull (&xs.ReplyList, Entry)) {
> > +      Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
> > +      Entry = GetNextNode (&xs.ReplyList, Entry);
> > +      RemoveEntryList (&Message->Link);
> > +      FreePool (Message->u.Reply.Body);
> > +      FreePool (Message);
> > +    }
> > +  }
> > +
> > +  gBS->CloseEvent (xs.EventChannelEvent);
> > +
> > +  //
> > +  // We zero out the whole ring -- the backend can handle this, and it's
> > +  // not going to surprise any frontends since it's equivalent to never
> > +  // having used the rings.
> > +  //
> > +  ZeroMem (xs.XenStore, sizeof (struct xenstore_domain_interface));
> > +  xs.XenStore = NULL;
> > +}
> > +
> > +//
> > +// 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);
> 
> Shouldn't that be one of the XENSTORE .. enums?
> 
>       return XENSTORE_STATUS_SUCCESS;

Yes, will fix.

> > +}
> > +
> > +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 (
> > +  IN XENSTORE_TRANSACTION  Transaction,
> > +  IN CONST CHAR8           *DirectoryPath,
> > +  IN CONST CHAR8           *Node,
> > +  IN 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);
> > +  if (XenStoreFindWatch (Token) == NULL) {
> > +    return;
> > +  }
> > +
> > +  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..2902e3f
> > --- /dev/null
> > +++ b/OvmfPkg/XenBusDxe/XenStore.h
> > @@ -0,0 +1,292 @@
> > +/** @file
> > +  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
> > +  Copyright (C) 2014, Citrix Ltd.
> > +
> > +  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.
> > +**/
> > +
> > +#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 DirectoryPath      The dirname of the path to read.
> > +  @param Node               The basename of the path to read.
> > +  @param DirectoryCountPtr  The returned number of directory entries.
> > +  @param DirectoryListPtr   An array of directory entry strings.
> > +
> > +  @return  On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value
> > +           indicating the type of failure.
> > +
> > +  @note The results buffer is alloced and should be free'd by the
> > +        caller.
> > +**/
> > +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 Directory    The dirname of the path to read.
> > +  @param Node         The basename of the path to read.
> > +
> > +  @retval TRUE  The path exists.
> > +  @retval FALSE 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 DirectoryPath  The dirname of the file to read.
> > +  @param Node           The basename of the file to read.
> > +  @param LenPtr         The amount of data read.
> > +  @param Result         The returned contents from this file.
> > +
> > +  @return  On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value
> > +           indicating the type of failure.
> > +
> > +  @note The results buffer is malloced and should be free'd by the
> > +        caller.
> > +**/
> > +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 DirectoryPath  The dirname of the file to write.
> > +  @param Node           The basename of the file to write.
> > +  @param Str            The NUL terminated string of data to write.
> > +
> > +  @return  On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value
> > +           indicating the type of failure.
> > +**/
> > +XENSTORE_STATUS
> > +XenStoreWrite (
> > +  IN XENSTORE_TRANSACTION  Transaction,
> > +  IN CONST CHAR8           *DirectoryPath,
> > +  IN CONST CHAR8           *Node,
> > +  IN CONST CHAR8           *Str
> > +  );
> > +
> > +/**
> > +  Remove a file or directory (directories must be empty).
> > +
> > +  @param Transaction    The XenStore transaction covering this request.
> > +  @param DirectoryPath  The dirname of the directory to remove.
> > +  @param Node           The basename of the directory to remove.
> > +
> > +  @return  On success, XENSTORE_STATUS_SUCCESS. 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, XENSTORE_STATUS_SUCCESS. 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 TRUE, the transaction is discarded
> > +                      instead of committed.
> > +
> > +  @return  On success, XENSTORE_STATUS_SUCCESS. 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 DirectoryPath    The dirname of the path to read.
> > +  @param Node             The basename of the path to read.
> > +  @param FormatString     AsciiSPrint format string followed by a variable 
> > number
> > +                          of arguments.
> > +
> > +  @return  On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value
> > +           indicating the type of write failure.
> > +**/
> > +XENSTORE_STATUS
> > +EFIAPI
> > +XenStoreSPrint (
> > +  IN XENSTORE_TRANSACTION   Transaction,
> > +  IN CONST CHAR8            *DirectoryPath,
> > +  IN CONST CHAR8            *Node,
> > +  IN CONST CHAR8            *FormatString,
> > +  ...
> > +  );
> > +
> > +/**
> > +  VA_LIST version of XenStoreSPrint().
> > +
> > +  @param Transaction    The XenStore transaction covering this request.
> > +  @param DirectoryPath  The dirname of the path to read.
> > +  @param Node           The basename of the path to read.
> > +  @param FormatString   Printf format string.
> > +  @param Marker         VA_LIST of printf arguments.
> > +
> > +  @return  On success, XENSTORE_STATUS_SUCCESS. 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 DirectoryPath  The dirname of the path to watch.
> > +  @param Node           The basename of the path to watch.
> > +  @param WatchPtr       A returned XENSTORE_WATCH pointer.
> > +
> > +  @return  On success, XENSTORE_STATUS_SUCCESS. 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 returned by a 
> > successful
> > +                call to XenStoreRegisterWatch ().
> > +**/
> > +VOID
> > +XenStoreUnregisterWatch (
> > +  IN XENSTORE_WATCH *Watch
> > +  );
> > +
> > +/**
> > +  Allocate and return the XenStore path string <DirectoryPath>/<Node>.  If 
> > name
> > +  is the NUL string, the returned value contains the path string
> > +  <DirectoryPath>.
> > +
> > +  @param DirectoryPath     The NUL terminated directory prefix for new 
> > path.
> > +  @param Node           The NUL terminated basename for the new path.
> > +
> > +  @return  A buffer containing the joined path.
> > + */
> > +CHAR8 *
> > +XenStoreJoin (
> > +  IN CONST CHAR8 *DirectoryPath,
> > +  IN CONST CHAR8 *Node
> > +  );
> > +
> > +
> > +/**
> > +  Initialize the XenStore states and rings.
> > +
> > +  @param Dev  A pointer to a XENBUS_DEVICE instance.
> > +
> > +  @return     EFI_SUCCESS if everything went smoothly.
> > +**/
> > +EFI_STATUS
> > +XenStoreInit (
> > +  XENBUS_DEVICE *Dev
> > +  );
> > +
> > +/**
> > +  Deinitialize the XenStore states and rings.
> > +
> > +  @param Dev  A pointer to a XENBUS_DEVICE instance.
> > +**/
> > +VOID
> > +XenStoreDeinit (
> > +  IN XENBUS_DEVICE *Dev
> > +  );
> > +
> > +#endif /* _XEN_XENSTORE_XENSTOREVAR_H */
> > -- 
> > Anthony PERARD
> > 
> > 
> > _______________________________________________
> > Xen-devel mailing list
> > Xen-devel@xxxxxxxxxxxxx
> > http://lists.xen.org/xen-devel

-- 
Anthony PERARD

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.