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

Reply via email to