]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/XenBusDxe/XenStore.c
IntelFsp2Pkg/SplitFspBin.py: Support rebasing 1.x binary.
[mirror_edk2.git] / OvmfPkg / XenBusDxe / XenStore.c
1 /** @file
2 Low-level kernel interface to the XenStore.
3
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
9 XenStore.
10
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.
15
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
22 guest.
23
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.
27
28 Several Xen services depend on the XenStore, most notably the
29 XenBus used to discover and manage Xen devices.
30
31 Copyright (C) 2005 Rusty Russell, IBM Corporation
32 Copyright (C) 2009,2010 Spectra Logic Corporation
33 Copyright (C) 2014, Citrix Ltd.
34
35 This file may be distributed separately from the Linux kernel, or
36 incorporated into other software packages, subject to the following license:
37
38 SPDX-License-Identifier: MIT
39 **/
40
41 #include "XenStore.h"
42
43 #include <Library/PrintLib.h>
44
45 #include <IndustryStandard/Xen/hvm/params.h>
46
47 #include "EventChannel.h"
48 #include <Library/XenHypercallLib.h>
49
50 //
51 // Private Data Structures
52 //
53
54 typedef struct {
55 CONST VOID *Data;
56 UINT32 Len;
57 } WRITE_REQUEST;
58
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
62 {
63 UINT32 Signature;
64 LIST_ENTRY Link;
65
66 /* Path being watched. */
67 CHAR8 *Node;
68 };
69
70 #define XENSTORE_WATCH_FROM_LINK(l) \
71 CR (l, XENSTORE_WATCH, Link, XENSTORE_WATCH_SIGNATURE)
72
73
74 /**
75 * Structure capturing messages received from the XenStore service.
76 */
77 #define XENSTORE_MESSAGE_SIGNATURE SIGNATURE_32 ('X', 'S', 's', 'm')
78 typedef struct {
79 UINT32 Signature;
80 LIST_ENTRY Link;
81
82 struct xsd_sockmsg Header;
83
84 union {
85 /* Queued replies. */
86 struct {
87 CHAR8 *Body;
88 } Reply;
89
90 /* Queued watch events. */
91 struct {
92 XENSTORE_WATCH *Handle;
93 CONST CHAR8 **Vector;
94 UINT32 VectorSize;
95 } Watch;
96 } u;
97 } XENSTORE_MESSAGE;
98 #define XENSTORE_MESSAGE_FROM_LINK(r) \
99 CR (r, XENSTORE_MESSAGE, Link, XENSTORE_MESSAGE_SIGNATURE)
100
101 /**
102 * Container for all XenStore related state.
103 */
104 typedef struct {
105 /**
106 * Pointer to shared memory communication structures allowing us
107 * to communicate with the XenStore service.
108 */
109 struct xenstore_domain_interface *XenStore;
110
111 XENBUS_DEVICE *Dev;
112
113 /**
114 * A list of replies to our requests.
115 *
116 * The reply list is filled by xs_rcv_thread(). It
117 * is consumed by the context that issued the request
118 * to which a reply is made. The requester blocks in
119 * XenStoreReadReply ().
120 *
121 * /note Only one requesting context can be active at a time.
122 */
123 LIST_ENTRY ReplyList;
124
125 /** Lock protecting the reply list. */
126 EFI_LOCK ReplyLock;
127
128 /**
129 * List of registered watches.
130 */
131 LIST_ENTRY RegisteredWatches;
132
133 /** Lock protecting the registered watches list. */
134 EFI_LOCK RegisteredWatchesLock;
135
136 /**
137 * List of pending watch callback events.
138 */
139 LIST_ENTRY WatchEvents;
140
141 /** Lock protecting the watch calback list. */
142 EFI_LOCK WatchEventsLock;
143
144 /**
145 * The event channel for communicating with the
146 * XenStore service.
147 */
148 evtchn_port_t EventChannel;
149
150 /** Handle for XenStore events. */
151 EFI_EVENT EventChannelEvent;
152 } XENSTORE_PRIVATE;
153
154 //
155 // Global Data
156 //
157 static XENSTORE_PRIVATE xs;
158
159
160 //
161 // Private Utility Functions
162 //
163
164 /**
165 Count and optionally record pointers to a number of NUL terminated
166 strings in a buffer.
167
168 @param Strings A pointer to a contiguous buffer of NUL terminated strings.
169 @param Len The length of the buffer pointed to by strings.
170 @param Dst An array to store pointers to each string found in strings.
171
172 @return A count of the number of strings found.
173 **/
174 STATIC
175 UINT32
176 ExtractStrings (
177 IN CONST CHAR8 *Strings,
178 IN UINTN Len,
179 OUT CONST CHAR8 **Dst OPTIONAL
180 )
181 {
182 UINT32 Num = 0;
183 CONST CHAR8 *Ptr;
184
185 for (Ptr = Strings; Ptr < Strings + Len; Ptr += AsciiStrSize (Ptr)) {
186 if (Dst != NULL) {
187 *Dst++ = Ptr;
188 }
189 Num++;
190 }
191
192 return Num;
193 }
194
195 /**
196 Convert a contiguous buffer containing a series of NUL terminated
197 strings into an array of pointers to strings.
198
199 The returned pointer references the array of string pointers which
200 is followed by the storage for the string data. It is the client's
201 responsibility to free this storage.
202
203 The storage addressed by Strings is free'd prior to Split returning.
204
205 @param Strings A pointer to a contiguous buffer of NUL terminated strings.
206 @param Len The length of the buffer pointed to by strings.
207 @param NumPtr The number of strings found and returned in the strings
208 array.
209
210 @return An array of pointers to the strings found in the input buffer.
211 **/
212 STATIC
213 CONST CHAR8 **
214 Split (
215 IN CHAR8 *Strings,
216 IN UINTN Len,
217 OUT UINT32 *NumPtr
218 )
219 {
220 CONST CHAR8 **Dst;
221
222 ASSERT(NumPtr != NULL);
223 ASSERT(Strings != NULL);
224
225 /* Protect against unterminated buffers. */
226 if (Len > 0) {
227 Strings[Len - 1] = '\0';
228 }
229
230 /* Count the Strings. */
231 *NumPtr = ExtractStrings (Strings, Len, NULL);
232
233 /* Transfer to one big alloc for easy freeing by the caller. */
234 Dst = AllocatePool (*NumPtr * sizeof (CHAR8 *) + Len);
235 CopyMem ((VOID*)&Dst[*NumPtr], Strings, Len);
236 FreePool (Strings);
237
238 /* Extract pointers to newly allocated array. */
239 Strings = (CHAR8 *) &Dst[*NumPtr];
240 ExtractStrings (Strings, Len, Dst);
241
242 return (Dst);
243 }
244
245 /**
246 Convert from watch token (unique identifier) to the associated
247 internal tracking structure for this watch.
248
249 @param Tocken The unique identifier for the watch to find.
250
251 @return A pointer to the found watch structure or NULL.
252 **/
253 STATIC
254 XENSTORE_WATCH *
255 XenStoreFindWatch (
256 IN CONST CHAR8 *Token
257 )
258 {
259 XENSTORE_WATCH *Watch, *WantedWatch;
260 LIST_ENTRY *Entry;
261
262 WantedWatch = (VOID *) AsciiStrHexToUintn (Token);
263
264 if (IsListEmpty (&xs.RegisteredWatches)) {
265 return NULL;
266 }
267 for (Entry = GetFirstNode (&xs.RegisteredWatches);
268 !IsNull (&xs.RegisteredWatches, Entry);
269 Entry = GetNextNode (&xs.RegisteredWatches, Entry)) {
270 Watch = XENSTORE_WATCH_FROM_LINK (Entry);
271 if (Watch == WantedWatch)
272 return Watch;
273 }
274
275 return NULL;
276 }
277
278 //
279 // Public Utility Functions
280 // API comments for these methods can be found in XenStore.h
281 //
282
283 CHAR8 *
284 XenStoreJoin (
285 IN CONST CHAR8 *DirectoryPath,
286 IN CONST CHAR8 *Node
287 )
288 {
289 CHAR8 *Buf;
290 UINTN BufSize;
291
292 /* +1 for '/' and +1 for '\0' */
293 BufSize = AsciiStrLen (DirectoryPath) + AsciiStrLen (Node) + 2;
294 Buf = AllocatePool (BufSize);
295 ASSERT (Buf != NULL);
296
297 if (Node[0] == '\0') {
298 AsciiSPrint (Buf, BufSize, "%a", DirectoryPath);
299 } else {
300 AsciiSPrint (Buf, BufSize, "%a/%a", DirectoryPath, Node);
301 }
302
303 return Buf;
304 }
305
306 //
307 // Low Level Communication Management
308 //
309
310 /**
311 Verify that the indexes for a ring are valid.
312
313 The difference between the producer and consumer cannot
314 exceed the size of the ring.
315
316 @param Cons The consumer index for the ring to test.
317 @param Prod The producer index for the ring to test.
318
319 @retval TRUE If indexes are in range.
320 @retval FALSE If the indexes are out of range.
321 **/
322 STATIC
323 BOOLEAN
324 XenStoreCheckIndexes (
325 XENSTORE_RING_IDX Cons,
326 XENSTORE_RING_IDX Prod
327 )
328 {
329 return ((Prod - Cons) <= XENSTORE_RING_SIZE);
330 }
331
332 /**
333 Return a pointer to, and the length of, the contiguous
334 free region available for output in a ring buffer.
335
336 @param Cons The consumer index for the ring.
337 @param Prod The producer index for the ring.
338 @param Buffer The base address of the ring's storage.
339 @param LenPtr The amount of contiguous storage available.
340
341 @return A pointer to the start location of the free region.
342 **/
343 STATIC
344 VOID *
345 XenStoreGetOutputChunk (
346 IN XENSTORE_RING_IDX Cons,
347 IN XENSTORE_RING_IDX Prod,
348 IN CHAR8 *Buffer,
349 OUT UINT32 *LenPtr
350 )
351 {
352 UINT32 Len;
353 Len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX (Prod);
354 if ((XENSTORE_RING_SIZE - (Prod - Cons)) < Len) {
355 Len = XENSTORE_RING_SIZE - (Prod - Cons);
356 }
357 *LenPtr = Len;
358 return (Buffer + MASK_XENSTORE_IDX (Prod));
359 }
360
361 /**
362 Return a pointer to, and the length of, the contiguous
363 data available to read from a ring buffer.
364
365 @param Cons The consumer index for the ring.
366 @param Prod The producer index for the ring.
367 @param Buffer The base address of the ring's storage.
368 @param LenPtr The amount of contiguous data available to read.
369
370 @return A pointer to the start location of the available data.
371 **/
372 STATIC
373 CONST VOID *
374 XenStoreGetInputChunk (
375 IN XENSTORE_RING_IDX Cons,
376 IN XENSTORE_RING_IDX Prod,
377 IN CONST CHAR8 *Buffer,
378 OUT UINT32 *LenPtr
379 )
380 {
381 UINT32 Len;
382
383 Len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX (Cons);
384 if ((Prod - Cons) < Len) {
385 Len = Prod - Cons;
386 }
387 *LenPtr = Len;
388 return (Buffer + MASK_XENSTORE_IDX (Cons));
389 }
390
391 /**
392 Wait for an event or timeout.
393
394 @param Event Event to wait for.
395 @param Timeout A timeout value in 100ns units.
396
397 @retval EFI_SUCCESS Event have been triggered or the current TPL is not
398 TPL_APPLICATION.
399 @retval EFI_TIMEOUT Timeout have expired.
400 **/
401 STATIC
402 EFI_STATUS
403 XenStoreWaitForEvent (
404 IN EFI_EVENT Event,
405 IN UINT64 Timeout
406 )
407 {
408 UINTN Index;
409 EFI_STATUS Status;
410 EFI_EVENT TimerEvent;
411 EFI_EVENT WaitList[2];
412
413 gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
414 gBS->SetTimer (TimerEvent, TimerRelative, Timeout);
415
416 WaitList[0] = xs.EventChannelEvent;
417 WaitList[1] = TimerEvent;
418 Status = gBS->WaitForEvent (2, WaitList, &Index);
419 ASSERT (Status != EFI_INVALID_PARAMETER);
420 gBS->CloseEvent (TimerEvent);
421 if (Status == EFI_UNSUPPORTED) {
422 return EFI_SUCCESS;
423 }
424 if (Index == 1) {
425 return EFI_TIMEOUT;
426 } else {
427 return EFI_SUCCESS;
428 }
429 }
430
431 /**
432 Transmit data to the XenStore service.
433
434 The buffer pointed to by DataPtr is at least Len bytes in length.
435
436 @param DataPtr A pointer to the contiguous data to send.
437 @param Len The amount of data to send.
438
439 @return On success 0, otherwise an errno value indicating the
440 cause of failure.
441 **/
442 STATIC
443 XENSTORE_STATUS
444 XenStoreWriteStore (
445 IN CONST VOID *DataPtr,
446 IN UINT32 Len
447 )
448 {
449 XENSTORE_RING_IDX Cons, Prod;
450 CONST CHAR8 *Data = (CONST CHAR8 *)DataPtr;
451
452 while (Len != 0) {
453 void *Dest;
454 UINT32 Available;
455
456 Cons = xs.XenStore->req_cons;
457 Prod = xs.XenStore->req_prod;
458 if ((Prod - Cons) == XENSTORE_RING_SIZE) {
459 /*
460 * Output ring is full. Wait for a ring event.
461 *
462 * Note that the events from both queues are combined, so being woken
463 * does not guarantee that data exist in the read ring.
464 */
465 EFI_STATUS Status;
466
467 Status = XenStoreWaitForEvent (xs.EventChannelEvent,
468 EFI_TIMER_PERIOD_SECONDS (1));
469 if (Status == EFI_TIMEOUT) {
470 DEBUG ((EFI_D_WARN, "XenStore Write, waiting for a ring event.\n"));
471 }
472 continue;
473 }
474
475 /* Verify queue sanity. */
476 if (!XenStoreCheckIndexes (Cons, Prod)) {
477 xs.XenStore->req_cons = xs.XenStore->req_prod = 0;
478 return XENSTORE_STATUS_EIO;
479 }
480
481 Dest = XenStoreGetOutputChunk (Cons, Prod, xs.XenStore->req, &Available);
482 if (Available > Len) {
483 Available = Len;
484 }
485
486 CopyMem (Dest, Data, Available);
487 Data += Available;
488 Len -= Available;
489
490 /*
491 * The store to the producer index, which indicates
492 * to the other side that new data has arrived, must
493 * be visible only after our copy of the data into the
494 * ring has completed.
495 */
496 MemoryFence ();
497 xs.XenStore->req_prod += Available;
498
499 /*
500 * The other side will see the change to req_prod at the time of the
501 * interrupt.
502 */
503 MemoryFence ();
504 XenEventChannelNotify (xs.Dev, xs.EventChannel);
505 }
506
507 return XENSTORE_STATUS_SUCCESS;
508 }
509
510 /**
511 Receive data from the XenStore service.
512
513 The buffer pointed to by DataPtr is at least Len bytes in length.
514
515 @param DataPtr A pointer to the contiguous buffer to receive the data.
516 @param Len The amount of data to receive.
517
518 @return On success 0, otherwise an errno value indicating the
519 cause of failure.
520 **/
521 STATIC
522 XENSTORE_STATUS
523 XenStoreReadStore (
524 OUT VOID *DataPtr,
525 IN UINT32 Len
526 )
527 {
528 XENSTORE_RING_IDX Cons, Prod;
529 CHAR8 *Data = (CHAR8 *) DataPtr;
530
531 while (Len != 0) {
532 UINT32 Available;
533 CONST CHAR8 *Src;
534
535 Cons = xs.XenStore->rsp_cons;
536 Prod = xs.XenStore->rsp_prod;
537 if (Cons == Prod) {
538 /*
539 * Nothing to read. Wait for a ring event.
540 *
541 * Note that the events from both queues are combined, so being woken
542 * does not guarantee that data exist in the read ring.
543 */
544 EFI_STATUS Status;
545
546 Status = XenStoreWaitForEvent (xs.EventChannelEvent,
547 EFI_TIMER_PERIOD_SECONDS (1));
548 if (Status == EFI_TIMEOUT) {
549 DEBUG ((EFI_D_WARN, "XenStore Read, waiting for a ring event.\n"));
550 }
551 continue;
552 }
553
554 /* Verify queue sanity. */
555 if (!XenStoreCheckIndexes (Cons, Prod)) {
556 xs.XenStore->rsp_cons = xs.XenStore->rsp_prod = 0;
557 return XENSTORE_STATUS_EIO;
558 }
559
560 Src = XenStoreGetInputChunk (Cons, Prod, xs.XenStore->rsp, &Available);
561 if (Available > Len) {
562 Available = Len;
563 }
564
565 /*
566 * Insure the data we read is related to the indexes
567 * we read above.
568 */
569 MemoryFence ();
570
571 CopyMem (Data, Src, Available);
572 Data += Available;
573 Len -= Available;
574
575 /*
576 * Insure that the producer of this ring does not see
577 * the ring space as free until after we have copied it
578 * out.
579 */
580 MemoryFence ();
581 xs.XenStore->rsp_cons += Available;
582
583 /*
584 * The producer will see the updated consumer index when the event is
585 * delivered.
586 */
587 MemoryFence ();
588 XenEventChannelNotify (xs.Dev, xs.EventChannel);
589 }
590
591 return XENSTORE_STATUS_SUCCESS;
592 }
593
594 //
595 // Received Message Processing
596 //
597
598 /**
599 Block reading the next message from the XenStore service and
600 process the result.
601
602 @return XENSTORE_STATUS_SUCCESS on success. Otherwise an errno value
603 indicating the type of failure encountered.
604 **/
605 STATIC
606 XENSTORE_STATUS
607 XenStoreProcessMessage (
608 VOID
609 )
610 {
611 XENSTORE_MESSAGE *Message;
612 CHAR8 *Body;
613 XENSTORE_STATUS Status;
614
615 Message = AllocateZeroPool (sizeof (XENSTORE_MESSAGE));
616 Message->Signature = XENSTORE_MESSAGE_SIGNATURE;
617 Status = XenStoreReadStore (&Message->Header, sizeof (Message->Header));
618 if (Status != XENSTORE_STATUS_SUCCESS) {
619 FreePool (Message);
620 DEBUG ((EFI_D_ERROR, "XenStore: Error read store (%d)\n", Status));
621 return Status;
622 }
623
624 Body = AllocatePool (Message->Header.len + 1);
625 Status = XenStoreReadStore (Body, Message->Header.len);
626 if (Status != XENSTORE_STATUS_SUCCESS) {
627 FreePool (Body);
628 FreePool (Message);
629 DEBUG ((EFI_D_ERROR, "XenStore: Error read store (%d)\n", Status));
630 return Status;
631 }
632 Body[Message->Header.len] = '\0';
633
634 if (Message->Header.type == XS_WATCH_EVENT) {
635 Message->u.Watch.Vector = Split(Body, Message->Header.len,
636 &Message->u.Watch.VectorSize);
637
638 EfiAcquireLock (&xs.RegisteredWatchesLock);
639 Message->u.Watch.Handle =
640 XenStoreFindWatch (Message->u.Watch.Vector[XS_WATCH_TOKEN]);
641 DEBUG ((EFI_D_INFO, "XenStore: Watch event %a\n",
642 Message->u.Watch.Vector[XS_WATCH_TOKEN]));
643 if (Message->u.Watch.Handle != NULL) {
644 EfiAcquireLock (&xs.WatchEventsLock);
645 InsertHeadList (&xs.WatchEvents, &Message->Link);
646 EfiReleaseLock (&xs.WatchEventsLock);
647 } else {
648 DEBUG ((EFI_D_WARN, "XenStore: Watch handle %a not found\n",
649 Message->u.Watch.Vector[XS_WATCH_TOKEN]));
650 FreePool((VOID*)Message->u.Watch.Vector);
651 FreePool(Message);
652 }
653 EfiReleaseLock (&xs.RegisteredWatchesLock);
654 } else {
655 Message->u.Reply.Body = Body;
656 EfiAcquireLock (&xs.ReplyLock);
657 InsertTailList (&xs.ReplyList, &Message->Link);
658 EfiReleaseLock (&xs.ReplyLock);
659 }
660
661 return XENSTORE_STATUS_SUCCESS;
662 }
663
664 //
665 // XenStore Message Request/Reply Processing
666 //
667
668 /**
669 Convert a XenStore error string into an errno number.
670
671 Unknown error strings are converted to EINVAL.
672
673 @param errorstring The error string to convert.
674
675 @return The errno best matching the input string.
676
677 **/
678 typedef struct {
679 XENSTORE_STATUS Status;
680 CONST CHAR8 *ErrorStr;
681 } XenStoreErrors;
682
683 static XenStoreErrors gXenStoreErrors[] = {
684 { XENSTORE_STATUS_EINVAL, "EINVAL" },
685 { XENSTORE_STATUS_EACCES, "EACCES" },
686 { XENSTORE_STATUS_EEXIST, "EEXIST" },
687 { XENSTORE_STATUS_EISDIR, "EISDIR" },
688 { XENSTORE_STATUS_ENOENT, "ENOENT" },
689 { XENSTORE_STATUS_ENOMEM, "ENOMEM" },
690 { XENSTORE_STATUS_ENOSPC, "ENOSPC" },
691 { XENSTORE_STATUS_EIO, "EIO" },
692 { XENSTORE_STATUS_ENOTEMPTY, "ENOTEMPTY" },
693 { XENSTORE_STATUS_ENOSYS, "ENOSYS" },
694 { XENSTORE_STATUS_EROFS, "EROFS" },
695 { XENSTORE_STATUS_EBUSY, "EBUSY" },
696 { XENSTORE_STATUS_EAGAIN, "EAGAIN" },
697 { XENSTORE_STATUS_EISCONN, "EISCONN" },
698 { XENSTORE_STATUS_E2BIG, "E2BIG" }
699 };
700
701 STATIC
702 XENSTORE_STATUS
703 XenStoreGetError (
704 CONST CHAR8 *ErrorStr
705 )
706 {
707 UINT32 Index;
708
709 for (Index = 0; Index < ARRAY_SIZE(gXenStoreErrors); Index++) {
710 if (!AsciiStrCmp (ErrorStr, gXenStoreErrors[Index].ErrorStr)) {
711 return gXenStoreErrors[Index].Status;
712 }
713 }
714 DEBUG ((EFI_D_WARN, "XenStore gave unknown error %a\n", ErrorStr));
715 return XENSTORE_STATUS_EINVAL;
716 }
717
718 /**
719 Block waiting for a reply to a message request.
720
721 @param TypePtr The returned type of the reply.
722 @param LenPtr The returned body length of the reply.
723 @param Result The returned body of the reply.
724 **/
725 STATIC
726 XENSTORE_STATUS
727 XenStoreReadReply (
728 OUT enum xsd_sockmsg_type *TypePtr,
729 OUT UINT32 *LenPtr OPTIONAL,
730 OUT VOID **Result
731 )
732 {
733 XENSTORE_MESSAGE *Message;
734 LIST_ENTRY *Entry;
735 CHAR8 *Body;
736
737 while (IsListEmpty (&xs.ReplyList)) {
738 XENSTORE_STATUS Status;
739 Status = XenStoreProcessMessage ();
740 if (Status != XENSTORE_STATUS_SUCCESS && Status != XENSTORE_STATUS_EAGAIN) {
741 DEBUG ((EFI_D_ERROR, "XenStore, error while reading the ring (%d).",
742 Status));
743 return Status;
744 }
745 }
746 EfiAcquireLock (&xs.ReplyLock);
747 Entry = GetFirstNode (&xs.ReplyList);
748 Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
749 RemoveEntryList (Entry);
750 EfiReleaseLock (&xs.ReplyLock);
751
752 *TypePtr = Message->Header.type;
753 if (LenPtr != NULL) {
754 *LenPtr = Message->Header.len;
755 }
756 Body = Message->u.Reply.Body;
757
758 FreePool (Message);
759 *Result = Body;
760 return XENSTORE_STATUS_SUCCESS;
761 }
762
763 /**
764 Send a message with an optionally muti-part body to the XenStore service.
765
766 @param Transaction The transaction to use for this request.
767 @param RequestType The type of message to send.
768 @param WriteRequest Pointers to the body sections of the request.
769 @param NumRequests The number of body sections in the request.
770 @param LenPtr The returned length of the reply.
771 @param ResultPtr The returned body of the reply.
772
773 @return XENSTORE_STATUS_SUCCESS on success. Otherwise an errno indicating
774 the cause of failure.
775 **/
776 STATIC
777 XENSTORE_STATUS
778 XenStoreTalkv (
779 IN CONST XENSTORE_TRANSACTION *Transaction,
780 IN enum xsd_sockmsg_type RequestType,
781 IN CONST WRITE_REQUEST *WriteRequest,
782 IN UINT32 NumRequests,
783 OUT UINT32 *LenPtr OPTIONAL,
784 OUT VOID **ResultPtr OPTIONAL
785 )
786 {
787 struct xsd_sockmsg Message;
788 void *Return = NULL;
789 UINT32 Index;
790 XENSTORE_STATUS Status;
791
792 if (Transaction == XST_NIL) {
793 Message.tx_id = 0;
794 } else {
795 Message.tx_id = Transaction->Id;
796 }
797 Message.req_id = 0;
798 Message.type = RequestType;
799 Message.len = 0;
800 for (Index = 0; Index < NumRequests; Index++) {
801 Message.len += WriteRequest[Index].Len;
802 }
803
804 Status = XenStoreWriteStore (&Message, sizeof (Message));
805 if (Status != XENSTORE_STATUS_SUCCESS) {
806 DEBUG ((EFI_D_ERROR, "XenStoreTalkv failed %d\n", Status));
807 goto Error;
808 }
809
810 for (Index = 0; Index < NumRequests; Index++) {
811 Status = XenStoreWriteStore (WriteRequest[Index].Data, WriteRequest[Index].Len);
812 if (Status != XENSTORE_STATUS_SUCCESS) {
813 DEBUG ((EFI_D_ERROR, "XenStoreTalkv failed %d\n", Status));
814 goto Error;
815 }
816 }
817
818 Status = XenStoreReadReply ((enum xsd_sockmsg_type *)&Message.type, LenPtr, &Return);
819
820 Error:
821 if (Status != XENSTORE_STATUS_SUCCESS) {
822 return Status;
823 }
824
825 if (Message.type == XS_ERROR) {
826 Status = XenStoreGetError (Return);
827 FreePool (Return);
828 return Status;
829 }
830
831 /* Reply is either error or an echo of our request message type. */
832 ASSERT ((enum xsd_sockmsg_type)Message.type == RequestType);
833
834 if (ResultPtr) {
835 *ResultPtr = Return;
836 } else {
837 FreePool (Return);
838 }
839
840 return XENSTORE_STATUS_SUCCESS;
841 }
842
843 /**
844 Wrapper for XenStoreTalkv allowing easy transmission of a message with
845 a single, contiguous, message body.
846
847 The returned result is provided in malloced storage and thus must be free'd
848 by the caller.
849
850 @param Transaction The transaction to use for this request.
851 @param RequestType The type of message to send.
852 @param Body The body of the request.
853 @param LenPtr The returned length of the reply.
854 @param Result The returned body of the reply.
855
856 @return 0 on success. Otherwise an errno indicating
857 the cause of failure.
858 **/
859 STATIC
860 XENSTORE_STATUS
861 XenStoreSingle (
862 IN CONST XENSTORE_TRANSACTION *Transaction,
863 IN enum xsd_sockmsg_type RequestType,
864 IN CONST CHAR8 *Body,
865 OUT UINT32 *LenPtr OPTIONAL,
866 OUT VOID **Result OPTIONAL
867 )
868 {
869 WRITE_REQUEST WriteRequest;
870
871 WriteRequest.Data = (VOID *) Body;
872 WriteRequest.Len = (UINT32)AsciiStrSize (Body);
873
874 return XenStoreTalkv (Transaction, RequestType, &WriteRequest, 1,
875 LenPtr, Result);
876 }
877
878 //
879 // XenStore Watch Support
880 //
881
882 /**
883 Transmit a watch request to the XenStore service.
884
885 @param Path The path in the XenStore to watch.
886 @param Tocken A unique identifier for this watch.
887
888 @return XENSTORE_STATUS_SUCCESS on success. Otherwise an errno indicating the
889 cause of failure.
890 **/
891 STATIC
892 XENSTORE_STATUS
893 XenStoreWatch (
894 CONST CHAR8 *Path,
895 CONST CHAR8 *Token
896 )
897 {
898 WRITE_REQUEST WriteRequest[2];
899
900 WriteRequest[0].Data = (VOID *) Path;
901 WriteRequest[0].Len = (UINT32)AsciiStrSize (Path);
902 WriteRequest[1].Data = (VOID *) Token;
903 WriteRequest[1].Len = (UINT32)AsciiStrSize (Token);
904
905 return XenStoreTalkv (XST_NIL, XS_WATCH, WriteRequest, 2, NULL, NULL);
906 }
907
908 /**
909 Transmit an uwatch request to the XenStore service.
910
911 @param Path The path in the XenStore to watch.
912 @param Tocken A unique identifier for this watch.
913
914 @return XENSTORE_STATUS_SUCCESS on success. Otherwise an errno indicating
915 the cause of failure.
916 **/
917 STATIC
918 XENSTORE_STATUS
919 XenStoreUnwatch (
920 CONST CHAR8 *Path,
921 CONST CHAR8 *Token
922 )
923 {
924 WRITE_REQUEST WriteRequest[2];
925
926 WriteRequest[0].Data = (VOID *) Path;
927 WriteRequest[0].Len = (UINT32)AsciiStrSize (Path);
928 WriteRequest[1].Data = (VOID *) Token;
929 WriteRequest[1].Len = (UINT32)AsciiStrSize (Token);
930
931 return XenStoreTalkv (XST_NIL, XS_UNWATCH, WriteRequest, 2, NULL, NULL);
932 }
933
934 STATIC
935 XENSTORE_STATUS
936 XenStoreWaitWatch (
937 VOID *Token
938 )
939 {
940 XENSTORE_MESSAGE *Message;
941 LIST_ENTRY *Entry = NULL;
942 LIST_ENTRY *Last = NULL;
943 XENSTORE_STATUS Status;
944
945 while (TRUE) {
946 EfiAcquireLock (&xs.WatchEventsLock);
947 if (IsListEmpty (&xs.WatchEvents) ||
948 Last == GetFirstNode (&xs.WatchEvents)) {
949 EfiReleaseLock (&xs.WatchEventsLock);
950 Status = XenStoreProcessMessage ();
951 if (Status != XENSTORE_STATUS_SUCCESS && Status != XENSTORE_STATUS_EAGAIN) {
952 return Status;
953 }
954 continue;
955 }
956
957 for (Entry = GetFirstNode (&xs.WatchEvents);
958 Entry != Last && !IsNull (&xs.WatchEvents, Entry);
959 Entry = GetNextNode (&xs.WatchEvents, Entry)) {
960 Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
961 if (Message->u.Watch.Handle == Token) {
962 RemoveEntryList (Entry);
963 EfiReleaseLock (&xs.WatchEventsLock);
964 FreePool((VOID*)Message->u.Watch.Vector);
965 FreePool(Message);
966 return XENSTORE_STATUS_SUCCESS;
967 }
968 }
969 Last = GetFirstNode (&xs.WatchEvents);
970 EfiReleaseLock (&xs.WatchEventsLock);
971 }
972 }
973
974 VOID
975 EFIAPI
976 NotifyEventChannelCheckForEvent (
977 IN EFI_EVENT Event,
978 IN VOID *Context
979 )
980 {
981 XENSTORE_PRIVATE *xsp;
982 xsp = (XENSTORE_PRIVATE *)Context;
983 if (TestAndClearBit (xsp->EventChannel, xsp->Dev->SharedInfo->evtchn_pending)) {
984 gBS->SignalEvent (Event);
985 }
986 }
987
988 /**
989 Setup communication channels with the XenStore service.
990
991 @retval EFI_SUCCESS if everything went well.
992 **/
993 STATIC
994 EFI_STATUS
995 XenStoreInitComms (
996 XENSTORE_PRIVATE *xsp
997 )
998 {
999 EFI_STATUS Status;
1000 EFI_EVENT TimerEvent;
1001 struct xenstore_domain_interface *XenStore = xsp->XenStore;
1002
1003 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
1004 Status = gBS->SetTimer (TimerEvent, TimerRelative,
1005 EFI_TIMER_PERIOD_SECONDS (5));
1006 while (XenStore->rsp_prod != XenStore->rsp_cons) {
1007 Status = gBS->CheckEvent (TimerEvent);
1008 if (!EFI_ERROR (Status)) {
1009 DEBUG ((EFI_D_WARN, "XENSTORE response ring is not quiescent "
1010 "(%08x:%08x): fixing up\n",
1011 XenStore->rsp_cons, XenStore->rsp_prod));
1012 XenStore->rsp_cons = XenStore->rsp_prod;
1013 }
1014 }
1015 gBS->CloseEvent (TimerEvent);
1016
1017 Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_NOTIFY,
1018 NotifyEventChannelCheckForEvent, xsp,
1019 &xsp->EventChannelEvent);
1020 ASSERT_EFI_ERROR (Status);
1021
1022 return Status;
1023 }
1024
1025 /**
1026 Initialize XenStore.
1027
1028 @param Dev A XENBUS_DEVICE instance.
1029
1030 @retval EFI_SUCCESS if everything went well.
1031 **/
1032 EFI_STATUS
1033 XenStoreInit (
1034 XENBUS_DEVICE *Dev
1035 )
1036 {
1037 EFI_STATUS Status;
1038 /**
1039 * The HVM guest pseudo-physical frame number. This is Xen's mapping
1040 * of the true machine frame number into our "physical address space".
1041 */
1042 UINTN XenStoreGpfn;
1043
1044 xs.Dev = Dev;
1045
1046 xs.EventChannel = (evtchn_port_t)XenHypercallHvmGetParam (HVM_PARAM_STORE_EVTCHN);
1047 XenStoreGpfn = (UINTN)XenHypercallHvmGetParam (HVM_PARAM_STORE_PFN);
1048 xs.XenStore = (VOID *) (XenStoreGpfn << EFI_PAGE_SHIFT);
1049 DEBUG ((EFI_D_INFO, "XenBusInit: XenBus rings @%p, event channel %x\n",
1050 xs.XenStore, xs.EventChannel));
1051
1052 InitializeListHead (&xs.ReplyList);
1053 InitializeListHead (&xs.WatchEvents);
1054 InitializeListHead (&xs.RegisteredWatches);
1055
1056 EfiInitializeLock (&xs.ReplyLock, TPL_NOTIFY);
1057 EfiInitializeLock (&xs.RegisteredWatchesLock, TPL_NOTIFY);
1058 EfiInitializeLock (&xs.WatchEventsLock, TPL_NOTIFY);
1059
1060 /* Initialize the shared memory rings to talk to xenstored */
1061 Status = XenStoreInitComms (&xs);
1062
1063 return Status;
1064 }
1065
1066 VOID
1067 XenStoreDeinit (
1068 IN XENBUS_DEVICE *Dev
1069 )
1070 {
1071 //
1072 // Emptying the list RegisteredWatches, but this list should already be
1073 // empty. Every driver that is using Watches should unregister them when
1074 // it is stopped.
1075 //
1076 if (!IsListEmpty (&xs.RegisteredWatches)) {
1077 XENSTORE_WATCH *Watch;
1078 LIST_ENTRY *Entry;
1079 DEBUG ((EFI_D_WARN, "XenStore: RegisteredWatches is not empty, cleaning up..."));
1080 Entry = GetFirstNode (&xs.RegisteredWatches);
1081 while (!IsNull (&xs.RegisteredWatches, Entry)) {
1082 Watch = XENSTORE_WATCH_FROM_LINK (Entry);
1083 Entry = GetNextNode (&xs.RegisteredWatches, Entry);
1084
1085 XenStoreUnregisterWatch (Watch);
1086 }
1087 }
1088
1089 //
1090 // Emptying the list WatchEvents, but this list should already be empty after
1091 // having cleanup the list RegisteredWatches.
1092 //
1093 if (!IsListEmpty (&xs.WatchEvents)) {
1094 LIST_ENTRY *Entry;
1095 DEBUG ((EFI_D_WARN, "XenStore: WatchEvents is not empty, cleaning up..."));
1096 Entry = GetFirstNode (&xs.WatchEvents);
1097 while (!IsNull (&xs.WatchEvents, Entry)) {
1098 XENSTORE_MESSAGE *Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
1099 Entry = GetNextNode (&xs.WatchEvents, Entry);
1100 RemoveEntryList (&Message->Link);
1101 FreePool ((VOID*)Message->u.Watch.Vector);
1102 FreePool (Message);
1103 }
1104 }
1105
1106 if (!IsListEmpty (&xs.ReplyList)) {
1107 XENSTORE_MESSAGE *Message;
1108 LIST_ENTRY *Entry;
1109 Entry = GetFirstNode (&xs.ReplyList);
1110 while (!IsNull (&xs.ReplyList, Entry)) {
1111 Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
1112 Entry = GetNextNode (&xs.ReplyList, Entry);
1113 RemoveEntryList (&Message->Link);
1114 FreePool (Message->u.Reply.Body);
1115 FreePool (Message);
1116 }
1117 }
1118
1119 gBS->CloseEvent (xs.EventChannelEvent);
1120
1121 if (xs.XenStore->server_features & XENSTORE_SERVER_FEATURE_RECONNECTION) {
1122 xs.XenStore->connection = XENSTORE_RECONNECT;
1123 XenEventChannelNotify (xs.Dev, xs.EventChannel);
1124 while (*(volatile UINT32*)&xs.XenStore->connection == XENSTORE_RECONNECT) {
1125 XenStoreWaitForEvent (xs.EventChannelEvent, EFI_TIMER_PERIOD_MILLISECONDS (100));
1126 }
1127 } else {
1128 /* If the backend reads the state while we're erasing it then the
1129 * ring state will become corrupted, preventing guest frontends from
1130 * connecting. This is rare. To help diagnose the failure, we fill
1131 * the ring with XS_INVALID packets. */
1132 SetMem (xs.XenStore->req, XENSTORE_RING_SIZE, 0xff);
1133 SetMem (xs.XenStore->rsp, XENSTORE_RING_SIZE, 0xff);
1134 xs.XenStore->req_cons = xs.XenStore->req_prod = 0;
1135 xs.XenStore->rsp_cons = xs.XenStore->rsp_prod = 0;
1136 }
1137 xs.XenStore = NULL;
1138 }
1139
1140 //
1141 // Public API
1142 // API comments for these methods can be found in XenStore.h
1143 //
1144
1145 XENSTORE_STATUS
1146 XenStoreListDirectory (
1147 IN CONST XENSTORE_TRANSACTION *Transaction,
1148 IN CONST CHAR8 *DirectoryPath,
1149 IN CONST CHAR8 *Node,
1150 OUT UINT32 *DirectoryCountPtr,
1151 OUT CONST CHAR8 ***DirectoryListPtr
1152 )
1153 {
1154 CHAR8 *Path;
1155 CHAR8 *TempStr;
1156 UINT32 Len = 0;
1157 XENSTORE_STATUS Status;
1158
1159 Path = XenStoreJoin (DirectoryPath, Node);
1160 Status = XenStoreSingle (Transaction, XS_DIRECTORY, Path, &Len,
1161 (VOID **) &TempStr);
1162 FreePool (Path);
1163 if (Status != XENSTORE_STATUS_SUCCESS) {
1164 return Status;
1165 }
1166
1167 *DirectoryListPtr = Split (TempStr, Len, DirectoryCountPtr);
1168
1169 return XENSTORE_STATUS_SUCCESS;
1170 }
1171
1172 BOOLEAN
1173 XenStorePathExists (
1174 IN CONST XENSTORE_TRANSACTION *Transaction,
1175 IN CONST CHAR8 *Directory,
1176 IN CONST CHAR8 *Node
1177 )
1178 {
1179 CONST CHAR8 **TempStr;
1180 XENSTORE_STATUS Status;
1181 UINT32 TempNum;
1182
1183 Status = XenStoreListDirectory (Transaction, Directory, Node,
1184 &TempNum, &TempStr);
1185 if (Status != XENSTORE_STATUS_SUCCESS) {
1186 return FALSE;
1187 }
1188 FreePool ((VOID*)TempStr);
1189 return TRUE;
1190 }
1191
1192 XENSTORE_STATUS
1193 XenStoreRead (
1194 IN CONST XENSTORE_TRANSACTION *Transaction,
1195 IN CONST CHAR8 *DirectoryPath,
1196 IN CONST CHAR8 *Node,
1197 OUT UINT32 *LenPtr OPTIONAL,
1198 OUT VOID **Result
1199 )
1200 {
1201 CHAR8 *Path;
1202 VOID *Value;
1203 XENSTORE_STATUS Status;
1204
1205 Path = XenStoreJoin (DirectoryPath, Node);
1206 Status = XenStoreSingle (Transaction, XS_READ, Path, LenPtr, &Value);
1207 FreePool (Path);
1208 if (Status != XENSTORE_STATUS_SUCCESS) {
1209 return Status;
1210 }
1211
1212 *Result = Value;
1213 return XENSTORE_STATUS_SUCCESS;
1214 }
1215
1216 XENSTORE_STATUS
1217 XenStoreWrite (
1218 IN CONST XENSTORE_TRANSACTION *Transaction,
1219 IN CONST CHAR8 *DirectoryPath,
1220 IN CONST CHAR8 *Node,
1221 IN CONST CHAR8 *Str
1222 )
1223 {
1224 CHAR8 *Path;
1225 WRITE_REQUEST WriteRequest[2];
1226 XENSTORE_STATUS Status;
1227
1228 Path = XenStoreJoin (DirectoryPath, Node);
1229
1230 WriteRequest[0].Data = (VOID *) Path;
1231 WriteRequest[0].Len = (UINT32)AsciiStrSize (Path);
1232 WriteRequest[1].Data = (VOID *) Str;
1233 WriteRequest[1].Len = (UINT32)AsciiStrLen (Str);
1234
1235 Status = XenStoreTalkv (Transaction, XS_WRITE, WriteRequest, 2, NULL, NULL);
1236 FreePool (Path);
1237
1238 return Status;
1239 }
1240
1241 XENSTORE_STATUS
1242 XenStoreRemove (
1243 IN CONST XENSTORE_TRANSACTION *Transaction,
1244 IN CONST CHAR8 *DirectoryPath,
1245 IN CONST CHAR8 *Node
1246 )
1247 {
1248 CHAR8 *Path;
1249 XENSTORE_STATUS Status;
1250
1251 Path = XenStoreJoin (DirectoryPath, Node);
1252 Status = XenStoreSingle (Transaction, XS_RM, Path, NULL, NULL);
1253 FreePool (Path);
1254
1255 return Status;
1256 }
1257
1258 XENSTORE_STATUS
1259 XenStoreTransactionStart (
1260 OUT XENSTORE_TRANSACTION *Transaction
1261 )
1262 {
1263 CHAR8 *IdStr;
1264 XENSTORE_STATUS Status;
1265
1266 Status = XenStoreSingle (XST_NIL, XS_TRANSACTION_START, "", NULL,
1267 (VOID **) &IdStr);
1268 if (Status == XENSTORE_STATUS_SUCCESS) {
1269 Transaction->Id = (UINT32)AsciiStrDecimalToUintn (IdStr);
1270 FreePool (IdStr);
1271 }
1272
1273 return Status;
1274 }
1275
1276 XENSTORE_STATUS
1277 XenStoreTransactionEnd (
1278 IN CONST XENSTORE_TRANSACTION *Transaction,
1279 IN BOOLEAN Abort
1280 )
1281 {
1282 CHAR8 AbortStr[2];
1283
1284 AbortStr[0] = Abort ? 'F' : 'T';
1285 AbortStr[1] = '\0';
1286
1287 return XenStoreSingle (Transaction, XS_TRANSACTION_END, AbortStr, NULL, NULL);
1288 }
1289
1290 XENSTORE_STATUS
1291 EFIAPI
1292 XenStoreVSPrint (
1293 IN CONST XENSTORE_TRANSACTION *Transaction,
1294 IN CONST CHAR8 *DirectoryPath,
1295 IN CONST CHAR8 *Node,
1296 IN CONST CHAR8 *FormatString,
1297 IN VA_LIST Marker
1298 )
1299 {
1300 CHAR8 *Buf;
1301 XENSTORE_STATUS Status;
1302 UINTN BufSize;
1303 VA_LIST Marker2;
1304
1305 VA_COPY (Marker2, Marker);
1306 BufSize = SPrintLengthAsciiFormat (FormatString, Marker2) + 1;
1307 VA_END (Marker2);
1308 Buf = AllocateZeroPool (BufSize);
1309 AsciiVSPrint (Buf, BufSize, FormatString, Marker);
1310 Status = XenStoreWrite (Transaction, DirectoryPath, Node, Buf);
1311 FreePool (Buf);
1312
1313 return Status;
1314 }
1315
1316 XENSTORE_STATUS
1317 EFIAPI
1318 XenStoreSPrint (
1319 IN CONST XENSTORE_TRANSACTION *Transaction,
1320 IN CONST CHAR8 *DirectoryPath,
1321 IN CONST CHAR8 *Node,
1322 IN CONST CHAR8 *FormatString,
1323 ...
1324 )
1325 {
1326 VA_LIST Marker;
1327 XENSTORE_STATUS Status;
1328
1329 VA_START (Marker, FormatString);
1330 Status = XenStoreVSPrint (Transaction, DirectoryPath, Node, FormatString, Marker);
1331 VA_END (Marker);
1332
1333 return Status;
1334 }
1335
1336 XENSTORE_STATUS
1337 XenStoreRegisterWatch (
1338 IN CONST CHAR8 *DirectoryPath,
1339 IN CONST CHAR8 *Node,
1340 OUT XENSTORE_WATCH **WatchPtr
1341 )
1342 {
1343 /* Pointer in ascii is the token. */
1344 CHAR8 Token[sizeof (XENSTORE_WATCH) * 2 + 1];
1345 XENSTORE_STATUS Status;
1346 XENSTORE_WATCH *Watch;
1347
1348 Watch = AllocateZeroPool (sizeof (XENSTORE_WATCH));
1349 Watch->Signature = XENSTORE_WATCH_SIGNATURE;
1350 Watch->Node = XenStoreJoin (DirectoryPath, Node);
1351
1352 EfiAcquireLock (&xs.RegisteredWatchesLock);
1353 InsertTailList (&xs.RegisteredWatches, &Watch->Link);
1354 EfiReleaseLock (&xs.RegisteredWatchesLock);
1355
1356 AsciiSPrint (Token, sizeof (Token), "%p", (VOID*) Watch);
1357 Status = XenStoreWatch (Watch->Node, Token);
1358
1359 /* Ignore errors due to multiple registration. */
1360 if (Status == XENSTORE_STATUS_EEXIST) {
1361 Status = XENSTORE_STATUS_SUCCESS;
1362 }
1363
1364 if (Status == XENSTORE_STATUS_SUCCESS) {
1365 *WatchPtr = Watch;
1366 } else {
1367 EfiAcquireLock (&xs.RegisteredWatchesLock);
1368 RemoveEntryList (&Watch->Link);
1369 EfiReleaseLock (&xs.RegisteredWatchesLock);
1370 FreePool (Watch->Node);
1371 FreePool (Watch);
1372 }
1373
1374 return Status;
1375 }
1376
1377 VOID
1378 XenStoreUnregisterWatch (
1379 IN XENSTORE_WATCH *Watch
1380 )
1381 {
1382 CHAR8 Token[sizeof (Watch) * 2 + 1];
1383 LIST_ENTRY *Entry;
1384
1385 ASSERT (Watch->Signature == XENSTORE_WATCH_SIGNATURE);
1386
1387 AsciiSPrint (Token, sizeof (Token), "%p", (VOID *) Watch);
1388 if (XenStoreFindWatch (Token) == NULL) {
1389 return;
1390 }
1391
1392 EfiAcquireLock (&xs.RegisteredWatchesLock);
1393 RemoveEntryList (&Watch->Link);
1394 EfiReleaseLock (&xs.RegisteredWatchesLock);
1395
1396 XenStoreUnwatch (Watch->Node, Token);
1397
1398 /* Cancel pending watch events. */
1399 EfiAcquireLock (&xs.WatchEventsLock);
1400 Entry = GetFirstNode (&xs.WatchEvents);
1401 while (!IsNull (&xs.WatchEvents, Entry)) {
1402 XENSTORE_MESSAGE *Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
1403 Entry = GetNextNode (&xs.WatchEvents, Entry);
1404 if (Message->u.Watch.Handle == Watch) {
1405 RemoveEntryList (&Message->Link);
1406 FreePool ((VOID*)Message->u.Watch.Vector);
1407 FreePool (Message);
1408 }
1409 }
1410 EfiReleaseLock (&xs.WatchEventsLock);
1411
1412 FreePool (Watch->Node);
1413 FreePool (Watch);
1414 }
1415
1416
1417 //
1418 // XENBUS protocol
1419 //
1420
1421 XENSTORE_STATUS
1422 EFIAPI
1423 XenBusWaitForWatch (
1424 IN XENBUS_PROTOCOL *This,
1425 IN VOID *Token
1426 )
1427 {
1428 return XenStoreWaitWatch (Token);
1429 }
1430
1431 XENSTORE_STATUS
1432 EFIAPI
1433 XenBusXenStoreRead (
1434 IN XENBUS_PROTOCOL *This,
1435 IN CONST XENSTORE_TRANSACTION *Transaction,
1436 IN CONST CHAR8 *Node,
1437 OUT VOID **Value
1438 )
1439 {
1440 return XenStoreRead (Transaction, This->Node, Node, NULL, Value);
1441 }
1442
1443 XENSTORE_STATUS
1444 EFIAPI
1445 XenBusXenStoreBackendRead (
1446 IN XENBUS_PROTOCOL *This,
1447 IN CONST XENSTORE_TRANSACTION *Transaction,
1448 IN CONST CHAR8 *Node,
1449 OUT VOID **Value
1450 )
1451 {
1452 return XenStoreRead (Transaction, This->Backend, Node, NULL, Value);
1453 }
1454
1455 XENSTORE_STATUS
1456 EFIAPI
1457 XenBusXenStoreRemove (
1458 IN XENBUS_PROTOCOL *This,
1459 IN CONST XENSTORE_TRANSACTION *Transaction,
1460 IN const char *Node
1461 )
1462 {
1463 return XenStoreRemove (Transaction, This->Node, Node);
1464 }
1465
1466 XENSTORE_STATUS
1467 EFIAPI
1468 XenBusXenStoreTransactionStart (
1469 IN XENBUS_PROTOCOL *This,
1470 OUT XENSTORE_TRANSACTION *Transaction
1471 )
1472 {
1473 return XenStoreTransactionStart (Transaction);
1474 }
1475
1476 XENSTORE_STATUS
1477 EFIAPI
1478 XenBusXenStoreTransactionEnd (
1479 IN XENBUS_PROTOCOL *This,
1480 IN CONST XENSTORE_TRANSACTION *Transaction,
1481 IN BOOLEAN Abort
1482 )
1483 {
1484 return XenStoreTransactionEnd (Transaction, Abort);
1485 }
1486
1487 XENSTORE_STATUS
1488 EFIAPI
1489 XenBusXenStoreSPrint (
1490 IN XENBUS_PROTOCOL *This,
1491 IN CONST XENSTORE_TRANSACTION *Transaction,
1492 IN CONST CHAR8 *DirectoryPath,
1493 IN CONST CHAR8 *Node,
1494 IN CONST CHAR8 *FormatString,
1495 ...
1496 )
1497 {
1498 VA_LIST Marker;
1499 XENSTORE_STATUS Status;
1500
1501 VA_START (Marker, FormatString);
1502 Status = XenStoreVSPrint (Transaction, DirectoryPath, Node, FormatString, Marker);
1503 VA_END (Marker);
1504
1505 return Status;
1506 }
1507
1508 XENSTORE_STATUS
1509 EFIAPI
1510 XenBusRegisterWatch (
1511 IN XENBUS_PROTOCOL *This,
1512 IN CONST CHAR8 *Node,
1513 OUT VOID **Token
1514 )
1515 {
1516 return XenStoreRegisterWatch (This->Node, Node, (XENSTORE_WATCH **) Token);
1517 }
1518
1519 XENSTORE_STATUS
1520 EFIAPI
1521 XenBusRegisterWatchBackend (
1522 IN XENBUS_PROTOCOL *This,
1523 IN CONST CHAR8 *Node,
1524 OUT VOID **Token
1525 )
1526 {
1527 return XenStoreRegisterWatch (This->Backend, Node, (XENSTORE_WATCH **) Token);
1528 }
1529
1530 VOID
1531 EFIAPI
1532 XenBusUnregisterWatch (
1533 IN XENBUS_PROTOCOL *This,
1534 IN VOID *Token
1535 )
1536 {
1537 XenStoreUnregisterWatch ((XENSTORE_WATCH *) Token);
1538 }