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