/** Frees previous allocated pages. @param Memory Base address of memory being freed. @param NumberOfPages The number of pages to free. @retval EFI_NOT_FOUND Could not find the entry that covers the range. @retval EFI_INVALID_PARAMETER Address not aligned. @return EFI_SUCCESS Pages successfully freed. **/ EFI_STATUS EFIAPI SmmFreePages ( IN EFI_PHYSICAL_ADDRESS Memory, IN UINTN NumberOfPages ) { LIST_ENTRY *Node; FREE_PAGE_LIST *Pages; if ((Memory & EFI_PAGE_MASK) != 0) { return EFI_INVALID_PARAMETER; } Pages = NULL; Node = mSmmMemoryMap.ForwardLink; while (Node != &mSmmMemoryMap) { Pages = BASE_CR (Node, FREE_PAGE_LIST, Link); if (Memory < (UINTN)Pages) { break; } Node = Node->ForwardLink; } if (Node != &mSmmMemoryMap && Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages) { return EFI_INVALID_PARAMETER; } if (Node->BackLink != &mSmmMemoryMap) { Pages = BASE_CR (Node->BackLink, FREE_PAGE_LIST, Link); if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) > Memory) { return EFI_INVALID_PARAMETER; } } Pages = (FREE_PAGE_LIST*)(UINTN)Memory; Pages->NumberOfPages = NumberOfPages; InsertTailList (Node, &Pages->Link); if (Pages->Link.BackLink != &mSmmMemoryMap) { Pages = InternalMergeNodes ( BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link) ); } if (Node != &mSmmMemoryMap) { InternalMergeNodes (Pages); } return EFI_SUCCESS; }
VOID RemovePagesFromList ( IN VOID *Buffer, OUT VOID **Allocation, OUT UINTN *Pages ) { LIST_ENTRY *Link; FREE_PAGE_NODE *OldNode; *Allocation = NULL; *Pages = 0; for (Link = mPageList.ForwardLink; Link != &mPageList; Link = Link->ForwardLink) { OldNode = BASE_CR (Link, FREE_PAGE_NODE, Link); if (OldNode->Buffer == Buffer) { *Allocation = OldNode->Allocation; *Pages = OldNode->Pages; RemoveEntryList (&OldNode->Link); FreePool (OldNode); return; } } return; }
/** This function find LockBox by GUID. @param Guid The guid to indentify the LockBox @return LockBoxData **/ SMM_LOCK_BOX_DATA * InternalFindLockBoxByGuid ( IN EFI_GUID *Guid ) { LIST_ENTRY *Link; SMM_LOCK_BOX_DATA *LockBox; LIST_ENTRY *LockBoxQueue; LockBoxQueue = InternalGetLockBoxQueue (); ASSERT (LockBoxQueue != NULL); for (Link = LockBoxQueue->ForwardLink; Link != LockBoxQueue; Link = Link->ForwardLink) { LockBox = BASE_CR ( Link, SMM_LOCK_BOX_DATA, Link ); if (CompareGuid (&LockBox->Guid, Guid)) { return LockBox; } } return NULL; }
/** Internal Function. Allocate a pool by specified PoolIndex. @param PoolIndex Index which indicate the Pool size. @param FreePoolHdr The returned Free pool. @retval EFI_OUT_OF_RESOURCES Allocation failed. @retval EFI_SUCCESS Pool successfully allocated. **/ EFI_STATUS InternalAllocPoolByIndex ( IN UINTN PoolIndex, OUT FREE_POOL_HEADER **FreePoolHdr ) { EFI_STATUS Status; FREE_POOL_HEADER *Hdr; EFI_PHYSICAL_ADDRESS Address; ASSERT (PoolIndex <= MAX_POOL_INDEX); Status = EFI_SUCCESS; if (PoolIndex == MAX_POOL_INDEX) { Status = SmmInternalAllocatePages (AllocateAnyPages, EfiRuntimeServicesData, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } Hdr = (FREE_POOL_HEADER *) (UINTN) Address; } else if (!IsListEmpty (&mSmmPoolLists[PoolIndex])) { Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link); RemoveEntryList (&Hdr->Link); } else { Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr); if (!EFI_ERROR (Status)) { Hdr->Header.Size >>= 1; Hdr->Header.Available = TRUE; InsertHeadList (&mSmmPoolLists[PoolIndex], &Hdr->Link); Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size); } }
/** Internal Function. Allocate n pages from free page list at given address. @param FreePageList The free page node. @param NumberOfPages Number of pages to be allocated. @param MaxAddress Request to allocate memory below this address. @return Memory address of allocated pages. **/ UINTN InternalAllocAddress ( IN OUT LIST_ENTRY *FreePageList, IN UINTN NumberOfPages, IN UINTN Address ) { UINTN EndAddress; LIST_ENTRY *Node; FREE_PAGE_LIST *Pages; if ((Address & EFI_PAGE_MASK) != 0) { return ~Address; } EndAddress = Address + EFI_PAGES_TO_SIZE (NumberOfPages); for (Node = FreePageList->BackLink; Node!= FreePageList; Node = Node->BackLink) { Pages = BASE_CR (Node, FREE_PAGE_LIST, Link); if ((UINTN)Pages <= Address) { if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) < EndAddress) { break; } return InternalAllocPagesOnOneNode (Pages, NumberOfPages, EndAddress); } } return ~Address; }
EFI_STATUS QNCSmmCoreUnRegister ( IN QNC_SMM_GENERIC_PROTOCOL *This, IN EFI_HANDLE DispatchHandle ) /*++ Routine Description: Arguments: Returns: --*/ // GC_TODO: This - add argument and description to function comment // GC_TODO: DispatchHandle - add argument and description to function comment // GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment // GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment // GC_TODO: EFI_SUCCESS - add return value to function comment { BOOLEAN SafeToDisable; DATABASE_RECORD *RecordToDelete; DATABASE_RECORD *RecordInDb; LIST_ENTRY *LinkInDb; if (DispatchHandle == NULL) { return EFI_INVALID_PARAMETER; } if (BASE_CR (DispatchHandle, DATABASE_RECORD, Link)->Signature != DATABASE_RECORD_SIGNATURE) { return EFI_INVALID_PARAMETER; } RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle); RemoveEntryList (&RecordToDelete->Link); RecordToDelete->Signature = 0; // // See if we can disable the source, reserved for future use since this might // not be the only criteria to disable // SafeToDisable = TRUE; LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); while(!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); if (CompareEnables (&RecordToDelete->SrcDesc, &RecordInDb->SrcDesc)) { SafeToDisable = FALSE; break; } LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); } if (SafeToDisable) { QNCSmmDisableSource( &RecordToDelete->SrcDesc ); } FreePool (RecordToDelete); return EFI_SUCCESS; }
/** Retrieve one record of from free record buffer. This record is removed from free record buffer. This function retrieves one record from free record buffer. If the pool has been exhausted, then new memory would be allocated for it. @return Pointer to the free record. NULL means failure to allocate new memeory for free record buffer. **/ DATA_HUB_STATUS_CODE_DATA_RECORD * AcquireRecordBuffer ( VOID ) { DATAHUB_STATUSCODE_RECORD *Record; EFI_TPL CurrentTpl; LIST_ENTRY *Node; UINT32 Index; CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); if (!IsListEmpty (&mRecordsBuffer)) { // // Strip one entry from free record buffer. // Node = GetFirstNode (&mRecordsBuffer); RemoveEntryList (Node); Record = BASE_CR (Node, DATAHUB_STATUSCODE_RECORD, Node); } else { if (CurrentTpl > TPL_NOTIFY) { // // Memory management should work at <=TPL_NOTIFY // gBS->RestoreTPL (CurrentTpl); return NULL; } // // If free record buffer is exhausted, then allocate 16 new records for it. // gBS->RestoreTPL (CurrentTpl); Record = (DATAHUB_STATUSCODE_RECORD *) AllocateZeroPool (sizeof (DATAHUB_STATUSCODE_RECORD) * 16); if (Record == NULL) { return NULL; } CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); // // Here we only insert 15 new records to the free record buffer, for the first record // will be returned immediately. // for (Index = 1; Index < 16; Index++) { InsertTailList (&mRecordsBuffer, &Record[Index].Node); } } Record->Signature = DATAHUB_STATUS_CODE_SIGNATURE; InsertTailList (&mRecordsFifo, &Record->Node); gBS->RestoreTPL (CurrentTpl); return (DATA_HUB_STATUS_CODE_DATA_RECORD *) (Record->Data); }
/** Console-specific helper function for the fstat() function. st_size Set to number of characters read for stdin and number written for stdout and stderr. st_physsize 1 for stdin, 0 if QueryMode error, else max X and Y coordinates for the current mode. st_curpos 0 for stdin, current X & Y coordinates for stdout and stderr st_blksize Set to 1 since this is a character device All other members of the stat structure are left unchanged. **/ static int EFIAPI da_ConStat( struct __filedes *filp, struct stat *Buffer, void *Something ) { ConInstance *Stream; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto; XYoffset CursorPos; INT32 OutMode; UINTN ModeCol; UINTN ModeRow; // ConGetInfo Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction); // Quick check to see if Stream looks reasonable if ((Stream->Cookie != CON_COOKIE) || // Cookie == 'IoAb' (Buffer == NULL)) { EFIerrno = RETURN_INVALID_PARAMETER; return -1; } // All of our parameters are correct, so fill in the information. Buffer->st_blksize = 1; // ConGetPosition if(Stream->InstanceNum == STDIN_FILENO) { // This is stdin Buffer->st_curpos = 0; Buffer->st_size = (off_t)Stream->NumRead; Buffer->st_physsize = 1; } else { Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev; CursorPos.XYpos.Column = (UINT32)Proto->Mode->CursorColumn; CursorPos.XYpos.Row = (UINT32)Proto->Mode->CursorRow; Buffer->st_curpos = (off_t)CursorPos.Offset; Buffer->st_size = (off_t)Stream->NumWritten; OutMode = Proto->Mode->Mode; EFIerrno = Proto->QueryMode(Proto, (UINTN)OutMode, &ModeCol, &ModeRow); if(RETURN_ERROR(EFIerrno)) { Buffer->st_physsize = 0; } else { CursorPos.XYpos.Column = (UINT32)ModeCol; CursorPos.XYpos.Row = (UINT32)ModeRow; Buffer->st_physsize = (off_t)CursorPos.Offset; } } return 0; }
/** Close a file handle opened by EfiOpen() and free all resources allocated by EfiOpen(). @param Stream Open File Handle @return EFI_INVALID_PARAMETER Stream is not an Open File @return EFI_SUCCESS Steam closed **/ EFI_STATUS EfiClose ( IN EFI_OPEN_FILE *File ) { EFI_STATUS Status; UINT64 TftpBufferSize; if (!FileHandleValid (File)) { return EFI_INVALID_PARAMETER; } //Write the buffer contents to TFTP file. if ((File->Type == EfiOpenTftp) && (File->IsDirty)) { TftpBufferSize = File->Size; Status = EblMtftp ( EFI_PXE_BASE_CODE_TFTP_WRITE_FILE, File->Buffer, TRUE, &TftpBufferSize, NULL, &File->ServerIp, (UINT8 *)File->FileName, NULL, FALSE ); if (EFI_ERROR(Status)) { AsciiPrint("TFTP error during APPLE_NSP_TFTP_WRITE_FILE: %r\n", Status); return Status; } } if ((File->Type == EfiOpenLoadFile) || ((File->Type == EfiOpenTftp) && (File->IsBufferValid == TRUE)) || ((File->Type == EfiOpenFirmwareVolume) && (File->IsBufferValid == TRUE))) { EblFreePool(File->Buffer); } EblFreePool (File->DevicePath); EblFreePool (File->DeviceName); EblFreePool (File->FsFileInfo); EblFreePool (File->FsInfo); if (File->FsFileHandle != NULL) { File->FsFileHandle->Close (File->FsFileHandle); } // Need to free File and it's Guard structures EblFreePool (BASE_CR (File, EFI_OPEN_FILE_GUARD, File)); return EFI_SUCCESS; }
/** The realloc function changes the size of the object pointed to by Ptr to the size specified by NewSize. The contents of the object are unchanged up to the lesser of the new and old sizes. If the new size is larger, the value of the newly allocated portion of the object is indeterminate. If Ptr is a null pointer, the realloc function behaves like the malloc function for the specified size. If Ptr does not match a pointer earlier returned by the calloc, malloc, or realloc function, or if the space has been deallocated by a call to the free or realloc function, the behavior is undefined. If the space cannot be allocated, the object pointed to by Ptr is unchanged. If NewSize is zero and Ptr is not a null pointer, the object it points to is freed. This implementation uses the UEFI memory allocation boot services to get a region of memory that is 8-byte aligned and of the specified size. The region is allocated with type EfiLoaderData. The following combinations of Ptr and NewSize can occur:<BR> Ptr NewSize<BR> -------- -------------------<BR> - NULL 0 Returns NULL; - NULL > 0 Same as malloc(NewSize) - invalid X Returns NULL; - valid NewSize >= OldSize Returns malloc(NewSize) with Oldsize bytes copied from Ptr - valid NewSize < OldSize Returns new buffer with Oldsize bytes copied from Ptr - valid 0 Return NULL. Frees Ptr. @param Ptr Pointer to a previously allocated region of memory to be resized. @param NewSize Size, in bytes, of the new object to allocate space for. @return NULL is returned if the space could not be allocated and errno contains the cause. Otherwise, a pointer to an 8-byte aligned region of the requested size is returned. If NewSize is zero, NULL is returned and errno will be unchanged. **/ void * realloc(void *Ptr, size_t ReqSize) { void *RetVal = NULL; CPOOL_HEAD *Head = NULL; size_t OldSize = 0; size_t NewSize; size_t NumCpy; // Find out the size of the OLD memory region if( Ptr != NULL) { Head = BASE_CR (Ptr, CPOOL_HEAD, Data); assert(Head != NULL); if (Head->Signature != CPOOL_HEAD_SIGNATURE) { errno = EFAULT; DEBUG((DEBUG_ERROR, "ERROR realloc(0x%p): Signature is 0x%8X, expected 0x%8X\n", Ptr, Head->Signature, CPOOL_HEAD_SIGNATURE)); return NULL; } OldSize = (size_t)Head->Size; } // At this point, Ptr is either NULL or a valid pointer to an allocated space NewSize = (size_t)(ReqSize + (sizeof(CPOOL_HEAD))); if( ReqSize > 0) { RetVal = malloc(NewSize); // Get the NEW memory region if( Ptr != NULL) { // If there is an OLD region... if( RetVal != NULL) { // and the NEW region was successfully allocated NumCpy = OldSize; if( OldSize > NewSize) { NumCpy = NewSize; } (VOID)CopyMem( RetVal, Ptr, NumCpy); // Copy old data to the new region. free( Ptr); // and reclaim the old region. } else { errno = ENOMEM; } } } else { free( Ptr); // Reclaim the old region. } DEBUG((DEBUG_POOL, "0x%p = realloc(%p, %d): Head: %p NewSz: %d\n", RetVal, Ptr, ReqSize, Head, NewSize)); return RetVal; }
/** Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. It convers pointer to new virtual address. @param Event Event whose notification function is being invoked. @param Context Pointer to the notification function's context. **/ VOID EFIAPI VariableClassAddressChangeEvent ( IN EFI_EVENT Event, IN VOID *Context ) { LIST_ENTRY *Link; VARIABLE_ENTRY *Entry; EFI_STATUS Status; EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->LangCodes); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLang); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal); EfiConvertPointer (0x0, (VOID **) &mHashCtx); EfiConvertPointer (0x0, (VOID **) &mSerializationRuntimeBuffer); EfiConvertPointer (0x0, (VOID **) &mNvVariableCache); EfiConvertPointer (0x0, (VOID **) &mPubKeyStore); EfiConvertPointer (0x0, (VOID **) &mCertDbStore); // // in the list of locked variables, convert the name pointers first // for ( Link = GetFirstNode (&mLockedVariableList) ; !IsNull (&mLockedVariableList, Link) ; Link = GetNextNode (&mLockedVariableList, Link) ) { Entry = BASE_CR (Link, VARIABLE_ENTRY, Link); Status = EfiConvertPointer (0x0, (VOID **) &Entry->Name); ASSERT_EFI_ERROR (Status); } // // second, convert the list itself using UefiRuntimeLib // Status = EfiConvertList (0x0, &mLockedVariableList); ASSERT_EFI_ERROR (Status); }
/** Internal worker function to validate a File handle. @param File Open File Handle @return TRUE File is valid @return FALSE File is not valid **/ BOOLEAN FileHandleValid ( IN EFI_OPEN_FILE *File ) { EFI_OPEN_FILE_GUARD *GuardFile; // Look right before and after file structure for the correct signatures GuardFile = BASE_CR (File, EFI_OPEN_FILE_GUARD, File); if ((GuardFile->Header != EFI_OPEN_FILE_GUARD_HEADER) || (GuardFile->Footer != EFI_OPEN_FILE_GUARD_FOOTER) ) { return FALSE; } return TRUE; }
/** Get FVB authentication status @param FvbProtocol FVB protocol. @return Authentication status. **/ UINT32 GetFvbAuthenticationStatus ( IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol ) { EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; UINT32 AuthenticationStatus; AuthenticationStatus = 0; FvbDevice = BASE_CR (FvbProtocol, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance); if (FvbDevice->Signature == FVB_DEVICE_SIGNATURE) { AuthenticationStatus = FvbDevice->AuthenticationStatus; } return AuthenticationStatus; }
/* Returns a bit mask describing which operations could be completed immediately. (POLLIN | POLLRDNORM) A Unicode character is available to read (POLLIN) A ScanCode is ready. (POLLOUT) The device is ready for output - always set on stdout and stderr. */ static short EFIAPI da_ConPoll( struct __filedes *filp, short events ) { EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto; ConInstance *Stream; EFI_STATUS Status = RETURN_SUCCESS; short RdyMask = 0; Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction); // Quick check to see if Stream looks reasonable if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb' EFIerrno = RETURN_INVALID_PARAMETER; return POLLNVAL; // Looks like a bad filp pointer } if(Stream->InstanceNum == 0) { // Only input is supported for this device Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev; if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) { Status = Proto->ReadKeyStroke(Proto, &Stream->UnGetKey); if(Status == RETURN_SUCCESS) { RdyMask = POLLIN; if(Stream->UnGetKey.UnicodeChar != CHAR_NULL) { RdyMask |= POLLRDNORM; } } else { Stream->UnGetKey.ScanCode = SCAN_NULL; Stream->UnGetKey.UnicodeChar = CHAR_NULL; } } } else if(Stream->InstanceNum < NUM_SPECIAL) { // Not 0, is it 1 or 2? // Only output is supported for this device RdyMask = POLLOUT; } else { RdyMask = POLLERR; // Not one of the standard streams } EFIerrno = Status; return (RdyMask & (events | POLL_RETONLY)); }
static int EFIAPI da_ConClose( IN struct __filedes *filp ) { ConInstance *Stream; Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction); // Quick check to see if Stream looks reasonable if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb' EFIerrno = RETURN_INVALID_PARAMETER; return -1; // Looks like a bad File Descriptor pointer } gMD->StdIo[Stream->InstanceNum] = NULL; // Mark the stream as closed return RETURN_SUCCESS; }
/** Internal Function. Merge two adjacent nodes. @param First The first of two nodes to merge. @return Pointer to node after merge (if success) or pointer to next node (if fail). **/ FREE_PAGE_LIST * InternalMergeNodes ( IN FREE_PAGE_LIST *First ) { FREE_PAGE_LIST *Next; Next = BASE_CR (First->Link.ForwardLink, FREE_PAGE_LIST, Link); ASSERT ( TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) >= First->NumberOfPages); if (TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) == First->NumberOfPages) { First->NumberOfPages += Next->NumberOfPages; RemoveEntryList (&Next->Link); Next = First; } return Next; }
/** Internal Function. Allocate a pool by specified PoolIndex. @param PoolType Type of pool to allocate. @param PoolIndex Index which indicate the Pool size. @param FreePoolHdr The returned Free pool. @retval EFI_OUT_OF_RESOURCES Allocation failed. @retval EFI_SUCCESS Pool successfully allocated. **/ EFI_STATUS InternalAllocPoolByIndex ( IN EFI_MEMORY_TYPE PoolType, IN UINTN PoolIndex, OUT FREE_POOL_HEADER **FreePoolHdr ) { EFI_STATUS Status; FREE_POOL_HEADER *Hdr; POOL_TAIL *Tail; EFI_PHYSICAL_ADDRESS Address; SMM_POOL_TYPE SmmPoolType; Address = 0; SmmPoolType = UefiMemoryTypeToSmmPoolType(PoolType); ASSERT (PoolIndex <= MAX_POOL_INDEX); Status = EFI_SUCCESS; Hdr = NULL; if (PoolIndex == MAX_POOL_INDEX) { Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address, FALSE); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } Hdr = (FREE_POOL_HEADER *) (UINTN) Address; } else if (!IsListEmpty (&mSmmPoolLists[SmmPoolType][PoolIndex])) { Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[SmmPoolType][PoolIndex]), FREE_POOL_HEADER, Link); RemoveEntryList (&Hdr->Link); } else { Status = InternalAllocPoolByIndex (PoolType, PoolIndex + 1, &Hdr); if (!EFI_ERROR (Status)) { Hdr->Header.Signature = 0; Hdr->Header.Size >>= 1; Hdr->Header.Available = TRUE; Hdr->Header.Type = 0; Tail = HEAD_TO_TAIL(&Hdr->Header); Tail->Signature = 0; Tail->Size = 0; InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &Hdr->Link); Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size); } }
/** Internal Function. Allocate n pages from free page list below MaxAddress. @param FreePageList The free page node. @param NumberOfPages Number of pages to be allocated. @param MaxAddress Request to allocate memory below this address. @return Memory address of allocated pages. **/ UINTN InternalAllocMaxAddress ( IN OUT LIST_ENTRY *FreePageList, IN UINTN NumberOfPages, IN UINTN MaxAddress ) { LIST_ENTRY *Node; FREE_PAGE_LIST *Pages; for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) { Pages = BASE_CR (Node, FREE_PAGE_LIST, Link); if (Pages->NumberOfPages >= NumberOfPages && (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress) { return InternalAllocPagesOnOneNode (Pages, NumberOfPages, MaxAddress); } } return (UINTN)(-1); }
/** The realloc function changes the size of the object pointed to by Ptr to the size specified by NewSize. The contents of the object are unchanged up to the lesser of the new and old sizes. If the new size is larger, the value of the newly allocated portion of the object is indeterminate. If Ptr is a null pointer, the realloc function behaves like the malloc function for the specified size. If Ptr does not match a pointer earlier returned by the calloc, malloc, or realloc function, or if the space has been deallocated by a call to the free or realloc function, the behavior is undefined. If the space cannot be allocated, the object pointed to by Ptr is unchanged. If NewSize is zero and Ptr is not a null pointer, the object it points to is freed. This implementation uses the UEFI memory allocation boot services to get a region of memory that is 8-byte aligned and of the specified size. The region is allocated with type EfiLoaderData. The following combinations of Ptr and NewSize can occur:<BR> Ptr NewSize<BR> -------- -------------------<BR> - NULL 0 Returns NULL; - NULL > 0 Same as malloc(NewSize) - invalid X Returns NULL; - valid NewSize >= OldSize Returns malloc(NewSize) with Oldsize bytes copied from Ptr - valid NewSize < OldSize Returns new buffer with Oldsize bytes copied from Ptr - valid 0 Return NULL. Frees Ptr. @param Ptr Pointer to a previously allocated region of memory to be resized. @param NewSize Size, in bytes, of the new object to allocate space for. @return NULL is returned if the space could not be allocated and errno contains the cause. Otherwise, a pointer to an 8-byte aligned region of the requested size is returned. If NewSize is zero, NULL is returned and errno will be unchanged. **/ void * realloc(void *Ptr, size_t NewSize) { void *RetVal = NULL; POOL_HEAD *Head; UINTN OldSize = 0; UINTN NumCpy; // Find out the size of the OLD memory region if( Ptr != NULL) { Head = BASE_CR (Ptr, POOL_HEAD, Data); assert(Head != NULL); if (Head->Signature != POOL_HEAD_SIGNATURE) { errno = EFAULT; return NULL; } OldSize = Head->Size; } // At this point, Ptr is either NULL or a valid pointer to an allocated space if( NewSize > 0) { RetVal = malloc(NewSize); // Get the NEW memory region if( Ptr != NULL) { // If there is an OLD region... if( RetVal != NULL) { // and the NEW region was successfully allocated NumCpy = OldSize; if( OldSize > NewSize) { NumCpy = NewSize; } (VOID)CopyMem( RetVal, Ptr, NumCpy); // Copy old data to the new region. free( Ptr); // and reclaim the old region. } } } else { if( Ptr != NULL) { free( Ptr); // Reclaim the old region. } } return RetVal; }
/** The clean process of the IfConfig6 application. @param[in] IfList The pointer of IfList(interface list). @retval EFI_SUCCESS The IfConfig6 clean processed successfully. @retval others The IfConfig6 clean process failed. **/ EFI_STATUS IfConfig6ClearInterfaceInfo ( IN LIST_ENTRY *IfList ) { EFI_STATUS Status; LIST_ENTRY *Entry; IFCONFIG6_INTERFACE_CB *IfCb; EFI_IP6_CONFIG_POLICY Policy; Policy = Ip6ConfigPolicyAutomatic; Entry = IfList->ForwardLink; Status = EFI_SUCCESS; if (IsListEmpty (IfList)) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_INTERFACE), mHiiHandle); } // // Go through the interface list. // while (Entry != IfList) { IfCb = BASE_CR (Entry, IFCONFIG6_INTERFACE_CB, Link); Status = IfCb->IfCfg->SetData ( IfCb->IfCfg, Ip6ConfigDataTypePolicy, sizeof (EFI_IP6_CONFIG_POLICY), &Policy ); if (EFI_ERROR (Status)) { break; } Entry = Entry->ForwardLink; } return Status; }
EFIAPI IIO_GetDeviceProto ( int fd, struct __filedes **filp ) { void *Proto; ConInstance *Stream; struct __filedes *pfil; Proto = NULL; if(ValidateFD( fd, VALID_OPEN)) { pfil = &gMD->fdarray[fd]; Stream = BASE_CR(pfil->f_ops, ConInstance, Abstraction); Proto = (void *)Stream->Dev; if(filp != NULL) { *filp = pfil; } } return Proto; }
static off_t EFIAPI da_ConSeek( struct __filedes *filp, off_t Position, int whence ///< Ignored by Console ) { ConInstance *Stream; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto; XYoffset CursorPos; Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction); // Quick check to see if Stream looks reasonable if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb' EFIerrno = RETURN_INVALID_PARAMETER; return -1; // Looks like a bad This pointer } if(Stream->InstanceNum == STDIN_FILENO) { // Seek is not valid for stdin EFIerrno = RETURN_UNSUPPORTED; return -1; } // Everything is OK to do the final verification and "seek". Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev; CursorPos.Offset = Position; EFIerrno = Proto->SetCursorPosition(Proto, (INTN)CursorPos.XYpos.Column, (INTN)CursorPos.XYpos.Row); if(RETURN_ERROR(EFIerrno)) { return -1; } else { return Position; } }
/** The free function causes the space pointed to by Ptr to be deallocated, that is, made available for further allocation. If Ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by the calloc, malloc, or realloc function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined. @param Ptr Pointer to a previously allocated region of memory to be freed. **/ void free(void *Ptr) { CPOOL_HEAD *Head; Head = BASE_CR(Ptr, CPOOL_HEAD, Data); assert(Head != NULL); DEBUG((DEBUG_POOL, "free(%p): Head: %p\n", Ptr, Head)); if(Ptr != NULL) { if (Head->Signature == CPOOL_HEAD_SIGNATURE) { (void) RemoveEntryList((LIST_ENTRY *)Head); // Remove this node from the malloc pool (void) gBS->FreePool (Head); // Now free the associated memory } else { errno = EFAULT; DEBUG((DEBUG_ERROR, "ERROR free(0x%p): Signature is 0x%8X, expected 0x%8X\n", Ptr, Head->Signature, CPOOL_HEAD_SIGNATURE)); } } DEBUG((DEBUG_POOL, "free Done\n")); }
/** The function extracts device information from OpalDeviceList and creat SmmDeviceList used for S3. @param[in] OpalDeviceList Opal device list created at POST which contains the information of OPAL_DISK_AND_PASSWORD_INFO @param[in,out] SmmDeviceList Opal Smm device list to be created and used for unlocking devices at S3 resume. @retval EFI_SUCCESS Create SmmDeviceList successfully. @retval Others Other execution results. **/ EFI_STATUS CreateSmmDeviceList ( IN LIST_ENTRY *OpalDeviceList, IN OUT LIST_ENTRY *SmmDeviceList ) { LIST_ENTRY *Entry; OPAL_DISK_AND_PASSWORD_INFO *PciDev; OPAL_SMM_DEVICE *SmmDev; for (Entry = OpalDeviceList->ForwardLink; Entry != OpalDeviceList; Entry = Entry->ForwardLink) { PciDev = BASE_CR (Entry, OPAL_DISK_AND_PASSWORD_INFO, Link); SmmDev = AllocateZeroPool (sizeof (OPAL_SMM_DEVICE)); if (SmmDev == NULL) { return EFI_OUT_OF_RESOURCES; } SmmDev->Signature = OPAL_SMM_DEVICE_SIGNATURE; ExtractDeviceInfoFromDevicePath(&PciDev->OpalDevicePath, SmmDev); SmmDev->PasswordLength = PciDev->PasswordLength; CopyMem(&(SmmDev->Password), PciDev->Password, OPAL_PASSWORD_MAX_LENGTH); SmmDev->Sscp.ReceiveData = SecurityReceiveData; SmmDev->Sscp.SendData = SecuritySendData; DEBUG ((DEBUG_INFO, "Opal SMM: Insert device node to SmmDeviceList:\n")); DEBUG ((DEBUG_INFO, "DeviceType:%x, Bus:%d, Dev:%d, Fun:%d\n", \ SmmDev->DeviceType, SmmDev->BusNum, SmmDev->DevNum, SmmDev->FuncNum)); DEBUG ((DEBUG_INFO, "SataPort:%x, MultiplierPort:%x, NvmeNamespaceId:%x\n", \ SmmDev->SataPort, SmmDev->SataPortMultiplierPort, SmmDev->NvmeNamespaceId)); InsertHeadList (SmmDeviceList, &SmmDev->Link); } return EFI_SUCCESS; }
/** This function find LockBox by GUID from SMRAM. @param LockBoxQueue The LockBox queue in SMRAM @param Guid The guid to indentify the LockBox @return LockBoxData **/ SMM_LOCK_BOX_DATA * InternalFindLockBoxByGuidFromSmram ( IN LIST_ENTRY *LockBoxQueue, IN EFI_GUID *Guid ) { LIST_ENTRY *Link; SMM_LOCK_BOX_DATA *LockBox; for (Link = InternalInitLinkDxe (LockBoxQueue); Link != LockBoxQueue; Link = InternalNextLinkDxe (Link)) { LockBox = BASE_CR ( Link, SMM_LOCK_BOX_DATA, Link ); if (CompareGuid (&LockBox->Guid, Guid)) { return LockBox; } } return NULL; }
/** ExitBootServices Callback function for memory protection. **/ VOID MemoryProtectionExitBootServicesCallback ( VOID ) { EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage; LIST_ENTRY *Link; // // We need remove the RT protection, because RT relocation need write code segment // at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. // // Firmware does not own page tables after ExitBootServices(), so the OS would // have to relax protection of RT code pages across SetVirtualAddressMap(), or // delay setting protections on RT code pages until after SetVirtualAddressMap(). // OS may set protection on RT based upon EFI_MEMORY_ATTRIBUTES_TABLE later. // if (mImageProtectionPolicy != 0) { for (Link = gRuntime->ImageHead.ForwardLink; Link != &gRuntime->ImageHead; Link = Link->ForwardLink) { RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link); SetUefiImageMemoryAttributes ((UINT64)(UINTN)RuntimeImage->ImageBase, ALIGN_VALUE(RuntimeImage->ImageSize, EFI_PAGE_SIZE), 0); } } }
/** This notification function is invoked when an instance of the EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done. @param Event The event that occured @param Context For EFI compatiblity. Not used. **/ VOID EFIAPI NotifyFwVolBlock ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_HANDLE Handle; EFI_STATUS Status; UINTN BufferSize; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; FV_DEVICE *FvDevice; EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; // // Examine all new handles // for (;;) { // // Get the next handle // BufferSize = sizeof (Handle); Status = CoreLocateHandle ( ByRegisterNotify, NULL, gEfiFwVolBlockNotifyReg, &BufferSize, &Handle ); // // If not found, we're done // if (EFI_NOT_FOUND == Status) { break; } if (EFI_ERROR (Status)) { continue; } // // Get the FirmwareVolumeBlock protocol on that handle // Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb); ASSERT_EFI_ERROR (Status); ASSERT (Fvb != NULL); // // Make sure the Fv Header is O.K. // Status = GetFwVolHeader (Fvb, &FwVolHeader); if (EFI_ERROR (Status)) { return; } ASSERT (FwVolHeader != NULL); if (!VerifyFvHeaderChecksum (FwVolHeader)) { CoreFreePool (FwVolHeader); continue; } // // Check to see that the file system is indeed formatted in a way we can // understand it... // if ((!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid)) && (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid))) { continue; } // // Check if there is an FV protocol already installed in that handle // Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv); if (!EFI_ERROR (Status)) { // // Update Fv to use a new Fvb // FvDevice = BASE_CR (Fv, FV_DEVICE, Fv); if (FvDevice->Signature == FV2_DEVICE_SIGNATURE) { // // Only write into our device structure if it's our device structure // FvDevice->Fvb = Fvb; } } else { // // No FwVol protocol on the handle so create a new one // FvDevice = AllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice); if (FvDevice == NULL) { return; } FvDevice->Fvb = Fvb; FvDevice->Handle = Handle; FvDevice->FwVolHeader = FwVolHeader; FvDevice->IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid); FvDevice->Fv.ParentHandle = Fvb->ParentHandle; if (Fvb->ParentHandle != NULL) { // // Inherit the authentication status from FVB. // FvDevice->AuthenticationStatus = GetFvbAuthenticationStatus (Fvb); } if (!EFI_ERROR (FvCheck (FvDevice))) { // // Install an New FV protocol on the existing handle // Status = CoreInstallProtocolInterface ( &Handle, &gEfiFirmwareVolume2ProtocolGuid, EFI_NATIVE_INTERFACE, &FvDevice->Fv ); ASSERT_EFI_ERROR (Status); } else { // // Free FvDevice Buffer for the corrupt FV image. // CoreFreePool (FvDevice); } } } return; }
/** Changes the runtime addressing mode of EFI firmware from physical to virtual. @param MemoryMapSize The size in bytes of VirtualMap. @param DescriptorSize The size in bytes of an entry in the VirtualMap. @param DescriptorVersion The version of the structure entries in VirtualMap. @param VirtualMap An array of memory descriptors which contain new virtual address mapping information for all runtime ranges. @retval EFI_SUCCESS The virtual address map has been applied. @retval EFI_UNSUPPORTED EFI firmware is not at runtime, or the EFI firmware is already in virtual address mapped mode. @retval EFI_INVALID_PARAMETER DescriptorSize or DescriptorVersion is invalid. @retval EFI_NO_MAPPING A virtual address was not supplied for a range in the memory map that requires a mapping. @retval EFI_NOT_FOUND A virtual address was supplied for an address that is not found in the memory map. **/ EFI_STATUS EFIAPI RuntimeDriverSetVirtualAddressMap ( IN UINTN MemoryMapSize, IN UINTN DescriptorSize, IN UINT32 DescriptorVersion, IN EFI_MEMORY_DESCRIPTOR *VirtualMap ) { EFI_STATUS Status; EFI_RUNTIME_EVENT_ENTRY *RuntimeEvent; EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage; LIST_ENTRY *Link; EFI_PHYSICAL_ADDRESS VirtImageBase; // // Can only switch to virtual addresses once the memory map is locked down, // and can only set it once // if (!mRuntime.AtRuntime || mRuntime.VirtualMode) { return EFI_UNSUPPORTED; } // // Only understand the original descriptor format // if (DescriptorVersion != EFI_MEMORY_DESCRIPTOR_VERSION || DescriptorSize < sizeof (EFI_MEMORY_DESCRIPTOR)) { return EFI_INVALID_PARAMETER; } // // We are now committed to go to virtual mode, so lets get to it! // mRuntime.VirtualMode = TRUE; // // ConvertPointer() needs this mVirtualMap to do the conversion. So set up // globals we need to parse the virtual address map. // mVirtualMapDescriptorSize = DescriptorSize; mVirtualMapMaxIndex = MemoryMapSize / DescriptorSize; mVirtualMap = VirtualMap; // // ReporstStatusCodeLib will check and make sure this service can be called in runtime mode. // REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_EFI_RUNTIME_SERVICE | EFI_SW_RS_PC_SET_VIRTUAL_ADDRESS_MAP)); // // Signal all the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE events. // All runtime events are stored in a list in Runtime AP. // for (Link = mRuntime.EventHead.ForwardLink; Link != &mRuntime.EventHead; Link = Link->ForwardLink) { RuntimeEvent = BASE_CR (Link, EFI_RUNTIME_EVENT_ENTRY, Link); if ((RuntimeEvent->Type & EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) { RuntimeEvent->NotifyFunction ( RuntimeEvent->Event, RuntimeEvent->NotifyContext ); } } // // Relocate runtime images. All runtime images are stored in a list in Runtime AP. // for (Link = mRuntime.ImageHead.ForwardLink; Link != &mRuntime.ImageHead; Link = Link->ForwardLink) { RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link); // // We don't want to relocate our selves, as we only run in physical mode. // if (mMyImageBase != RuntimeImage->ImageBase) { VirtImageBase = (EFI_PHYSICAL_ADDRESS) (UINTN) RuntimeImage->ImageBase; Status = RuntimeDriverConvertPointer (0, (VOID **) &VirtImageBase); ASSERT_EFI_ERROR (Status); PeCoffLoaderRelocateImageForRuntime ( (EFI_PHYSICAL_ADDRESS) (UINTN) RuntimeImage->ImageBase, VirtImageBase, (UINTN) RuntimeImage->ImageSize, RuntimeImage->RelocationData ); InvalidateInstructionCacheRange (RuntimeImage->ImageBase, (UINTN) RuntimeImage->ImageSize); } } // // Convert all the Runtime Services except ConvertPointer() and SetVirtualAddressMap() // and recompute the CRC-32 // RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetTime); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetTime); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetWakeupTime); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetWakeupTime); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->ResetSystem); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetNextHighMonotonicCount); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetVariable); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetVariable); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetNextVariableName); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->QueryVariableInfo); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->UpdateCapsule); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->QueryCapsuleCapabilities); RuntimeDriverCalculateEfiHdrCrc (&gRT->Hdr); // // UEFI don't require System Configuration Tables Conversion. // // // Convert the runtime fields of the EFI System Table and recompute the CRC-32 // RuntimeDriverConvertInternalPointer ((VOID **) &gST->FirmwareVendor); RuntimeDriverConvertInternalPointer ((VOID **) &gST->ConfigurationTable); RuntimeDriverConvertInternalPointer ((VOID **) &gST->RuntimeServices); RuntimeDriverCalculateEfiHdrCrc (&gST->Hdr); // // At this point, gRT and gST are physical pointers, but the contents of these tables // have been converted to runtime. // // // mVirtualMap is only valid during SetVirtualAddressMap() call // mVirtualMap = NULL; return EFI_SUCCESS; }
/** Helper function of memory allocation with Guard pages. @param FreePageList The free page node. @param NumberOfPages Number of pages to be allocated. @param MaxAddress Request to allocate memory below this address. @param MemoryType Type of memory requested. @return Memory address of allocated pages. **/ UINTN InternalAllocMaxAddressWithGuard ( IN OUT LIST_ENTRY *FreePageList, IN UINTN NumberOfPages, IN UINTN MaxAddress, IN EFI_MEMORY_TYPE MemoryType ) { LIST_ENTRY *Node; FREE_PAGE_LIST *Pages; UINTN PagesToAlloc; UINTN HeadGuard; UINTN TailGuard; UINTN Address; for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) { Pages = BASE_CR (Node, FREE_PAGE_LIST, Link); if (Pages->NumberOfPages >= NumberOfPages && (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress) { // // We may need 1 or 2 more pages for Guard. Check it out. // PagesToAlloc = NumberOfPages; TailGuard = (UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages); if (!IsGuardPage (TailGuard)) { // // Add one if no Guard at the end of current free memory block. // PagesToAlloc += 1; TailGuard = 0; } HeadGuard = (UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages - PagesToAlloc) - EFI_PAGE_SIZE; if (!IsGuardPage (HeadGuard)) { // // Add one if no Guard at the page before the address to allocate // PagesToAlloc += 1; HeadGuard = 0; } if (Pages->NumberOfPages < PagesToAlloc) { // Not enough space to allocate memory with Guards? Try next block. continue; } Address = InternalAllocPagesOnOneNode (Pages, PagesToAlloc, MaxAddress); ConvertSmmMemoryMapEntry(MemoryType, Address, PagesToAlloc, FALSE); CoreFreeMemoryMapStack(); if (HeadGuard == 0) { // Don't pass the Guard page to user. Address += EFI_PAGE_SIZE; } SetGuardForMemory (Address, NumberOfPages); return Address; } } return (UINTN)(-1); }
/** Dispatch function for a Software SMI handler. @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). @param[in] RegisterContext Points to an optional handler context which was specified when the handler was registered. @param[in, out] CommBuffer A pointer to a collection of Data in memory that will be conveyed from a non-SMM environment into an SMM environment. @param[in, out] CommBufferSize The Size of the CommBuffer. @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers should still be called. @retval Others Other execution results. **/ EFI_STATUS EFIAPI SmmUnlockOpalPassword ( IN EFI_HANDLE DispatchHandle, IN CONST VOID *RegisterContext, IN OUT VOID *CommBuffer, IN OUT UINTN *CommBufferSize ) { EFI_STATUS Status; OPAL_SMM_DEVICE *OpalDev; LIST_ENTRY *Entry; UINT8 BaseClassCode; UINT8 SubClassCode; UINT8 ProgInt; TCG_RESULT Result; UINT8 SataCmdSt; UINT8 *StorePcieConfDataList[16]; UINTN RpBase; UINTN MemoryBase; UINTN MemoryLength; OPAL_SESSION Session; BOOLEAN BlockSidSupport; ZeroMem (StorePcieConfDataList, sizeof (StorePcieConfDataList)); Status = EFI_DEVICE_ERROR; // // try to unlock all locked hdd disks. // for (Entry = mSmmDeviceList.ForwardLink; Entry != &mSmmDeviceList; Entry = Entry->ForwardLink) { OpalDev = BASE_CR(Entry, OPAL_SMM_DEVICE, Link); RpBase = 0; SataCmdSt = 0; /// /// Configure RootPort for PCIe AHCI/NVME devices. /// if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { /// /// Save original RootPort configuration space to heap /// RpBase = SaveRestoreRootportConfSpace ( OpalDev, TRUE, StorePcieConfDataList ); MemoryBase = mNvmeContext.Nbar; MemoryLength = 0; ConfigureRootPortForPcieNand (RpBase, OpalDev->BusNum, (UINT32) MemoryBase, (UINT32) MemoryLength); /// /// Enable PCIE decode for RootPort /// SataCmdSt = PciRead8 (RpBase + NVME_PCIE_PCICMD); PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0x6); } else { SataCmdSt = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD)); PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), 0x6); } BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0B)); SubClassCode = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0A)); ProgInt = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x09)); if (BaseClassCode != PCI_CLASS_MASS_STORAGE) { Status = EFI_INVALID_PARAMETER; break; } Status = EFI_DEVICE_ERROR; if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_SATA) { if ((SubClassCode == PCI_CLASS_MASS_STORAGE_AHCI) || (SubClassCode == PCI_CLASS_MASS_STORAGE_RAID)) { Status = GetAhciBaseAddress (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "GetAhciBaseAddress error, Status: %r\n", Status)); goto done; } Status = AhciModeInitialize ((UINT8)OpalDev->SataPort); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "AhciModeInitialize error, Status: %r\n", Status)); goto done; } } else { DEBUG ((DEBUG_ERROR, "SubClassCode not support for SATA device\n")); } } else if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) { if (ProgInt != PCI_IF_NVMHCI) { DEBUG ((DEBUG_ERROR, "PI not support, skipped\n")); Status = EFI_NOT_FOUND; goto done; } mNvmeContext.PciBase = PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0); mNvmeContext.NvmeInitWaitTime = 0; mNvmeContext.Nsid = OpalDev->NvmeNamespaceId; Status = NvmeControllerInit (&mNvmeContext); } else { DEBUG ((DEBUG_ERROR, "SubClassCode not support for NVME device\n")); } } else { DEBUG ((DEBUG_ERROR, "Invalid Devicetype\n")); goto done; } Status = EFI_DEVICE_ERROR; BlockSidSupport = FALSE; if (IsOpalDeviceLocked (OpalDev, &BlockSidSupport)) { ZeroMem(&Session, sizeof(Session)); Session.Sscp = &OpalDev->Sscp; Session.MediaId = 0; Session.OpalBaseComId = OpalDev->OpalBaseComId; Result = OpalSupportUnlock (&Session, OpalDev->Password, OpalDev->PasswordLength, NULL); if (Result == TcgResultSuccess) { Status = EFI_SUCCESS; } } if (mSendBlockSID && BlockSidSupport) { Result = OpalBlockSid (&Session, TRUE); if (Result != TcgResultSuccess) { break; } } if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) { Status = NvmeControllerExit (&mNvmeContext); } } done: if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { ASSERT (RpBase != 0); PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0); RpBase = SaveRestoreRootportConfSpace ( OpalDev, FALSE, // restore StorePcieConfDataList ); PciWrite8 (RpBase + NVME_PCIE_PCICMD, SataCmdSt); } else { PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), SataCmdSt); } if (EFI_ERROR (Status)) { break; } } return Status; }