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