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