/** Prints a debug message to the debug output device if the specified error level is enabled. If any bit in ErrorLevel is also set in PcdDebugPrintErrorLevel, then print the message specified by Format and the associated variable argument list to the debug output device. If Format is NULL, then ASSERT(). @param ErrorLevel The error level of the debug message. @param Format Format string for the debug message to print. **/ VOID EFIAPI DebugPrint ( IN UINTN ErrorLevel, IN CONST CHAR8 *Format, ... ) { UINT64 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof (UINT64)]; EFI_DEBUG_INFO *DebugInfo; UINTN TotalSize; UINTN Index; VA_LIST Marker; UINT64 *ArgumentPointer; // // If Format is NULL, then ASSERT(). // ASSERT (Format != NULL); // // Check driver Debug Level value and global debug level // if ((ErrorLevel & PcdGet32(PcdDebugPrintErrorLevel)) == 0) { return; } TotalSize = sizeof (EFI_DEBUG_INFO) + 12 * sizeof (UINT64) + AsciiStrLen (Format) + 1; if (TotalSize > EFI_STATUS_CODE_DATA_MAX_SIZE) { return; } // // Then EFI_DEBUG_INFO // DebugInfo = (EFI_DEBUG_INFO *)Buffer; DebugInfo->ErrorLevel = (UINT32)ErrorLevel; // // 256 byte mini Var Arg stack. That is followed by the format string. // VA_START (Marker, Format); for (Index = 0, ArgumentPointer = (UINT64 *)(DebugInfo + 1); Index < 12; Index++, ArgumentPointer++) { WriteUnaligned64(ArgumentPointer, VA_ARG (Marker, UINT64)); } VA_END (Marker); AsciiStrCpy ((CHAR8 *)ArgumentPointer, Format); REPORT_STATUS_CODE_EX ( EFI_DEBUG_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_DC_UNSPECIFIED), 0, NULL, &gEfiStatusCodeDataTypeDebugGuid, DebugInfo, TotalSize ); }
/** Set the variable and report the error through status code upon failure. @param VariableName A Null-terminated string that is the name of the vendor's variable. Each VariableName is unique for each VendorGuid. VariableName must contain 1 or more characters. If VariableName is an empty string, then EFI_INVALID_PARAMETER is returned. @param VendorGuid A unique identifier for the vendor. @param Attributes Attributes bitmask to set for the variable. @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is set, then a SetVariable() call with a DataSize of zero will not cause any change to the variable value (the timestamp associated with the variable may be updated however even if no new data value is provided,see the description of the EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). @param Data The contents for the variable. @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as defined by the Attributes. @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the DataSize exceeds the maximum allowed. @retval EFI_INVALID_PARAMETER VariableName is an empty string. @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error. @retval EFI_WRITE_PROTECTED The variable in question is read-only. @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted. @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo does NOT pass the validation check carried out by the firmware. @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found. **/ EFI_STATUS BdsDxeSetVariableAndReportStatusCodeOnError ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN VOID *Data ) { EFI_STATUS Status; EDKII_SET_VARIABLE_STATUS *SetVariableStatus; UINTN NameSize; Status = gRT->SetVariable ( VariableName, VendorGuid, Attributes, DataSize, Data ); if (EFI_ERROR (Status)) { NameSize = StrSize (VariableName); SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize); if (SetVariableStatus != NULL) { CopyGuid (&SetVariableStatus->Guid, VendorGuid); SetVariableStatus->NameSize = NameSize; SetVariableStatus->DataSize = DataSize; SetVariableStatus->SetStatus = Status; SetVariableStatus->Attributes = Attributes; CopyMem (SetVariableStatus + 1, VariableName, NameSize); CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize); REPORT_STATUS_CODE_EX ( EFI_ERROR_CODE, PcdGet32 (PcdErrorCodeSetVariable), 0, NULL, &gEdkiiStatusCodeDataTypeVariableGuid, SetVariableStatus, sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize ); FreePool (SetVariableStatus); } } return Status; }
/** Perform the memory test. @param[in] This The protocol instance pointer. @param[out] TestedMemorySize Return the tested extended memory size. @param[out] TotalMemorySize Return the whole system physical memory size. The total memory size does not include memory in a slot with a disabled DIMM. @param[out] ErrorOut TRUE if the memory error occured. @param[in] IfTestAbort Indicates that the user pressed "ESC" to skip the memory test. @retval EFI_SUCCESS One block of memory passed the test. @retval EFI_NOT_FOUND All memory blocks have already been tested. @retval EFI_DEVICE_ERROR Memory device error occured, and no agent can handle it. **/ EFI_STATUS EFIAPI GenPerformMemoryTest ( IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This, OUT UINT64 *TestedMemorySize, OUT UINT64 *TotalMemorySize, OUT BOOLEAN *ErrorOut, IN BOOLEAN TestAbort ) { EFI_STATUS Status; GENERIC_MEMORY_TEST_PRIVATE *Private; EFI_MEMORY_RANGE_EXTENDED_DATA *RangeData; UINT64 BlockBoundary; Private = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This); *ErrorOut = FALSE; RangeData = NULL; BlockBoundary = 0; // // In extensive mode the boundary of "mCurrentRange->Length" may will lost // some range that is not Private->BdsBlockSize size boundry, so need // the software mechanism to confirm all memory location be covered. // if (mCurrentAddress < (mCurrentRange->StartAddress + mCurrentRange->Length)) { if ((mCurrentAddress + Private->BdsBlockSize) <= (mCurrentRange->StartAddress + mCurrentRange->Length)) { BlockBoundary = Private->BdsBlockSize; } else { BlockBoundary = mCurrentRange->StartAddress + mCurrentRange->Length - mCurrentAddress; } // // If TestAbort is true, means user cancel the memory test // if (!TestAbort && Private->CoverLevel != IGNORE) { // // Report status code of every memory range // RangeData = AllocateZeroPool (sizeof (EFI_MEMORY_RANGE_EXTENDED_DATA)); if (RangeData == NULL) { return EFI_OUT_OF_RESOURCES; } RangeData->DataHeader.HeaderSize = (UINT16) sizeof (EFI_STATUS_CODE_DATA); RangeData->DataHeader.Size = (UINT16) (sizeof (EFI_MEMORY_RANGE_EXTENDED_DATA) - sizeof (EFI_STATUS_CODE_DATA)); RangeData->Start = mCurrentAddress; RangeData->Length = BlockBoundary; REPORT_STATUS_CODE_EX ( EFI_PROGRESS_CODE, EFI_COMPUTING_UNIT_MEMORY | EFI_CU_MEMORY_PC_TEST, 0, &gEfiGenericMemTestProtocolGuid, NULL, (UINT8 *) RangeData + sizeof (EFI_STATUS_CODE_DATA), RangeData->DataHeader.Size ); // // The software memory test (R/W/V) perform here. It will detect the // memory mis-compare error. // WriteMemory (Private, mCurrentAddress, BlockBoundary); Status = VerifyMemory (Private, mCurrentAddress, BlockBoundary); if (EFI_ERROR (Status)) { // // If perform here, means there is mis-compare error, and no agent can // handle it, so we return to BDS EFI_DEVICE_ERROR. // *ErrorOut = TRUE; return EFI_DEVICE_ERROR; } } mTestedSystemMemory += BlockBoundary; *TestedMemorySize = mTestedSystemMemory; // // If the memory test restart after the platform driver disable dimms, // the NonTestSystemMemory may be changed, but the base memory size will // not changed, so we can get the current total memory size. // *TotalMemorySize = Private->BaseMemorySize + mNonTestedSystemMemory; // // Update the current test address pointing to next BDS BLOCK // mCurrentAddress += Private->BdsBlockSize; return EFI_SUCCESS; } // // Change to next non tested memory range // mCurrentLink = mCurrentLink->ForwardLink; if (mCurrentLink != &Private->NonTestedMemRanList) { mCurrentRange = NONTESTED_MEMORY_RANGE_FROM_LINK (mCurrentLink); mCurrentAddress = mCurrentRange->StartAddress; return EFI_SUCCESS; } else { // // Here means all the memory test have finished // *TestedMemorySize = mTestedSystemMemory; *TotalMemorySize = Private->BaseMemorySize + mNonTestedSystemMemory; return EFI_NOT_FOUND; } }
/** Verify the range of physical memory which covered by memory test pattern. This function will also do not return any informatin just cause system reset, because the handle error encount fatal error and disable the bad DIMMs. @param[in] Private Point to generic memory test driver's private data. @param[in] Start The memory range's start address. @param[in] Size The memory range's size. @retval EFI_SUCCESS Successful verify the range of memory, no errors' location found. @retval Others The range of memory have errors contained. **/ EFI_STATUS VerifyMemory ( IN GENERIC_MEMORY_TEST_PRIVATE *Private, IN EFI_PHYSICAL_ADDRESS Start, IN UINT64 Size ) { EFI_PHYSICAL_ADDRESS Address; INTN ErrorFound; EFI_MEMORY_EXTENDED_ERROR_DATA *ExtendedErrorData; Address = Start; ExtendedErrorData = NULL; // // Add 4G memory address check for IA32 platform // NOTE: Without page table, there is no way to use memory above 4G. // if (Start + Size > MAX_ADDRESS) { return EFI_SUCCESS; } // // Use the software memory test to check whether have detected miscompare // error here. If there is miscompare error here then check if generic // memory test driver can disable the bad DIMM. // while (Address < (Start + Size)) { ErrorFound = CompareMemWithoutCheckArgument ( (VOID *) (UINTN) (Address), Private->MonoPattern, Private->MonoTestSize ); if (ErrorFound != 0) { // // Report uncorrectable errors // ExtendedErrorData = AllocateZeroPool (sizeof (EFI_MEMORY_EXTENDED_ERROR_DATA)); if (ExtendedErrorData == NULL) { return EFI_OUT_OF_RESOURCES; } ExtendedErrorData->DataHeader.HeaderSize = (UINT16) sizeof (EFI_STATUS_CODE_DATA); ExtendedErrorData->DataHeader.Size = (UINT16) (sizeof (EFI_MEMORY_EXTENDED_ERROR_DATA) - sizeof (EFI_STATUS_CODE_DATA)); ExtendedErrorData->Granularity = EFI_MEMORY_ERROR_DEVICE; ExtendedErrorData->Operation = EFI_MEMORY_OPERATION_READ; ExtendedErrorData->Syndrome = 0x0; ExtendedErrorData->Address = Address; ExtendedErrorData->Resolution = 0x40; REPORT_STATUS_CODE_EX ( EFI_ERROR_CODE, EFI_COMPUTING_UNIT_MEMORY | EFI_CU_MEMORY_EC_UNCORRECTABLE, 0, &gEfiGenericMemTestProtocolGuid, NULL, (UINT8 *) ExtendedErrorData + sizeof (EFI_STATUS_CODE_DATA), ExtendedErrorData->DataHeader.Size ); return EFI_DEVICE_ERROR; } Address += Private->CoverageSpan; } return EFI_SUCCESS; }
/** Start function of Driver binding protocol which start this driver on Controller by detecting all disks and installing BlockIo protocol on them. @param This Protocol instance pointer. @param Controller Handle of device to bind driver to. @param RemainingDevicePath produce all possible children. @retval EFI_SUCCESS This driver is added to ControllerHandle. @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle. @retval other This driver does not support this device. **/ EFI_STATUS EFIAPI IDEBusDriverBindingStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { EFI_STATUS Status; EFI_STATUS SavedStatus; EFI_PCI_IO_PROTOCOL *PciIo; EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; EFI_DEV_PATH *Node; UINT8 IdeChannel; UINT8 BeginningIdeChannel; UINT8 EndIdeChannel; UINT8 IdeDevice; UINT8 BeginningIdeDevice; UINT8 EndIdeDevice; IDE_BLK_IO_DEV *IdeBlkIoDevice[IdeMaxChannel][IdeMaxDevice]; IDE_BLK_IO_DEV *IdeBlkIoDevicePtr; IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel]; ATA_TRANSFER_MODE TransferMode; ATA_DRIVE_PARMS DriveParameters; EFI_DEV_PATH NewNode; UINT8 ConfigurationOptions; UINT16 CommandBlockBaseAddr; UINT16 ControlBlockBaseAddr; UINTN DataSize; IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData; UINT64 Supports; // // Local variables declaration for IdeControllerInit support // EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit; BOOLEAN EnumAll; BOOLEAN ChannelEnabled; UINT8 MaxDevices; EFI_IDENTIFY_DATA IdentifyData; EFI_ATA_COLLECTIVE_MODE *SupportedModes; IdeBusDriverPrivateData = NULL; SupportedModes = NULL; // // Perform IdeBus initialization // Status = gBS->OpenProtocol ( Controller, &gEfiDevicePathProtocolGuid, (VOID **) &ParentDevicePath, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) { return Status; } // // Now open the IDE_CONTROLLER_INIT protocol. Step7.1 // Status = gBS->OpenProtocol ( Controller, &gEfiIdeControllerInitProtocolGuid, (VOID **) &IdeInit, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); // // The following OpenProtocol function with _GET_PROTOCOL attribute and // will not return EFI_ALREADY_STARTED, so save it for now // SavedStatus = Status; if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) { DEBUG ((EFI_D_ERROR, "Open Init, Status=%x", Status)); // // open protocol is not SUCCESS or not ALREADY_STARTED, error exit // goto ErrorExit; } // // Save Enumall. Step7.2 // EnumAll = IdeInit->EnumAll; // // Consume PCI I/O protocol. Note that the OpenProtocol with _GET_PROTOCOL // attribute will not return EFI_ALREADY_STARTED // Status = gBS->OpenProtocol ( Controller, &gEfiPciIoProtocolGuid, (VOID **) &PciIo, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "Open PciIo, Status=%x", Status)); goto ErrorExit; } // // We must check EFI_ALREADY_STARTED because many ATAPI devices are removable // if (SavedStatus != EFI_ALREADY_STARTED) { IdeBusDriverPrivateData = AllocatePool (sizeof (IDE_BUS_DRIVER_PRIVATE_DATA)); if (IdeBusDriverPrivateData == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ErrorExit; } ZeroMem (IdeBusDriverPrivateData, sizeof (IDE_BUS_DRIVER_PRIVATE_DATA)); Status = gBS->InstallMultipleProtocolInterfaces ( &Controller, &gEfiCallerIdGuid, IdeBusDriverPrivateData, NULL ); if (EFI_ERROR (Status)) { goto ErrorExit; } } else { Status = gBS->OpenProtocol ( Controller, &gEfiCallerIdGuid, (VOID **) &IdeBusDriverPrivateData, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { IdeBusDriverPrivateData = NULL; goto ErrorExit; } } Status = PciIo->Attributes ( PciIo, EfiPciIoAttributeOperationSupported, 0, &Supports ); if (!EFI_ERROR (Status)) { Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE; Status = PciIo->Attributes ( PciIo, EfiPciIoAttributeOperationEnable, Supports, NULL ); } if (EFI_ERROR (Status)) { goto ErrorExit; } // // Read the environment variable that contains the IDEBus Driver's // Config options that were set by the Driver Configuration Protocol // DataSize = sizeof (ConfigurationOptions); Status = gRT->GetVariable ( (CHAR16 *) L"Configuration", &gEfiCallerIdGuid, NULL, &DataSize, &ConfigurationOptions ); if (EFI_ERROR (Status)) { ConfigurationOptions = 0x0f; } if (EnumAll || RemainingDevicePath == NULL) { // // If IdeInit->EnumAll is TRUE or RemainingDevicePath is NULL, // must enumerate all IDE devices anyway // BeginningIdeChannel = IdePrimary; EndIdeChannel = IdeSecondary; BeginningIdeDevice = IdeMaster; EndIdeDevice = IdeSlave; } else if (!IsDevicePathEnd (RemainingDevicePath)) { // // If RemainingDevicePath isn't the End of Device Path Node, // only scan the specified device by RemainingDevicePath // Node = (EFI_DEV_PATH *) RemainingDevicePath; BeginningIdeChannel = Node->Atapi.PrimarySecondary; EndIdeChannel = BeginningIdeChannel; BeginningIdeDevice = Node->Atapi.SlaveMaster; EndIdeDevice = BeginningIdeDevice; if (BeginningIdeChannel >= IdeMaxChannel || EndIdeChannel >= IdeMaxChannel) { Status = EFI_INVALID_PARAMETER; goto ErrorExit; } if (BeginningIdeDevice >= IdeMaxDevice|| EndIdeDevice >= IdeMaxDevice) { Status = EFI_INVALID_PARAMETER; goto ErrorExit; } } else { // // If RemainingDevicePath is the End of Device Path Node, // skip enumerate any device and return EFI_SUCESSS // BeginningIdeChannel = IdeMaxChannel; EndIdeChannel = IdeMaxChannel - 1; BeginningIdeDevice = IdeMaxDevice; EndIdeDevice = IdeMaxDevice - 1; } // // Obtain IDE IO port registers' base addresses // Status = GetIdeRegistersBaseAddr (PciIo, IdeRegsBaseAddr); if (EFI_ERROR (Status)) { goto ErrorExit; } // // Report status code: begin IdeBus initialization // REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET), ParentDevicePath ); // // Strictly follow the enumeration based on IDE_CONTROLLER_INIT protocol // for (IdeChannel = BeginningIdeChannel; IdeChannel <= EndIdeChannel; IdeChannel++) { IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, IdeChannel); // // now obtain channel information fron IdeControllerInit protocol. Step9 // Status = IdeInit->GetChannelInfo ( IdeInit, IdeChannel, &ChannelEnabled, &MaxDevices ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "[GetChannel, Status=%x]", Status)); continue; } if (!ChannelEnabled) { continue; } EndIdeDevice = (UINT8) MIN ((MaxDevices - 1), EndIdeDevice); ASSERT (EndIdeDevice < IdeMaxDevice); // // Now inform the IDE Controller Init Module. Sept10 // IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelReset, IdeChannel); // // No reset channel function implemented. Sept11 // IdeInit->NotifyPhase (IdeInit, EfiIdeAfterChannelReset, IdeChannel); // // Step13 // IdeInit->NotifyPhase ( IdeInit, EfiIdeBusBeforeDevicePresenceDetection, IdeChannel ); // // Prepare to detect IDE device of this channel // InitializeIDEChannelData (); // // -- 1st inner loop --- Master/Slave ------------ Step14 // for (IdeDevice = BeginningIdeDevice; IdeDevice <= EndIdeDevice; IdeDevice++) { // // Check whether the configuration options allow this device // if ((ConfigurationOptions & (1 << (IdeChannel * 2 + IdeDevice))) == 0) { continue; } // // The device has been scanned in another Start(), No need to scan it again // for perf optimization. // if (IdeBusDriverPrivateData->HaveScannedDevice[IdeChannel * 2 + IdeDevice]) { continue; } // // create child handle for the detected device. // IdeBlkIoDevice[IdeChannel][IdeDevice] = AllocatePool (sizeof (IDE_BLK_IO_DEV)); if (IdeBlkIoDevice[IdeChannel][IdeDevice] == NULL) { continue; } IdeBlkIoDevicePtr = IdeBlkIoDevice[IdeChannel][IdeDevice]; ZeroMem (IdeBlkIoDevicePtr, sizeof (IDE_BLK_IO_DEV)); IdeBlkIoDevicePtr->Signature = IDE_BLK_IO_DEV_SIGNATURE; IdeBlkIoDevicePtr->Channel = (EFI_IDE_CHANNEL) IdeChannel; IdeBlkIoDevicePtr->Device = (EFI_IDE_DEVICE) IdeDevice; // // initialize Block IO interface's Media pointer // IdeBlkIoDevicePtr->BlkIo.Media = &IdeBlkIoDevicePtr->BlkMedia; // // Initialize IDE IO port addresses, including Command Block registers // and Control Block registers // IdeBlkIoDevicePtr->IoPort = AllocatePool (sizeof (IDE_BASE_REGISTERS)); if (IdeBlkIoDevicePtr->IoPort == NULL) { continue; } ZeroMem (IdeBlkIoDevicePtr->IoPort, sizeof (IDE_BASE_REGISTERS)); CommandBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].CommandBlockBaseAddr; ControlBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].ControlBlockBaseAddr; IdeBlkIoDevicePtr->IoPort->Data = CommandBlockBaseAddr; (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01); IdeBlkIoDevicePtr->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02); IdeBlkIoDevicePtr->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03); IdeBlkIoDevicePtr->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04); IdeBlkIoDevicePtr->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05); IdeBlkIoDevicePtr->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06); (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07); (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Alt) = ControlBlockBaseAddr; IdeBlkIoDevicePtr->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01); IdeBlkIoDevicePtr->IoPort->MasterSlave = (UINT16) ((IdeDevice == IdeMaster) ? 1 : 0); IdeBlkIoDevicePtr->PciIo = PciIo; IdeBlkIoDevicePtr->IdeBusDriverPrivateData = IdeBusDriverPrivateData; IdeBlkIoDevicePtr->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeChannel].BusMasterBaseAddr; // // Report Status code: is about to detect IDE drive // REPORT_STATUS_CODE_EX ( EFI_PROGRESS_CODE, (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_PRESENCE_DETECT), 0, &gEfiCallerIdGuid, NULL, NULL, 0 ); // // Discover device, now! // PERF_START (NULL, "DiscoverIdeDevice", "IDE", 0); Status = DiscoverIdeDevice (IdeBlkIoDevicePtr); PERF_END (NULL, "DiscoverIdeDevice", "IDE", 0); IdeBusDriverPrivateData->HaveScannedDevice[IdeChannel * 2 + IdeDevice] = TRUE; IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice] = FALSE; if (!EFI_ERROR (Status)) { // // Set Device Path // ZeroMem (&NewNode, sizeof (NewNode)); NewNode.DevPath.Type = MESSAGING_DEVICE_PATH; NewNode.DevPath.SubType = MSG_ATAPI_DP; SetDevicePathNodeLength (&NewNode.DevPath, sizeof (ATAPI_DEVICE_PATH)); NewNode.Atapi.PrimarySecondary = (UINT8) IdeBlkIoDevicePtr->Channel; NewNode.Atapi.SlaveMaster = (UINT8) IdeBlkIoDevicePtr->Device; NewNode.Atapi.Lun = IdeBlkIoDevicePtr->Lun; IdeBlkIoDevicePtr->DevicePath = AppendDevicePathNode ( ParentDevicePath, &NewNode.DevPath ); if (IdeBlkIoDevicePtr->DevicePath == NULL) { ReleaseIdeResources (IdeBlkIoDevicePtr); continue; } // // Submit identify data to IDE controller init driver // CopyMem (&IdentifyData, IdeBlkIoDevicePtr->IdData, sizeof (IdentifyData)); IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = TRUE; IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, &IdentifyData); } else { // // Device detection failed // IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE; IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, NULL); ReleaseIdeResources (IdeBlkIoDevicePtr); IdeBlkIoDevicePtr = NULL; } // // end of 1st inner loop --- // } // // end of 1st outer loop ========= // } // // = 2nd outer loop == Primary/Secondary ================= // for (IdeChannel = BeginningIdeChannel; IdeChannel <= EndIdeChannel; IdeChannel++) { // // -- 2nd inner loop --- Master/Slave -------- // for (IdeDevice = BeginningIdeDevice; IdeDevice <= EndIdeDevice; IdeDevice++) { ASSERT (IdeChannel * 2 + IdeDevice < MAX_IDE_DEVICE); if (IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice]) { continue; } if (!IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice]) { continue; } Status = IdeInit->CalculateMode ( IdeInit, IdeChannel, IdeDevice, &SupportedModes ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "[bStStp20S=%x]", Status)); continue; } ASSERT (IdeChannel < IdeMaxChannel && IdeDevice < IdeMaxDevice); IdeBlkIoDevicePtr = IdeBlkIoDevice[IdeChannel][IdeDevice]; // // Set best supported PIO mode on this IDE device // if (SupportedModes->PioMode.Mode <= AtaPioMode2) { TransferMode.ModeCategory = ATA_MODE_CATEGORY_DEFAULT_PIO; } else { TransferMode.ModeCategory = ATA_MODE_CATEGORY_FLOW_PIO; } TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode); if (SupportedModes->ExtModeCount == 0){ Status = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode); if (EFI_ERROR (Status)) { IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE; ReleaseIdeResources (IdeBlkIoDevicePtr); IdeBlkIoDevicePtr = NULL; continue; } } // // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't // be set together. Only one DMA mode can be set to a device. If setting // DMA mode operation fails, we can continue moving on because we only use // PIO mode at boot time. DMA modes are used by certain kind of OS booting // if (SupportedModes->UdmaMode.Valid) { TransferMode.ModeCategory = ATA_MODE_CATEGORY_UDMA; TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode); Status = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode); if (EFI_ERROR (Status)) { IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE; ReleaseIdeResources (IdeBlkIoDevicePtr); IdeBlkIoDevicePtr = NULL; continue; } // // Record Udma Mode // IdeBlkIoDevicePtr->UdmaMode.Valid = TRUE; IdeBlkIoDevicePtr->UdmaMode.Mode = SupportedModes->UdmaMode.Mode; EnableInterrupt (IdeBlkIoDevicePtr); } else if (SupportedModes->MultiWordDmaMode.Valid) { TransferMode.ModeCategory = ATA_MODE_CATEGORY_MDMA; TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode; Status = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode); if (EFI_ERROR (Status)) { IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE; ReleaseIdeResources (IdeBlkIoDevicePtr); IdeBlkIoDevicePtr = NULL; continue; } EnableInterrupt (IdeBlkIoDevicePtr); } // // Init driver parameters // DriveParameters.Sector = (UINT8) ((ATA5_IDENTIFY_DATA *) IdeBlkIoDevicePtr->IdData)->sectors_per_track; DriveParameters.Heads = (UINT8) (((ATA5_IDENTIFY_DATA *) IdeBlkIoDevicePtr->IdData)->heads - 1); DriveParameters.MultipleSector = (UINT8) IdeBlkIoDevicePtr->IdData->AtaData.multi_sector_cmd_max_sct_cnt; // // Set Parameters for the device: // 1) Init // 2) Establish the block count for READ/WRITE MULTIPLE (EXT) command // if ((IdeBlkIoDevicePtr->Type == IdeHardDisk) || (IdeBlkIoDevicePtr->Type == Ide48bitAddressingHardDisk)) { Status = SetDriveParameters (IdeBlkIoDevicePtr, &DriveParameters); } // // Record PIO mode used in private data // IdeBlkIoDevicePtr->PioMode = (ATA_PIO_MODE) SupportedModes->PioMode.Mode; // // Set IDE controller Timing Blocks in the PCI Configuration Space // IdeInit->SetTiming (IdeInit, IdeChannel, IdeDevice, SupportedModes); // // Add Component Name for the IDE/ATAPI device that was discovered. // IdeBlkIoDevicePtr->ControllerNameTable = NULL; ADD_IDE_ATAPI_NAME (IdeBlkIoDevicePtr); Status = gBS->InstallMultipleProtocolInterfaces ( &IdeBlkIoDevicePtr->Handle, &gEfiDevicePathProtocolGuid, IdeBlkIoDevicePtr->DevicePath, &gEfiBlockIoProtocolGuid, &IdeBlkIoDevicePtr->BlkIo, &gEfiDiskInfoProtocolGuid, &IdeBlkIoDevicePtr->DiskInfo, NULL ); if (EFI_ERROR (Status)) { ReleaseIdeResources (IdeBlkIoDevicePtr); } gBS->OpenProtocol ( Controller, &gEfiPciIoProtocolGuid, (VOID **) &PciIo, This->DriverBindingHandle, IdeBlkIoDevicePtr->Handle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice] = TRUE; // // Report status code: device eanbled! // REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_ENABLE), IdeBlkIoDevicePtr->DevicePath ); // // Create event to clear pending IDE interrupt // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, ClearInterrupt, IdeBlkIoDevicePtr, &gEfiEventExitBootServicesGuid, &IdeBlkIoDevicePtr->ExitBootServiceEvent ); // // end of 2nd inner loop ---- // } // // end of 2nd outer loop ========== // } // // All configurations done! Notify IdeController to do post initialization // work such as saving IDE controller PCI settings for S3 resume // IdeInit->NotifyPhase (IdeInit, EfiIdeBusPhaseMaximum, 0); if (SupportedModes != NULL) { FreePool (SupportedModes); } PERF_START (NULL, "Finish IDE detection", "IDE", 1); PERF_END (NULL, "Finish IDE detection", "IDE", 0); return EFI_SUCCESS; ErrorExit: // // Report error code: controller error // REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_ERROR_CODE | EFI_ERROR_MINOR, (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_EC_CONTROLLER_ERROR), ParentDevicePath ); gBS->CloseProtocol ( Controller, &gEfiIdeControllerInitProtocolGuid, This->DriverBindingHandle, Controller ); gBS->UninstallMultipleProtocolInterfaces ( Controller, &gEfiCallerIdGuid, IdeBusDriverPrivateData, NULL ); if (IdeBusDriverPrivateData != NULL) { gBS->FreePool (IdeBusDriverPrivateData); } if (SupportedModes != NULL) { gBS->FreePool (SupportedModes); } gBS->CloseProtocol ( Controller, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, Controller ); gBS->CloseProtocol ( Controller, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, Controller ); return Status; }