/** @file CrLegacySupport ;****************************************************************************** ;* Copyright (c) 2012 - 2017, Insyde Software Corp. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** */ #include "CrLegacySupport.h" #include "CrBdaMemManager.h" #include "CrServiceMisc.h" #include #include EFI_CONSOLE_REDIRECTION_SERVICE_PROTOCOL *gCrService = NULL; EFI_CONSOLE_REDIRECTION_INFO *gCrInfo = NULL; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *mRootBridgeIo = NULL; EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *mLegacyBiosPlatformProtocol = NULL; CR_EFI_MEM_MANAGER *mCrEbdaMemManager = NULL; EFI_LEGACY_BIOS_PROTOCOL *mLegacyBios = NULL; EFI_EVENT mLegacyBootEvent; EFI_LEGACY_BIOS_PLATFORM_HOOKS mPlatformHooks; EFI_CONSOLE_REDIRECTION_OPROM_INFO_PROTOCOL mCrOpROMInfo = {0}; UINT32 mLastEbda = 0; UINT8 mUartUid = 0; // // Baud Rate Divisor. Baud Rate 1200 Divisor = 115200/1200 = 96 // static UINT16 mBaudRateDivisor [] = {96, 48, 24, 12, 6, 3, 2, 1 }; // // This table use for translate CrInfo terminal type to EBdaCrInfo's TerminalType // This table is depend on AdvanceVfr.vfr (vt100=Bit0 vt100P=Bit1 vt-utf8=Bit2 pc-ansi=Bit3) // static UINT8 gTerminalFlagTable [] = {TP_VT100, TP_VT100P, TP_VTUTF8, TP_PCANSI}; BOOLEAN IsUartFlowControlNode ( IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl ) { return (BOOLEAN) ( (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) && (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid)) ); } UINT8 SupportFlowControl ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { UART_FLOW_CONTROL_DEVICE_PATH *FlowControl; while (!IsDevicePathEnd (DevicePath)) { if (IsUartFlowControlNode ((UART_FLOW_CONTROL_DEVICE_PATH *) DevicePath)) { FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *)DevicePath; return (UINT8)(ReadUnaligned32 (&FlowControl->FlowControlMap)); } DevicePath = NextDevicePathNode (DevicePath); } return 0; } UINT8 CrGetUartUid ( IN EFI_CONSOLE_REDIRECTION_OPROM_INFO_PROTOCOL *This ) { return mUartUid++; } CR_COMMON_AREA_INFO* GetCrCommonArea ( IN EFI_CONSOLE_REDIRECTION_OPROM_INFO_PROTOCOL *This ) { CR_EFI_MEM_MANAGER *CrEfiMemManager; UINT32 Ebda; UINT8 BiosPhase; UINT32 Signature; UINT32 EbdaBlock; if (This->CrOpROMInstalled) { Ebda = (UINTN)((*(UINT16*)(UINTN)0x40e) << 4); BiosPhase = EBDA_DATA(BIOS_PHASE, UINT8); if (BiosPhase == BIOS_PHASE_DOS_RUNING || BiosPhase == BIOS_PHASE_OPROM_RUNING || BiosPhase == BIOS_PHASE_OPROM) { return NULL; } if (mLastEbda != Ebda) { mCrEbdaMemManager = NULL; mLastEbda = Ebda; } // // Search CROpROM allocated EBDA memory // if (mCrEbdaMemManager == NULL) { for (EbdaBlock = 0; EbdaBlock < (0xA0000 - Ebda); EbdaBlock+=0x400) { Signature = EBDA_DATA(EbdaBlock, UINT32); if (Signature == CR_MEM_MANAGER_SIGNATURE) { mCrEbdaMemManager = (CR_EFI_MEM_MANAGER *)(UINTN)(((*(UINT16*)(UINTN)0x40e) << 4) + (EbdaBlock)); break; } } } if (mCrEbdaMemManager != NULL) { // // Return CR Common Area // return (CR_COMMON_AREA_INFO *)((UINTN)mCrEbdaMemManager + (UINTN)mCrEbdaMemManager->CommonAreaOffset); } } else { if (mCrMemStart != 0) { CrEfiMemManager = (CR_EFI_MEM_MANAGER *)(UINTN)mCrMemStart; return (CR_COMMON_AREA_INFO *)(UINTN)(mCrMemStart + CrEfiMemManager->CommonAreaOffset); } } return NULL; } /** Clear UART IER Register to disable UART interrupt **/ VOID ClearUartIer ( VOID ) { UINTN Index; if (gCrInfo == NULL) { return; } for (Index = 0; Index < gCrInfo->DeviceCount; Index++) { gCrInfo->CRDevice[Index].Uart16550protocol->RegWrite( gCrInfo->CRDevice[Index].Uart16550protocol, UART_IER_OFFSET, 0 ); } } /** Set interrupt of UART device @param EnableIntr Enable or disable UART interrupt **/ VOID SetSerialInterrupt ( IN UINT8 EnableIntr ) { H2O_UART_16550_ACCESS_PROTOCOL *UartProtocol; CR_COMMON_AREA_INFO *CrOpromInfo; UINT64 PciAddress; UINT16 u16; UINT8 u8; UINTN Index; if (gCrInfo == NULL) { return; } u16 = 0; u8 = 0; CrOpromInfo = NULL; for (Index = 0; Index < gCrInfo->DeviceCount; Index++) { UartProtocol = gCrInfo->CRDevice[Index].Uart16550protocol; switch (gCrInfo->CRDevice[Index].Type) { case ISA_SERIAL_DEVICE: UartProtocol->RegRead (UartProtocol, UART_MCR_OFFSET, &u8); if (EnableIntr) { u8 = u8 | UART_MCR_OUT2_BIT; } else { u8 = u8 & ~UART_MCR_OUT2_BIT; } UartProtocol->RegWrite(UartProtocol, UART_MCR_OFFSET, u8); break; case PCI_SERIAL_DEVICE: case PCI_HS_SERIAL_DEVICE: u16 = gCrInfo->CRDevice[Index].Uart16550protocol->DeviceInfo->UID; PciAddress = EFI_PCI_ADDRESS (GET_BUS(u16), GET_DEV(u16), GET_FUN(u16), PCI_CONFIG_COMMAND_WORD); mRootBridgeIo->Pci.Read (mRootBridgeIo, EfiPciWidthUint16, PciAddress, 1, &u16); if (EnableIntr) { u16 = u16 & ~PCI_CONFIG_DISABLE_INTERRUPT; u16 = u16 | PCI_CONFIG_BUS_MASTER; } else { u16 = u16 | PCI_CONFIG_DISABLE_INTERRUPT; u16 = u16 & ~PCI_CONFIG_BUS_MASTER; } mRootBridgeIo->Pci.Write (mRootBridgeIo, EfiPciWidthUint16, PciAddress, 1, &u16); break; default: break; } } } /** Enable interrupt of UART device **/ VOID EnableSerialInterrupt ( VOID ) { SetSerialInterrupt (1); } /** Disable interrupt of UART device **/ VOID DisableSerialInterrupt ( VOID ) { SetSerialInterrupt (0); // // Due to some UART device can't be disable interrupt by SetSerialInterrupt (0) // So, we need clear IER register setting to ensure UART device interrupt disable // ClearUartIer (); } /** Translate Esc Sequence Code into KeyBoard scan code @param TerminalEscCode Pointer to Terminal ESC Sequence Code protocol @param EscTableIndex Index of Terminal ESC Sequence Code @retval return translate result **/ UINT8 TranslateEfiScanCode ( IN EFI_TERMINAL_ESC_CODE_PROTOCOL *TerminalEscCode, IN UINTN EscTableIndex ) { EFI_TO_KB_SCANCODE_MAP *pScanCodeMap; ESC_SEQUENCE_CODE *pEscSeqCode; UINT8 DataType; UINTN Index; DataType = TerminalEscCode->EscSequenceCode[EscTableIndex].DataType; if ((DataType == ESC_CODE_SCANCODE) || (DataType == ESC_CODE_EXTENTION)) { pEscSeqCode = TerminalEscCode->EscSequenceCode; pScanCodeMap = TerminalEscCode->EfiToKbScanCode; for (Index = 0; pScanCodeMap[Index].EfiScanCode != 0; Index++) { if (pScanCodeMap[Index].EfiScanCode == pEscSeqCode[EscTableIndex].Data) { return (UINT8) (pScanCodeMap[Index].KbScanCode); } } } return (UINT8)(TerminalEscCode->EscSequenceCode[EscTableIndex].Data); } /** Fill Console Redirection supported special commands to CR_EFI_INFO structure @param TerminalEscCode Pointer to Console Redirection EFI Information structure @retval EFI_SUCCESS Special commands fill success @retval EFI_UNSUPPORTED Special commands fill fail **/ EFI_STATUS FillCrSpecialCommandTable ( IN OUT CR_EFI_INFO *CrEfiInfo ) { EFI_STATUS Status; EFI_TERMINAL_ESC_CODE_PROTOCOL *TerminalEscCode; CR_EFI_SPECIAL_COMMAND_TABLE *CrSpcTable; UINTN Index; CHAR8 AsciiStr[128]; UINTN StringLength; CHAR8 *pCrSpcStr; Status = gBS->LocateProtocol (&gTerminalEscCodeProtocolGuid, NULL, (VOID **)&TerminalEscCode); if (EFI_ERROR (Status) || (TerminalEscCode->CrSpecialCommandCount == 0)) { CrEfiInfo->CrSpecialCommandTableOffset = 0; return EFI_UNSUPPORTED; } CrSpcTable = (CR_EFI_SPECIAL_COMMAND_TABLE *) CrEfiMemAlloc ( sizeof(CR_EFI_SPECIAL_COMMAND_TABLE) + sizeof (CR_EFI_SPECIAL_COMMAND) * (TerminalEscCode->CrSpecialCommandCount - 1)); if (CrSpcTable == NULL) { ASSERT (0); return EFI_UNSUPPORTED; } CrEfiInfo->CrSpecialCommandTableOffset = (UINT16)((UINTN)CrSpcTable - mCrMemStart); CrSpcTable->Count = TerminalEscCode->CrSpecialCommandCount; for (Index = 0; Index < TerminalEscCode->CrSpecialCommandCount; Index++) { CrSpcTable->CrSpecialCommand[Index].Command = TerminalEscCode->CrSpecialCommand[Index].Command; CrSpcTable->CrSpecialCommand[Index].CommandType = TerminalEscCode->CrSpecialCommand[Index].CommandType; //[-start-180729-IB08400622-modify]// UnicodeStrToAsciiStrS ((CONST CHAR16 *)TerminalEscCode->CrSpecialCommand[Index].CommandStr, AsciiStr, 128); //[-end-180729-IB08400622-modify]// StringLength = AsciiStrLen (AsciiStr); pCrSpcStr = (CHAR8 *) CrEfiMemAlloc (StringLength + 1); if (pCrSpcStr == NULL) { ASSERT (0); return EFI_UNSUPPORTED; } CopyMem (pCrSpcStr ,AsciiStr, StringLength + 1); CrSpcTable->CrSpecialCommand[Index].CommandStrOffset = (UINT16)((UINTN)pCrSpcStr - mCrMemStart); } return EFI_SUCCESS; } /** Fill Console Redirection supported Terminal ESC Sequence Code to CR_EFI_INFO structure @param TerminalEscCode Pointer to Console Redirection EFI Information structure @retval EFI_SUCCESS Terminal ESC Sequence Code fill success @retval EFI_UNSUPPORTED Terminal ESC Sequence Code fill fail **/ EFI_STATUS FillTerminalEscCode ( IN OUT CR_EFI_INFO *CrEfiInfo ) { EFI_STATUS Status; EFI_TERMINAL_ESC_CODE_PROTOCOL *TerminalEscCode; CR_EFI_ESC_SEQUENCE_CODE_TABLE *CrEscCodeTable; UINTN Index; CHAR8 AsciiStr[128]; UINTN StringLength; CHAR8 *pCrEscCode; UINT8 Data; Status = gBS->LocateProtocol (&gTerminalEscCodeProtocolGuid, NULL, (VOID **)&TerminalEscCode); if (EFI_ERROR (Status)) { return EFI_UNSUPPORTED; } // // Build ESC sequence code table // CrEscCodeTable = (CR_EFI_ESC_SEQUENCE_CODE_TABLE *) CrEfiMemAlloc (sizeof(CR_EFI_ESC_SEQUENCE_CODE_TABLE) + sizeof(CR_EFI_ESC_SEQUENCE_CODE) * (TerminalEscCode->EscCodeCount - 1)); if (CrEscCodeTable == NULL) { ASSERT (0); return EFI_UNSUPPORTED; } CrEfiInfo->TerminalEscCodeOffset = (UINT16)((UINTN)CrEscCodeTable - mCrMemStart); CrEscCodeTable->Count = TerminalEscCode->EscCodeCount; for (Index = 0; Index < TerminalEscCode->EscCodeCount; Index++) { CrEscCodeTable->CrEscSequenceCode[Index].TerminalType = TerminalEscCode->EscSequenceCode[Index].TerminalType; CrEscCodeTable->CrEscSequenceCode[Index].Reserve = TerminalEscCode->EscSequenceCode[Index].Reserve; CrEscCodeTable->CrEscSequenceCode[Index].DataType = TerminalEscCode->EscSequenceCode[Index].DataType; Data = TranslateEfiScanCode(TerminalEscCode, Index); CrEscCodeTable->CrEscSequenceCode[Index].Data = Data; // // Process ESC sequence code string // //[-start-180729-IB08400622-modify]// UnicodeStrToAsciiStrS ((CONST CHAR16 *)TerminalEscCode->EscSequenceCode[Index].EscSequenceCode, AsciiStr, 128); //[-end-180729-IB08400622-modify]// StringLength = AsciiStrLen(AsciiStr); pCrEscCode = (CHAR8 *) CrEfiMemAlloc (StringLength + 1); if (pCrEscCode == NULL) { ASSERT (0); return EFI_UNSUPPORTED; } CopyMem (pCrEscCode ,AsciiStr, StringLength + 1); CrEscCodeTable->CrEscSequenceCode[Index].OffsetOfString = (UINT16)((UINTN)pCrEscCode - mCrMemStart); } return EFI_SUCCESS; } BOOLEAN IsCrOpROMDevice ( IN EFI_CONSOLE_REDIRECTION_DEVICE *CrDevice ) { return CrDevice->Uart16550protocol->DeviceInfo->LegacySupport; } /** Fill Console Redirection Terminal device information to CR_EFI_INFO structure @param CrPolicy Pointer to Console Redirection policy protocol @param CRInfo Pointer to Console Redirection information structure @retval EFI_SUCCESS Console Redirection Terminal device information fill success @retval EFI_INVALID_PARAMETER Console Redirection Terminal device information fill fail **/ EFI_STATUS FillCRInfo ( IN EFI_CONSOLE_REDIRECTION_INFO *CRInfo ) { CR_EFI_INFO *CrEfiInfo; CR_DEVICE *CRDevice; UINT8 UartProtocol; UINTN CRInfoSize; UINTN Index; UINTN CrOpromDevNum; UINTN DevCount; UART_16550_DEVICE_INFO *UartDevInfo; if (CRInfo == NULL) { return EFI_INVALID_PARAMETER; } UartProtocol = 0; if (mCrPolicy.GlobalDataBits == CR_DATA_8BIT) { UartProtocol = UART_DATA_BITS_8; } else { UartProtocol = UART_DATA_BITS_7; } if (mCrPolicy.GlobalStopBits == CR_STOP_2BIT) { UartProtocol |= UART_STOP_BITS_2; } switch (mCrPolicy.GlobalParity) { case CR_PARITY_EVEN: UartProtocol |= UART_PARITY_EVEN; break; case CR_PARITY_ODD: UartProtocol |= UART_PARITY_ODD; break; default: break; } // // Count CR legacy support device // CrOpromDevNum = 0; for (Index = 0; Index < CRInfo->DeviceCount; Index++) { if ( IsCrOpROMDevice (&(CRInfo->CRDevice[Index])) ) { CrOpromDevNum++; } } // // Caculate memory size that CRINFO need // CRInfoSize = sizeof(CR_EFI_INFO) + CrOpromDevNum * sizeof(CR_DEVICE); // // Allocate memory from CR Efi Memory Manager // CrEfiInfo = (CR_EFI_INFO *) CrEfiMemAlloc (CRInfoSize); if (CrEfiInfo == NULL) { ASSERT (0); return EFI_UNSUPPORTED; } CrEfiInfo->Signature = SIGNATURE_16 ('C', 'R'); CrEfiInfo->Revision = CR_INFO_REVISION; CrEfiInfo->HLength = sizeof (CR_EFI_INFO); CrEfiInfo->DeviceCount = (UINT8)CrOpromDevNum; CRDevice = (CR_DEVICE *)((UINT8 *)CrEfiInfo + sizeof(CR_EFI_INFO)); for (DevCount = 0, Index = 0; Index < CRInfo->DeviceCount; Index++) { if ( !IsCrOpROMDevice (&(CRInfo->CRDevice[Index])) ) { continue; } UartDevInfo = CRInfo->CRDevice[Index].Uart16550protocol->DeviceInfo; CRDevice[DevCount].Type = UartDevInfo->DeviceType; CRDevice[DevCount].BaudRateDivisor = CRInfo->CRDevice[Index].BaudRateDivisor; CRDevice[DevCount].BaudRate = (UINT32)(UartDevInfo->SerialClockFreq / UartDevInfo->SampleRate / CRDevice[DevCount].BaudRateDivisor); CRDevice[DevCount].UartUid = UartDevInfo->UartUid; CRDevice[DevCount].FlowControl = SupportFlowControl(CRInfo->CRDevice[Index].DevicePath); if (CRInfo->CRDevice[Index].Type == ISA_SERIAL_DEVICE) { CRDevice[DevCount].Device.IsaSerial.ComPortAddress = (UINT16)CRInfo->CRDevice[Index].Uart16550protocol->DeviceInfo->BaseAddress; CRDevice[DevCount].Device.IsaSerial.ComPortIrq = CRInfo->CRDevice[Index].Uart16550protocol->DeviceInfo->DevIRQ; } else if (CRInfo->CRDevice[Index].Type == PCI_SERIAL_DEVICE) { CRDevice[DevCount].Device.PciSerial.Bus = GET_BUS(CRInfo->CRDevice[Index].Uart16550protocol->DeviceInfo->UID); CRDevice[DevCount].Device.PciSerial.Device = GET_DEV(CRInfo->CRDevice[Index].Uart16550protocol->DeviceInfo->UID); CRDevice[DevCount].Device.PciSerial.Function = GET_FUN(CRInfo->CRDevice[Index].Uart16550protocol->DeviceInfo->UID); } else if (CRInfo->CRDevice[Index].Type == PCI_HS_SERIAL_DEVICE) { CRDevice[DevCount].Device.PciHsSerial.Bus = GET_BUS(UartDevInfo->UID); CRDevice[DevCount].Device.PciHsSerial.Device = GET_DEV(UartDevInfo->UID); CRDevice[DevCount].Device.PciHsSerial.Function = GET_FUN(UartDevInfo->UID); CRDevice[DevCount].Device.PciHsSerial.AccessWidth = UartDevInfo->RegisterByteWidth; } else if (CRInfo->CRDevice[Index].Type == PCH_HS_SERIAL_DEVICE) { CRDevice[DevCount].Device.PchHsSerial.BaseAddr_Irq = (UINT32)(UartDevInfo->BaseAddress + UartDevInfo->DevIRQ); CRDevice[DevCount].Device.PchHsSerial.AccessWidth = UartDevInfo->RegisterByteWidth; } DevCount++; } CrEfiInfo->BaudRateDivisor = mBaudRateDivisor[mCrPolicy.GlobalBaudRate]; CrEfiInfo->TerminalType = gTerminalFlagTable[mCrPolicy.GlobalTerminalType]; CrEfiInfo->Protocol = UartProtocol; CrEfiInfo->FIFOLength = mCrPolicy.CRFifoLength; CrEfiInfo->InfoWaitTime = mCrPolicy.CRInfoWaitTime; CrEfiInfo->CRWriteCharInterval = mCrPolicy.CRWriteCharInterval; CrEfiInfo->ShowHelp = mCrPolicy.Feature.Bit.CRShowHelp; CrEfiInfo->CRAfterPost = mCrPolicy.Feature.Bit.CRAfterPost; CrEfiInfo->CRHeadlessVBuffer = mCrPolicy.Feature.Bit.CRHeadlessVBuffer; CrEfiInfo->FeatureFlag = mCrPolicy.Feature.Data16; CrEfiInfo->SmiPort = PcdGet16 (PcdSoftwareSmiPort); CrEfiInfo->CrsSmi = PcdGet8 (PcdH2OCrSoftwareSmi); // // Set Headless flag to notify serial OPROM. (H:Headless V:Vga card) // if (CRInfo->Headless == TRUE) { CrEfiInfo->Headless = 'H'; } else { CrEfiInfo->Headless = 'V'; } FillTerminalEscCode (CrEfiInfo); FillCrSpecialCommandTable (CrEfiInfo); BDA_DATA(CR_MEM_MANAGER, UINT16) = (UINT16) mCrMemStart; BDA_DATA(CR_CRINFO, UINT16) = (UINT16)((UINTN)CrEfiInfo - mCrMemStart); return EFI_SUCCESS; } /** Load Console Redirection Option ROM @param CrPolicy Pointer to Console Redirection policy protocol @retval EFI_SUCCESS Console Redirection Option ROM load success @retval EFI_UNSUPPORTED Console Redirection Option ROM load fail **/ EFI_STATUS LoadOpRomImage ( VOID ) { EFI_STATUS Status; VOID *LocalRomImage; UINTN LocalRomSize; UINTN Flags; EFI_IA32_REGISTER_SET RegisterSet; VOID *LegacyRegion; UINT16 Legacy16CallSegment; UINT16 Legacy16CallOffset; LocalRomSize = 0; LocalRomImage = NULL; Status = GetSectionFromAnyFv ( PcdGetPtr(PcdH2OCrOpRomFile), EFI_SECTION_RAW, 0, &LocalRomImage, &LocalRomSize ); if (EFI_ERROR (Status)) { return EFI_UNSUPPORTED; } if (LocalRomImage != NULL || LocalRomSize != 0) { if (mCrPolicy.Feature.Bit.CROpROMLoadOnESegment == TRUE) { // // Get space from E-Seg for CrOpROM // Status = mLegacyBios->GetLegacyRegion ( mLegacyBios, LocalRomSize, 0, 0x200, &LegacyRegion ); if (EFI_ERROR(Status)) { ASSERT_EFI_ERROR(Status); return Status; } // // Copy CrOpROM to reserved space in E-Seg // Status = mLegacyBios->CopyLegacyRegion ( mLegacyBios, LocalRomSize, LegacyRegion, (VOID *)(UINTN)LocalRomImage ); if (EFI_ERROR(Status)) { ASSERT_EFI_ERROR(Status); return Status; } EBDA_DATA(BIOS_PHASE, UINT8) = BIOS_PHASE_OPROM; EnableSerialInterrupt (); ZeroMem (&RegisterSet, sizeof (RegisterSet)); Legacy16CallSegment = (UINT16) (((UINTN)LegacyRegion) >> 4); Legacy16CallOffset = 0x0003; Status = mLegacyBios->FarCall86 ( mLegacyBios, Legacy16CallSegment, Legacy16CallOffset, &RegisterSet, NULL, 0 ); ASSERT_EFI_ERROR(Status); DisableSerialInterrupt (); EBDA_DATA(BIOS_PHASE, UINT8) = BIOS_PHASE_INIT; } else { Status = mLegacyBios->InstallPciRom ( mLegacyBios, NULL, &LocalRomImage, &Flags, NULL, NULL, NULL, NULL ); ASSERT_EFI_ERROR(Status); } } return Status; } /** Set Terminal mode to 80x25 or restore text mode in efi @param SetMode0 TRUE : Set mode0 (80x25) FALSE : Restore Termainl mode. **/ VOID SetTerminalModeForLegacy ( BOOLEAN SetMode0 ) { UINTN Index; EFI_STATUS Status; EFI_DEVICE_PATH *DPath; EFI_HANDLE TerminalHandle; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput; for (Index = 0; Index < gCrInfo->DeviceCount; Index++) { DPath = gCrInfo->CRDevice[Index].DevicePath; Status = gBS->LocateDevicePath ( &gEfiSimpleTextOutProtocolGuid, &DPath, &TerminalHandle ); if (EFI_ERROR(Status)) { continue; } Status = gBS->HandleProtocol (TerminalHandle, &gEfiSimpleTextOutProtocolGuid, &SimpleTextOutput); if (EFI_ERROR(Status)) { continue; } if (SetMode0) { gCrInfo->CRDevice[Index].TextMode = SimpleTextOutput->Mode->Mode; SimpleTextOutput->SetMode (SimpleTextOutput, 0); } else { SimpleTextOutput->SetMode (SimpleTextOutput, gCrInfo->CRDevice[Index].TextMode); } } } /** Notify function for LegacyBoot event be invoked @param Event The Event that is being processed @param Context The Event Context **/ VOID EFIAPI LegacyBootNotifyFunction ( IN EFI_EVENT Event, IN VOID *Context ) { UINT16 *BdaEBdaOffset; UINT16 EBdaSegment; UINT8 *pBiosPhase; // // End of POST time for console redirection // BdaEBdaOffset = (UINT16 *)(UINTN)BDA_EBDA_OFFSET; EBdaSegment = *BdaEBdaOffset; pBiosPhase = (UINT8 *)(UINTN)(((UINT32)EBdaSegment << SEGMENT_SHIFT) + BIOS_PHASE); *pBiosPhase = BIOS_PHASE_OS; SetTerminalModeForLegacy (TRUE); EnableSerialInterrupt (); gBS->CloseEvent (mLegacyBootEvent); return; } /** Set text mode or restore original video mode. @param DeviceHandle Mode specific. See EFI_GET_PLATFORM_HOOK_MODE enum. @param SwitchMode Switch to text mode or restore original mode. @retval None. **/ VOID SwitchVideoMode ( IN EFI_HANDLE DeviceHandle, IN BOOLEAN SwitchMode ) { EFI_IA32_REGISTER_SET RegisterSet; BOOLEAN ForceSwitchTextMode; static UINT16 VideoOriginalMode; if (SwitchMode == SWITCH_TEXT_MODE) { ForceSwitchTextMode = TRUE; // // Check platform & oem policy for 'ForceSwitchTextMode'. // DxeCsSvcInstallPciRomSwitchTextMode (DeviceHandle, &ForceSwitchTextMode); DEBUG ((DEBUG_INFO, "Cr << %a >> DxeChipsetService() SwitchTextMode:%d\n", __FUNCTION__, ForceSwitchTextMode)); // // OemServices // OemSvcInstallPciRomSwitchTextMode (DeviceHandle, &ForceSwitchTextMode); DEBUG ((DEBUG_INFO, "Cr << %a >> OemService() SwitchTextMode:%d\n", __FUNCTION__, ForceSwitchTextMode)); if (ForceSwitchTextMode) { // // Save Original VESA Vedio Mode // VideoOriginalMode = MAX_UINT16; RegisterSet.X.AX = VESA_GET_MODE; RegisterSet.X.BX = 0; mLegacyBios->Int86 (mLegacyBios, INT_10, &RegisterSet); if (RegisterSet.H.AL == VESA_SUPPORTED && RegisterSet.X.BX != VGA_TEXT_MODE) { VideoOriginalMode = RegisterSet.X.BX; // // Set the 80x25 Text VGA Mode before dispatch CRS ROM // RegisterSet.H.AH = VGA_SET_MODE; RegisterSet.H.AL = VGA_TEXT_MODE; mLegacyBios->Int86 (mLegacyBios, INT_10, &RegisterSet); } else { DEBUG ((DEBUG_WARN, "\nCr << %a >> Do not save the original video mode. VESA_SUPPORTED:0x%x, Mode:0x%x\n", __FUNCTION__, RegisterSet.X.AX, RegisterSet.X.BX )); } } } else { if (VideoOriginalMode != MAX_UINT16) { // // Restore Original Vedio Mode // RegisterSet.X.AX = VESA_SET_MODE; RegisterSet.X.BX = VideoOriginalMode; mLegacyBios->Int86 (mLegacyBios, INT_10, &RegisterSet); DEBUG ((DEBUG_INFO, "Cr << %a >> Restore Original Vedio Mode:0x%x\n", __FUNCTION__, VideoOriginalMode)); } } } /** Allows Console Redirection perform specific required action after a LegacyBios operation. @param This The protocol instance pointer @param Mode Will bypass to next caller @param Type Will bypass to next caller @param DeviceHandle Will bypass to next caller @param ShadowAddress Will bypass to next caller @param Compatibility16Table Will bypass to next caller @param AdditionalData Will bypass to next caller @retval EFI_SUCCESS The operation performed successfully. @retval EFI_UNSUPPORTED Mode is not supported on the platform. **/ EFI_STATUS EFIAPI CrsPlatformHooks ( IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, IN EFI_GET_PLATFORM_HOOK_MODE Mode, IN UINT16 Type, IN EFI_HANDLE DeviceHandle, IN OUT UINTN *ShadowAddress, IN EFI_COMPATIBILITY16_TABLE *Compatibility16Table, IN VOID **AdditionalData ) { EFI_STATUS Status; BOOLEAN IsCrRom; IsCrRom = IS_CRROM(ShadowAddress)? TRUE: FALSE; // // If not CROpRom, execute original LegacyBios function for setup legacy environment. // if (!IsCrRom) { Status = mPlatformHooks (This, Mode, Type, DeviceHandle, ShadowAddress, Compatibility16Table, AdditionalData); if (EFI_ERROR(Status)) { return Status; } } switch (Mode) { case EfiPlatformHookPrepareToScanRom: if (IsCrRom) { SwitchVideoMode (DeviceHandle, SWITCH_TEXT_MODE); } SetTerminalModeForLegacy (TRUE); // // Set flag for CRS before Oprom runing // EBDA_DATA(BIOS_PHASE, UINT8) = BIOS_PHASE_OPROM; EnableSerialInterrupt (); break; case EfiPlatformHookShadowServiceRoms: break; case EfiPlatformHookAfterRomInit: DisableSerialInterrupt (); // // Set flag for CRS after Oprom runing // EBDA_DATA(BIOS_PHASE, UINT8) = BIOS_PHASE_INIT; SetTerminalModeForLegacy (FALSE); if (IsCrRom) { SwitchVideoMode (DeviceHandle, SWITCH_ORIGINAL_MODE); } break; default: break; } return EFI_SUCCESS; } /** Confirm AB segment can be accessed @retval EFI_SUCCESS AB segment can be accessed. @retval EFI_ACCESS_DENIED AB segment can not be accessed. **/ EFI_STATUS AbSegAccessConfirm ( VOID ) { UINT8 RestoreData; UINT8 *pVBuffer; UINT8 Data[2]; UINT8 Index; RestoreData = 0; Data[0] = 0x55; Data[1] = 0xAA; pVBuffer = (UINT8 *)((UINTN)(TEXT_PAGE_0_START)); CopyMem (&RestoreData, pVBuffer, sizeof (UINT8)); for (Index = 0; Index < 2; Index++) { CopyMem (pVBuffer, &Data[Index], sizeof (UINT8)); if (CompareMem (pVBuffer, &Data[Index], sizeof (UINT8)) != 0) { return EFI_ACCESS_DENIED; } } CopyMem (pVBuffer, &RestoreData, sizeof (UINT8)); return EFI_SUCCESS; } EFI_STATUS PutDeviceInfoToSmm ( UINTN DeviceCount, UART_16550_DEVICE_INFO *DeviceBuffer ) { EFI_STATUS Status; EFI_SMM_CONTROL2_PROTOCOL *SmmControl2; UINT8 SmiFuncNo; UINT8 SmiData; Status = CommonSetVariable ( CR_UART_DEVICE_INFO_VAR_NAME, &gH2OConsoleRedirectionServiceProtocolGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS, DeviceCount * sizeof(UART_16550_DEVICE_INFO), DeviceBuffer ); Status = gBS->LocateProtocol (&gEfiSmmControl2ProtocolGuid, NULL, &SmmControl2); if (EFI_ERROR(Status)) { ASSERT (FALSE); return Status; } SmiFuncNo = PcdGet8 (PcdH2OCrSoftwareSmi); // // The SmiData is for pass Wellsburg RC code. It need pass the SmiData and value must be 1 // SmiData = 1; Status = SmmControl2->Trigger (SmmControl2, &SmiFuncNo, &SmiData, FALSE, 0); if (EFI_ERROR(Status)) { ASSERT (FALSE); return Status; } //- Status = CommonSetVariable ( //- CR_UART_DEVICE_INFO_VAR_NAME, //- &gH2OConsoleRedirectionServiceProtocolGuid, //- 0, //- 0, //- NULL //- ); return EFI_SUCCESS; } VOID CrSmmPutCRInfo ( EFI_CONSOLE_REDIRECTION_INFO *CRInfo ) { EFI_STATUS Status; UINTN BufferSize; VOID *Buffer; UART_16550_DEVICE_INFO *DeviceInfo; UINTN Index; BufferSize = CRInfo->DeviceCount * sizeof (UART_16550_DEVICE_INFO); Status = gBS->AllocatePool ( EfiRuntimeServicesData, BufferSize, &Buffer); if (EFI_ERROR(Status)) { ASSERT(FALSE); return; } DeviceInfo = (UART_16550_DEVICE_INFO *) Buffer; for (Index =0; Index < CRInfo->DeviceCount; Index++, DeviceInfo++) { CopyMem (DeviceInfo, CRInfo->CRDevice[Index].Uart16550protocol->DeviceInfo, sizeof(UART_16550_DEVICE_INFO)); } PutDeviceInfoToSmm ( CRInfo->DeviceCount, Buffer); gBS->FreePool (Buffer); } EFI_STATUS CrOpRomSupport ( EFI_CONSOLE_REDIRECTION_INFO *CRInfo ) { EFI_STATUS Status; EFI_SMM_ACCESS2_PROTOCOL *SmmAccess; UINT16 *pVgaBuffer; UINT16 TextElement; UINTN TextCount; Status = gBS->LocateProtocol (&gEfiPciRootBridgeIoProtocolGuid, NULL,(VOID **) &mRootBridgeIo); if (EFI_ERROR (Status)) { ASSERT_EFI_ERROR(Status); return Status; } // // Check Console Redirection is Enable or Disable // Status = gBS->LocateProtocol (&gH2OConsoleRedirectionServiceProtocolGuid, NULL, (VOID **)&gCrService); if (EFI_ERROR (Status)) { ASSERT_EFI_ERROR(Status); return Status; } if (gCrService->CRInfo == NULL) { return EFI_NOT_FOUND; } else { gCrInfo = gCrService->CRInfo; } // // Get LegacyBiosProtocol for Load Serial Redirect Oprom // Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **)&mLegacyBios); if (EFI_ERROR (Status)) { return EFI_UNSUPPORTED; } // // Hook in LegacyBiosPlatform to do update BiosPhase Flag // if (mLegacyBiosPlatformProtocol == NULL) { Status = gBS->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid, NULL, (VOID **)&mLegacyBiosPlatformProtocol); ASSERT_EFI_ERROR(Status); if (!EFI_ERROR(Status)) { mPlatformHooks = mLegacyBiosPlatformProtocol->PlatformHooks; mLegacyBiosPlatformProtocol->PlatformHooks = CrsPlatformHooks; } } // // If Headless , Enable AB segment // if (mHeadless && (mCrPolicy.Feature.Bit.CRHeadlessVBuffer == CR_HEADLESS_USE_VBUFFER)) { Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess); if (!EFI_ERROR(Status)) { Status = SmmAccess->Open (SmmAccess); if (!EFI_ERROR(Status)) { Status = AbSegAccessConfirm (); if (!EFI_ERROR(Status)) { // // Initialize VGA buffer (B8000 ~ B9000) for Option Rom ,EX: SCSI , PXE ... etc. // TextElement = CHAR_SPACE | ((COLOR_BG_BLACK | COLOR_FG_WHITE) << 8); pVgaBuffer = (UINT16 *)((UINTN)(TEXT_PAGE_0_START)); TextCount = 0; do { *pVgaBuffer = TextElement; pVgaBuffer++; TextCount++; } while (TextCount < TEXT_PAGE_SIZE / 2); DEBUG ((DEBUG_INFO | DEBUG_ERROR, "\nConsole Redirection : Usb AB Segment as VBuffer in Headless system\n" ) ); } } } // // If CAN NOT use AB segment(VBuffer) be used, auto change to use EBDA space // if (EFI_ERROR (Status)) { mCrPolicy.Feature.Bit.CRHeadlessVBuffer = CR_HEADLESS_USE_EBDA; DEBUG ((DEBUG_INFO | DEBUG_ERROR, "\nConsole Redirection : Usb EBDA as VBuffer in Headless system\n" ) ); } } mCrOpROMInfo.CrOpROMInstalled = FALSE; mCrOpROMInfo.CrGetCommonArea = GetCrCommonArea; mCrOpROMInfo.CrGetUartUid = CrGetUartUid; // // Install CROpROMInfo Protocol for Cr Usb terminal reference // gBS->InstallProtocolInterface ( &mCrServiceImageHandle, &gH2OCrOpRomInfoProtocolGuid, EFI_NATIVE_INTERFACE, &mCrOpROMInfo ); // // Fill CRInfo in CrEfiMemory space. That hand off CRInfo to Option Rom. // FillCRInfo (gCrInfo); // // Legacy ROM need support MMIO, MMIO need Smm driver support. this information is for SMM driver consume. // CrSmmPutCRInfo ( CRInfo); // // Load Console Redirection Option ROM // Status = LoadOpRomImage (); if (Status == EFI_SUCCESS) { mCrOpROMInfo.CrOpROMInstalled = TRUE; // // When After Post time, we must notify OPRom to work and close SMM AB segment. // EfiCreateEventLegacyBootEx (TPL_NOTIFY, LegacyBootNotifyFunction, NULL, &mLegacyBootEvent); } // // Load OpROM complete, free CREfiMemory space // FreeCrEfiMemorySpace (); return Status; }