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