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