/** Allocate a block of memory to be used by the buffer pool. @param Pages How many pages to allocate. @return The allocated memory block or NULL if failed. **/ SD_PEIM_MEM_BLOCK * SdPeimAllocMemBlock ( IN UINTN Pages ) { SD_PEIM_MEM_BLOCK *Block; VOID *BufHost; VOID *Mapping; EFI_PHYSICAL_ADDRESS MappedAddr; EFI_STATUS Status; VOID *TempPtr; TempPtr = NULL; Block = NULL; Status = PeiServicesAllocatePool (sizeof(SD_PEIM_MEM_BLOCK), &TempPtr); if (EFI_ERROR (Status)) { return NULL; } ZeroMem ((VOID*)(UINTN)TempPtr, sizeof(SD_PEIM_MEM_BLOCK)); // // each bit in the bit array represents SD_PEIM_MEM_UNIT // bytes of memory in the memory block. // ASSERT (SD_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE); Block = (SD_PEIM_MEM_BLOCK*)(UINTN)TempPtr; Block->BufLen = EFI_PAGES_TO_SIZE (Pages); Block->BitsLen = Block->BufLen / (SD_PEIM_MEM_UNIT * 8); Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr); if (EFI_ERROR (Status)) { return NULL; } ZeroMem ((VOID*)(UINTN)TempPtr, Block->BitsLen); Block->Bits = (UINT8*)(UINTN)TempPtr; Status = IoMmuAllocateBuffer ( Pages, &BufHost, &MappedAddr, &Mapping ); if (EFI_ERROR (Status)) { return NULL; } ZeroMem ((VOID*)(UINTN)BufHost, EFI_PAGES_TO_SIZE (Pages)); Block->BufHost = (UINT8 *) (UINTN) BufHost; Block->Buf = (UINT8 *) (UINTN) MappedAddr; Block->Mapping = Mapping; Block->Next = NULL; return Block; }
/** Allocates pages at a specified alignment. If Alignment is not a power of two and Alignment is not zero, then ASSERT(). @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 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; EFI_PHYSICAL_ADDRESS DeviceMemory; UINTN AlignedDeviceMemory; UINTN RealPages; // // 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 = IoMmuAllocateBuffer ( Pages, &Memory, &DeviceMemory, Mapping ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask; AlignedDeviceMemory = ((UINTN) DeviceMemory + AlignmentMask) & ~AlignmentMask; } else { // // Do not over-allocate pages in this case. // Status = IoMmuAllocateBuffer ( Pages, &Memory, &DeviceMemory, Mapping ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } AlignedMemory = (UINTN) Memory; AlignedDeviceMemory = (UINTN) DeviceMemory; } *HostAddress = (VOID *) AlignedMemory; *DeviceAddress = (EFI_PHYSICAL_ADDRESS) AlignedDeviceMemory; return EFI_SUCCESS; }
/** Allocate a block of memory to be used by the buffer pool. @param Pages How many pages to allocate. @return Pointer to the allocated memory block or NULL if failed. **/ USBHC_MEM_BLOCK * UsbHcAllocMemBlock ( IN UINTN Pages ) { USBHC_MEM_BLOCK *Block; VOID *BufHost; VOID *Mapping; EFI_PHYSICAL_ADDRESS MappedAddr; EFI_STATUS Status; UINTN PageNumber; EFI_PHYSICAL_ADDRESS TempPtr; PageNumber = EFI_SIZE_TO_PAGES (sizeof (USBHC_MEM_BLOCK)); Status = PeiServicesAllocatePages ( EfiBootServicesData, PageNumber, &TempPtr ); if (EFI_ERROR (Status)) { return NULL; } ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber)); // // each bit in the bit array represents USBHC_MEM_UNIT // bytes of memory in the memory block. // ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE); Block = (USBHC_MEM_BLOCK *) (UINTN) TempPtr; Block->BufLen = EFI_PAGES_TO_SIZE (Pages); Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8); PageNumber = EFI_SIZE_TO_PAGES (Block->BitsLen); Status = PeiServicesAllocatePages ( EfiBootServicesData, PageNumber, &TempPtr ); if (EFI_ERROR (Status)) { return NULL; } ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber)); Block->Bits = (UINT8 *) (UINTN) TempPtr; Status = IoMmuAllocateBuffer ( Pages, &BufHost, &MappedAddr, &Mapping ); if (EFI_ERROR (Status)) { return NULL; } ZeroMem ((VOID *) (UINTN) BufHost, EFI_PAGES_TO_SIZE (Pages)); Block->BufHost = (UINT8 *) (UINTN) BufHost; Block->Buf = (UINT8 *) (UINTN) MappedAddr; Block->Mapping = Mapping; Block->Next = NULL; return Block; }
/** Entry point of the PEIM. @param[in] FileHandle Handle of the file being invoked. @param[in] PeiServices Describes the list of possible PEI Services. @retval EFI_SUCCESS PPI successfully installed. **/ EFI_STATUS EFIAPI NvmExpressPeimEntry ( IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status; EFI_BOOT_MODE BootMode; EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI *NvmeHcPpi; UINT8 Controller; UINTN MmioBase; UINTN DevicePathLength; EFI_DEVICE_PATH_PROTOCOL *DevicePath; PEI_NVME_CONTROLLER_PRIVATE_DATA *Private; EFI_PHYSICAL_ADDRESS DeviceAddress; DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__)); // // Get the current boot mode. // Status = PeiServicesGetBootMode (&BootMode); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: Fail to get the current boot mode.\n", __FUNCTION__)); return Status; } // // Locate the NVME host controller PPI // Status = PeiServicesLocatePpi ( &gEdkiiPeiNvmExpressHostControllerPpiGuid, 0, NULL, (VOID **) &NvmeHcPpi ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: Fail to locate NvmeHostControllerPpi.\n", __FUNCTION__)); return EFI_UNSUPPORTED; } Controller = 0; MmioBase = 0; while (TRUE) { Status = NvmeHcPpi->GetNvmeHcMmioBar ( NvmeHcPpi, Controller, &MmioBase ); // // When status is error, meant no controller is found // if (EFI_ERROR (Status)) { break; } Status = NvmeHcPpi->GetNvmeHcDevicePath ( NvmeHcPpi, Controller, &DevicePathLength, &DevicePath ); if (EFI_ERROR (Status)) { DEBUG (( DEBUG_ERROR, "%a: Fail to allocate get the device path for Controller %d.\n", __FUNCTION__, Controller )); return Status; } // // Check validity of the device path of the NVM Express controller. // Status = NvmeIsHcDevicePathValid (DevicePath, DevicePathLength); if (EFI_ERROR (Status)) { DEBUG (( DEBUG_ERROR, "%a: The device path is invalid for Controller %d.\n", __FUNCTION__, Controller )); Controller++; continue; } // // For S3 resume performance consideration, not all NVM Express controllers // will be initialized. The driver consumes the content within // S3StorageDeviceInitList LockBox to see if a controller will be skipped // during S3 resume. // if ((BootMode == BOOT_ON_S3_RESUME) && (NvmeS3SkipThisController (DevicePath, DevicePathLength))) { DEBUG (( DEBUG_ERROR, "%a: Controller %d is skipped during S3.\n", __FUNCTION__, Controller )); Controller++; continue; } // // Memory allocation for controller private data // Private = AllocateZeroPool (sizeof (PEI_NVME_CONTROLLER_PRIVATE_DATA)); if (Private == NULL) { DEBUG (( DEBUG_ERROR, "%a: Fail to allocate private data for Controller %d.\n", __FUNCTION__, Controller )); return EFI_OUT_OF_RESOURCES; } // // Memory allocation for transfer-related data // Status = IoMmuAllocateBuffer ( NVME_MEM_MAX_PAGES, &Private->Buffer, &DeviceAddress, &Private->BufferMapping ); if (EFI_ERROR (Status)) { DEBUG (( DEBUG_ERROR, "%a: Fail to allocate DMA buffers for Controller %d.\n", __FUNCTION__, Controller )); return Status; } ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Private->Buffer)); DEBUG ((DEBUG_INFO, "%a: DMA buffer base at 0x%x\n", __FUNCTION__, Private->Buffer)); // // Initialize controller private data // Private->Signature = NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE; Private->MmioBase = MmioBase; Private->DevicePathLength = DevicePathLength; Private->DevicePath = DevicePath; // // Initialize the NVME controller // Status = NvmeControllerInit (Private); if (EFI_ERROR (Status)) { DEBUG (( DEBUG_ERROR, "%a: Controller initialization fail for Controller %d with Status - %r.\n", __FUNCTION__, Controller, Status )); NvmeFreeDmaResource (Private); Controller++; continue; } // // Enumerate the NVME namespaces on the controller // Status = NvmeDiscoverNamespaces (Private); if (EFI_ERROR (Status)) { // // No active namespace was found on the controller // DEBUG (( DEBUG_ERROR, "%a: Namespaces discovery fail for Controller %d with Status - %r.\n", __FUNCTION__, Controller, Status )); NvmeFreeDmaResource (Private); Controller++; continue; } Private->BlkIoPpi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo; Private->BlkIoPpi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo; Private->BlkIoPpi.ReadBlocks = NvmeBlockIoPeimReadBlocks; CopyMem ( &Private->BlkIoPpiList, &mNvmeBlkIoPpiListTemplate, sizeof (EFI_PEI_PPI_DESCRIPTOR) ); Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi; Private->BlkIo2Ppi.Revision = EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION; Private->BlkIo2Ppi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo2; Private->BlkIo2Ppi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo2; Private->BlkIo2Ppi.ReadBlocks = NvmeBlockIoPeimReadBlocks2; CopyMem ( &Private->BlkIo2PpiList, &mNvmeBlkIo2PpiListTemplate, sizeof (EFI_PEI_PPI_DESCRIPTOR) ); Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi; PeiServicesInstallPpi (&Private->BlkIoPpiList); // // Check if the NVME controller supports the Security Receive/Send commands // if ((Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED) != 0) { DEBUG (( DEBUG_INFO, "%a: Security Security Command PPI will be produced for Controller %d.\n", __FUNCTION__, Controller )); Private->StorageSecurityPpi.Revision = EDKII_STORAGE_SECURITY_PPI_REVISION; Private->StorageSecurityPpi.GetNumberofDevices = NvmeStorageSecurityGetDeviceNo; Private->StorageSecurityPpi.GetDevicePath = NvmeStorageSecurityGetDevicePath; Private->StorageSecurityPpi.ReceiveData = NvmeStorageSecurityReceiveData; Private->StorageSecurityPpi.SendData = NvmeStorageSecuritySendData; CopyMem ( &Private->StorageSecurityPpiList, &mNvmeStorageSecurityPpiListTemplate, sizeof (EFI_PEI_PPI_DESCRIPTOR) ); Private->StorageSecurityPpiList.Ppi = &Private->StorageSecurityPpi; PeiServicesInstallPpi (&Private->StorageSecurityPpiList); } CopyMem ( &Private->EndOfPeiNotifyList, &mNvmeEndOfPeiNotifyListTemplate, sizeof (EFI_PEI_NOTIFY_DESCRIPTOR) ); PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList); DEBUG (( DEBUG_INFO, "%a: Controller %d has been successfully initialized.\n", __FUNCTION__, Controller )); Controller++; } return EFI_SUCCESS; }