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