diff --git a/OvmfPkg/XenBusDxe/GrantTable.c b/OvmfPkg/XenBusDxe/GrantTable.c new file mode 100644 index 0000000000..b17fef3605 --- /dev/null +++ b/OvmfPkg/XenBusDxe/GrantTable.c @@ -0,0 +1,217 @@ +/** @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. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. +**/ +#include "XenBusDxe.h" + +#include + +#include "XenHypercall.h" + +#include "GrantTable.h" +#include "InterlockedCompareExchange16.h" + +#define NR_RESERVED_ENTRIES 8 + +/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */ +#define NR_GRANT_FRAMES 4 +#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 + ) +{ + UINTN 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; + UINT32 Flags; + + ASSERT (GrantTable != NULL); + Ref = XenGrantTableGetFreeEntry (); + GrantTable[Ref].frame = 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 ((EFI_D_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, + IN UINT64 MmioAddr + ) +{ + 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 (Index); + } + + GrantTable = (VOID*)(UINTN) MmioAddr; + 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) GrantTable) >> EFI_PAGE_SHIFT) + Index; + ReturnCode = XenHypercallMemoryOp (Dev, XENMEM_add_to_physmap, &Parameters); + if (ReturnCode != 0) { + DEBUG ((EFI_D_ERROR, "Xen GrantTable, add_to_physmap hypercall error: %d\n", 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) GrantTable) >> EFI_PAGE_SHIFT) + Index; + DEBUG ((EFI_D_INFO, "Xen GrantTable, removing %X\n", Parameters.gpfn)); + ReturnCode = XenHypercallMemoryOp (Dev, XENMEM_remove_from_physmap, &Parameters); + if (ReturnCode != 0) { + DEBUG ((EFI_D_ERROR, "Xen GrantTable, remove_from_physmap hypercall error: %d\n", 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); +} diff --git a/OvmfPkg/XenBusDxe/GrantTable.h b/OvmfPkg/XenBusDxe/GrantTable.h new file mode 100644 index 0000000000..5772c56662 --- /dev/null +++ b/OvmfPkg/XenBusDxe/GrantTable.h @@ -0,0 +1,77 @@ +/** @file + Grant Table function declaration. + + Grant Table are used to grant access to certain page of the current + VM to an other VM. + + Copyright (C) 2014, Citrix Ltd. + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#ifndef __GNTTAB_H__ +#define __GNTTAB_H__ + +#include + +/** + Initialize the Grant Table at the address MmioAddr. + + @param Dev A pointer to XENBUS_DEVICE. + @param MmioAddr An address where the grant table can be mapped into + the guest. +**/ +VOID +XenGrantTableInit ( + IN XENBUS_DEVICE *Dev, + IN UINT64 MmioAddr + ); + +/** + Desinitilize the Grant Table. +**/ +VOID +XenGrantTableDeinit ( + IN XENBUS_DEVICE *Dev + ); + +/** + Grant access to the page Frame to the domain DomainId. + + @param This A pointer to XENBUS_PROTOCOL instance. + @param DomainId ID of the domain to grant acces to. + @param Frame Frame Number of the page to grant access to. + @param ReadOnly Provide read-only or read-write access. + @param RefPtr Reference number of the grant will be writen to this pointer. +**/ +EFI_STATUS +EFIAPI +XenBusGrantAccess ( + IN XENBUS_PROTOCOL *This, + IN domid_t DomainId, + IN UINTN Frame, // MFN + IN BOOLEAN ReadOnly, + OUT grant_ref_t *RefPtr + ); + +/** + End access to grant Ref, previously return by XenBusGrantAccess. + + @param This A pointer to XENBUS_PROTOCOL instance. + @param Ref Reference numeber of a grant previously returned by + XenBusGrantAccess. +**/ +EFI_STATUS +EFIAPI +XenBusGrantEndAccess ( + IN XENBUS_PROTOCOL *This, + IN grant_ref_t Ref + ); + +#endif /* !__GNTTAB_H__ */ diff --git a/OvmfPkg/XenBusDxe/XenBusDxe.c b/OvmfPkg/XenBusDxe/XenBusDxe.c index 776d896368..edeb20ef38 100644 --- a/OvmfPkg/XenBusDxe/XenBusDxe.c +++ b/OvmfPkg/XenBusDxe/XenBusDxe.c @@ -30,6 +30,7 @@ #include "XenBusDxe.h" #include "XenHypercall.h" +#include "GrantTable.h" /// @@ -282,6 +283,8 @@ XenBusDxeDriverBindingStart ( EFI_STATUS Status; XENBUS_DEVICE *Dev; EFI_PCI_IO_PROTOCOL *PciIo; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc; + UINT64 MmioAddr; Status = gBS->OpenProtocol ( ControllerHandle, @@ -313,6 +316,20 @@ XenBusDxeDriverBindingStart ( mMyDevice = Dev; EfiReleaseLock (&mMyDeviceLock); + // + // The BAR1 of this PCI device is used for shared memory and is supposed to + // look like MMIO. The address space of the BAR1 will be used to map the + // Grant Table. + // + Status = PciIo->GetBarAttributes (PciIo, PCI_BAR_IDX1, NULL, (VOID**) &BarDesc); + ASSERT_EFI_ERROR (Status); + ASSERT (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM); + + /* Get a Memory address for mapping the Grant Table. */ + DEBUG ((EFI_D_INFO, "XenBus: BAR at %LX\n", BarDesc->AddrRangeMin)); + MmioAddr = BarDesc->AddrRangeMin; + FreePool (BarDesc); + Status = XenHyperpageInit (Dev); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "XenBus: Unable to retrieve the hyperpage.\n")); @@ -327,6 +344,8 @@ XenBusDxeDriverBindingStart ( goto ErrorAllocated; } + XenGrantTableInit (Dev, MmioAddr); + Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK, NotifyExitBoot, (VOID*) Dev, @@ -380,6 +399,7 @@ XenBusDxeDriverBindingStop ( XENBUS_DEVICE *Dev = mMyDevice; gBS->CloseEvent (Dev->ExitBootEvent); + XenGrantTableDeinit (Dev); gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, ControllerHandle); diff --git a/OvmfPkg/XenBusDxe/XenBusDxe.inf b/OvmfPkg/XenBusDxe/XenBusDxe.inf index 4e92a204f2..080e55a9bb 100644 --- a/OvmfPkg/XenBusDxe/XenBusDxe.inf +++ b/OvmfPkg/XenBusDxe/XenBusDxe.inf @@ -38,6 +38,8 @@ XenHypercall.h InterlockedCompareExchange16.c InterlockedCompareExchange16.h + GrantTable.c + GrantTable.h [Sources.IA32] Ia32/hypercall.S