/** Destory FrameList buffer. @param Uhc The UHCI device. **/ VOID UhciDestoryFrameList ( IN USB_HC_DEV *Uhc ) { // // Unmap the common buffer for framelist entry, // and free the common buffer. // Uhci's frame list occupy 4k memory. // Uhc->PciIo->Unmap (Uhc->PciIo, Uhc->FrameMapping); Uhc->PciIo->FreeBuffer ( Uhc->PciIo, EFI_SIZE_TO_PAGES (4096), (VOID *) Uhc->FrameBase ); if (Uhc->FrameBaseHostAddr != NULL) { FreePool (Uhc->FrameBaseHostAddr); } if (Uhc->SyncIntQh != NULL) { UsbHcFreeMem (Uhc->MemPool, Uhc->SyncIntQh, sizeof (UHCI_QH_SW)); } if (Uhc->CtrlQh != NULL) { UsbHcFreeMem (Uhc->MemPool, Uhc->CtrlQh, sizeof (UHCI_QH_SW)); } if (Uhc->BulkQh != NULL) { UsbHcFreeMem (Uhc->MemPool, Uhc->BulkQh, sizeof (UHCI_QH_SW)); } Uhc->FrameBase = NULL; Uhc->FrameBaseHostAddr = NULL; Uhc->SyncIntQh = NULL; Uhc->CtrlQh = NULL; Uhc->BulkQh = NULL; }
/** Allocate reset vector buffer. @param[in, out] CpuMpData The pointer to CPU MP Data structure. **/ VOID AllocateResetVector ( IN OUT CPU_MP_DATA *CpuMpData ) { EFI_STATUS Status; UINTN ApResetVectorSize; EFI_PHYSICAL_ADDRESS StartAddress; if (CpuMpData->SaveRestoreFlag) { BackupAndPrepareWakeupBuffer (CpuMpData); } else { ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO); StartAddress = BASE_1MB; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (ApResetVectorSize), &StartAddress ); ASSERT_EFI_ERROR (Status); CpuMpData->WakeupBuffer = (UINTN) StartAddress; CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize); // // copy AP reset code in it // CopyMem ( (VOID *) CpuMpData->WakeupBuffer, (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress, CpuMpData->AddressMap.RendezvousFunnelSize ); } }
/** Initialize the shadow stack related data structure. @param CpuIndex The index of CPU. @param ShadowStack The bottom of the shadow stack for this CPU. **/ VOID InitShadowStack ( IN UINTN CpuIndex, IN VOID *ShadowStack ) { UINTN SmmShadowStackSize; UINT64 *InterruptSspTable; if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) { SmmShadowStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmShadowStackSize))); if (FeaturePcdGet (PcdCpuSmmStackGuard)) { SmmShadowStackSize += EFI_PAGES_TO_SIZE (2); } mCetPl0Ssp = (UINT32)((UINTN)ShadowStack + SmmShadowStackSize - sizeof(UINT64)); PatchInstructionX86 (mPatchCetPl0Ssp, mCetPl0Ssp, 4); DEBUG ((DEBUG_INFO, "mCetPl0Ssp - 0x%x\n", mCetPl0Ssp)); DEBUG ((DEBUG_INFO, "ShadowStack - 0x%x\n", ShadowStack)); DEBUG ((DEBUG_INFO, " SmmShadowStackSize - 0x%x\n", SmmShadowStackSize)); if (FeaturePcdGet (PcdCpuSmmStackGuard)) { if (mSmmInterruptSspTables == 0) { mSmmInterruptSspTables = (UINTN)AllocateZeroPool(sizeof(UINT64) * 8 * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus); ASSERT (mSmmInterruptSspTables != 0); DEBUG ((DEBUG_INFO, "mSmmInterruptSspTables - 0x%x\n", mSmmInterruptSspTables)); } mCetInterruptSsp = (UINT32)((UINTN)ShadowStack + EFI_PAGES_TO_SIZE(1) - sizeof(UINT64)); mCetInterruptSspTable = (UINT32)(UINTN)(mSmmInterruptSspTables + sizeof(UINT64) * 8 * CpuIndex); InterruptSspTable = (UINT64 *)(UINTN)mCetInterruptSspTable; InterruptSspTable[1] = mCetInterruptSsp; PatchInstructionX86 (mPatchCetInterruptSsp, mCetInterruptSsp, 4); PatchInstructionX86 (mPatchCetInterruptSspTable, mCetInterruptSspTable, 4); DEBUG ((DEBUG_INFO, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp)); DEBUG ((DEBUG_INFO, "mCetInterruptSspTable - 0x%x\n", mCetInterruptSspTable)); } } }
/** Perform CPU specific actions required to migrate the PEI Services Table pointer from temporary RAM to permanent RAM. For IA32 CPUs, the PEI Services Table pointer is stored in the 4 bytes immediately preceding the Interrupt Descriptor Table (IDT) in memory. For X64 CPUs, the PEI Services Table pointer is stored in the 8 bytes immediately preceding the Interrupt Descriptor Table (IDT) in memory. For Itanium and ARM CPUs, a the PEI Services Table Pointer is stored in a dedicated CPU register. This means that there is no memory storage associated with storing the PEI Services Table pointer, so no additional migration actions are required for Itanium or ARM CPUs. If The cached PEI Services Table pointer is NULL, then ASSERT(). If the permanent memory is allocated failed, then ASSERT(). **/ VOID EFIAPI MigratePeiServicesTablePointer ( VOID ) { EFI_STATUS Status; IA32_DESCRIPTOR Idtr; EFI_PHYSICAL_ADDRESS IdtBase; CONST EFI_PEI_SERVICES **PeiServices; // // Get PEI Services Table pointer // AsmReadIdtr (&Idtr); PeiServices = (CONST EFI_PEI_SERVICES **) (*(UINTN*)(Idtr.Base - sizeof (UINTN))); ASSERT (PeiServices != NULL); // // Allocate the permanent memory. // Status = (*PeiServices)->AllocatePages ( PeiServices, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Idtr.Limit + 1 + sizeof (UINTN)), &IdtBase ); ASSERT_EFI_ERROR (Status); // // Idt table needs to be migrated into memory. // CopyMem ((VOID *) (UINTN) IdtBase, (VOID *) (Idtr.Base - sizeof (UINTN)), Idtr.Limit + 1 + sizeof (UINTN)); Idtr.Base = (UINTN) IdtBase + sizeof (UINTN); AsmWriteIdtr (&Idtr); return; }
/** Allocate EfiACPIMemoryNVS memory. @param[in] Size Size of memory to allocate. @return Allocated address for output. **/ VOID * AllocateAcpiNvsMemory ( IN UINTN Size ) { EFI_PHYSICAL_ADDRESS Address; EFI_STATUS Status; VOID *Buffer; Status = gBS->AllocatePages ( AllocateAnyPages, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &Address ); if (EFI_ERROR (Status)) { return NULL; } Buffer = (VOID *)(UINTN)Address; ZeroMem (Buffer, Size); return Buffer; }
/** Initialize SMM profile data structures. **/ VOID InitSmmProfileInternal ( VOID ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS Base; VOID *Registration; UINTN Index; UINTN MsrDsAreaSizePerCpu; UINTN TotalSize; mPFEntryCount = (UINTN *)AllocateZeroPool (sizeof (UINTN) * mMaxNumberOfCpus); ASSERT (mPFEntryCount != NULL); mLastPFEntryValue = (UINT64 (*)[MAX_PF_ENTRY_COUNT])AllocateZeroPool ( sizeof (mLastPFEntryValue[0]) * mMaxNumberOfCpus); ASSERT (mLastPFEntryValue != NULL); mLastPFEntryPointer = (UINT64 *(*)[MAX_PF_ENTRY_COUNT])AllocateZeroPool ( sizeof (mLastPFEntryPointer[0]) * mMaxNumberOfCpus); ASSERT (mLastPFEntryPointer != NULL); // // Allocate memory for SmmProfile below 4GB. // The base address // mSmmProfileSize = PcdGet32 (PcdCpuSmmProfileSize); ASSERT ((mSmmProfileSize & 0xFFF) == 0); if (mBtsSupported) { TotalSize = mSmmProfileSize + mMsrDsAreaSize; } else { TotalSize = mSmmProfileSize; } Base = 0xFFFFFFFF; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiReservedMemoryType, EFI_SIZE_TO_PAGES (TotalSize), &Base ); ASSERT_EFI_ERROR (Status); ZeroMem ((VOID *)(UINTN)Base, TotalSize); mSmmProfileBase = (SMM_PROFILE_HEADER *)(UINTN)Base; // // Initialize SMM profile data header. // mSmmProfileBase->HeaderSize = sizeof (SMM_PROFILE_HEADER); mSmmProfileBase->MaxDataEntries = (UINT64)((mSmmProfileSize - sizeof(SMM_PROFILE_HEADER)) / sizeof (SMM_PROFILE_ENTRY)); mSmmProfileBase->MaxDataSize = MultU64x64 (mSmmProfileBase->MaxDataEntries, sizeof(SMM_PROFILE_ENTRY)); mSmmProfileBase->CurDataEntries = 0; mSmmProfileBase->CurDataSize = 0; mSmmProfileBase->TsegStart = mCpuHotPlugData.SmrrBase; mSmmProfileBase->TsegSize = mCpuHotPlugData.SmrrSize; mSmmProfileBase->NumSmis = 0; mSmmProfileBase->NumCpus = gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; if (mBtsSupported) { mMsrDsArea = (MSR_DS_AREA_STRUCT **)AllocateZeroPool (sizeof (MSR_DS_AREA_STRUCT *) * mMaxNumberOfCpus); ASSERT (mMsrDsArea != NULL); mMsrBTSRecord = (BRANCH_TRACE_RECORD **)AllocateZeroPool (sizeof (BRANCH_TRACE_RECORD *) * mMaxNumberOfCpus); ASSERT (mMsrBTSRecord != NULL); mMsrPEBSRecord = (PEBS_RECORD **)AllocateZeroPool (sizeof (PEBS_RECORD *) * mMaxNumberOfCpus); ASSERT (mMsrPEBSRecord != NULL); mMsrDsAreaBase = (MSR_DS_AREA_STRUCT *)((UINTN)Base + mSmmProfileSize); MsrDsAreaSizePerCpu = mMsrDsAreaSize / mMaxNumberOfCpus; mBTSRecordNumber = (MsrDsAreaSizePerCpu - sizeof(PEBS_RECORD) * PEBS_RECORD_NUMBER - sizeof(MSR_DS_AREA_STRUCT)) / sizeof(BRANCH_TRACE_RECORD); for (Index = 0; Index < mMaxNumberOfCpus; Index++) { mMsrDsArea[Index] = (MSR_DS_AREA_STRUCT *)((UINTN)mMsrDsAreaBase + MsrDsAreaSizePerCpu * Index); mMsrBTSRecord[Index] = (BRANCH_TRACE_RECORD *)((UINTN)mMsrDsArea[Index] + sizeof(MSR_DS_AREA_STRUCT)); mMsrPEBSRecord[Index] = (PEBS_RECORD *)((UINTN)mMsrDsArea[Index] + MsrDsAreaSizePerCpu - sizeof(PEBS_RECORD) * PEBS_RECORD_NUMBER); mMsrDsArea[Index]->BTSBufferBase = (UINTN)mMsrBTSRecord[Index]; mMsrDsArea[Index]->BTSIndex = mMsrDsArea[Index]->BTSBufferBase; mMsrDsArea[Index]->BTSAbsoluteMaximum = mMsrDsArea[Index]->BTSBufferBase + mBTSRecordNumber * sizeof(BRANCH_TRACE_RECORD) + 1; mMsrDsArea[Index]->BTSInterruptThreshold = mMsrDsArea[Index]->BTSAbsoluteMaximum + 1; mMsrDsArea[Index]->PEBSBufferBase = (UINTN)mMsrPEBSRecord[Index]; mMsrDsArea[Index]->PEBSIndex = mMsrDsArea[Index]->PEBSBufferBase; mMsrDsArea[Index]->PEBSAbsoluteMaximum = mMsrDsArea[Index]->PEBSBufferBase + PEBS_RECORD_NUMBER * sizeof(PEBS_RECORD) + 1; mMsrDsArea[Index]->PEBSInterruptThreshold = mMsrDsArea[Index]->PEBSAbsoluteMaximum + 1; } } mProtectionMemRange = mProtectionMemRangeTemplate; mProtectionMemRangeCount = sizeof (mProtectionMemRangeTemplate) / sizeof (MEMORY_PROTECTION_RANGE); // // Update TSeg entry. // mProtectionMemRange[0].Range.Base = mCpuHotPlugData.SmrrBase; mProtectionMemRange[0].Range.Top = mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize; // // Update SMM profile entry. // mProtectionMemRange[1].Range.Base = (EFI_PHYSICAL_ADDRESS)(UINTN)mSmmProfileBase; mProtectionMemRange[1].Range.Top = (EFI_PHYSICAL_ADDRESS)(UINTN)mSmmProfileBase + TotalSize; // // Allocate memory reserved for creating 4KB pages. // InitPagesForPFHandler (); // // Start SMM profile when SmmReadyToLock protocol is installed. // Status = gSmst->SmmRegisterProtocolNotify ( &gEfiSmmReadyToLockProtocolGuid, InitSmmProfileCallBack, &Registration ); ASSERT_EFI_ERROR (Status); return ; }
/** Main entry point. @param[in] ImageHandle The firmware allocated handle for the EFI image. @param[in] SystemTable A pointer to the EFI System Table. @retval EFI_SUCCESS Successfully initialized. **/ EFI_STATUS EFIAPI FvbInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; VOID *Ptr; VOID *SubPtr; BOOLEAN Initialize; EFI_HANDLE Handle; EFI_PHYSICAL_ADDRESS Address; RETURN_STATUS PcdStatus; DEBUG ((EFI_D_INFO, "EMU Variable FVB Started\n")); // // Verify that the PCD's are set correctly. // if ( (PcdGet32 (PcdVariableStoreSize) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) ) > EMU_FVB_BLOCK_SIZE ) { DEBUG ((EFI_D_ERROR, "EMU Variable invalid PCD sizes\n")); return EFI_INVALID_PARAMETER; } if (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0) { DEBUG ((EFI_D_INFO, "Disabling EMU Variable FVB since " "flash variables appear to be supported.\n")); return EFI_ABORTED; } // // By default we will initialize the FV contents. But, if // PcdEmuVariableNvStoreReserved is non-zero, then we will // use this location for our buffer. // // If this location does not have a proper FV header, then // we will initialize it. // Initialize = TRUE; if (PcdGet64 (PcdEmuVariableNvStoreReserved) != 0) { Ptr = (VOID*)(UINTN) PcdGet64 (PcdEmuVariableNvStoreReserved); DEBUG (( EFI_D_INFO, "EMU Variable FVB: Using pre-reserved block at %p\n", Ptr )); Status = ValidateFvHeader (Ptr); if (!EFI_ERROR (Status)) { DEBUG ((EFI_D_INFO, "EMU Variable FVB: Found valid pre-existing FV\n")); Initialize = FALSE; } } else { Ptr = AllocateAlignedRuntimePages ( EFI_SIZE_TO_PAGES (EMU_FVB_SIZE), SIZE_64KB ); } mEmuVarsFvb.BufferPtr = Ptr; // // Initialize the main FV header and variable store header // if (Initialize) { SetMem (Ptr, EMU_FVB_SIZE, ERASED_UINT8); InitializeFvAndVariableStoreHeaders (Ptr); } PcdStatus = PcdSet64S (PcdFlashNvStorageVariableBase64, (UINT32)(UINTN) Ptr); ASSERT_RETURN_ERROR (PcdStatus); // // Initialize the Fault Tolerant Write data area // SubPtr = (VOID*) ((UINT8*) Ptr + PcdGet32 (PcdVariableStoreSize)); PcdStatus = PcdSet32S (PcdFlashNvStorageFtwWorkingBase, (UINT32)(UINTN) SubPtr); ASSERT_RETURN_ERROR (PcdStatus); // // Initialize the Fault Tolerant Write spare block // SubPtr = (VOID*) ((UINT8*) Ptr + EMU_FVB_BLOCK_SIZE); PcdStatus = PcdSet32S (PcdFlashNvStorageFtwSpareBase, (UINT32)(UINTN) SubPtr); ASSERT_RETURN_ERROR (PcdStatus); // // Setup FVB device path // Address = (EFI_PHYSICAL_ADDRESS)(UINTN) Ptr; mEmuVarsFvb.DevicePath.MemMapDevPath.StartingAddress = Address; mEmuVarsFvb.DevicePath.MemMapDevPath.EndingAddress = Address + EMU_FVB_SIZE - 1; // // Install the protocols // DEBUG ((EFI_D_INFO, "Installing FVB for EMU Variable support\n")); Handle = 0; Status = gBS->InstallMultipleProtocolInterfaces ( &Handle, &gEfiFirmwareVolumeBlock2ProtocolGuid, &mEmuVarsFvb.FwVolBlockInstance, &gEfiDevicePathProtocolGuid, &mEmuVarsFvb.DevicePath, NULL ); ASSERT_EFI_ERROR (Status); // // Register for the virtual address change event // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, FvbVirtualAddressChangeEvent, NULL, &gEfiEventVirtualAddressChangeGuid, &mEmuVarsFvbAddrChangeEvent ); ASSERT_EFI_ERROR (Status); return EFI_SUCCESS; }
/** Decompresses a section to the output buffer. This function looks up the compression type field in the input section and applies the appropriate compression algorithm to compress the section to a callee allocated buffer. @param This Points to this instance of the EFI_PEI_DECOMPRESS_PEI PPI. @param CompressionSection Points to the compressed section. @param OutputBuffer Holds the returned pointer to the decompressed sections. @param OutputSize Holds the returned size of the decompress section streams. @retval EFI_SUCCESS The section was decompressed successfully. OutputBuffer contains the resulting data and OutputSize contains the resulting size. **/ EFI_STATUS EFIAPI Decompress ( IN CONST EFI_PEI_DECOMPRESS_PPI *This, IN CONST EFI_COMPRESSION_SECTION *CompressionSection, OUT VOID **OutputBuffer, OUT UINTN *OutputSize ) { EFI_STATUS Status; UINT8 *DstBuffer; UINT8 *ScratchBuffer; UINT32 DstBufferSize; UINT32 ScratchBufferSize; VOID *CompressionSource; UINT32 CompressionSourceSize; UINT32 UncompressedLength; UINT8 CompressionType; if (CompressionSection->CommonHeader.Type != EFI_SECTION_COMPRESSION) { ASSERT (FALSE); return EFI_INVALID_PARAMETER; } if (IS_SECTION2 (CompressionSection)) { CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION2)); CompressionSourceSize = (UINT32) (SECTION2_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION2)); UncompressedLength = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->UncompressedLength; CompressionType = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->CompressionType; } else { CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION)); CompressionSourceSize = (UINT32) (SECTION_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION)); UncompressedLength = CompressionSection->UncompressedLength; CompressionType = CompressionSection->CompressionType; } // // This is a compression set, expand it // switch (CompressionType) { case EFI_STANDARD_COMPRESSION: if (FeaturePcdGet(PcdDxeIplSupportUefiDecompress)) { // // Load EFI standard compression. // For compressed data, decompress them to destination buffer. // Status = UefiDecompressGetInfo ( CompressionSource, CompressionSourceSize, &DstBufferSize, &ScratchBufferSize ); if (EFI_ERROR (Status)) { // // GetInfo failed // DEBUG ((DEBUG_ERROR, "Decompress GetInfo Failed - %r\n", Status)); return EFI_NOT_FOUND; } // // Allocate scratch buffer // ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize)); if (ScratchBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } // // Allocate destination buffer, extra one page for adjustment // DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1); if (DstBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } // // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header // to make section data at page alignment. // DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER); // // Call decompress function // Status = UefiDecompress ( CompressionSource, DstBuffer, ScratchBuffer ); if (EFI_ERROR (Status)) { // // Decompress failed // DEBUG ((DEBUG_ERROR, "Decompress Failed - %r\n", Status)); return EFI_NOT_FOUND; } break; } else { // // PcdDxeIplSupportUefiDecompress is FALSE // Don't support UEFI decompression algorithm. // ASSERT (FALSE); return EFI_NOT_FOUND; } case EFI_NOT_COMPRESSED: // // Allocate destination buffer // DstBufferSize = UncompressedLength; DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1); if (DstBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } // // Adjust DstBuffer offset, skip EFI section header // to make section data at page alignment. // DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER); // // stream is not actually compressed, just encapsulated. So just copy it. // CopyMem (DstBuffer, CompressionSource, DstBufferSize); break; default: // // Don't support other unknown compression type. // ASSERT (FALSE); return EFI_NOT_FOUND; } *OutputSize = DstBufferSize; *OutputBuffer = DstBuffer; return EFI_SUCCESS; }
/** The ExtractSection() function processes the input section and returns a pointer to the section contents. If the section being extracted does not require processing (if the section GuidedSectionHeader.Attributes has the EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then OutputBuffer is just updated to point to the start of the section's contents. Otherwise, *Buffer must be allocated from PEI permanent memory. @param This Indicates the EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance. Buffer containing the input GUIDed section to be processed. OutputBuffer OutputBuffer is allocated from PEI permanent memory and contains the new section stream. @param InputSection A pointer to the input buffer, which contains the input section to be processed. @param OutputBuffer A pointer to a caller-allocated buffer, whose size is specified by the contents of OutputSize. @param OutputSize A pointer to a caller-allocated UINTN in which the size of *OutputBuffer allocation is stored. If the function returns anything other than EFI_SUCCESS, the value of OutputSize is undefined. @param AuthenticationStatus A pointer to a caller-allocated UINT32 that indicates the authentication status of the output buffer. If the input section's GuidedSectionHeader. Attributes field has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit as clear, AuthenticationStatus must return zero. These bits reflect the status of the extraction operation. If the function returns anything other than EFI_SUCCESS, the value of AuthenticationStatus is undefined. @retval EFI_SUCCESS The InputSection was successfully processed and the section contents were returned. @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process the request. @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance of the GUIDed Section Extraction PPI. **/ EFI_STATUS EFIAPI CustomGuidedSectionExtract ( IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This, IN CONST VOID *InputSection, OUT VOID **OutputBuffer, OUT UINTN *OutputSize, OUT UINT32 *AuthenticationStatus ) { EFI_STATUS Status; UINT8 *ScratchBuffer; UINT32 ScratchBufferSize; UINT32 OutputBufferSize; UINT16 SectionAttribute; // // Init local variable // ScratchBuffer = NULL; // // Call GetInfo to get the size and attribute of input guided section data. // Status = ExtractGuidedSectionGetInfo ( InputSection, &OutputBufferSize, &ScratchBufferSize, &SectionAttribute ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status)); return Status; } if (ScratchBufferSize != 0) { // // Allocate scratch buffer // ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize)); if (ScratchBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } } if (((SectionAttribute & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) && OutputBufferSize > 0) { // // Allocate output buffer // *OutputBuffer = AllocatePages (EFI_SIZE_TO_PAGES (OutputBufferSize) + 1); if (*OutputBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } DEBUG ((DEBUG_INFO, "Customized Guided section Memory Size required is 0x%x and address is 0x%p\n", OutputBufferSize, *OutputBuffer)); // // *OutputBuffer still is one section. Adjust *OutputBuffer offset, // skip EFI section header to make section data at page alignment. // *OutputBuffer = (VOID *)((UINT8 *) *OutputBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER)); } Status = ExtractGuidedSectionDecode ( InputSection, OutputBuffer, ScratchBuffer, AuthenticationStatus ); if (EFI_ERROR (Status)) { // // Decode failed // DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status)); return Status; } *OutputSize = (UINTN) OutputBufferSize; return EFI_SUCCESS; }
void efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) { static EFI_GUID image_protocol = LOADED_IMAGE_PROTOCOL; EFI_LOADED_IMAGE *img; CHAR16 *argp, *args, **argv; EFI_STATUS status; int argc, addprog; IH = image_handle; ST = system_table; BS = ST->BootServices; RS = ST->RuntimeServices; heapsize = 512*1024; status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, EFI_SIZE_TO_PAGES(heapsize), &heap); if (status != EFI_SUCCESS) BS->Exit(IH, status, 0, NULL); setheap((void *)heap, (void *)(heap + heapsize)); /* Use exit() from here on... */ status = BS->HandleProtocol(IH, &image_protocol, (VOID**)&img); if (status != EFI_SUCCESS) exit(status); /* * Pre-process the (optional) load options. If the option string * is given as an ASCII string, we use a poor man's ASCII to * Unicode-16 translation. The size of the option string as given * to us includes the terminating null character. We assume the * string is an ASCII string if strlen() plus the terminating * '\0' is less than LoadOptionsSize. Even if all Unicode-16 * characters have the upper 8 bits non-zero, the terminating * null character will cause a one-off. * If the string is already in Unicode-16, we make a copy so that * we know we can always modify the string. */ if (img->LoadOptionsSize > 0 && img->LoadOptions != NULL) { if (img->LoadOptionsSize == strlen(img->LoadOptions) + 1) { args = malloc(img->LoadOptionsSize << 1); for (argc = 0; argc < img->LoadOptionsSize; argc++) args[argc] = ((char*)img->LoadOptions)[argc]; } else { args = malloc(img->LoadOptionsSize); memcpy(args, img->LoadOptions, img->LoadOptionsSize); } } else args = NULL; /* * Use a quick and dirty algorithm to build the argv vector. We * first count the number of words. Then, after allocating the * vector, we split the string up. We don't deal with quotes or * other more advanced shell features. * The EFI shell will pas the name of the image as the first * word in the argument list. This does not happen if we're * loaded by the boot manager. This is not so easy to figure * out though. The ParentHandle is not always NULL, because * there can be a function (=image) that will perform the task * for the boot manager. */ /* Part 1: Figure out if we need to add our program name. */ addprog = (args == NULL || img->ParentHandle == NULL || img->FilePath == NULL) ? 1 : 0; if (!addprog) { addprog = (DevicePathType(img->FilePath) != MEDIA_DEVICE_PATH || DevicePathSubType(img->FilePath) != MEDIA_FILEPATH_DP || DevicePathNodeLength(img->FilePath) <= sizeof(FILEPATH_DEVICE_PATH)) ? 1 : 0; if (!addprog) { /* XXX todo. */ } } /* Part 2: count words. */ argc = (addprog) ? 1 : 0; argp = args; while (argp != NULL && *argp != 0) { argp = arg_skipsep(argp); if (*argp == 0) break; argc++; argp = arg_skipword(argp); } /* Part 3: build vector. */ argv = malloc((argc + 1) * sizeof(CHAR16*)); argc = 0; if (addprog) argv[argc++] = L"loader.efi"; argp = args; while (argp != NULL && *argp != 0) { argp = arg_skipsep(argp); if (*argp == 0) break; argv[argc++] = argp; argp = arg_skipword(argp); /* Terminate the words. */ if (*argp != 0) *argp++ = 0; } argv[argc] = NULL; status = main(argc, argv); exit(status); }
int ldr_bootinfo(struct bootinfo *bi, uint64_t *bi_addr) { VOID *fpswa; EFI_MEMORY_DESCRIPTOR *mm; EFI_PHYSICAL_ADDRESS addr; EFI_HANDLE handle; EFI_STATUS status; size_t bisz; UINTN mmsz, pages, sz; UINT32 mmver; bi->bi_systab = (uint64_t)ST; bi->bi_hcdp = (uint64_t)efi_get_table(&hcdp_guid); sz = sizeof(EFI_HANDLE); status = BS->LocateHandle(ByProtocol, &fpswa_guid, 0, &sz, &handle); if (status == 0) status = BS->HandleProtocol(handle, &fpswa_guid, &fpswa); bi->bi_fpswa = (status == 0) ? (uint64_t)fpswa : 0; bisz = (sizeof(struct bootinfo) + 0x0f) & ~0x0f; /* * Allocate enough pages to hold the bootinfo block and the memory * map EFI will return to us. The memory map has an unknown size, * so we have to determine that first. Note that the AllocatePages * call can itself modify the memory map, so we have to take that * into account as well. The changes to the memory map are caused * by splitting a range of free memory into two (AFAICT), so that * one is marked as being loader data. */ sz = 0; BS->GetMemoryMap(&sz, NULL, &mapkey, &mmsz, &mmver); sz += mmsz; sz = (sz + 15) & ~15; pages = EFI_SIZE_TO_PAGES(sz + bisz); status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, pages, &addr); if (EFI_ERROR(status)) { printf("%s: AllocatePages() returned 0x%lx\n", __func__, (long)status); return (ENOMEM); } /* * Read the memory map and stash it after bootinfo. Align the * memory map on a 16-byte boundary (the bootinfo block is page * aligned). */ *bi_addr = addr; mm = (void *)(addr + bisz); sz = (EFI_PAGE_SIZE * pages) - bisz; status = BS->GetMemoryMap(&sz, mm, &mapkey, &mmsz, &mmver); if (EFI_ERROR(status)) { printf("%s: GetMemoryMap() returned 0x%lx\n", __func__, (long)status); return (EINVAL); } bi->bi_memmap = (uint64_t)mm; bi->bi_memmap_size = sz; bi->bi_memdesc_size = mmsz; bi->bi_memdesc_version = mmver; bcopy(bi, (void *)(*bi_addr), sizeof(*bi)); return (0); }
VOID * UncachedInternalAllocateAlignedPages ( IN EFI_MEMORY_TYPE MemoryType, IN UINTN Pages, IN UINTN Alignment ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS Memory; EFI_PHYSICAL_ADDRESS AlignedMemory; UINTN AlignmentMask; UINTN UnalignedPages; UINTN RealPages; EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; // // Alignment must be a power of two or zero. // ASSERT ((Alignment & (Alignment - 1)) == 0); if (Pages == 0) { return NULL; } if (Alignment > EFI_PAGE_SIZE) { // // Caculate the total number of pages since alignment is larger than page size. // AlignmentMask = Alignment - 1; RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment); // // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow. // ASSERT (RealPages > Pages); Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory); if (EFI_ERROR (Status)) { return NULL; } AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask; UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory); if (UnalignedPages > 0) { // // Free first unaligned page(s). // Status = gBS->FreePages (Memory, UnalignedPages); ASSERT_EFI_ERROR (Status); } Memory = (EFI_PHYSICAL_ADDRESS) (AlignedMemory + EFI_PAGES_TO_SIZE (Pages)); UnalignedPages = RealPages - Pages - UnalignedPages; if (UnalignedPages > 0) { // // Free last unaligned page(s). // Status = gBS->FreePages (Memory, UnalignedPages); ASSERT_EFI_ERROR (Status); } } else { // // Do not over-allocate pages in this case. // Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory); if (EFI_ERROR (Status)) { return NULL; } AlignedMemory = (UINTN) Memory; } Status = gDS->GetMemorySpaceDescriptor (Memory, &Descriptor); if (!EFI_ERROR (Status)) { // We are making an assumption that all of memory has the same default attributes gAttributes = Descriptor.Attributes; } Status = gDS->SetMemorySpaceAttributes (Memory, EFI_PAGES_TO_SIZE (Pages), EFI_MEMORY_WC); ASSERT_EFI_ERROR (Status); return (VOID *)(UINTN)Memory; }
/** Return the Virtual Memory Map of your platform This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU on your platform. @param[out] VirtualMemoryMap Array of ARM_MEMORY_REGION_DESCRIPTOR describing a Physical-to- Virtual Memory mapping. This array must be ended by a zero-filled entry **/ VOID ArmPlatformGetVirtualMemoryMap ( IN ARM_MEMORY_REGION_DESCRIPTOR** VirtualMemoryMap ) { ARM_MEMORY_REGION_ATTRIBUTES CacheAttributes; //EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttributes; UINTN Index; ARM_MEMORY_REGION_DESCRIPTOR *VirtualMemoryTable; //UINT32 SysId; //BOOLEAN HasSparseMemory; //EFI_VIRTUAL_ADDRESS SparseMemoryBase; //UINT64 SparseMemorySize; EFI_PEI_HOB_POINTERS NextHob; ASSERT (VirtualMemoryMap != NULL); VirtualMemoryTable = (ARM_MEMORY_REGION_DESCRIPTOR*)AllocatePages(EFI_SIZE_TO_PAGES (sizeof(ARM_MEMORY_REGION_DESCRIPTOR) * MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS)); if (VirtualMemoryTable == NULL) { return; } if (FeaturePcdGet(PcdCacheEnable) == TRUE) { CacheAttributes = DDR_ATTRIBUTES_CACHED; } else { CacheAttributes = DDR_ATTRIBUTES_UNCACHED; } /* // ReMap (Either NOR Flash or DRAM) VirtualMemoryTable[Index].PhysicalBase = ARM_VE_REMAP_BASE; VirtualMemoryTable[Index].VirtualBase = ARM_VE_REMAP_BASE; VirtualMemoryTable[Index].Length = ARM_VE_REMAP_SZ; if (FeaturePcdGet(PcdNorFlashRemapping) == FALSE) { // Map the NOR Flash as Secure Memory if (FeaturePcdGet(PcdCacheEnable) == TRUE) { VirtualMemoryTable[Index].Attributes = DDR_ATTRIBUTES_CACHED; } else { VirtualMemoryTable[Index].Attributes = DDR_ATTRIBUTES_UNCACHED; } } else { // DRAM mapping VirtualMemoryTable[Index].Attributes = CacheAttributes; } */ Index = OemSetVirtualMapDesc(VirtualMemoryTable, CacheAttributes); // Search for System Memory Hob that contains the EFI resource system memory s00296804 NextHob.Raw = GetHobList (); while ((NextHob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, NextHob.Raw)) != NULL) { if (NextHob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) { if (NextHob.ResourceDescriptor->PhysicalStart > BASE_4GB)//只修改4G以上的属性 { VirtualMemoryTable[++Index].PhysicalBase = NextHob.ResourceDescriptor->PhysicalStart; VirtualMemoryTable[Index].VirtualBase = NextHob.ResourceDescriptor->PhysicalStart; VirtualMemoryTable[Index].Length =NextHob.ResourceDescriptor->ResourceLength; VirtualMemoryTable[Index].Attributes = CacheAttributes; } } NextHob.Raw = GET_NEXT_HOB (NextHob); } // End of Table VirtualMemoryTable[++Index].PhysicalBase = 0; VirtualMemoryTable[Index].VirtualBase = 0; VirtualMemoryTable[Index].Length = 0; VirtualMemoryTable[Index].Attributes = (ARM_MEMORY_REGION_ATTRIBUTES)0; ASSERT((Index + 1) <= MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS); DEBUG((EFI_D_ERROR, "[%a]:[%dL] discriptor count=%d\n", __FUNCTION__, __LINE__, Index+1)); *VirtualMemoryMap = VirtualMemoryTable; }
/** Process a QEMU_LOADER_ALLOCATE command. @param[in] Allocate The QEMU_LOADER_ALLOCATE command to process. @param[in,out] Tracker The ORDERED_COLLECTION tracking the BLOB user structures created thus far. @retval EFI_SUCCESS An area of whole AcpiNVS pages has been allocated for the blob contents, and the contents have been saved. A BLOB object (user structure) has been allocated from pool memory, referencing the blob contents. The BLOB user structure has been linked into Tracker. @retval EFI_PROTOCOL_ERROR Malformed fw_cfg file name has been found in Allocate, or the Allocate command references a file that is already known by Tracker. @retval EFI_UNSUPPORTED Unsupported alignment request has been found in Allocate. @retval EFI_OUT_OF_RESOURCES Pool allocation failed. @return Error codes from QemuFwCfgFindFile() and gBS->AllocatePages(). **/ STATIC EFI_STATUS EFIAPI ProcessCmdAllocate ( IN CONST QEMU_LOADER_ALLOCATE *Allocate, IN OUT ORDERED_COLLECTION *Tracker ) { FIRMWARE_CONFIG_ITEM FwCfgItem; UINTN FwCfgSize; EFI_STATUS Status; UINTN NumPages; EFI_PHYSICAL_ADDRESS Address; BLOB *Blob; if (Allocate->File[QEMU_LOADER_FNAME_SIZE - 1] != '\0') { DEBUG ((EFI_D_ERROR, "%a: malformed file name\n", __FUNCTION__)); return EFI_PROTOCOL_ERROR; } if (Allocate->Alignment > EFI_PAGE_SIZE) { DEBUG ((EFI_D_ERROR, "%a: unsupported alignment 0x%x\n", __FUNCTION__, Allocate->Alignment)); return EFI_UNSUPPORTED; } Status = QemuFwCfgFindFile ((CHAR8 *)Allocate->File, &FwCfgItem, &FwCfgSize); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "%a: QemuFwCfgFindFile(\"%a\"): %r\n", __FUNCTION__, Allocate->File, Status)); return Status; } NumPages = EFI_SIZE_TO_PAGES (FwCfgSize); Address = 0xFFFFFFFF; Status = gBS->AllocatePages (AllocateMaxAddress, EfiACPIMemoryNVS, NumPages, &Address); if (EFI_ERROR (Status)) { return Status; } Blob = AllocatePool (sizeof *Blob); if (Blob == NULL) { Status = EFI_OUT_OF_RESOURCES; goto FreePages; } CopyMem (Blob->File, Allocate->File, QEMU_LOADER_FNAME_SIZE); Blob->Size = FwCfgSize; Blob->Base = (VOID *)(UINTN)Address; Blob->HostsOnlyTableData = TRUE; Status = OrderedCollectionInsert (Tracker, NULL, Blob); if (Status == RETURN_ALREADY_STARTED) { DEBUG ((EFI_D_ERROR, "%a: duplicated file \"%a\"\n", __FUNCTION__, Allocate->File)); Status = EFI_PROTOCOL_ERROR; } if (EFI_ERROR (Status)) { goto FreeBlob; } QemuFwCfgSelectItem (FwCfgItem); QemuFwCfgReadBytes (FwCfgSize, Blob->Base); ZeroMem (Blob->Base + Blob->Size, EFI_PAGES_TO_SIZE (NumPages) - Blob->Size); DEBUG ((EFI_D_VERBOSE, "%a: File=\"%a\" Alignment=0x%x Zone=%d Size=0x%Lx " "Address=0x%Lx\n", __FUNCTION__, Allocate->File, Allocate->Alignment, Allocate->Zone, (UINT64)Blob->Size, (UINT64)(UINTN)Blob->Base)); return EFI_SUCCESS; FreeBlob: FreePool (Blob); FreePages: gBS->FreePages (Address, NumPages); return Status; }
/** Download, process, and install ACPI table data from the QEMU loader interface. @param[in] AcpiProtocol The ACPI table protocol used to install tables. @retval EFI_UNSUPPORTED Firmware configuration is unavailable, or QEMU loader command with unsupported parameters has been found. @retval EFI_NOT_FOUND The host doesn't export the required fw_cfg files. @retval EFI_OUT_OF_RESOURCES Memory allocation failed, or more than INSTALLED_TABLES_MAX tables found. @retval EFI_PROTOCOL_ERROR Found invalid fw_cfg contents. @return Status codes returned by AcpiProtocol->InstallAcpiTable(). **/ EFI_STATUS EFIAPI InstallQemuFwCfgTables ( IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol ) { EFI_STATUS Status; FIRMWARE_CONFIG_ITEM FwCfgItem; UINTN FwCfgSize; QEMU_LOADER_ENTRY *LoaderStart; CONST QEMU_LOADER_ENTRY *LoaderEntry, *LoaderEnd; ORIGINAL_ATTRIBUTES *OriginalPciAttributes; UINTN OriginalPciAttributesCount; ORDERED_COLLECTION *Tracker; UINTN *InstalledKey; INT32 Installed; ORDERED_COLLECTION_ENTRY *TrackerEntry, *TrackerEntry2; Status = QemuFwCfgFindFile ("etc/table-loader", &FwCfgItem, &FwCfgSize); if (EFI_ERROR (Status)) { return Status; } if (FwCfgSize % sizeof *LoaderEntry != 0) { DEBUG ((EFI_D_ERROR, "%a: \"etc/table-loader\" has invalid size 0x%Lx\n", __FUNCTION__, (UINT64)FwCfgSize)); return EFI_PROTOCOL_ERROR; } LoaderStart = AllocatePool (FwCfgSize); if (LoaderStart == NULL) { return EFI_OUT_OF_RESOURCES; } EnablePciDecoding (&OriginalPciAttributes, &OriginalPciAttributesCount); QemuFwCfgSelectItem (FwCfgItem); QemuFwCfgReadBytes (FwCfgSize, LoaderStart); RestorePciDecoding (OriginalPciAttributes, OriginalPciAttributesCount); LoaderEnd = LoaderStart + FwCfgSize / sizeof *LoaderEntry; Tracker = OrderedCollectionInit (BlobCompare, BlobKeyCompare); if (Tracker == NULL) { Status = EFI_OUT_OF_RESOURCES; goto FreeLoader; } // // first pass: process the commands // for (LoaderEntry = LoaderStart; LoaderEntry < LoaderEnd; ++LoaderEntry) { switch (LoaderEntry->Type) { case QemuLoaderCmdAllocate: Status = ProcessCmdAllocate (&LoaderEntry->Command.Allocate, Tracker); break; case QemuLoaderCmdAddPointer: Status = ProcessCmdAddPointer (&LoaderEntry->Command.AddPointer, Tracker); break; case QemuLoaderCmdAddChecksum: Status = ProcessCmdAddChecksum (&LoaderEntry->Command.AddChecksum, Tracker); break; default: DEBUG ((EFI_D_VERBOSE, "%a: unknown loader command: 0x%x\n", __FUNCTION__, LoaderEntry->Type)); break; } if (EFI_ERROR (Status)) { goto FreeTracker; } } InstalledKey = AllocatePool (INSTALLED_TABLES_MAX * sizeof *InstalledKey); if (InstalledKey == NULL) { Status = EFI_OUT_OF_RESOURCES; goto FreeTracker; } // // second pass: identify and install ACPI tables // Installed = 0; for (LoaderEntry = LoaderStart; LoaderEntry < LoaderEnd; ++LoaderEntry) { if (LoaderEntry->Type == QemuLoaderCmdAddPointer) { Status = Process2ndPassCmdAddPointer (&LoaderEntry->Command.AddPointer, Tracker, AcpiProtocol, InstalledKey, &Installed); if (EFI_ERROR (Status)) { break; } } } if (EFI_ERROR (Status)) { // // roll back partial installation // while (Installed > 0) { --Installed; AcpiProtocol->UninstallAcpiTable (AcpiProtocol, InstalledKey[Installed]); } } else { DEBUG ((EFI_D_INFO, "%a: installed %d tables\n", __FUNCTION__, Installed)); } FreePool (InstalledKey); FreeTracker: // // Tear down the tracker infrastructure. Each fw_cfg blob will be left in // place only if we're exiting with success and the blob hosts data that is // not directly part of some ACPI table. // for (TrackerEntry = OrderedCollectionMin (Tracker); TrackerEntry != NULL; TrackerEntry = TrackerEntry2) { VOID *UserStruct; BLOB *Blob; TrackerEntry2 = OrderedCollectionNext (TrackerEntry); OrderedCollectionDelete (Tracker, TrackerEntry, &UserStruct); Blob = UserStruct; if (EFI_ERROR (Status) || Blob->HostsOnlyTableData) { DEBUG ((EFI_D_VERBOSE, "%a: freeing \"%a\"\n", __FUNCTION__, Blob->File)); gBS->FreePages ((UINTN)Blob->Base, EFI_SIZE_TO_PAGES (Blob->Size)); } FreePool (Blob); } OrderedCollectionUninit (Tracker); FreeLoader: FreePool (LoaderStart); return Status; }
STATIC EFI_STATUS EFIAPI EmmcIdentificationMode ( IN MMC_HOST_INSTANCE *MmcHostInstance, IN OCR_RESPONSE Response ) { EFI_MMC_HOST_PROTOCOL *Host; EFI_BLOCK_IO_MEDIA *Media; EFI_STATUS Status; EMMC_DEVICE_STATE State; UINT32 RCA; Host = MmcHostInstance->MmcHost; Media = MmcHostInstance->BlockIo.Media; // Fetch card identity register Status = Host->SendCommand (Host, MMC_CMD2, 0); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to send CMD2, Status=%r.\n", Status)); return Status; } Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CIDData)); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): CID retrieval error, Status=%r.\n", Status)); return Status; } // Assign a relative address value to the card MmcHostInstance->CardInfo.RCA = ++mEmmcRcaCount; // TODO: might need a more sophisticated way of doing this RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET; Status = Host->SendCommand (Host, MMC_CMD3, RCA); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): RCA set error, Status=%r.\n", Status)); return Status; } // Fetch card specific data Status = Host->SendCommand (Host, MMC_CMD9, RCA); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to send CMD9, Status=%r.\n", Status)); return Status; } Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CSDData)); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): CSD retrieval error, Status=%r.\n", Status)); return Status; } // Select the card Status = Host->SendCommand (Host, MMC_CMD7, RCA); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Card selection error, Status=%r.\n", Status)); } if (MMC_HOST_HAS_SETIOS(Host)) { // Set 1-bit bus width Status = Host->SetIos (Host, 0, 1, EMMCBACKWARD); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set 1-bit bus width error, Status=%r.\n", Status)); return Status; } // Set 1-bit bus width for EXTCSD Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, EMMC_BUS_WIDTH_1BIT); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set extcsd bus width error, Status=%r.\n", Status)); return Status; } } // Fetch ECSD MmcHostInstance->CardInfo.ECSDData = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (ECSD))); if (MmcHostInstance->CardInfo.ECSDData == NULL) { return EFI_OUT_OF_RESOURCES; } Status = Host->SendCommand (Host, MMC_CMD8, 0); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD fetch error, Status=%r.\n", Status)); } Status = Host->ReadBlockData (Host, 0, 512, (UINT32 *)MmcHostInstance->CardInfo.ECSDData); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD read error, Status=%r.\n", Status)); goto FreePageExit; } // Make sure device exiting data mode do { Status = EmmcGetDeviceState (MmcHostInstance, &State); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to get device state, Status=%r.\n", Status)); goto FreePageExit; } } while (State == EMMC_DATA_STATE); // Set up media Media->BlockSize = EMMC_CARD_SIZE; // 512-byte support is mandatory for eMMC cards Media->MediaId = MmcHostInstance->CardInfo.CIDData.PSN; Media->ReadOnly = MmcHostInstance->CardInfo.CSDData.PERM_WRITE_PROTECT; Media->LogicalBlocksPerPhysicalBlock = 1; Media->IoAlign = 4; // Compute last block using bits [215:212] of the ECSD Media->LastBlock = MmcHostInstance->CardInfo.ECSDData->SECTOR_COUNT - 1; // eMMC isn't supposed to report this for // Cards <2GB in size, but the model does. // Setup card type MmcHostInstance->CardInfo.CardType = EMMC_CARD; return EFI_SUCCESS; FreePageExit: FreePages (MmcHostInstance->CardInfo.ECSDData, EFI_SIZE_TO_PAGES (sizeof (ECSD))); return Status; }
/** Return the Virtual Memory Map of your platform This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU on your platform. @param[out] VirtualMemoryMap Array of ARM_MEMORY_REGION_DESCRIPTOR describing a Physical-to- Virtual Memory mapping. This array must be ended by a zero-filled entry **/ VOID ArmPlatformGetVirtualMemoryMap ( IN ARM_MEMORY_REGION_DESCRIPTOR** VirtualMemoryMap ) { ARM_MEMORY_REGION_ATTRIBUTES CacheAttributes; UINTN Index = 0; ARM_MEMORY_REGION_DESCRIPTOR *VirtualMemoryTable; ASSERT(VirtualMemoryMap != NULL); VirtualMemoryTable = (ARM_MEMORY_REGION_DESCRIPTOR*)AllocatePages(EFI_SIZE_TO_PAGES (sizeof(ARM_MEMORY_REGION_DESCRIPTOR) * MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS)); if (VirtualMemoryTable == NULL) { return; } if (FeaturePcdGet(PcdCacheEnable) == TRUE) { CacheAttributes = DDR_ATTRIBUTES_CACHED; } else { CacheAttributes = DDR_ATTRIBUTES_UNCACHED; } if (FeaturePcdGet(PcdNorFlashRemapping) == FALSE) { // ReMap (Either NOR Flash or DRAM) VirtualMemoryTable[Index].PhysicalBase = ARM_VE_REMAP_BASE; VirtualMemoryTable[Index].VirtualBase = ARM_VE_REMAP_BASE; VirtualMemoryTable[Index].Length = ARM_VE_REMAP_SZ; VirtualMemoryTable[Index].Attributes = CacheAttributes; } // DDR VirtualMemoryTable[++Index].PhysicalBase = ARM_VE_DRAM_BASE; VirtualMemoryTable[Index].VirtualBase = ARM_VE_DRAM_BASE; VirtualMemoryTable[Index].Length = ARM_VE_DRAM_SZ; VirtualMemoryTable[Index].Attributes = CacheAttributes; // SMC CS7 VirtualMemoryTable[++Index].PhysicalBase = ARM_VE_SMB_MB_ON_CHIP_PERIPH_BASE; VirtualMemoryTable[Index].VirtualBase = ARM_VE_SMB_MB_ON_CHIP_PERIPH_BASE; VirtualMemoryTable[Index].Length = ARM_VE_SMB_MB_ON_CHIP_PERIPH_SZ; VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE; // SMB CS0-CS1 - NOR Flash 1 & 2 VirtualMemoryTable[++Index].PhysicalBase = ARM_VE_SMB_NOR0_BASE; VirtualMemoryTable[Index].VirtualBase = ARM_VE_SMB_NOR0_BASE; VirtualMemoryTable[Index].Length = ARM_VE_SMB_NOR0_SZ + ARM_VE_SMB_NOR1_SZ; VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE; // SMB CS2 - SRAM VirtualMemoryTable[++Index].PhysicalBase = ARM_VE_SMB_SRAM_BASE; VirtualMemoryTable[Index].VirtualBase = ARM_VE_SMB_SRAM_BASE; VirtualMemoryTable[Index].Length = ARM_VE_SMB_SRAM_SZ; VirtualMemoryTable[Index].Attributes = CacheAttributes; // SMB CS3-CS6 - Motherboard Peripherals VirtualMemoryTable[++Index].PhysicalBase = ARM_VE_SMB_PERIPH_BASE; VirtualMemoryTable[Index].VirtualBase = ARM_VE_SMB_PERIPH_BASE; VirtualMemoryTable[Index].Length = ARM_VE_SMB_PERIPH_SZ; VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE; // If a Logic Tile is connected to The ARM Versatile Express Motherboard if (MmioRead32(ARM_VE_SYS_PROCID1_REG) != 0) { VirtualMemoryTable[++Index].PhysicalBase = ARM_VE_EXT_AXI_BASE; VirtualMemoryTable[Index].VirtualBase = ARM_VE_EXT_AXI_BASE; VirtualMemoryTable[Index].Length = ARM_VE_EXT_AXI_SZ; VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE; ASSERT((Index + 1) == (MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS + 1)); } else { ASSERT((Index + 1) == MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS); } // End of Table VirtualMemoryTable[++Index].PhysicalBase = 0; VirtualMemoryTable[Index].VirtualBase = 0; VirtualMemoryTable[Index].Length = 0; VirtualMemoryTable[Index].Attributes = (ARM_MEMORY_REGION_ATTRIBUTES)0; *VirtualMemoryMap = VirtualMemoryTable; }
PhysicalBase += TT_DESCRIPTOR_SECTION_SIZE; } } RETURN_STATUS EFIAPI ArmConfigureMmu ( IN ARM_MEMORY_REGION_DESCRIPTOR *MemoryTable, OUT VOID **TranslationTableBase OPTIONAL, OUT UINTN *TranslationTableSize OPTIONAL ) { VOID *TranslationTable; // Allocate pages for translation table. TranslationTable = AllocatePages (EFI_SIZE_TO_PAGES (TRANSLATION_TABLE_SIZE + TRANSLATION_TABLE_ALIGNMENT)); if (TranslationTable == NULL) { return RETURN_OUT_OF_RESOURCES; } TranslationTable = (VOID *)(((UINTN)TranslationTable + TRANSLATION_TABLE_ALIGNMENT_MASK) & ~TRANSLATION_TABLE_ALIGNMENT_MASK); if (TranslationTableBase != NULL) { *TranslationTableBase = TranslationTable; } if (TranslationTableBase != NULL) { *TranslationTableSize = TRANSLATION_TABLE_SIZE; } ZeroMem(TranslationTable, TRANSLATION_TABLE_SIZE);
EFI_STATUS BootDeviceGetType ( IN EFI_DEVICE_PATH* DevicePath, OUT ARM_BDS_LOADER_TYPE *BootType, OUT UINT32 *Attributes ) { EFI_STATUS Status; BOOLEAN IsEfiApp; BOOLEAN IsBootLoader; BOOLEAN HasFDTSupport; CHAR16* FileName; EFI_DEVICE_PATH* PrevDevicePathNode; EFI_DEVICE_PATH* DevicePathNode; EFI_PHYSICAL_ADDRESS Image; UINTN FileSize; EFI_IMAGE_DOS_HEADER* DosHeader; UINTN PeCoffHeaderOffset; EFI_IMAGE_NT_HEADERS32* NtHeader; // // Check if the last node of the device path is a FilePath node // PrevDevicePathNode = NULL; DevicePathNode = DevicePath; while ((DevicePathNode != NULL) && !IsDevicePathEnd (DevicePathNode)) { PrevDevicePathNode = DevicePathNode; DevicePathNode = NextDevicePathNode (DevicePathNode); } if ((PrevDevicePathNode != NULL) && (PrevDevicePathNode->Type == MEDIA_DEVICE_PATH) && (PrevDevicePathNode->SubType == MEDIA_FILEPATH_DP)) { FileName = ((FILEPATH_DEVICE_PATH*)PrevDevicePathNode)->PathName; } else { FileName = NULL; } if (FileName == NULL) { Print(L"Is an EFI Application? "); Status = GetHIInputBoolean (&IsEfiApp); if (EFI_ERROR(Status)) { return EFI_ABORTED; } } else if (HasFilePathEfiExtension(FileName)) { IsEfiApp = TRUE; } else { // Check if the file exist Status = BdsLoadImage (DevicePath, AllocateAnyPages, &Image, &FileSize); if (!EFI_ERROR (Status)) { DosHeader = (EFI_IMAGE_DOS_HEADER *)(UINTN) Image; if (DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE) { // // DOS image header is present, // so read the PE header after the DOS image header. // PeCoffHeaderOffset = DosHeader->e_lfanew; } else { PeCoffHeaderOffset = 0; } // // Check PE/COFF image. // NtHeader = (EFI_IMAGE_NT_HEADERS32 *)(UINTN) (Image + PeCoffHeaderOffset); if (NtHeader->Signature != EFI_IMAGE_NT_SIGNATURE) { IsEfiApp = FALSE; } else { IsEfiApp = TRUE; } // Free memory gBS->FreePages (Image, EFI_SIZE_TO_PAGES(FileSize)); } else { // If we did not manage to open it then ask for the type Print(L"Is an EFI Application? "); Status = GetHIInputBoolean (&IsEfiApp); if (EFI_ERROR(Status)) { return EFI_ABORTED; } } } if (IsEfiApp) { Print(L"Is your application an OS loader? "); Status = GetHIInputBoolean (&IsBootLoader); if (EFI_ERROR(Status)) { return EFI_ABORTED; } if (!IsBootLoader) { *Attributes |= LOAD_OPTION_CATEGORY_APP; } *BootType = BDS_LOADER_EFI_APPLICATION; } else { Print(L"Has FDT support? "); Status = GetHIInputBoolean (&HasFDTSupport); if (EFI_ERROR(Status)) { return EFI_ABORTED; } if (HasFDTSupport) { *BootType = BDS_LOADER_KERNEL_LINUX_FDT; } else { *BootType = BDS_LOADER_KERNEL_LINUX_ATAG; } } return EFI_SUCCESS; }
/** * efree - Return memory allocated with emalloc * @memory: the address of the emalloc() allocation * @size: the size of the allocation */ void efree(EFI_PHYSICAL_ADDRESS memory, UINTN size) { UINTN nr_pages = EFI_SIZE_TO_PAGES(size); free_pages(memory, nr_pages); }
void exit(EFI_STATUS exit_code) { BS->FreePages(heap, EFI_SIZE_TO_PAGES(heapsize)); BS->Exit(IH, exit_code, 0, NULL); }
/** Allocates one or more 4KB pages of a certain memory type at a specified alignment. Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is returned. If there is not enough memory at the specified alignment remaining to satisfy the request, then NULL is returned. If Alignment is not a power of two and Alignment is not zero, then ASSERT(). If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). @param MemoryType The type of memory to allocate. @param Pages The number of 4 KB pages to allocate. @param Alignment The requested alignment of the allocation. Must be a power of two. If Alignment is zero, then byte alignment is used. @return A pointer to the allocated buffer or NULL if allocation fails. **/ VOID * InternalAllocateAlignedPages ( IN EFI_MEMORY_TYPE MemoryType, IN UINTN Pages, IN UINTN Alignment ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS Memory; UINTN AlignedMemory; UINTN AlignmentMask; UINTN UnalignedPages; UINTN RealPages; // // Alignment must be a power of two or zero. // ASSERT ((Alignment & (Alignment - 1)) == 0); if (Pages == 0) { return NULL; } if (Alignment > EFI_PAGE_SIZE) { // // Calculate the total number of pages since alignment is larger than page size. // AlignmentMask = Alignment - 1; RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment); // // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow. // ASSERT (RealPages > Pages); Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory); if (EFI_ERROR (Status)) { return NULL; } AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask; UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory); if (UnalignedPages > 0) { // // Free first unaligned page(s). // Status = gBS->FreePages (Memory, UnalignedPages); ASSERT_EFI_ERROR (Status); } Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages); UnalignedPages = RealPages - Pages - UnalignedPages; if (UnalignedPages > 0) { // // Free last unaligned page(s). // Status = gBS->FreePages (Memory, UnalignedPages); ASSERT_EFI_ERROR (Status); } } else { // // Do not over-allocate pages in this case. // Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory); if (EFI_ERROR (Status)) { return NULL; } AlignedMemory = (UINTN) Memory; } return (VOID *) AlignedMemory; }
/** Allocate some memory from the host controller's memory pool which can be used to communicate with host controller. @param Pool The host controller's memory pool. @param Size Size of the memory to allocate. @return The allocated memory or NULL. **/ VOID * UsbHcAllocateMem ( IN USBHC_MEM_POOL *Pool, IN UINTN Size ) { USBHC_MEM_BLOCK *Head; USBHC_MEM_BLOCK *Block; USBHC_MEM_BLOCK *NewBlock; VOID *Mem; UINTN AllocSize; UINTN Pages; Mem = NULL; AllocSize = USBHC_MEM_ROUND (Size); Head = Pool->Head; ASSERT (Head != NULL); // // First check whether current memory blocks can satisfy the allocation. // for (Block = Head; Block != NULL; Block = Block->Next) { Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT); if (Mem != NULL) { ZeroMem (Mem, Size); break; } } if (Mem != NULL) { return Mem; } // // Create a new memory block if there is not enough memory // in the pool. If the allocation size is larger than the // default page number, just allocate a large enough memory // block. Otherwise allocate default pages. // if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) { Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1; } else { Pages = USBHC_MEM_DEFAULT_PAGES; } NewBlock = UsbHcAllocMemBlock (Pool, Pages); if (NewBlock == NULL) { DEBUG ((EFI_D_ERROR, "UsbHcAllocateMem: failed to allocate block\n")); return NULL; } // // Add the new memory block to the pool, then allocate memory from it // UsbHcInsertMemBlockToPool (Head, NewBlock); Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT); if (Mem != NULL) { ZeroMem (Mem, Size); } return Mem; }
/** Allocates one or more 4KB pages of a certain memory type at a specified alignment. Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is returned. If there is not enough memory at the specified alignment remaining to satisfy the request, then NULL is returned. If Alignment is not a power of two and Alignment is not zero, then ASSERT(). If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). @param MemoryType The type of memory to allocate. @param Pages The number of 4 KB pages to allocate. @param Alignment The requested alignment of the allocation. Must be a power of two. If Alignment is zero, then byte alignment is used. @return A pointer to the allocated buffer or NULL if allocation fails. **/ VOID * InternalAllocateAlignedPages ( IN EFI_MEMORY_TYPE MemoryType, IN UINTN Pages, IN UINTN Alignment ) { EFI_PHYSICAL_ADDRESS Memory; EFI_PHYSICAL_ADDRESS AlignedMemory; EFI_PEI_HOB_POINTERS Hob; BOOLEAN SkipBeforeMemHob; BOOLEAN SkipAfterMemHob; EFI_PHYSICAL_ADDRESS HobBaseAddress; UINT64 HobLength; EFI_MEMORY_TYPE HobMemoryType; UINTN TotalPages; // // Alignment must be a power of two or zero. // ASSERT ((Alignment & (Alignment - 1)) == 0); if (Pages == 0) { return NULL; } // // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow. // ASSERT (Pages <= (MAX_ADDRESS - EFI_SIZE_TO_PAGES (Alignment))); // // We would rather waste some memory to save PEI code size. // meaning in addition to the requested size for the aligned mem, // we simply reserve an overhead memory equal to Alignmemt(page-aligned), no matter what. // The overhead mem size could be reduced later with more involved malloc mechanisms // (e.g., somthing that can detect the alignment boundary before allocating memory or // can request that memory be allocated at a certain address that is aleady aligned). // TotalPages = Pages + (Alignment <= EFI_PAGE_SIZE ? 0 : EFI_SIZE_TO_PAGES(Alignment)); Memory = (EFI_PHYSICAL_ADDRESS) (UINTN) InternalAllocatePages (MemoryType, TotalPages); if (Memory == 0) { DEBUG((DEBUG_INFO, "Out of memory resource! \n")); return NULL; } DEBUG ((DEBUG_INFO, "Allocated Memory unaligned: Address = 0x%LX, Pages = 0x%X, Type = %d \n", Memory, TotalPages, (UINTN) MemoryType)); // // Alignment calculation // AlignedMemory = Memory; if (Alignment > EFI_PAGE_SIZE) { AlignedMemory = ALIGN_VALUE (Memory, Alignment); } DEBUG ((DEBUG_INFO, "After aligning to 0x%X bytes: Address = 0x%LX, Pages = 0x%X \n", Alignment, AlignedMemory, Pages)); // // In general three HOBs cover the total allocated space. // The aligned portion is covered by the aligned mem HOB and // the unaligned(to be freed) portions before and after the aligned portion are covered by newly created HOBs. // // Before mem HOB covers the region between "Memory" and "AlignedMemory" // Aligned mem HOB covers the region between "AlignedMemory" and "AlignedMemory + EFI_PAGES_TO_SIZE(Pages)" // After mem HOB covers the region between "AlignedMemory + EFI_PAGES_TO_SIZE(Pages)" and "Memory + EFI_PAGES_TO_SIZE(TotalPages)" // // The before or after mem HOBs need to be skipped under special cases where the aligned portion // touches either the top or bottom of the original allocated space. // SkipBeforeMemHob = FALSE; SkipAfterMemHob = FALSE; if (Memory == AlignedMemory) { SkipBeforeMemHob = TRUE; } if ((Memory + EFI_PAGES_TO_SIZE(TotalPages)) == (AlignedMemory + EFI_PAGES_TO_SIZE(Pages))) { // // This condition is never met in the current implementation. // There is always some after-mem since the overhead mem(used in TotalPages) // is no less than Alignment. // SkipAfterMemHob = TRUE; } // // Search for the mem HOB referring to the original(unaligned) allocation // and update the size and type if needed. // Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION); while (Hob.Raw != NULL) { if (Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress == Memory) { break; } Hob.Raw = GET_NEXT_HOB (Hob); Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw); } ASSERT (Hob.Raw != NULL); if (SkipBeforeMemHob) { // // Use this HOB as aligned mem HOB as there is no portion before it. // HobLength = EFI_PAGES_TO_SIZE(Pages); Hob.MemoryAllocation->AllocDescriptor.MemoryLength = HobLength; } else { // // Use this HOB as before mem HOB and create a new HOB for the aligned portion // HobLength = (AlignedMemory - Memory); Hob.MemoryAllocation->AllocDescriptor.MemoryLength = HobLength; Hob.MemoryAllocation->AllocDescriptor.MemoryType = EfiConventionalMemory; } HobBaseAddress = Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress; HobMemoryType = Hob.MemoryAllocation->AllocDescriptor.MemoryType; // // Build the aligned mem HOB if needed // if (!SkipBeforeMemHob) { DEBUG((DEBUG_INFO, "Updated before-mem HOB with BaseAddress = %LX, Length = %LX, MemoryType = %d \n", HobBaseAddress, HobLength, (UINTN) HobMemoryType)); HobBaseAddress = AlignedMemory; HobLength = EFI_PAGES_TO_SIZE(Pages); HobMemoryType = MemoryType; BuildMemoryAllocationHob ( HobBaseAddress, HobLength, HobMemoryType ); DEBUG((DEBUG_INFO, "Created aligned-mem HOB with BaseAddress = %LX, Length = %LX, MemoryType = %d \n", HobBaseAddress, HobLength, (UINTN) HobMemoryType)); } else { if (HobBaseAddress != 0) { DEBUG((DEBUG_INFO, "Updated aligned-mem HOB with BaseAddress = %LX, Length = %LX, MemoryType = %d \n", HobBaseAddress, HobLength, (UINTN) HobMemoryType)); } } // // Build the after mem HOB if needed // if (!SkipAfterMemHob) { HobBaseAddress = AlignedMemory + EFI_PAGES_TO_SIZE(Pages); HobLength = (Memory + EFI_PAGES_TO_SIZE(TotalPages)) - (AlignedMemory + EFI_PAGES_TO_SIZE(Pages)); HobMemoryType = EfiConventionalMemory; BuildMemoryAllocationHob ( HobBaseAddress, HobLength, HobMemoryType ); DEBUG((DEBUG_INFO, "Created after-mem HOB with BaseAddress = %LX, Length = %LX, MemoryType = %d \n", HobBaseAddress, HobLength, (UINTN) HobMemoryType)); } return (VOID *) (UINTN) AlignedMemory; }
/** Create Frame List Structure. @param Uhc UHCI device. @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources. @retval EFI_UNSUPPORTED Map memory fail. @retval EFI_SUCCESS Success. **/ EFI_STATUS UhciInitFrameList ( IN USB_HC_DEV *Uhc ) { EFI_PHYSICAL_ADDRESS MappedAddr; EFI_STATUS Status; VOID *Buffer; VOID *Mapping; UINTN Pages; UINTN Bytes; UINTN Index; EFI_PHYSICAL_ADDRESS PhyAddr; // // The Frame List is a common buffer that will be // accessed by both the cpu and the usb bus master // at the same time. The Frame List ocupies 4K bytes, // and must be aligned on 4-Kbyte boundaries. // Bytes = 4096; Pages = EFI_SIZE_TO_PAGES (Bytes); Status = Uhc->PciIo->AllocateBuffer ( Uhc->PciIo, AllocateAnyPages, EfiBootServicesData, Pages, &Buffer, 0 ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } Status = Uhc->PciIo->Map ( Uhc->PciIo, EfiPciIoOperationBusMasterCommonBuffer, Buffer, &Bytes, &MappedAddr, &Mapping ); if (EFI_ERROR (Status) || (Bytes != 4096)) { Status = EFI_UNSUPPORTED; goto ON_ERROR; } Uhc->FrameBase = (UINT32 *) (UINTN) Buffer; Uhc->FrameMapping = Mapping; // // Tell the Host Controller where the Frame List lies, // by set the Frame List Base Address Register. // UhciSetFrameListBaseAddr (Uhc->PciIo, (VOID *) (UINTN) MappedAddr); // // Allocate the QH used by sync interrupt/control/bulk transfer. // FS ctrl/bulk queue head is set to loopback so additional BW // can be reclaimed. Notice, LS don't support bulk transfer and // also doesn't support BW reclamation. // Uhc->SyncIntQh = UhciCreateQh (Uhc, 1); Uhc->CtrlQh = UhciCreateQh (Uhc, 1); Uhc->BulkQh = UhciCreateQh (Uhc, 1); if ((Uhc->SyncIntQh == NULL) || (Uhc->CtrlQh == NULL) || (Uhc->BulkQh == NULL)) { Uhc->PciIo->Unmap (Uhc->PciIo, Mapping); Status = EFI_OUT_OF_RESOURCES; goto ON_ERROR; } // // +-------------+ // | | // Link the three together: SyncIntQh->CtrlQh->BulkQh <---------+ // Each frame entry is linked to this sequence of QH. These QH // will remain on the schedul, never got removed // PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Uhc->CtrlQh, sizeof (UHCI_QH_HW)); Uhc->SyncIntQh->QhHw.HorizonLink = QH_HLINK (PhyAddr, FALSE); Uhc->SyncIntQh->NextQh = Uhc->CtrlQh; PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Uhc->BulkQh, sizeof (UHCI_QH_HW)); Uhc->CtrlQh->QhHw.HorizonLink = QH_HLINK (PhyAddr, FALSE); Uhc->CtrlQh->NextQh = Uhc->BulkQh; // // Some old platform such as Intel's Tiger 4 has a difficult time // in supporting the full speed bandwidth reclamation in the previous // mentioned form. Most new platforms don't suffer it. // Uhc->BulkQh->QhHw.HorizonLink = QH_HLINK (PhyAddr, FALSE); Uhc->BulkQh->NextQh = NULL; Uhc->FrameBaseHostAddr = AllocateZeroPool (4096); if (Uhc->FrameBaseHostAddr == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ON_ERROR; } PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Uhc->SyncIntQh, sizeof (UHCI_QH_HW)); for (Index = 0; Index < UHCI_FRAME_NUM; Index++) { Uhc->FrameBase[Index] = QH_HLINK (PhyAddr, FALSE); Uhc->FrameBaseHostAddr[Index] = (UINT32)(UINTN)Uhc->SyncIntQh; } return EFI_SUCCESS; ON_ERROR: if (Uhc->SyncIntQh != NULL) { UsbHcFreeMem (Uhc->MemPool, Uhc->SyncIntQh, sizeof (UHCI_QH_SW)); } if (Uhc->CtrlQh != NULL) { UsbHcFreeMem (Uhc->MemPool, Uhc->CtrlQh, sizeof (UHCI_QH_SW)); } if (Uhc->BulkQh != NULL) { UsbHcFreeMem (Uhc->MemPool, Uhc->BulkQh, sizeof (UHCI_QH_SW)); } Uhc->PciIo->FreeBuffer (Uhc->PciIo, Pages, Buffer); return Status; }
/** Allocates pages at a specified alignment that are suitable for an EfiPciIoOperationBusMasterCommonBuffer mapping. If Alignment is not a power of two and Alignment is not zero, then ASSERT(). @param PciIo The PciIo that can be used to access the host controller. @param Pages The number of pages to allocate. @param Alignment The requested alignment of the allocation. Must be a power of two. @param HostAddress The system memory address to map to the PCI controller. @param DeviceAddress The resulting map address for the bus master PCI controller to use to access the hosts HostAddress. @param Mapping A resulting value to pass to Unmap(). @retval EFI_SUCCESS Success to allocate aligned pages. @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid. @retval EFI_OUT_OF_RESOURCES Do not have enough resources to allocate memory. **/ EFI_STATUS UsbHcAllocateAlignedPages ( IN EFI_PCI_IO_PROTOCOL *PciIo, IN UINTN Pages, IN UINTN Alignment, OUT VOID **HostAddress, OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, OUT VOID **Mapping ) { EFI_STATUS Status; VOID *Memory; UINTN AlignedMemory; UINTN AlignmentMask; UINTN UnalignedPages; UINTN RealPages; UINTN Bytes; // // Alignment must be a power of two or zero. // ASSERT ((Alignment & (Alignment - 1)) == 0); if ((Alignment & (Alignment - 1)) != 0) { return EFI_INVALID_PARAMETER; } if (Pages == 0) { return EFI_INVALID_PARAMETER; } if (Alignment > EFI_PAGE_SIZE) { // // Calculate the total number of pages since alignment is larger than page size. // AlignmentMask = Alignment - 1; RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment); // // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow. // ASSERT (RealPages > Pages); Status = PciIo->AllocateBuffer ( PciIo, AllocateAnyPages, EfiBootServicesData, Pages, &Memory, 0 ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask; UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory); if (UnalignedPages > 0) { // // Free first unaligned page(s). // Status = PciIo->FreeBuffer (PciIo, UnalignedPages, Memory); ASSERT_EFI_ERROR (Status); } Memory = (VOID *)(UINTN)(AlignedMemory + EFI_PAGES_TO_SIZE (Pages)); UnalignedPages = RealPages - Pages - UnalignedPages; if (UnalignedPages > 0) { // // Free last unaligned page(s). // Status = PciIo->FreeBuffer (PciIo, UnalignedPages, Memory); ASSERT_EFI_ERROR (Status); } } else { // // Do not over-allocate pages in this case. // Status = PciIo->AllocateBuffer ( PciIo, AllocateAnyPages, EfiBootServicesData, Pages, &Memory, 0 ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } AlignedMemory = (UINTN) Memory; } Bytes = EFI_PAGES_TO_SIZE (Pages); Status = PciIo->Map ( PciIo, EfiPciIoOperationBusMasterCommonBuffer, (VOID *) AlignedMemory, &Bytes, DeviceAddress, Mapping ); if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) { Status = PciIo->FreeBuffer (PciIo, Pages, (VOID *) AlignedMemory); return EFI_OUT_OF_RESOURCES; } *HostAddress = (VOID *) AlignedMemory; return EFI_SUCCESS; }
/** Initialize the Event Log and log events passed from the PEI phase. @retval EFI_SUCCESS Operation completed successfully. @retval EFI_OUT_OF_RESOURCES Out of memory. **/ EFI_STATUS EFIAPI SetupEventLog ( VOID ) { EFI_STATUS Status; TCG_PCR_EVENT *TcgEvent; EFI_PEI_HOB_POINTERS GuidHob; EFI_PHYSICAL_ADDRESS Lasa; if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) { Lasa = mTcgClientAcpiTemplate.Lasa; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), &Lasa ); if (EFI_ERROR (Status)) { return Status; } mTcgClientAcpiTemplate.Lasa = Lasa; // // To initialize them as 0xFF is recommended // because the OS can know the last entry for that. // SetMem ((VOID *)(UINTN)mTcgClientAcpiTemplate.Lasa, PcdGet32 (PcdTcgLogAreaMinLen), 0xFF); mTcgClientAcpiTemplate.Laml = PcdGet32 (PcdTcgLogAreaMinLen); } else { Lasa = mTcgServerAcpiTemplate.Lasa; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), &Lasa ); if (EFI_ERROR (Status)) { return Status; } mTcgServerAcpiTemplate.Lasa = Lasa; // // To initialize them as 0xFF is recommended // because the OS can know the last entry for that. // SetMem ((VOID *)(UINTN)mTcgServerAcpiTemplate.Lasa, PcdGet32 (PcdTcgLogAreaMinLen), 0xFF); mTcgServerAcpiTemplate.Laml = PcdGet32 (PcdTcgLogAreaMinLen); } GuidHob.Raw = GetHobList (); while (!EFI_ERROR (Status) && (GuidHob.Raw = GetNextGuidHob (&gTcgEventEntryHobGuid, GuidHob.Raw)) != NULL) { TcgEvent = GET_GUID_HOB_DATA (GuidHob.Guid); GuidHob.Raw = GET_NEXT_HOB (GuidHob); Status = TcgDxeLogEventI ( &mTcgDxeData, (TCG_PCR_EVENT_HDR*)TcgEvent, TcgEvent->Event ); } return Status; }
/** Debug Agent provided notify callback function on Memory Discovered PPI. @param[in] PeiServices Indirect reference to the PEI Services Table. @param[in] NotifyDescriptor Address of the notification descriptor data structure. @param[in] Ppi Address of the PPI that was installed. @retval EFI_SUCCESS If the function completed successfully. **/ EFI_STATUS EFIAPI DebugAgentCallbackMemoryDiscoveredPpi ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ) { EFI_STATUS Status; DEBUG_AGENT_MAILBOX *Mailbox; BOOLEAN InterruptStatus; EFI_PHYSICAL_ADDRESS Address; DEBUG_AGENT_MAILBOX *NewMailbox; UINT64 *MailboxLocationInHob; // // Save and disable original interrupt status // InterruptStatus = SaveAndDisableInterrupts (); // // Allocate ACPI NVS memory for new Mailbox and Debug Port Handle buffer // Status = PeiServicesAllocatePages ( EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)), &Address ); ASSERT_EFI_ERROR (Status); NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Address; // // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox // and Debug Port Handle buffer in the allocated pool that may be marked as free by DXE Core after DXE Core // reallocates the HOB. // Mailbox = GetMailboxPointer (); CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX)); CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize)); // // Update Mailbox Location pointer in GUIDed HOB and IDT entry with new one // MailboxLocationInHob = GetMailboxLocationFromHob (); ASSERT (MailboxLocationInHob != NULL); *MailboxLocationInHob = (UINT64)(UINTN)NewMailbox; SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob); // // Update Debug Port Handle in new Mailbox // UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1)); // // Set physical memory ready flag // SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1); if (IsHostAttached ()) { // // Trigger one software interrupt to inform HOST // TriggerSoftInterrupt (MEMORY_READY_SIGNATURE); } // // Restore interrupt state. // SetInterruptState (InterruptStatus); return EFI_SUCCESS; }
/** Installs the Device Recovery Module PPI, Initialize BlockIo Ppi installation notification @param FileHandle The file handle of the image. @param PeiServices General purpose services available to every PEIM. @retval EFI_SUCCESS The function completed successfully. @retval EFI_OUT_OF_RESOURCES There is not enough system memory. **/ EFI_STATUS EFIAPI CdExpressPeimEntry ( IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status; PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData; if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { return EFI_SUCCESS; } PrivateData = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*PrivateData))); if (PrivateData == NULL) { return EFI_OUT_OF_RESOURCES; } // // Initialize Private Data (to zero, as is required by subsequent operations) // ZeroMem (PrivateData, sizeof (*PrivateData)); PrivateData->Signature = PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE; PrivateData->BlockBuffer = AllocatePages (EFI_SIZE_TO_PAGES (PEI_CD_BLOCK_SIZE)); if (PrivateData->BlockBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } PrivateData->CapsuleCount = 0; Status = UpdateBlocksAndVolumes (PrivateData, TRUE); Status = UpdateBlocksAndVolumes (PrivateData, FALSE); // // Installs Ppi // PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules = GetNumberRecoveryCapsules; PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo = GetRecoveryCapsuleInfo; PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule = LoadRecoveryCapsule; PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); PrivateData->PpiDescriptor.Guid = &gEfiPeiDeviceRecoveryModulePpiGuid; PrivateData->PpiDescriptor.Ppi = &PrivateData->DeviceRecoveryPpi; Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } // // PrivateData is allocated now, set it to the module variable // mPrivateData = PrivateData; // // Installs Block Io Ppi notification function // PrivateData->NotifyDescriptor.Flags = ( EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK ); PrivateData->NotifyDescriptor.Guid = &gEfiPeiVirtualBlockIoPpiGuid; PrivateData->NotifyDescriptor.Notify = BlockIoNotifyEntry; PrivateData->NotifyDescriptor2.Flags = ( EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST ); PrivateData->NotifyDescriptor2.Guid = &gEfiPeiVirtualBlockIo2PpiGuid; PrivateData->NotifyDescriptor2.Notify = BlockIoNotifyEntry; return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor); }
/** Initialize debug agent. This function is used to set up debug environment for SEC and PEI phase. If InitFlag is DEBUG_AGENT_INIT_PREMEM_SEC, it will overirde IDT table entries and initialize debug port. It will enable interrupt to support break-in feature. It will set up debug agent Mailbox in cache-as-ramfrom. It will be called before physical memory is ready. If InitFlag is DEBUG_AGENT_INIT_POSTMEM_SEC, debug agent will build one GUIDed HOB to copy debug agent Mailbox. It will be called after physical memory is ready. This function is used to set up debug environment to support source level debugging. If certain Debug Agent Library instance has to save some private data in the stack, this function must work on the mode that doesn't return to the caller, then the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is responsible to invoke the passing-in function at the end of InitializeDebugAgent(). If the parameter Function is not NULL, Debug Agent Library instance will invoke it by passing in the Context to be its parameter. If Function() is NULL, Debug Agent Library instance will return after setup debug environment. @param[in] InitFlag Init flag is used to decide the initialize process. @param[in] Context Context needed according to InitFlag; it was optional. @param[in] Function Continue function called by debug agent library; it was optional. **/ VOID EFIAPI InitializeDebugAgent ( IN UINT32 InitFlag, IN VOID *Context, OPTIONAL IN DEBUG_AGENT_CONTINUE Function OPTIONAL ) { DEBUG_AGENT_MAILBOX *Mailbox; DEBUG_AGENT_MAILBOX *NewMailbox; DEBUG_AGENT_MAILBOX MailboxInStack; DEBUG_AGENT_PHASE2_CONTEXT Phase2Context; DEBUG_AGENT_CONTEXT_POSTMEM_SEC *DebugAgentContext; EFI_STATUS Status; IA32_DESCRIPTOR *Ia32Idtr; IA32_IDT_ENTRY *Ia32IdtEntry; UINT64 DebugPortHandle; UINT64 MailboxLocation; UINT64 *MailboxLocationPointer; EFI_PHYSICAL_ADDRESS Address; UINT32 DebugTimerFrequency; BOOLEAN CpuInterruptState; // // Disable interrupts and save current interrupt state // CpuInterruptState = SaveAndDisableInterrupts(); switch (InitFlag) { case DEBUG_AGENT_INIT_PREMEM_SEC: InitializeDebugIdt (); MailboxLocation = (UINT64)(UINTN)&MailboxInStack; Mailbox = &MailboxInStack; ZeroMem ((VOID *) Mailbox, sizeof (DEBUG_AGENT_MAILBOX)); // // Get and save debug port handle and set the length of memory block. // SetLocationSavedMailboxPointerInIdtEntry (&MailboxLocation); // // Force error message could be printed during the first shakehand between Target/HOST. // SetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL, DEBUG_AGENT_ERROR); // // Save init arch type when debug agent initialized // SetDebugFlag (DEBUG_AGENT_FLAG_INIT_ARCH, DEBUG_ARCH_SYMBOL); // // Initialize Debug Timer hardware and save its frequency // InitializeDebugTimer (&DebugTimerFrequency, TRUE); UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency); Phase2Context.InitFlag = InitFlag; Phase2Context.Context = Context; Phase2Context.Function = Function; DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2); // // If reaches here, it means Debug Port initialization failed. // DEBUG ((EFI_D_ERROR, "Debug Agent: Debug port initialization failed.\n")); break; case DEBUG_AGENT_INIT_POSTMEM_SEC: Mailbox = GetMailboxPointer (); // // Memory has been ready // SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1); if (IsHostAttached ()) { // // Trigger one software interrupt to inform HOST // TriggerSoftInterrupt (MEMORY_READY_SIGNATURE); } // // Install Vector Handoff Info PPI to persist vectors used by Debug Agent // Status = PeiServicesInstallPpi (&mVectorHandoffInfoPpiList[0]); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to install Vector Handoff Info PPI!\n")); CpuDeadLoop (); } // // Fix up Debug Port handle address and mailbox address // DebugAgentContext = (DEBUG_AGENT_CONTEXT_POSTMEM_SEC *) Context; if (DebugAgentContext != NULL) { DebugPortHandle = (UINT64)(UINT32)(Mailbox->DebugPortHandle + DebugAgentContext->StackMigrateOffset); UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle); Mailbox = (DEBUG_AGENT_MAILBOX *) ((UINTN) Mailbox + DebugAgentContext->StackMigrateOffset); MailboxLocation = (UINT64)(UINTN)Mailbox; // // Build mailbox location in HOB and fix-up its address // MailboxLocationPointer = BuildGuidDataHob ( &gEfiDebugAgentGuid, &MailboxLocation, sizeof (UINT64) ); MailboxLocationPointer = (UINT64 *) ((UINTN) MailboxLocationPointer + DebugAgentContext->HeapMigrateOffset); } else { // // DebugAgentContext is NULL. Then, Mailbox can directly be copied into memory. // Allocate ACPI NVS memory for new Mailbox and Debug Port Handle buffer // Status = PeiServicesAllocatePages ( EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)), &Address ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to allocate pages!\n")); CpuDeadLoop (); } NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Address; // // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox // and Debug Port Handle buffer in the allocated pool that may be marked as free by DXE Core after DXE Core // reallocates the HOB. // CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX)); CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize)); UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1)); MailboxLocation = (UINT64)(UINTN)NewMailbox; // // Build mailbox location in HOB // MailboxLocationPointer = BuildGuidDataHob ( &gEfiDebugAgentGuid, &MailboxLocation, sizeof (UINT64) ); } // // Update IDT entry to save the location saved mailbox pointer // SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer); break; case DEBUG_AGENT_INIT_PEI: if (Context == NULL) { DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n")); CpuDeadLoop (); } // // Check if Debug Agent has initialized before // if (IsDebugAgentInitialzed()) { DEBUG ((EFI_D_WARN, "Debug Agent: It has already initialized in SEC Core!\n")); break; } // // Install Vector Handoff Info PPI to persist vectors used by Debug Agent // Status = PeiServicesInstallPpi (&mVectorHandoffInfoPpiList[0]); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to install Vector Handoff Info PPI!\n")); CpuDeadLoop (); } // // Set up IDT entries // InitializeDebugIdt (); // // Build mailbox in HOB and setup Mailbox Set In Pei flag // Mailbox = AllocateZeroPool (sizeof (DEBUG_AGENT_MAILBOX)); if (Mailbox == NULL) { DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to allocate memory!\n")); CpuDeadLoop (); } else { MailboxLocation = (UINT64)(UINTN)Mailbox; MailboxLocationPointer = BuildGuidDataHob ( &gEfiDebugAgentGuid, &MailboxLocation, sizeof (UINT64) ); // // Initialize Debug Timer hardware and save its frequency // InitializeDebugTimer (&DebugTimerFrequency, TRUE); UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency); // // Update IDT entry to save the location pointer saved mailbox pointer // SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer); } // // Save init arch type when debug agent initialized // SetDebugFlag (DEBUG_AGENT_FLAG_INIT_ARCH, DEBUG_ARCH_SYMBOL); // // Register for a callback once memory has been initialized. // If memery has been ready, the callback funtion will be invoked immediately // Status = PeiServicesNotifyPpi (&mMemoryDiscoveredNotifyList[0]); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to register memory discovered callback function!\n")); CpuDeadLoop (); } // // Set HOB check flag if memory has not been ready yet // if (GetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY) == 0) { SetDebugFlag (DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB, 1); } Phase2Context.InitFlag = InitFlag; Phase2Context.Context = Context; Phase2Context.Function = Function; DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2); FindAndReportModuleImageInfo (4); break; case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64: if (Context == NULL) { DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n")); CpuDeadLoop (); } else { Ia32Idtr = (IA32_DESCRIPTOR *) Context; Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base); MailboxLocationPointer = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow + (UINT32) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16)); Mailbox = (DEBUG_AGENT_MAILBOX *) (UINTN)(*MailboxLocationPointer); // // Mailbox should valid and setup before executing thunk code // VerifyMailboxChecksum (Mailbox); DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((VOID *)(UINTN)Mailbox->DebugPortHandle, NULL); UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle); // // Set up IDT entries // InitializeDebugIdt (); // // Update IDT entry to save location pointer saved the mailbox pointer // SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer); FindAndReportModuleImageInfo (4); } break; default: // // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this // Debug Agent library instance. // DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n")); CpuDeadLoop (); break; } if (InitFlag == DEBUG_AGENT_INIT_POSTMEM_SEC) { // // Restore CPU Interrupt state and keep debug timer interrupt state as is // in DEBUG_AGENT_INIT_POSTMEM_SEC case // SetInterruptState (CpuInterruptState); } else { // // Enable Debug Timer interrupt // SaveAndSetDebugTimerInterrupt (TRUE); // // Enable CPU interrupts so debug timer interrupts can be delivered // EnableInterrupts (); } // // If Function is not NULL, invoke it always whatever debug agent was initialized sucesssfully or not. // if (Function != NULL) { Function (Context); } // // Set return status for DEBUG_AGENT_INIT_PEI // if (InitFlag == DEBUG_AGENT_INIT_PEI && Context != NULL) { *(EFI_STATUS *)Context = EFI_SUCCESS; } }