| /** @file | |
| Platform BDS customizations. | |
| Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "BdsPlatform.h" | |
| #include "QemuBootOrder.h" | |
| // | |
| // Global data | |
| // | |
| VOID *mEfiDevPathNotifyReg; | |
| EFI_EVENT mEfiDevPathEvent; | |
| VOID *mEmuVariableEventReg; | |
| EFI_EVENT mEmuVariableEvent; | |
| BOOLEAN mDetectVgaOnly; | |
| // | |
| // Type definitions | |
| // | |
| typedef | |
| EFI_STATUS | |
| (EFIAPI *PROTOCOL_INSTANCE_CALLBACK)( | |
| IN EFI_HANDLE Handle, | |
| IN VOID *Instance, | |
| IN VOID *Context | |
| ); | |
| /** | |
| @param[in] Handle - Handle of PCI device instance | |
| @param[in] PciIo - PCI IO protocol instance | |
| @param[in] Pci - PCI Header register block | |
| **/ | |
| typedef | |
| EFI_STATUS | |
| (EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)( | |
| IN EFI_HANDLE Handle, | |
| IN EFI_PCI_IO_PROTOCOL *PciIo, | |
| IN PCI_TYPE00 *Pci | |
| ); | |
| // | |
| // Function prototypes | |
| // | |
| EFI_STATUS | |
| VisitAllInstancesOfProtocol ( | |
| IN EFI_GUID *Id, | |
| IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction, | |
| IN VOID *Context | |
| ); | |
| EFI_STATUS | |
| VisitAllPciInstancesOfProtocol ( | |
| IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction | |
| ); | |
| VOID | |
| InstallDevicePathCallback ( | |
| VOID | |
| ); | |
| // | |
| // BDS Platform Functions | |
| // | |
| VOID | |
| EFIAPI | |
| PlatformBdsInit ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| Platform Bds init. Incude the platform firmware vendor, revision | |
| and so crc check. | |
| Arguments: | |
| Returns: | |
| None. | |
| --*/ | |
| { | |
| DEBUG ((EFI_D_INFO, "PlatformBdsInit\n")); | |
| InstallDevicePathCallback (); | |
| } | |
| EFI_STATUS | |
| ConnectRootBridge ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| Connect RootBridge | |
| Arguments: | |
| None. | |
| Returns: | |
| EFI_SUCCESS - Connect RootBridge successfully. | |
| EFI_STATUS - Connect RootBridge fail. | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| EFI_HANDLE RootHandle; | |
| // | |
| // Make all the PCI_IO protocols on PCI Seg 0 show up | |
| // | |
| BdsLibConnectDevicePath (gPlatformRootBridges[0]); | |
| Status = gBS->LocateDevicePath ( | |
| &gEfiDevicePathProtocolGuid, | |
| &gPlatformRootBridges[0], | |
| &RootHandle | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Status = gBS->ConnectController (RootHandle, NULL, NULL, FALSE); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| PrepareLpcBridgeDevicePath ( | |
| IN EFI_HANDLE DeviceHandle | |
| ) | |
| /*++ | |
| Routine Description: | |
| Add IsaKeyboard to ConIn, | |
| add IsaSerial to ConOut, ConIn, ErrOut. | |
| LPC Bridge: 06 01 00 | |
| Arguments: | |
| DeviceHandle - Handle of PCIIO protocol. | |
| Returns: | |
| EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut. | |
| EFI_STATUS - No LPC bridge is added. | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; | |
| CHAR16 *DevPathStr; | |
| DevicePath = NULL; | |
| Status = gBS->HandleProtocol ( | |
| DeviceHandle, | |
| &gEfiDevicePathProtocolGuid, | |
| (VOID*)&DevicePath | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| TempDevicePath = DevicePath; | |
| // | |
| // Register Keyboard | |
| // | |
| DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode); | |
| BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL); | |
| // | |
| // Register COM1 | |
| // | |
| DevicePath = TempDevicePath; | |
| gPnp16550ComPortDeviceNode.UID = 0; | |
| DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode); | |
| DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode); | |
| DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode); | |
| // | |
| // Print Device Path | |
| // | |
| DevPathStr = DevicePathToStr(DevicePath); | |
| if (DevPathStr != NULL) { | |
| DEBUG(( | |
| EFI_D_INFO, | |
| "BdsPlatform.c+%d: COM%d DevPath: %s\n", | |
| __LINE__, | |
| gPnp16550ComPortDeviceNode.UID + 1, | |
| DevPathStr | |
| )); | |
| FreePool(DevPathStr); | |
| } | |
| BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL); | |
| BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL); | |
| BdsLibUpdateConsoleVariable (VarErrorOut, DevicePath, NULL); | |
| // | |
| // Register COM2 | |
| // | |
| DevicePath = TempDevicePath; | |
| gPnp16550ComPortDeviceNode.UID = 1; | |
| DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode); | |
| DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode); | |
| DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode); | |
| // | |
| // Print Device Path | |
| // | |
| DevPathStr = DevicePathToStr(DevicePath); | |
| if (DevPathStr != NULL) { | |
| DEBUG(( | |
| EFI_D_INFO, | |
| "BdsPlatform.c+%d: COM%d DevPath: %s\n", | |
| __LINE__, | |
| gPnp16550ComPortDeviceNode.UID + 1, | |
| DevPathStr | |
| )); | |
| FreePool(DevPathStr); | |
| } | |
| BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL); | |
| BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL); | |
| BdsLibUpdateConsoleVariable (VarErrorOut, DevicePath, NULL); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| GetGopDevicePath ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath, | |
| OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath | |
| ) | |
| { | |
| UINTN Index; | |
| EFI_STATUS Status; | |
| EFI_HANDLE PciDeviceHandle; | |
| EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath; | |
| UINTN GopHandleCount; | |
| EFI_HANDLE *GopHandleBuffer; | |
| if (PciDevicePath == NULL || GopDevicePath == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Initialize the GopDevicePath to be PciDevicePath | |
| // | |
| *GopDevicePath = PciDevicePath; | |
| TempPciDevicePath = PciDevicePath; | |
| Status = gBS->LocateDevicePath ( | |
| &gEfiDevicePathProtocolGuid, | |
| &TempPciDevicePath, | |
| &PciDeviceHandle | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Try to connect this handle, so that GOP dirver could start on this | |
| // device and create child handles with GraphicsOutput Protocol installed | |
| // on them, then we get device paths of these child handles and select | |
| // them as possible console device. | |
| // | |
| gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE); | |
| Status = gBS->LocateHandleBuffer ( | |
| ByProtocol, | |
| &gEfiGraphicsOutputProtocolGuid, | |
| NULL, | |
| &GopHandleCount, | |
| &GopHandleBuffer | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // Add all the child handles as possible Console Device | |
| // | |
| for (Index = 0; Index < GopHandleCount; Index++) { | |
| Status = gBS->HandleProtocol (GopHandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath); | |
| if (EFI_ERROR (Status)) { | |
| continue; | |
| } | |
| if (CompareMem ( | |
| PciDevicePath, | |
| TempDevicePath, | |
| GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH | |
| ) == 0) { | |
| // | |
| // In current implementation, we only enable one of the child handles | |
| // as console device, i.e. sotre one of the child handle's device | |
| // path to variable "ConOut" | |
| // In futhure, we could select all child handles to be console device | |
| // | |
| *GopDevicePath = TempDevicePath; | |
| // | |
| // Delete the PCI device's path that added by GetPlugInPciVgaDevicePath() | |
| // Add the integrity GOP device path. | |
| // | |
| BdsLibUpdateConsoleVariable (VarConsoleOutDev, NULL, PciDevicePath); | |
| BdsLibUpdateConsoleVariable (VarConsoleOutDev, TempDevicePath, NULL); | |
| } | |
| } | |
| gBS->FreePool (GopHandleBuffer); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| PreparePciVgaDevicePath ( | |
| IN EFI_HANDLE DeviceHandle | |
| ) | |
| /*++ | |
| Routine Description: | |
| Add PCI VGA to ConOut. | |
| PCI VGA: 03 00 00 | |
| Arguments: | |
| DeviceHandle - Handle of PCIIO protocol. | |
| Returns: | |
| EFI_SUCCESS - PCI VGA is added to ConOut. | |
| EFI_STATUS - No PCI VGA device is added. | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *GopDevicePath; | |
| DevicePath = NULL; | |
| Status = gBS->HandleProtocol ( | |
| DeviceHandle, | |
| &gEfiDevicePathProtocolGuid, | |
| (VOID*)&DevicePath | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| GetGopDevicePath (DevicePath, &GopDevicePath); | |
| DevicePath = GopDevicePath; | |
| BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| PreparePciSerialDevicePath ( | |
| IN EFI_HANDLE DeviceHandle | |
| ) | |
| /*++ | |
| Routine Description: | |
| Add PCI Serial to ConOut, ConIn, ErrOut. | |
| PCI Serial: 07 00 02 | |
| Arguments: | |
| DeviceHandle - Handle of PCIIO protocol. | |
| Returns: | |
| EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut. | |
| EFI_STATUS - No PCI Serial device is added. | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| DevicePath = NULL; | |
| Status = gBS->HandleProtocol ( | |
| DeviceHandle, | |
| &gEfiDevicePathProtocolGuid, | |
| (VOID*)&DevicePath | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode); | |
| DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode); | |
| BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL); | |
| BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL); | |
| BdsLibUpdateConsoleVariable (VarErrorOut, DevicePath, NULL); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| VisitAllInstancesOfProtocol ( | |
| IN EFI_GUID *Id, | |
| IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction, | |
| IN VOID *Context | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN HandleCount; | |
| EFI_HANDLE *HandleBuffer; | |
| UINTN Index; | |
| VOID *Instance; | |
| // | |
| // Start to check all the PciIo to find all possible device | |
| // | |
| HandleCount = 0; | |
| HandleBuffer = NULL; | |
| Status = gBS->LocateHandleBuffer ( | |
| ByProtocol, | |
| Id, | |
| NULL, | |
| &HandleCount, | |
| &HandleBuffer | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| for (Index = 0; Index < HandleCount; Index++) { | |
| Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance); | |
| if (EFI_ERROR (Status)) { | |
| continue; | |
| } | |
| Status = (*CallBackFunction) ( | |
| HandleBuffer[Index], | |
| Instance, | |
| Context | |
| ); | |
| } | |
| gBS->FreePool (HandleBuffer); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| VisitingAPciInstance ( | |
| IN EFI_HANDLE Handle, | |
| IN VOID *Instance, | |
| IN VOID *Context | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| PCI_TYPE00 Pci; | |
| PciIo = (EFI_PCI_IO_PROTOCOL*) Instance; | |
| // | |
| // Check for all PCI device | |
| // | |
| Status = PciIo->Pci.Read ( | |
| PciIo, | |
| EfiPciIoWidthUint32, | |
| 0, | |
| sizeof (Pci) / sizeof (UINT32), | |
| &Pci | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) ( | |
| Handle, | |
| PciIo, | |
| &Pci | |
| ); | |
| } | |
| EFI_STATUS | |
| VisitAllPciInstances ( | |
| IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction | |
| ) | |
| { | |
| return VisitAllInstancesOfProtocol ( | |
| &gEfiPciIoProtocolGuid, | |
| VisitingAPciInstance, | |
| (VOID*)(UINTN) CallBackFunction | |
| ); | |
| } | |
| /** | |
| Do platform specific PCI Device check and add them to | |
| ConOut, ConIn, ErrOut. | |
| @param[in] Handle - Handle of PCI device instance | |
| @param[in] PciIo - PCI IO protocol instance | |
| @param[in] Pci - PCI Header register block | |
| @retval EFI_SUCCESS - PCI Device check and Console variable update successfully. | |
| @retval EFI_STATUS - PCI Device check or Console variable update fail. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| DetectAndPreparePlatformPciDevicePath ( | |
| IN EFI_HANDLE Handle, | |
| IN EFI_PCI_IO_PROTOCOL *PciIo, | |
| IN PCI_TYPE00 *Pci | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = PciIo->Attributes ( | |
| PciIo, | |
| EfiPciIoAttributeOperationEnable, | |
| EFI_PCI_DEVICE_ENABLE, | |
| NULL | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| if (!mDetectVgaOnly) { | |
| // | |
| // Here we decide whether it is LPC Bridge | |
| // | |
| if ((IS_PCI_LPC (Pci)) || | |
| ((IS_PCI_ISA_PDECODE (Pci)) && | |
| (Pci->Hdr.VendorId == 0x8086) && | |
| (Pci->Hdr.DeviceId == 0x7000) | |
| ) | |
| ) { | |
| // | |
| // Add IsaKeyboard to ConIn, | |
| // add IsaSerial to ConOut, ConIn, ErrOut | |
| // | |
| DEBUG ((EFI_D_INFO, "Found LPC Bridge device\n")); | |
| PrepareLpcBridgeDevicePath (Handle); | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Here we decide which Serial device to enable in PCI bus | |
| // | |
| if (IS_PCI_16550SERIAL (Pci)) { | |
| // | |
| // Add them to ConOut, ConIn, ErrOut. | |
| // | |
| DEBUG ((EFI_D_INFO, "Found PCI 16550 SERIAL device\n")); | |
| PreparePciSerialDevicePath (Handle); | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| // | |
| // Here we decide which VGA device to enable in PCI bus | |
| // | |
| if (IS_PCI_VGA (Pci)) { | |
| // | |
| // Add them to ConOut. | |
| // | |
| DEBUG ((EFI_D_INFO, "Found PCI VGA device\n")); | |
| PreparePciVgaDevicePath (Handle); | |
| return EFI_SUCCESS; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut | |
| @param[in] DetectVgaOnly - Only detect VGA device if it's TRUE. | |
| @retval EFI_SUCCESS - PCI Device check and Console variable update successfully. | |
| @retval EFI_STATUS - PCI Device check or Console variable update fail. | |
| **/ | |
| EFI_STATUS | |
| DetectAndPreparePlatformPciDevicePaths ( | |
| BOOLEAN DetectVgaOnly | |
| ) | |
| { | |
| mDetectVgaOnly = DetectVgaOnly; | |
| return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath); | |
| } | |
| EFI_STATUS | |
| PlatformBdsConnectConsole ( | |
| IN BDS_CONSOLE_CONNECT_ENTRY *PlatformConsole | |
| ) | |
| /*++ | |
| Routine Description: | |
| Connect the predefined platform default console device. Always try to find | |
| and enable the vga device if have. | |
| Arguments: | |
| PlatformConsole - Predfined platform default console device array. | |
| Returns: | |
| EFI_SUCCESS - Success connect at least one ConIn and ConOut | |
| device, there must have one ConOut device is | |
| active vga device. | |
| EFI_STATUS - Return the status of | |
| BdsLibConnectAllDefaultConsoles () | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| UINTN Index; | |
| EFI_DEVICE_PATH_PROTOCOL *VarConout; | |
| EFI_DEVICE_PATH_PROTOCOL *VarConin; | |
| UINTN DevicePathSize; | |
| // | |
| // Connect RootBridge | |
| // | |
| VarConout = BdsLibGetVariableAndSize ( | |
| VarConsoleOut, | |
| &gEfiGlobalVariableGuid, | |
| &DevicePathSize | |
| ); | |
| VarConin = BdsLibGetVariableAndSize ( | |
| VarConsoleInp, | |
| &gEfiGlobalVariableGuid, | |
| &DevicePathSize | |
| ); | |
| if (VarConout == NULL || VarConin == NULL) { | |
| // | |
| // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut | |
| // | |
| DetectAndPreparePlatformPciDevicePaths (FALSE); | |
| // | |
| // Have chance to connect the platform default console, | |
| // the platform default console is the minimue device group | |
| // the platform should support | |
| // | |
| for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) { | |
| // | |
| // Update the console variable with the connect type | |
| // | |
| if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) { | |
| BdsLibUpdateConsoleVariable (VarConsoleInp, PlatformConsole[Index].DevicePath, NULL); | |
| } | |
| if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) { | |
| BdsLibUpdateConsoleVariable (VarConsoleOut, PlatformConsole[Index].DevicePath, NULL); | |
| } | |
| if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) { | |
| BdsLibUpdateConsoleVariable (VarErrorOut, PlatformConsole[Index].DevicePath, NULL); | |
| } | |
| } | |
| } else { | |
| // | |
| // Only detect VGA device and add them to ConOut | |
| // | |
| DetectAndPreparePlatformPciDevicePaths (TRUE); | |
| } | |
| // | |
| // Connect the all the default console with current cosole variable | |
| // | |
| Status = BdsLibConnectAllDefaultConsoles (); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| VOID | |
| PciInitialization ( | |
| ) | |
| { | |
| // | |
| // Bus 0, Device 0, Function 0 - Host to PCI Bridge | |
| // | |
| PciWrite8 (PCI_LIB_ADDRESS (0, 0, 0, 0x3c), 0x00); | |
| // | |
| // Bus 0, Device 1, Function 0 - PCI to ISA Bridge | |
| // | |
| PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x3c), 0x00); | |
| PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // LNKA routing target | |
| PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // LNKB routing target | |
| PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // LNKC routing target | |
| PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // LNKD routing target | |
| // | |
| // Bus 0, Device 1, Function 1 - IDE Controller | |
| // | |
| PciWrite8 (PCI_LIB_ADDRESS (0, 1, 1, 0x3c), 0x00); | |
| PciWrite8 (PCI_LIB_ADDRESS (0, 1, 1, 0x0d), 0x40); | |
| // | |
| // Bus 0, Device 1, Function 3 - Power Managment Controller | |
| // | |
| PciWrite8 (PCI_LIB_ADDRESS (0, 1, 3, 0x3c), 0x09); | |
| PciWrite8 (PCI_LIB_ADDRESS (0, 1, 3, 0x3d), 0x01); // INTA | |
| // | |
| // Bus 0, Device 2, Function 0 - Video Controller | |
| // | |
| PciWrite8 (PCI_LIB_ADDRESS (0, 2, 0, 0x3c), 0x00); | |
| // | |
| // Bus 0, Device 3, Function 0 - Network Controller | |
| // | |
| PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3c), 0x0a); | |
| PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3d), 0x01); // INTA (-> LNKC) | |
| // | |
| // Bus 0, Device 5, Function 0 - RAM Memory | |
| // | |
| PciWrite8 (PCI_LIB_ADDRESS (0, 5, 0, 0x3c), 0x0b); | |
| PciWrite8 (PCI_LIB_ADDRESS (0, 5, 0, 0x3d), 0x01); // INTA (-> LNKA) | |
| } | |
| VOID | |
| AcpiInitialization ( | |
| VOID | |
| ) | |
| { | |
| // | |
| // Set ACPI SCI_EN bit in PMCNTRL | |
| // | |
| IoOr16 ((PciRead32 (PCI_LIB_ADDRESS (0, 1, 3, 0x40)) & ~BIT0) + 4, BIT0); | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| ConnectRecursivelyIfPciMassStorage ( | |
| IN EFI_HANDLE Handle, | |
| IN EFI_PCI_IO_PROTOCOL *Instance, | |
| IN PCI_TYPE00 *PciHeader | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| CHAR16 *DevPathStr; | |
| if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE)) { | |
| DevicePath = NULL; | |
| Status = gBS->HandleProtocol ( | |
| Handle, | |
| &gEfiDevicePathProtocolGuid, | |
| (VOID*)&DevicePath | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Print Device Path | |
| // | |
| DevPathStr = DevicePathToStr (DevicePath); | |
| if (DevPathStr != NULL) { | |
| DEBUG(( | |
| EFI_D_INFO, | |
| "Found Mass Storage device: %s\n", | |
| DevPathStr | |
| )); | |
| FreePool(DevPathStr); | |
| } | |
| Status = gBS->ConnectController (Handle, NULL, NULL, TRUE); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This notification function is invoked when the | |
| EMU Variable FVB has been changed. | |
| @param Event The event that occured | |
| @param Context For EFI compatiblity. Not used. | |
| **/ | |
| VOID | |
| EFIAPI | |
| EmuVariablesUpdatedCallback ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| DEBUG ((EFI_D_INFO, "EmuVariablesUpdatedCallback\n")); | |
| UpdateNvVarsOnFileSystem (); | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| VisitingFileSystemInstance ( | |
| IN EFI_HANDLE Handle, | |
| IN VOID *Instance, | |
| IN VOID *Context | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| STATIC BOOLEAN ConnectedToFileSystem = FALSE; | |
| if (ConnectedToFileSystem) { | |
| return EFI_ALREADY_STARTED; | |
| } | |
| Status = ConnectNvVarsToFileSystem (Handle); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| ConnectedToFileSystem = TRUE; | |
| mEmuVariableEvent = | |
| EfiCreateProtocolNotifyEvent ( | |
| &gEfiDevicePathProtocolGuid, | |
| TPL_CALLBACK, | |
| EmuVariablesUpdatedCallback, | |
| NULL, | |
| &mEmuVariableEventReg | |
| ); | |
| PcdSet64 (PcdEmuVariableEvent, (UINT64)(UINTN) mEmuVariableEvent); | |
| return EFI_SUCCESS; | |
| } | |
| VOID | |
| PlatformBdsRestoreNvVarsFromHardDisk ( | |
| ) | |
| { | |
| VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage); | |
| VisitAllInstancesOfProtocol ( | |
| &gEfiSimpleFileSystemProtocolGuid, | |
| VisitingFileSystemInstance, | |
| NULL | |
| ); | |
| } | |
| VOID | |
| PlatformBdsConnectSequence ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| Connect with predeined platform connect sequence, | |
| the OEM/IBV can customize with their own connect sequence. | |
| Arguments: | |
| None. | |
| Returns: | |
| None. | |
| --*/ | |
| { | |
| UINTN Index; | |
| DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n")); | |
| Index = 0; | |
| // | |
| // Here we can get the customized platform connect sequence | |
| // Notes: we can connect with new variable which record the | |
| // last time boots connect device path sequence | |
| // | |
| while (gPlatformConnectSequence[Index] != NULL) { | |
| // | |
| // Build the platform boot option | |
| // | |
| BdsLibConnectDevicePath (gPlatformConnectSequence[Index]); | |
| Index++; | |
| } | |
| // | |
| // Just use the simple policy to connect all devices | |
| // | |
| BdsLibConnectAll (); | |
| PciInitialization (); | |
| AcpiInitialization (); | |
| // | |
| // Clear the logo after all devices are connected. | |
| // | |
| gST->ConOut->ClearScreen (gST->ConOut); | |
| } | |
| VOID | |
| PlatformBdsGetDriverOption ( | |
| IN OUT LIST_ENTRY *BdsDriverLists | |
| ) | |
| /*++ | |
| Routine Description: | |
| Load the predefined driver option, OEM/IBV can customize this | |
| to load their own drivers | |
| Arguments: | |
| BdsDriverLists - The header of the driver option link list. | |
| Returns: | |
| None. | |
| --*/ | |
| { | |
| DEBUG ((EFI_D_INFO, "PlatformBdsGetDriverOption\n")); | |
| return; | |
| } | |
| VOID | |
| PlatformBdsDiagnostics ( | |
| IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel, | |
| IN BOOLEAN QuietBoot, | |
| IN BASEM_MEMORY_TEST BaseMemoryTest | |
| ) | |
| /*++ | |
| Routine Description: | |
| Perform the platform diagnostic, such like test memory. OEM/IBV also | |
| can customize this fuction to support specific platform diagnostic. | |
| Arguments: | |
| MemoryTestLevel - The memory test intensive level | |
| QuietBoot - Indicate if need to enable the quiet boot | |
| BaseMemoryTest - A pointer to BaseMemoryTest() | |
| Returns: | |
| None. | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| DEBUG ((EFI_D_INFO, "PlatformBdsDiagnostics\n")); | |
| // | |
| // Here we can decide if we need to show | |
| // the diagnostics screen | |
| // Notes: this quiet boot code should be remove | |
| // from the graphic lib | |
| // | |
| if (QuietBoot) { | |
| EnableQuietBoot (PcdGetPtr(PcdLogoFile)); | |
| // | |
| // Perform system diagnostic | |
| // | |
| Status = BaseMemoryTest (MemoryTestLevel); | |
| if (EFI_ERROR (Status)) { | |
| DisableQuietBoot (); | |
| } | |
| return ; | |
| } | |
| // | |
| // Perform system diagnostic | |
| // | |
| Status = BaseMemoryTest (MemoryTestLevel); | |
| } | |
| VOID | |
| EFIAPI | |
| PlatformBdsPolicyBehavior ( | |
| IN OUT LIST_ENTRY *DriverOptionList, | |
| IN OUT LIST_ENTRY *BootOptionList, | |
| IN PROCESS_CAPSULES ProcessCapsules, | |
| IN BASEM_MEMORY_TEST BaseMemoryTest | |
| ) | |
| /*++ | |
| Routine Description: | |
| The function will excute with as the platform policy, current policy | |
| is driven by boot mode. IBV/OEM can customize this code for their specific | |
| policy action. | |
| Arguments: | |
| DriverOptionList - The header of the driver option link list | |
| BootOptionList - The header of the boot option link list | |
| ProcessCapsules - A pointer to ProcessCapsules() | |
| BaseMemoryTest - A pointer to BaseMemoryTest() | |
| Returns: | |
| None. | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| UINT16 Timeout; | |
| EFI_EVENT UserInputDurationTime; | |
| LIST_ENTRY *Link; | |
| BDS_COMMON_OPTION *BootOption; | |
| UINTN Index; | |
| EFI_INPUT_KEY Key; | |
| EFI_TPL OldTpl; | |
| EFI_BOOT_MODE BootMode; | |
| DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior\n")); | |
| ConnectRootBridge (); | |
| if (PcdGetBool (PcdOvmfFlashVariablesEnable)) { | |
| DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars " | |
| "from disk since flash variables appear to be supported.\n")); | |
| } else { | |
| // | |
| // Try to restore variables from the hard disk early so | |
| // they can be used for the other BDS connect operations. | |
| // | |
| PlatformBdsRestoreNvVarsFromHardDisk (); | |
| } | |
| // | |
| // Init the time out value | |
| // | |
| Timeout = PcdGet16 (PcdPlatformBootTimeOut); | |
| // | |
| // Load the driver option as the driver option list | |
| // | |
| PlatformBdsGetDriverOption (DriverOptionList); | |
| // | |
| // Get current Boot Mode | |
| // | |
| Status = BdsLibGetBootMode (&BootMode); | |
| DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode)); | |
| // | |
| // Go the different platform policy with different boot mode | |
| // Notes: this part code can be change with the table policy | |
| // | |
| ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION); | |
| // | |
| // Connect platform console | |
| // | |
| Status = PlatformBdsConnectConsole (gPlatformConsole); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Here OEM/IBV can customize with defined action | |
| // | |
| PlatformBdsNoConsoleAction (); | |
| } | |
| // | |
| // Create a 300ms duration event to ensure user has enough input time to enter Setup | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_TIMER, | |
| 0, | |
| NULL, | |
| NULL, | |
| &UserInputDurationTime | |
| ); | |
| ASSERT (Status == EFI_SUCCESS); | |
| Status = gBS->SetTimer (UserInputDurationTime, TimerRelative, 3000000); | |
| ASSERT (Status == EFI_SUCCESS); | |
| // | |
| // Memory test and Logo show | |
| // | |
| PlatformBdsDiagnostics (IGNORE, TRUE, BaseMemoryTest); | |
| // | |
| // Perform some platform specific connect sequence | |
| // | |
| PlatformBdsConnectSequence (); | |
| // | |
| // Process QEMU's -kernel command line option | |
| // | |
| TryRunningQemuKernel (); | |
| // | |
| // Give one chance to enter the setup if we | |
| // have the time out | |
| // | |
| if (Timeout != 0) { | |
| //PlatformBdsEnterFrontPage (Timeout, FALSE); | |
| } | |
| DEBUG ((EFI_D_INFO, "BdsLibConnectAll\n")); | |
| BdsLibConnectAll (); | |
| BdsLibEnumerateAllBootOption (BootOptionList); | |
| SetBootOrderFromQemu (BootOptionList); | |
| // | |
| // Please uncomment above ConnectAll and EnumerateAll code and remove following first boot | |
| // checking code in real production tip. | |
| // | |
| // In BOOT_WITH_FULL_CONFIGURATION boot mode, should always connect every device | |
| // and do enumerate all the default boot options. But in development system board, the boot mode | |
| // cannot be BOOT_ASSUMING_NO_CONFIGURATION_CHANGES because the machine box | |
| // is always open. So the following code only do the ConnectAll and EnumerateAll at first boot. | |
| // | |
| Status = BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder"); | |
| if (EFI_ERROR(Status)) { | |
| // | |
| // If cannot find "BootOrder" variable, it may be first boot. | |
| // Try to connect all devices and enumerate all boot options here. | |
| // | |
| BdsLibConnectAll (); | |
| BdsLibEnumerateAllBootOption (BootOptionList); | |
| } | |
| // | |
| // To give the User a chance to enter Setup here, if user set TimeOut is 0. | |
| // BDS should still give user a chance to enter Setup | |
| // | |
| // Connect first boot option, and then check user input before exit | |
| // | |
| for (Link = BootOptionList->ForwardLink; Link != BootOptionList;Link = Link->ForwardLink) { | |
| BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE); | |
| if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) { | |
| // | |
| // skip the header of the link list, becuase it has no boot option | |
| // | |
| continue; | |
| } else { | |
| // | |
| // Make sure the boot option device path connected, but ignore the BBS device path | |
| // | |
| if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) { | |
| BdsLibConnectDevicePath (BootOption->DevicePath); | |
| } | |
| break; | |
| } | |
| } | |
| // | |
| // Check whether the user input after the duration time has expired | |
| // | |
| OldTpl = EfiGetCurrentTpl(); | |
| gBS->RestoreTPL (TPL_APPLICATION); | |
| gBS->WaitForEvent (1, &UserInputDurationTime, &Index); | |
| gBS->CloseEvent (UserInputDurationTime); | |
| Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); | |
| gBS->RaiseTPL (OldTpl); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // Enter Setup if user input | |
| // | |
| Timeout = 0xffff; | |
| PlatformBdsEnterFrontPage (Timeout, FALSE); | |
| } | |
| return ; | |
| } | |
| VOID | |
| EFIAPI | |
| PlatformBdsBootSuccess ( | |
| IN BDS_COMMON_OPTION *Option | |
| ) | |
| /*++ | |
| Routine Description: | |
| Hook point after a boot attempt succeeds. We don't expect a boot option to | |
| return, so the EFI 1.0 specification defines that you will default to an | |
| interactive mode and stop processing the BootOrder list in this case. This | |
| is alos a platform implementation and can be customized by IBV/OEM. | |
| Arguments: | |
| Option - Pointer to Boot Option that succeeded to boot. | |
| Returns: | |
| None. | |
| --*/ | |
| { | |
| CHAR16 *TmpStr; | |
| DEBUG ((EFI_D_INFO, "PlatformBdsBootSuccess\n")); | |
| // | |
| // If Boot returned with EFI_SUCCESS and there is not in the boot device | |
| // select loop then we need to pop up a UI and wait for user input. | |
| // | |
| TmpStr = Option->StatusString; | |
| if (TmpStr != NULL) { | |
| BdsLibOutputStrings (gST->ConOut, TmpStr, Option->Description, L"\n\r", NULL); | |
| FreePool (TmpStr); | |
| } | |
| } | |
| VOID | |
| EFIAPI | |
| PlatformBdsBootFail ( | |
| IN BDS_COMMON_OPTION *Option, | |
| IN EFI_STATUS Status, | |
| IN CHAR16 *ExitData, | |
| IN UINTN ExitDataSize | |
| ) | |
| /*++ | |
| Routine Description: | |
| Hook point after a boot attempt fails. | |
| Arguments: | |
| Option - Pointer to Boot Option that failed to boot. | |
| Status - Status returned from failed boot. | |
| ExitData - Exit data returned from failed boot. | |
| ExitDataSize - Exit data size returned from failed boot. | |
| Returns: | |
| None. | |
| --*/ | |
| { | |
| CHAR16 *TmpStr; | |
| DEBUG ((EFI_D_INFO, "PlatformBdsBootFail\n")); | |
| // | |
| // If Boot returned with failed status then we need to pop up a UI and wait | |
| // for user input. | |
| // | |
| TmpStr = Option->StatusString; | |
| if (TmpStr != NULL) { | |
| BdsLibOutputStrings (gST->ConOut, TmpStr, Option->Description, L"\n\r", NULL); | |
| FreePool (TmpStr); | |
| } | |
| } | |
| EFI_STATUS | |
| PlatformBdsNoConsoleAction ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function is remained for IBV/OEM to do some platform action, | |
| if there no console device can be connected. | |
| Arguments: | |
| None. | |
| Returns: | |
| EFI_SUCCESS - Direct return success now. | |
| --*/ | |
| { | |
| DEBUG ((EFI_D_INFO, "PlatformBdsNoConsoleAction\n")); | |
| return EFI_SUCCESS; | |
| } | |
| VOID | |
| EFIAPI | |
| PlatformBdsLockNonUpdatableFlash ( | |
| VOID | |
| ) | |
| { | |
| DEBUG ((EFI_D_INFO, "PlatformBdsLockNonUpdatableFlash\n")); | |
| return; | |
| } | |
| /** | |
| This notification function is invoked when an instance of the | |
| EFI_DEVICE_PATH_PROTOCOL is produced. | |
| @param Event The event that occured | |
| @param Context For EFI compatiblity. Not used. | |
| **/ | |
| VOID | |
| EFIAPI | |
| NotifyDevPath ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| EFI_HANDLE Handle; | |
| EFI_STATUS Status; | |
| UINTN BufferSize; | |
| EFI_DEVICE_PATH_PROTOCOL *DevPathNode; | |
| ATAPI_DEVICE_PATH *Atapi; | |
| // | |
| // Examine all new handles | |
| // | |
| for (;;) { | |
| // | |
| // Get the next handle | |
| // | |
| BufferSize = sizeof (Handle); | |
| Status = gBS->LocateHandle ( | |
| ByRegisterNotify, | |
| NULL, | |
| mEfiDevPathNotifyReg, | |
| &BufferSize, | |
| &Handle | |
| ); | |
| // | |
| // If not found, we're done | |
| // | |
| if (EFI_NOT_FOUND == Status) { | |
| break; | |
| } | |
| if (EFI_ERROR (Status)) { | |
| continue; | |
| } | |
| // | |
| // Get the DevicePath protocol on that handle | |
| // | |
| Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevPathNode); | |
| ASSERT_EFI_ERROR (Status); | |
| while (!IsDevicePathEnd (DevPathNode)) { | |
| // | |
| // Find the handler to dump this device path node | |
| // | |
| if ( | |
| (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) && | |
| (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP) | |
| ) { | |
| Atapi = (ATAPI_DEVICE_PATH*) DevPathNode; | |
| PciOr16 ( | |
| PCI_LIB_ADDRESS ( | |
| 0, | |
| 1, | |
| 1, | |
| (Atapi->PrimarySecondary == 1) ? 0x42: 0x40 | |
| ), | |
| BIT15 | |
| ); | |
| } | |
| // | |
| // Next device path node | |
| // | |
| DevPathNode = NextDevicePathNode (DevPathNode); | |
| } | |
| } | |
| return; | |
| } | |
| VOID | |
| InstallDevicePathCallback ( | |
| VOID | |
| ) | |
| { | |
| DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n")); | |
| mEfiDevPathEvent = EfiCreateProtocolNotifyEvent ( | |
| &gEfiDevicePathProtocolGuid, | |
| TPL_CALLBACK, | |
| NotifyDevPath, | |
| NULL, | |
| &mEfiDevPathNotifyReg | |
| ); | |
| } | |
| /** | |
| Lock the ConsoleIn device in system table. All key | |
| presses will be ignored until the Password is typed in. The only way to | |
| disable the password is to type it in to a ConIn device. | |
| @param Password Password used to lock ConIn device. | |
| @retval EFI_SUCCESS lock the Console In Spliter virtual handle successfully. | |
| @retval EFI_UNSUPPORTED Password not found | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| LockKeyboards ( | |
| IN CHAR16 *Password | |
| ) | |
| { | |
| return EFI_UNSUPPORTED; | |
| } | |