1 /** @file
2 
3   Copyright (C) 2016, Linaro Ltd. All rights reserved.<BR>
4 
5   This program and the accompanying materials are licensed and made available
6   under the terms and conditions of the BSD License which accompanies this
7   distribution. The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
11   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "NonDiscoverablePciDeviceIo.h"
16 
17 #include <Protocol/DriverBinding.h>
18 
19 EFI_CPU_ARCH_PROTOCOL      *mCpu;
20 
21 //
22 // We only support the following device types
23 //
24 STATIC
25 CONST EFI_GUID * CONST
26 SupportedNonDiscoverableDevices[] = {
27   &gEdkiiNonDiscoverableAhciDeviceGuid,
28   &gEdkiiNonDiscoverableEhciDeviceGuid,
29   &gEdkiiNonDiscoverableNvmeDeviceGuid,
30   &gEdkiiNonDiscoverableOhciDeviceGuid,
31   &gEdkiiNonDiscoverableSdhciDeviceGuid,
32   &gEdkiiNonDiscoverableUfsDeviceGuid,
33   &gEdkiiNonDiscoverableUhciDeviceGuid,
34   &gEdkiiNonDiscoverableXhciDeviceGuid,
35 };
36 
37 //
38 // Probe, start and stop functions of this driver, called by the DXE core for
39 // specific devices.
40 //
41 // The following specifications document these interfaces:
42 // - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
43 // - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
44 //
45 // The implementation follows:
46 // - Driver Writer's Guide for UEFI 2.3.1 v1.01
47 //   - 5.1.3.4 OpenProtocol() and CloseProtocol()
48 // - UEFI Spec 2.3.1 + Errata C
49 //   -  6.3 Protocol Handler Services
50 //
51 
52 /**
53   Supported function of Driver Binding protocol for this driver.
54   Test to see if this driver supports ControllerHandle.
55 
56   @param This                   Protocol instance pointer.
57   @param DeviceHandle           Handle of device to test.
58   @param RemainingDevicePath    A pointer to the device path.
59                                 it should be ignored by device driver.
60 
61   @retval EFI_SUCCESS           This driver supports this device.
62   @retval other                 This driver does not support this device.
63 
64 **/
65 STATIC
66 EFI_STATUS
67 EFIAPI
NonDiscoverablePciDeviceSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)68 NonDiscoverablePciDeviceSupported (
69   IN EFI_DRIVER_BINDING_PROTOCOL *This,
70   IN EFI_HANDLE                  DeviceHandle,
71   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
72   )
73 {
74   NON_DISCOVERABLE_DEVICE             *Device;
75   EFI_STATUS                          Status;
76   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
77   INTN                                Idx;
78 
79   Status = gBS->OpenProtocol (DeviceHandle,
80                   &gEdkiiNonDiscoverableDeviceProtocolGuid, (VOID **)&Device,
81                   This->DriverBindingHandle, DeviceHandle,
82                   EFI_OPEN_PROTOCOL_BY_DRIVER);
83   if (EFI_ERROR (Status)) {
84     return Status;
85   }
86 
87   Status = EFI_UNSUPPORTED;
88   for (Idx = 0; Idx < ARRAY_SIZE (SupportedNonDiscoverableDevices); Idx++) {
89     if (CompareGuid (Device->Type, SupportedNonDiscoverableDevices [Idx])) {
90       Status = EFI_SUCCESS;
91       break;
92     }
93   }
94 
95   if (EFI_ERROR (Status)) {
96     goto CloseProtocol;
97   }
98 
99   //
100   // We only support MMIO devices, so iterate over the resources to ensure
101   // that they only describe things that we can handle
102   //
103   for (Desc = Device->Resources; Desc->Desc != ACPI_END_TAG_DESCRIPTOR;
104        Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {
105     if (Desc->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR ||
106         Desc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {
107       Status = EFI_UNSUPPORTED;
108       break;
109     }
110   }
111 
112 CloseProtocol:
113   gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,
114          This->DriverBindingHandle, DeviceHandle);
115 
116   return Status;
117 }
118 
119 /**
120   This routine is called right after the .Supported() called and
121   Start this driver on ControllerHandle.
122 
123   @param This                   Protocol instance pointer.
124   @param DeviceHandle           Handle of device to bind driver to.
125   @param RemainingDevicePath    A pointer to the device path.
126                                 it should be ignored by device driver.
127 
128   @retval EFI_SUCCESS           This driver is added to this device.
129   @retval other                 Some error occurs when binding this driver to this device.
130 
131 **/
132 STATIC
133 EFI_STATUS
134 EFIAPI
NonDiscoverablePciDeviceStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)135 NonDiscoverablePciDeviceStart (
136   IN EFI_DRIVER_BINDING_PROTOCOL *This,
137   IN EFI_HANDLE                  DeviceHandle,
138   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
139   )
140 {
141   NON_DISCOVERABLE_PCI_DEVICE   *Dev;
142   EFI_STATUS                    Status;
143 
144   Dev = AllocateZeroPool (sizeof *Dev);
145   if (Dev == NULL) {
146     return EFI_OUT_OF_RESOURCES;
147   }
148 
149   Status = gBS->OpenProtocol (DeviceHandle,
150                   &gEdkiiNonDiscoverableDeviceProtocolGuid,
151                   (VOID **)&Dev->Device, This->DriverBindingHandle,
152                   DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
153   if (EFI_ERROR (Status)) {
154     goto FreeDev;
155   }
156 
157   InitializePciIoProtocol (Dev);
158 
159   //
160   // Setup complete, attempt to export the driver instance's
161   // EFI_PCI_IO_PROTOCOL interface.
162   //
163   Dev->Signature = NON_DISCOVERABLE_PCI_DEVICE_SIG;
164   Status = gBS->InstallProtocolInterface (&DeviceHandle, &gEfiPciIoProtocolGuid,
165                   EFI_NATIVE_INTERFACE, &Dev->PciIo);
166   if (EFI_ERROR (Status)) {
167     goto CloseProtocol;
168   }
169 
170   return EFI_SUCCESS;
171 
172 CloseProtocol:
173   gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,
174          This->DriverBindingHandle, DeviceHandle);
175 
176 FreeDev:
177   FreePool (Dev);
178 
179   return Status;
180 }
181 
182 /**
183   Stop this driver on ControllerHandle.
184 
185   @param This               Protocol instance pointer.
186   @param DeviceHandle       Handle of device to stop driver on.
187   @param NumberOfChildren   Not used.
188   @param ChildHandleBuffer  Not used.
189 
190   @retval EFI_SUCCESS   This driver is removed from this device.
191   @retval other         Some error occurs when removing this driver from this device.
192 
193 **/
194 STATIC
195 EFI_STATUS
196 EFIAPI
NonDiscoverablePciDeviceStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)197 NonDiscoverablePciDeviceStop (
198   IN EFI_DRIVER_BINDING_PROTOCOL *This,
199   IN EFI_HANDLE                  DeviceHandle,
200   IN UINTN                       NumberOfChildren,
201   IN EFI_HANDLE                  *ChildHandleBuffer
202   )
203 {
204   EFI_STATUS                      Status;
205   EFI_PCI_IO_PROTOCOL             *PciIo;
206   NON_DISCOVERABLE_PCI_DEVICE     *Dev;
207 
208   Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
209                   (VOID **)&PciIo, This->DriverBindingHandle, DeviceHandle,
210                   EFI_OPEN_PROTOCOL_GET_PROTOCOL);
211   if (EFI_ERROR (Status)) {
212     return Status;
213   }
214 
215   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO (PciIo);
216 
217   //
218   // Handle Stop() requests for in-use driver instances gracefully.
219   //
220   Status = gBS->UninstallProtocolInterface (DeviceHandle,
221                   &gEfiPciIoProtocolGuid, &Dev->PciIo);
222   if (EFI_ERROR (Status)) {
223     return Status;
224   }
225 
226   gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,
227          This->DriverBindingHandle, DeviceHandle);
228 
229   FreePool (Dev);
230 
231   return EFI_SUCCESS;
232 }
233 
234 
235 //
236 // The static object that groups the Supported() (ie. probe), Start() and
237 // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
238 // C, 10.1 EFI Driver Binding Protocol.
239 //
240 STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
241   &NonDiscoverablePciDeviceSupported,
242   &NonDiscoverablePciDeviceStart,
243   &NonDiscoverablePciDeviceStop,
244   0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
245   NULL,
246   NULL
247 };
248 
249 /**
250   Entry point of this driver.
251 
252   @param  ImageHandle     Image handle this driver.
253   @param  SystemTable     Pointer to the System Table.
254 
255   @retval EFI_SUCCESS     The entry point is executed successfully.
256   @retval other           Some error occurred when executing this entry point.
257 
258 **/
259 EFI_STATUS
260 EFIAPI
NonDiscoverablePciDeviceDxeEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)261 NonDiscoverablePciDeviceDxeEntryPoint (
262   IN EFI_HANDLE       ImageHandle,
263   IN EFI_SYSTEM_TABLE *SystemTable
264   )
265 {
266   EFI_STATUS      Status;
267 
268   Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu);
269   ASSERT_EFI_ERROR(Status);
270 
271   return EfiLibInstallDriverBindingComponentName2 (
272            ImageHandle,
273            SystemTable,
274            &gDriverBinding,
275            ImageHandle,
276            &gComponentName,
277            &gComponentName2
278            );
279 }
280