2 Low-level kernel interface to the XenStore.
4 The XenStore interface is a simple storage system that is a means of
5 communicating state and configuration data between the Xen Domain 0
6 and the various guest domains. All configuration data other than
7 a small amount of essential information required during the early
8 boot process of launching a Xen aware guest, is managed using the
11 The XenStore is ASCII string based, and has a structure and semantics
12 similar to a filesystem. There are files and directories, the directories
13 able to contain files or other directories. The depth of the hierarchy
14 is only limited by the XenStore's maximum path length.
16 The communication channel between the XenStore service and other
17 domains is via two, guest specific, ring buffers in a shared memory
18 area. One ring buffer is used for communicating in each direction.
19 The grant table references for this shared memory are given to the
20 guest either via the xen_start_info structure for a fully para-
21 virtualized guest, or via HVM hypercalls for a hardware virtualized
24 The XenStore communication relies on an event channel and thus
25 interrupts. But under OVMF this XenStore client will pull the
26 state of the event channel.
28 Several Xen services depend on the XenStore, most notably the
29 XenBus used to discover and manage Xen devices.
31 Copyright (C) 2005 Rusty Russell, IBM Corporation
32 Copyright (C) 2009,2010 Spectra Logic Corporation
33 Copyright (C) 2014, Citrix Ltd.
35 This file may be distributed separately from the Linux kernel, or
36 incorporated into other software packages, subject to the following license:
38 SPDX-License-Identifier: MIT
43 #include <Library/PrintLib.h>
45 #include <IndustryStandard/Xen/hvm/params.h>
47 #include "EventChannel.h"
48 #include <Library/XenHypercallLib.h>
51 // Private Data Structures
59 /* Register callback to watch subtree (node) in the XenStore. */
60 #define XENSTORE_WATCH_SIGNATURE SIGNATURE_32 ('X','S','w','a')
61 struct _XENSTORE_WATCH
{
65 /* Path being watched. */
69 #define XENSTORE_WATCH_FROM_LINK(l) \
70 CR (l, XENSTORE_WATCH, Link, XENSTORE_WATCH_SIGNATURE)
73 * Structure capturing messages received from the XenStore service.
75 #define XENSTORE_MESSAGE_SIGNATURE SIGNATURE_32 ('X', 'S', 's', 'm')
80 struct xsd_sockmsg Header
;
88 /* Queued watch events. */
90 XENSTORE_WATCH
*Handle
;
96 #define XENSTORE_MESSAGE_FROM_LINK(r) \
97 CR (r, XENSTORE_MESSAGE, Link, XENSTORE_MESSAGE_SIGNATURE)
100 * Container for all XenStore related state.
104 * Pointer to shared memory communication structures allowing us
105 * to communicate with the XenStore service.
107 struct xenstore_domain_interface
*XenStore
;
112 * A list of replies to our requests.
114 * The reply list is filled by xs_rcv_thread(). It
115 * is consumed by the context that issued the request
116 * to which a reply is made. The requester blocks in
117 * XenStoreReadReply ().
119 * /note Only one requesting context can be active at a time.
121 LIST_ENTRY ReplyList
;
123 /** Lock protecting the reply list. */
127 * List of registered watches.
129 LIST_ENTRY RegisteredWatches
;
131 /** Lock protecting the registered watches list. */
132 EFI_LOCK RegisteredWatchesLock
;
135 * List of pending watch callback events.
137 LIST_ENTRY WatchEvents
;
139 /** Lock protecting the watch callback list. */
140 EFI_LOCK WatchEventsLock
;
143 * The event channel for communicating with the
146 evtchn_port_t EventChannel
;
148 /** Handle for XenStore events. */
149 EFI_EVENT EventChannelEvent
;
155 static XENSTORE_PRIVATE xs
;
158 // Private Utility Functions
162 Count and optionally record pointers to a number of NUL terminated
165 @param Strings A pointer to a contiguous buffer of NUL terminated strings.
166 @param Len The length of the buffer pointed to by strings.
167 @param Dst An array to store pointers to each string found in strings.
169 @return A count of the number of strings found.
174 IN CONST CHAR8
*Strings
,
176 OUT CONST CHAR8
**Dst OPTIONAL
182 for (Ptr
= Strings
; Ptr
< Strings
+ Len
; Ptr
+= AsciiStrSize (Ptr
)) {
194 Convert a contiguous buffer containing a series of NUL terminated
195 strings into an array of pointers to strings.
197 The returned pointer references the array of string pointers which
198 is followed by the storage for the string data. It is the client's
199 responsibility to free this storage.
201 The storage addressed by Strings is free'd prior to Split returning.
203 @param Strings A pointer to a contiguous buffer of NUL terminated strings.
204 @param Len The length of the buffer pointed to by strings.
205 @param NumPtr The number of strings found and returned in the strings
208 @return An array of pointers to the strings found in the input buffer.
220 ASSERT (NumPtr
!= NULL
);
221 ASSERT (Strings
!= NULL
);
223 /* Protect against unterminated buffers. */
225 Strings
[Len
- 1] = '\0';
228 /* Count the Strings. */
229 *NumPtr
= ExtractStrings (Strings
, Len
, NULL
);
231 /* Transfer to one big alloc for easy freeing by the caller. */
232 Dst
= AllocatePool (*NumPtr
* sizeof (CHAR8
*) + Len
);
233 CopyMem ((VOID
*)&Dst
[*NumPtr
], Strings
, Len
);
236 /* Extract pointers to newly allocated array. */
237 Strings
= (CHAR8
*)&Dst
[*NumPtr
];
238 ExtractStrings (Strings
, Len
, Dst
);
244 Convert from watch token (unique identifier) to the associated
245 internal tracking structure for this watch.
247 @param Tocken The unique identifier for the watch to find.
249 @return A pointer to the found watch structure or NULL.
254 IN CONST CHAR8
*Token
257 XENSTORE_WATCH
*Watch
, *WantedWatch
;
260 WantedWatch
= (VOID
*)AsciiStrHexToUintn (Token
);
262 if (IsListEmpty (&xs
.RegisteredWatches
)) {
266 for (Entry
= GetFirstNode (&xs
.RegisteredWatches
);
267 !IsNull (&xs
.RegisteredWatches
, Entry
);
268 Entry
= GetNextNode (&xs
.RegisteredWatches
, Entry
))
270 Watch
= XENSTORE_WATCH_FROM_LINK (Entry
);
271 if (Watch
== WantedWatch
) {
280 // Public Utility Functions
281 // API comments for these methods can be found in XenStore.h
286 IN CONST CHAR8
*DirectoryPath
,
293 /* +1 for '/' and +1 for '\0' */
294 BufSize
= AsciiStrLen (DirectoryPath
) + AsciiStrLen (Node
) + 2;
295 Buf
= AllocatePool (BufSize
);
296 ASSERT (Buf
!= NULL
);
298 if (Node
[0] == '\0') {
299 AsciiSPrint (Buf
, BufSize
, "%a", DirectoryPath
);
301 AsciiSPrint (Buf
, BufSize
, "%a/%a", DirectoryPath
, Node
);
308 // Low Level Communication Management
312 Verify that the indexes for a ring are valid.
314 The difference between the producer and consumer cannot
315 exceed the size of the ring.
317 @param Cons The consumer index for the ring to test.
318 @param Prod The producer index for the ring to test.
320 @retval TRUE If indexes are in range.
321 @retval FALSE If the indexes are out of range.
325 XenStoreCheckIndexes (
326 XENSTORE_RING_IDX Cons
,
327 XENSTORE_RING_IDX Prod
330 return ((Prod
- Cons
) <= XENSTORE_RING_SIZE
);
334 Return a pointer to, and the length of, the contiguous
335 free region available for output in a ring buffer.
337 @param Cons The consumer index for the ring.
338 @param Prod The producer index for the ring.
339 @param Buffer The base address of the ring's storage.
340 @param LenPtr The amount of contiguous storage available.
342 @return A pointer to the start location of the free region.
346 XenStoreGetOutputChunk (
347 IN XENSTORE_RING_IDX Cons
,
348 IN XENSTORE_RING_IDX Prod
,
355 Len
= XENSTORE_RING_SIZE
- MASK_XENSTORE_IDX (Prod
);
356 if ((XENSTORE_RING_SIZE
- (Prod
- Cons
)) < Len
) {
357 Len
= XENSTORE_RING_SIZE
- (Prod
- Cons
);
361 return (Buffer
+ MASK_XENSTORE_IDX (Prod
));
365 Return a pointer to, and the length of, the contiguous
366 data available to read from a ring buffer.
368 @param Cons The consumer index for the ring.
369 @param Prod The producer index for the ring.
370 @param Buffer The base address of the ring's storage.
371 @param LenPtr The amount of contiguous data available to read.
373 @return A pointer to the start location of the available data.
377 XenStoreGetInputChunk (
378 IN XENSTORE_RING_IDX Cons
,
379 IN XENSTORE_RING_IDX Prod
,
380 IN CONST CHAR8
*Buffer
,
386 Len
= XENSTORE_RING_SIZE
- MASK_XENSTORE_IDX (Cons
);
387 if ((Prod
- Cons
) < Len
) {
392 return (Buffer
+ MASK_XENSTORE_IDX (Cons
));
396 Wait for an event or timeout.
398 @param Event Event to wait for.
399 @param Timeout A timeout value in 100ns units.
401 @retval EFI_SUCCESS Event have been triggered or the current TPL is not
403 @retval EFI_TIMEOUT Timeout have expired.
407 XenStoreWaitForEvent (
414 EFI_EVENT TimerEvent
;
415 EFI_EVENT WaitList
[2];
417 gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
418 gBS
->SetTimer (TimerEvent
, TimerRelative
, Timeout
);
420 WaitList
[0] = xs
.EventChannelEvent
;
421 WaitList
[1] = TimerEvent
;
422 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
423 ASSERT (Status
!= EFI_INVALID_PARAMETER
);
424 gBS
->CloseEvent (TimerEvent
);
425 if (Status
== EFI_UNSUPPORTED
) {
437 Transmit data to the XenStore service.
439 The buffer pointed to by DataPtr is at least Len bytes in length.
441 @param DataPtr A pointer to the contiguous data to send.
442 @param Len The amount of data to send.
444 @return On success 0, otherwise an errno value indicating the
450 IN CONST VOID
*DataPtr
,
454 XENSTORE_RING_IDX Cons
, Prod
;
455 CONST CHAR8
*Data
= (CONST CHAR8
*)DataPtr
;
461 Cons
= xs
.XenStore
->req_cons
;
462 Prod
= xs
.XenStore
->req_prod
;
463 if ((Prod
- Cons
) == XENSTORE_RING_SIZE
) {
465 * Output ring is full. Wait for a ring event.
467 * Note that the events from both queues are combined, so being woken
468 * does not guarantee that data exist in the read ring.
472 Status
= XenStoreWaitForEvent (
473 xs
.EventChannelEvent
,
474 EFI_TIMER_PERIOD_SECONDS (1)
476 if (Status
== EFI_TIMEOUT
) {
477 DEBUG ((DEBUG_WARN
, "XenStore Write, waiting for a ring event.\n"));
483 /* Verify queue sanity. */
484 if (!XenStoreCheckIndexes (Cons
, Prod
)) {
485 xs
.XenStore
->req_cons
= xs
.XenStore
->req_prod
= 0;
486 return XENSTORE_STATUS_EIO
;
489 Dest
= XenStoreGetOutputChunk (Cons
, Prod
, xs
.XenStore
->req
, &Available
);
490 if (Available
> Len
) {
494 CopyMem (Dest
, Data
, Available
);
499 * The store to the producer index, which indicates
500 * to the other side that new data has arrived, must
501 * be visible only after our copy of the data into the
502 * ring has completed.
505 xs
.XenStore
->req_prod
+= Available
;
508 * The other side will see the change to req_prod at the time of the
512 XenEventChannelNotify (xs
.Dev
, xs
.EventChannel
);
515 return XENSTORE_STATUS_SUCCESS
;
519 Receive data from the XenStore service.
521 The buffer pointed to by DataPtr is at least Len bytes in length.
523 @param DataPtr A pointer to the contiguous buffer to receive the data.
524 @param Len The amount of data to receive.
526 @return On success 0, otherwise an errno value indicating the
536 XENSTORE_RING_IDX Cons
, Prod
;
537 CHAR8
*Data
= (CHAR8
*)DataPtr
;
543 Cons
= xs
.XenStore
->rsp_cons
;
544 Prod
= xs
.XenStore
->rsp_prod
;
547 * Nothing to read. Wait for a ring event.
549 * Note that the events from both queues are combined, so being woken
550 * does not guarantee that data exist in the read ring.
554 Status
= XenStoreWaitForEvent (
555 xs
.EventChannelEvent
,
556 EFI_TIMER_PERIOD_SECONDS (1)
558 if (Status
== EFI_TIMEOUT
) {
559 DEBUG ((DEBUG_WARN
, "XenStore Read, waiting for a ring event.\n"));
565 /* Verify queue sanity. */
566 if (!XenStoreCheckIndexes (Cons
, Prod
)) {
567 xs
.XenStore
->rsp_cons
= xs
.XenStore
->rsp_prod
= 0;
568 return XENSTORE_STATUS_EIO
;
571 Src
= XenStoreGetInputChunk (Cons
, Prod
, xs
.XenStore
->rsp
, &Available
);
572 if (Available
> Len
) {
577 * Insure the data we read is related to the indexes
582 CopyMem (Data
, Src
, Available
);
587 * Insure that the producer of this ring does not see
588 * the ring space as free until after we have copied it
592 xs
.XenStore
->rsp_cons
+= Available
;
595 * The producer will see the updated consumer index when the event is
599 XenEventChannelNotify (xs
.Dev
, xs
.EventChannel
);
602 return XENSTORE_STATUS_SUCCESS
;
606 // Received Message Processing
610 Block reading the next message from the XenStore service and
613 @return XENSTORE_STATUS_SUCCESS on success. Otherwise an errno value
614 indicating the type of failure encountered.
618 XenStoreProcessMessage (
622 XENSTORE_MESSAGE
*Message
;
624 XENSTORE_STATUS Status
;
626 Message
= AllocateZeroPool (sizeof (XENSTORE_MESSAGE
));
627 Message
->Signature
= XENSTORE_MESSAGE_SIGNATURE
;
628 Status
= XenStoreReadStore (&Message
->Header
, sizeof (Message
->Header
));
629 if (Status
!= XENSTORE_STATUS_SUCCESS
) {
631 DEBUG ((DEBUG_ERROR
, "XenStore: Error read store (%d)\n", Status
));
635 Body
= AllocatePool (Message
->Header
.len
+ 1);
636 Status
= XenStoreReadStore (Body
, Message
->Header
.len
);
637 if (Status
!= XENSTORE_STATUS_SUCCESS
) {
640 DEBUG ((DEBUG_ERROR
, "XenStore: Error read store (%d)\n", Status
));
644 Body
[Message
->Header
.len
] = '\0';
646 if (Message
->Header
.type
== XS_WATCH_EVENT
) {
647 Message
->u
.Watch
.Vector
= Split (
650 &Message
->u
.Watch
.VectorSize
653 EfiAcquireLock (&xs
.RegisteredWatchesLock
);
654 Message
->u
.Watch
.Handle
=
655 XenStoreFindWatch (Message
->u
.Watch
.Vector
[XS_WATCH_TOKEN
]);
658 "XenStore: Watch event %a\n",
659 Message
->u
.Watch
.Vector
[XS_WATCH_TOKEN
]
661 if (Message
->u
.Watch
.Handle
!= NULL
) {
662 EfiAcquireLock (&xs
.WatchEventsLock
);
663 InsertHeadList (&xs
.WatchEvents
, &Message
->Link
);
664 EfiReleaseLock (&xs
.WatchEventsLock
);
668 "XenStore: Watch handle %a not found\n",
669 Message
->u
.Watch
.Vector
[XS_WATCH_TOKEN
]
671 FreePool ((VOID
*)Message
->u
.Watch
.Vector
);
675 EfiReleaseLock (&xs
.RegisteredWatchesLock
);
677 Message
->u
.Reply
.Body
= Body
;
678 EfiAcquireLock (&xs
.ReplyLock
);
679 InsertTailList (&xs
.ReplyList
, &Message
->Link
);
680 EfiReleaseLock (&xs
.ReplyLock
);
683 return XENSTORE_STATUS_SUCCESS
;
687 // XenStore Message Request/Reply Processing
691 Convert a XenStore error string into an errno number.
693 Unknown error strings are converted to EINVAL.
695 @param errorstring The error string to convert.
697 @return The errno best matching the input string.
701 XENSTORE_STATUS Status
;
702 CONST CHAR8
*ErrorStr
;
705 static XenStoreErrors gXenStoreErrors
[] = {
706 { XENSTORE_STATUS_EINVAL
, "EINVAL" },
707 { XENSTORE_STATUS_EACCES
, "EACCES" },
708 { XENSTORE_STATUS_EEXIST
, "EEXIST" },
709 { XENSTORE_STATUS_EISDIR
, "EISDIR" },
710 { XENSTORE_STATUS_ENOENT
, "ENOENT" },
711 { XENSTORE_STATUS_ENOMEM
, "ENOMEM" },
712 { XENSTORE_STATUS_ENOSPC
, "ENOSPC" },
713 { XENSTORE_STATUS_EIO
, "EIO" },
714 { XENSTORE_STATUS_ENOTEMPTY
, "ENOTEMPTY" },
715 { XENSTORE_STATUS_ENOSYS
, "ENOSYS" },
716 { XENSTORE_STATUS_EROFS
, "EROFS" },
717 { XENSTORE_STATUS_EBUSY
, "EBUSY" },
718 { XENSTORE_STATUS_EAGAIN
, "EAGAIN" },
719 { XENSTORE_STATUS_EISCONN
, "EISCONN" },
720 { XENSTORE_STATUS_E2BIG
, "E2BIG" }
726 CONST CHAR8
*ErrorStr
731 for (Index
= 0; Index
< ARRAY_SIZE (gXenStoreErrors
); Index
++) {
732 if (!AsciiStrCmp (ErrorStr
, gXenStoreErrors
[Index
].ErrorStr
)) {
733 return gXenStoreErrors
[Index
].Status
;
737 DEBUG ((DEBUG_WARN
, "XenStore gave unknown error %a\n", ErrorStr
));
738 return XENSTORE_STATUS_EINVAL
;
742 Block waiting for a reply to a message request.
744 @param TypePtr The returned type of the reply.
745 @param LenPtr The returned body length of the reply.
746 @param Result The returned body of the reply.
751 OUT
enum xsd_sockmsg_type
*TypePtr
,
752 OUT UINT32
*LenPtr OPTIONAL
,
756 XENSTORE_MESSAGE
*Message
;
760 while (IsListEmpty (&xs
.ReplyList
)) {
761 XENSTORE_STATUS Status
;
762 Status
= XenStoreProcessMessage ();
763 if ((Status
!= XENSTORE_STATUS_SUCCESS
) && (Status
!= XENSTORE_STATUS_EAGAIN
)) {
766 "XenStore, error while reading the ring (%d).",
773 EfiAcquireLock (&xs
.ReplyLock
);
774 Entry
= GetFirstNode (&xs
.ReplyList
);
775 Message
= XENSTORE_MESSAGE_FROM_LINK (Entry
);
776 RemoveEntryList (Entry
);
777 EfiReleaseLock (&xs
.ReplyLock
);
779 *TypePtr
= Message
->Header
.type
;
780 if (LenPtr
!= NULL
) {
781 *LenPtr
= Message
->Header
.len
;
784 Body
= Message
->u
.Reply
.Body
;
788 return XENSTORE_STATUS_SUCCESS
;
792 Send a message with an optionally multi-part body to the XenStore service.
794 @param Transaction The transaction to use for this request.
795 @param RequestType The type of message to send.
796 @param WriteRequest Pointers to the body sections of the request.
797 @param NumRequests The number of body sections in the request.
798 @param LenPtr The returned length of the reply.
799 @param ResultPtr The returned body of the reply.
801 @return XENSTORE_STATUS_SUCCESS on success. Otherwise an errno indicating
802 the cause of failure.
807 IN CONST XENSTORE_TRANSACTION
*Transaction
,
808 IN
enum xsd_sockmsg_type RequestType
,
809 IN CONST WRITE_REQUEST
*WriteRequest
,
810 IN UINT32 NumRequests
,
811 OUT UINT32
*LenPtr OPTIONAL
,
812 OUT VOID
**ResultPtr OPTIONAL
815 struct xsd_sockmsg Message
;
818 XENSTORE_STATUS Status
;
820 if (Transaction
== XST_NIL
) {
823 Message
.tx_id
= Transaction
->Id
;
827 Message
.type
= RequestType
;
829 for (Index
= 0; Index
< NumRequests
; Index
++) {
830 Message
.len
+= WriteRequest
[Index
].Len
;
833 Status
= XenStoreWriteStore (&Message
, sizeof (Message
));
834 if (Status
!= XENSTORE_STATUS_SUCCESS
) {
835 DEBUG ((DEBUG_ERROR
, "XenStoreTalkv failed %d\n", Status
));
839 for (Index
= 0; Index
< NumRequests
; Index
++) {
840 Status
= XenStoreWriteStore (WriteRequest
[Index
].Data
, WriteRequest
[Index
].Len
);
841 if (Status
!= XENSTORE_STATUS_SUCCESS
) {
842 DEBUG ((DEBUG_ERROR
, "XenStoreTalkv failed %d\n", Status
));
847 Status
= XenStoreReadReply ((enum xsd_sockmsg_type
*)&Message
.type
, LenPtr
, &Return
);
850 if (Status
!= XENSTORE_STATUS_SUCCESS
) {
854 if (Message
.type
== XS_ERROR
) {
855 Status
= XenStoreGetError (Return
);
860 /* Reply is either error or an echo of our request message type. */
861 ASSERT ((enum xsd_sockmsg_type
)Message
.type
== RequestType
);
869 return XENSTORE_STATUS_SUCCESS
;
873 Wrapper for XenStoreTalkv allowing easy transmission of a message with
874 a single, contiguous, message body.
876 The returned result is provided in malloced storage and thus must be free'd
879 @param Transaction The transaction to use for this request.
880 @param RequestType The type of message to send.
881 @param Body The body of the request.
882 @param LenPtr The returned length of the reply.
883 @param Result The returned body of the reply.
885 @return 0 on success. Otherwise an errno indicating
886 the cause of failure.
891 IN CONST XENSTORE_TRANSACTION
*Transaction
,
892 IN
enum xsd_sockmsg_type RequestType
,
893 IN CONST CHAR8
*Body
,
894 OUT UINT32
*LenPtr OPTIONAL
,
895 OUT VOID
**Result OPTIONAL
898 WRITE_REQUEST WriteRequest
;
900 WriteRequest
.Data
= (VOID
*)Body
;
901 WriteRequest
.Len
= (UINT32
)AsciiStrSize (Body
);
903 return XenStoreTalkv (
914 // XenStore Watch Support
918 Transmit a watch request to the XenStore service.
920 @param Path The path in the XenStore to watch.
921 @param Tocken A unique identifier for this watch.
923 @return XENSTORE_STATUS_SUCCESS on success. Otherwise an errno indicating the
933 WRITE_REQUEST WriteRequest
[2];
935 WriteRequest
[0].Data
= (VOID
*)Path
;
936 WriteRequest
[0].Len
= (UINT32
)AsciiStrSize (Path
);
937 WriteRequest
[1].Data
= (VOID
*)Token
;
938 WriteRequest
[1].Len
= (UINT32
)AsciiStrSize (Token
);
940 return XenStoreTalkv (XST_NIL
, XS_WATCH
, WriteRequest
, 2, NULL
, NULL
);
944 Transmit an uwatch request to the XenStore service.
946 @param Path The path in the XenStore to watch.
947 @param Tocken A unique identifier for this watch.
949 @return XENSTORE_STATUS_SUCCESS on success. Otherwise an errno indicating
950 the cause of failure.
959 WRITE_REQUEST WriteRequest
[2];
961 WriteRequest
[0].Data
= (VOID
*)Path
;
962 WriteRequest
[0].Len
= (UINT32
)AsciiStrSize (Path
);
963 WriteRequest
[1].Data
= (VOID
*)Token
;
964 WriteRequest
[1].Len
= (UINT32
)AsciiStrSize (Token
);
966 return XenStoreTalkv (XST_NIL
, XS_UNWATCH
, WriteRequest
, 2, NULL
, NULL
);
975 XENSTORE_MESSAGE
*Message
;
976 LIST_ENTRY
*Entry
= NULL
;
977 LIST_ENTRY
*Last
= NULL
;
978 XENSTORE_STATUS Status
;
981 EfiAcquireLock (&xs
.WatchEventsLock
);
982 if (IsListEmpty (&xs
.WatchEvents
) ||
983 (Last
== GetFirstNode (&xs
.WatchEvents
)))
985 EfiReleaseLock (&xs
.WatchEventsLock
);
986 Status
= XenStoreProcessMessage ();
987 if ((Status
!= XENSTORE_STATUS_SUCCESS
) && (Status
!= XENSTORE_STATUS_EAGAIN
)) {
994 for (Entry
= GetFirstNode (&xs
.WatchEvents
);
995 Entry
!= Last
&& !IsNull (&xs
.WatchEvents
, Entry
);
996 Entry
= GetNextNode (&xs
.WatchEvents
, Entry
))
998 Message
= XENSTORE_MESSAGE_FROM_LINK (Entry
);
999 if (Message
->u
.Watch
.Handle
== Token
) {
1000 RemoveEntryList (Entry
);
1001 EfiReleaseLock (&xs
.WatchEventsLock
);
1002 FreePool ((VOID
*)Message
->u
.Watch
.Vector
);
1004 return XENSTORE_STATUS_SUCCESS
;
1008 Last
= GetFirstNode (&xs
.WatchEvents
);
1009 EfiReleaseLock (&xs
.WatchEventsLock
);
1015 NotifyEventChannelCheckForEvent (
1020 XENSTORE_PRIVATE
*xsp
;
1022 xsp
= (XENSTORE_PRIVATE
*)Context
;
1023 if (TestAndClearBit (xsp
->EventChannel
, xsp
->Dev
->SharedInfo
->evtchn_pending
)) {
1024 gBS
->SignalEvent (Event
);
1029 Setup communication channels with the XenStore service.
1031 @retval EFI_SUCCESS if everything went well.
1036 XENSTORE_PRIVATE
*xsp
1040 EFI_EVENT TimerEvent
;
1041 struct xenstore_domain_interface
*XenStore
= xsp
->XenStore
;
1043 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
1044 Status
= gBS
->SetTimer (
1047 EFI_TIMER_PERIOD_SECONDS (5)
1049 while (XenStore
->rsp_prod
!= XenStore
->rsp_cons
) {
1050 Status
= gBS
->CheckEvent (TimerEvent
);
1051 if (!EFI_ERROR (Status
)) {
1054 "XENSTORE response ring is not quiescent "
1055 "(%08x:%08x): fixing up\n",
1059 XenStore
->rsp_cons
= XenStore
->rsp_prod
;
1063 gBS
->CloseEvent (TimerEvent
);
1065 Status
= gBS
->CreateEvent (
1068 NotifyEventChannelCheckForEvent
,
1070 &xsp
->EventChannelEvent
1072 ASSERT_EFI_ERROR (Status
);
1078 Initialize XenStore.
1080 @param Dev A XENBUS_DEVICE instance.
1082 @retval EFI_SUCCESS if everything went well.
1092 * The HVM guest pseudo-physical frame number. This is Xen's mapping
1093 * of the true machine frame number into our "physical address space".
1099 xs
.EventChannel
= (evtchn_port_t
)XenHypercallHvmGetParam (HVM_PARAM_STORE_EVTCHN
);
1100 XenStoreGpfn
= (UINTN
)XenHypercallHvmGetParam (HVM_PARAM_STORE_PFN
);
1101 xs
.XenStore
= (VOID
*)(XenStoreGpfn
<< EFI_PAGE_SHIFT
);
1104 "XenBusInit: XenBus rings @%p, event channel %x\n",
1109 InitializeListHead (&xs
.ReplyList
);
1110 InitializeListHead (&xs
.WatchEvents
);
1111 InitializeListHead (&xs
.RegisteredWatches
);
1113 EfiInitializeLock (&xs
.ReplyLock
, TPL_NOTIFY
);
1114 EfiInitializeLock (&xs
.RegisteredWatchesLock
, TPL_NOTIFY
);
1115 EfiInitializeLock (&xs
.WatchEventsLock
, TPL_NOTIFY
);
1117 /* Initialize the shared memory rings to talk to xenstored */
1118 Status
= XenStoreInitComms (&xs
);
1125 IN XENBUS_DEVICE
*Dev
1129 // Emptying the list RegisteredWatches, but this list should already be
1130 // empty. Every driver that is using Watches should unregister them when
1133 if (!IsListEmpty (&xs
.RegisteredWatches
)) {
1134 XENSTORE_WATCH
*Watch
;
1136 DEBUG ((DEBUG_WARN
, "XenStore: RegisteredWatches is not empty, cleaning up..."));
1137 Entry
= GetFirstNode (&xs
.RegisteredWatches
);
1138 while (!IsNull (&xs
.RegisteredWatches
, Entry
)) {
1139 Watch
= XENSTORE_WATCH_FROM_LINK (Entry
);
1140 Entry
= GetNextNode (&xs
.RegisteredWatches
, Entry
);
1142 XenStoreUnregisterWatch (Watch
);
1147 // Emptying the list WatchEvents, but this list should already be empty after
1148 // having cleanup the list RegisteredWatches.
1150 if (!IsListEmpty (&xs
.WatchEvents
)) {
1152 DEBUG ((DEBUG_WARN
, "XenStore: WatchEvents is not empty, cleaning up..."));
1153 Entry
= GetFirstNode (&xs
.WatchEvents
);
1154 while (!IsNull (&xs
.WatchEvents
, Entry
)) {
1155 XENSTORE_MESSAGE
*Message
= XENSTORE_MESSAGE_FROM_LINK (Entry
);
1156 Entry
= GetNextNode (&xs
.WatchEvents
, Entry
);
1157 RemoveEntryList (&Message
->Link
);
1158 FreePool ((VOID
*)Message
->u
.Watch
.Vector
);
1163 if (!IsListEmpty (&xs
.ReplyList
)) {
1164 XENSTORE_MESSAGE
*Message
;
1166 Entry
= GetFirstNode (&xs
.ReplyList
);
1167 while (!IsNull (&xs
.ReplyList
, Entry
)) {
1168 Message
= XENSTORE_MESSAGE_FROM_LINK (Entry
);
1169 Entry
= GetNextNode (&xs
.ReplyList
, Entry
);
1170 RemoveEntryList (&Message
->Link
);
1171 FreePool (Message
->u
.Reply
.Body
);
1176 gBS
->CloseEvent (xs
.EventChannelEvent
);
1178 if (xs
.XenStore
->server_features
& XENSTORE_SERVER_FEATURE_RECONNECTION
) {
1179 xs
.XenStore
->connection
= XENSTORE_RECONNECT
;
1180 XenEventChannelNotify (xs
.Dev
, xs
.EventChannel
);
1181 while (*(volatile UINT32
*)&xs
.XenStore
->connection
== XENSTORE_RECONNECT
) {
1182 XenStoreWaitForEvent (xs
.EventChannelEvent
, EFI_TIMER_PERIOD_MILLISECONDS (100));
1185 /* If the backend reads the state while we're erasing it then the
1186 * ring state will become corrupted, preventing guest frontends from
1187 * connecting. This is rare. To help diagnose the failure, we fill
1188 * the ring with XS_INVALID packets. */
1189 SetMem (xs
.XenStore
->req
, XENSTORE_RING_SIZE
, 0xff);
1190 SetMem (xs
.XenStore
->rsp
, XENSTORE_RING_SIZE
, 0xff);
1191 xs
.XenStore
->req_cons
= xs
.XenStore
->req_prod
= 0;
1192 xs
.XenStore
->rsp_cons
= xs
.XenStore
->rsp_prod
= 0;
1200 // API comments for these methods can be found in XenStore.h
1204 XenStoreListDirectory (
1205 IN CONST XENSTORE_TRANSACTION
*Transaction
,
1206 IN CONST CHAR8
*DirectoryPath
,
1207 IN CONST CHAR8
*Node
,
1208 OUT UINT32
*DirectoryCountPtr
,
1209 OUT CONST CHAR8
***DirectoryListPtr
1215 XENSTORE_STATUS Status
;
1217 Path
= XenStoreJoin (DirectoryPath
, Node
);
1218 Status
= XenStoreSingle (
1226 if (Status
!= XENSTORE_STATUS_SUCCESS
) {
1230 *DirectoryListPtr
= Split (TempStr
, Len
, DirectoryCountPtr
);
1232 return XENSTORE_STATUS_SUCCESS
;
1236 XenStorePathExists (
1237 IN CONST XENSTORE_TRANSACTION
*Transaction
,
1238 IN CONST CHAR8
*Directory
,
1239 IN CONST CHAR8
*Node
1242 CONST CHAR8
**TempStr
;
1243 XENSTORE_STATUS Status
;
1246 Status
= XenStoreListDirectory (
1253 if (Status
!= XENSTORE_STATUS_SUCCESS
) {
1257 FreePool ((VOID
*)TempStr
);
1263 IN CONST XENSTORE_TRANSACTION
*Transaction
,
1264 IN CONST CHAR8
*DirectoryPath
,
1265 IN CONST CHAR8
*Node
,
1266 OUT UINT32
*LenPtr OPTIONAL
,
1272 XENSTORE_STATUS Status
;
1274 Path
= XenStoreJoin (DirectoryPath
, Node
);
1275 Status
= XenStoreSingle (Transaction
, XS_READ
, Path
, LenPtr
, &Value
);
1277 if (Status
!= XENSTORE_STATUS_SUCCESS
) {
1282 return XENSTORE_STATUS_SUCCESS
;
1287 IN CONST XENSTORE_TRANSACTION
*Transaction
,
1288 IN CONST CHAR8
*DirectoryPath
,
1289 IN CONST CHAR8
*Node
,
1294 WRITE_REQUEST WriteRequest
[2];
1295 XENSTORE_STATUS Status
;
1297 Path
= XenStoreJoin (DirectoryPath
, Node
);
1299 WriteRequest
[0].Data
= (VOID
*)Path
;
1300 WriteRequest
[0].Len
= (UINT32
)AsciiStrSize (Path
);
1301 WriteRequest
[1].Data
= (VOID
*)Str
;
1302 WriteRequest
[1].Len
= (UINT32
)AsciiStrLen (Str
);
1304 Status
= XenStoreTalkv (Transaction
, XS_WRITE
, WriteRequest
, 2, NULL
, NULL
);
1312 IN CONST XENSTORE_TRANSACTION
*Transaction
,
1313 IN CONST CHAR8
*DirectoryPath
,
1314 IN CONST CHAR8
*Node
1318 XENSTORE_STATUS Status
;
1320 Path
= XenStoreJoin (DirectoryPath
, Node
);
1321 Status
= XenStoreSingle (Transaction
, XS_RM
, Path
, NULL
, NULL
);
1328 XenStoreTransactionStart (
1329 OUT XENSTORE_TRANSACTION
*Transaction
1333 XENSTORE_STATUS Status
;
1335 Status
= XenStoreSingle (
1337 XS_TRANSACTION_START
,
1342 if (Status
== XENSTORE_STATUS_SUCCESS
) {
1343 Transaction
->Id
= (UINT32
)AsciiStrDecimalToUintn (IdStr
);
1351 XenStoreTransactionEnd (
1352 IN CONST XENSTORE_TRANSACTION
*Transaction
,
1358 AbortStr
[0] = Abort
? 'F' : 'T';
1361 return XenStoreSingle (Transaction
, XS_TRANSACTION_END
, AbortStr
, NULL
, NULL
);
1367 IN CONST XENSTORE_TRANSACTION
*Transaction
,
1368 IN CONST CHAR8
*DirectoryPath
,
1369 IN CONST CHAR8
*Node
,
1370 IN CONST CHAR8
*FormatString
,
1375 XENSTORE_STATUS Status
;
1379 VA_COPY (Marker2
, Marker
);
1380 BufSize
= SPrintLengthAsciiFormat (FormatString
, Marker2
) + 1;
1382 Buf
= AllocateZeroPool (BufSize
);
1383 AsciiVSPrint (Buf
, BufSize
, FormatString
, Marker
);
1384 Status
= XenStoreWrite (Transaction
, DirectoryPath
, Node
, Buf
);
1393 IN CONST XENSTORE_TRANSACTION
*Transaction
,
1394 IN CONST CHAR8
*DirectoryPath
,
1395 IN CONST CHAR8
*Node
,
1396 IN CONST CHAR8
*FormatString
,
1401 XENSTORE_STATUS Status
;
1403 VA_START (Marker
, FormatString
);
1404 Status
= XenStoreVSPrint (Transaction
, DirectoryPath
, Node
, FormatString
, Marker
);
1411 XenStoreRegisterWatch (
1412 IN CONST CHAR8
*DirectoryPath
,
1413 IN CONST CHAR8
*Node
,
1414 OUT XENSTORE_WATCH
**WatchPtr
1417 /* Pointer in ascii is the token. */
1418 CHAR8 Token
[sizeof (XENSTORE_WATCH
) * 2 + 1];
1419 XENSTORE_STATUS Status
;
1420 XENSTORE_WATCH
*Watch
;
1422 Watch
= AllocateZeroPool (sizeof (XENSTORE_WATCH
));
1423 Watch
->Signature
= XENSTORE_WATCH_SIGNATURE
;
1424 Watch
->Node
= XenStoreJoin (DirectoryPath
, Node
);
1426 EfiAcquireLock (&xs
.RegisteredWatchesLock
);
1427 InsertTailList (&xs
.RegisteredWatches
, &Watch
->Link
);
1428 EfiReleaseLock (&xs
.RegisteredWatchesLock
);
1430 AsciiSPrint (Token
, sizeof (Token
), "%p", (VOID
*)Watch
);
1431 Status
= XenStoreWatch (Watch
->Node
, Token
);
1433 /* Ignore errors due to multiple registration. */
1434 if (Status
== XENSTORE_STATUS_EEXIST
) {
1435 Status
= XENSTORE_STATUS_SUCCESS
;
1438 if (Status
== XENSTORE_STATUS_SUCCESS
) {
1441 EfiAcquireLock (&xs
.RegisteredWatchesLock
);
1442 RemoveEntryList (&Watch
->Link
);
1443 EfiReleaseLock (&xs
.RegisteredWatchesLock
);
1444 FreePool (Watch
->Node
);
1452 XenStoreUnregisterWatch (
1453 IN XENSTORE_WATCH
*Watch
1456 CHAR8 Token
[sizeof (Watch
) * 2 + 1];
1459 ASSERT (Watch
->Signature
== XENSTORE_WATCH_SIGNATURE
);
1461 AsciiSPrint (Token
, sizeof (Token
), "%p", (VOID
*)Watch
);
1462 if (XenStoreFindWatch (Token
) == NULL
) {
1466 EfiAcquireLock (&xs
.RegisteredWatchesLock
);
1467 RemoveEntryList (&Watch
->Link
);
1468 EfiReleaseLock (&xs
.RegisteredWatchesLock
);
1470 XenStoreUnwatch (Watch
->Node
, Token
);
1472 /* Cancel pending watch events. */
1473 EfiAcquireLock (&xs
.WatchEventsLock
);
1474 Entry
= GetFirstNode (&xs
.WatchEvents
);
1475 while (!IsNull (&xs
.WatchEvents
, Entry
)) {
1476 XENSTORE_MESSAGE
*Message
= XENSTORE_MESSAGE_FROM_LINK (Entry
);
1477 Entry
= GetNextNode (&xs
.WatchEvents
, Entry
);
1478 if (Message
->u
.Watch
.Handle
== Watch
) {
1479 RemoveEntryList (&Message
->Link
);
1480 FreePool ((VOID
*)Message
->u
.Watch
.Vector
);
1485 EfiReleaseLock (&xs
.WatchEventsLock
);
1487 FreePool (Watch
->Node
);
1497 XenBusWaitForWatch (
1498 IN XENBUS_PROTOCOL
*This
,
1502 return XenStoreWaitWatch (Token
);
1507 XenBusXenStoreRead (
1508 IN XENBUS_PROTOCOL
*This
,
1509 IN CONST XENSTORE_TRANSACTION
*Transaction
,
1510 IN CONST CHAR8
*Node
,
1514 return XenStoreRead (Transaction
, This
->Node
, Node
, NULL
, Value
);
1519 XenBusXenStoreBackendRead (
1520 IN XENBUS_PROTOCOL
*This
,
1521 IN CONST XENSTORE_TRANSACTION
*Transaction
,
1522 IN CONST CHAR8
*Node
,
1526 return XenStoreRead (Transaction
, This
->Backend
, Node
, NULL
, Value
);
1531 XenBusXenStoreRemove (
1532 IN XENBUS_PROTOCOL
*This
,
1533 IN CONST XENSTORE_TRANSACTION
*Transaction
,
1537 return XenStoreRemove (Transaction
, This
->Node
, Node
);
1542 XenBusXenStoreTransactionStart (
1543 IN XENBUS_PROTOCOL
*This
,
1544 OUT XENSTORE_TRANSACTION
*Transaction
1547 return XenStoreTransactionStart (Transaction
);
1552 XenBusXenStoreTransactionEnd (
1553 IN XENBUS_PROTOCOL
*This
,
1554 IN CONST XENSTORE_TRANSACTION
*Transaction
,
1558 return XenStoreTransactionEnd (Transaction
, Abort
);
1563 XenBusXenStoreSPrint (
1564 IN XENBUS_PROTOCOL
*This
,
1565 IN CONST XENSTORE_TRANSACTION
*Transaction
,
1566 IN CONST CHAR8
*DirectoryPath
,
1567 IN CONST CHAR8
*Node
,
1568 IN CONST CHAR8
*FormatString
,
1573 XENSTORE_STATUS Status
;
1575 VA_START (Marker
, FormatString
);
1576 Status
= XenStoreVSPrint (Transaction
, DirectoryPath
, Node
, FormatString
, Marker
);
1584 XenBusRegisterWatch (
1585 IN XENBUS_PROTOCOL
*This
,
1586 IN CONST CHAR8
*Node
,
1590 return XenStoreRegisterWatch (This
->Node
, Node
, (XENSTORE_WATCH
**)Token
);
1595 XenBusRegisterWatchBackend (
1596 IN XENBUS_PROTOCOL
*This
,
1597 IN CONST CHAR8
*Node
,
1601 return XenStoreRegisterWatch (This
->Backend
, Node
, (XENSTORE_WATCH
**)Token
);
1606 XenBusUnregisterWatch (
1607 IN XENBUS_PROTOCOL
*This
,
1611 XenStoreUnregisterWatch ((XENSTORE_WATCH
*)Token
);