1 /** @file
2  Emu Bus driver
3 
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
5 Portions copyright (c) 2011, Apple Inc. All rights reserved.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 
9 **/
10 
11 #include "EmuBusDriverDxe.h"
12 
13 
14 
15 //
16 // DriverBinding protocol global
17 //
18 EFI_DRIVER_BINDING_PROTOCOL           gEmuBusDriverBinding = {
19   EmuBusDriverBindingSupported,
20   EmuBusDriverBindingStart,
21   EmuBusDriverBindingStop,
22   0xa,
23   NULL,
24   NULL
25 };
26 
27 
28 
29 EFI_STATUS
30 EFIAPI
EmuBusDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)31 EmuBusDriverBindingSupported (
32   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
33   IN  EFI_HANDLE                   ControllerHandle,
34   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
35   )
36 {
37   EFI_STATUS                Status;
38   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
39   EMU_THUNK_PROTOCOL        *EmuThunk;
40 
41   //
42   // Check the contents of the first Device Path Node of RemainingDevicePath to make sure
43   // it is a legal Device Path Node for this bus driver's children.
44   //
45   if (RemainingDevicePath != NULL) {
46     //
47     // Check if RemainingDevicePath is the End of Device Path Node,
48     // if yes, go on checking other conditions
49     //
50     if (!IsDevicePathEnd (RemainingDevicePath)) {
51       //
52       // If RemainingDevicePath isn't the End of Device Path Node,
53       // check its validation
54       //
55       if (RemainingDevicePath->Type != HARDWARE_DEVICE_PATH ||
56           RemainingDevicePath->SubType != HW_VENDOR_DP ||
57           DevicePathNodeLength(RemainingDevicePath) != sizeof(EMU_VENDOR_DEVICE_PATH_NODE)) {
58         return EFI_UNSUPPORTED;
59       }
60     }
61   }
62 
63   //
64   // Open the IO Abstraction(s) needed to perform the supported test
65   //
66   Status = gBS->OpenProtocol (
67                   ControllerHandle,
68                   &gEmuThunkProtocolGuid,
69                   (VOID **)&EmuThunk   ,
70                   This->DriverBindingHandle,
71                   ControllerHandle,
72                   EFI_OPEN_PROTOCOL_BY_DRIVER
73                   );
74   if (Status == EFI_ALREADY_STARTED) {
75     return EFI_SUCCESS;
76   }
77 
78   if (EFI_ERROR (Status)) {
79     return Status;
80   }
81 
82   //
83   // Close the I/O Abstraction(s) used to perform the supported test
84   //
85   gBS->CloseProtocol (
86         ControllerHandle,
87         &gEmuThunkProtocolGuid,
88         This->DriverBindingHandle,
89         ControllerHandle
90         );
91 
92   //
93   // Open the EFI Device Path protocol needed to perform the supported test
94   //
95   Status = gBS->OpenProtocol (
96                   ControllerHandle,
97                   &gEfiDevicePathProtocolGuid,
98                   (VOID **)&ParentDevicePath,
99                   This->DriverBindingHandle,
100                   ControllerHandle,
101                   EFI_OPEN_PROTOCOL_BY_DRIVER
102                   );
103   if (Status == EFI_ALREADY_STARTED) {
104     return EFI_SUCCESS;
105   }
106 
107   if (EFI_ERROR (Status)) {
108     return Status;
109   }
110 
111 
112   //
113   // Close protocol, don't use device path protocol in the Support() function
114   //
115   gBS->CloseProtocol (
116         ControllerHandle,
117         &gEfiDevicePathProtocolGuid,
118         This->DriverBindingHandle,
119         ControllerHandle
120         );
121 
122   return Status;
123 }
124 
125 
126 EFI_STATUS
127 EFIAPI
EmuBusDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)128 EmuBusDriverBindingStart (
129   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
130   IN  EFI_HANDLE                   ControllerHandle,
131   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
132   )
133 {
134   EFI_STATUS                      Status;
135   EFI_STATUS                      InstallStatus;
136   EMU_THUNK_PROTOCOL              *EmuThunk;
137   EFI_DEVICE_PATH_PROTOCOL        *ParentDevicePath;
138   EMU_IO_DEVICE                   *EmuDevice;
139   EMU_BUS_DEVICE                  *EmuBusDevice;
140   EMU_IO_THUNK_PROTOCOL           *EmuIoThunk;
141   UINT16                          ComponentName[512];
142   EMU_VENDOR_DEVICE_PATH_NODE     *Node;
143   BOOLEAN                         CreateDevice;
144 
145   InstallStatus = EFI_UNSUPPORTED;
146   Status = EFI_UNSUPPORTED;
147 
148   //
149   // Grab the protocols we need
150   //
151   Status = gBS->OpenProtocol (
152                   ControllerHandle,
153                   &gEfiDevicePathProtocolGuid,
154                   (VOID **)&ParentDevicePath,
155                   This->DriverBindingHandle,
156                   ControllerHandle,
157                   EFI_OPEN_PROTOCOL_BY_DRIVER
158                   );
159   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
160     return Status;
161   }
162 
163   Status = gBS->OpenProtocol (
164                   ControllerHandle,
165                   &gEmuThunkProtocolGuid,
166                   (VOID **)&EmuThunk,
167                   This->DriverBindingHandle,
168                   ControllerHandle,
169                   EFI_OPEN_PROTOCOL_BY_DRIVER
170                   );
171   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
172     return Status;
173   }
174 
175   if (Status != EFI_ALREADY_STARTED) {
176     EmuBusDevice = AllocatePool (sizeof (EMU_BUS_DEVICE));
177     if (EmuBusDevice == NULL) {
178       return EFI_OUT_OF_RESOURCES;
179     }
180 
181     EmuBusDevice->Signature           = EMU_BUS_DEVICE_SIGNATURE;
182     EmuBusDevice->ControllerNameTable = NULL;
183 
184     AddUnicodeString2 (
185       "eng",
186       gEmuBusDriverComponentName.SupportedLanguages,
187       &EmuBusDevice->ControllerNameTable,
188       L"Emulator Bus Controller",
189       TRUE
190       );
191     AddUnicodeString2 (
192       "en",
193       gEmuBusDriverComponentName2.SupportedLanguages,
194       &EmuBusDevice->ControllerNameTable,
195       L"Emulator Bus Controller",
196       FALSE
197       );
198 
199 
200     Status = gBS->InstallMultipleProtocolInterfaces (
201                     &ControllerHandle,
202                     &gEfiCallerIdGuid, EmuBusDevice,
203                     NULL
204                     );
205     if (EFI_ERROR (Status)) {
206       FreeUnicodeStringTable (EmuBusDevice->ControllerNameTable);
207       gBS->FreePool (EmuBusDevice);
208       return Status;
209     }
210   }
211 
212 
213   for (Status = EFI_SUCCESS, EmuIoThunk = NULL; !EFI_ERROR (Status); ) {
214     Status = EmuThunk->GetNextProtocol (TRUE, &EmuIoThunk);
215     if (EFI_ERROR (Status)) {
216       break;
217     }
218 
219     CreateDevice = TRUE;
220     if (RemainingDevicePath != NULL) {
221       CreateDevice  = FALSE;
222       //
223       // Check if RemainingDevicePath is the End of Device Path Node,
224       // if yes, don't create any child device
225       //
226       if (!IsDevicePathEnd (RemainingDevicePath)) {
227         //
228         // If RemainingDevicePath isn't the End of Device Path Node,
229         // check its validation
230         //
231         Node          = (EMU_VENDOR_DEVICE_PATH_NODE *) RemainingDevicePath;
232         if (Node->VendorDevicePath.Header.Type == HARDWARE_DEVICE_PATH &&
233             Node->VendorDevicePath.Header.SubType == HW_VENDOR_DP &&
234             DevicePathNodeLength (&Node->VendorDevicePath.Header) == sizeof (EMU_VENDOR_DEVICE_PATH_NODE)
235             ) {
236           if (CompareGuid (&Node->VendorDevicePath.Guid, EmuIoThunk->Protocol) && Node->Instance == EmuIoThunk->Instance) {
237             CreateDevice = TRUE;
238           }
239         }
240       }
241     }
242 
243     if (CreateDevice) {
244       //
245       // Allocate instance structure, and fill in parent information.
246       //
247       EmuDevice = AllocatePool (sizeof (EMU_IO_DEVICE));
248       if (EmuDevice == NULL) {
249         return EFI_OUT_OF_RESOURCES;
250       }
251 
252       EmuDevice->Handle             = NULL;
253       EmuDevice->ControllerHandle   = ControllerHandle;
254       EmuDevice->ParentDevicePath   = ParentDevicePath;
255       CopyMem (&EmuDevice->EmuIoThunk, EmuIoThunk, sizeof (EMU_IO_THUNK_PROTOCOL));
256 
257       EmuDevice->ControllerNameTable = NULL;
258 
259       StrnCpyS (
260         ComponentName,
261         sizeof (ComponentName) / sizeof (CHAR16),
262         EmuIoThunk->ConfigString,
263         sizeof (ComponentName) / sizeof (CHAR16)
264         );
265 
266       EmuDevice->DevicePath = EmuBusCreateDevicePath (
267                                   ParentDevicePath,
268                                   EmuIoThunk->Protocol,
269                                   EmuIoThunk->Instance
270                                   );
271       if (EmuDevice->DevicePath == NULL) {
272         gBS->FreePool (EmuDevice);
273         return EFI_OUT_OF_RESOURCES;
274       }
275 
276       AddUnicodeString (
277         "eng",
278         gEmuBusDriverComponentName.SupportedLanguages,
279         &EmuDevice->ControllerNameTable,
280         ComponentName
281         );
282 
283       EmuDevice->Signature = EMU_IO_DEVICE_SIGNATURE;
284 
285       InstallStatus = gBS->InstallMultipleProtocolInterfaces (
286                             &EmuDevice->Handle,
287                             &gEfiDevicePathProtocolGuid,  EmuDevice->DevicePath,
288                             &gEmuIoThunkProtocolGuid,     &EmuDevice->EmuIoThunk,
289                             NULL
290                             );
291       if (EFI_ERROR (InstallStatus)) {
292         FreeUnicodeStringTable (EmuDevice->ControllerNameTable);
293         gBS->FreePool (EmuDevice);
294       } else {
295         //
296         // Open For Child Device
297         //
298         Status = gBS->OpenProtocol (
299                         ControllerHandle,
300                         &gEmuThunkProtocolGuid,
301                         (VOID **)&EmuThunk   ,
302                         This->DriverBindingHandle,
303                         EmuDevice->Handle,
304                         EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
305                         );
306         if (!EFI_ERROR (Status)) {
307           InstallStatus = EFI_SUCCESS;
308         }
309       }
310     }
311   }
312 
313   return InstallStatus;
314 }
315 
316 
317 EFI_STATUS
318 EFIAPI
EmuBusDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)319 EmuBusDriverBindingStop (
320   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
321   IN  EFI_HANDLE                   ControllerHandle,
322   IN  UINTN                        NumberOfChildren,
323   IN  EFI_HANDLE                   *ChildHandleBuffer
324   )
325 {
326   EFI_STATUS                Status;
327   UINTN                     Index;
328   BOOLEAN                   AllChildrenStopped;
329   EMU_IO_THUNK_PROTOCOL     *EmuIoThunk;
330   EMU_BUS_DEVICE            *EmuBusDevice;
331   EMU_IO_DEVICE             *EmuDevice;
332   EMU_THUNK_PROTOCOL        *EmuThunk;
333 
334   //
335   // Complete all outstanding transactions to Controller.
336   // Don't allow any new transaction to Controller to be started.
337   //
338 
339   if (NumberOfChildren == 0) {
340     //
341     // Close the bus driver
342     //
343     Status = gBS->OpenProtocol (
344                     ControllerHandle,
345                     &gEfiCallerIdGuid,
346                     (VOID **)&EmuBusDevice,
347                     This->DriverBindingHandle,
348                     ControllerHandle,
349                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
350                     );
351     if (EFI_ERROR (Status)) {
352       return Status;
353     }
354 
355     gBS->UninstallMultipleProtocolInterfaces (
356           ControllerHandle,
357           &gEfiCallerIdGuid,  EmuBusDevice,
358           NULL
359           );
360 
361     FreeUnicodeStringTable (EmuBusDevice->ControllerNameTable);
362 
363     gBS->FreePool (EmuBusDevice);
364 
365     gBS->CloseProtocol (
366           ControllerHandle,
367           &gEmuThunkProtocolGuid,
368           This->DriverBindingHandle,
369           ControllerHandle
370           );
371 
372     gBS->CloseProtocol (
373           ControllerHandle,
374           &gEfiDevicePathProtocolGuid,
375           This->DriverBindingHandle,
376           ControllerHandle
377           );
378     return EFI_SUCCESS;
379   }
380 
381   AllChildrenStopped = TRUE;
382 
383   for (Index = 0; Index < NumberOfChildren; Index++) {
384 
385     Status = gBS->OpenProtocol (
386                     ChildHandleBuffer[Index],
387                     &gEmuIoThunkProtocolGuid,
388                     (VOID **)&EmuIoThunk,
389                     This->DriverBindingHandle,
390                     ControllerHandle,
391                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
392                     );
393     if (!EFI_ERROR (Status)) {
394       EmuDevice = EMU_IO_DEVICE_FROM_THIS (EmuIoThunk);
395 
396       Status = gBS->CloseProtocol (
397                       ControllerHandle,
398                       &gEmuThunkProtocolGuid,
399                       This->DriverBindingHandle,
400                       EmuDevice->Handle
401                       );
402 
403       Status = gBS->UninstallMultipleProtocolInterfaces (
404                       EmuDevice->Handle,
405                       &gEfiDevicePathProtocolGuid,  EmuDevice->DevicePath,
406                       &gEmuIoThunkProtocolGuid,     &EmuDevice->EmuIoThunk,
407                       NULL
408                       );
409 
410       if (EFI_ERROR (Status)) {
411         gBS->OpenProtocol (
412               ControllerHandle,
413               &gEmuThunkProtocolGuid,
414               (VOID **) &EmuThunk   ,
415               This->DriverBindingHandle,
416               EmuDevice->Handle,
417               EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
418               );
419       } else {
420         //
421         // Close the child handle
422         //
423         FreeUnicodeStringTable (EmuDevice->ControllerNameTable);
424         FreePool (EmuDevice);
425       }
426     }
427 
428     if (EFI_ERROR (Status)) {
429       AllChildrenStopped = FALSE;
430     }
431   }
432 
433   if (!AllChildrenStopped) {
434     return EFI_DEVICE_ERROR;
435   }
436 
437   return EFI_SUCCESS;
438 }
439 
440 
441 /*++
442 
443 Routine Description:
444   Create a device path node using Guid and InstanceNumber and append it to
445   the passed in RootDevicePath
446 
447 Arguments:
448   RootDevicePath - Root of the device path to return.
449 
450   Guid           - GUID to use in vendor device path node.
451 
452   InstanceNumber - Instance number to use in the vendor device path. This
453                     argument is needed to make sure each device path is unique.
454 
455 Returns:
456 
457   EFI_DEVICE_PATH_PROTOCOL
458 
459 **/
460 EFI_DEVICE_PATH_PROTOCOL *
EmuBusCreateDevicePath(IN EFI_DEVICE_PATH_PROTOCOL * RootDevicePath,IN EFI_GUID * Guid,IN UINT16 InstanceNumber)461 EmuBusCreateDevicePath (
462   IN  EFI_DEVICE_PATH_PROTOCOL  *RootDevicePath,
463   IN  EFI_GUID                  *Guid,
464   IN  UINT16                    InstanceNumber
465   )
466 {
467   EMU_VENDOR_DEVICE_PATH_NODE  DevicePath;
468 
469   DevicePath.VendorDevicePath.Header.Type     = HARDWARE_DEVICE_PATH;
470   DevicePath.VendorDevicePath.Header.SubType  = HW_VENDOR_DP;
471   SetDevicePathNodeLength (&DevicePath.VendorDevicePath.Header, sizeof (EMU_VENDOR_DEVICE_PATH_NODE));
472 
473   //
474   // The GUID defines the Class
475   //
476   CopyMem (&DevicePath.VendorDevicePath.Guid, Guid, sizeof (EFI_GUID));
477 
478   //
479   // Add an instance number so we can make sure there are no Device Path
480   // duplication.
481   //
482   DevicePath.Instance = InstanceNumber;
483 
484   return AppendDevicePathNode (
485           RootDevicePath,
486           (EFI_DEVICE_PATH_PROTOCOL *) &DevicePath
487           );
488 }
489 
490 
491 
492 /**
493   The user Entry Point for module EmuBusDriver. The user code starts with this function.
494 
495   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
496   @param[in] SystemTable    A pointer to the EFI System Table.
497 
498   @retval EFI_SUCCESS       The entry point is executed successfully.
499   @retval other             Some error occurs when executing this entry point.
500 
501 **/
502 EFI_STATUS
503 EFIAPI
InitializeEmuBusDriver(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)504 InitializeEmuBusDriver (
505   IN EFI_HANDLE           ImageHandle,
506   IN EFI_SYSTEM_TABLE     *SystemTable
507   )
508 {
509   EFI_STATUS              Status;
510 
511   Status = EfiLibInstallAllDriverProtocols (
512              ImageHandle,
513              SystemTable,
514              &gEmuBusDriverBinding,
515              ImageHandle,
516              &gEmuBusDriverComponentName,
517              NULL,
518              NULL
519              );
520   ASSERT_EFI_ERROR (Status);
521 
522 
523   return Status;
524 }
525 
526 
527 
528 
529