1 /** @file
2   Grant Table function implementation.
3 
4   Grant Table are used to grant access to certain page of the current
5   VM to an other VM.
6 
7   Author: Steven Smith (sos22@cam.ac.uk)
8   Changes: Grzegorz Milos (gm281@cam.ac.uk)
9   Copyright (C) 2006, Cambridge University
10   Copyright (C) 2014, Citrix Ltd.
11 
12   Redistribution and use in source and binary forms, with or without
13   modification, are permitted provided that the following conditions
14   are met:
15   1. Redistributions of source code must retain the above copyright
16      notice, this list of conditions and the following disclaimer.
17   2. Redistributions in binary form must reproduce the above copyright
18      notice, this list of conditions and the following disclaimer in the
19      documentation and/or other materials provided with the distribution.
20 
21   THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24   ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
25   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31   SUCH DAMAGE.
32 **/
33 #include "XenBusDxe.h"
34 
35 #include <IndustryStandard/Xen/memory.h>
36 
37 #include <Library/XenHypercallLib.h>
38 #include <Library/SynchronizationLib.h>
39 
40 #include "GrantTable.h"
41 
42 #define NR_RESERVED_ENTRIES 8
43 
44 /* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */
45 #define NR_GRANT_FRAMES 4
46 #define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * EFI_PAGE_SIZE / sizeof(grant_entry_v1_t))
47 
48 STATIC grant_entry_v1_t *GrantTable = NULL;
49 STATIC grant_ref_t GrantList[NR_GRANT_ENTRIES];
50 STATIC EFI_LOCK mGrantListLock;
51 #ifdef GNT_DEBUG
52 STATIC BOOLEAN GrantInUseList[NR_GRANT_ENTRIES];
53 #endif
54 
55 STATIC
56 VOID
XenGrantTablePutFreeEntry(grant_ref_t Ref)57 XenGrantTablePutFreeEntry (
58   grant_ref_t Ref
59   )
60 {
61   EfiAcquireLock (&mGrantListLock);
62 #ifdef GNT_DEBUG
63   ASSERT (GrantInUseList[Ref]);
64   GrantInUseList[Ref] = FALSE;
65 #endif
66   GrantList[Ref] = GrantList[0];
67   GrantList[0] = Ref;
68   EfiReleaseLock (&mGrantListLock);
69 }
70 
71 STATIC
72 grant_ref_t
XenGrantTableGetFreeEntry(VOID)73 XenGrantTableGetFreeEntry (
74   VOID
75   )
76 {
77   grant_ref_t Ref;
78 
79   EfiAcquireLock (&mGrantListLock);
80   Ref = GrantList[0];
81   ASSERT (Ref >= NR_RESERVED_ENTRIES && Ref < NR_GRANT_ENTRIES);
82   GrantList[0] = GrantList[Ref];
83 #ifdef GNT_DEBUG
84   ASSERT (!GrantInUseList[Ref]);
85   GrantInUseList[Ref] = TRUE;
86 #endif
87   EfiReleaseLock (&mGrantListLock);
88   return Ref;
89 }
90 
91 STATIC
92 grant_ref_t
XenGrantTableGrantAccess(IN domid_t DomainId,IN UINTN Frame,IN BOOLEAN ReadOnly)93 XenGrantTableGrantAccess (
94   IN domid_t  DomainId,
95   IN UINTN    Frame,
96   IN BOOLEAN  ReadOnly
97   )
98 {
99   grant_ref_t Ref;
100   UINT16 Flags;
101 
102   ASSERT (GrantTable != NULL);
103   Ref = XenGrantTableGetFreeEntry ();
104   GrantTable[Ref].frame = (UINT32)Frame;
105   GrantTable[Ref].domid = DomainId;
106   MemoryFence ();
107   Flags = GTF_permit_access;
108   if (ReadOnly) {
109     Flags |= GTF_readonly;
110   }
111   GrantTable[Ref].flags = Flags;
112 
113   return Ref;
114 }
115 
116 STATIC
117 EFI_STATUS
XenGrantTableEndAccess(grant_ref_t Ref)118 XenGrantTableEndAccess (
119   grant_ref_t Ref
120   )
121 {
122   UINT16 Flags, OldFlags;
123 
124   ASSERT (GrantTable != NULL);
125   ASSERT (Ref >= NR_RESERVED_ENTRIES && Ref < NR_GRANT_ENTRIES);
126 
127   OldFlags = GrantTable[Ref].flags;
128   do {
129     if ((Flags = OldFlags) & (GTF_reading | GTF_writing)) {
130       DEBUG ((EFI_D_WARN, "WARNING: g.e. still in use! (%x)\n", Flags));
131       return EFI_NOT_READY;
132     }
133     OldFlags = InterlockedCompareExchange16 (&GrantTable[Ref].flags, Flags, 0);
134   } while (OldFlags != Flags);
135 
136   XenGrantTablePutFreeEntry (Ref);
137   return EFI_SUCCESS;
138 }
139 
140 VOID
XenGrantTableInit(IN XENBUS_DEVICE * Dev)141 XenGrantTableInit (
142   IN XENBUS_DEVICE  *Dev
143   )
144 {
145   xen_add_to_physmap_t Parameters;
146   INTN Index;
147   INTN ReturnCode;
148 
149 #ifdef GNT_DEBUG
150   SetMem(GrantInUseList, sizeof (GrantInUseList), 1);
151 #endif
152   EfiInitializeLock (&mGrantListLock, TPL_NOTIFY);
153   for (Index = NR_RESERVED_ENTRIES; Index < NR_GRANT_ENTRIES; Index++) {
154     XenGrantTablePutFreeEntry ((grant_ref_t)Index);
155   }
156 
157   GrantTable = (VOID*)(UINTN) Dev->XenIo->GrantTableAddress;
158   for (Index = 0; Index < NR_GRANT_FRAMES; Index++) {
159     Parameters.domid = DOMID_SELF;
160     Parameters.idx = Index;
161     Parameters.space = XENMAPSPACE_grant_table;
162     Parameters.gpfn = (xen_pfn_t) ((UINTN) GrantTable >> EFI_PAGE_SHIFT) + Index;
163     ReturnCode = XenHypercallMemoryOp (XENMEM_add_to_physmap, &Parameters);
164     if (ReturnCode != 0) {
165       DEBUG ((EFI_D_ERROR,
166         "Xen GrantTable, add_to_physmap hypercall error: %Ld\n",
167         (INT64)ReturnCode));
168     }
169   }
170 }
171 
172 VOID
XenGrantTableDeinit(XENBUS_DEVICE * Dev)173 XenGrantTableDeinit (
174   XENBUS_DEVICE *Dev
175   )
176 {
177   INTN ReturnCode, Index;
178   xen_remove_from_physmap_t Parameters;
179 
180   if (GrantTable == NULL) {
181     return;
182   }
183 
184   for (Index = NR_GRANT_FRAMES - 1; Index >= 0; Index--) {
185     Parameters.domid = DOMID_SELF;
186     Parameters.gpfn = (xen_pfn_t) ((UINTN) GrantTable >> EFI_PAGE_SHIFT) + Index;
187     DEBUG ((EFI_D_INFO, "Xen GrantTable, removing %Lx\n",
188       (UINT64)Parameters.gpfn));
189     ReturnCode = XenHypercallMemoryOp (XENMEM_remove_from_physmap, &Parameters);
190     if (ReturnCode != 0) {
191       DEBUG ((EFI_D_ERROR,
192         "Xen GrantTable, remove_from_physmap hypercall error: %Ld\n",
193         (INT64)ReturnCode));
194     }
195   }
196   GrantTable = NULL;
197 }
198 
199 EFI_STATUS
200 EFIAPI
XenBusGrantAccess(IN XENBUS_PROTOCOL * This,IN domid_t DomainId,IN UINTN Frame,IN BOOLEAN ReadOnly,OUT grant_ref_t * RefPtr)201 XenBusGrantAccess (
202   IN  XENBUS_PROTOCOL *This,
203   IN  domid_t         DomainId,
204   IN  UINTN           Frame, // MFN
205   IN  BOOLEAN         ReadOnly,
206   OUT grant_ref_t     *RefPtr
207   )
208 {
209   *RefPtr = XenGrantTableGrantAccess (DomainId, Frame, ReadOnly);
210   return EFI_SUCCESS;
211 }
212 
213 EFI_STATUS
214 EFIAPI
XenBusGrantEndAccess(IN XENBUS_PROTOCOL * This,IN grant_ref_t Ref)215 XenBusGrantEndAccess (
216   IN XENBUS_PROTOCOL  *This,
217   IN grant_ref_t      Ref
218   )
219 {
220   return XenGrantTableEndAccess (Ref);
221 }
222