* RuntimeDXE unable to save variables to flash @ 2018-10-04 10:56 Hristo Mihaylov 2018-10-04 17:00 ` Laszlo Ersek 0 siblings, 1 reply; 5+ messages in thread From: Hristo Mihaylov @ 2018-10-04 10:56 UTC (permalink / raw) To: edk2-devel@lists.01.org Hello, I have an issue that I don't know how to fix. I'm building a BIOS for a custom x86_64 platform. The first part of the problem is: the BIOS boots to the end of DXE where it crashes with a General Protection exception. ``` !!!! X64 Exception Type - 0D(#GP - General Protection) CPU Apic ID - 00000027 !!!! RIP - 0000000077ADE823, CS - 0000000000000038, RFLAGS - 0000000000010047 ExceptionData - 0000000000000000 RAX - 00000000FFFFFFFF, RCX - 00000000000001FE, RDX - 0000000000000000 RBX - 00000000FFFFFFFF, RSP - 0000000075B443C0, RBP - 00000000800FD000 RSI - 0000000000000001, RDI - 0000000077AFC520 R8 - 0000000077AFC618, R9 - 0000000000000001, R10 - 0000000070000000 R11 - 00000000758B7F10, R12 - 0000000077AFC510, R13 - 0000000000000001 R14 - 0000000080000000, R15 - 0000000002C30064 DS - 0000000000000020, ES - 0000000000000020, FS - 0000000000000020 GS - 0000000000000020, SS - 0000000000000020 CR0 - 0000000080000033, CR2 - 0000000000000000, CR3 - 0000000075977000 CR4 - 0000000000000668, CR8 - 0000000000000000 DR0 - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000 DR3 - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400 GDTR - 0000000075986928 000000000000004F, LDTR - 0000000000000000 IDTR - 0000000077ACF400 00000000000001FF, TR - 0000000000000040 FXSAVE_STATE - 0000000075B44020 ``` This exception occurs when the BIOS is enabling or disabling the write protection of the SPI. It only crashes when it's doing the protection in SMM. The code responsible for that is: ``` EFI_STATUS EFIAPI DisableBiosWriteProtect ( VOID ) { UINTN SpiBaseAddress; UINT32 Data32; SpiBaseAddress = MmPciBase ( DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_SPI, PCI_FUNCTION_NUMBER_PCH_SPI ); // Write clear BC_SYNC_SS prior to change WPD from 0 to 1. // MmioOr8 ( SpiBaseAddress + R_PCH_SPI_BC + 1, (B_PCH_SPI_BC_SYNC_SS >> 8) ); /// /// Set BIOSWE bit (SPI PCI Offset DCh [0]) = 1b /// Enable the access to the BIOS space for both read and write cycles /// MmioOr8 ( SpiBaseAddress + R_PCH_SPI_BC, B_PCH_SPI_BC_WPD ); /// /// PCH BIOS Spec Section 3.7 BIOS Region SMM Protection Enabling /// If the following steps are implemented: /// - Set the EISS bit (SPI PCI Offset DCh [5]) = 1b /// - Follow the 1st recommendation in section 3.6 /// the BIOS Region can only be updated by following the steps bellow: /// - Once all threads enter SMM /// - Read memory location FED30880h OR with 00000001h, place the result in EAX, /// and write data to lower 32 bits of MSR 1FEh (sample code available) /// - Set BIOSWE bit (SPI PCI Offset DCh [0]) = 1b /// - Modify BIOS Region /// - Clear BIOSWE bit (SPI PCI Offset DCh [0]) = 0b /// if ((MmioRead8 (SpiBaseAddress + R_PCH_SPI_BC) & B_PCH_SPI_BC_EISS) != 0) { /// /// Read memory location FED30880h OR with 00000001h, place the result in EAX, /// and write data to lower 32 bits of MSR 1FEh (sample code available) /// Data32 = MmioRead32 ((UINTN) (0xFED30880)) | BIT0; // crash occurs here AsmWriteMsr32 (0x1FE, Data32); } return EFI_SUCCESS; } VOID EFIAPI EnableBiosWriteProtect ( VOID ) { UINTN SpiBaseAddress; UINT32 Data32; SpiBaseAddress = MmPciBase ( DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_SPI, PCI_FUNCTION_NUMBER_PCH_SPI ); /// /// Clear BIOSWE bit (SPI PCI Offset DCh [0]) = 0b /// Disable the access to the BIOS space for write cycles /// MmioAnd8 ( SpiBaseAddress + R_PCH_SPI_BC, (UINT8) (~B_PCH_SPI_BC_WPD) ); /// /// Check if EISS bit is set /// if (((MmioRead8 (SpiBaseAddress + R_PCH_SPI_BC)) & B_PCH_SPI_BC_EISS) == B_PCH_SPI_BC_EISS) { /// /// Read memory location FED30880h AND with FFFFFFFEh, place the result in EAX, /// and write data to lower 32 bits of MSR 1FEh (sample code available) /// Data32 = MmioRead32 ((UINTN) (0xFED30880)) & (~BIT0); // crash occurs here //AsmWriteMsr32 (0x1FE, Data32); } } ``` I can work around the crash by hardcoding the values 0x0 and 0x1, or commenting out the writes. The second part is that variables cannot be saved or updated: ``` Variable driver flush the HOB variable to flash: {guid} TCG2_CONFIGURATION Invalid Parameter Variable driver flush the HOB variable to flash: {guid} Setup Invalid Parameter Variable driver flush the HOB variable to flash: {guid} PchRcConfiguration Invalid Parameter Variable driver flush the HOB variable to flash: {guid} MeRcConfiguration Invalid Parameter Variable driver flush the HOB variable to flash: {guid} IeRcConfiguration Invalid Parameter Variable driver flush the HOB variable to flash: {guid} SocketIioConfig Invalid Parameter Variable driver flush the HOB variable to flash: {guid} SocketCommonRcConfig Invalid Parameter Variable driver flush the HOB variable to flash: {guid} SocketMpLinkConfig Invalid Parameter Variable driver flush the HOB variable to flash: {guid} SocketMemoryConfig Invalid Parameter Variable driver flush the HOB variable to flash: {guid} SocketPowerManagementConfig Invalid Parameter Variable driver flush the HOB variable to flash: {guid} SocketProcessorCoreConfig Invalid Parameter Variable driver flush the HOB variable to flash: {guid} FpgaSocketConfig Invalid Parameter ``` I can't save variables to non-volatile storage, I can save some to volatile storage, but others I cannot save at all. I tracked the failure down to here: https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c#L338 and I'm not sure how to proceed. The platform is based on UDK2015. Any advice? --- Regards, Hristo Mihaylov ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: RuntimeDXE unable to save variables to flash 2018-10-04 10:56 RuntimeDXE unable to save variables to flash Hristo Mihaylov @ 2018-10-04 17:00 ` Laszlo Ersek 2018-10-09 10:25 ` Hristo Mihaylov 0 siblings, 1 reply; 5+ messages in thread From: Laszlo Ersek @ 2018-10-04 17:00 UTC (permalink / raw) To: Hristo Mihaylov, edk2-devel@lists.01.org On 10/04/18 12:56, Hristo Mihaylov wrote: > Hello, > > I have an issue that I don't know how to fix. I'm building a BIOS for a custom > x86_64 platform. > > The first part of the problem is: the BIOS boots to the end of DXE where > it crashes with a General Protection exception. > > ``` > !!!! X64 Exception Type - 0D(#GP - General Protection) CPU Apic ID - 00000027 !!!! > RIP - 0000000077ADE823, CS - 0000000000000038, RFLAGS - 0000000000010047 > ExceptionData - 0000000000000000 > RAX - 00000000FFFFFFFF, RCX - 00000000000001FE, RDX - 0000000000000000 > RBX - 00000000FFFFFFFF, RSP - 0000000075B443C0, RBP - 00000000800FD000 > RSI - 0000000000000001, RDI - 0000000077AFC520 > R8 - 0000000077AFC618, R9 - 0000000000000001, R10 - 0000000070000000 > R11 - 00000000758B7F10, R12 - 0000000077AFC510, R13 - 0000000000000001 > R14 - 0000000080000000, R15 - 0000000002C30064 > DS - 0000000000000020, ES - 0000000000000020, FS - 0000000000000020 > GS - 0000000000000020, SS - 0000000000000020 > CR0 - 0000000080000033, CR2 - 0000000000000000, CR3 - 0000000075977000 > CR4 - 0000000000000668, CR8 - 0000000000000000 > DR0 - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000 > DR3 - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400 > GDTR - 0000000075986928 000000000000004F, LDTR - 0000000000000000 > IDTR - 0000000077ACF400 00000000000001FF, TR - 0000000000000040 > FXSAVE_STATE - 0000000075B44020 > ``` > > This exception occurs when the BIOS is enabling or disabling the write > protection of the SPI. It only crashes when it's doing the protection in SMM. > The code responsible for that is: > > ``` > EFI_STATUS > EFIAPI > DisableBiosWriteProtect ( > VOID > ) > { > UINTN SpiBaseAddress; > UINT32 Data32; > > SpiBaseAddress = MmPciBase ( > DEFAULT_PCI_BUS_NUMBER_PCH, > PCI_DEVICE_NUMBER_PCH_SPI, > PCI_FUNCTION_NUMBER_PCH_SPI > ); > // Write clear BC_SYNC_SS prior to change WPD from 0 to 1. > // > MmioOr8 ( > SpiBaseAddress + R_PCH_SPI_BC + 1, > (B_PCH_SPI_BC_SYNC_SS >> 8) > ); > /// > /// Set BIOSWE bit (SPI PCI Offset DCh [0]) = 1b > /// Enable the access to the BIOS space for both read and write cycles > /// > MmioOr8 ( > SpiBaseAddress + R_PCH_SPI_BC, > B_PCH_SPI_BC_WPD > ); > /// > /// PCH BIOS Spec Section 3.7 BIOS Region SMM Protection Enabling > /// If the following steps are implemented: > /// - Set the EISS bit (SPI PCI Offset DCh [5]) = 1b > /// - Follow the 1st recommendation in section 3.6 > /// the BIOS Region can only be updated by following the steps bellow: > /// - Once all threads enter SMM > /// - Read memory location FED30880h OR with 00000001h, place the result in EAX, > /// and write data to lower 32 bits of MSR 1FEh (sample code available) > /// - Set BIOSWE bit (SPI PCI Offset DCh [0]) = 1b > /// - Modify BIOS Region > /// - Clear BIOSWE bit (SPI PCI Offset DCh [0]) = 0b > /// > if ((MmioRead8 (SpiBaseAddress + R_PCH_SPI_BC) & B_PCH_SPI_BC_EISS) != 0) { > /// > /// Read memory location FED30880h OR with 00000001h, place the result in EAX, > /// and write data to lower 32 bits of MSR 1FEh (sample code available) > /// > Data32 = MmioRead32 ((UINTN) (0xFED30880)) | BIT0; > > // crash occurs here > AsmWriteMsr32 (0x1FE, Data32); > } > > return EFI_SUCCESS; > } > > VOID > EFIAPI > EnableBiosWriteProtect ( > VOID > ) > { > UINTN SpiBaseAddress; > UINT32 Data32; > > SpiBaseAddress = MmPciBase ( > DEFAULT_PCI_BUS_NUMBER_PCH, > PCI_DEVICE_NUMBER_PCH_SPI, > PCI_FUNCTION_NUMBER_PCH_SPI > ); > /// > /// Clear BIOSWE bit (SPI PCI Offset DCh [0]) = 0b > /// Disable the access to the BIOS space for write cycles > /// > MmioAnd8 ( > SpiBaseAddress + R_PCH_SPI_BC, > (UINT8) (~B_PCH_SPI_BC_WPD) > ); > > /// > /// Check if EISS bit is set > /// > if (((MmioRead8 (SpiBaseAddress + R_PCH_SPI_BC)) & B_PCH_SPI_BC_EISS) == B_PCH_SPI_BC_EISS) { > /// > /// Read memory location FED30880h AND with FFFFFFFEh, place the result in EAX, > /// and write data to lower 32 bits of MSR 1FEh (sample code available) > /// > Data32 = MmioRead32 ((UINTN) (0xFED30880)) & (~BIT0); > > // crash occurs here > //AsmWriteMsr32 (0x1FE, Data32); > } > } > ``` > > I can work around the crash by hardcoding the values 0x0 and 0x1, or commenting out the writes. Accessing invalid MSRs may raise injections. How do you know the MSR 0x1FE is valid (and the Data32 value is valid)? > > The second part is that variables cannot be saved or updated: > > ``` > Variable driver flush the HOB variable to flash: {guid} TCG2_CONFIGURATION Invalid Parameter > Variable driver flush the HOB variable to flash: {guid} Setup Invalid Parameter > Variable driver flush the HOB variable to flash: {guid} PchRcConfiguration Invalid Parameter > Variable driver flush the HOB variable to flash: {guid} MeRcConfiguration Invalid Parameter > Variable driver flush the HOB variable to flash: {guid} IeRcConfiguration Invalid Parameter > Variable driver flush the HOB variable to flash: {guid} SocketIioConfig Invalid Parameter > Variable driver flush the HOB variable to flash: {guid} SocketCommonRcConfig Invalid Parameter > Variable driver flush the HOB variable to flash: {guid} SocketMpLinkConfig Invalid Parameter > Variable driver flush the HOB variable to flash: {guid} SocketMemoryConfig Invalid Parameter > Variable driver flush the HOB variable to flash: {guid} SocketPowerManagementConfig Invalid Parameter > Variable driver flush the HOB variable to flash: {guid} SocketProcessorCoreConfig Invalid Parameter > Variable driver flush the HOB variable to flash: {guid} FpgaSocketConfig Invalid Parameter > ``` > > I can't save variables to non-volatile storage, I can save some to volatile > storage, but others I cannot save at all. > > I tracked the failure down to here: https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c#L338 > and I'm not sure how to proceed. The platform is based on UDK2015. That's an Fvb->Write() call. Do you have access to the source of the flash driver (which produces the FVB protocol instance)? (FWIW, EFI_INVALID_PARAMETER doesn't seem a spec-compliant return value for EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL.Write()). Thanks Laszlo ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: RuntimeDXE unable to save variables to flash 2018-10-04 17:00 ` Laszlo Ersek @ 2018-10-09 10:25 ` Hristo Mihaylov 2018-10-09 10:49 ` Laszlo Ersek 0 siblings, 1 reply; 5+ messages in thread From: Hristo Mihaylov @ 2018-10-09 10:25 UTC (permalink / raw) To: Laszlo Ersek, edk2-devel@lists.01.org Thanks Laszlo, > Accessing invalid MSRs may raise injections. How do you know the MSR 0x1FE is valid (and the Data32 value is valid)? I'll investigate this further. > That's an Fvb->Write() call. Do you have access to the source of the flash driver (which produces the FVB protocol instance)? Yes, I found that the writing is done in a function called SendSpiCmd, here's the signature (I can't disclose the full source). ``` /** This function sends the programmed SPI command to the slave device. @param[in] This Pointer to the PCH_SPI_PROTOCOL instance. @param[in] SpiRegionType The SPI Region type for flash cycle which is listed in the Descriptor @param[in] FlashCycleType The Flash SPI cycle type list in HSFC (Hardware Sequencing Flash Control Register) register @param[in] Address The Flash Linear Address must fall within a region for which BIOS has access permissions. @param[in] ByteCount Number of bytes in the data portion of the SPI cycle. @param[in,out] Buffer Pointer to caller-allocated buffer containing the dada received or sent during the SPI cycle. @retval EFI_SUCCESS SPI command completes successfully. @retval EFI_DEVICE_ERROR Device error, the command aborts abnormally. @retval EFI_ACCESS_DENIED Some unrecognized command encountered in hardware sequencing mode @retval EFI_INVALID_PARAMETER The parameters specified are not valid. **/ EFI_STATUS SendSpiCmd ( IN EFI_SPI_PROTOCOL *This, IN FLASH_REGION_TYPE FlashRegionType, IN FLASH_CYCLE_TYPE FlashCycleType, IN UINT32 Address, IN UINT32 ByteCount, IN OUT UINT8 *Buffer ) ``` It fails when it does a sanity check. It checks `if (Address + ByteCount) > FlashRegionSize`. The FlashRegionSize seems to be estimated correctly, because it's used to write other values to that region, which succeed. When I log the sanity check like for the incorrect value I see: `SendSpiCmd: (46334052 + 60 = 46334112) > 20971520` the address seems to be way off. The Address is calculated in FvbGetLbaAddress. Almost a 1 to 1 copy of https://github.com/tianocore/edk2/blob/75b7aa9528bdd05a7ecf4e64a6beb478d31b402c/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c#L237 I thought that the issue is either because of invalid FV block or the size of the flash region is calculated incorrectly, but this only happens in SMM. Now I'm leaning more towards permissions. Any advice? Regards, Hristo Mihaylov -----Original Message----- From: Laszlo Ersek [mailto:lersek@redhat.com] Sent: 04 October 2018 19:00 To: Hristo Mihaylov <hristo.mihaylov@prodrive-technologies.com>; edk2-devel@lists.01.org Subject: Re: [edk2] RuntimeDXE unable to save variables to flash On 10/04/18 12:56, Hristo Mihaylov wrote: > Hello, > > I have an issue that I don't know how to fix. I'm building a BIOS for > a custom > x86_64 platform. > > The first part of the problem is: the BIOS boots to the end of DXE > where it crashes with a General Protection exception. > > ``` > !!!! X64 Exception Type - 0D(#GP - General Protection) CPU Apic ID - 00000027 !!!! > RIP - 0000000077ADE823, CS - 0000000000000038, RFLAGS - > 0000000000010047 ExceptionData - 0000000000000000 RAX - > 00000000FFFFFFFF, RCX - 00000000000001FE, RDX - 0000000000000000 RBX > - 00000000FFFFFFFF, RSP - 0000000075B443C0, RBP - 00000000800FD000 RSI > - 0000000000000001, RDI - 0000000077AFC520 > R8 - 0000000077AFC618, R9 - 0000000000000001, R10 - 0000000070000000 > R11 - 00000000758B7F10, R12 - 0000000077AFC510, R13 - > 0000000000000001 > R14 - 0000000080000000, R15 - 0000000002C30064 > DS - 0000000000000020, ES - 0000000000000020, FS - 0000000000000020 > GS - 0000000000000020, SS - 0000000000000020 > CR0 - 0000000080000033, CR2 - 0000000000000000, CR3 - > 0000000075977000 > CR4 - 0000000000000668, CR8 - 0000000000000000 > DR0 - 0000000000000000, DR1 - 0000000000000000, DR2 - > 0000000000000000 > DR3 - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - > 0000000000000400 GDTR - 0000000075986928 000000000000004F, LDTR - 0000000000000000 > IDTR - 0000000077ACF400 00000000000001FF, TR - 0000000000000040 > FXSAVE_STATE - 0000000075B44020 > ``` > > This exception occurs when the BIOS is enabling or disabling the write > protection of the SPI. It only crashes when it's doing the protection in SMM. > The code responsible for that is: > > ``` > EFI_STATUS > EFIAPI > DisableBiosWriteProtect ( > VOID > ) > { > UINTN SpiBaseAddress; > UINT32 Data32; > > SpiBaseAddress = MmPciBase ( > DEFAULT_PCI_BUS_NUMBER_PCH, > PCI_DEVICE_NUMBER_PCH_SPI, > PCI_FUNCTION_NUMBER_PCH_SPI > ); > // Write clear BC_SYNC_SS prior to change WPD from 0 to 1. > // > MmioOr8 ( > SpiBaseAddress + R_PCH_SPI_BC + 1, > (B_PCH_SPI_BC_SYNC_SS >> 8) > ); > /// > /// Set BIOSWE bit (SPI PCI Offset DCh [0]) = 1b > /// Enable the access to the BIOS space for both read and write cycles > /// > MmioOr8 ( > SpiBaseAddress + R_PCH_SPI_BC, > B_PCH_SPI_BC_WPD > ); > /// > /// PCH BIOS Spec Section 3.7 BIOS Region SMM Protection Enabling > /// If the following steps are implemented: > /// - Set the EISS bit (SPI PCI Offset DCh [5]) = 1b > /// - Follow the 1st recommendation in section 3.6 > /// the BIOS Region can only be updated by following the steps bellow: > /// - Once all threads enter SMM > /// - Read memory location FED30880h OR with 00000001h, place the result in EAX, > /// and write data to lower 32 bits of MSR 1FEh (sample code available) > /// - Set BIOSWE bit (SPI PCI Offset DCh [0]) = 1b > /// - Modify BIOS Region > /// - Clear BIOSWE bit (SPI PCI Offset DCh [0]) = 0b > /// > if ((MmioRead8 (SpiBaseAddress + R_PCH_SPI_BC) & B_PCH_SPI_BC_EISS) != 0) { > /// > /// Read memory location FED30880h OR with 00000001h, place the result in EAX, > /// and write data to lower 32 bits of MSR 1FEh (sample code available) > /// > Data32 = MmioRead32 ((UINTN) (0xFED30880)) | BIT0; > > // crash occurs here > AsmWriteMsr32 (0x1FE, Data32); > } > > return EFI_SUCCESS; > } > > VOID > EFIAPI > EnableBiosWriteProtect ( > VOID > ) > { > UINTN SpiBaseAddress; > UINT32 Data32; > > SpiBaseAddress = MmPciBase ( > DEFAULT_PCI_BUS_NUMBER_PCH, > PCI_DEVICE_NUMBER_PCH_SPI, > PCI_FUNCTION_NUMBER_PCH_SPI > ); > /// > /// Clear BIOSWE bit (SPI PCI Offset DCh [0]) = 0b > /// Disable the access to the BIOS space for write cycles > /// > MmioAnd8 ( > SpiBaseAddress + R_PCH_SPI_BC, > (UINT8) (~B_PCH_SPI_BC_WPD) > ); > > /// > /// Check if EISS bit is set > /// > if (((MmioRead8 (SpiBaseAddress + R_PCH_SPI_BC)) & B_PCH_SPI_BC_EISS) == B_PCH_SPI_BC_EISS) { > /// > /// Read memory location FED30880h AND with FFFFFFFEh, place the result in EAX, > /// and write data to lower 32 bits of MSR 1FEh (sample code available) > /// > Data32 = MmioRead32 ((UINTN) (0xFED30880)) & (~BIT0); > > // crash occurs here > //AsmWriteMsr32 (0x1FE, Data32); > } > } > ``` > > I can work around the crash by hardcoding the values 0x0 and 0x1, or commenting out the writes. Accessing invalid MSRs may raise injections. How do you know the MSR 0x1FE is valid (and the Data32 value is valid)? > > The second part is that variables cannot be saved or updated: > > ``` > Variable driver flush the HOB variable to flash: {guid} > TCG2_CONFIGURATION Invalid Parameter Variable driver flush the HOB > variable to flash: {guid} Setup Invalid Parameter Variable driver > flush the HOB variable to flash: {guid} PchRcConfiguration Invalid > Parameter Variable driver flush the HOB variable to flash: {guid} > MeRcConfiguration Invalid Parameter Variable driver flush the HOB > variable to flash: {guid} IeRcConfiguration Invalid Parameter Variable > driver flush the HOB variable to flash: {guid} SocketIioConfig Invalid > Parameter Variable driver flush the HOB variable to flash: {guid} > SocketCommonRcConfig Invalid Parameter Variable driver flush the HOB > variable to flash: {guid} SocketMpLinkConfig Invalid Parameter > Variable driver flush the HOB variable to flash: {guid} > SocketMemoryConfig Invalid Parameter Variable driver flush the HOB > variable to flash: {guid} SocketPowerManagementConfig Invalid > Parameter Variable driver flush the HOB variable to flash: {guid} > SocketProcessorCoreConfig Invalid Parameter Variable driver flush the > HOB variable to flash: {guid} FpgaSocketConfig Invalid Parameter ``` > > I can't save variables to non-volatile storage, I can save some to > volatile storage, but others I cannot save at all. > > I tracked the failure down to here: > https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/V > ariable/RuntimeDxe/Variable.c#L338 > and I'm not sure how to proceed. The platform is based on UDK2015. That's an Fvb->Write() call. Do you have access to the source of the flash driver (which produces the FVB protocol instance)? (FWIW, EFI_INVALID_PARAMETER doesn't seem a spec-compliant return value for EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL.Write()). Thanks Laszlo ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: RuntimeDXE unable to save variables to flash 2018-10-09 10:25 ` Hristo Mihaylov @ 2018-10-09 10:49 ` Laszlo Ersek 2018-10-31 12:41 ` Hristo Mihaylov 0 siblings, 1 reply; 5+ messages in thread From: Laszlo Ersek @ 2018-10-09 10:49 UTC (permalink / raw) To: Hristo Mihaylov, edk2-devel@lists.01.org On 10/09/18 12:25, Hristo Mihaylov wrote: > Thanks Laszlo, > >> Accessing invalid MSRs may raise injections. How do you know the MSR 0x1FE is valid (and the Data32 value is valid)? > > I'll investigate this further. > >> That's an Fvb->Write() call. Do you have access to the source of the flash driver (which produces the FVB protocol instance)? > > Yes, I found that the writing is done in a function called SendSpiCmd, here's the signature (I can't disclose the full source). > > ``` > /** > This function sends the programmed SPI command to the slave device. > > @param[in] This Pointer to the PCH_SPI_PROTOCOL instance. > @param[in] SpiRegionType The SPI Region type for flash cycle which is listed in the Descriptor > @param[in] FlashCycleType The Flash SPI cycle type list in HSFC (Hardware Sequencing Flash Control Register) register > @param[in] Address The Flash Linear Address must fall within a region for which BIOS has access permissions. > @param[in] ByteCount Number of bytes in the data portion of the SPI cycle. > @param[in,out] Buffer Pointer to caller-allocated buffer containing the dada received or sent during the SPI cycle. > > @retval EFI_SUCCESS SPI command completes successfully. > @retval EFI_DEVICE_ERROR Device error, the command aborts abnormally. > @retval EFI_ACCESS_DENIED Some unrecognized command encountered in hardware sequencing mode > @retval EFI_INVALID_PARAMETER The parameters specified are not valid. > **/ > EFI_STATUS > SendSpiCmd ( > IN EFI_SPI_PROTOCOL *This, > IN FLASH_REGION_TYPE FlashRegionType, > IN FLASH_CYCLE_TYPE FlashCycleType, > IN UINT32 Address, > IN UINT32 ByteCount, > IN OUT UINT8 *Buffer > ) > ``` > > It fails when it does a sanity check. It checks `if (Address + ByteCount) > FlashRegionSize`. The FlashRegionSize > seems to be estimated correctly, because it's used to write other values to that region, which succeed. > > When I log the sanity check like for the incorrect value I see: `SendSpiCmd: (46334052 + 60 = 46334112) > 20971520` > the address seems to be way off. > > The Address is calculated in FvbGetLbaAddress. Almost a 1 to 1 copy of > https://github.com/tianocore/edk2/blob/75b7aa9528bdd05a7ecf4e64a6beb478d31b402c/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c#L237 > > I thought that the issue is either because of invalid FV block or the size of the flash region is calculated > incorrectly, but this only happens in SMM. Now I'm leaning more towards permissions. > > Any advice? Hmm, not much. Either the blockmap is wrong, as you suggest, or else the Lba input param to FvbGetLbaAddress() is bogus, and FvbGetLbaAddress() returns EFI_INVALID_PARAMETER, when it reaches the terminator blockmap entry (without finding Lba). Does the caller of FvbGetLbaAddress() check the return value? Laszlo ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: RuntimeDXE unable to save variables to flash 2018-10-09 10:49 ` Laszlo Ersek @ 2018-10-31 12:41 ` Hristo Mihaylov 0 siblings, 0 replies; 5+ messages in thread From: Hristo Mihaylov @ 2018-10-31 12:41 UTC (permalink / raw) To: Laszlo Ersek, edk2-devel@lists.01.org I wanted to close this off, The value was checked. The problem was that I had previously changed the offsets/sizes of some FD/FVs. Removing those changes fixed the issue. --- Hristo -----Original Message----- From: Laszlo Ersek [mailto:lersek@redhat.com] Sent: 09 October 2018 12:49 To: Hristo Mihaylov <hristo.mihaylov@prodrive-technologies.com>; edk2-devel@lists.01.org Subject: Re: [edk2] RuntimeDXE unable to save variables to flash On 10/09/18 12:25, Hristo Mihaylov wrote: > Thanks Laszlo, > >> Accessing invalid MSRs may raise injections. How do you know the MSR 0x1FE is valid (and the Data32 value is valid)? > > I'll investigate this further. > >> That's an Fvb->Write() call. Do you have access to the source of the flash driver (which produces the FVB protocol instance)? > > Yes, I found that the writing is done in a function called SendSpiCmd, here's the signature (I can't disclose the full source). > > ``` > /** > This function sends the programmed SPI command to the slave device. > > @param[in] This Pointer to the PCH_SPI_PROTOCOL instance. > @param[in] SpiRegionType The SPI Region type for flash cycle which is listed in the Descriptor > @param[in] FlashCycleType The Flash SPI cycle type list in HSFC (Hardware Sequencing Flash Control Register) register > @param[in] Address The Flash Linear Address must fall within a region for which BIOS has access permissions. > @param[in] ByteCount Number of bytes in the data portion of the SPI cycle. > @param[in,out] Buffer Pointer to caller-allocated buffer containing the dada received or sent during the SPI cycle. > > @retval EFI_SUCCESS SPI command completes successfully. > @retval EFI_DEVICE_ERROR Device error, the command aborts abnormally. > @retval EFI_ACCESS_DENIED Some unrecognized command encountered in hardware sequencing mode > @retval EFI_INVALID_PARAMETER The parameters specified are not valid. > **/ > EFI_STATUS > SendSpiCmd ( > IN EFI_SPI_PROTOCOL *This, > IN FLASH_REGION_TYPE FlashRegionType, > IN FLASH_CYCLE_TYPE FlashCycleType, > IN UINT32 Address, > IN UINT32 ByteCount, > IN OUT UINT8 *Buffer > ) > ``` > > It fails when it does a sanity check. It checks `if (Address + > ByteCount) > FlashRegionSize`. The FlashRegionSize seems to be estimated correctly, because it's used to write other values to that region, which succeed. > > When I log the sanity check like for the incorrect value I see: > `SendSpiCmd: (46334052 + 60 = 46334112) > 20971520` the address seems to be way off. > > The Address is calculated in FvbGetLbaAddress. Almost a 1 to 1 copy of > https://github.com/tianocore/edk2/blob/75b7aa9528bdd05a7ecf4e64a6beb47 > 8d31b402c/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c#L237 > > I thought that the issue is either because of invalid FV block or the > size of the flash region is calculated incorrectly, but this only happens in SMM. Now I'm leaning more towards permissions. > > Any advice? Hmm, not much. Either the blockmap is wrong, as you suggest, or else the Lba input param to FvbGetLbaAddress() is bogus, and FvbGetLbaAddress() returns EFI_INVALID_PARAMETER, when it reaches the terminator blockmap entry (without finding Lba). Does the caller of FvbGetLbaAddress() check the return value? Laszlo ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2018-10-31 12:41 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2018-10-04 10:56 RuntimeDXE unable to save variables to flash Hristo Mihaylov 2018-10-04 17:00 ` Laszlo Ersek 2018-10-09 10:25 ` Hristo Mihaylov 2018-10-09 10:49 ` Laszlo Ersek 2018-10-31 12:41 ` Hristo Mihaylov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox