1 /** @file
2   Usb3 Debug Port library instance
3 
4   Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include <Base.h>
10 
11 #include <PiDxe.h>
12 #include <Library/SerialPortLib.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/UefiBootServicesTableLib.h>
15 #include <Library/UefiLib.h>
16 #include <Library/PciLib.h>
17 #include <Library/PcdLib.h>
18 #include <Library/TimerLib.h>
19 #include <Library/Usb3DebugPortParamLib.h>
20 #include <Protocol/SmmBase2.h>
21 #include <Protocol/SmmAccess2.h>
22 #include <Protocol/IoMmu.h>
23 #include <Protocol/PciIo.h>
24 #include <Protocol/DxeSmmReadyToLock.h>
25 #include "Usb3DebugPortLibInternal.h"
26 
27 extern EFI_SMRAM_DESCRIPTOR mSmramCheckRanges[MAX_SMRAM_RANGE];
28 extern UINTN                mSmramCheckRangeCount;
29 extern BOOLEAN              mUsb3InSmm;
30 extern UINT64               mUsb3MmioSize;
31 extern BOOLEAN              mUsb3GetCapSuccess;
32 
33 GUID                        gUsb3DbgGuid =  USB3_DBG_GUID;
34 
35 USB3_DEBUG_PORT_CONTROLLER  mUsb3DebugPort;
36 USB3_DEBUG_PORT_INSTANCE    *mUsb3Instance = NULL;
37 EFI_PCI_IO_PROTOCOL         *mUsb3PciIo = NULL;
38 
39 /**
40   Creates a named event that can be signaled.
41 
42   This function creates an event using NotifyTpl, NoifyFunction.
43   If Name is NULL, then ASSERT().
44   If NotifyTpl is not a legal TPL value, then ASSERT().
45   If NotifyFunction is NULL, then ASSERT().
46 
47   @param  Name                  Supplies the GUID name of the event.
48   @param  NotifyTpl             Supplies the task priority level of the event notifications.
49   @param  NotifyFunction        Supplies the function to notify when the event is signaled.
50   @param  Event                 A pointer to the event created.
51 
52   @retval EFI_SUCCESS           A named event was created.
53   @retval EFI_OUT_OF_RESOURCES  There are not enough resource to create the named event.
54 
55 **/
56 EFI_STATUS
57 EFIAPI
Usb3NamedEventListen(IN CONST EFI_GUID * Name,IN EFI_TPL NotifyTpl,IN EFI_EVENT_NOTIFY NotifyFunction,IN EFI_EVENT * Event)58 Usb3NamedEventListen (
59   IN CONST EFI_GUID    *Name,
60   IN EFI_TPL           NotifyTpl,
61   IN EFI_EVENT_NOTIFY  NotifyFunction,
62   IN EFI_EVENT         *Event
63   )
64 {
65   EFI_STATUS  Status;
66   VOID        *RegistrationLocal;
67 
68   ASSERT (Name != NULL);
69   ASSERT (NotifyFunction != NULL);
70   ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);
71 
72   //
73   // Create event
74   //
75   Status = gBS->CreateEvent (
76                   EVT_NOTIFY_SIGNAL,
77                   NotifyTpl,
78                   NotifyFunction,
79                   NULL,
80                   Event
81                   );
82   ASSERT_EFI_ERROR (Status);
83 
84   //
85   // Register for an installation of protocol interface
86   //
87   Status = gBS->RegisterProtocolNotify (
88                   (EFI_GUID *) Name,
89                   *Event,
90                   &RegistrationLocal
91                   );
92   ASSERT_EFI_ERROR (Status);
93 
94   return Status;
95 }
96 
97 /**
98   USB3 map one DMA buffer.
99 
100   @param PciIo          Pointer to PciIo for USB3 debug port.
101   @param Address        DMA buffer address to be mapped.
102   @param NumberOfBytes  Number of bytes to be mapped.
103 
104 **/
105 VOID
Usb3MapOneDmaBuffer(IN EFI_PCI_IO_PROTOCOL * PciIo,IN EFI_PHYSICAL_ADDRESS Address,IN UINTN NumberOfBytes)106 Usb3MapOneDmaBuffer (
107   IN EFI_PCI_IO_PROTOCOL        *PciIo,
108   IN EFI_PHYSICAL_ADDRESS       Address,
109   IN UINTN                      NumberOfBytes
110   )
111 {
112   EFI_STATUS                    Status;
113   VOID                          *HostAddress;
114   EFI_PHYSICAL_ADDRESS          DeviceAddress;
115   VOID                          *Mapping;
116 
117   HostAddress = (VOID *) (UINTN) Address;
118   Status = PciIo->Map (
119                     PciIo,
120                     EfiPciIoOperationBusMasterCommonBuffer,
121                     HostAddress,
122                     &NumberOfBytes,
123                     &DeviceAddress,
124                     &Mapping
125                     );
126   ASSERT_EFI_ERROR (Status);
127   ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress));
128 }
129 
130 /**
131   USB3 map DMA buffers.
132 
133   @param Instance       Pointer to USB3 debug port instance.
134   @param PciIo          Pointer to PciIo for USB3 debug port.
135 
136 **/
137 VOID
Usb3MapDmaBuffers(IN USB3_DEBUG_PORT_INSTANCE * Instance,IN EFI_PCI_IO_PROTOCOL * PciIo)138 Usb3MapDmaBuffers (
139   IN USB3_DEBUG_PORT_INSTANCE   *Instance,
140   IN EFI_PCI_IO_PROTOCOL        *PciIo
141   )
142 {
143   Usb3MapOneDmaBuffer (
144     PciIo,
145     Instance->Urb.Data,
146     XHC_DEBUG_PORT_DATA_LENGTH
147     );
148 
149   Usb3MapOneDmaBuffer (
150     PciIo,
151     Instance->TransferRingIn.RingSeg0,
152     sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
153     );
154 
155   Usb3MapOneDmaBuffer (
156     PciIo,
157     Instance->TransferRingOut.RingSeg0,
158     sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
159     );
160 
161   Usb3MapOneDmaBuffer (
162     PciIo,
163     Instance->EventRing.EventRingSeg0,
164     sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER
165     );
166 
167   Usb3MapOneDmaBuffer (
168     PciIo,
169     Instance->EventRing.ERSTBase,
170     sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER
171     );
172 
173   Usb3MapOneDmaBuffer (
174     PciIo,
175     Instance->DebugCapabilityContext,
176     sizeof (XHC_DC_CONTEXT)
177     );
178 
179   Usb3MapOneDmaBuffer (
180     PciIo,
181     ((XHC_DC_CONTEXT *) (UINTN) Instance->DebugCapabilityContext)->DbcInfoContext.String0DescAddress,
182     STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN
183     );
184 }
185 
186 /**
187   Invoke a notification event
188 
189   @param[in]  Event                 Event whose notification function is being invoked.
190   @param[in]  Context               The pointer to the notification function's context,
191                                     which is implementation-dependent.
192 
193 **/
194 VOID
195 EFIAPI
Usb3DxeSmmReadyToLockNotify(IN EFI_EVENT Event,IN VOID * Context)196 Usb3DxeSmmReadyToLockNotify (
197   IN  EFI_EVENT                Event,
198   IN  VOID                     *Context
199   )
200 {
201   ASSERT (mUsb3Instance != NULL);
202 
203   //
204   // For the case that the USB3 debug port instance and DMA buffers are
205   // from PEI HOB with IOMMU enabled.
206   // Reinitialize USB3 debug port with granted DXE DMA buffer accessible
207   // by SMM environment.
208   //
209   InitializeUsb3DebugPort (mUsb3Instance);
210 
211   SaveUsb3InstanceAddress (mUsb3Instance);
212 
213   gBS->CloseEvent (Event);
214 }
215 
216 /**
217   USB3 get IOMMU protocol.
218 
219   @return Pointer to IOMMU protocol.
220 
221 **/
222 EDKII_IOMMU_PROTOCOL *
Usb3GetIoMmu(VOID)223 Usb3GetIoMmu (
224   VOID
225   )
226 {
227   EFI_STATUS                Status;
228   EDKII_IOMMU_PROTOCOL      *IoMmu;
229 
230   IoMmu = NULL;
231   Status = gBS->LocateProtocol (
232              &gEdkiiIoMmuProtocolGuid,
233              NULL,
234              (VOID **) &IoMmu
235              );
236   if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
237     return IoMmu;
238   }
239 
240   return NULL;
241 }
242 
243 /**
244   Invoke a notification event
245 
246   @param[in]  Event                 Event whose notification function is being invoked.
247   @param[in]  Context               The pointer to the notification function's context,
248                                     which is implementation-dependent.
249 
250 **/
251 VOID
252 EFIAPI
Usb3PciIoNotify(IN EFI_EVENT Event,IN VOID * Context)253 Usb3PciIoNotify (
254   IN  EFI_EVENT                Event,
255   IN  VOID                     *Context
256   )
257 {
258   EFI_STATUS                    Status;
259   UINTN                         PciIoHandleCount;
260   EFI_HANDLE                    *PciIoHandleBuffer;
261   UINTN                         Index;
262   EFI_PCI_IO_PROTOCOL           *PciIo;
263   UINTN                         PciSegment;
264   UINTN                         PciBusNumber;
265   UINTN                         PciDeviceNumber;
266   UINTN                         PciFunctionNumber;
267   EFI_EVENT                     SmmReadyToLockEvent;
268 
269   Status = gBS->LocateHandleBuffer (
270                   ByProtocol,
271                   &gEfiPciIoProtocolGuid,
272                   NULL,
273                   &PciIoHandleCount,
274                   &PciIoHandleBuffer
275                   );
276   if (!EFI_ERROR (Status) &&
277       (PciIoHandleBuffer != NULL) &&
278       (PciIoHandleCount != 0)) {
279     for (Index = 0; Index < PciIoHandleCount; Index++) {
280       Status = gBS->HandleProtocol (
281                       PciIoHandleBuffer[Index],
282                       &gEfiPciIoProtocolGuid,
283                       (VOID **) &PciIo
284                       );
285       ASSERT_EFI_ERROR (Status);
286       Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBusNumber, &PciDeviceNumber, &PciFunctionNumber);
287       ASSERT_EFI_ERROR (Status);
288       if ((PciBusNumber == mUsb3DebugPort.PciAddress.Bus) &&
289           (PciDeviceNumber == mUsb3DebugPort.PciAddress.Device) &&
290           (PciFunctionNumber == mUsb3DebugPort.PciAddress.Function)) {
291         //
292         // Found the PciIo for USB3 debug port.
293         //
294         ASSERT (mUsb3Instance != NULL);
295         if (Usb3GetIoMmu () != NULL) {
296           Usb3MapDmaBuffers (mUsb3Instance, PciIo);
297 
298           if (mUsb3Instance->FromHob) {
299             mUsb3PciIo = PciIo;
300             Usb3NamedEventListen (
301               &gEfiDxeSmmReadyToLockProtocolGuid,
302               TPL_NOTIFY,
303               Usb3DxeSmmReadyToLockNotify,
304               &SmmReadyToLockEvent
305               );
306           }
307         }
308         gBS->CloseEvent (Event);
309         break;
310       }
311     }
312 
313     gBS->FreePool (PciIoHandleBuffer);
314   }
315 }
316 
317 /**
318   Return XHCI MMIO base address.
319 
320 **/
321 EFI_PHYSICAL_ADDRESS
GetXhciBaseAddress(VOID)322 GetXhciBaseAddress (
323   VOID
324   )
325 {
326   UINT8                       Bus;
327   UINT8                       Device;
328   UINT8                       Function;
329   EFI_PHYSICAL_ADDRESS        Address;
330   UINT32                      Low;
331   UINT32                      High;
332 
333   if (mUsb3DebugPort.Controller == 0) {
334     mUsb3DebugPort.Controller = GetUsb3DebugPortController();
335   }
336 
337   Bus = mUsb3DebugPort.PciAddress.Bus;
338   Device = mUsb3DebugPort.PciAddress.Device;
339   Function = mUsb3DebugPort.PciAddress.Function;
340 
341   Low = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET));
342   High = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4));
343   Address = (EFI_PHYSICAL_ADDRESS) (LShiftU64 ((UINT64) High, 32) | Low);
344   //
345   // Mask other parts which are not part of base address
346   //
347   Address &= XHCI_BASE_ADDRESS_64_BIT_MASK;
348   return Address;
349 }
350 
351 /**
352   Return XHCI debug instance address.
353 
354 **/
355 USB3_DEBUG_PORT_INSTANCE *
GetUsb3DebugPortInstance(VOID)356 GetUsb3DebugPortInstance (
357   VOID
358   )
359 {
360   USB3_DEBUG_PORT_INSTANCE               *Instance;
361   EFI_PHYSICAL_ADDRESS                   XhcMmioBase;
362   UINT64                                 CapabilityPointer;
363   UINT32                                 Capability;
364   BOOLEAN                                Flag;
365   UINT8                                  Bus;
366   UINT8                                  Device;
367   UINT8                                  Function;
368   UINT16                                 Command;
369   USB3_DEBUG_PORT_CONTROLLER             UsbDebugPort;
370 
371   Instance = NULL;
372 
373   XhcMmioBase = GetXhciBaseAddress ();
374 
375   if ((XhcMmioBase == 0) || (XhcMmioBase == XHCI_BASE_ADDRESS_64_BIT_MASK)) {
376     return NULL;
377   }
378 
379   if (mUsb3Instance != NULL) {
380     FixUsb3InstanceResource (mUsb3Instance, XhcMmioBase);
381     return mUsb3Instance;
382   }
383 
384   Command = GetXhciPciCommand ();
385 
386   UsbDebugPort.Controller = GetUsb3DebugPortController();
387   Bus      = UsbDebugPort.PciAddress.Bus;
388   Device   = UsbDebugPort.PciAddress.Device;
389   Function = UsbDebugPort.PciAddress.Function;
390 
391   //
392   // Set Command Register
393   //
394   if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) {
395     PciWrite16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET), Command | EFI_PCI_COMMAND_MEMORY_SPACE);
396     PciRead16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
397   }
398 
399   //
400   // Calculate capability offset from HCCPARAMS [16:31], in 32-bit words
401   //
402   CapabilityPointer = XhcMmioBase + (MmioRead32 ((UINTN)(XhcMmioBase + XHC_HCCPARAMS_OFFSET)) >> 16) * 4;
403 
404   //
405   // Search XHCI debug capability
406   //
407   Flag = FALSE;
408   Capability = MmioRead32 ((UINTN)CapabilityPointer);
409   while (TRUE) {
410     if ((Capability & XHC_CAPABILITY_ID_MASK) == PCI_CAPABILITY_ID_DEBUG_PORT) {
411       Flag = TRUE;
412       break;
413     }
414     if ((((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) & XHC_CAPABILITY_ID_MASK) == 0) {
415       //
416       // Reach the end of list, quit
417       //
418       break;
419     }
420     CapabilityPointer += ((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) * 4;
421     Capability = MmioRead32 ((UINTN)CapabilityPointer);
422   }
423 
424   if (Flag) {
425     Instance = (USB3_DEBUG_PORT_INSTANCE *)(UINTN) MmioRead32 ((UINTN) (CapabilityPointer + XHC_DC_DCDDI2));
426 
427     if (Instance != NULL) {
428       FixUsb3InstanceResource (Instance, XhcMmioBase);
429     }
430   }
431 
432   //
433   // Restore Command Register
434   //
435   PciWrite16(PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command);
436 
437   return Instance;
438 }
439 
440 
441 /**
442   Initialize USB3 debug port.
443 
444   This method invokes various internal functions to facilitate
445   detection and initialization of USB3 debug port.
446 
447   @retval RETURN_SUCCESS        The USB3 debug port was initialized.
448 **/
449 RETURN_STATUS
450 EFIAPI
USB3Initialize(VOID)451 USB3Initialize (
452   VOID
453   )
454 {
455   //
456   // Leave it empty, we assume PEI phase already do initialization
457   //
458   return RETURN_SUCCESS;
459 }
460 
461 /**
462   Initialize USB3 debug port.
463 
464   This method invokes various internal functions to facilitate
465   detection and initialization of USB3 debug port.
466 
467   @retval RETURN_SUCCESS        The serial device was initialized.
468 **/
469 RETURN_STATUS
470 EFIAPI
USB3InitializeReal(VOID)471 USB3InitializeReal (
472   VOID
473   )
474 {
475   USB3_DEBUG_PORT_INSTANCE    UsbDbg;
476   USB3_DEBUG_PORT_INSTANCE    *Instance;
477   EFI_PHYSICAL_ADDRESS        Address;
478   EFI_STATUS                  Status;
479   EFI_EVENT                   Event;
480 
481   if ((gST == NULL) || (gBS == NULL)) {
482     //
483     // gST and gBS have not been initialized yet
484     //
485     return EFI_DEVICE_ERROR;
486   }
487 
488   Status = EfiGetSystemConfigurationTable (&gUsb3DbgGuid, (VOID **) &mUsb3Instance);
489   if (!EFI_ERROR (Status)) {
490     goto Done;
491   }
492 
493   //
494   // It is first time to run DXE instance, copy Instance from Hob to ACPINvs
495   // NOTE: Hob is not ready at this time, so copy it from XHCI register.
496   //
497   Instance = GetUsb3DebugPortInstance ();
498   if (Instance == NULL) {
499     //
500     // Initialize USB debug
501     //
502     SetMem (&UsbDbg, sizeof(UsbDbg), 0);
503     DiscoverUsb3DebugPort (&UsbDbg);
504     if (UsbDbg.DebugSupport) {
505       InitializeUsb3DebugPort (&UsbDbg);
506     }
507     Instance = &UsbDbg;
508   }
509   Address = SIZE_4GB;
510   Status = gBS->AllocatePages (
511                   AllocateMaxAddress,
512                   EfiACPIMemoryNVS,
513                   EFI_SIZE_TO_PAGES (sizeof (USB3_DEBUG_PORT_INSTANCE)),
514                   &Address
515                   );
516   if (EFI_ERROR (Status)) {
517     return Status;
518   }
519 
520   CopyMem (
521     (VOID *)(UINTN)Address,
522     Instance,
523     sizeof (USB3_DEBUG_PORT_INSTANCE)
524     );
525   mUsb3Instance = (USB3_DEBUG_PORT_INSTANCE *)(UINTN)Address;
526 
527   Status = gBS->InstallConfigurationTable (&gUsb3DbgGuid, mUsb3Instance);
528   if (EFI_ERROR (Status)) {
529     return Status;
530   }
531 
532   if (mUsb3Instance->DebugSupport) {
533     SaveUsb3InstanceAddress (mUsb3Instance);
534   }
535 
536 Done:
537   if ((mUsb3Instance != NULL) && mUsb3Instance->Ready && (mUsb3Instance->PciIoEvent == 0)) {
538     Status = Usb3NamedEventListen (
539                &gEfiPciIoProtocolGuid,
540                TPL_NOTIFY,
541                Usb3PciIoNotify,
542                &Event
543                );
544     if (!EFI_ERROR (Status)) {
545       mUsb3Instance->PciIoEvent = (EFI_PHYSICAL_ADDRESS) (UINTN) Event;
546     }
547   }
548 
549   return RETURN_SUCCESS;
550 }
551 
552 /**
553   Calculate the size of XHCI MMIO space.
554 
555   @retval     TURE         The XHCI MMIO is in SMRAM ranges.
556   @retval     FALSE        The XHCI MMIO is out of SMRAM ranges.
557 **/
558 UINT64
CalculateMmioSize(VOID)559 CalculateMmioSize (
560   VOID
561   )
562 {
563   UINT8                       Bus;
564   UINT8                       Device;
565   UINT8                       Function;
566   UINT32                      Value;
567   UINT32                      Mask;
568   UINT64                      MmioSize;
569   UINT16                      Command;
570   USB3_DEBUG_PORT_CONTROLLER  UsbDebugPort;
571   EFI_PHYSICAL_ADDRESS        XhcMmioBase;
572 
573   UsbDebugPort.Controller = GetUsb3DebugPortController();
574   Bus      = UsbDebugPort.PciAddress.Bus;
575   Device   = UsbDebugPort.PciAddress.Device;
576   Function = UsbDebugPort.PciAddress.Function;
577 
578   Mask     = 0xFFFFFFF0;
579   MmioSize = 0;
580 
581   XhcMmioBase = GetXhciBaseAddress ();
582 
583   //
584   // Disable MSE
585   //
586   Command = PciRead16 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
587   PciWrite16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command & ~(EFI_PCI_COMMAND_MEMORY_SPACE));
588 
589   //
590   // Get Mmio Size
591   //
592   PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET), 0xFFFFFFFF);
593   Value    = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET));
594 
595   switch (Value & 0x07) {
596     case 0x0:
597       //
598       // Memory space: anywhere in 32 bit address space
599       //
600       MmioSize = (~(Value & Mask)) + 1;
601       break;
602     case 0x4:
603       //
604       // Memory space: anywhere in 64 bit address space
605       //
606       MmioSize = Value & Mask;
607       PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), 0xFFFFFFFF);
608       Value    = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4));
609       //
610       // Fix the length to support some spefic 64 bit BAR
611       //
612       Value |= ((UINT32)(-1) << HighBitSet32 (Value));
613       //
614       // Calculate the size of 64bit bar
615       //
616       MmioSize  |= LShiftU64 ((UINT64) Value, 32);
617       MmioSize  = (~(MmioSize)) + 1;
618       break;
619     default:
620       //
621       // Unknown BAR type
622       //
623       MmioSize = (~(Value & Mask)) + 1;
624       break;
625   };
626 
627 
628   //
629   // Restore MMIO address
630   //
631   PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET), (UINT32)XhcMmioBase);
632   PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), (UINT32) (XhcMmioBase >> 32));
633 
634   PciWrite16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command | EFI_PCI_COMMAND_MEMORY_SPACE);
635 
636   return MmioSize;
637 }
638 
639 /**
640   The constructor function initialize USB3 debug port.
641 
642   @param  ImageHandle   The firmware allocated handle for the EFI image.
643   @param  SystemTable   A pointer to the EFI System Table.
644 
645   @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
646 
647 **/
648 EFI_STATUS
649 EFIAPI
Usb3DebugPortLibDxeConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)650 Usb3DebugPortLibDxeConstructor (
651   IN EFI_HANDLE        ImageHandle,
652   IN EFI_SYSTEM_TABLE  *SystemTable
653   )
654 {
655   EFI_SMM_BASE2_PROTOCOL        *SmmBase;
656   EFI_SMM_ACCESS2_PROTOCOL      *SmmAccess;
657   UINTN                         Size;
658   EFI_STATUS                    Status;
659 
660   //
661   // Do real initialization here, because we need copy data from Hob to ACPINvs.
662   // We must do it in constructor because it depends on UefiBootServicesTableLib.
663   //
664   if (FeaturePcdGet (PcdUsb3DebugFeatureEnable)) {
665     USB3InitializeReal ();
666   }
667 
668   mUsb3MmioSize = CalculateMmioSize ();
669 
670   if (gBS != NULL) {
671     SmmBase = NULL;
672     Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID **)&SmmBase);
673     if (!EFI_ERROR (Status)) {
674       SmmBase->InSmm(SmmBase, &mUsb3InSmm);
675     }
676 
677     if (mUsb3InSmm) {
678       //
679       // Get SMRAM information
680       //
681       SmmAccess = NULL;
682       Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);
683       if (!EFI_ERROR (Status)) {
684         Size = sizeof (mSmramCheckRanges);
685 
686         Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmramCheckRanges);
687         if (!EFI_ERROR (Status)) {
688           mSmramCheckRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
689         }
690       }
691     }
692   }
693 
694   return EFI_SUCCESS;
695 }
696 
697 /**
698   The destructor function.
699 
700   @param  ImageHandle   The firmware allocated handle for the EFI image.
701   @param  SystemTable   A pointer to the EFI System Table.
702 
703   @retval EFI_SUCCESS   The destructor always returns EFI_SUCCESS.
704 
705 **/
706 EFI_STATUS
707 EFIAPI
Usb3DebugPortLibDxeDestructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)708 Usb3DebugPortLibDxeDestructor (
709   IN EFI_HANDLE        ImageHandle,
710   IN EFI_SYSTEM_TABLE  *SystemTable
711   )
712 {
713   if ((mUsb3Instance != NULL) && (mUsb3Instance->PciIoEvent != 0)) {
714     //
715     // Close the event created.
716     //
717     gBS->CloseEvent ((EFI_EVENT) (UINTN) mUsb3Instance->PciIoEvent);
718     mUsb3Instance->PciIoEvent = 0;
719   }
720   return EFI_SUCCESS;
721 }
722 
723 /**
724   Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
725   OperationBusMasterCommonBuffer64 mapping.
726 
727   @param PciIo                  Pointer to PciIo for USB3 debug port.
728   @param Pages                  The number of pages to allocate.
729   @param Address                A pointer to store the base system memory address of the
730                                 allocated range.
731 
732   @retval EFI_SUCCESS           The requested memory pages were allocated.
733   @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
734                                 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
735   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
736   @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
737 
738 **/
739 EFI_STATUS
Usb3AllocateDmaBuffer(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINTN Pages,OUT VOID ** Address)740 Usb3AllocateDmaBuffer (
741   IN EFI_PCI_IO_PROTOCOL    *PciIo,
742   IN UINTN                  Pages,
743   OUT VOID                  **Address
744   )
745 {
746   EFI_STATUS            Status;
747 
748   *Address = NULL;
749   Status = PciIo->AllocateBuffer (
750                     PciIo,
751                     AllocateAnyPages,
752                     EfiRuntimeServicesData,
753                     Pages,
754                     Address,
755                     0
756                     );
757   if (!EFI_ERROR (Status)) {
758     Usb3MapOneDmaBuffer (
759       PciIo,
760       (EFI_PHYSICAL_ADDRESS) (UINTN) *Address,
761       EFI_PAGES_TO_SIZE (Pages)
762       );
763   }
764   return Status;
765 }
766 
767 /**
768   Allocate aligned memory for XHC's usage.
769 
770   @param BufferSize     The size, in bytes, of the Buffer.
771 
772   @return A pointer to the allocated buffer or NULL if allocation fails.
773 
774 **/
775 VOID*
AllocateAlignBuffer(IN UINTN BufferSize)776 AllocateAlignBuffer (
777   IN UINTN                    BufferSize
778   )
779 {
780   VOID                    *Buf;
781   EFI_PHYSICAL_ADDRESS    Address;
782   EFI_STATUS              Status;
783 
784   Buf = NULL;
785 
786   if (gBS != NULL) {
787     if (mUsb3PciIo != NULL) {
788       Usb3AllocateDmaBuffer (
789         mUsb3PciIo,
790         EFI_SIZE_TO_PAGES (BufferSize),
791         &Buf
792         );
793     } else {
794       Address = 0xFFFFFFFF;
795       Status = gBS->AllocatePages (
796                       AllocateMaxAddress,
797                       EfiACPIMemoryNVS,
798                       EFI_SIZE_TO_PAGES (BufferSize),
799                       &Address
800                       );
801       if (!EFI_ERROR (Status)) {
802         Buf = (VOID *)(UINTN)Address;
803       }
804     }
805   }
806 
807   return Buf;
808 }
809 
810 /**
811   Check whether AllocatePages in permanent memory is ready.
812 
813   @retval TRUE  AllocatePages in permanent memory is ready.
814   @retval FALSE AllocatePages in permanent memory is not ready.
815 
816 **/
817 BOOLEAN
IsAllocatePagesReady(VOID)818 IsAllocatePagesReady (
819   VOID
820   )
821 {
822   if (gBS != NULL) {
823     return TRUE;
824   }
825 
826   return FALSE;
827 }
828 
829