/** Connect a class of devices using the platform Boot Manager policy. The ConnectDeviceClass() function allows the caller to request that the Boot Manager connect a class of devices. If Class is EFI_BOOT_MANAGER_POLICY_CONSOLE_GUID then the Boot Manager will use platform policy to connect consoles. Some platforms may restrict the number of consoles connected as they attempt to fast boot, and calling ConnectDeviceClass() with a Class value of EFI_BOOT_MANAGER_POLICY_CONSOLE_GUID must connect the set of consoles that follow the Boot Manager platform policy, and the EFI_SIMPLE_TEXT_INPUT_PROTOCOL, EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL, and the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL are produced on the connected handles. The Boot Manager may restrict which consoles get connect due to platform policy, for example a security policy may require that a given console is not connected. If Class is EFI_BOOT_MANAGER_POLICY_NETWORK_GUID then the Boot Manager will connect the protocols the platforms supports for UEFI general purpose network applications on one or more handles. If more than one network controller is available a platform will connect, one, many, or all of the networks based on platform policy. Connecting UEFI networking protocols, like EFI_DHCP4_PROTOCOL, does not establish connections on the network. The UEFI general purpose network application that called ConnectDeviceClass() may need to use the published protocols to establish the network connection. The Boot Manager can optionally have a policy to establish a network connection. If Class is EFI_BOOT_MANAGER_POLICY_CONNECT_ALL_GUID then the Boot Manager will connect all UEFI drivers using the UEFI Boot Service EFI_BOOT_SERVICES.ConnectController(). If the Boot Manager has policy associated with connect all UEFI drivers this policy will be used. A platform can also define platform specific Class values as a properly generated EFI_GUID would never conflict with this specification. @param[in] This A pointer to the EFI_BOOT_MANAGER_POLICY_PROTOCOL instance. @param[in] Class A pointer to an EFI_GUID that represents a class of devices that will be connected using the Boot Mangers platform policy. @retval EFI_SUCCESS At least one devices of the Class was connected. @retval EFI_DEVICE_ERROR Devices were not connected due to an error. @retval EFI_NOT_FOUND The Class is not supported by the platform. @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION. **/ EFI_STATUS EFIAPI BootManagerPolicyConnectDeviceClass ( IN EFI_BOOT_MANAGER_POLICY_PROTOCOL *This, IN EFI_GUID *Class ) { if (EfiGetCurrentTpl () != TPL_APPLICATION) { return EFI_UNSUPPORTED; } if (CompareGuid (Class, &gEfiBootManagerPolicyConnectAllGuid)) { ConnectAllAndCreateNetworkDeviceList (); return EFI_SUCCESS; } if (CompareGuid (Class, &gEfiBootManagerPolicyConsoleGuid)) { return EfiBootManagerConnectAllDefaultConsoles (); } if (CompareGuid (Class, &gEfiBootManagerPolicyNetworkGuid)) { return ConnectNetwork (); } return EFI_NOT_FOUND; }
/** Connect a device path following the platforms EFI Boot Manager policy. The ConnectDevicePath() function allows the caller to connect a DevicePath using the same policy as the EFI Boot Manger. @param[in] This A pointer to the EFI_BOOT_MANAGER_POLICY_PROTOCOL instance. @param[in] DevicePath Points to the start of the EFI device path to connect. If DevicePath is NULL then all the controllers in the system will be connected using the platforms EFI Boot Manager policy. @param[in] Recursive If TRUE, then ConnectController() is called recursively until the entire tree of controllers below the controller specified by DevicePath have been created. If FALSE, then the tree of controllers is only expanded one level. If DevicePath is NULL then Recursive is ignored. @retval EFI_SUCCESS The DevicePath was connected. @retval EFI_NOT_FOUND The DevicePath was not found. @retval EFI_NOT_FOUND No driver was connected to DevicePath. @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI device drivers on the DevicePath. @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION. **/ EFI_STATUS EFIAPI BootManagerPolicyConnectDevicePath ( IN EFI_BOOT_MANAGER_POLICY_PROTOCOL *This, IN EFI_DEVICE_PATH *DevicePath, IN BOOLEAN Recursive ) { EFI_STATUS Status; EFI_HANDLE Controller; if (EfiGetCurrentTpl () != TPL_APPLICATION) { return EFI_UNSUPPORTED; } if (DevicePath == NULL) { EfiBootManagerConnectAll (); return EFI_SUCCESS; } if (Recursive) { Status = EfiBootManagerConnectDevicePath (DevicePath, NULL); } else { Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &DevicePath, &Controller); if (!EFI_ERROR (Status)) { Status = gBS->ConnectController (Controller, NULL, DevicePath, FALSE); } } return Status; }
/** Stalls the CPU for at least the given number of nanoseconds. Stalls the CPU for the number of nanoseconds specified by NanoSeconds. @param NanoSeconds The minimum number of nanoseconds to delay. @return The value of NanoSeconds inputted. **/ UINTN EFIAPI NanoSecondDelay ( IN UINTN NanoSeconds ) { EFI_STATUS Status; UINT64 HundredNanoseconds; UINTN Index; if ((gTimerPeriod != 0) && ((UINT64)NanoSeconds > gTimerPeriod) && (EfiGetCurrentTpl () == TPL_APPLICATION)) { // // This stall is long, so use gBS->WaitForEvent () to yield CPU to DXE Core // HundredNanoseconds = DivU64x32 (NanoSeconds, 100); Status = gBS->SetTimer (gTimerEvent, TimerRelative, HundredNanoseconds); ASSERT_EFI_ERROR (Status); Status = gBS->WaitForEvent (sizeof (gTimerEvent)/sizeof (EFI_EVENT), &gTimerEvent, &Index); ASSERT_EFI_ERROR (Status); } else { gEmuThunk->Sleep (NanoSeconds); } return NanoSeconds; }
/** Log data record into the data logging hub @param This Protocol instance structure @param DataRecordGuid GUID that defines record contents @param ProducerName GUID that defines the name of the producer of the data @param DataRecordClass Class that defines generic record type @param RawData Data Log record as defined by DataRecordGuid @param RawDataSize Size of Data Log data in bytes @retval EFI_SUCCESS If data was logged @retval EFI_OUT_OF_RESOURCES If data was not logged due to lack of system resources. **/ EFI_STATUS EFIAPI DataHubLogData ( IN EFI_DATA_HUB_PROTOCOL *This, IN EFI_GUID *DataRecordGuid, IN EFI_GUID *ProducerName, IN UINT64 DataRecordClass, IN VOID *RawData, IN UINT32 RawDataSize ) { EFI_STATUS Status; DATA_HUB_INSTANCE *Private; EFI_DATA_ENTRY *LogEntry; UINT32 TotalSize; UINT32 RecordSize; EFI_DATA_RECORD_HEADER *Record; VOID *Raw; DATA_HUB_FILTER_DRIVER *FilterEntry; LIST_ENTRY *Link; LIST_ENTRY *Head; EFI_TIME LogTime; Private = DATA_HUB_INSTANCE_FROM_THIS (This); // // Combine the storage for the internal structs and a copy of the log record. // Record follows PrivateLogEntry. The consumer will be returned a pointer // to Record so we don't what it to be the thing that was allocated from // pool, so the consumer can't free an data record by mistake. // RecordSize = sizeof (EFI_DATA_RECORD_HEADER) + RawDataSize; TotalSize = sizeof (EFI_DATA_ENTRY) + RecordSize; // // First try to get log time at TPL level <= TPL_CALLBACK. // ZeroMem (&LogTime, sizeof (LogTime)); if (EfiGetCurrentTpl() <= TPL_CALLBACK) { gRT->GetTime (&LogTime, NULL); } // // The Logging action is the critical section, so it is locked. // The MTC asignment & update and logging must be an // atomic operation, so use the lock. // Status = EfiAcquireLockOrFail (&Private->DataLock); if (EFI_ERROR (Status)) { // // Reentrancy detected so exit! // return Status; } LogEntry = AllocatePool (TotalSize); if (LogEntry == NULL) { EfiReleaseLock (&Private->DataLock); return EFI_OUT_OF_RESOURCES; } ZeroMem (LogEntry, TotalSize); Record = (EFI_DATA_RECORD_HEADER *) (LogEntry + 1); Raw = (VOID *) (Record + 1); // // Build Standard Log Header // Record->Version = EFI_DATA_RECORD_HEADER_VERSION; Record->HeaderSize = (UINT16) sizeof (EFI_DATA_RECORD_HEADER); Record->RecordSize = RecordSize; CopyMem (&Record->DataRecordGuid, DataRecordGuid, sizeof (EFI_GUID)); CopyMem (&Record->ProducerName, ProducerName, sizeof (EFI_GUID)); Record->DataRecordClass = DataRecordClass; // // Ensure LogMonotonicCount is not zero // Record->LogMonotonicCount = ++Private->GlobalMonotonicCount; CopyMem (&Record->LogTime, &LogTime, sizeof (LogTime)); // // Insert log into the internal linked list. // LogEntry->Signature = EFI_DATA_ENTRY_SIGNATURE; LogEntry->Record = Record; LogEntry->RecordSize = sizeof (EFI_DATA_ENTRY) + RawDataSize; InsertTailList (&Private->DataListHead, &LogEntry->Link); CopyMem (Raw, RawData, RawDataSize); EfiReleaseLock (&Private->DataLock); // // Send Signal to all the filter drivers which are interested // in the record's class and guid. // Head = &Private->FilterDriverListHead; for (Link = GetFirstNode(Head); Link != Head; Link = GetNextNode(Head, Link)) { FilterEntry = FILTER_ENTRY_FROM_LINK (Link); if (((FilterEntry->ClassFilter & DataRecordClass) != 0) && (CompareGuid (&FilterEntry->FilterDataRecordGuid, &gZeroGuid) || CompareGuid (&FilterEntry->FilterDataRecordGuid, DataRecordGuid))) { gBS->SignalEvent (FilterEntry->Event); } } return EFI_SUCCESS; }
/** Detect whether the removable media is present and whether it has changed. @param UsbMass The device to check. @retval EFI_SUCCESS The media status is successfully checked. @retval Other Failed to detect media. **/ EFI_STATUS UsbBootDetectMedia ( IN USB_MASS_DEVICE *UsbMass ) { EFI_BLOCK_IO_MEDIA OldMedia; EFI_BLOCK_IO_MEDIA *Media; UINT8 CmdSet; EFI_TPL OldTpl; EFI_STATUS Status; Media = &UsbMass->BlockIoMedia; CopyMem (&OldMedia, &(UsbMass->BlockIoMedia), sizeof (EFI_BLOCK_IO_MEDIA)); CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass; Status = UsbBootIsUnitReady (UsbMass); if (EFI_ERROR (Status) && (Status != EFI_MEDIA_CHANGED)) { goto ON_ERROR; } if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) { // // MODE SENSE is required for the device with PDT of 0x00/0x07/0x0E, // according to Section 4 of USB Mass Storage Specification for Bootability. // MODE SENSE(10) is useless here, while MODE SENSE(6) defined in SCSI // could get the information of Write Protected. // Since not all device support this command, skip if fail. // UsbScsiModeSense (UsbMass); } Status = UsbBootReadCapacity (UsbMass); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootReadCapacity (%r)\n", Status)); goto ON_ERROR; } return EFI_SUCCESS; ON_ERROR: // // Detect whether it is necessary to reinstall the Block I/O Protocol. // // MediaId may change in RequestSense for MediaChanged // MediaPresent may change in RequestSense for NoMedia // MediaReadOnly may change in RequestSense for WriteProtected or MediaChanged // MediaPresent/BlockSize/LastBlock may change in ReadCapacity // if ((Media->MediaId != OldMedia.MediaId) || (Media->MediaPresent != OldMedia.MediaPresent) || (Media->ReadOnly != OldMedia.ReadOnly) || (Media->BlockSize != OldMedia.BlockSize) || (Media->LastBlock != OldMedia.LastBlock)) { // // This function is called by Block I/O Protocol APIs, which run at TPL_NOTIFY. // Here we temporarily restore TPL to TPL_CALLBACK to invoke ReinstallProtocolInterface(). // OldTpl = EfiGetCurrentTpl (); gBS->RestoreTPL (TPL_CALLBACK); gBS->ReinstallProtocolInterface ( UsbMass->Controller, &gEfiBlockIoProtocolGuid, &UsbMass->BlockIo, &UsbMass->BlockIo ); ASSERT (EfiGetCurrentTpl () == TPL_CALLBACK); gBS->RaiseTPL (OldTpl); // // Update MediaId after reinstalling Block I/O Protocol. // if (Media->MediaPresent != OldMedia.MediaPresent) { if (Media->MediaPresent) { Media->MediaId = 1; } else { Media->MediaId = 0; } } if ((Media->ReadOnly != OldMedia.ReadOnly) || (Media->BlockSize != OldMedia.BlockSize) || (Media->LastBlock != OldMedia.LastBlock)) { Media->MediaId++; } } return Status; }
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; VBoxLogFlowFuncEnter(); 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 (); #ifdef VBOX { UINTN cFileSystem = 0; EFI_HANDLE *phFileSystem = NULL; BDS_COMMON_OPTION *BootOption0080 = NULL; EFI_STATUS rc = EFI_SUCCESS; DEBUG ((EFI_D_INFO, "------------------ VBox Platform Specific Initialization Start -----------------------\n")); BootOption0080 = BdsLibVariableToOption(BootOptionList, L"Boot0080"); if (!BootOption0080) { rc = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &cFileSystem, &phFileSystem); VBoxLogFlowFuncMarkRC(rc); VBoxLogFlowFuncMarkVar(cFileSystem, "%d"); if ( rc == EFI_SUCCESS && cFileSystem > 0) { EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *pFSVolume; EFI_FILE_HANDLE hFSRoot; EFI_FILE_HANDLE hBootEfiFile; UINTN iFileSystem = 0; /* Ok, we've found several simple file system handles * 1. we should find if '\\System\\Library\\CoreServices\\boot.efi' present * 2. Alter 'BootOrder' to include this file in boot sequence. */ for (iFileSystem = 0; iFileSystem < cFileSystem; ++iFileSystem) { EFI_DEVICE_PATH_PROTOCOL *pDevicePath = NULL; /* mount and look up the boot.efi */ rc = gBS->HandleProtocol (phFileSystem[iFileSystem], &gEfiSimpleFileSystemProtocolGuid, (VOID *) &pFSVolume); VBoxLogFlowFuncMarkVar(iFileSystem, "%d"); VBoxLogFlowFuncMarkRC(rc); if (EFI_ERROR(rc)) continue; rc = pFSVolume->OpenVolume(pFSVolume, &hFSRoot); VBoxLogFlowFuncMarkRC(rc); if (EFI_ERROR(rc)) continue; rc = hFSRoot->Open(hFSRoot, &hBootEfiFile, L"\\System\\Library\\CoreServices\\boot.efi", EFI_FILE_MODE_READ, 0); VBoxLogFlowFuncMarkRC(rc); if (EFI_ERROR(rc)) continue; /* nice file is found and we have to register it */ pDevicePath = FileDevicePath(phFileSystem[iFileSystem], L"\\System\\Library\\CoreServices\\boot.efi"); VBoxLogFlowFuncMarkVar(pDevicePath,"%p"); if (!pDevicePath) continue; rc = BdsLibRegisterNewOption (BootOptionList, pDevicePath, L"Mac Boot", L"BootOrder"); VBoxLogFlowFuncMarkRC(rc); } } } else { VBoxLogFlowFuncMarkVar(BootOption0080->LoadOptionsSize, "%d"); if (BootOption0080->LoadOptionsSize) VBoxLogFlowFuncMarkVar(BootOption0080->LoadOptions, "%s"); #if 0 /* Boot0080 option is found */ UINT16 *BootOrder; UINTN BootOrderSize; UINTN Index = 0; CHAR16 *BootOptionName; ASSERT(BootOption0080->Signature == BDS_LOAD_OPTION_SIGNATURE); BootOrder = BdsLibGetVariableAndSize ( L"BootOrder", &gEfiGlobalVariableGuid, &BootOrderSize); ASSERT(BootOrder); BootOptionName = AllocateRuntimePool(256 * sizeof(UINT16)); UnicodeSPrint(BootOptionName, 256 * sizeof(UINT16), L"Boot%04x", BootOrder[Index]); BootOption0080->OptionName = BootOptionName; rc = gRT->SetVariable(BootOptionName, &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, sizeof(BDS_COMMON_OPTION), BootOption0080); LogFlowFuncMarkRC(rc); #if 0 rc = BdsLibRegisterNewOption (BootOptionList, BootOption0080->DevicePath, L"Mac Boot Temp", L"BootOrder"); #endif LogFlowFuncMarkRC(rc); #endif } DEBUG ((EFI_D_INFO, "------------------ VBox Platform Specific Initialization End -----------------------\n")); } #endif BdsLibEnumerateAllBootOption (BootOptionList); SetBootOrderFromQemu (BootOptionList); // // The BootOrder variable may have changed, reload the in-memory list with // it. // BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder"); // // 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); } VBoxLogFlowFuncLeave(); return ; }
/** Stops a device controller or a bus controller. The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). As a result, much of the error checking on the parameters to Stop() has been moved into this common boot service. It is legal to call Stop() from other locations, but the following calling restrictions must be followed, or the system behavior will not be deterministic. 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this same driver's Start() function. 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid EFI_HANDLE. In addition, all of these handles must have been created in this driver's Start() function, and the Start() function must have called OpenProtocol() on ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. @param[in] ControllerHandle A handle to the device being stopped. The handle must support a bus specific I/O protocol for the driver to use to stop the device. @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL if NumberOfChildren is 0. @retval EFI_SUCCESS The device was stopped. @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. **/ EFI_STATUS EFIAPI I2cHostDriverStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer ) { EFI_STATUS Status; I2C_HOST_CONTEXT *I2cHostContext; EFI_I2C_HOST_PROTOCOL *I2cHost; EFI_TPL TplPrevious; TplPrevious = EfiGetCurrentTpl (); if (TplPrevious > TPL_I2C_SYNC) { DEBUG ((EFI_D_ERROR, "I2cHost: TPL %d is too high in Stop.\n", TplPrevious)); return EFI_DEVICE_ERROR; } Status = gBS->OpenProtocol ( Controller, &gEfiI2cHostProtocolGuid, (VOID **) &I2cHost, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } I2cHostContext = I2C_HOST_CONTEXT_FROM_PROTOCOL (I2cHost); // // Raise TPL for critical section // TplPrevious = gBS->RaiseTPL (TPL_I2C_SYNC); // // If there is pending request or pending bus configuration, do not stop // Status = EFI_DEVICE_ERROR; if (( !I2cHostContext->I2cBusConfigurationManagementPending ) && IsListEmpty (&I2cHostContext->RequestList)) { // // Remove the I2C host protocol // Status = gBS->UninstallMultipleProtocolInterfaces ( Controller, &gEfiI2cHostProtocolGuid, I2cHost, NULL ); } // // Leave critical section // gBS->RestoreTPL (TplPrevious); if (!EFI_ERROR (Status)) { gBS->CloseProtocol ( Controller, &gEfiI2cBusConfigurationManagementProtocolGuid, This->DriverBindingHandle, Controller ); // // Release I2c Host resources // if (I2cHostContext->I2cBusConfigurationEvent != NULL) { gBS->CloseEvent (I2cHostContext->I2cBusConfigurationEvent); I2cHostContext->I2cBusConfigurationEvent = NULL; } if (I2cHostContext->I2cEvent != NULL) { gBS->CloseEvent (I2cHostContext->I2cEvent); I2cHostContext->I2cEvent = NULL; } FreePool (I2cHostContext); } // // Return the stop status // return Status; }
/** The function will execute with as the platform policy, current policy is driven by boot mode. IBV/OEM can customize this code for their specific policy action. @param DriverOptionList The header of the driver option link list @param BootOptionList The header of the boot option link list @param ProcessCapsules A pointer to ProcessCapsules() @param BaseMemoryTest A pointer to BaseMemoryTest() **/ VOID EFIAPI PlatformBdsPolicyBehavior ( IN LIST_ENTRY *DriverOptionList, IN LIST_ENTRY *BootOptionList, IN PROCESS_CAPSULES ProcessCapsules, IN BASEM_MEMORY_TEST BaseMemoryTest ) { 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 (); // // 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 (); // // 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); } }