/** Write to a given location in the PCI configuration space. @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation. @param This Pointer to local data for the interface. @param Width The width of the access. Enumerated in bytes. See EFI_PEI_PCI_CFG_PPI_WIDTH above. @param Address The physical address of the access. The format of the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS. @param Buffer A pointer to the buffer of data. @retval EFI_SUCCESS The function completed successfully. @retval EFI_INVALID_PARAMETER The invalid access width. **/ EFI_STATUS EFIAPI PciCfg2Write ( IN CONST EFI_PEI_SERVICES **PeiServices, IN CONST EFI_PEI_PCI_CFG2_PPI *This, IN EFI_PEI_PCI_CFG_PPI_WIDTH Width, IN UINT64 Address, IN OUT VOID *Buffer ) { UINTN PciLibAddress; PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address); if (Width == EfiPeiPciCfgWidthUint8) { PciWrite8 (PciLibAddress, *((UINT8 *) Buffer)); } else if (Width == EfiPeiPciCfgWidthUint16) { if ((PciLibAddress & 0x01) == 0) { // // Aligned Pci address access // PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *) Buffer)); } else { // // Unaligned Pci address access, break up the request into byte by byte. // PciWrite8 (PciLibAddress, *((UINT8 *) Buffer)); PciWrite8 (PciLibAddress + 1, *((UINT8 *) Buffer + 1)); } } else if (Width == EfiPeiPciCfgWidthUint32) { if ((PciLibAddress & 0x03) == 0) { // // Aligned Pci address access // PciWrite32 (PciLibAddress, ReadUnaligned32 ((UINT32 *) Buffer)); } else if ((PciLibAddress & 0x01) == 0) { // // Unaligned Pci address access, break up the request into word by word. // PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *) Buffer)); PciWrite16 (PciLibAddress + 2, ReadUnaligned16 ((UINT16 *) Buffer + 1)); } else { // // Unaligned Pci address access, break up the request into byte by byte. // PciWrite8 (PciLibAddress, *((UINT8 *) Buffer)); PciWrite8 (PciLibAddress + 1, *((UINT8 *) Buffer + 1)); PciWrite8 (PciLibAddress + 2, *((UINT8 *) Buffer + 2)); PciWrite8 (PciLibAddress + 3, *((UINT8 *) Buffer + 3)); } } else { return EFI_INVALID_PARAMETER; } return EFI_SUCCESS; }
/** Retrieves an 16-bit value for a given PCD token. Retrieves the current 16-bits value for a PCD token number. If the TokenNumber is invalid, the results are unpredictable. @param[in] TokenNumber The PCD token number. @return The UINT16 value. **/ UINT16 EFIAPI DxePcdGet16 ( IN UINTN TokenNumber ) { return ReadUnaligned16 (GetWorker (TokenNumber, sizeof (UINT16))); }
/** Returns the 16-bit Length field of a device path node. Returns the 16-bit Length field of the device path node specified by Node. Node is not required to be aligned on a 16-bit boundary, so it is recommended that a function such as ReadUnaligned16() be used to extract the contents of the Length field. If Node is NULL, then ASSERT(). @param Node A pointer to a device path node data structure. @return The 16-bit Length field of the device path node specified by Node. **/ UINTN EFIAPI DevicePathNodeLength ( IN CONST VOID *Node ) { ASSERT (Node != NULL); return ReadUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0]); }
/** Retrieves an 16-bit value for a given PCD token. Retrieves the 16-bit value of a particular PCD token. If the TokenNumber is invalid or the token space specified by Guid does not exist, the results are unpredictable. @param[in] Guid The token space for the token number. @param[in] ExTokenNumber The PCD token number. @return The size 16-bit value for the PCD token. **/ UINT16 EFIAPI DxePcdGet16Ex ( IN CONST EFI_GUID *Guid, IN UINTN ExTokenNumber ) { return ReadUnaligned16 (ExGetWorker (Guid, ExTokenNumber, sizeof(UINT16))); }
/** Writes memory-mapped registers. @param[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation. @param[in] This Pointer to local data for the interface. @param[in] Width The width of the access. Enumerated in bytes. @param[in] Address The physical address of the access. @param[in] Count The number of accesses to perform. @param[in] Buffer A pointer to the buffer of data. @retval EFI_SUCCESS The function completed successfully. @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. @retval EFI_INVALID_PARAMETER Buffer is NULL. @retval EFI_UNSUPPORTED The address range specified by Address, Width, and Count is not valid for this EFI system. **/ EFI_STATUS EFIAPI CpuMemoryServiceWrite ( IN CONST EFI_PEI_SERVICES **PeiServices, IN CONST EFI_PEI_CPU_IO_PPI *This, IN EFI_PEI_CPU_IO_PPI_WIDTH Width, IN UINT64 Address, IN UINTN Count, IN VOID *Buffer ) { EFI_STATUS Status; UINT8 InStride; UINT8 OutStride; EFI_PEI_CPU_IO_PPI_WIDTH OperationWidth; BOOLEAN Aligned; UINT8 *Uint8Buffer; Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer); if (EFI_ERROR (Status)) { return Status; } // // Select loop based on the width of the transfer // InStride = mInStride[Width]; OutStride = mOutStride[Width]; OperationWidth = (EFI_PEI_CPU_IO_PPI_WIDTH) (Width & 0x03); Aligned = (BOOLEAN)(((UINTN)Buffer & (mInStride[OperationWidth] - 1)) == 0x00); for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { if (OperationWidth == EfiPeiCpuIoWidthUint8) { MmioWrite8 ((UINTN)Address, *Uint8Buffer); } else if (OperationWidth == EfiPeiCpuIoWidthUint16) { if (Aligned) { MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer)); } else { MmioWrite16 ((UINTN)Address, ReadUnaligned16 ((UINT16 *)Uint8Buffer)); } } else if (OperationWidth == EfiPeiCpuIoWidthUint32) { if (Aligned) { MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer)); } else { MmioWrite32 ((UINTN)Address, ReadUnaligned32 ((UINT32 *)Uint8Buffer)); } } else if (OperationWidth == EfiPeiCpuIoWidthUint64) { if (Aligned) { MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer)); } else { MmioWrite64 ((UINTN)Address, ReadUnaligned64 ((UINT64 *)Uint8Buffer)); } } } return EFI_SUCCESS; }
/** Returns the 16-bit Length field of a device path node. Returns the 16-bit Length field of the device path node specified by Node. Node is not required to be aligned on a 16-bit boundary, so it is recommended that a function such as ReadUnaligned16() be used to extract the contents of the Length field. If Node is NULL, then ASSERT(). @param Node A pointer to a device path node data structure. @return The 16-bit Length field of the device path node specified by Node. **/ UINTN EFIAPI DevicePathNodeLength ( IN CONST VOID *Node ) { UINTN Length; ASSERT (Node != NULL); Length = ReadUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0]); ASSERT (Length >= sizeof (EFI_DEVICE_PATH_PROTOCOL)); return Length; }
/** Validate the Boot####, Driver####, SysPrep#### variable (VendorGuid/Name) @param Variable The variable data. @param VariableSize The variable size. @retval TRUE The variable data is correct. @retval FALSE The variable data is corrupted. **/ BOOLEAN BmValidateOption ( UINT8 *Variable, UINTN VariableSize ) { UINT16 FilePathSize; EFI_DEVICE_PATH_PROTOCOL *DevicePath; UINTN DescriptionSize; if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) { return FALSE; } // // Skip the option attribute // Variable += sizeof (UINT32); // // Get the option's device path size // FilePathSize = ReadUnaligned16 ((UINT16 *) Variable); Variable += sizeof (UINT16); // // Get the option's description string size // DescriptionSize = BmStrSizeEx ((CHAR16 *) Variable, VariableSize - sizeof (UINT16) - sizeof (UINT32)); Variable += DescriptionSize; // // Get the option's device path // DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Variable; // // Validation boot option variable. // if ((FilePathSize == 0) || (DescriptionSize == 0)) { return FALSE; } if (sizeof (UINT32) + sizeof (UINT16) + DescriptionSize + FilePathSize > VariableSize) { return FALSE; } return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0); }
/** This function performs a read-modify-write operation on the contents from a given location in the PCI configuration space. @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation. @param This Pointer to local data for the interface. @param Width The width of the access. Enumerated in bytes. Type EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read(). @param Address The physical address of the access. @param SetBits Points to value to bitwise-OR with the read configuration value. The size of the value is determined by Width. @param ClearBits Points to the value to negate and bitwise-AND with the read configuration value. The size of the value is determined by Width. @retval EFI_SUCCESS The function completed successfully. @retval EFI_INVALID_PARAMETER The invalid access width. **/ EFI_STATUS EFIAPI PciCfg2Modify ( IN CONST EFI_PEI_SERVICES **PeiServices, IN CONST EFI_PEI_PCI_CFG2_PPI *This, IN EFI_PEI_PCI_CFG_PPI_WIDTH Width, IN UINT64 Address, IN VOID *SetBits, IN VOID *ClearBits ) { UINTN PciLibAddress; UINT16 ClearValue16; UINT16 SetValue16; UINT32 ClearValue32; UINT32 SetValue32; PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address); if (Width == EfiPeiPciCfgWidthUint8) { PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits)); } else if (Width == EfiPeiPciCfgWidthUint16) { if ((PciLibAddress & 0x01) == 0) { // // Aligned Pci address access // ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits)); SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits); PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16); } else { // // Unaligned Pci address access, break up the request into byte by byte. // PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits)); PciAndThenOr8 (PciLibAddress + 1, (UINT8) (~(*((UINT8 *) ClearBits + 1))), *((UINT8 *) SetBits + 1)); } } else if (Width == EfiPeiPciCfgWidthUint32) { if ((PciLibAddress & 0x03) == 0) { // // Aligned Pci address access // ClearValue32 = (UINT32) (~ReadUnaligned32 ((UINT32 *) ClearBits)); SetValue32 = ReadUnaligned32 ((UINT32 *) SetBits); PciAndThenOr32 (PciLibAddress, ClearValue32, SetValue32); } else if ((PciLibAddress & 0x01) == 0) { // // Unaligned Pci address access, break up the request into word by word. // ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits)); SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits); PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16); ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits + 1)); SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits + 1); PciAndThenOr16 (PciLibAddress + 2, ClearValue16, SetValue16); } else { // // Unaligned Pci address access, break up the request into byte by byte. // PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits)); PciAndThenOr8 (PciLibAddress + 1, (UINT8) (~(*((UINT8 *) ClearBits + 1))), *((UINT8 *) SetBits + 1)); PciAndThenOr8 (PciLibAddress + 2, (UINT8) (~(*((UINT8 *) ClearBits + 2))), *((UINT8 *) SetBits + 2)); PciAndThenOr8 (PciLibAddress + 3, (UINT8) (~(*((UINT8 *) ClearBits + 3))), *((UINT8 *) SetBits + 3)); } } else { return EFI_INVALID_PARAMETER; } return EFI_SUCCESS; }
EFI_STATUS BootOptionStart ( IN BDS_LOAD_OPTION *BootOption ) { EFI_STATUS Status; EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL* EfiDevicePathFromTextProtocol; UINT32 LoaderType; ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData; ARM_BDS_LINUX_ARGUMENTS* LinuxArguments; EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath; EFI_DEVICE_PATH_PROTOCOL* DefaultFdtDevicePath; UINTN FdtDevicePathSize; UINTN CmdLineSize; UINTN InitrdSize; EFI_DEVICE_PATH* Initrd; UINT16 LoadOptionIndexSize; if (IS_ARM_BDS_BOOTENTRY (BootOption)) { Status = EFI_UNSUPPORTED; OptionalData = BootOption->OptionalData; LoaderType = ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType); if (LoaderType == BDS_LOADER_EFI_APPLICATION) { if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_APP) { // Need to connect every drivers to ensure no dependencies are missing for the application BdsConnectAllDrivers (); } Status = BdsStartEfiApplication (gImageHandle, BootOption->FilePathList, 0, NULL); } else if (LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) { LinuxArguments = &(OptionalData->Arguments.LinuxArguments); CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize); InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize); if (InitrdSize > 0) { Initrd = GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize)); } else { Initrd = NULL; } Status = BdsBootLinuxAtag (BootOption->FilePathList, Initrd, // Initrd (CHAR8*)(LinuxArguments + 1)); // CmdLine } else if (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT) { LinuxArguments = &(OptionalData->Arguments.LinuxArguments); CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize); InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize); if (InitrdSize > 0) { Initrd = GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize)); } else { Initrd = NULL; } // Get the default FDT device path Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol); ASSERT_EFI_ERROR(Status); DefaultFdtDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdFdtDevicePath)); // Get the FDT device path FdtDevicePathSize = GetDevicePathSize (DefaultFdtDevicePath); Status = GetEnvironmentVariable ((CHAR16 *)L"Fdt", &gArmGlobalVariableGuid, DefaultFdtDevicePath, &FdtDevicePathSize, (VOID **)&FdtDevicePath); ASSERT_EFI_ERROR(Status); Status = BdsBootLinuxFdt (BootOption->FilePathList, Initrd, // Initrd (CHAR8*)(LinuxArguments + 1), FdtDevicePath); FreePool (DefaultFdtDevicePath); FreePool (FdtDevicePath); } } else { // Connect all the drivers if the EFI Application is not a EFI OS Loader if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_APP) { BdsConnectAllDrivers (); } // Set BootCurrent variable LoadOptionIndexSize = sizeof(UINT16); gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, LoadOptionIndexSize, &(BootOption->LoadOptionIndex)); Status = BdsStartEfiApplication (gImageHandle, BootOption->FilePathList, BootOption->OptionalDataSize, BootOption->OptionalData); // Clear BootCurrent variable LoadOptionIndexSize = sizeof(UINT16); gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL); } return Status; }
/** This service enables the sending of commands to the TPM12. @param[in] InputParameterBlockSize Size of the TPM12 input parameter block. @param[in] InputParameterBlock Pointer to the TPM12 input parameter block. @param[in,out] OutputParameterBlockSize Size of the TPM12 output parameter block. @param[in] OutputParameterBlock Pointer to the TPM12 output parameter block. @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. **/ EFI_STATUS EFIAPI Tpm12SubmitCommand ( IN UINT32 InputParameterBlockSize, IN UINT8 *InputParameterBlock, IN OUT UINT32 *OutputParameterBlockSize, IN UINT8 *OutputParameterBlock ) { EFI_STATUS Status; UINT32 TpmOutSize; TPM_RSP_COMMAND_HDR *ResponseHeader; UINT64 Current; UINT64 Previous; UINT64 Total; UINT64 Start; UINT64 End; UINT64 Timeout; INT64 Cycle; INT64 Delta; // // Make sure response buffer is big enough to hold a response header // if (*OutputParameterBlockSize < sizeof (TPM_RSP_COMMAND_HDR)) { Status = EFI_BUFFER_TOO_SMALL; goto Done; } // // Get the current timer value // Current = GetPerformanceCounter(); // // Initialize local variables // Start = 0; End = 0; Total = 0; // // Retrieve the performance counter properties and compute the number of // performance counter ticks required to reach the maximum TIS timeout of // TIS_TIMEOUT_A. TIS_TIMEOUT_A is in microseconds. // Timeout = DivU64x32 ( MultU64x32 ( GetPerformanceCounterProperties (&Start, &End), TIS_TIMEOUT_A ), 1000000 ); Cycle = End - Start; if (Cycle < 0) { Cycle = -Cycle; } Cycle++; // // Send command // do { Status = WriteTpmBufferMultiple (InputParameterBlock, InputParameterBlockSize); Previous = Current; Current = GetPerformanceCounter(); Delta = (INT64) (Current - Previous); if (Start > End) { Delta = -Delta; } if (Delta < 0) { Delta += Cycle; } Total += Delta; if (Total >= Timeout) { Status = EFI_TIMEOUT; goto Done; } } while (EFI_ERROR (Status)); // // Receive response header // do { Status = ReadTpmBufferMultiple (OutputParameterBlock, sizeof (TPM_RSP_COMMAND_HDR)); Previous = Current; Current = GetPerformanceCounter(); Delta = (INT64) (Current - Previous); if (Start > End) { Delta = -Delta; } if (Delta < 0) { Delta += Cycle; } Total += Delta; if (Total >= Timeout) { Status = EFI_TIMEOUT; goto Done; } } while (EFI_ERROR (Status)); // // Check the response data header (tag, parasize and returncode) // ResponseHeader = (TPM_RSP_COMMAND_HDR *)OutputParameterBlock; if (SwapBytes16 (ReadUnaligned16 (&ResponseHeader->tag)) != TPM_TAG_RSP_COMMAND) { Status = EFI_DEVICE_ERROR; goto Done; } TpmOutSize = SwapBytes32 (ReadUnaligned32 (&ResponseHeader->paramSize)); if (TpmOutSize == sizeof (TPM_RSP_COMMAND_HDR)) { Status = EFI_SUCCESS; goto Done; } if (TpmOutSize < sizeof (TPM_RSP_COMMAND_HDR)) { Status = EFI_DEVICE_ERROR; goto Done; } if (*OutputParameterBlockSize < TpmOutSize) { Status = EFI_BUFFER_TOO_SMALL; goto Done; } *OutputParameterBlockSize = TpmOutSize; // // Receive the remaining data in the response header // do { Status = ReadTpmBufferMultiple ( OutputParameterBlock + sizeof (TPM_RSP_COMMAND_HDR), TpmOutSize - sizeof (TPM_RSP_COMMAND_HDR) ); Previous = Current; Current = GetPerformanceCounter(); Delta = (INT64) (Current - Previous); if (Start > End) { Delta = -Delta; } if (Delta < 0) { Delta += Cycle; } Total += Delta; if (Total >= Timeout) { Status = EFI_TIMEOUT; goto Done; } } while (EFI_ERROR (Status)); Done: DEBUG (( EFI_D_VERBOSE, "Tpm12SubmitCommand() Status = %r Time = %ld ms\n", Status, DivU64x64Remainder ( MultU64x32 (Total, 1000), GetPerformanceCounterProperties (NULL, NULL), NULL ) )); return Status; }
/** This command is used to read the public area and Name of an NV Index. @param[in] NvIndex The NV Index. @param[out] NvPublic The public area of the index. @param[out] NvName The Name of the nvIndex. @retval EFI_SUCCESS Operation completed successfully. @retval EFI_DEVICE_ERROR The command was unsuccessful. @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found. **/ EFI_STATUS EFIAPI Tpm2NvReadPublic ( IN TPMI_RH_NV_INDEX NvIndex, OUT TPM2B_NV_PUBLIC *NvPublic, OUT TPM2B_NAME *NvName ) { EFI_STATUS Status; TPM2_NV_READPUBLIC_COMMAND SendBuffer; TPM2_NV_READPUBLIC_RESPONSE RecvBuffer; UINT32 SendBufferSize; UINT32 RecvBufferSize; UINT16 NvPublicSize; UINT16 NvNameSize; UINT8 *Buffer; TPM_RC ResponseCode; // // Construct command // SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_ReadPublic); SendBuffer.NvIndex = SwapBytes32 (NvIndex); SendBufferSize = (UINT32) sizeof (SendBuffer); SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); // // send Tpm command // RecvBufferSize = sizeof (RecvBuffer); Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); if (EFI_ERROR (Status)) { return Status; } if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { DEBUG ((EFI_D_ERROR, "Tpm2NvReadPublic - RecvBufferSize Error - %x\n", RecvBufferSize)); return EFI_DEVICE_ERROR; } ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode); if (ResponseCode != TPM_RC_SUCCESS) { DEBUG ((EFI_D_ERROR, "Tpm2NvReadPublic - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); } switch (ResponseCode) { case TPM_RC_SUCCESS: // return data break; case TPM_RC_HANDLE + RC_NV_ReadPublic_nvIndex: // TPM_RC_NV_DEFINED: return EFI_NOT_FOUND; case TPM_RC_VALUE + RC_NV_ReadPublic_nvIndex: return EFI_INVALID_PARAMETER; default: return EFI_DEVICE_ERROR; } if (RecvBufferSize <= sizeof (TPM2_RESPONSE_HEADER) + sizeof (UINT16) + sizeof(UINT16)) { DEBUG ((EFI_D_ERROR, "Tpm2NvReadPublic - RecvBufferSize Error - %x\n", RecvBufferSize)); return EFI_NOT_FOUND; } // // Basic check // NvPublicSize = SwapBytes16 (RecvBuffer.NvPublic.size); if (NvPublicSize > sizeof(TPMS_NV_PUBLIC)) { DEBUG ((DEBUG_ERROR, "Tpm2NvReadPublic - NvPublic.size error %x\n", NvPublicSize)); return EFI_DEVICE_ERROR; } NvNameSize = SwapBytes16 (ReadUnaligned16 ((UINT16 *)((UINT8 *)&RecvBuffer + sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + NvPublicSize))); if (NvNameSize > sizeof(TPMU_NAME)){ DEBUG ((DEBUG_ERROR, "Tpm2NvReadPublic - NvNameSize error %x\n", NvNameSize)); return EFI_DEVICE_ERROR; } if (RecvBufferSize != sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + NvPublicSize + sizeof(UINT16) + NvNameSize) { DEBUG ((EFI_D_ERROR, "Tpm2NvReadPublic - RecvBufferSize Error - NvPublicSize %x\n", RecvBufferSize)); return EFI_NOT_FOUND; } // // Return the response // CopyMem (NvPublic, &RecvBuffer.NvPublic, sizeof(UINT16) + NvPublicSize); NvPublic->size = NvPublicSize; NvPublic->nvPublic.nvIndex = SwapBytes32 (NvPublic->nvPublic.nvIndex); NvPublic->nvPublic.nameAlg = SwapBytes16 (NvPublic->nvPublic.nameAlg); WriteUnaligned32 ((UINT32 *)&NvPublic->nvPublic.attributes, SwapBytes32 (ReadUnaligned32 ((UINT32 *)&NvPublic->nvPublic.attributes))); NvPublic->nvPublic.authPolicy.size = SwapBytes16 (NvPublic->nvPublic.authPolicy.size); Buffer = (UINT8 *)&RecvBuffer.NvPublic.nvPublic.authPolicy; Buffer += sizeof(UINT16) + NvPublic->nvPublic.authPolicy.size; NvPublic->nvPublic.dataSize = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); CopyMem (NvName->name, (UINT8 *)&RecvBuffer + sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + NvPublicSize + sizeof(UINT16), NvNameSize); NvName->size = NvNameSize; return EFI_SUCCESS; }
/** This command is used to cause an update to the indicated PCR. The data in eventData is hashed using the hash algorithm associated with each bank in which the indicated PCR has been allocated. After the data is hashed, the digests list is returned. If the pcrHandle references an implemented PCR and not TPM_ALG_NULL, digests list is processed as in TPM2_PCR_Extend(). A TPM shall support an Event.size of zero through 1,024 inclusive. @param[in] PcrHandle Handle of the PCR @param[in] EventData Event data in sized buffer @param[out] Digests List of digest @retval EFI_SUCCESS Operation completed successfully. @retval EFI_DEVICE_ERROR Unexpected device behavior. **/ EFI_STATUS EFIAPI Tpm2PcrEvent ( IN TPMI_DH_PCR PcrHandle, IN TPM2B_EVENT *EventData, OUT TPML_DIGEST_VALUES *Digests ) { EFI_STATUS Status; TPM2_PCR_EVENT_COMMAND Cmd; TPM2_PCR_EVENT_RESPONSE Res; UINT32 CmdSize; UINT32 RespSize; UINT32 ResultBufSize; UINT8 *Buffer; UINTN Index; UINT32 SessionInfoSize; UINT16 DigestSize; Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS); Cmd.Header.commandCode = SwapBytes32(TPM_CC_PCR_Event); Cmd.PcrHandle = SwapBytes32(PcrHandle); // // Add in Auth session // Buffer = (UINT8 *)&Cmd.AuthSessionPcr; // sessionInfoSize SessionInfoSize = CopyAuthSessionCommand (NULL, Buffer); Buffer += SessionInfoSize; Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize); // Event WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(EventData->size)); Buffer += sizeof(UINT16); CopyMem (Buffer, EventData->buffer, EventData->size); Buffer += EventData->size; CmdSize = (UINT32)((UINTN)Buffer - (UINTN)&Cmd); Cmd.Header.paramSize = SwapBytes32(CmdSize); ResultBufSize = sizeof(Res); Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); if (EFI_ERROR(Status)) { return Status; } if (ResultBufSize > sizeof(Res)) { DEBUG ((EFI_D_ERROR, "Tpm2PcrEvent: Failed ExecuteCommand: Buffer Too Small\r\n")); return EFI_BUFFER_TOO_SMALL; } // // Validate response headers // RespSize = SwapBytes32(Res.Header.paramSize); if (RespSize > sizeof(Res)) { DEBUG ((EFI_D_ERROR, "Tpm2PcrEvent: Response size too large! %d\r\n", RespSize)); return EFI_BUFFER_TOO_SMALL; } // // Fail if command failed // if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { DEBUG ((EFI_D_ERROR, "Tpm2PcrEvent: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); return EFI_DEVICE_ERROR; } // // Unmarshal the response // Buffer = (UINT8 *)&Res.Digests; Digests->count = SwapBytes32 (ReadUnaligned32 ((UINT32 *)Buffer)); Buffer += sizeof(UINT32); for (Index = 0; Index < Digests->count; Index++) { Digests->digests[Index].hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); Buffer += sizeof(UINT16); DigestSize = GetHashSizeFromAlgo (Digests->digests[Index].hashAlg); if (DigestSize == 0) { DEBUG ((EFI_D_ERROR, "Unknown hash algorithm %d\r\n", Digests->digests[Index].hashAlg)); return EFI_DEVICE_ERROR; } CopyMem( &Digests->digests[Index].digest, Buffer, DigestSize ); Buffer += DigestSize; } return EFI_SUCCESS; }
/** Build the Boot#### or Driver#### option from the VariableName. @param VariableName Variable name of the load option @param VendorGuid Variable GUID of the load option @param Option Return the load option. @retval EFI_SUCCESS Get the option just been created @retval EFI_NOT_FOUND Failed to get the new option **/ EFI_STATUS EFIAPI EfiBootManagerVariableToLoadOptionEx ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option ) { EFI_STATUS Status; UINT32 Attribute; UINT16 FilePathSize; UINT8 *Variable; UINT8 *VariablePtr; UINTN VariableSize; EFI_DEVICE_PATH_PROTOCOL *FilePath; UINT8 *OptionalData; UINT32 OptionalDataSize; CHAR16 *Description; EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType; UINT16 OptionNumber; if ((VariableName == NULL) || (Option == NULL)) { return EFI_INVALID_PARAMETER; } if (!BmIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) { return EFI_INVALID_PARAMETER; } // // Read the variable // GetVariable2 (VariableName, VendorGuid, (VOID **) &Variable, &VariableSize); if (Variable == NULL) { return EFI_NOT_FOUND; } // // Validate *#### variable data. // if (!BmValidateOption(Variable, VariableSize)) { FreePool (Variable); return EFI_INVALID_PARAMETER; } // // Get the option attribute // VariablePtr = Variable; Attribute = ReadUnaligned32 ((UINT32 *) VariablePtr); VariablePtr += sizeof (UINT32); // // Get the option's device path size // FilePathSize = ReadUnaligned16 ((UINT16 *) VariablePtr); VariablePtr += sizeof (UINT16); // // Get the option's description string // Description = (CHAR16 *) VariablePtr; // // Get the option's description string size // VariablePtr += StrSize ((CHAR16 *) VariablePtr); // // Get the option's device path // FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr; VariablePtr += FilePathSize; OptionalDataSize = (UINT32) (VariableSize - (UINTN) (VariablePtr - Variable)); if (OptionalDataSize == 0) { OptionalData = NULL; } else { OptionalData = VariablePtr; } Status = EfiBootManagerInitializeLoadOption ( Option, OptionNumber, OptionType, Attribute, Description, FilePath, OptionalData, OptionalDataSize ); ASSERT_EFI_ERROR (Status); CopyGuid (&Option->VendorGuid, VendorGuid); FreePool (Variable); return Status; }
/** This command includes a secret-based authorization to a policy. The caller proves knowledge of the secret value using an authorization session using the authValue associated with authHandle. @param[in] AuthHandle Handle for an entity providing the authorization @param[in] PolicySession Handle for the policy session being extended. @param[in] AuthSession Auth Session context @param[in] NonceTPM The policy nonce for the session. @param[in] CpHashA Digest of the command parameters to which this authorization is limited. @param[in] PolicyRef A reference to a policy relating to the authorization. @param[in] Expiration Time when authorization will expire, measured in seconds from the time that nonceTPM was generated. @param[out] Timeout Time value used to indicate to the TPM when the ticket expires. @param[out] PolicyTicket A ticket that includes a value indicating when the authorization expires. @retval EFI_SUCCESS Operation completed successfully. @retval EFI_DEVICE_ERROR The command was unsuccessful. **/ EFI_STATUS EFIAPI Tpm2PolicySecret ( IN TPMI_DH_ENTITY AuthHandle, IN TPMI_SH_POLICY PolicySession, IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL IN TPM2B_NONCE *NonceTPM, IN TPM2B_DIGEST *CpHashA, IN TPM2B_NONCE *PolicyRef, IN INT32 Expiration, OUT TPM2B_TIMEOUT *Timeout, OUT TPMT_TK_AUTH *PolicyTicket ) { EFI_STATUS Status; TPM2_POLICY_SECRET_COMMAND SendBuffer; TPM2_POLICY_SECRET_RESPONSE RecvBuffer; UINT32 SendBufferSize; UINT32 RecvBufferSize; UINT8 *Buffer; UINT32 SessionInfoSize; // // Construct command // SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS); SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_PolicySecret); SendBuffer.AuthHandle = SwapBytes32 (AuthHandle); SendBuffer.PolicySession = SwapBytes32 (PolicySession); // // Add in Auth session // Buffer = (UINT8 *)&SendBuffer.AuthSession; // sessionInfoSize SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); Buffer += SessionInfoSize; SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize); // // Real data // WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(NonceTPM->size)); Buffer += sizeof(UINT16); CopyMem (Buffer, NonceTPM->buffer, NonceTPM->size); Buffer += NonceTPM->size; WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(CpHashA->size)); Buffer += sizeof(UINT16); CopyMem (Buffer, CpHashA->buffer, CpHashA->size); Buffer += CpHashA->size; WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(PolicyRef->size)); Buffer += sizeof(UINT16); CopyMem (Buffer, PolicyRef->buffer, PolicyRef->size); Buffer += PolicyRef->size; WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32((UINT32)Expiration)); Buffer += sizeof(UINT32); SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer); SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); // // send Tpm command // RecvBufferSize = sizeof (RecvBuffer); Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); if (EFI_ERROR (Status)) { goto Done; } if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { DEBUG ((EFI_D_ERROR, "Tpm2PolicySecret - RecvBufferSize Error - %x\n", RecvBufferSize)); Status = EFI_DEVICE_ERROR; goto Done; } if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { DEBUG ((EFI_D_ERROR, "Tpm2PolicySecret - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); Status = EFI_DEVICE_ERROR; goto Done; } // // Return the response // Buffer = (UINT8 *)&RecvBuffer.Timeout; Timeout->size = SwapBytes16(ReadUnaligned16 ((UINT16 *)Buffer)); if (Timeout->size > sizeof(UINT64)) { DEBUG ((DEBUG_ERROR, "Tpm2PolicySecret - Timeout->size error %x\n", Timeout->size)); Status = EFI_DEVICE_ERROR; goto Done; } Buffer += sizeof(UINT16); CopyMem (Timeout->buffer, Buffer, Timeout->size); PolicyTicket->tag = SwapBytes16(ReadUnaligned16 ((UINT16 *)Buffer)); Buffer += sizeof(UINT16); PolicyTicket->hierarchy = SwapBytes32(ReadUnaligned32 ((UINT32 *)Buffer)); Buffer += sizeof(UINT32); PolicyTicket->digest.size = SwapBytes16(ReadUnaligned16 ((UINT16 *)Buffer)); Buffer += sizeof(UINT16); if (PolicyTicket->digest.size > sizeof(TPMU_HA)) { DEBUG ((DEBUG_ERROR, "Tpm2PolicySecret - digest.size error %x\n", PolicyTicket->digest.size)); Status = EFI_DEVICE_ERROR; goto Done; } CopyMem (PolicyTicket->digest.buffer, Buffer, PolicyTicket->digest.size); Done: // // Clear AuthSession Content // ZeroMem (&SendBuffer, sizeof(SendBuffer)); ZeroMem (&RecvBuffer, sizeof(RecvBuffer)); return Status; }
/** Receive response data of last command from TPM. @param[out] TpmBuffer Buffer for response data. @param[out] RespSize Response data length. @retval EFI_SUCCESS Operation completed successfully. @retval EFI_TIMEOUT The register can't run into the expected status in time. @retval EFI_DEVICE_ERROR Unexpected device status. @retval EFI_BUFFER_TOO_SMALL Response data is too long. **/ EFI_STATUS TisPcReceive ( OUT UINT8 *TpmBuffer, OUT UINT32 *RespSize ) { EFI_STATUS Status; UINT16 BurstCount; UINT32 Index; UINT32 ResponseSize; TPM_RSP_COMMAND_HDR *ResponseHeader; // // Wait for the command completion // Status = TisPcWaitRegisterBits ( INFINEON_TPM_STS_0_ADDRESS_DEFAULT, (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA), 0, TIS_TIMEOUT_B ); if (EFI_ERROR (Status)) { Status = EFI_TIMEOUT; goto Done; } // // Read the response data header and check it // Index = 0; BurstCount = 0; while (Index < sizeof (TPM_RSP_COMMAND_HDR)) { Status = TisPcReadBurstCount (&BurstCount); if (EFI_ERROR (Status)) { Status = EFI_TIMEOUT; goto Done; } for (; BurstCount > 0 ; BurstCount--) { *(TpmBuffer + Index) = TpmReadByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT); Index++; if (Index == sizeof (TPM_RSP_COMMAND_HDR)) break; } } // // Check the response data header (tag, parasize and returncode) // ResponseHeader = (TPM_RSP_COMMAND_HDR *)TpmBuffer; if (SwapBytes16 (ReadUnaligned16 (&ResponseHeader->tag)) != TPM_TAG_RSP_COMMAND) { Status = EFI_DEVICE_ERROR; goto Done; } ResponseSize = SwapBytes32 (ReadUnaligned32 (&ResponseHeader->paramSize)); if (ResponseSize == sizeof (TPM_RSP_COMMAND_HDR)) { Status = EFI_SUCCESS; goto Done; } if (ResponseSize < sizeof (TPM_RSP_COMMAND_HDR)) { Status = EFI_DEVICE_ERROR; goto Done; } if (*RespSize < ResponseSize) { Status = EFI_BUFFER_TOO_SMALL; goto Done; } *RespSize = ResponseSize; // // Continue reading the remaining data // while (Index < ResponseSize) { for (; BurstCount > 0 ; BurstCount--) { *(TpmBuffer + Index) = TpmReadByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT); Index++; if (Index == ResponseSize) { Status = EFI_SUCCESS; goto Done; } } Status = TisPcReadBurstCount (&BurstCount); if (EFI_ERROR (Status) && (Index < ResponseSize)) { Status = EFI_DEVICE_ERROR; goto Done; } } Done: // // Ensure the TPM state change from "Execution" or "Completion" to "Idle/Ready" // TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_READY); return Status; }
/** Write I/O registers. @param[in] PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation. @param[in] This Pointer to local data for the interface. @param[in] Width The width of the access. Enumerated in bytes. @param[in] Address The physical address of the access. @param[in] Count The number of accesses to perform. @param[in] Buffer A pointer to the buffer of data. @retval EFI_SUCCESS The function completed successfully. @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. @retval EFI_INVALID_PARAMETER Buffer is NULL. @retval EFI_UNSUPPORTED The address range specified by Address, Width, and Count is not valid for this EFI system. **/ EFI_STATUS EFIAPI CpuIoServiceWrite ( IN CONST EFI_PEI_SERVICES **PeiServices, IN CONST EFI_PEI_CPU_IO_PPI *This, IN EFI_PEI_CPU_IO_PPI_WIDTH Width, IN UINT64 Address, IN UINTN Count, IN VOID *Buffer ) { EFI_STATUS Status; UINT8 InStride; UINT8 OutStride; EFI_PEI_CPU_IO_PPI_WIDTH OperationWidth; BOOLEAN Aligned; UINT8 *Uint8Buffer; // // Make sure the parameters are valid // Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer); if (EFI_ERROR (Status)) { return Status; } // // Select loop based on the width of the transfer // InStride = mInStride[Width]; OutStride = mOutStride[Width]; OperationWidth = (EFI_PEI_CPU_IO_PPI_WIDTH) (Width & 0x03); // // Fifo operations supported for (mInStride[Width] == 0) // if (InStride == 0) { switch (OperationWidth) { case EfiPeiCpuIoWidthUint8: IoWriteFifo8 ((UINTN)Address, Count, Buffer); return EFI_SUCCESS; case EfiPeiCpuIoWidthUint16: IoWriteFifo16 ((UINTN)Address, Count, Buffer); return EFI_SUCCESS; case EfiPeiCpuIoWidthUint32: IoWriteFifo32 ((UINTN)Address, Count, Buffer); return EFI_SUCCESS; default: // // The CpuIoCheckParameter call above will ensure that this // path is not taken. // ASSERT (FALSE); break; } } Aligned = (BOOLEAN)(((UINTN)Buffer & (mInStride[OperationWidth] - 1)) == 0x00); for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { if (OperationWidth == EfiPeiCpuIoWidthUint8) { IoWrite8 ((UINTN)Address, *Uint8Buffer); } else if (OperationWidth == EfiPeiCpuIoWidthUint16) { if (Aligned) { IoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer)); } else { IoWrite16 ((UINTN)Address, ReadUnaligned16 ((UINT16 *)Uint8Buffer)); } } else if (OperationWidth == EfiPeiCpuIoWidthUint32) { if (Aligned) { IoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer)); } else { IoWrite32 ((UINTN)Address, ReadUnaligned32 ((UINT32 *)Uint8Buffer)); } } } return EFI_SUCCESS; }
EFI_STATUS BootMenuUpdateBootOption ( IN LIST_ENTRY *BootOptionsList ) { EFI_STATUS Status; BDS_LOAD_OPTION_ENTRY *BootOptionEntry; BDS_LOAD_OPTION *BootOption; BDS_LOAD_OPTION_SUPPORT* DeviceSupport; ARM_BDS_LOADER_ARGUMENTS* BootArguments; CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX]; CHAR8 CmdLine[BOOT_DEVICE_OPTION_MAX]; CHAR16 UnicodeCmdLine[BOOT_DEVICE_OPTION_MAX]; EFI_DEVICE_PATH *DevicePath; EFI_DEVICE_PATH *TempInitrdPath; ARM_BDS_LOADER_TYPE BootType; ARM_BDS_LOADER_OPTIONAL_DATA* LoaderOptionalData; ARM_BDS_LINUX_ARGUMENTS* LinuxArguments; EFI_DEVICE_PATH *InitrdPathNodes; EFI_DEVICE_PATH *InitrdPath; UINTN InitrdSize; UINTN CmdLineSize; BOOLEAN InitrdSupport; UINT8* OptionalData; UINTN OptionalDataSize; BOOLEAN IsPrintable; BOOLEAN IsUnicode; DisplayBootOptions (BootOptionsList); Status = SelectBootOption (BootOptionsList, UPDATE_BOOT_ENTRY, &BootOptionEntry); if (EFI_ERROR (Status)) { return Status; } BootOption = BootOptionEntry->BdsLoadOption; // Get the device support for this Boot Option Status = BootDeviceGetDeviceSupport (BootOption->FilePathList, &DeviceSupport); if (EFI_ERROR(Status)) { Print(L"Not possible to retrieve the supported device for the update\n"); return EFI_UNSUPPORTED; } Status = DeviceSupport->UpdateDevicePathNode (BootOption->FilePathList, L"EFI Application or the kernel", &DevicePath); if (EFI_ERROR(Status)) { Status = EFI_ABORTED; goto EXIT; } if (DeviceSupport->RequestBootType) { Status = BootDeviceGetType (DevicePath, &BootType, &BootOption->Attributes); if (EFI_ERROR(Status)) { Status = EFI_ABORTED; goto EXIT; } } LoaderOptionalData = BootOption->OptionalData; if (LoaderOptionalData != NULL) { BootType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((UINT32 *)(&LoaderOptionalData->Header.LoaderType)); } else { BootType = BDS_LOADER_EFI_APPLICATION; } if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) { LinuxArguments = &LoaderOptionalData->Arguments.LinuxArguments; CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize); InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize); if (InitrdSize > 0) { Print(L"Keep the initrd: "); } else { Print(L"Add an initrd: "); } Status = GetHIInputBoolean (&InitrdSupport); if (EFI_ERROR(Status)) { Status = EFI_ABORTED; goto EXIT; } if (InitrdSupport) { if (InitrdSize > 0) { // Case we update the initrd device path Status = DeviceSupport->UpdateDevicePathNode ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize), L"initrd", &InitrdPath); if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) {// EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd Status = EFI_ABORTED; goto EXIT; } InitrdSize = GetDevicePathSize (InitrdPath); } else { // Case we create the initrd device path Status = DeviceSupport->CreateDevicePathNode (L"initrd", &InitrdPathNodes); if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd Status = EFI_ABORTED; goto EXIT; } if (InitrdPathNodes != NULL) { // Duplicate Linux kernel Device Path TempInitrdPath = DuplicateDevicePath (BootOption->FilePathList); // Replace Linux kernel Node by EndNode SetDevicePathEndNode (GetLastDevicePathNode (TempInitrdPath)); // Append the Device Path to the selected device path InitrdPath = AppendDevicePath (TempInitrdPath, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNodes); FreePool (TempInitrdPath); // Free the InitrdPathNodes created by Support->CreateDevicePathNode() FreePool (InitrdPathNodes); if (InitrdPath == NULL) { Status = EFI_OUT_OF_RESOURCES; goto EXIT; } InitrdSize = GetDevicePathSize (InitrdPath); } else { InitrdPath = NULL; } } } else { InitrdSize = 0; } Print(L"Arguments to pass to the binary: "); if (CmdLineSize > 0) { AsciiStrnCpy (CmdLine, (CONST CHAR8*)(LinuxArguments + 1), sizeof (CmdLine)); CmdLine[sizeof (CmdLine) - 1] = '\0'; } else { CmdLine[0] = '\0'; } Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX); if (EFI_ERROR(Status)) { Status = EFI_ABORTED; goto FREE_DEVICE_PATH; } CmdLineSize = AsciiStrSize (CmdLine); OptionalDataSize = sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize; BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool (OptionalDataSize); BootArguments->LinuxArguments.CmdLineSize = CmdLineSize; BootArguments->LinuxArguments.InitrdSize = InitrdSize; CopyMem (&BootArguments->LinuxArguments + 1, CmdLine, CmdLineSize); CopyMem ((VOID*)((UINTN)(&BootArguments->LinuxArguments + 1) + CmdLineSize), InitrdPath, InitrdSize); OptionalData = (UINT8*)BootArguments; } else { Print (L"Arguments to pass to the EFI Application: "); if (BootOption->OptionalDataSize > 0) { IsPrintable = IsPrintableString (BootOption->OptionalData, &IsUnicode); if (IsPrintable) { // // The size in bytes of the string, final zero included, should // be equal to or at least lower than "BootOption->OptionalDataSize" // and the "IsPrintableString()" has already tested that the length // in number of characters is smaller than BOOT_DEVICE_OPTION_MAX, // final '\0' included. We can thus copy the string for editing // using "CopyMem()". Furthermore, note that in the case of an Unicode // string "StrnCpy()" and "StrCpy()" can not be used to copy the // string because the data pointed to by "BootOption->OptionalData" // is not necessarily 2-byte aligned. // if (IsUnicode) { CopyMem ( UnicodeCmdLine, BootOption->OptionalData, MIN (sizeof (UnicodeCmdLine), BootOption->OptionalDataSize) ); } else { CopyMem ( CmdLine, BootOption->OptionalData, MIN (sizeof (CmdLine), BootOption->OptionalDataSize) ); } } } else { UnicodeCmdLine[0] = L'\0'; IsPrintable = TRUE; IsUnicode = TRUE; } // We do not request arguments for OptionalData that cannot be printed if (IsPrintable) { if (IsUnicode) { Status = EditHIInputStr (UnicodeCmdLine, BOOT_DEVICE_OPTION_MAX); if (EFI_ERROR (Status)) { Status = EFI_ABORTED; goto FREE_DEVICE_PATH; } OptionalData = (UINT8*)UnicodeCmdLine; OptionalDataSize = StrSize (UnicodeCmdLine); } else { Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX); if (EFI_ERROR (Status)) { Status = EFI_ABORTED; goto FREE_DEVICE_PATH; } OptionalData = (UINT8*)CmdLine; OptionalDataSize = AsciiStrSize (CmdLine); } } else { // We keep the former OptionalData OptionalData = BootOption->OptionalData; OptionalDataSize = BootOption->OptionalDataSize; } } Print(L"Description for this new Entry: "); StrnCpy (BootDescription, BootOption->Description, BOOT_DEVICE_DESCRIPTION_MAX); Status = EditHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX); if (EFI_ERROR(Status)) { Status = EFI_ABORTED; goto FREE_DEVICE_PATH; } // Update the entry Status = BootOptionUpdate (BootOption, BootOption->Attributes, BootDescription, DevicePath, BootType, OptionalData, OptionalDataSize); FREE_DEVICE_PATH: FreePool (DevicePath); EXIT: if (Status == EFI_ABORTED) { Print(L"\n"); } return Status; }
/** Copies the data in a caller supplied buffer to a specified range of PCI configuration space. Writes the range of PCI configuration registers specified by StartAddress and Size from the buffer specified by Buffer. This function only allows the PCI configuration registers from a single PCI function to be written. Size is returned. When possible 32-bit PCI configuration write cycles are used to write from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit and 16-bit PCI configuration write cycles may be used at the beginning and the end of the range. If StartAddress > 0x0FFFFFFF, then ASSERT(). If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT(). If Size > 0 and Buffer is NULL, then ASSERT(). @param StartAddress The starting address that encodes the PCI Bus, Device, Function and Register. @param Size The size in bytes of the transfer. @param Buffer The pointer to a buffer containing the data to write. @return Size written to StartAddress. **/ UINTN EFIAPI PciWriteBuffer ( IN UINTN StartAddress, IN UINTN Size, IN VOID *Buffer ) { UINTN ReturnValue; ASSERT_INVALID_PCI_ADDRESS (StartAddress, 0); ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000); if (Size == 0) { return 0; } ASSERT (Buffer != NULL); // // Save Size for return // ReturnValue = Size; if ((StartAddress & BIT0) != 0) { // // Write a byte if StartAddress is byte aligned // PciWrite8 (StartAddress, *(UINT8*)Buffer); StartAddress += sizeof (UINT8); Size -= sizeof (UINT8); Buffer = (UINT8*)Buffer + 1; } if (Size >= sizeof (UINT16) && (StartAddress & BIT1) != 0) { // // Write a word if StartAddress is word aligned // PciWrite16 (StartAddress, ReadUnaligned16 (Buffer)); StartAddress += sizeof (UINT16); Size -= sizeof (UINT16); Buffer = (UINT16*)Buffer + 1; } while (Size >= sizeof (UINT32)) { // // Write as many double words as possible // PciWrite32 (StartAddress, ReadUnaligned32 (Buffer)); StartAddress += sizeof (UINT32); Size -= sizeof (UINT32); Buffer = (UINT32*)Buffer + 1; } if (Size >= sizeof (UINT16)) { // // Write the last remaining word if exist // PciWrite16 (StartAddress, ReadUnaligned16 (Buffer)); StartAddress += sizeof (UINT16); Size -= sizeof (UINT16); Buffer = (UINT16*)Buffer + 1; } if (Size >= sizeof (UINT8)) { // // Write the last remaining byte if exist // PciWrite8 (StartAddress, *(UINT8*)Buffer); } return ReturnValue; }
EFI_STATUS BootMenuMain ( VOID ) { LIST_ENTRY BootOptionsList; UINTN OptionCount; UINTN BootOptionCount; EFI_STATUS Status; LIST_ENTRY* Entry; BDS_LOAD_OPTION* BootOption; UINTN BootOptionSelected; UINTN Index; UINTN BootMainEntryCount; BOOLEAN IsUnicode; BootOption = NULL; BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY); while (TRUE) { // Get Boot#### list BootOptionList (&BootOptionsList); OptionCount = 1; // Display the Boot options for (Entry = GetFirstNode (&BootOptionsList); !IsNull (&BootOptionsList,Entry); Entry = GetNextNode (&BootOptionsList,Entry) ) { BootOption = LOAD_OPTION_FROM_LINK(Entry); Print(L"[%d] %s\n", OptionCount, BootOption->Description); DEBUG_CODE_BEGIN(); CHAR16* DevicePathTxt; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData; UINTN CmdLineSize; ARM_BDS_LOADER_TYPE LoaderType; Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); if (EFI_ERROR(Status)) { // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe) DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathToTextProtocol\n")); return Status; } DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootOption->FilePathList, TRUE, TRUE); Print(L"\t- %s\n",DevicePathTxt); // If it is a supported BootEntry then print its details if (IS_ARM_BDS_BOOTENTRY (BootOption)) { OptionalData = BootOption->OptionalData; LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType); if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT)) { if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.InitrdSize) > 0) { CmdLineSize = ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize); DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText ( GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(&OptionalData->Arguments.LinuxArguments + 1) + CmdLineSize)), TRUE, TRUE); Print(L"\t- Initrd: %s\n", DevicePathTxt); } if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize) > 0) { Print(L"\t- Arguments: %a\n", (&OptionalData->Arguments.LinuxArguments + 1)); } } switch (LoaderType) { case BDS_LOADER_EFI_APPLICATION: Print(L"\t- LoaderType: EFI Application\n"); break; case BDS_LOADER_KERNEL_LINUX_ATAG: Print(L"\t- LoaderType: Linux kernel with ATAG support\n"); break; case BDS_LOADER_KERNEL_LINUX_FDT: Print(L"\t- LoaderType: Linux kernel with FDT support\n"); break; default: Print(L"\t- LoaderType: Not recognized (%d)\n", LoaderType); } } else if (BootOption->OptionalData != NULL) { if (IsPrintableString (BootOption->OptionalData, &IsUnicode)) { if (IsUnicode) { Print (L"\t- Arguments: %s\n", BootOption->OptionalData); } else { AsciiPrint ("\t- Arguments: %a\n", BootOption->OptionalData); } } } FreePool(DevicePathTxt); DEBUG_CODE_END(); OptionCount++; } BootOptionCount = OptionCount-1; // Display the hardcoded Boot entries for (Index = 0; Index < BootMainEntryCount; Index++) { Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]); OptionCount++; } // Request the boot entry from the user BootOptionSelected = 0; while (BootOptionSelected == 0) { Print(L"Start: "); Status = GetHIInputInteger (&BootOptionSelected); if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) { Print(L"Invalid input (max %d)\n",(OptionCount-1)); BootOptionSelected = 0; } } // Start the selected entry if (BootOptionSelected > BootOptionCount) { // Start the hardcoded entry Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList); } else { // Find the selected entry from the Boot#### list Index = 1; for (Entry = GetFirstNode (&BootOptionsList); !IsNull (&BootOptionsList,Entry); Entry = GetNextNode (&BootOptionsList,Entry) ) { if (Index == BootOptionSelected) { BootOption = LOAD_OPTION_FROM_LINK(Entry); break; } Index++; } Status = BootOptionStart (BootOption); } } // Should never go here }
/** Get file name from device path. The file name may contain one or more device path node. Save the file name in a buffer if file name is found. The caller is responsible to free the buffer. @param[in] DevicePath A pointer to a device path. @param[out] FileName The callee allocated buffer to save the file name if file name is found. @param[out] FileNameOffset The offset of file name in device path if file name is found. @retval UINTN The file name length. 0 means file name is not found. **/ UINTN GetFileName ( IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, OUT UINT8 **FileName, OUT UINTN *FileNameOffset ) { UINTN Length; EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath; EFI_DEVICE_PATH_PROTOCOL *RootDevicePath; CHAR8 *NodeStr; UINTN NodeStrLength; CHAR16 LastNodeChar; CHAR16 FirstNodeChar; // // Get the length of DevicePath before file name. // Length = 0; RootDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath; while (!IsDevicePathEnd (RootDevicePath)) { if ((DevicePathType(RootDevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType(RootDevicePath) == MEDIA_FILEPATH_DP)) { break; } Length += DevicePathNodeLength (RootDevicePath); RootDevicePath = NextDevicePathNode (RootDevicePath); } *FileNameOffset = Length; if (Length == 0) { return 0; } // // Get the file name length. // Length = 0; TmpDevicePath = RootDevicePath; while (!IsDevicePathEnd (TmpDevicePath)) { if ((DevicePathType(TmpDevicePath) != MEDIA_DEVICE_PATH) || (DevicePathSubType(TmpDevicePath) != MEDIA_FILEPATH_DP)) { break; } Length += DevicePathNodeLength (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); TmpDevicePath = NextDevicePathNode (TmpDevicePath); } if (Length == 0) { return 0; } *FileName = AllocateZeroPool (Length); ASSERT (*FileName != NULL); // // Copy the file name to the buffer. // Length = 0; LastNodeChar = '\\'; TmpDevicePath = RootDevicePath; while (!IsDevicePathEnd (TmpDevicePath)) { if ((DevicePathType(TmpDevicePath) != MEDIA_DEVICE_PATH) || (DevicePathSubType(TmpDevicePath) != MEDIA_FILEPATH_DP)) { break; } FirstNodeChar = (CHAR16) ReadUnaligned16 ((UINT16 *)((UINT8 *)TmpDevicePath + sizeof (EFI_DEVICE_PATH_PROTOCOL))); NodeStr = (CHAR8 *)TmpDevicePath + sizeof (EFI_DEVICE_PATH_PROTOCOL); NodeStrLength = DevicePathNodeLength (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL) - sizeof(CHAR16); if ((FirstNodeChar == '\\') && (LastNodeChar == '\\')) { // // Skip separator "\" when there are two separators. // NodeStr += sizeof (CHAR16); NodeStrLength -= sizeof (CHAR16); } else if ((FirstNodeChar != '\\') && (LastNodeChar != '\\')) { // // Add separator "\" when there is no separator. // WriteUnaligned16 ((UINT16 *)(*FileName + Length), '\\'); Length += sizeof (CHAR16); } CopyMem (*FileName + Length, NodeStr, NodeStrLength); Length += NodeStrLength; LastNodeChar = (CHAR16) ReadUnaligned16 ((UINT16 *) (NodeStr + NodeStrLength - sizeof(CHAR16))); TmpDevicePath = NextDevicePathNode (TmpDevicePath); } return Length; }
EFI_STATUS BootOptionStart ( IN BDS_LOAD_OPTION *BootOption ) { EFI_STATUS Status; UINT32 LoaderType; ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData; ARM_BDS_LINUX_ARGUMENTS* LinuxArguments; UINTN CmdLineSize; UINTN InitrdSize; EFI_DEVICE_PATH* Initrd; UINT16 LoadOptionIndexSize; if (IS_ARM_BDS_BOOTENTRY (BootOption)) { Status = EFI_UNSUPPORTED; OptionalData = BootOption->OptionalData; LoaderType = ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType); if (LoaderType == BDS_LOADER_EFI_APPLICATION) { if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_APP) { // Need to connect every drivers to ensure no dependencies are missing for the application BdsConnectAllDrivers (); } Status = BdsStartEfiApplication (gImageHandle, BootOption->FilePathList, 0, NULL); } else if (LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) { LinuxArguments = &(OptionalData->Arguments.LinuxArguments); CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize); InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize); if (InitrdSize > 0) { Initrd = GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize)); } else { Initrd = NULL; } Status = BdsBootLinuxAtag (BootOption->FilePathList, Initrd, // Initrd (CHAR8*)(LinuxArguments + 1)); // CmdLine } else if (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT) { LinuxArguments = &(OptionalData->Arguments.LinuxArguments); CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize); InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize); if (InitrdSize > 0) { Initrd = GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize)); } else { Initrd = NULL; } Status = BdsBootLinuxFdt ( BootOption->FilePathList, Initrd, (CHAR8*)(LinuxArguments + 1) ); } } else { // Connect all the drivers if the EFI Application is not a EFI OS Loader if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_APP) { BdsConnectAllDrivers (); } // Set BootCurrent variable LoadOptionIndexSize = sizeof(UINT16); gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, LoadOptionIndexSize, &(BootOption->LoadOptionIndex)); Status = BdsStartEfiApplication (gImageHandle, BootOption->FilePathList, BootOption->OptionalDataSize, BootOption->OptionalData); // Clear BootCurrent variable LoadOptionIndexSize = sizeof(UINT16); gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL); } return Status; }