Revert "DebugUsb3: Check mUsb3Instance before dereferencing it"
[mirror_edk2.git] / SourceLevelDebugPkg / Library / DebugCommunicationLibUsb3 / DebugCommunicationLibUsb3Dxe.c
CommitLineData
2cb6eabe
EL
1/** @file\r
2 Debug Port Library implementation based on usb3 debug port.\r
3\r
de8373fa 4 Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>\r
2cb6eabe
EL
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php.\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <Base.h>\r
16#include <PiDxe.h>\r
17#include <Library/UefiBootServicesTableLib.h>\r
de8373fa
SZ
18#include <Library/HobLib.h>\r
19#include <Protocol/PciIo.h>\r
20#include <Protocol/IoMmu.h>\r
2cb6eabe
EL
21#include "DebugCommunicationLibUsb3Internal.h"\r
22\r
de8373fa
SZ
23GUID gUsb3DbgGuid = USB3_DBG_GUID;\r
24\r
25USB3_DEBUG_PORT_HANDLE *mUsb3Instance = NULL;\r
26\r
27/**\r
28 Creates a named event that can be signaled.\r
29\r
30 This function creates an event using NotifyTpl, NoifyFunction.\r
31 If Name is NULL, then ASSERT().\r
32 If NotifyTpl is not a legal TPL value, then ASSERT().\r
33 If NotifyFunction is NULL, then ASSERT().\r
34\r
35 @param Name Supplies the GUID name of the event.\r
36 @param NotifyTpl Supplies the task priority level of the event notifications.\r
37 @param NotifyFunction Supplies the function to notify when the event is signaled.\r
38 @param Event A pointer to the event created.\r
39\r
40 @retval EFI_SUCCESS A named event was created.\r
41 @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.\r
42\r
43**/\r
44EFI_STATUS\r
45EFIAPI\r
46Usb3NamedEventListen (\r
47 IN CONST EFI_GUID *Name,\r
48 IN EFI_TPL NotifyTpl,\r
49 IN EFI_EVENT_NOTIFY NotifyFunction,\r
50 IN EFI_EVENT *Event\r
51 )\r
52{\r
53 EFI_STATUS Status;\r
54 VOID *RegistrationLocal;\r
55\r
56 ASSERT (Name != NULL);\r
57 ASSERT (NotifyFunction != NULL);\r
58 ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);\r
59\r
60 //\r
61 // Create event\r
62 //\r
63 Status = gBS->CreateEvent (\r
64 EVT_NOTIFY_SIGNAL,\r
65 NotifyTpl,\r
66 NotifyFunction,\r
67 NULL,\r
68 Event\r
69 );\r
70 ASSERT_EFI_ERROR (Status);\r
71\r
72 //\r
73 // Register for an installation of protocol interface\r
74 //\r
75 Status = gBS->RegisterProtocolNotify (\r
76 (EFI_GUID *) Name,\r
77 *Event,\r
78 &RegistrationLocal\r
79 );\r
80 ASSERT_EFI_ERROR (Status);\r
81\r
82 return Status;\r
83}\r
84\r
85/**\r
86 USB3 map one DMA buffer.\r
87\r
88 @param Instance Pointer to USB3 debug port instance.\r
89 @param PciIo Pointer to PciIo for USB3 debug port.\r
90 @param Address DMA buffer address to be mapped.\r
91 @param NumberOfBytes Number of bytes to be mapped.\r
92 @param BackupBuffer Backup buffer address.\r
93\r
94**/\r
95VOID\r
96Usb3MapOneDmaBuffer (\r
97 IN USB3_DEBUG_PORT_HANDLE *Instance,\r
98 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
99 IN EFI_PHYSICAL_ADDRESS Address,\r
100 IN UINTN NumberOfBytes,\r
101 IN EFI_PHYSICAL_ADDRESS BackupBuffer\r
102 )\r
103{\r
104 EFI_STATUS Status;\r
105 VOID *HostAddress;\r
106 EFI_PHYSICAL_ADDRESS DeviceAddress;\r
107 VOID *Mapping;\r
108\r
109 HostAddress = (VOID *) (UINTN) Address;\r
110 Status = PciIo->Map (\r
111 PciIo,\r
112 EfiPciIoOperationBusMasterCommonBuffer,\r
113 HostAddress,\r
114 &NumberOfBytes,\r
115 &DeviceAddress,\r
116 &Mapping\r
117 );\r
118 ASSERT_EFI_ERROR (Status);\r
119 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress));\r
120 if (Instance->FromHob) {\r
121 //\r
122 // Reallocate the DMA buffer by AllocateAddress with\r
123 // the memory type accessible by SMM.\r
124 //\r
125 CopyMem ((VOID *) (UINTN) BackupBuffer, (VOID *) (UINTN) Address, NumberOfBytes);\r
126 Status = gBS->FreePages (Address, EFI_SIZE_TO_PAGES (NumberOfBytes));\r
127 ASSERT_EFI_ERROR (Status);\r
128 Status = gBS->AllocatePages (\r
129 AllocateAddress,\r
130 EfiACPIMemoryNVS,\r
131 EFI_SIZE_TO_PAGES (NumberOfBytes),\r
132 &Address\r
133 );\r
134 ASSERT_EFI_ERROR (Status);\r
135 CopyMem ((VOID *) (UINTN) Address, (VOID *) (UINTN) BackupBuffer, NumberOfBytes);\r
136 }\r
137}\r
138\r
139/**\r
140 USB3 map DMA buffers.\r
141\r
142 @param Instance Pointer to USB3 debug port instance.\r
143 @param PciIo Pointer to PciIo for USB3 debug port.\r
144\r
145**/\r
146VOID\r
147Usb3MapDmaBuffers (\r
148 IN USB3_DEBUG_PORT_HANDLE *Instance,\r
149 IN EFI_PCI_IO_PROTOCOL *PciIo\r
150 )\r
151{\r
152 EFI_STATUS Status;\r
153 EDKII_IOMMU_PROTOCOL *IoMmu;\r
154 EFI_PHYSICAL_ADDRESS BackupBuffer;\r
155 UINTN BackupBufferSize;\r
156\r
157 IoMmu = NULL;\r
158 Status = gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL, (VOID **) &IoMmu);\r
159 if (EFI_ERROR (Status) || (IoMmu == NULL)) {\r
160 //\r
161 // No need to map the DMA buffers.\r
162 //\r
163 return;\r
164 }\r
165\r
166 //\r
167 // Allocate backup buffer for the case that the USB3\r
168 // debug port instance and DMA buffers are from PEI HOB.\r
169 // For this case, the DMA buffers need to be reallocated\r
170 // by AllocateAddress with the memory type accessible by\r
171 // SMM.\r
172 //\r
173 BackupBufferSize = MAX (XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE,\r
174 MAX (sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER,\r
175 MAX (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER,\r
176 MAX (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER,\r
177 MAX (sizeof (XHC_DC_CONTEXT),\r
178 STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN)))));\r
179\r
180 Status = gBS->AllocatePages (\r
181 AllocateAnyPages,\r
182 EfiBootServicesData,\r
183 EFI_SIZE_TO_PAGES (BackupBufferSize),\r
184 &BackupBuffer\r
185 );\r
186 ASSERT_EFI_ERROR (Status);\r
187\r
188 Usb3MapOneDmaBuffer (\r
189 Instance,\r
190 PciIo,\r
191 Instance->UrbIn.Data,\r
192 XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE,\r
193 BackupBuffer\r
194 );\r
195\r
196 Usb3MapOneDmaBuffer (\r
197 Instance,\r
198 PciIo,\r
199 Instance->TransferRingIn.RingSeg0,\r
200 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER,\r
201 BackupBuffer\r
202 );\r
203\r
204 Usb3MapOneDmaBuffer (\r
205 Instance,\r
206 PciIo,\r
207 Instance->TransferRingOut.RingSeg0,\r
208 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER,\r
209 BackupBuffer\r
210 );\r
211\r
212 Usb3MapOneDmaBuffer (\r
213 Instance,\r
214 PciIo,\r
215 Instance->EventRing.EventRingSeg0,\r
216 sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER,\r
217 BackupBuffer\r
218 );\r
219\r
220 Usb3MapOneDmaBuffer (\r
221 Instance,\r
222 PciIo,\r
223 Instance->EventRing.ERSTBase,\r
224 sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER,\r
225 BackupBuffer\r
226 );\r
227\r
228 Usb3MapOneDmaBuffer (\r
229 Instance,\r
230 PciIo,\r
231 Instance->DebugCapabilityContext,\r
232 sizeof (XHC_DC_CONTEXT),\r
233 BackupBuffer\r
234 );\r
235\r
236 Usb3MapOneDmaBuffer (\r
237 Instance,\r
238 PciIo,\r
239 ((XHC_DC_CONTEXT *) (UINTN) Instance->DebugCapabilityContext)->DbcInfoContext.String0DescAddress,\r
240 STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN,\r
241 BackupBuffer\r
242 );\r
243\r
244 gBS->FreePages (BackupBuffer, EFI_SIZE_TO_PAGES (BackupBufferSize));\r
245}\r
246\r
247/**\r
248 Invoke a notification event\r
249\r
250 @param[in] Event Event whose notification function is being invoked.\r
251 @param[in] Context The pointer to the notification function's context,\r
252 which is implementation-dependent.\r
253\r
254**/\r
255VOID\r
256EFIAPI\r
257Usb3PciIoNotify (\r
258 IN EFI_EVENT Event,\r
259 IN VOID *Context\r
260 )\r
261{\r
262 EFI_STATUS Status;\r
263 UINTN PciIoHandleCount;\r
264 EFI_HANDLE *PciIoHandleBuffer;\r
265 UINTN Index;\r
266 EFI_PCI_IO_PROTOCOL *PciIo;\r
267 UINTN PciSegment;\r
268 UINTN PciBusNumber;\r
269 UINTN PciDeviceNumber;\r
270 UINTN PciFunctionNumber;\r
271 UINT32 PciAddress;\r
272\r
273 ASSERT (mUsb3Instance != NULL);\r
274\r
275 Status = gBS->LocateHandleBuffer (\r
276 ByProtocol,\r
277 &gEfiPciIoProtocolGuid,\r
278 NULL,\r
279 &PciIoHandleCount,\r
280 &PciIoHandleBuffer\r
281 );\r
282 if (!EFI_ERROR (Status) &&\r
283 (PciIoHandleBuffer != NULL) &&\r
284 (PciIoHandleCount != 0)) { \r
285 for (Index = 0; Index < PciIoHandleCount; Index++) {\r
286 Status = gBS->HandleProtocol (\r
287 PciIoHandleBuffer[Index],\r
288 &gEfiPciIoProtocolGuid,\r
289 (VOID **) &PciIo\r
290 );\r
291 ASSERT_EFI_ERROR (Status);\r
292 Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBusNumber, &PciDeviceNumber, &PciFunctionNumber);\r
293 ASSERT_EFI_ERROR (Status);\r
294 PciAddress = (UINT32) ((PciBusNumber << 20) | (PciDeviceNumber << 15) | (PciFunctionNumber << 12));\r
295 if (PciAddress == PcdGet32(PcdUsbXhciPciAddress)) {\r
296 //\r
297 // Found the PciIo for USB3 debug port.\r
298 //\r
299 DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
300 mUsb3Instance->InNotify = TRUE;\r
301 Usb3MapDmaBuffers (mUsb3Instance, PciIo);\r
302 mUsb3Instance->InNotify = FALSE;\r
303 gBS->CloseEvent ((EFI_EVENT) (UINTN) mUsb3Instance->PciIoEvent);\r
304 break;\r
305 }\r
306 }\r
307\r
308 gBS->FreePool (PciIoHandleBuffer);\r
309 }\r
310}\r
311\r
312/**\r
313 Return USB3 debug instance address.\r
314\r
315**/ \r
316USB3_DEBUG_PORT_HANDLE *\r
317GetUsb3DebugPortInstance (\r
318 VOID\r
319 )\r
320{\r
321 USB3_DEBUG_PORT_HANDLE *Instance;\r
322 EFI_PEI_HOB_POINTERS Hob;\r
323\r
324 Instance = NULL;\r
325\r
326 if (mUsb3Instance != NULL) {\r
327 Instance = mUsb3Instance;\r
328 goto Done;\r
329 }\r
330\r
331 Hob.Raw = GetFirstGuidHob (&gUsb3DbgGuid);\r
332 if (Hob.Raw != NULL) {\r
333 Instance = GET_GUID_HOB_DATA (Hob.Guid);\r
334 }\r
335\r
336Done:\r
337 if (Instance != NULL) {\r
338 DiscoverInitializeUsbDebugPort (Instance);\r
339 }\r
340 return Instance;\r
341}\r
342\r
2cb6eabe
EL
343/**\r
344 Allocate aligned memory for XHC's usage.\r
345\r
346 @param BufferSize The size, in bytes, of the Buffer.\r
347 \r
348 @return A pointer to the allocated buffer or NULL if allocation fails.\r
349\r
350**/\r
351VOID*\r
352AllocateAlignBuffer (\r
353 IN UINTN BufferSize\r
354 )\r
355{\r
95055567
ED
356 EFI_PHYSICAL_ADDRESS TmpAddr;\r
357 EFI_STATUS Status;\r
358 VOID *Buf;\r
2cb6eabe
EL
359 \r
360 Buf = NULL;\r
361 \r
362 if (gBS != NULL) {\r
95055567
ED
363 TmpAddr = 0xFFFFFFFF;\r
364 Status = gBS->AllocatePages (\r
365 AllocateMaxAddress,\r
366 EfiACPIMemoryNVS,\r
367 EFI_SIZE_TO_PAGES (BufferSize),\r
368 &TmpAddr\r
369 );\r
370 if (!EFI_ERROR (Status)) {\r
371 Buf = (VOID *) (UINTN) TmpAddr;\r
372 }\r
2cb6eabe
EL
373 }\r
374\r
375 return Buf;\r
376}\r
de8373fa
SZ
377\r
378/**\r
379 The constructor function initialize USB3 debug port.\r
380\r
381 @param ImageHandle The firmware allocated handle for the EFI image.\r
382 @param SystemTable A pointer to the EFI System Table.\r
383\r
384 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
385\r
386**/\r
387EFI_STATUS\r
388EFIAPI\r
389DebugCommunicationUsb3DxeConstructor (\r
390 IN EFI_HANDLE ImageHandle,\r
391 IN EFI_SYSTEM_TABLE *SystemTable\r
392 )\r
393{\r
394 USB3_DEBUG_PORT_HANDLE UsbDbg;\r
395 USB3_DEBUG_PORT_HANDLE *Instance;\r
396 EFI_PHYSICAL_ADDRESS Address;\r
397 EFI_STATUS Status;\r
398 EFI_EVENT Event;\r
399\r
400 Instance = GetUsb3DebugPortInstance ();\r
401\r
402 Status = EfiGetSystemConfigurationTable (&gUsb3DbgGuid, (VOID **) &mUsb3Instance);\r
403 if (!EFI_ERROR (Status)) {\r
404 goto Done;\r
405 }\r
406\r
407 if (Instance == NULL) {\r
408 //\r
409 // Initialize USB debug\r
410 //\r
411 ZeroMem (&UsbDbg, sizeof (UsbDbg));\r
412 UsbDbg.Initialized = USB3DBG_UNINITIALIZED;\r
413\r
414 DiscoverInitializeUsbDebugPort (&UsbDbg);\r
415\r
416 Instance = &UsbDbg;\r
417 }\r
418\r
419 //\r
420 // It is first time to run DXE instance, copy Instance from Hob to ACPINvs.\r
421 //\r
422 Address = SIZE_4GB;\r
423 Status = gBS->AllocatePages (\r
424 AllocateMaxAddress,\r
425 EfiACPIMemoryNVS,\r
426 EFI_SIZE_TO_PAGES (sizeof (USB3_DEBUG_PORT_HANDLE)),\r
427 &Address\r
428 );\r
429 if (EFI_ERROR (Status)) {\r
430 return Status;\r
431 }\r
432\r
433 CopyMem (\r
434 (VOID *)(UINTN)Address,\r
435 Instance,\r
436 sizeof (USB3_DEBUG_PORT_HANDLE)\r
437 );\r
438 mUsb3Instance = (USB3_DEBUG_PORT_HANDLE *)(UINTN)Address;\r
439\r
440 Status = gBS->InstallConfigurationTable (&gUsb3DbgGuid, mUsb3Instance);\r
441 if (EFI_ERROR (Status)) {\r
442 return Status;\r
443 }\r
444\r
445Done:\r
abea3bca 446 if (mUsb3Instance->Ready && (mUsb3Instance->PciIoEvent == 0)) {\r
de8373fa
SZ
447 Status = Usb3NamedEventListen (\r
448 &gEfiPciIoProtocolGuid,\r
449 TPL_NOTIFY,\r
450 Usb3PciIoNotify,\r
451 &Event\r
452 );\r
453 if (!EFI_ERROR (Status)) {\r
454 mUsb3Instance->PciIoEvent = (EFI_PHYSICAL_ADDRESS) (UINTN) Event;\r
455 }\r
456 }\r
457\r
458 return EFI_SUCCESS;\r
459}\r
460\r
461/**\r
462 The destructor function.\r
463\r
464 @param ImageHandle The firmware allocated handle for the EFI image.\r
465 @param SystemTable A pointer to the EFI System Table.\r
466\r
467 @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS.\r
468\r
469**/\r
470EFI_STATUS\r
471EFIAPI\r
472DebugCommunicationUsb3DxeDestructor (\r
473 IN EFI_HANDLE ImageHandle,\r
474 IN EFI_SYSTEM_TABLE *SystemTable\r
475 )\r
476{\r
477 if ((mUsb3Instance != NULL) && (mUsb3Instance->PciIoEvent != 0)) {\r
478 //\r
479 // Close the event created.\r
480 //\r
481 gBS->CloseEvent ((EFI_EVENT) (UINTN) mUsb3Instance->PciIoEvent);\r
482 mUsb3Instance->PciIoEvent = 0;\r
483 }\r
484 return EFI_SUCCESS;\r
485}\r
486\r