[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v2 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> --- 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); + 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 (); + } + 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; + } + + 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); +} + +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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |