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     VirtioMmioSetQueueAddress,             // SetQueueAddress
     29     VirtioMmioSetQueueSel,                 // SetQueueSel
     30     VirtioMmioSetQueueNotify,              // SetQueueNotify
     31     VirtioMmioSetQueueAlignment,           // SetQueueAlign
     32     VirtioMmioSetPageSize,                 // SetPageSize
     33     VirtioMmioGetQueueSize,                // GetQueueNumMax
     34     VirtioMmioSetQueueSize,                // SetQueueNum
     35     VirtioMmioGetDeviceStatus,             // GetDeviceStatus
     36     VirtioMmioSetDeviceStatus,             // SetDeviceStatus
     37     VirtioMmioDeviceWrite,                 // WriteDevice
     38     VirtioMmioDeviceRead                   // ReadDevice
     39 };
     40 
     41 /**
     42 
     43   Initialize the VirtIo MMIO Device
     44 
     45   @param[in] BaseAddress   Base Address of the VirtIo MMIO Device
     46 
     47   @param[in, out] Device   The driver instance to configure.
     48 
     49   @retval EFI_SUCCESS      Setup complete.
     50 
     51   @retval EFI_UNSUPPORTED  The driver is not a VirtIo MMIO device.
     52 
     53 **/
     54 STATIC
     55 EFI_STATUS
     56 EFIAPI
     57 VirtioMmioInit (
     58   IN PHYSICAL_ADDRESS        BaseAddress,
     59   IN OUT VIRTIO_MMIO_DEVICE *Device
     60   )
     61 {
     62   UINT32     MagicValue;
     63   UINT32     VendorId;
     64   UINT32     Version;
     65 
     66   //
     67   // Initialize VirtIo Mmio Device
     68   //
     69   CopyMem (&Device->VirtioDevice, &mMmioDeviceProtocolTemplate,
     70         sizeof (VIRTIO_DEVICE_PROTOCOL));
     71   Device->BaseAddress = BaseAddress;
     72   Device->VirtioDevice.Revision = VIRTIO_SPEC_REVISION (0, 9, 5);
     73   Device->VirtioDevice.SubSystemDeviceId =
     74           MmioRead32 (BaseAddress + VIRTIO_MMIO_OFFSET_DEVICE_ID);
     75 
     76   //
     77   // Double-check MMIO-specific values
     78   //
     79   MagicValue = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_MAGIC);
     80   if (MagicValue != VIRTIO_MMIO_MAGIC) {
     81     return EFI_UNSUPPORTED;
     82   }
     83 
     84   Version = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_VERSION);
     85   if (Version != 1) {
     86     return EFI_UNSUPPORTED;
     87   }
     88 
     89   //
     90   // Double-check MMIO-specific values
     91   //
     92   VendorId = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_VENDOR_ID);
     93   if (VendorId != VIRTIO_VENDOR_ID) {
     94     //
     95     // The ARM Base and Foundation Models do not report a valid VirtIo VendorId.
     96     // They return a value of 0x0 for the VendorId.
     97     //
     98     DEBUG((EFI_D_WARN, "VirtioMmioInit: Warning: The VendorId (0x%X) does not "
     99                        "match the VirtIo VendorId (0x%X).\n",
    100                        VendorId, VIRTIO_VENDOR_ID));
    101   }
    102 
    103   return EFI_SUCCESS;
    104 }
    105 
    106 
    107 /**
    108 
    109   Uninitialize the internals of a virtio-mmio device that has been successfully
    110   set up with VirtioMmioInit().
    111 
    112   @param[in, out]  Device  The device to clean up.
    113 
    114 **/
    115 
    116 STATIC
    117 VOID
    118 EFIAPI
    119 VirtioMmioUninit (
    120   IN VIRTIO_MMIO_DEVICE *Device
    121   )
    122 {
    123   //
    124   // Note: This function mirrors VirtioMmioInit() that does not allocate any
    125   //       resources - there's nothing to free here.
    126   //
    127 }
    128 
    129 EFI_STATUS
    130 VirtioMmioInstallDevice (
    131   IN PHYSICAL_ADDRESS       BaseAddress,
    132   IN EFI_HANDLE             Handle
    133   )
    134 {
    135   EFI_STATUS          Status;
    136   VIRTIO_MMIO_DEVICE *VirtIo;
    137 
    138   if (!BaseAddress) {
    139     return EFI_INVALID_PARAMETER;
    140   }
    141   if (Handle == NULL) {
    142     return EFI_INVALID_PARAMETER;
    143   }
    144 
    145   //
    146   // Allocate VIRTIO_MMIO_DEVICE
    147   //
    148   VirtIo = AllocateZeroPool (sizeof (VIRTIO_MMIO_DEVICE));
    149   if (VirtIo == NULL) {
    150     return EFI_OUT_OF_RESOURCES;
    151   }
    152 
    153   VirtIo->Signature = VIRTIO_MMIO_DEVICE_SIGNATURE;
    154 
    155   Status = VirtioMmioInit (BaseAddress, VirtIo);
    156   if (EFI_ERROR (Status)) {
    157     goto FreeVirtioMem;
    158   }
    159 
    160   //
    161   // Install VIRTIO_DEVICE_PROTOCOL to Handle
    162   //
    163   Status = gBS->InstallProtocolInterface (&Handle,
    164                   &gVirtioDeviceProtocolGuid, EFI_NATIVE_INTERFACE,
    165                   &VirtIo->VirtioDevice);
    166   if (EFI_ERROR (Status)) {
    167     goto UninitVirtio;
    168   }
    169 
    170   return EFI_SUCCESS;
    171 
    172 UninitVirtio:
    173   VirtioMmioUninit (VirtIo);
    174 
    175 FreeVirtioMem:
    176   FreePool (VirtIo);
    177   return Status;
    178 }
    179 
    180 EFI_STATUS
    181 VirtioMmioUninstallDevice (
    182   IN EFI_HANDLE             DeviceHandle
    183   )
    184 {
    185   VIRTIO_DEVICE_PROTOCOL  *VirtioDevice;
    186   VIRTIO_MMIO_DEVICE      *MmioDevice;
    187   EFI_STATUS              Status;
    188 
    189   Status = gBS->OpenProtocol (
    190                   DeviceHandle,                  // candidate device
    191                   &gVirtioDeviceProtocolGuid,    // retrieve the VirtIo iface
    192                   (VOID **)&VirtioDevice,        // target pointer
    193                   DeviceHandle,                  // requestor driver identity
    194                   DeviceHandle,                  // requesting lookup for dev.
    195                   EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no ref. added
    196                   );
    197   if (EFI_ERROR (Status)) {
    198     return Status;
    199   }
    200 
    201   //
    202   // Get the MMIO device from the VirtIo Device instance
    203   //
    204   MmioDevice = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (VirtioDevice);
    205 
    206   //
    207   // Uninstall the protocol interface
    208   //
    209   Status = gBS->UninstallProtocolInterface (DeviceHandle,
    210       &gVirtioDeviceProtocolGuid, &MmioDevice->VirtioDevice
    211       );
    212   if (EFI_ERROR (Status)) {
    213     return Status;
    214   }
    215 
    216   //
    217   // Uninitialize the VirtIo Device
    218   //
    219   VirtioMmioUninit (MmioDevice);
    220   FreePool (MmioDevice);
    221 
    222   return EFI_SUCCESS;
    223 }
    224