public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Hristo Mihaylov <hristo.mihaylov@prodrive-technologies.com>
To: "edk2-devel@lists.01.org" <edk2-devel@lists.01.org>
Subject: RuntimeDXE unable to save variables to flash
Date: Thu, 4 Oct 2018 10:56:18 +0000	[thread overview]
Message-ID: <bdcbf8b6e56648e297aef34bd2fa996c@prodrive-technologies.com> (raw)

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


             reply	other threads:[~2018-10-04 10:56 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-10-04 10:56 Hristo Mihaylov [this message]
2018-10-04 17:00 ` RuntimeDXE unable to save variables to flash Laszlo Ersek
2018-10-09 10:25   ` Hristo Mihaylov
2018-10-09 10:49     ` Laszlo Ersek
2018-10-31 12:41       ` Hristo Mihaylov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=bdcbf8b6e56648e297aef34bd2fa996c@prodrive-technologies.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox