]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/DebugPortDxe/DebugPort.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / DebugPortDxe / DebugPort.c
1 /** @file
2 Top level C file for debugport driver. Contains initialization function.
3 This driver layers on top of SerialIo.
4 ALL CODE IN THE SERIALIO STACK MUST BE RE-ENTRANT AND CALLABLE FROM
5 INTERRUPT CONTEXT
6
7 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10 **/
11
12 #include "DebugPort.h"
13
14 //
15 // Globals
16 //
17 EFI_DRIVER_BINDING_PROTOCOL gDebugPortDriverBinding = {
18 DebugPortSupported,
19 DebugPortStart,
20 DebugPortStop,
21 DEBUGPORT_DRIVER_VERSION,
22 NULL,
23 NULL
24 };
25
26 DEBUGPORT_DEVICE mDebugPortDevice = {
27 DEBUGPORT_DEVICE_SIGNATURE,
28 (EFI_HANDLE)0,
29 (EFI_HANDLE)0,
30 (EFI_DEVICE_PATH_PROTOCOL *)NULL,
31 {
32 DebugPortReset,
33 DebugPortWrite,
34 DebugPortRead,
35 DebugPortPoll
36 },
37 (EFI_HANDLE)0,
38 (EFI_SERIAL_IO_PROTOCOL *)NULL,
39 DEBUGPORT_UART_DEFAULT_BAUDRATE,
40 DEBUGPORT_UART_DEFAULT_FIFO_DEPTH,
41 DEBUGPORT_UART_DEFAULT_TIMEOUT,
42 (EFI_PARITY_TYPE)DEBUGPORT_UART_DEFAULT_PARITY,
43 DEBUGPORT_UART_DEFAULT_DATA_BITS,
44 (EFI_STOP_BITS_TYPE)DEBUGPORT_UART_DEFAULT_STOP_BITS
45 };
46
47 /**
48 Local worker function to obtain device path information from DebugPort variable.
49
50 Records requested settings in DebugPort device structure.
51
52 **/
53 EFI_DEVICE_PATH_PROTOCOL *
54 GetDebugPortVariable (
55 VOID
56 )
57 {
58 UINTN DataSize;
59 EFI_DEVICE_PATH_PROTOCOL *DebugPortVariable;
60 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
61
62 GetVariable2 (EFI_DEBUGPORT_VARIABLE_NAME, &gEfiDebugPortVariableGuid, (VOID **)&DebugPortVariable, &DataSize);
63 if (DebugPortVariable == NULL) {
64 return NULL;
65 }
66
67 DevicePath = DebugPortVariable;
68 while (!IsDevicePathEnd (DevicePath) && !IS_UART_DEVICEPATH (DevicePath)) {
69 DevicePath = NextDevicePathNode (DevicePath);
70 }
71
72 if (IsDevicePathEnd (DevicePath)) {
73 FreePool (DebugPortVariable);
74 return NULL;
75 } else {
76 CopyMem (
77 &mDebugPortDevice.BaudRate,
78 &((UART_DEVICE_PATH *)DevicePath)->BaudRate,
79 sizeof (((UART_DEVICE_PATH *)DevicePath)->BaudRate)
80 );
81 mDebugPortDevice.ReceiveFifoDepth = DEBUGPORT_UART_DEFAULT_FIFO_DEPTH;
82 mDebugPortDevice.Timeout = DEBUGPORT_UART_DEFAULT_TIMEOUT;
83 CopyMem (
84 &mDebugPortDevice.Parity,
85 &((UART_DEVICE_PATH *)DevicePath)->Parity,
86 sizeof (((UART_DEVICE_PATH *)DevicePath)->Parity)
87 );
88 CopyMem (
89 &mDebugPortDevice.DataBits,
90 &((UART_DEVICE_PATH *)DevicePath)->DataBits,
91 sizeof (((UART_DEVICE_PATH *)DevicePath)->DataBits)
92 );
93 CopyMem (
94 &mDebugPortDevice.StopBits,
95 &((UART_DEVICE_PATH *)DevicePath)->StopBits,
96 sizeof (((UART_DEVICE_PATH *)DevicePath)->StopBits)
97 );
98 return DebugPortVariable;
99 }
100 }
101
102 /**
103 Debug Port Driver entry point.
104
105 Reads DebugPort variable to determine what device and settings to use as the
106 debug port. Binds exclusively to SerialIo. Reverts to defaults if no variable
107 is found.
108
109 @param[in] ImageHandle The firmware allocated handle for the EFI image.
110 @param[in] SystemTable A pointer to the EFI System Table.
111
112 @retval EFI_SUCCESS The entry point is executed successfully.
113 @retval EFI_OUT_OF_RESOURCES Fails to allocate memory for device.
114 @retval other Some error occurs when executing this entry point.
115
116 **/
117 EFI_STATUS
118 EFIAPI
119 InitializeDebugPortDriver (
120 IN EFI_HANDLE ImageHandle,
121 IN EFI_SYSTEM_TABLE *SystemTable
122 )
123 {
124 EFI_STATUS Status;
125
126 //
127 // Install driver model protocol(s).
128 //
129 Status = EfiLibInstallDriverBindingComponentName2 (
130 ImageHandle,
131 SystemTable,
132 &gDebugPortDriverBinding,
133 ImageHandle,
134 &gDebugPortComponentName,
135 &gDebugPortComponentName2
136 );
137 ASSERT_EFI_ERROR (Status);
138
139 return Status;
140 }
141
142 /**
143 Checks to see if there's not already a DebugPort interface somewhere.
144
145 If there's a DEBUGPORT variable, the device path must match exactly. If there's
146 no DEBUGPORT variable, then device path is not checked and does not matter.
147 Checks to see that there's a serial io interface on the controller handle
148 that can be bound BY_DRIVER | EXCLUSIVE.
149 If all these tests succeed, then we return EFI_SUCCESS, else, EFI_UNSUPPORTED
150 or other error returned by OpenProtocol.
151
152 @param This Protocol instance pointer.
153 @param ControllerHandle Handle of device to test.
154 @param RemainingDevicePath Optional parameter use to pick a specific child
155 device to start.
156
157 @retval EFI_SUCCESS This driver supports this device.
158 @retval EFI_UNSUPPORTED Debug Port device is not supported.
159 @retval EFI_OUT_OF_RESOURCES Fails to allocate memory for device.
160 @retval others Some error occurs.
161
162 **/
163 EFI_STATUS
164 EFIAPI
165 DebugPortSupported (
166 IN EFI_DRIVER_BINDING_PROTOCOL *This,
167 IN EFI_HANDLE ControllerHandle,
168 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
169 )
170 {
171 EFI_STATUS Status;
172 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
173 EFI_DEVICE_PATH_PROTOCOL *DebugPortVariable;
174 EFI_SERIAL_IO_PROTOCOL *SerialIo;
175 EFI_DEBUGPORT_PROTOCOL *DebugPortInterface;
176 EFI_HANDLE TempHandle;
177
178 //
179 // Check to see that there's not a debugport protocol already published,
180 // since only one standard UART serial port could be supported by this driver.
181 //
182 if (gBS->LocateProtocol (&gEfiDebugPortProtocolGuid, NULL, (VOID **)&DebugPortInterface) != EFI_NOT_FOUND) {
183 return EFI_UNSUPPORTED;
184 }
185
186 //
187 // Read DebugPort variable to determine debug port selection and parameters
188 //
189 DebugPortVariable = GetDebugPortVariable ();
190
191 if (DebugPortVariable != NULL) {
192 //
193 // There's a DEBUGPORT variable, so do LocateDevicePath and check to see if
194 // the closest matching handle matches the controller handle, and if it does,
195 // check to see that the remaining device path has the DebugPort GUIDed messaging
196 // device path only. Otherwise, it's a mismatch and EFI_UNSUPPORTED is returned.
197 //
198 DevicePath = DebugPortVariable;
199 Status = gBS->LocateDevicePath (
200 &gEfiSerialIoProtocolGuid,
201 &DevicePath,
202 &TempHandle
203 );
204
205 if ((Status == EFI_SUCCESS) && (TempHandle != ControllerHandle)) {
206 Status = EFI_UNSUPPORTED;
207 }
208
209 if ((Status == EFI_SUCCESS) &&
210 ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
211 (DevicePath->SubType != MSG_VENDOR_DP) ||
212 (*((UINT16 *)DevicePath->Length) != sizeof (DEBUGPORT_DEVICE_PATH))))
213 {
214 Status = EFI_UNSUPPORTED;
215 }
216
217 if ((Status == EFI_SUCCESS) && !CompareGuid (&gEfiDebugPortDevicePathGuid, (GUID *)(DevicePath + 1))) {
218 Status = EFI_UNSUPPORTED;
219 }
220
221 FreePool (DebugPortVariable);
222 if (EFI_ERROR (Status)) {
223 return Status;
224 }
225 }
226
227 Status = gBS->OpenProtocol (
228 ControllerHandle,
229 &gEfiSerialIoProtocolGuid,
230 (VOID **)&SerialIo,
231 This->DriverBindingHandle,
232 ControllerHandle,
233 EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE
234 );
235 if (EFI_ERROR (Status)) {
236 return Status;
237 }
238
239 Status = gBS->CloseProtocol (
240 ControllerHandle,
241 &gEfiSerialIoProtocolGuid,
242 This->DriverBindingHandle,
243 ControllerHandle
244 );
245
246 return Status;
247 }
248
249 /**
250 Binds exclusively to serial io on the controller handle, Produces DebugPort
251 protocol and DevicePath on new handle.
252
253 @param This Protocol instance pointer.
254 @param ControllerHandle Handle of device to bind driver to.
255 @param RemainingDevicePath Optional parameter use to pick a specific child
256 device to start.
257
258 @retval EFI_SUCCESS This driver is added to ControllerHandle.
259 @retval EFI_OUT_OF_RESOURCES Fails to allocate memory for device.
260 @retval others Some error occurs.
261
262 **/
263 EFI_STATUS
264 EFIAPI
265 DebugPortStart (
266 IN EFI_DRIVER_BINDING_PROTOCOL *This,
267 IN EFI_HANDLE ControllerHandle,
268 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
269 )
270 {
271 EFI_STATUS Status;
272 DEBUGPORT_DEVICE_PATH DebugPortDP;
273 EFI_DEVICE_PATH_PROTOCOL EndDP;
274 EFI_DEVICE_PATH_PROTOCOL *Dp1;
275
276 Status = gBS->OpenProtocol (
277 ControllerHandle,
278 &gEfiSerialIoProtocolGuid,
279 (VOID **)&mDebugPortDevice.SerialIoBinding,
280 This->DriverBindingHandle,
281 ControllerHandle,
282 EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE
283 );
284 if (EFI_ERROR (Status)) {
285 return Status;
286 }
287
288 mDebugPortDevice.SerialIoDeviceHandle = ControllerHandle;
289
290 //
291 // Initialize the Serial Io interface...
292 //
293 Status = mDebugPortDevice.SerialIoBinding->SetAttributes (
294 mDebugPortDevice.SerialIoBinding,
295 mDebugPortDevice.BaudRate,
296 mDebugPortDevice.ReceiveFifoDepth,
297 mDebugPortDevice.Timeout,
298 mDebugPortDevice.Parity,
299 mDebugPortDevice.DataBits,
300 mDebugPortDevice.StopBits
301 );
302 if (EFI_ERROR (Status)) {
303 mDebugPortDevice.BaudRate = 0;
304 mDebugPortDevice.Parity = DefaultParity;
305 mDebugPortDevice.DataBits = 0;
306 mDebugPortDevice.StopBits = DefaultStopBits;
307 mDebugPortDevice.ReceiveFifoDepth = 0;
308 Status = mDebugPortDevice.SerialIoBinding->SetAttributes (
309 mDebugPortDevice.SerialIoBinding,
310 mDebugPortDevice.BaudRate,
311 mDebugPortDevice.ReceiveFifoDepth,
312 mDebugPortDevice.Timeout,
313 mDebugPortDevice.Parity,
314 mDebugPortDevice.DataBits,
315 mDebugPortDevice.StopBits
316 );
317 if (EFI_ERROR (Status)) {
318 gBS->CloseProtocol (
319 ControllerHandle,
320 &gEfiSerialIoProtocolGuid,
321 This->DriverBindingHandle,
322 ControllerHandle
323 );
324 return Status;
325 }
326 }
327
328 mDebugPortDevice.SerialIoBinding->Reset (mDebugPortDevice.SerialIoBinding);
329
330 //
331 // Create device path instance for DebugPort
332 //
333 DebugPortDP.Header.Type = MESSAGING_DEVICE_PATH;
334 DebugPortDP.Header.SubType = MSG_VENDOR_DP;
335 SetDevicePathNodeLength (&(DebugPortDP.Header), sizeof (DebugPortDP));
336 CopyGuid (&DebugPortDP.Guid, &gEfiDebugPortDevicePathGuid);
337
338 Dp1 = DevicePathFromHandle (ControllerHandle);
339 if (Dp1 == NULL) {
340 Dp1 = &EndDP;
341 SetDevicePathEndNode (Dp1);
342 }
343
344 mDebugPortDevice.DebugPortDevicePath = AppendDevicePathNode (Dp1, (EFI_DEVICE_PATH_PROTOCOL *)&DebugPortDP);
345 if (mDebugPortDevice.DebugPortDevicePath == NULL) {
346 return EFI_OUT_OF_RESOURCES;
347 }
348
349 //
350 // Publish DebugPort and Device Path protocols
351 //
352 Status = gBS->InstallMultipleProtocolInterfaces (
353 &mDebugPortDevice.DebugPortDeviceHandle,
354 &gEfiDevicePathProtocolGuid,
355 mDebugPortDevice.DebugPortDevicePath,
356 &gEfiDebugPortProtocolGuid,
357 &mDebugPortDevice.DebugPortInterface,
358 NULL
359 );
360
361 if (EFI_ERROR (Status)) {
362 gBS->CloseProtocol (
363 ControllerHandle,
364 &gEfiSerialIoProtocolGuid,
365 This->DriverBindingHandle,
366 ControllerHandle
367 );
368 return Status;
369 }
370
371 //
372 // Connect debugport child to serial io
373 //
374 Status = gBS->OpenProtocol (
375 ControllerHandle,
376 &gEfiSerialIoProtocolGuid,
377 (VOID **)&mDebugPortDevice.SerialIoBinding,
378 This->DriverBindingHandle,
379 mDebugPortDevice.DebugPortDeviceHandle,
380 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
381 );
382
383 if (EFI_ERROR (Status)) {
384 gBS->CloseProtocol (
385 ControllerHandle,
386 &gEfiSerialIoProtocolGuid,
387 This->DriverBindingHandle,
388 ControllerHandle
389 );
390 return Status;
391 }
392
393 return EFI_SUCCESS;
394 }
395
396 /**
397 Stop this driver on ControllerHandle by removing Serial IO protocol on
398 the ControllerHandle.
399
400 @param This Protocol instance pointer.
401 @param ControllerHandle Handle of device to stop driver on
402 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
403 children is zero stop the entire bus driver.
404 @param ChildHandleBuffer List of Child Handles to Stop.
405
406 @retval EFI_SUCCESS This driver is removed ControllerHandle.
407 @retval other This driver was not removed from this device.
408
409 **/
410 EFI_STATUS
411 EFIAPI
412 DebugPortStop (
413 IN EFI_DRIVER_BINDING_PROTOCOL *This,
414 IN EFI_HANDLE ControllerHandle,
415 IN UINTN NumberOfChildren,
416 IN EFI_HANDLE *ChildHandleBuffer
417 )
418 {
419 EFI_STATUS Status;
420
421 if (NumberOfChildren == 0) {
422 //
423 // Close the bus driver
424 //
425 gBS->CloseProtocol (
426 ControllerHandle,
427 &gEfiSerialIoProtocolGuid,
428 This->DriverBindingHandle,
429 ControllerHandle
430 );
431
432 mDebugPortDevice.SerialIoBinding = NULL;
433
434 gBS->CloseProtocol (
435 ControllerHandle,
436 &gEfiDevicePathProtocolGuid,
437 This->DriverBindingHandle,
438 ControllerHandle
439 );
440
441 FreePool (mDebugPortDevice.DebugPortDevicePath);
442
443 return EFI_SUCCESS;
444 } else {
445 //
446 // Disconnect SerialIo child handle
447 //
448 Status = gBS->CloseProtocol (
449 mDebugPortDevice.SerialIoDeviceHandle,
450 &gEfiSerialIoProtocolGuid,
451 This->DriverBindingHandle,
452 mDebugPortDevice.DebugPortDeviceHandle
453 );
454
455 if (EFI_ERROR (Status)) {
456 return Status;
457 }
458
459 //
460 // Unpublish our protocols (DevicePath, DebugPort)
461 //
462 Status = gBS->UninstallMultipleProtocolInterfaces (
463 mDebugPortDevice.DebugPortDeviceHandle,
464 &gEfiDevicePathProtocolGuid,
465 mDebugPortDevice.DebugPortDevicePath,
466 &gEfiDebugPortProtocolGuid,
467 &mDebugPortDevice.DebugPortInterface,
468 NULL
469 );
470
471 if (EFI_ERROR (Status)) {
472 gBS->OpenProtocol (
473 ControllerHandle,
474 &gEfiSerialIoProtocolGuid,
475 (VOID **)&mDebugPortDevice.SerialIoBinding,
476 This->DriverBindingHandle,
477 mDebugPortDevice.DebugPortDeviceHandle,
478 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
479 );
480 } else {
481 mDebugPortDevice.DebugPortDeviceHandle = NULL;
482 }
483 }
484
485 return Status;
486 }
487
488 /**
489 DebugPort protocol member function. Calls SerialIo:GetControl to flush buffer.
490 We cannot call SerialIo:SetAttributes because it uses pool services, which use
491 locks, which affect TPL, so it's not interrupt context safe or re-entrant.
492 SerialIo:Reset() calls SetAttributes, so it can't be used either.
493
494 The port itself should be fine since it was set up during initialization.
495
496 @param This Protocol instance pointer.
497
498 @return EFI_SUCCESS Always.
499
500 **/
501 EFI_STATUS
502 EFIAPI
503 DebugPortReset (
504 IN EFI_DEBUGPORT_PROTOCOL *This
505 )
506 {
507 UINTN BufferSize;
508 UINTN BitBucket;
509
510 while (This->Poll (This) == EFI_SUCCESS) {
511 BufferSize = 1;
512 This->Read (This, 0, &BufferSize, &BitBucket);
513 }
514
515 return EFI_SUCCESS;
516 }
517
518 /**
519 DebugPort protocol member function. Calls SerialIo:Read() after setting
520 if it's different than the last SerialIo access.
521
522 @param This Pointer to DebugPort protocol.
523 @param Timeout Timeout value.
524 @param BufferSize On input, the size of Buffer.
525 On output, the amount of data actually written.
526 @param Buffer Pointer to buffer to read.
527
528 @retval EFI_SUCCESS
529 @retval others
530
531 **/
532 EFI_STATUS
533 EFIAPI
534 DebugPortRead (
535 IN EFI_DEBUGPORT_PROTOCOL *This,
536 IN UINT32 Timeout,
537 IN OUT UINTN *BufferSize,
538 IN VOID *Buffer
539 )
540 {
541 DEBUGPORT_DEVICE *DebugPortDevice;
542 UINTN LocalBufferSize;
543 EFI_STATUS Status;
544 UINT8 *BufferPtr;
545
546 DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This);
547 BufferPtr = Buffer;
548 LocalBufferSize = *BufferSize;
549
550 do {
551 Status = DebugPortDevice->SerialIoBinding->Read (
552 DebugPortDevice->SerialIoBinding,
553 &LocalBufferSize,
554 BufferPtr
555 );
556 if (Status == EFI_TIMEOUT) {
557 if (Timeout > DEBUGPORT_UART_DEFAULT_TIMEOUT) {
558 Timeout -= DEBUGPORT_UART_DEFAULT_TIMEOUT;
559 } else {
560 Timeout = 0;
561 }
562 } else if (EFI_ERROR (Status)) {
563 break;
564 }
565
566 BufferPtr += LocalBufferSize;
567 LocalBufferSize = *BufferSize - (BufferPtr - (UINT8 *)Buffer);
568 } while (LocalBufferSize != 0 && Timeout > 0);
569
570 *BufferSize = (UINTN)BufferPtr - (UINTN)Buffer;
571
572 return Status;
573 }
574
575 /**
576 DebugPort protocol member function. Calls SerialIo:Write() Writes 8 bytes at
577 a time and does a GetControl between 8 byte writes to help insure reads are
578 interspersed This is poor-man's flow control.
579
580 @param This Pointer to DebugPort protocol.
581 @param Timeout Timeout value.
582 @param BufferSize On input, the size of Buffer.
583 On output, the amount of data actually written.
584 @param Buffer Pointer to buffer to read.
585
586 @retval EFI_SUCCESS The data was written.
587 @retval others Fails when writting datas to debug port device.
588
589 **/
590 EFI_STATUS
591 EFIAPI
592 DebugPortWrite (
593 IN EFI_DEBUGPORT_PROTOCOL *This,
594 IN UINT32 Timeout,
595 IN OUT UINTN *BufferSize,
596 OUT VOID *Buffer
597 )
598 {
599 DEBUGPORT_DEVICE *DebugPortDevice;
600 UINTN Position;
601 UINTN WriteSize;
602 EFI_STATUS Status;
603 UINT32 SerialControl;
604
605 Status = EFI_SUCCESS;
606 DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This);
607
608 WriteSize = 8;
609 for (Position = 0; Position < *BufferSize && !EFI_ERROR (Status); Position += WriteSize) {
610 DebugPortDevice->SerialIoBinding->GetControl (
611 DebugPortDevice->SerialIoBinding,
612 &SerialControl
613 );
614 if (*BufferSize - Position < 8) {
615 WriteSize = *BufferSize - Position;
616 }
617
618 Status = DebugPortDevice->SerialIoBinding->Write (
619 DebugPortDevice->SerialIoBinding,
620 &WriteSize,
621 &((UINT8 *)Buffer)[Position]
622 );
623 }
624
625 *BufferSize = Position;
626 return Status;
627 }
628
629 /**
630 DebugPort protocol member function. Calls SerialIo:Write() after setting
631 if it's different than the last SerialIo access.
632
633 @param This Pointer to DebugPort protocol.
634
635 @retval EFI_SUCCESS At least 1 character is ready to be read from
636 the DebugPort interface.
637 @retval EFI_NOT_READY There are no characters ready to read from the
638 DebugPort interface
639 @retval EFI_DEVICE_ERROR A hardware failure occurred... (from SerialIo)
640
641 **/
642 EFI_STATUS
643 EFIAPI
644 DebugPortPoll (
645 IN EFI_DEBUGPORT_PROTOCOL *This
646 )
647 {
648 EFI_STATUS Status;
649 UINT32 SerialControl;
650 DEBUGPORT_DEVICE *DebugPortDevice;
651
652 DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This);
653
654 Status = DebugPortDevice->SerialIoBinding->GetControl (
655 DebugPortDevice->SerialIoBinding,
656 &SerialControl
657 );
658
659 if (!EFI_ERROR (Status)) {
660 if ((SerialControl & EFI_SERIAL_INPUT_BUFFER_EMPTY) != 0) {
661 Status = EFI_NOT_READY;
662 } else {
663 Status = EFI_SUCCESS;
664 }
665 }
666
667 return Status;
668 }
669
670 /**
671 Unload function that is registered in the LoadImage protocol. It un-installs
672 protocols produced and deallocates pool used by the driver. Called by the core
673 when unloading the driver.
674
675 @param ImageHandle
676
677 @retval EFI_SUCCESS Unload Debug Port driver successfully.
678 @retval EFI_ABORTED Serial IO is still binding.
679
680 **/
681 EFI_STATUS
682 EFIAPI
683 ImageUnloadHandler (
684 EFI_HANDLE ImageHandle
685 )
686 {
687 EFI_STATUS Status;
688 VOID *ComponentName;
689 VOID *ComponentName2;
690
691 if (mDebugPortDevice.SerialIoBinding != NULL) {
692 return EFI_ABORTED;
693 }
694
695 //
696 // Driver is stopped already.
697 //
698 Status = gBS->HandleProtocol (ImageHandle, &gEfiComponentNameProtocolGuid, &ComponentName);
699 if (EFI_ERROR (Status)) {
700 ComponentName = NULL;
701 }
702
703 Status = gBS->HandleProtocol (ImageHandle, &gEfiComponentName2ProtocolGuid, &ComponentName2);
704 if (EFI_ERROR (Status)) {
705 ComponentName2 = NULL;
706 }
707
708 if (ComponentName == NULL) {
709 if (ComponentName2 == NULL) {
710 Status = gBS->UninstallMultipleProtocolInterfaces (
711 ImageHandle,
712 &gEfiDriverBindingProtocolGuid,
713 &gDebugPortDriverBinding,
714 NULL
715 );
716 } else {
717 Status = gBS->UninstallMultipleProtocolInterfaces (
718 ImageHandle,
719 &gEfiDriverBindingProtocolGuid,
720 &gDebugPortDriverBinding,
721 &gEfiComponentName2ProtocolGuid,
722 ComponentName2,
723 NULL
724 );
725 }
726 } else {
727 if (ComponentName2 == NULL) {
728 Status = gBS->UninstallMultipleProtocolInterfaces (
729 ImageHandle,
730 &gEfiDriverBindingProtocolGuid,
731 &gDebugPortDriverBinding,
732 &gEfiComponentNameProtocolGuid,
733 ComponentName,
734 NULL
735 );
736 } else {
737 Status = gBS->UninstallMultipleProtocolInterfaces (
738 ImageHandle,
739 &gEfiDriverBindingProtocolGuid,
740 &gDebugPortDriverBinding,
741 &gEfiComponentNameProtocolGuid,
742 ComponentName,
743 &gEfiComponentName2ProtocolGuid,
744 ComponentName2,
745 NULL
746 );
747 }
748 }
749
750 return Status;
751 }