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 callback 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
ExtractStrings(IN CONST CHAR8 * Strings,IN UINTN Len,OUT CONST CHAR8 ** Dst OPTIONAL)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 **
Split(IN CHAR8 * Strings,IN UINTN Len,OUT UINT32 * NumPtr)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 *
XenStoreFindWatch(IN CONST CHAR8 * Token)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 *
XenStoreJoin(IN CONST CHAR8 * DirectoryPath,IN CONST CHAR8 * Node)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
XenStoreCheckIndexes(XENSTORE_RING_IDX Cons,XENSTORE_RING_IDX Prod)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 *
XenStoreGetOutputChunk(IN XENSTORE_RING_IDX Cons,IN XENSTORE_RING_IDX Prod,IN CHAR8 * Buffer,OUT UINT32 * LenPtr)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 *
XenStoreGetInputChunk(IN XENSTORE_RING_IDX Cons,IN XENSTORE_RING_IDX Prod,IN CONST CHAR8 * Buffer,OUT UINT32 * LenPtr)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
XenStoreWaitForEvent(IN EFI_EVENT Event,IN UINT64 Timeout)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
XenStoreWriteStore(IN CONST VOID * DataPtr,IN UINT32 Len)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 ((DEBUG_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
XenStoreReadStore(OUT VOID * DataPtr,IN UINT32 Len)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 ((DEBUG_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
XenStoreProcessMessage(VOID)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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_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
XenStoreGetError(CONST CHAR8 * ErrorStr)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 ((DEBUG_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
XenStoreReadReply(OUT enum xsd_sockmsg_type * TypePtr,OUT UINT32 * LenPtr OPTIONAL,OUT VOID ** Result)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 ((DEBUG_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 multi-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
XenStoreTalkv(IN CONST XENSTORE_TRANSACTION * Transaction,IN enum xsd_sockmsg_type RequestType,IN CONST WRITE_REQUEST * WriteRequest,IN UINT32 NumRequests,OUT UINT32 * LenPtr OPTIONAL,OUT VOID ** ResultPtr OPTIONAL)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 ((DEBUG_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 ((DEBUG_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
XenStoreSingle(IN CONST XENSTORE_TRANSACTION * Transaction,IN enum xsd_sockmsg_type RequestType,IN CONST CHAR8 * Body,OUT UINT32 * LenPtr OPTIONAL,OUT VOID ** Result OPTIONAL)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
XenStoreWatch(CONST CHAR8 * Path,CONST CHAR8 * Token)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
XenStoreUnwatch(CONST CHAR8 * Path,CONST CHAR8 * Token)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
XenStoreWaitWatch(VOID * Token)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
NotifyEventChannelCheckForEvent(IN EFI_EVENT Event,IN VOID * Context)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
XenStoreInitComms(XENSTORE_PRIVATE * xsp)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 ((DEBUG_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
XenStoreInit(XENBUS_DEVICE * Dev)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 ((DEBUG_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
XenStoreDeinit(IN XENBUS_DEVICE * Dev)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 ((DEBUG_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 ((DEBUG_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
XenStoreListDirectory(IN CONST XENSTORE_TRANSACTION * Transaction,IN CONST CHAR8 * DirectoryPath,IN CONST CHAR8 * Node,OUT UINT32 * DirectoryCountPtr,OUT CONST CHAR8 *** DirectoryListPtr)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
XenStorePathExists(IN CONST XENSTORE_TRANSACTION * Transaction,IN CONST CHAR8 * Directory,IN CONST CHAR8 * Node)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
XenStoreRead(IN CONST XENSTORE_TRANSACTION * Transaction,IN CONST CHAR8 * DirectoryPath,IN CONST CHAR8 * Node,OUT UINT32 * LenPtr OPTIONAL,OUT VOID ** Result)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
XenStoreWrite(IN CONST XENSTORE_TRANSACTION * Transaction,IN CONST CHAR8 * DirectoryPath,IN CONST CHAR8 * Node,IN CONST CHAR8 * Str)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
XenStoreRemove(IN CONST XENSTORE_TRANSACTION * Transaction,IN CONST CHAR8 * DirectoryPath,IN CONST CHAR8 * Node)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
XenStoreTransactionStart(OUT XENSTORE_TRANSACTION * Transaction)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
XenStoreTransactionEnd(IN CONST XENSTORE_TRANSACTION * Transaction,IN BOOLEAN Abort)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
XenStoreVSPrint(IN CONST XENSTORE_TRANSACTION * Transaction,IN CONST CHAR8 * DirectoryPath,IN CONST CHAR8 * Node,IN CONST CHAR8 * FormatString,IN VA_LIST Marker)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
XenStoreSPrint(IN CONST XENSTORE_TRANSACTION * Transaction,IN CONST CHAR8 * DirectoryPath,IN CONST CHAR8 * Node,IN CONST CHAR8 * FormatString,...)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
XenStoreRegisterWatch(IN CONST CHAR8 * DirectoryPath,IN CONST CHAR8 * Node,OUT XENSTORE_WATCH ** WatchPtr)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
XenStoreUnregisterWatch(IN XENSTORE_WATCH * Watch)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
XenBusWaitForWatch(IN XENBUS_PROTOCOL * This,IN VOID * Token)1423 XenBusWaitForWatch (
1424   IN XENBUS_PROTOCOL *This,
1425   IN VOID *Token
1426   )
1427 {
1428   return XenStoreWaitWatch (Token);
1429 }
1430 
1431 XENSTORE_STATUS
1432 EFIAPI
XenBusXenStoreRead(IN XENBUS_PROTOCOL * This,IN CONST XENSTORE_TRANSACTION * Transaction,IN CONST CHAR8 * Node,OUT VOID ** Value)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
XenBusXenStoreBackendRead(IN XENBUS_PROTOCOL * This,IN CONST XENSTORE_TRANSACTION * Transaction,IN CONST CHAR8 * Node,OUT VOID ** Value)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
XenBusXenStoreRemove(IN XENBUS_PROTOCOL * This,IN CONST XENSTORE_TRANSACTION * Transaction,IN const char * Node)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
XenBusXenStoreTransactionStart(IN XENBUS_PROTOCOL * This,OUT XENSTORE_TRANSACTION * Transaction)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
XenBusXenStoreTransactionEnd(IN XENBUS_PROTOCOL * This,IN CONST XENSTORE_TRANSACTION * Transaction,IN BOOLEAN Abort)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
XenBusXenStoreSPrint(IN XENBUS_PROTOCOL * This,IN CONST XENSTORE_TRANSACTION * Transaction,IN CONST CHAR8 * DirectoryPath,IN CONST CHAR8 * Node,IN CONST CHAR8 * FormatString,...)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
XenBusRegisterWatch(IN XENBUS_PROTOCOL * This,IN CONST CHAR8 * Node,OUT VOID ** Token)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
XenBusRegisterWatchBackend(IN XENBUS_PROTOCOL * This,IN CONST CHAR8 * Node,OUT VOID ** Token)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
XenBusUnregisterWatch(IN XENBUS_PROTOCOL * This,IN VOID * Token)1532 XenBusUnregisterWatch (
1533   IN XENBUS_PROTOCOL  *This,
1534   IN VOID             *Token
1535   )
1536 {
1537   XenStoreUnregisterWatch ((XENSTORE_WATCH *) Token);
1538 }
1539