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