Home | History | Annotate | Download | only in XenBusDxe
      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 (at) cam.ac.uk)
      8   Changes: Grzegorz Milos (gm281 (at) 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
     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
     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
     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
    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
    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
    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
    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
    215 XenBusGrantEndAccess (
    216   IN XENBUS_PROTOCOL  *This,
    217   IN grant_ref_t      Ref
    218   )
    219 {
    220   return XenGrantTableEndAccess (Ref);
    221 }
    222