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
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel