]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/XenBusDxe/XenStore.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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
ac0a286f
MK
55 CONST VOID *Data;\r
56 UINT32 Len;\r
a9090a94
AP
57} WRITE_REQUEST;\r
58\r
59/* Register callback to watch subtree (node) in the XenStore. */\r
ac0a286f
MK
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
a9090a94
AP
64\r
65 /* Path being watched. */\r
ac0a286f 66 CHAR8 *Node;\r
a9090a94
AP
67};\r
68\r
69#define XENSTORE_WATCH_FROM_LINK(l) \\r
70 CR (l, XENSTORE_WATCH, Link, XENSTORE_WATCH_SIGNATURE)\r
71\r
a9090a94
AP
72/**\r
73 * Structure capturing messages received from the XenStore service.\r
74 */\r
ac0a286f 75#define XENSTORE_MESSAGE_SIGNATURE SIGNATURE_32 ('X', 'S', 's', 'm')\r
a9090a94 76typedef struct {\r
ac0a286f
MK
77 UINT32 Signature;\r
78 LIST_ENTRY Link;\r
a9090a94 79\r
ac0a286f 80 struct xsd_sockmsg Header;\r
a9090a94
AP
81\r
82 union {\r
83 /* Queued replies. */\r
84 struct {\r
ac0a286f 85 CHAR8 *Body;\r
a9090a94
AP
86 } Reply;\r
87\r
88 /* Queued watch events. */\r
89 struct {\r
ac0a286f
MK
90 XENSTORE_WATCH *Handle;\r
91 CONST CHAR8 **Vector;\r
92 UINT32 VectorSize;\r
a9090a94
AP
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
ac0a286f 107 struct xenstore_domain_interface *XenStore;\r
a9090a94 108\r
ac0a286f 109 XENBUS_DEVICE *Dev;\r
a9090a94
AP
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
ac0a286f 121 LIST_ENTRY ReplyList;\r
a9090a94
AP
122\r
123 /** Lock protecting the reply list. */\r
ac0a286f 124 EFI_LOCK ReplyLock;\r
a9090a94
AP
125\r
126 /**\r
127 * List of registered watches.\r
128 */\r
ac0a286f 129 LIST_ENTRY RegisteredWatches;\r
a9090a94
AP
130\r
131 /** Lock protecting the registered watches list. */\r
ac0a286f 132 EFI_LOCK RegisteredWatchesLock;\r
a9090a94
AP
133\r
134 /**\r
135 * List of pending watch callback events.\r
136 */\r
ac0a286f 137 LIST_ENTRY WatchEvents;\r
a9090a94 138\r
493dde94 139 /** Lock protecting the watch callback list. */\r
ac0a286f 140 EFI_LOCK WatchEventsLock;\r
a9090a94
AP
141\r
142 /**\r
143 * The event channel for communicating with the\r
144 * XenStore service.\r
145 */\r
ac0a286f 146 evtchn_port_t EventChannel;\r
a9090a94
AP
147\r
148 /** Handle for XenStore events. */\r
ac0a286f 149 EFI_EVENT EventChannelEvent;\r
a9090a94
AP
150} XENSTORE_PRIVATE;\r
151\r
152//\r
153// Global Data\r
154//\r
ac0a286f 155static XENSTORE_PRIVATE xs;\r
a9090a94
AP
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
ac0a286f
MK
174 IN CONST CHAR8 *Strings,\r
175 IN UINTN Len,\r
176 OUT CONST CHAR8 **Dst OPTIONAL\r
a9090a94
AP
177 )\r
178{\r
ac0a286f
MK
179 UINT32 Num = 0;\r
180 CONST CHAR8 *Ptr;\r
a9090a94
AP
181\r
182 for (Ptr = Strings; Ptr < Strings + Len; Ptr += AsciiStrSize (Ptr)) {\r
183 if (Dst != NULL) {\r
184 *Dst++ = Ptr;\r
185 }\r
ac0a286f 186\r
a9090a94
AP
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
ac0a286f 218 CONST CHAR8 **Dst;\r
a9090a94 219\r
ac0a286f
MK
220 ASSERT (NumPtr != NULL);\r
221 ASSERT (Strings != NULL);\r
a9090a94
AP
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
ac0a286f 233 CopyMem ((VOID *)&Dst[*NumPtr], Strings, Len);\r
a9090a94
AP
234 FreePool (Strings);\r
235\r
236 /* Extract pointers to newly allocated array. */\r
ac0a286f 237 Strings = (CHAR8 *)&Dst[*NumPtr];\r
a9090a94
AP
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
ac0a286f 254 IN CONST CHAR8 *Token\r
a9090a94
AP
255 )\r
256{\r
ac0a286f
MK
257 XENSTORE_WATCH *Watch, *WantedWatch;\r
258 LIST_ENTRY *Entry;\r
a9090a94 259\r
ac0a286f 260 WantedWatch = (VOID *)AsciiStrHexToUintn (Token);\r
a9090a94
AP
261\r
262 if (IsListEmpty (&xs.RegisteredWatches)) {\r
263 return NULL;\r
264 }\r
ac0a286f 265\r
a9090a94
AP
266 for (Entry = GetFirstNode (&xs.RegisteredWatches);\r
267 !IsNull (&xs.RegisteredWatches, Entry);\r
ac0a286f
MK
268 Entry = GetNextNode (&xs.RegisteredWatches, Entry))\r
269 {\r
a9090a94 270 Watch = XENSTORE_WATCH_FROM_LINK (Entry);\r
ac0a286f 271 if (Watch == WantedWatch) {\r
a9090a94 272 return Watch;\r
ac0a286f 273 }\r
a9090a94
AP
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
ac0a286f
MK
286 IN CONST CHAR8 *DirectoryPath,\r
287 IN CONST CHAR8 *Node\r
a9090a94
AP
288 )\r
289{\r
ac0a286f
MK
290 CHAR8 *Buf;\r
291 UINTN BufSize;\r
a9090a94
AP
292\r
293 /* +1 for '/' and +1 for '\0' */\r
2462bd3d 294 BufSize = AsciiStrLen (DirectoryPath) + AsciiStrLen (Node) + 2;\r
ac0a286f 295 Buf = AllocatePool (BufSize);\r
2462bd3d
LE
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
a9090a94
AP
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
ac0a286f
MK
326 XENSTORE_RING_IDX Cons,\r
327 XENSTORE_RING_IDX Prod\r
a9090a94
AP
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
ac0a286f
MK
347 IN XENSTORE_RING_IDX Cons,\r
348 IN XENSTORE_RING_IDX Prod,\r
349 IN CHAR8 *Buffer,\r
350 OUT UINT32 *LenPtr\r
a9090a94
AP
351 )\r
352{\r
ac0a286f
MK
353 UINT32 Len;\r
354\r
a9090a94
AP
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
ac0a286f 359\r
a9090a94
AP
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
ac0a286f
MK
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
a9090a94
AP
382 )\r
383{\r
ac0a286f 384 UINT32 Len;\r
a9090a94
AP
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
ac0a286f 390\r
a9090a94
AP
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
ac0a286f
MK
408 IN EFI_EVENT Event,\r
409 IN UINT64 Timeout\r
a9090a94
AP
410 )\r
411{\r
ac0a286f
MK
412 UINTN Index;\r
413 EFI_STATUS Status;\r
414 EFI_EVENT TimerEvent;\r
415 EFI_EVENT WaitList[2];\r
a9090a94
AP
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
ac0a286f 422 Status = gBS->WaitForEvent (2, WaitList, &Index);\r
a9090a94
AP
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
ac0a286f 428\r
a9090a94
AP
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
ac0a286f
MK
450 IN CONST VOID *DataPtr,\r
451 IN UINT32 Len\r
a9090a94
AP
452 )\r
453{\r
ac0a286f
MK
454 XENSTORE_RING_IDX Cons, Prod;\r
455 CONST CHAR8 *Data = (CONST CHAR8 *)DataPtr;\r
a9090a94
AP
456\r
457 while (Len != 0) {\r
ac0a286f
MK
458 void *Dest;\r
459 UINT32 Available;\r
a9090a94
AP
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
ac0a286f 470 EFI_STATUS Status;\r
a9090a94 471\r
ac0a286f
MK
472 Status = XenStoreWaitForEvent (\r
473 xs.EventChannelEvent,\r
474 EFI_TIMER_PERIOD_SECONDS (1)\r
475 );\r
a9090a94 476 if (Status == EFI_TIMEOUT) {\r
70d5086c 477 DEBUG ((DEBUG_WARN, "XenStore Write, waiting for a ring event.\n"));\r
a9090a94 478 }\r
ac0a286f 479\r
a9090a94
AP
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
ac0a286f 496 Len -= Available;\r
a9090a94
AP
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
ac0a286f
MK
532 OUT VOID *DataPtr,\r
533 IN UINT32 Len\r
a9090a94
AP
534 )\r
535{\r
ac0a286f
MK
536 XENSTORE_RING_IDX Cons, Prod;\r
537 CHAR8 *Data = (CHAR8 *)DataPtr;\r
a9090a94
AP
538\r
539 while (Len != 0) {\r
ac0a286f
MK
540 UINT32 Available;\r
541 CONST CHAR8 *Src;\r
a9090a94
AP
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
ac0a286f 552 EFI_STATUS Status;\r
a9090a94 553\r
ac0a286f
MK
554 Status = XenStoreWaitForEvent (\r
555 xs.EventChannelEvent,\r
556 EFI_TIMER_PERIOD_SECONDS (1)\r
557 );\r
a9090a94 558 if (Status == EFI_TIMEOUT) {\r
70d5086c 559 DEBUG ((DEBUG_WARN, "XenStore Read, waiting for a ring event.\n"));\r
a9090a94 560 }\r
ac0a286f 561\r
a9090a94
AP
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
ac0a286f 584 Len -= Available;\r
a9090a94
AP
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
ac0a286f
MK
622 XENSTORE_MESSAGE *Message;\r
623 CHAR8 *Body;\r
624 XENSTORE_STATUS Status;\r
a9090a94 625\r
ac0a286f 626 Message = AllocateZeroPool (sizeof (XENSTORE_MESSAGE));\r
a9090a94 627 Message->Signature = XENSTORE_MESSAGE_SIGNATURE;\r
ac0a286f 628 Status = XenStoreReadStore (&Message->Header, sizeof (Message->Header));\r
a9090a94
AP
629 if (Status != XENSTORE_STATUS_SUCCESS) {\r
630 FreePool (Message);\r
70d5086c 631 DEBUG ((DEBUG_ERROR, "XenStore: Error read store (%d)\n", Status));\r
a9090a94
AP
632 return Status;\r
633 }\r
634\r
ac0a286f 635 Body = AllocatePool (Message->Header.len + 1);\r
a9090a94
AP
636 Status = XenStoreReadStore (Body, Message->Header.len);\r
637 if (Status != XENSTORE_STATUS_SUCCESS) {\r
638 FreePool (Body);\r
639 FreePool (Message);\r
70d5086c 640 DEBUG ((DEBUG_ERROR, "XenStore: Error read store (%d)\n", Status));\r
a9090a94
AP
641 return Status;\r
642 }\r
ac0a286f 643\r
a9090a94
AP
644 Body[Message->Header.len] = '\0';\r
645\r
646 if (Message->Header.type == XS_WATCH_EVENT) {\r
ac0a286f
MK
647 Message->u.Watch.Vector = Split (\r
648 Body,\r
649 Message->Header.len,\r
650 &Message->u.Watch.VectorSize\r
651 );\r
a9090a94
AP
652\r
653 EfiAcquireLock (&xs.RegisteredWatchesLock);\r
654 Message->u.Watch.Handle =\r
655 XenStoreFindWatch (Message->u.Watch.Vector[XS_WATCH_TOKEN]);\r
ac0a286f
MK
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
a9090a94
AP
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
ac0a286f
MK
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
a9090a94 673 }\r
ac0a286f 674\r
a9090a94
AP
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
ac0a286f
MK
701 XENSTORE_STATUS Status;\r
702 CONST CHAR8 *ErrorStr;\r
a9090a94
AP
703} XenStoreErrors;\r
704\r
ac0a286f
MK
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
a9090a94 714 { XENSTORE_STATUS_ENOTEMPTY, "ENOTEMPTY" },\r
ac0a286f
MK
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
a9090a94 721};\r
a9090a94
AP
722\r
723STATIC\r
724XENSTORE_STATUS\r
725XenStoreGetError (\r
ac0a286f 726 CONST CHAR8 *ErrorStr\r
a9090a94
AP
727 )\r
728{\r
ac0a286f 729 UINT32 Index;\r
a9090a94 730\r
ac0a286f 731 for (Index = 0; Index < ARRAY_SIZE (gXenStoreErrors); Index++) {\r
a9090a94
AP
732 if (!AsciiStrCmp (ErrorStr, gXenStoreErrors[Index].ErrorStr)) {\r
733 return gXenStoreErrors[Index].Status;\r
734 }\r
735 }\r
ac0a286f 736\r
70d5086c 737 DEBUG ((DEBUG_WARN, "XenStore gave unknown error %a\n", ErrorStr));\r
a9090a94
AP
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
ac0a286f
MK
751 OUT enum xsd_sockmsg_type *TypePtr,\r
752 OUT UINT32 *LenPtr OPTIONAL,\r
753 OUT VOID **Result\r
a9090a94
AP
754 )\r
755{\r
ac0a286f
MK
756 XENSTORE_MESSAGE *Message;\r
757 LIST_ENTRY *Entry;\r
758 CHAR8 *Body;\r
a9090a94
AP
759\r
760 while (IsListEmpty (&xs.ReplyList)) {\r
ac0a286f 761 XENSTORE_STATUS Status;\r
a9090a94 762 Status = XenStoreProcessMessage ();\r
ac0a286f
MK
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
a9090a94
AP
769 return Status;\r
770 }\r
771 }\r
ac0a286f 772\r
a9090a94 773 EfiAcquireLock (&xs.ReplyLock);\r
ac0a286f 774 Entry = GetFirstNode (&xs.ReplyList);\r
a9090a94
AP
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
ac0a286f 783\r
a9090a94
AP
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
493dde94 792 Send a message with an optionally multi-part body to the XenStore service.\r
a9090a94
AP
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
ac0a286f
MK
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
a9090a94
AP
813 )\r
814{\r
ac0a286f
MK
815 struct xsd_sockmsg Message;\r
816 void *Return = NULL;\r
817 UINT32 Index;\r
818 XENSTORE_STATUS Status;\r
a9090a94 819\r
e26a83cd
AP
820 if (Transaction == XST_NIL) {\r
821 Message.tx_id = 0;\r
822 } else {\r
823 Message.tx_id = Transaction->Id;\r
824 }\r
ac0a286f 825\r
a9090a94 826 Message.req_id = 0;\r
ac0a286f
MK
827 Message.type = RequestType;\r
828 Message.len = 0;\r
a9090a94
AP
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
70d5086c 835 DEBUG ((DEBUG_ERROR, "XenStoreTalkv failed %d\n", Status));\r
a9090a94
AP
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
70d5086c 842 DEBUG ((DEBUG_ERROR, "XenStoreTalkv failed %d\n", Status));\r
a9090a94
AP
843 goto Error;\r
844 }\r
845 }\r
846\r
017a4866 847 Status = XenStoreReadReply ((enum xsd_sockmsg_type *)&Message.type, LenPtr, &Return);\r
a9090a94
AP
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
017a4866 861 ASSERT ((enum xsd_sockmsg_type)Message.type == RequestType);\r
a9090a94
AP
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
ac0a286f
MK
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
a9090a94
AP
896 )\r
897{\r
ac0a286f
MK
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
a9090a94
AP
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
ac0a286f
MK
929 CONST CHAR8 *Path,\r
930 CONST CHAR8 *Token\r
a9090a94
AP
931 )\r
932{\r
ac0a286f 933 WRITE_REQUEST WriteRequest[2];\r
a9090a94 934\r
ac0a286f
MK
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
a9090a94
AP
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
ac0a286f
MK
955 CONST CHAR8 *Path,\r
956 CONST CHAR8 *Token\r
a9090a94
AP
957 )\r
958{\r
ac0a286f 959 WRITE_REQUEST WriteRequest[2];\r
a9090a94 960\r
ac0a286f
MK
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
a9090a94
AP
965\r
966 return XenStoreTalkv (XST_NIL, XS_UNWATCH, WriteRequest, 2, NULL, NULL);\r
967}\r
968\r
c23c037f
AP
969STATIC\r
970XENSTORE_STATUS\r
971XenStoreWaitWatch (\r
ac0a286f 972 VOID *Token\r
c23c037f
AP
973 )\r
974{\r
ac0a286f
MK
975 XENSTORE_MESSAGE *Message;\r
976 LIST_ENTRY *Entry = NULL;\r
977 LIST_ENTRY *Last = NULL;\r
978 XENSTORE_STATUS Status;\r
c23c037f
AP
979\r
980 while (TRUE) {\r
981 EfiAcquireLock (&xs.WatchEventsLock);\r
982 if (IsListEmpty (&xs.WatchEvents) ||\r
ac0a286f
MK
983 (Last == GetFirstNode (&xs.WatchEvents)))\r
984 {\r
c23c037f
AP
985 EfiReleaseLock (&xs.WatchEventsLock);\r
986 Status = XenStoreProcessMessage ();\r
ac0a286f 987 if ((Status != XENSTORE_STATUS_SUCCESS) && (Status != XENSTORE_STATUS_EAGAIN)) {\r
c23c037f
AP
988 return Status;\r
989 }\r
ac0a286f 990\r
c23c037f
AP
991 continue;\r
992 }\r
993\r
994 for (Entry = GetFirstNode (&xs.WatchEvents);\r
995 Entry != Last && !IsNull (&xs.WatchEvents, Entry);\r
ac0a286f
MK
996 Entry = GetNextNode (&xs.WatchEvents, Entry))\r
997 {\r
c23c037f
AP
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
ac0a286f
MK
1002 FreePool ((VOID *)Message->u.Watch.Vector);\r
1003 FreePool (Message);\r
c23c037f
AP
1004 return XENSTORE_STATUS_SUCCESS;\r
1005 }\r
1006 }\r
ac0a286f 1007\r
c23c037f
AP
1008 Last = GetFirstNode (&xs.WatchEvents);\r
1009 EfiReleaseLock (&xs.WatchEventsLock);\r
1010 }\r
1011}\r
1012\r
a9090a94
AP
1013VOID\r
1014EFIAPI\r
1015NotifyEventChannelCheckForEvent (\r
ac0a286f
MK
1016 IN EFI_EVENT Event,\r
1017 IN VOID *Context\r
a9090a94
AP
1018 )\r
1019{\r
ac0a286f
MK
1020 XENSTORE_PRIVATE *xsp;\r
1021\r
17247f53
LG
1022 xsp = (XENSTORE_PRIVATE *)Context;\r
1023 if (TestAndClearBit (xsp->EventChannel, xsp->Dev->SharedInfo->evtchn_pending)) {\r
a9090a94
AP
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
ac0a286f 1036 XENSTORE_PRIVATE *xsp\r
a9090a94
AP
1037 )\r
1038{\r
ac0a286f
MK
1039 EFI_STATUS Status;\r
1040 EFI_EVENT TimerEvent;\r
1041 struct xenstore_domain_interface *XenStore = xsp->XenStore;\r
a9090a94
AP
1042\r
1043 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
ac0a286f
MK
1044 Status = gBS->SetTimer (\r
1045 TimerEvent,\r
1046 TimerRelative,\r
1047 EFI_TIMER_PERIOD_SECONDS (5)\r
1048 );\r
a9090a94
AP
1049 while (XenStore->rsp_prod != XenStore->rsp_cons) {\r
1050 Status = gBS->CheckEvent (TimerEvent);\r
1051 if (!EFI_ERROR (Status)) {\r
ac0a286f
MK
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
a9090a94
AP
1059 XenStore->rsp_cons = XenStore->rsp_prod;\r
1060 }\r
1061 }\r
ac0a286f 1062\r
a9090a94
AP
1063 gBS->CloseEvent (TimerEvent);\r
1064\r
ac0a286f
MK
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
a9090a94
AP
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
ac0a286f 1086 XENBUS_DEVICE *Dev\r
a9090a94
AP
1087 )\r
1088{\r
ac0a286f
MK
1089 EFI_STATUS Status;\r
1090\r
a9090a94
AP
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
ac0a286f 1095 UINTN XenStoreGpfn;\r
a9090a94
AP
1096\r
1097 xs.Dev = Dev;\r
1098\r
bbc3758a 1099 xs.EventChannel = (evtchn_port_t)XenHypercallHvmGetParam (HVM_PARAM_STORE_EVTCHN);\r
ac0a286f
MK
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
a9090a94
AP
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
a9090a94
AP
1119\r
1120 return Status;\r
1121}\r
1122\r
1123VOID\r
1124XenStoreDeinit (\r
ac0a286f 1125 IN XENBUS_DEVICE *Dev\r
a9090a94
AP
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
ac0a286f
MK
1134 XENSTORE_WATCH *Watch;\r
1135 LIST_ENTRY *Entry;\r
70d5086c 1136 DEBUG ((DEBUG_WARN, "XenStore: RegisteredWatches is not empty, cleaning up..."));\r
a9090a94
AP
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
ac0a286f 1151 LIST_ENTRY *Entry;\r
70d5086c 1152 DEBUG ((DEBUG_WARN, "XenStore: WatchEvents is not empty, cleaning up..."));\r
a9090a94
AP
1153 Entry = GetFirstNode (&xs.WatchEvents);\r
1154 while (!IsNull (&xs.WatchEvents, Entry)) {\r
ac0a286f 1155 XENSTORE_MESSAGE *Message = XENSTORE_MESSAGE_FROM_LINK (Entry);\r
a9090a94
AP
1156 Entry = GetNextNode (&xs.WatchEvents, Entry);\r
1157 RemoveEntryList (&Message->Link);\r
ac0a286f 1158 FreePool ((VOID *)Message->u.Watch.Vector);\r
a9090a94
AP
1159 FreePool (Message);\r
1160 }\r
1161 }\r
1162\r
1163 if (!IsListEmpty (&xs.ReplyList)) {\r
ac0a286f
MK
1164 XENSTORE_MESSAGE *Message;\r
1165 LIST_ENTRY *Entry;\r
a9090a94
AP
1166 Entry = GetFirstNode (&xs.ReplyList);\r
1167 while (!IsNull (&xs.ReplyList, Entry)) {\r
1168 Message = XENSTORE_MESSAGE_FROM_LINK (Entry);\r
ac0a286f 1169 Entry = GetNextNode (&xs.ReplyList, Entry);\r
a9090a94
AP
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
ac0a286f 1181 while (*(volatile UINT32 *)&xs.XenStore->connection == XENSTORE_RECONNECT) {\r
a9090a94
AP
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
ac0a286f 1194\r
a9090a94
AP
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
ac0a286f
MK
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
a9090a94
AP
1210 )\r
1211{\r
ac0a286f
MK
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
a9090a94
AP
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
ac0a286f
MK
1237 IN CONST XENSTORE_TRANSACTION *Transaction,\r
1238 IN CONST CHAR8 *Directory,\r
1239 IN CONST CHAR8 *Node\r
a9090a94
AP
1240 )\r
1241{\r
ac0a286f
MK
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
a9090a94
AP
1253 if (Status != XENSTORE_STATUS_SUCCESS) {\r
1254 return FALSE;\r
1255 }\r
ac0a286f
MK
1256\r
1257 FreePool ((VOID *)TempStr);\r
a9090a94
AP
1258 return TRUE;\r
1259}\r
1260\r
1261XENSTORE_STATUS\r
1262XenStoreRead (\r
ac0a286f
MK
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
a9090a94
AP
1268 )\r
1269{\r
ac0a286f
MK
1270 CHAR8 *Path;\r
1271 VOID *Value;\r
1272 XENSTORE_STATUS Status;\r
a9090a94 1273\r
ac0a286f 1274 Path = XenStoreJoin (DirectoryPath, Node);\r
a9090a94
AP
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
ac0a286f
MK
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
a9090a94
AP
1291 )\r
1292{\r
ac0a286f
MK
1293 CHAR8 *Path;\r
1294 WRITE_REQUEST WriteRequest[2];\r
1295 XENSTORE_STATUS Status;\r
a9090a94
AP
1296\r
1297 Path = XenStoreJoin (DirectoryPath, Node);\r
1298\r
ac0a286f
MK
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
a9090a94
AP
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
ac0a286f
MK
1312 IN CONST XENSTORE_TRANSACTION *Transaction,\r
1313 IN CONST CHAR8 *DirectoryPath,\r
1314 IN CONST CHAR8 *Node\r
a9090a94
AP
1315 )\r
1316{\r
ac0a286f
MK
1317 CHAR8 *Path;\r
1318 XENSTORE_STATUS Status;\r
a9090a94 1319\r
ac0a286f 1320 Path = XenStoreJoin (DirectoryPath, Node);\r
a9090a94
AP
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
ac0a286f
MK
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
a9090a94 1342 if (Status == XENSTORE_STATUS_SUCCESS) {\r
017a4866 1343 Transaction->Id = (UINT32)AsciiStrDecimalToUintn (IdStr);\r
a9090a94
AP
1344 FreePool (IdStr);\r
1345 }\r
1346\r
1347 return Status;\r
1348}\r
1349\r
1350XENSTORE_STATUS\r
1351XenStoreTransactionEnd (\r
ac0a286f
MK
1352 IN CONST XENSTORE_TRANSACTION *Transaction,\r
1353 IN BOOLEAN Abort\r
a9090a94
AP
1354 )\r
1355{\r
ac0a286f 1356 CHAR8 AbortStr[2];\r
a9090a94 1357\r
02c6760c
LE
1358 AbortStr[0] = Abort ? 'F' : 'T';\r
1359 AbortStr[1] = '\0';\r
a9090a94
AP
1360\r
1361 return XenStoreSingle (Transaction, XS_TRANSACTION_END, AbortStr, NULL, NULL);\r
1362}\r
1363\r
1364XENSTORE_STATUS\r
c5c9e7e2 1365EFIAPI\r
a9090a94 1366XenStoreVSPrint (\r
ac0a286f
MK
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
a9090a94
AP
1372 )\r
1373{\r
ac0a286f
MK
1374 CHAR8 *Buf;\r
1375 XENSTORE_STATUS Status;\r
1376 UINTN BufSize;\r
1377 VA_LIST Marker2;\r
a9090a94 1378\r
1250f370
Z
1379 VA_COPY (Marker2, Marker);\r
1380 BufSize = SPrintLengthAsciiFormat (FormatString, Marker2) + 1;\r
1381 VA_END (Marker2);\r
a9090a94
AP
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
ac0a286f
MK
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
a9090a94
AP
1397 ...\r
1398 )\r
1399{\r
ac0a286f
MK
1400 VA_LIST Marker;\r
1401 XENSTORE_STATUS Status;\r
a9090a94
AP
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
ac0a286f
MK
1418 CHAR8 Token[sizeof (XENSTORE_WATCH) * 2 + 1];\r
1419 XENSTORE_STATUS Status;\r
1420 XENSTORE_WATCH *Watch;\r
a9090a94 1421\r
ac0a286f 1422 Watch = AllocateZeroPool (sizeof (XENSTORE_WATCH));\r
a9090a94 1423 Watch->Signature = XENSTORE_WATCH_SIGNATURE;\r
ac0a286f 1424 Watch->Node = XenStoreJoin (DirectoryPath, Node);\r
a9090a94
AP
1425\r
1426 EfiAcquireLock (&xs.RegisteredWatchesLock);\r
1427 InsertTailList (&xs.RegisteredWatches, &Watch->Link);\r
1428 EfiReleaseLock (&xs.RegisteredWatchesLock);\r
1429\r
ac0a286f 1430 AsciiSPrint (Token, sizeof (Token), "%p", (VOID *)Watch);\r
a9090a94
AP
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
ac0a286f 1453 IN XENSTORE_WATCH *Watch\r
a9090a94
AP
1454 )\r
1455{\r
ac0a286f
MK
1456 CHAR8 Token[sizeof (Watch) * 2 + 1];\r
1457 LIST_ENTRY *Entry;\r
a9090a94
AP
1458\r
1459 ASSERT (Watch->Signature == XENSTORE_WATCH_SIGNATURE);\r
1460\r
ac0a286f 1461 AsciiSPrint (Token, sizeof (Token), "%p", (VOID *)Watch);\r
a9090a94
AP
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
ac0a286f 1476 XENSTORE_MESSAGE *Message = XENSTORE_MESSAGE_FROM_LINK (Entry);\r
a9090a94
AP
1477 Entry = GetNextNode (&xs.WatchEvents, Entry);\r
1478 if (Message->u.Watch.Handle == Watch) {\r
1479 RemoveEntryList (&Message->Link);\r
ac0a286f 1480 FreePool ((VOID *)Message->u.Watch.Vector);\r
a9090a94
AP
1481 FreePool (Message);\r
1482 }\r
1483 }\r
ac0a286f 1484\r
a9090a94
AP
1485 EfiReleaseLock (&xs.WatchEventsLock);\r
1486\r
1487 FreePool (Watch->Node);\r
1488 FreePool (Watch);\r
1489}\r
c23c037f 1490\r
c23c037f
AP
1491//\r
1492// XENBUS protocol\r
1493//\r
1494\r
1495XENSTORE_STATUS\r
1496EFIAPI\r
1497XenBusWaitForWatch (\r
ac0a286f
MK
1498 IN XENBUS_PROTOCOL *This,\r
1499 IN VOID *Token\r
c23c037f
AP
1500 )\r
1501{\r
1502 return XenStoreWaitWatch (Token);\r
1503}\r
1504\r
1505XENSTORE_STATUS\r
1506EFIAPI\r
1507XenBusXenStoreRead (\r
ac0a286f
MK
1508 IN XENBUS_PROTOCOL *This,\r
1509 IN CONST XENSTORE_TRANSACTION *Transaction,\r
1510 IN CONST CHAR8 *Node,\r
1511 OUT VOID **Value\r
c23c037f
AP
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
ac0a286f
MK
1520 IN XENBUS_PROTOCOL *This,\r
1521 IN CONST XENSTORE_TRANSACTION *Transaction,\r
1522 IN CONST CHAR8 *Node,\r
1523 OUT VOID **Value\r
c23c037f
AP
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
ac0a286f
MK
1532 IN XENBUS_PROTOCOL *This,\r
1533 IN CONST XENSTORE_TRANSACTION *Transaction,\r
1534 IN const char *Node\r
c23c037f
AP
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
ac0a286f
MK
1553 IN XENBUS_PROTOCOL *This,\r
1554 IN CONST XENSTORE_TRANSACTION *Transaction,\r
1555 IN BOOLEAN Abort\r
c23c037f
AP
1556 )\r
1557{\r
1558 return XenStoreTransactionEnd (Transaction, Abort);\r
1559}\r
1560\r
1561XENSTORE_STATUS\r
1562EFIAPI\r
1563XenBusXenStoreSPrint (\r
ac0a286f
MK
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
c23c037f
AP
1569 ...\r
1570 )\r
1571{\r
ac0a286f
MK
1572 VA_LIST Marker;\r
1573 XENSTORE_STATUS Status;\r
c23c037f
AP
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
ac0a286f
MK
1585 IN XENBUS_PROTOCOL *This,\r
1586 IN CONST CHAR8 *Node,\r
1587 OUT VOID **Token\r
c23c037f
AP
1588 )\r
1589{\r
ac0a286f 1590 return XenStoreRegisterWatch (This->Node, Node, (XENSTORE_WATCH **)Token);\r
c23c037f
AP
1591}\r
1592\r
1593XENSTORE_STATUS\r
1594EFIAPI\r
1595XenBusRegisterWatchBackend (\r
ac0a286f
MK
1596 IN XENBUS_PROTOCOL *This,\r
1597 IN CONST CHAR8 *Node,\r
1598 OUT VOID **Token\r
c23c037f
AP
1599 )\r
1600{\r
ac0a286f 1601 return XenStoreRegisterWatch (This->Backend, Node, (XENSTORE_WATCH **)Token);\r
c23c037f
AP
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
ac0a286f 1611 XenStoreUnregisterWatch ((XENSTORE_WATCH *)Token);\r
c23c037f 1612}\r