From 899c1020de7d1239891d61e15a034aa1b13a8381 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Tue, 27 Jun 2017 01:34:25 +0200 Subject: [PATCH 3/3] MdeModulePkg/TerminalDxe: fix OpenProtocol() usage The TerminalDriverBindingStart() function exploits the previous, non-standard behavior of edk2 that OpenProtocol() outputs the valid protocol Interface even when OpenProtocol() returns EFI_ALREADY_STARTED. This behavior has been deleted with commit 45cfcd8dccf8 ("MdeModulePkg/DxeCore: Fixed Interface returned by CoreOpenProtocol", 2017-06-23); Interface is no longer set on error (which conforms to the UEFI spec). As a result, when the OpenProtocol() calls in TerminalDriverBindingStart() fail with EFI_ALREADY_STARTED, ParentDevicePath and SerialIo have uninitialized (indeterminate) values, leading to a failed assertion later. Restore the previous behavior of TerminalDriverBindingStart() by explicitly getting the protocol interfaces with EFI_OPEN_PROTOCOL_GET_PROTOCOL. Cc: "Gabriel L. Somlo" Cc: Amit Kumar Cc: Eric Dong Cc: Liming Gao Cc: Star Zeng Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek --- .../Universal/Console/TerminalDxe/Terminal.c | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c index c90879b0dd87..16fe6de21f1e 100644 --- a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c +++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c @@ -508,36 +508,50 @@ TerminalDriverBindingStart ( UINTN EntryCount; UINTN Index; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput; EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextInput; EFI_UNICODE_STRING_TABLE *ControllerNameTable; // // Get the Device Path Protocol to build the device path of the child device // Status = gBS->OpenProtocol ( Controller, &gEfiDevicePathProtocolGuid, (VOID **) &ParentDevicePath, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED)); + if (Status == EFI_ALREADY_STARTED) { + // + // Repeat the above OpenProtocol() call with GET_PROTOCOL. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + ASSERT_EFI_ERROR (Status); + } // // Open the Serial I/O Protocol BY_DRIVER. It might already be started. // Status = gBS->OpenProtocol ( Controller, &gEfiSerialIoProtocolGuid, (VOID **) &SerialIo, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED)); if (!IsHotPlugDevice (ParentDevicePath)) { // // if the serial device is a hot plug device, do not update the // ConInDev, ConOutDev, and StdErrDev variables. @@ -549,36 +563,49 @@ TerminalDriverBindingStart ( // // Do not create any child for END remaining device path. // if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) { return EFI_SUCCESS; } if (Status == EFI_ALREADY_STARTED) { if (RemainingDevicePath == NULL) { // // If RemainingDevicePath is NULL or is the End of Device Path Node // return EFI_SUCCESS; } // + // Repeat the above OpenProtocol() call with GET_PROTOCOL. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiSerialIoProtocolGuid, + (VOID **) &SerialIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + ASSERT_EFI_ERROR (Status); + + // // This driver can only produce one child per serial port. // Change its terminal type as remaining device path requests. // Status = gBS->OpenProtocolInformation ( Controller, &gEfiSerialIoProtocolGuid, &OpenInfoBuffer, &EntryCount ); if (!EFI_ERROR (Status)) { Status = EFI_NOT_FOUND; for (Index = 0; Index < EntryCount; Index++) { if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { Status = gBS->OpenProtocol ( OpenInfoBuffer[Index].ControllerHandle, &gEfiSimpleTextInProtocolGuid, (VOID **) &SimpleTextInput, This->DriverBindingHandle, @@ -850,36 +877,41 @@ FreeResources: } if (TerminalDevice->TerminalConsoleModeData != NULL) { FreePool (TerminalDevice->TerminalConsoleModeData); } FreePool (TerminalDevice); CloseProtocols: // // Remove Parent Device Path from // the Console Device Environment Variables // TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath); TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath); TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath); + // + // Closing the protocol interfaces opened with BY_DRIVER is required. Closing + // the protocol interfaces opened with GET_PROTOCOL is not required but + // permitted. + // Status = gBS->CloseProtocol ( Controller, &gEfiSerialIoProtocolGuid, This->DriverBindingHandle, Controller ); ASSERT_EFI_ERROR (Status); Status = gBS->CloseProtocol ( Controller, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, Controller ); ASSERT_EFI_ERROR (Status); return Status; } -- 2.13.1.3.g8be5a757fa67