[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 |