]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/XenBusDxe/XenStore.c
9eeb6f54fb50293dd2063903c9e9b606193db0b4
[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 #ifndef ARRAY_SIZE
717 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
718 #endif
719
720 STATIC
721 XENSTORE_STATUS
722 XenStoreGetError (
723 CONST CHAR8 *ErrorStr
724 )
725 {
726 UINT32 Index;
727
728 for (Index = 0; Index < ARRAY_SIZE(gXenStoreErrors); Index++) {
729 if (!AsciiStrCmp (ErrorStr, gXenStoreErrors[Index].ErrorStr)) {
730 return gXenStoreErrors[Index].Status;
731 }
732 }
733 DEBUG ((EFI_D_WARN, "XenStore gave unknown error %a\n", ErrorStr));
734 return XENSTORE_STATUS_EINVAL;
735 }
736
737 /**
738 Block waiting for a reply to a message request.
739
740 @param TypePtr The returned type of the reply.
741 @param LenPtr The returned body length of the reply.
742 @param Result The returned body of the reply.
743 **/
744 STATIC
745 XENSTORE_STATUS
746 XenStoreReadReply (
747 OUT enum xsd_sockmsg_type *TypePtr,
748 OUT UINT32 *LenPtr OPTIONAL,
749 OUT VOID **Result
750 )
751 {
752 XENSTORE_MESSAGE *Message;
753 LIST_ENTRY *Entry;
754 CHAR8 *Body;
755
756 while (IsListEmpty (&xs.ReplyList)) {
757 XENSTORE_STATUS Status;
758 Status = XenStoreProcessMessage ();
759 if (Status != XENSTORE_STATUS_SUCCESS && Status != XENSTORE_STATUS_EAGAIN) {
760 DEBUG ((EFI_D_ERROR, "XenStore, error while reading the ring (%d).",
761 Status));
762 return Status;
763 }
764 }
765 EfiAcquireLock (&xs.ReplyLock);
766 Entry = GetFirstNode (&xs.ReplyList);
767 Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
768 RemoveEntryList (Entry);
769 EfiReleaseLock (&xs.ReplyLock);
770
771 *TypePtr = Message->Header.type;
772 if (LenPtr != NULL) {
773 *LenPtr = Message->Header.len;
774 }
775 Body = Message->u.Reply.Body;
776
777 FreePool (Message);
778 *Result = Body;
779 return XENSTORE_STATUS_SUCCESS;
780 }
781
782 /**
783 Send a message with an optionally muti-part body to the XenStore service.
784
785 @param Transaction The transaction to use for this request.
786 @param RequestType The type of message to send.
787 @param WriteRequest Pointers to the body sections of the request.
788 @param NumRequests The number of body sections in the request.
789 @param LenPtr The returned length of the reply.
790 @param ResultPtr The returned body of the reply.
791
792 @return XENSTORE_STATUS_SUCCESS on success. Otherwise an errno indicating
793 the cause of failure.
794 **/
795 STATIC
796 XENSTORE_STATUS
797 XenStoreTalkv (
798 IN CONST XENSTORE_TRANSACTION *Transaction,
799 IN enum xsd_sockmsg_type RequestType,
800 IN CONST WRITE_REQUEST *WriteRequest,
801 IN UINT32 NumRequests,
802 OUT UINT32 *LenPtr OPTIONAL,
803 OUT VOID **ResultPtr OPTIONAL
804 )
805 {
806 struct xsd_sockmsg Message;
807 void *Return = NULL;
808 UINT32 Index;
809 XENSTORE_STATUS Status;
810
811 if (Transaction == XST_NIL) {
812 Message.tx_id = 0;
813 } else {
814 Message.tx_id = Transaction->Id;
815 }
816 Message.req_id = 0;
817 Message.type = RequestType;
818 Message.len = 0;
819 for (Index = 0; Index < NumRequests; Index++) {
820 Message.len += WriteRequest[Index].Len;
821 }
822
823 Status = XenStoreWriteStore (&Message, sizeof (Message));
824 if (Status != XENSTORE_STATUS_SUCCESS) {
825 DEBUG ((EFI_D_ERROR, "XenStoreTalkv failed %d\n", Status));
826 goto Error;
827 }
828
829 for (Index = 0; Index < NumRequests; Index++) {
830 Status = XenStoreWriteStore (WriteRequest[Index].Data, WriteRequest[Index].Len);
831 if (Status != XENSTORE_STATUS_SUCCESS) {
832 DEBUG ((EFI_D_ERROR, "XenStoreTalkv failed %d\n", Status));
833 goto Error;
834 }
835 }
836
837 Status = XenStoreReadReply ((enum xsd_sockmsg_type *)&Message.type, LenPtr, &Return);
838
839 Error:
840 if (Status != XENSTORE_STATUS_SUCCESS) {
841 return Status;
842 }
843
844 if (Message.type == XS_ERROR) {
845 Status = XenStoreGetError (Return);
846 FreePool (Return);
847 return Status;
848 }
849
850 /* Reply is either error or an echo of our request message type. */
851 ASSERT ((enum xsd_sockmsg_type)Message.type == RequestType);
852
853 if (ResultPtr) {
854 *ResultPtr = Return;
855 } else {
856 FreePool (Return);
857 }
858
859 return XENSTORE_STATUS_SUCCESS;
860 }
861
862 /**
863 Wrapper for XenStoreTalkv allowing easy transmission of a message with
864 a single, contiguous, message body.
865
866 The returned result is provided in malloced storage and thus must be free'd
867 by the caller.
868
869 @param Transaction The transaction to use for this request.
870 @param RequestType The type of message to send.
871 @param Body The body of the request.
872 @param LenPtr The returned length of the reply.
873 @param Result The returned body of the reply.
874
875 @return 0 on success. Otherwise an errno indicating
876 the cause of failure.
877 **/
878 STATIC
879 XENSTORE_STATUS
880 XenStoreSingle (
881 IN CONST XENSTORE_TRANSACTION *Transaction,
882 IN enum xsd_sockmsg_type RequestType,
883 IN CONST CHAR8 *Body,
884 OUT UINT32 *LenPtr OPTIONAL,
885 OUT VOID **Result OPTIONAL
886 )
887 {
888 WRITE_REQUEST WriteRequest;
889
890 WriteRequest.Data = (VOID *) Body;
891 WriteRequest.Len = (UINT32)AsciiStrSize (Body);
892
893 return XenStoreTalkv (Transaction, RequestType, &WriteRequest, 1,
894 LenPtr, Result);
895 }
896
897 //
898 // XenStore Watch Support
899 //
900
901 /**
902 Transmit a watch request to the XenStore service.
903
904 @param Path The path in the XenStore to watch.
905 @param Tocken A unique identifier for this watch.
906
907 @return XENSTORE_STATUS_SUCCESS on success. Otherwise an errno indicating the
908 cause of failure.
909 **/
910 STATIC
911 XENSTORE_STATUS
912 XenStoreWatch (
913 CONST CHAR8 *Path,
914 CONST CHAR8 *Token
915 )
916 {
917 WRITE_REQUEST WriteRequest[2];
918
919 WriteRequest[0].Data = (VOID *) Path;
920 WriteRequest[0].Len = (UINT32)AsciiStrSize (Path);
921 WriteRequest[1].Data = (VOID *) Token;
922 WriteRequest[1].Len = (UINT32)AsciiStrSize (Token);
923
924 return XenStoreTalkv (XST_NIL, XS_WATCH, WriteRequest, 2, NULL, NULL);
925 }
926
927 /**
928 Transmit an uwatch request to the XenStore service.
929
930 @param Path The path in the XenStore to watch.
931 @param Tocken A unique identifier for this watch.
932
933 @return XENSTORE_STATUS_SUCCESS on success. Otherwise an errno indicating
934 the cause of failure.
935 **/
936 STATIC
937 XENSTORE_STATUS
938 XenStoreUnwatch (
939 CONST CHAR8 *Path,
940 CONST CHAR8 *Token
941 )
942 {
943 WRITE_REQUEST WriteRequest[2];
944
945 WriteRequest[0].Data = (VOID *) Path;
946 WriteRequest[0].Len = (UINT32)AsciiStrSize (Path);
947 WriteRequest[1].Data = (VOID *) Token;
948 WriteRequest[1].Len = (UINT32)AsciiStrSize (Token);
949
950 return XenStoreTalkv (XST_NIL, XS_UNWATCH, WriteRequest, 2, NULL, NULL);
951 }
952
953 STATIC
954 XENSTORE_STATUS
955 XenStoreWaitWatch (
956 VOID *Token
957 )
958 {
959 XENSTORE_MESSAGE *Message;
960 LIST_ENTRY *Entry = NULL;
961 LIST_ENTRY *Last = NULL;
962 XENSTORE_STATUS Status;
963
964 while (TRUE) {
965 EfiAcquireLock (&xs.WatchEventsLock);
966 if (IsListEmpty (&xs.WatchEvents) ||
967 Last == GetFirstNode (&xs.WatchEvents)) {
968 EfiReleaseLock (&xs.WatchEventsLock);
969 Status = XenStoreProcessMessage ();
970 if (Status != XENSTORE_STATUS_SUCCESS && Status != XENSTORE_STATUS_EAGAIN) {
971 return Status;
972 }
973 continue;
974 }
975
976 for (Entry = GetFirstNode (&xs.WatchEvents);
977 Entry != Last && !IsNull (&xs.WatchEvents, Entry);
978 Entry = GetNextNode (&xs.WatchEvents, Entry)) {
979 Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
980 if (Message->u.Watch.Handle == Token) {
981 RemoveEntryList (Entry);
982 EfiReleaseLock (&xs.WatchEventsLock);
983 FreePool((VOID*)Message->u.Watch.Vector);
984 FreePool(Message);
985 return XENSTORE_STATUS_SUCCESS;
986 }
987 }
988 Last = GetFirstNode (&xs.WatchEvents);
989 EfiReleaseLock (&xs.WatchEventsLock);
990 }
991 }
992
993 VOID
994 EFIAPI
995 NotifyEventChannelCheckForEvent (
996 IN EFI_EVENT Event,
997 IN VOID *Context
998 )
999 {
1000 XENSTORE_PRIVATE *xsp;
1001 xsp = (XENSTORE_PRIVATE *)Context;
1002 if (TestAndClearBit (xsp->EventChannel, xsp->Dev->SharedInfo->evtchn_pending)) {
1003 gBS->SignalEvent (Event);
1004 }
1005 }
1006
1007 /**
1008 Setup communication channels with the XenStore service.
1009
1010 @retval EFI_SUCCESS if everything went well.
1011 **/
1012 STATIC
1013 EFI_STATUS
1014 XenStoreInitComms (
1015 XENSTORE_PRIVATE *xsp
1016 )
1017 {
1018 EFI_STATUS Status;
1019 EFI_EVENT TimerEvent;
1020 struct xenstore_domain_interface *XenStore = xsp->XenStore;
1021
1022 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
1023 Status = gBS->SetTimer (TimerEvent, TimerRelative,
1024 EFI_TIMER_PERIOD_SECONDS (5));
1025 while (XenStore->rsp_prod != XenStore->rsp_cons) {
1026 Status = gBS->CheckEvent (TimerEvent);
1027 if (!EFI_ERROR (Status)) {
1028 DEBUG ((EFI_D_WARN, "XENSTORE response ring is not quiescent "
1029 "(%08x:%08x): fixing up\n",
1030 XenStore->rsp_cons, XenStore->rsp_prod));
1031 XenStore->rsp_cons = XenStore->rsp_prod;
1032 }
1033 }
1034 gBS->CloseEvent (TimerEvent);
1035
1036 Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_NOTIFY,
1037 NotifyEventChannelCheckForEvent, xsp,
1038 &xsp->EventChannelEvent);
1039 ASSERT_EFI_ERROR (Status);
1040
1041 return Status;
1042 }
1043
1044 /**
1045 Initialize XenStore.
1046
1047 @param Dev A XENBUS_DEVICE instance.
1048
1049 @retval EFI_SUCCESS if everything went well.
1050 **/
1051 EFI_STATUS
1052 XenStoreInit (
1053 XENBUS_DEVICE *Dev
1054 )
1055 {
1056 EFI_STATUS Status;
1057 /**
1058 * The HVM guest pseudo-physical frame number. This is Xen's mapping
1059 * of the true machine frame number into our "physical address space".
1060 */
1061 UINTN XenStoreGpfn;
1062
1063 xs.Dev = Dev;
1064
1065 xs.EventChannel = (evtchn_port_t)XenHypercallHvmGetParam (HVM_PARAM_STORE_EVTCHN);
1066 XenStoreGpfn = (UINTN)XenHypercallHvmGetParam (HVM_PARAM_STORE_PFN);
1067 xs.XenStore = (VOID *) (XenStoreGpfn << EFI_PAGE_SHIFT);
1068 DEBUG ((EFI_D_INFO, "XenBusInit: XenBus rings @%p, event channel %x\n",
1069 xs.XenStore, xs.EventChannel));
1070
1071 InitializeListHead (&xs.ReplyList);
1072 InitializeListHead (&xs.WatchEvents);
1073 InitializeListHead (&xs.RegisteredWatches);
1074
1075 EfiInitializeLock (&xs.ReplyLock, TPL_NOTIFY);
1076 EfiInitializeLock (&xs.RegisteredWatchesLock, TPL_NOTIFY);
1077 EfiInitializeLock (&xs.WatchEventsLock, TPL_NOTIFY);
1078
1079 /* Initialize the shared memory rings to talk to xenstored */
1080 Status = XenStoreInitComms (&xs);
1081 if (EFI_ERROR (Status)) {
1082 return Status;
1083 }
1084
1085 return Status;
1086 }
1087
1088 VOID
1089 XenStoreDeinit (
1090 IN XENBUS_DEVICE *Dev
1091 )
1092 {
1093 //
1094 // Emptying the list RegisteredWatches, but this list should already be
1095 // empty. Every driver that is using Watches should unregister them when
1096 // it is stopped.
1097 //
1098 if (!IsListEmpty (&xs.RegisteredWatches)) {
1099 XENSTORE_WATCH *Watch;
1100 LIST_ENTRY *Entry;
1101 DEBUG ((EFI_D_WARN, "XenStore: RegisteredWatches is not empty, cleaning up..."));
1102 Entry = GetFirstNode (&xs.RegisteredWatches);
1103 while (!IsNull (&xs.RegisteredWatches, Entry)) {
1104 Watch = XENSTORE_WATCH_FROM_LINK (Entry);
1105 Entry = GetNextNode (&xs.RegisteredWatches, Entry);
1106
1107 XenStoreUnregisterWatch (Watch);
1108 }
1109 }
1110
1111 //
1112 // Emptying the list WatchEvents, but this list should already be empty after
1113 // having cleanup the list RegisteredWatches.
1114 //
1115 if (!IsListEmpty (&xs.WatchEvents)) {
1116 LIST_ENTRY *Entry;
1117 DEBUG ((EFI_D_WARN, "XenStore: WatchEvents is not empty, cleaning up..."));
1118 Entry = GetFirstNode (&xs.WatchEvents);
1119 while (!IsNull (&xs.WatchEvents, Entry)) {
1120 XENSTORE_MESSAGE *Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
1121 Entry = GetNextNode (&xs.WatchEvents, Entry);
1122 RemoveEntryList (&Message->Link);
1123 FreePool ((VOID*)Message->u.Watch.Vector);
1124 FreePool (Message);
1125 }
1126 }
1127
1128 if (!IsListEmpty (&xs.ReplyList)) {
1129 XENSTORE_MESSAGE *Message;
1130 LIST_ENTRY *Entry;
1131 Entry = GetFirstNode (&xs.ReplyList);
1132 while (!IsNull (&xs.ReplyList, Entry)) {
1133 Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
1134 Entry = GetNextNode (&xs.ReplyList, Entry);
1135 RemoveEntryList (&Message->Link);
1136 FreePool (Message->u.Reply.Body);
1137 FreePool (Message);
1138 }
1139 }
1140
1141 gBS->CloseEvent (xs.EventChannelEvent);
1142
1143 if (xs.XenStore->server_features & XENSTORE_SERVER_FEATURE_RECONNECTION) {
1144 xs.XenStore->connection = XENSTORE_RECONNECT;
1145 XenEventChannelNotify (xs.Dev, xs.EventChannel);
1146 while (*(volatile UINT32*)&xs.XenStore->connection == XENSTORE_RECONNECT) {
1147 XenStoreWaitForEvent (xs.EventChannelEvent, EFI_TIMER_PERIOD_MILLISECONDS (100));
1148 }
1149 } else {
1150 /* If the backend reads the state while we're erasing it then the
1151 * ring state will become corrupted, preventing guest frontends from
1152 * connecting. This is rare. To help diagnose the failure, we fill
1153 * the ring with XS_INVALID packets. */
1154 SetMem (xs.XenStore->req, XENSTORE_RING_SIZE, 0xff);
1155 SetMem (xs.XenStore->rsp, XENSTORE_RING_SIZE, 0xff);
1156 xs.XenStore->req_cons = xs.XenStore->req_prod = 0;
1157 xs.XenStore->rsp_cons = xs.XenStore->rsp_prod = 0;
1158 }
1159 xs.XenStore = NULL;
1160 }
1161
1162 //
1163 // Public API
1164 // API comments for these methods can be found in XenStore.h
1165 //
1166
1167 XENSTORE_STATUS
1168 XenStoreListDirectory (
1169 IN CONST XENSTORE_TRANSACTION *Transaction,
1170 IN CONST CHAR8 *DirectoryPath,
1171 IN CONST CHAR8 *Node,
1172 OUT UINT32 *DirectoryCountPtr,
1173 OUT CONST CHAR8 ***DirectoryListPtr
1174 )
1175 {
1176 CHAR8 *Path;
1177 CHAR8 *TempStr;
1178 UINT32 Len = 0;
1179 XENSTORE_STATUS Status;
1180
1181 Path = XenStoreJoin (DirectoryPath, Node);
1182 Status = XenStoreSingle (Transaction, XS_DIRECTORY, Path, &Len,
1183 (VOID **) &TempStr);
1184 FreePool (Path);
1185 if (Status != XENSTORE_STATUS_SUCCESS) {
1186 return Status;
1187 }
1188
1189 *DirectoryListPtr = Split (TempStr, Len, DirectoryCountPtr);
1190
1191 return XENSTORE_STATUS_SUCCESS;
1192 }
1193
1194 BOOLEAN
1195 XenStorePathExists (
1196 IN CONST XENSTORE_TRANSACTION *Transaction,
1197 IN CONST CHAR8 *Directory,
1198 IN CONST CHAR8 *Node
1199 )
1200 {
1201 CONST CHAR8 **TempStr;
1202 XENSTORE_STATUS Status;
1203 UINT32 TempNum;
1204
1205 Status = XenStoreListDirectory (Transaction, Directory, Node,
1206 &TempNum, &TempStr);
1207 if (Status != XENSTORE_STATUS_SUCCESS) {
1208 return FALSE;
1209 }
1210 FreePool ((VOID*)TempStr);
1211 return TRUE;
1212 }
1213
1214 XENSTORE_STATUS
1215 XenStoreRead (
1216 IN CONST XENSTORE_TRANSACTION *Transaction,
1217 IN CONST CHAR8 *DirectoryPath,
1218 IN CONST CHAR8 *Node,
1219 OUT UINT32 *LenPtr OPTIONAL,
1220 OUT VOID **Result
1221 )
1222 {
1223 CHAR8 *Path;
1224 VOID *Value;
1225 XENSTORE_STATUS Status;
1226
1227 Path = XenStoreJoin (DirectoryPath, Node);
1228 Status = XenStoreSingle (Transaction, XS_READ, Path, LenPtr, &Value);
1229 FreePool (Path);
1230 if (Status != XENSTORE_STATUS_SUCCESS) {
1231 return Status;
1232 }
1233
1234 *Result = Value;
1235 return XENSTORE_STATUS_SUCCESS;
1236 }
1237
1238 XENSTORE_STATUS
1239 XenStoreWrite (
1240 IN CONST XENSTORE_TRANSACTION *Transaction,
1241 IN CONST CHAR8 *DirectoryPath,
1242 IN CONST CHAR8 *Node,
1243 IN CONST CHAR8 *Str
1244 )
1245 {
1246 CHAR8 *Path;
1247 WRITE_REQUEST WriteRequest[2];
1248 XENSTORE_STATUS Status;
1249
1250 Path = XenStoreJoin (DirectoryPath, Node);
1251
1252 WriteRequest[0].Data = (VOID *) Path;
1253 WriteRequest[0].Len = (UINT32)AsciiStrSize (Path);
1254 WriteRequest[1].Data = (VOID *) Str;
1255 WriteRequest[1].Len = (UINT32)AsciiStrLen (Str);
1256
1257 Status = XenStoreTalkv (Transaction, XS_WRITE, WriteRequest, 2, NULL, NULL);
1258 FreePool (Path);
1259
1260 return Status;
1261 }
1262
1263 XENSTORE_STATUS
1264 XenStoreRemove (
1265 IN CONST XENSTORE_TRANSACTION *Transaction,
1266 IN CONST CHAR8 *DirectoryPath,
1267 IN CONST CHAR8 *Node
1268 )
1269 {
1270 CHAR8 *Path;
1271 XENSTORE_STATUS Status;
1272
1273 Path = XenStoreJoin (DirectoryPath, Node);
1274 Status = XenStoreSingle (Transaction, XS_RM, Path, NULL, NULL);
1275 FreePool (Path);
1276
1277 return Status;
1278 }
1279
1280 XENSTORE_STATUS
1281 XenStoreTransactionStart (
1282 OUT XENSTORE_TRANSACTION *Transaction
1283 )
1284 {
1285 CHAR8 *IdStr;
1286 XENSTORE_STATUS Status;
1287
1288 Status = XenStoreSingle (XST_NIL, XS_TRANSACTION_START, "", NULL,
1289 (VOID **) &IdStr);
1290 if (Status == XENSTORE_STATUS_SUCCESS) {
1291 Transaction->Id = (UINT32)AsciiStrDecimalToUintn (IdStr);
1292 FreePool (IdStr);
1293 }
1294
1295 return Status;
1296 }
1297
1298 XENSTORE_STATUS
1299 XenStoreTransactionEnd (
1300 IN CONST XENSTORE_TRANSACTION *Transaction,
1301 IN BOOLEAN Abort
1302 )
1303 {
1304 CHAR8 AbortStr[2];
1305
1306 AbortStr[0] = Abort ? 'F' : 'T';
1307 AbortStr[1] = '\0';
1308
1309 return XenStoreSingle (Transaction, XS_TRANSACTION_END, AbortStr, NULL, NULL);
1310 }
1311
1312 XENSTORE_STATUS
1313 XenStoreVSPrint (
1314 IN CONST XENSTORE_TRANSACTION *Transaction,
1315 IN CONST CHAR8 *DirectoryPath,
1316 IN CONST CHAR8 *Node,
1317 IN CONST CHAR8 *FormatString,
1318 IN VA_LIST Marker
1319 )
1320 {
1321 CHAR8 *Buf;
1322 XENSTORE_STATUS Status;
1323 UINTN BufSize;
1324 VA_LIST Marker2;
1325
1326 VA_COPY (Marker2, Marker);
1327 BufSize = SPrintLengthAsciiFormat (FormatString, Marker2) + 1;
1328 VA_END (Marker2);
1329 Buf = AllocateZeroPool (BufSize);
1330 AsciiVSPrint (Buf, BufSize, FormatString, Marker);
1331 Status = XenStoreWrite (Transaction, DirectoryPath, Node, Buf);
1332 FreePool (Buf);
1333
1334 return Status;
1335 }
1336
1337 XENSTORE_STATUS
1338 EFIAPI
1339 XenStoreSPrint (
1340 IN CONST XENSTORE_TRANSACTION *Transaction,
1341 IN CONST CHAR8 *DirectoryPath,
1342 IN CONST CHAR8 *Node,
1343 IN CONST CHAR8 *FormatString,
1344 ...
1345 )
1346 {
1347 VA_LIST Marker;
1348 XENSTORE_STATUS Status;
1349
1350 VA_START (Marker, FormatString);
1351 Status = XenStoreVSPrint (Transaction, DirectoryPath, Node, FormatString, Marker);
1352 VA_END (Marker);
1353
1354 return Status;
1355 }
1356
1357 XENSTORE_STATUS
1358 XenStoreRegisterWatch (
1359 IN CONST CHAR8 *DirectoryPath,
1360 IN CONST CHAR8 *Node,
1361 OUT XENSTORE_WATCH **WatchPtr
1362 )
1363 {
1364 /* Pointer in ascii is the token. */
1365 CHAR8 Token[sizeof (XENSTORE_WATCH) * 2 + 1];
1366 XENSTORE_STATUS Status;
1367 XENSTORE_WATCH *Watch;
1368
1369 Watch = AllocateZeroPool (sizeof (XENSTORE_WATCH));
1370 Watch->Signature = XENSTORE_WATCH_SIGNATURE;
1371 Watch->Node = XenStoreJoin (DirectoryPath, Node);
1372
1373 EfiAcquireLock (&xs.RegisteredWatchesLock);
1374 InsertTailList (&xs.RegisteredWatches, &Watch->Link);
1375 EfiReleaseLock (&xs.RegisteredWatchesLock);
1376
1377 AsciiSPrint (Token, sizeof (Token), "%p", (VOID*) Watch);
1378 Status = XenStoreWatch (Watch->Node, Token);
1379
1380 /* Ignore errors due to multiple registration. */
1381 if (Status == XENSTORE_STATUS_EEXIST) {
1382 Status = XENSTORE_STATUS_SUCCESS;
1383 }
1384
1385 if (Status == XENSTORE_STATUS_SUCCESS) {
1386 *WatchPtr = Watch;
1387 } else {
1388 EfiAcquireLock (&xs.RegisteredWatchesLock);
1389 RemoveEntryList (&Watch->Link);
1390 EfiReleaseLock (&xs.RegisteredWatchesLock);
1391 FreePool (Watch->Node);
1392 FreePool (Watch);
1393 }
1394
1395 return Status;
1396 }
1397
1398 VOID
1399 XenStoreUnregisterWatch (
1400 IN XENSTORE_WATCH *Watch
1401 )
1402 {
1403 CHAR8 Token[sizeof (Watch) * 2 + 1];
1404 LIST_ENTRY *Entry;
1405
1406 ASSERT (Watch->Signature == XENSTORE_WATCH_SIGNATURE);
1407
1408 AsciiSPrint (Token, sizeof (Token), "%p", (VOID *) Watch);
1409 if (XenStoreFindWatch (Token) == NULL) {
1410 return;
1411 }
1412
1413 EfiAcquireLock (&xs.RegisteredWatchesLock);
1414 RemoveEntryList (&Watch->Link);
1415 EfiReleaseLock (&xs.RegisteredWatchesLock);
1416
1417 XenStoreUnwatch (Watch->Node, Token);
1418
1419 /* Cancel pending watch events. */
1420 EfiAcquireLock (&xs.WatchEventsLock);
1421 Entry = GetFirstNode (&xs.WatchEvents);
1422 while (!IsNull (&xs.WatchEvents, Entry)) {
1423 XENSTORE_MESSAGE *Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
1424 Entry = GetNextNode (&xs.WatchEvents, Entry);
1425 if (Message->u.Watch.Handle == Watch) {
1426 RemoveEntryList (&Message->Link);
1427 FreePool ((VOID*)Message->u.Watch.Vector);
1428 FreePool (Message);
1429 }
1430 }
1431 EfiReleaseLock (&xs.WatchEventsLock);
1432
1433 FreePool (Watch->Node);
1434 FreePool (Watch);
1435 }
1436
1437
1438 //
1439 // XENBUS protocol
1440 //
1441
1442 XENSTORE_STATUS
1443 EFIAPI
1444 XenBusWaitForWatch (
1445 IN XENBUS_PROTOCOL *This,
1446 IN VOID *Token
1447 )
1448 {
1449 return XenStoreWaitWatch (Token);
1450 }
1451
1452 XENSTORE_STATUS
1453 EFIAPI
1454 XenBusXenStoreRead (
1455 IN XENBUS_PROTOCOL *This,
1456 IN CONST XENSTORE_TRANSACTION *Transaction,
1457 IN CONST CHAR8 *Node,
1458 OUT VOID **Value
1459 )
1460 {
1461 return XenStoreRead (Transaction, This->Node, Node, NULL, Value);
1462 }
1463
1464 XENSTORE_STATUS
1465 EFIAPI
1466 XenBusXenStoreBackendRead (
1467 IN XENBUS_PROTOCOL *This,
1468 IN CONST XENSTORE_TRANSACTION *Transaction,
1469 IN CONST CHAR8 *Node,
1470 OUT VOID **Value
1471 )
1472 {
1473 return XenStoreRead (Transaction, This->Backend, Node, NULL, Value);
1474 }
1475
1476 XENSTORE_STATUS
1477 EFIAPI
1478 XenBusXenStoreRemove (
1479 IN XENBUS_PROTOCOL *This,
1480 IN CONST XENSTORE_TRANSACTION *Transaction,
1481 IN const char *Node
1482 )
1483 {
1484 return XenStoreRemove (Transaction, This->Node, Node);
1485 }
1486
1487 XENSTORE_STATUS
1488 EFIAPI
1489 XenBusXenStoreTransactionStart (
1490 IN XENBUS_PROTOCOL *This,
1491 OUT XENSTORE_TRANSACTION *Transaction
1492 )
1493 {
1494 return XenStoreTransactionStart (Transaction);
1495 }
1496
1497 XENSTORE_STATUS
1498 EFIAPI
1499 XenBusXenStoreTransactionEnd (
1500 IN XENBUS_PROTOCOL *This,
1501 IN CONST XENSTORE_TRANSACTION *Transaction,
1502 IN BOOLEAN Abort
1503 )
1504 {
1505 return XenStoreTransactionEnd (Transaction, Abort);
1506 }
1507
1508 XENSTORE_STATUS
1509 EFIAPI
1510 XenBusXenStoreSPrint (
1511 IN XENBUS_PROTOCOL *This,
1512 IN CONST XENSTORE_TRANSACTION *Transaction,
1513 IN CONST CHAR8 *DirectoryPath,
1514 IN CONST CHAR8 *Node,
1515 IN CONST CHAR8 *FormatString,
1516 ...
1517 )
1518 {
1519 VA_LIST Marker;
1520 XENSTORE_STATUS Status;
1521
1522 VA_START (Marker, FormatString);
1523 Status = XenStoreVSPrint (Transaction, DirectoryPath, Node, FormatString, Marker);
1524 VA_END (Marker);
1525
1526 return Status;
1527 }
1528
1529 XENSTORE_STATUS
1530 EFIAPI
1531 XenBusRegisterWatch (
1532 IN XENBUS_PROTOCOL *This,
1533 IN CONST CHAR8 *Node,
1534 OUT VOID **Token
1535 )
1536 {
1537 return XenStoreRegisterWatch (This->Node, Node, (XENSTORE_WATCH **) Token);
1538 }
1539
1540 XENSTORE_STATUS
1541 EFIAPI
1542 XenBusRegisterWatchBackend (
1543 IN XENBUS_PROTOCOL *This,
1544 IN CONST CHAR8 *Node,
1545 OUT VOID **Token
1546 )
1547 {
1548 return XenStoreRegisterWatch (This->Backend, Node, (XENSTORE_WATCH **) Token);
1549 }
1550
1551 VOID
1552 EFIAPI
1553 XenBusUnregisterWatch (
1554 IN XENBUS_PROTOCOL *This,
1555 IN VOID *Token
1556 )
1557 {
1558 XenStoreUnregisterWatch ((XENSTORE_WATCH *) Token);
1559 }