• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
3 
4   This program and the accompanying materials
5   are licensed and made available under the terms and conditions of the BSD License
6   which accompanies this distribution.  The full text of the license may be found at
7   http://opensource.org/licenses/bsd-license.php
8 
9   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 **/
13 
14 #include <PiDxe.h>
15 
16 #include <Guid/NonDiscoverableDevice.h>
17 
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/DevicePathLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/NonDiscoverableDeviceRegistrationLib.h>
23 #include <Library/UefiBootServicesTableLib.h>
24 
25 #include <Protocol/DevicePath.h>
26 #include <Protocol/NonDiscoverableDevice.h>
27 
28 /**
29   Get Guid form the type of non-discoverable device.
30 
31   @param[in]  Type    The type of non-discoverable device.
32 
33   @retval   Return the Guid.
34 
35 **/
36 STATIC
37 CONST EFI_GUID *
GetGuidFromType(IN NON_DISCOVERABLE_DEVICE_TYPE Type)38 GetGuidFromType (
39   IN  NON_DISCOVERABLE_DEVICE_TYPE  Type
40   )
41 {
42   switch (Type) {
43   case NonDiscoverableDeviceTypeAhci:
44     return &gEdkiiNonDiscoverableAhciDeviceGuid;
45 
46   case NonDiscoverableDeviceTypeAmba:
47     return &gEdkiiNonDiscoverableAmbaDeviceGuid;
48 
49   case NonDiscoverableDeviceTypeEhci:
50     return &gEdkiiNonDiscoverableEhciDeviceGuid;
51 
52   case NonDiscoverableDeviceTypeNvme:
53     return &gEdkiiNonDiscoverableNvmeDeviceGuid;
54 
55   case NonDiscoverableDeviceTypeOhci:
56     return &gEdkiiNonDiscoverableOhciDeviceGuid;
57 
58   case NonDiscoverableDeviceTypeSdhci:
59     return &gEdkiiNonDiscoverableSdhciDeviceGuid;
60 
61   case NonDiscoverableDeviceTypeUfs:
62     return &gEdkiiNonDiscoverableUfsDeviceGuid;
63 
64   case NonDiscoverableDeviceTypeUhci:
65     return &gEdkiiNonDiscoverableUhciDeviceGuid;
66 
67   case NonDiscoverableDeviceTypeXhci:
68     return &gEdkiiNonDiscoverableXhciDeviceGuid;
69 
70   default:
71     return NULL;
72   }
73 }
74 
75 #pragma pack (1)
76 typedef struct {
77   VENDOR_DEVICE_PATH                  Vendor;
78   UINT64                              BaseAddress;
79   UINT8                               ResourceType;
80   EFI_DEVICE_PATH_PROTOCOL            End;
81 } NON_DISCOVERABLE_DEVICE_PATH;
82 #pragma pack ()
83 
84 /**
85   Register a non-discoverable MMIO device.
86 
87   @param[in]      Type                The type of non-discoverable device
88   @param[in]      DmaType             Whether the device is DMA coherent
89   @param[in]      InitFunc            Initialization routine to be invoked when
90                                       the device is enabled
91   @param[in,out]  Handle              The handle onto which to install the
92                                       non-discoverable device protocol.
93                                       If Handle is NULL or *Handle is NULL, a
94                                       new handle will be allocated.
95   @param[in]      NumMmioResources    The number of UINTN base/size pairs that
96                                       follow, each describing an MMIO region
97                                       owned by the device
98   @param[in]  ...                     The variable argument list which contains the
99                                       info about MmioResources.
100 
101   @retval EFI_SUCCESS                 The registration succeeded.
102   @retval EFI_INVALID_PARAMETER       An invalid argument was given
103   @retval Other                       The registration failed.
104 
105 **/
106 EFI_STATUS
107 EFIAPI
RegisterNonDiscoverableMmioDevice(IN NON_DISCOVERABLE_DEVICE_TYPE Type,IN NON_DISCOVERABLE_DEVICE_DMA_TYPE DmaType,IN NON_DISCOVERABLE_DEVICE_INIT InitFunc,IN OUT EFI_HANDLE * Handle OPTIONAL,IN UINTN NumMmioResources,...)108 RegisterNonDiscoverableMmioDevice (
109   IN      NON_DISCOVERABLE_DEVICE_TYPE      Type,
110   IN      NON_DISCOVERABLE_DEVICE_DMA_TYPE  DmaType,
111   IN      NON_DISCOVERABLE_DEVICE_INIT      InitFunc,
112   IN OUT  EFI_HANDLE                        *Handle OPTIONAL,
113   IN      UINTN                             NumMmioResources,
114   ...
115   )
116 {
117   NON_DISCOVERABLE_DEVICE             *Device;
118   NON_DISCOVERABLE_DEVICE_PATH        *DevicePath;
119   EFI_HANDLE                          LocalHandle;
120   EFI_STATUS                          Status;
121   UINTN                               AllocSize;
122   UINTN                               Index;
123   VA_LIST                             Args;
124   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
125   EFI_ACPI_END_TAG_DESCRIPTOR         *End;
126   UINTN                               Base, Size;
127 
128   if (Type >= NonDiscoverableDeviceTypeMax ||
129       DmaType >= NonDiscoverableDeviceDmaTypeMax ||
130       NumMmioResources == 0) {
131     return EFI_INVALID_PARAMETER;
132   }
133 
134   if (Handle == NULL) {
135     Handle = &LocalHandle;
136     LocalHandle = NULL;
137   }
138 
139   AllocSize = sizeof *Device +
140               NumMmioResources * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +
141               sizeof (EFI_ACPI_END_TAG_DESCRIPTOR);
142   Device = (NON_DISCOVERABLE_DEVICE *)AllocateZeroPool (AllocSize);
143   if (Device == NULL) {
144     return EFI_OUT_OF_RESOURCES;
145   }
146 
147   Device->Type = GetGuidFromType (Type);
148   ASSERT (Device->Type != NULL);
149 
150   Device->DmaType = DmaType;
151   Device->Initialize = InitFunc;
152   Device->Resources = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(Device + 1);
153 
154   VA_START (Args, NumMmioResources);
155   for (Index = 0; Index < NumMmioResources; Index++) {
156     Desc = &Device->Resources [Index];
157     Base = VA_ARG (Args, UINTN);
158     Size = VA_ARG (Args, UINTN);
159 
160     Desc->Desc                  = ACPI_ADDRESS_SPACE_DESCRIPTOR;
161     Desc->Len                   = sizeof *Desc - 3;
162     Desc->AddrRangeMin          = Base;
163     Desc->AddrLen               = Size;
164     Desc->AddrRangeMax          = Base + Size - 1;
165     Desc->ResType               = ACPI_ADDRESS_SPACE_TYPE_MEM;
166     Desc->AddrSpaceGranularity  = (Base + Size > SIZE_4GB) ? 64 : 32;
167     Desc->AddrTranslationOffset = 0;
168   }
169   VA_END (Args);
170 
171   End = (EFI_ACPI_END_TAG_DESCRIPTOR *)&Device->Resources [NumMmioResources];
172 
173   End->Desc     = ACPI_END_TAG_DESCRIPTOR;
174   End->Checksum = 0;
175 
176   DevicePath = (NON_DISCOVERABLE_DEVICE_PATH *)CreateDeviceNode (
177                                                  HARDWARE_DEVICE_PATH,
178                                                  HW_VENDOR_DP,
179                                                  sizeof (*DevicePath));
180   if (DevicePath == NULL) {
181     Status = EFI_OUT_OF_RESOURCES;
182     goto FreeDevice;
183   }
184 
185   CopyGuid (&DevicePath->Vendor.Guid, &gEdkiiNonDiscoverableDeviceProtocolGuid);
186 
187   //
188   // Use the base address and type of the first region to
189   // make the device path unique
190   //
191   DevicePath->BaseAddress = Device->Resources [0].AddrRangeMin;
192   DevicePath->ResourceType = Device->Resources [0].ResType;
193 
194   SetDevicePathNodeLength (&DevicePath->Vendor,
195     sizeof (*DevicePath) - sizeof (DevicePath->End));
196   SetDevicePathEndNode (&DevicePath->End);
197 
198   Status = gBS->InstallMultipleProtocolInterfaces (Handle,
199                   &gEdkiiNonDiscoverableDeviceProtocolGuid, Device,
200                   &gEfiDevicePathProtocolGuid, DevicePath,
201                   NULL);
202   if (EFI_ERROR (Status)) {
203     goto FreeDevicePath;
204   }
205   return EFI_SUCCESS;
206 
207 FreeDevicePath:
208   FreePool (DevicePath);
209 
210 FreeDevice:
211   FreePool (Device);
212 
213   return Status;
214 }
215