Home | History | Annotate | Download | only in VirtioMmioDeviceLib
      1 /** @file
      2 
      3   This driver produces Virtio Device Protocol instances for Virtio Mmio devices.
      4 
      5   Copyright (C) 2013, ARM Ltd.
      6 
      7   This program and the accompanying materials are licensed and made available
      8   under the terms and conditions of the BSD License which accompanies this
      9   distribution. The full text of the license may be found at
     10   http://opensource.org/licenses/bsd-license.php
     11 
     12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
     13   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include <Library/BaseMemoryLib.h>
     18 #include <Library/MemoryAllocationLib.h>
     19 #include <Library/UefiBootServicesTableLib.h>
     20 
     21 #include "VirtioMmioDevice.h"
     22 
     23 static VIRTIO_DEVICE_PROTOCOL mMmioDeviceProtocolTemplate = {
     24     0,                                     // Revision
     25     0,                                     // SubSystemDeviceId
     26     VirtioMmioGetDeviceFeatures,           // GetDeviceFeatures
     27     VirtioMmioSetGuestFeatures,            // SetGuestFeatures
     28     VirtioMmioGetQueueAddress,             // GetQueueAddress
     29     VirtioMmioSetQueueAddress,             // SetQueueAddress
     30     VirtioMmioSetQueueSel,                 // SetQueueSel
     31     VirtioMmioSetQueueNotify,              // SetQueueNotify
     32     VirtioMmioSetQueueAlignment,           // SetQueueAlign
     33     VirtioMmioSetPageSize,                 // SetPageSize
     34     VirtioMmioGetQueueSize,                // GetQueueNumMax
     35     VirtioMmioSetQueueSize,                // SetQueueNum
     36     VirtioMmioGetDeviceStatus,             // GetDeviceStatus
     37     VirtioMmioSetDeviceStatus,             // SetDeviceStatus
     38     VirtioMmioDeviceWrite,                 // WriteDevice
     39     VirtioMmioDeviceRead                   // ReadDevice
     40 };
     41 
     42 /**
     43 
     44   Initialize the VirtIo MMIO Device
     45 
     46   @param[in] BaseAddress   Base Address of the VirtIo MMIO Device
     47 
     48   @param[in, out] Device   The driver instance to configure.
     49 
     50   @retval EFI_SUCCESS      Setup complete.
     51 
     52   @retval EFI_UNSUPPORTED  The driver is not a VirtIo MMIO device.
     53 
     54 **/
     55 STATIC
     56 EFI_STATUS
     57 EFIAPI
     58 VirtioMmioInit (
     59   IN PHYSICAL_ADDRESS        BaseAddress,
     60   IN OUT VIRTIO_MMIO_DEVICE *Device
     61   )
     62 {
     63   UINT32     MagicValue;
     64   UINT32     VendorId;
     65   UINT32     Version;
     66 
     67   //
     68   // Initialize VirtIo Mmio Device
     69   //
     70   CopyMem (&Device->VirtioDevice, &mMmioDeviceProtocolTemplate,
     71         sizeof (VIRTIO_DEVICE_PROTOCOL));
     72   Device->BaseAddress = BaseAddress;
     73   Device->VirtioDevice.Revision = VIRTIO_SPEC_REVISION (0, 9, 5);
     74   Device->VirtioDevice.SubSystemDeviceId =
     75           MmioRead32 (BaseAddress + VIRTIO_MMIO_OFFSET_DEVICE_ID);
     76 
     77   //
     78   // Double-check MMIO-specific values
     79   //
     80   MagicValue = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_MAGIC);
     81   if (MagicValue != VIRTIO_MMIO_MAGIC) {
     82     return EFI_UNSUPPORTED;
     83   }
     84 
     85   Version = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_VERSION);
     86   if (Version != 1) {
     87     return EFI_UNSUPPORTED;
     88   }
     89 
     90   //
     91   // Double-check MMIO-specific values
     92   //
     93   VendorId = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_VENDOR_ID);
     94   if (VendorId != VIRTIO_VENDOR_ID) {
     95     //
     96     // The ARM Base and Foundation Models do not report a valid VirtIo VendorId.
     97     // They return a value of 0x0 for the VendorId.
     98     //
     99     DEBUG((EFI_D_WARN, "VirtioMmioInit: Warning: The VendorId (0x%X) does not "
    100                        "match the VirtIo VendorId (0x%X).\n",
    101                        VendorId, VIRTIO_VENDOR_ID));
    102   }
    103 
    104   return EFI_SUCCESS;
    105 }
    106 
    107 
    108 /**
    109 
    110   Uninitialize the internals of a virtio-mmio device that has been successfully
    111   set up with VirtioMmioInit().
    112 
    113   @param[in, out]  Device  The device to clean up.
    114 
    115 **/
    116 
    117 STATIC
    118 VOID
    119 EFIAPI
    120 VirtioMmioUninit (
    121   IN VIRTIO_MMIO_DEVICE *Device
    122   )
    123 {
    124   //
    125   // Note: This function mirrors VirtioMmioInit() that does not allocate any
    126   //       resources - there's nothing to free here.
    127   //
    128 }
    129 
    130 EFI_STATUS
    131 VirtioMmioInstallDevice (
    132   IN PHYSICAL_ADDRESS       BaseAddress,
    133   IN EFI_HANDLE             Handle
    134   )
    135 {
    136   EFI_STATUS          Status;
    137   VIRTIO_MMIO_DEVICE *VirtIo;
    138 
    139   if (!BaseAddress) {
    140     return EFI_INVALID_PARAMETER;
    141   }
    142   if (Handle == NULL) {
    143     return EFI_INVALID_PARAMETER;
    144   }
    145 
    146   //
    147   // Allocate VIRTIO_MMIO_DEVICE
    148   //
    149   VirtIo = AllocateZeroPool (sizeof (VIRTIO_MMIO_DEVICE));
    150   if (VirtIo == NULL) {
    151     return EFI_OUT_OF_RESOURCES;
    152   }
    153 
    154   VirtIo->Signature = VIRTIO_MMIO_DEVICE_SIGNATURE;
    155 
    156   Status = VirtioMmioInit (BaseAddress, VirtIo);
    157   if (EFI_ERROR (Status)) {
    158     goto FreeVirtioMem;
    159   }
    160 
    161   //
    162   // Install VIRTIO_DEVICE_PROTOCOL to Handle
    163   //
    164   Status = gBS->InstallProtocolInterface (&Handle,
    165                   &gVirtioDeviceProtocolGuid, EFI_NATIVE_INTERFACE,
    166                   &VirtIo->VirtioDevice);
    167   if (EFI_ERROR (Status)) {
    168     goto UninitVirtio;
    169   }
    170 
    171   return EFI_SUCCESS;
    172 
    173 UninitVirtio:
    174   VirtioMmioUninit (VirtIo);
    175 
    176 FreeVirtioMem:
    177   FreePool (VirtIo);
    178   return Status;
    179 }
    180 
    181 EFI_STATUS
    182 VirtioMmioUninstallDevice (
    183   IN EFI_HANDLE             DeviceHandle
    184   )
    185 {
    186   VIRTIO_DEVICE_PROTOCOL  *VirtioDevice;
    187   VIRTIO_MMIO_DEVICE      *MmioDevice;
    188   EFI_STATUS              Status;
    189 
    190   Status = gBS->OpenProtocol (
    191                   DeviceHandle,                  // candidate device
    192                   &gVirtioDeviceProtocolGuid,    // retrieve the VirtIo iface
    193                   (VOID **)&VirtioDevice,        // target pointer
    194                   DeviceHandle,                  // requestor driver identity
    195                   DeviceHandle,                  // requesting lookup for dev.
    196                   EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no ref. added
    197                   );
    198   if (EFI_ERROR (Status)) {
    199     return Status;
    200   }
    201 
    202   //
    203   // Get the MMIO device from the VirtIo Device instance
    204   //
    205   MmioDevice = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (VirtioDevice);
    206 
    207   //
    208   // Uninstall the protocol interface
    209   //
    210   Status = gBS->UninstallProtocolInterface (DeviceHandle,
    211       &gVirtioDeviceProtocolGuid, &MmioDevice->VirtioDevice
    212       );
    213   if (EFI_ERROR (Status)) {
    214     return Status;
    215   }
    216 
    217   //
    218   // Uninitialize the VirtIo Device
    219   //
    220   VirtioMmioUninit (MmioDevice);
    221   FreePool (MmioDevice);
    222 
    223   return EFI_SUCCESS;
    224 }
    225