| /** @file | |
| Grant Table function implementation. | |
| Grant Table are used to grant access to certain page of the current | |
| VM to an other VM. | |
| Author: Steven Smith (sos22@cam.ac.uk) | |
| Changes: Grzegorz Milos (gm281@cam.ac.uk) | |
| Copyright (C) 2006, Cambridge University | |
| Copyright (C) 2014, Citrix Ltd. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "XenBusDxe.h" | |
| #include <IndustryStandard/Xen/memory.h> | |
| #include <Library/XenHypercallLib.h> | |
| #include <Library/SynchronizationLib.h> | |
| #include "GrantTable.h" | |
| #define NR_RESERVED_ENTRIES 8 | |
| #define NR_GRANT_FRAMES (FixedPcdGet32 (PcdXenGrantFrames)) | |
| #define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * EFI_PAGE_SIZE / sizeof(grant_entry_v1_t)) | |
| STATIC grant_entry_v1_t *GrantTable = NULL; | |
| STATIC grant_ref_t GrantList[NR_GRANT_ENTRIES]; | |
| STATIC EFI_LOCK mGrantListLock; | |
| #ifdef GNT_DEBUG | |
| STATIC BOOLEAN GrantInUseList[NR_GRANT_ENTRIES]; | |
| #endif | |
| STATIC | |
| VOID | |
| XenGrantTablePutFreeEntry ( | |
| grant_ref_t Ref | |
| ) | |
| { | |
| EfiAcquireLock (&mGrantListLock); | |
| #ifdef GNT_DEBUG | |
| ASSERT (GrantInUseList[Ref]); | |
| GrantInUseList[Ref] = FALSE; | |
| #endif | |
| GrantList[Ref] = GrantList[0]; | |
| GrantList[0] = Ref; | |
| EfiReleaseLock (&mGrantListLock); | |
| } | |
| STATIC | |
| grant_ref_t | |
| XenGrantTableGetFreeEntry ( | |
| VOID | |
| ) | |
| { | |
| grant_ref_t Ref; | |
| EfiAcquireLock (&mGrantListLock); | |
| Ref = GrantList[0]; | |
| ASSERT (Ref >= NR_RESERVED_ENTRIES && Ref < NR_GRANT_ENTRIES); | |
| GrantList[0] = GrantList[Ref]; | |
| #ifdef GNT_DEBUG | |
| ASSERT (!GrantInUseList[Ref]); | |
| GrantInUseList[Ref] = TRUE; | |
| #endif | |
| EfiReleaseLock (&mGrantListLock); | |
| return Ref; | |
| } | |
| STATIC | |
| grant_ref_t | |
| XenGrantTableGrantAccess ( | |
| IN domid_t DomainId, | |
| IN UINTN Frame, | |
| IN BOOLEAN ReadOnly | |
| ) | |
| { | |
| grant_ref_t Ref; | |
| UINT16 Flags; | |
| ASSERT (GrantTable != NULL); | |
| Ref = XenGrantTableGetFreeEntry (); | |
| GrantTable[Ref].frame = (UINT32)Frame; | |
| GrantTable[Ref].domid = DomainId; | |
| MemoryFence (); | |
| Flags = GTF_permit_access; | |
| if (ReadOnly) { | |
| Flags |= GTF_readonly; | |
| } | |
| GrantTable[Ref].flags = Flags; | |
| return Ref; | |
| } | |
| STATIC | |
| EFI_STATUS | |
| XenGrantTableEndAccess ( | |
| grant_ref_t Ref | |
| ) | |
| { | |
| UINT16 Flags, OldFlags; | |
| ASSERT (GrantTable != NULL); | |
| ASSERT (Ref >= NR_RESERVED_ENTRIES && Ref < NR_GRANT_ENTRIES); | |
| OldFlags = GrantTable[Ref].flags; | |
| do { | |
| if ((Flags = OldFlags) & (GTF_reading | GTF_writing)) { | |
| DEBUG ((DEBUG_WARN, "WARNING: g.e. still in use! (%x)\n", Flags)); | |
| return EFI_NOT_READY; | |
| } | |
| OldFlags = InterlockedCompareExchange16 (&GrantTable[Ref].flags, Flags, 0); | |
| } while (OldFlags != Flags); | |
| XenGrantTablePutFreeEntry (Ref); | |
| return EFI_SUCCESS; | |
| } | |
| VOID | |
| XenGrantTableInit ( | |
| IN XENBUS_DEVICE *Dev | |
| ) | |
| { | |
| xen_add_to_physmap_t Parameters; | |
| INTN Index; | |
| INTN ReturnCode; | |
| #ifdef GNT_DEBUG | |
| SetMem (GrantInUseList, sizeof (GrantInUseList), 1); | |
| #endif | |
| EfiInitializeLock (&mGrantListLock, TPL_NOTIFY); | |
| for (Index = NR_RESERVED_ENTRIES; Index < NR_GRANT_ENTRIES; Index++) { | |
| XenGrantTablePutFreeEntry ((grant_ref_t)Index); | |
| } | |
| GrantTable = (VOID *)(UINTN)Dev->XenIo->GrantTableAddress; | |
| for (Index = 0; Index < NR_GRANT_FRAMES; Index++) { | |
| Parameters.domid = DOMID_SELF; | |
| Parameters.idx = Index; | |
| Parameters.space = XENMAPSPACE_grant_table; | |
| Parameters.gpfn = (xen_pfn_t)((UINTN)GrantTable >> EFI_PAGE_SHIFT) + Index; | |
| ReturnCode = XenHypercallMemoryOp (XENMEM_add_to_physmap, &Parameters); | |
| if (ReturnCode != 0) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "Xen GrantTable, add_to_physmap hypercall error: %Ld\n", | |
| (INT64)ReturnCode | |
| )); | |
| } | |
| } | |
| } | |
| VOID | |
| XenGrantTableDeinit ( | |
| XENBUS_DEVICE *Dev | |
| ) | |
| { | |
| INTN ReturnCode, Index; | |
| xen_remove_from_physmap_t Parameters; | |
| if (GrantTable == NULL) { | |
| return; | |
| } | |
| for (Index = NR_GRANT_FRAMES - 1; Index >= 0; Index--) { | |
| Parameters.domid = DOMID_SELF; | |
| Parameters.gpfn = (xen_pfn_t)((UINTN)GrantTable >> EFI_PAGE_SHIFT) + Index; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "Xen GrantTable, removing %Lx\n", | |
| (UINT64)Parameters.gpfn | |
| )); | |
| ReturnCode = XenHypercallMemoryOp (XENMEM_remove_from_physmap, &Parameters); | |
| if (ReturnCode != 0) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "Xen GrantTable, remove_from_physmap hypercall error: %Ld\n", | |
| (INT64)ReturnCode | |
| )); | |
| } | |
| } | |
| GrantTable = NULL; | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| XenBusGrantAccess ( | |
| IN XENBUS_PROTOCOL *This, | |
| IN domid_t DomainId, | |
| IN UINTN Frame, // MFN | |
| IN BOOLEAN ReadOnly, | |
| OUT grant_ref_t *RefPtr | |
| ) | |
| { | |
| *RefPtr = XenGrantTableGrantAccess (DomainId, Frame, ReadOnly); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| XenBusGrantEndAccess ( | |
| IN XENBUS_PROTOCOL *This, | |
| IN grant_ref_t Ref | |
| ) | |
| { | |
| return XenGrantTableEndAccess (Ref); | |
| } |