]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/Ia32/Ia32FtwMisc.c
Adjust directory structures.
[mirror_edk2.git] / MdeModulePkg / Universal / FirmwareVolume / FaultTolerantWriteDxe / Ia32 / Ia32FtwMisc.c
diff --git a/MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/Ia32/Ia32FtwMisc.c b/MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/Ia32/Ia32FtwMisc.c
new file mode 100644 (file)
index 0000000..6425f29
--- /dev/null
@@ -0,0 +1,403 @@
+/*++\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation                                                         \r
+All rights reserved. This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+Module Name:\r
+\r
+  Ia32FtwMisc.c\r
+  \r
+Abstract:\r
+  \r
+   Ia32 platform related code to support FtwLite..\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+\r
+#include <FtwLite.h>\r
+\r
+//\r
+// MACROs for boot block update\r
+//\r
+#define BOOT_BLOCK_BASE 0xFFFF0000\r
+\r
+//\r
+// (LPC -- D31:F0)\r
+//\r
+#define LPC_BUS_NUMBER    0x00\r
+#define LPC_DEVICE_NUMBER 0x1F\r
+#define LPC_IF            0xF0\r
+//\r
+// Top swap\r
+//\r
+#define GEN_STATUS    0xD4\r
+#define TOP_SWAP_BIT  (1 << 13)\r
+\r
+STATIC\r
+UINT32\r
+ReadPciRegister (\r
+  IN UINT32                 Offset\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Read PCI register value.\r
+\r
+Arguments:\r
+\r
+  Offset  - Offset of the register\r
+\r
+Returns:\r
+\r
+  The value.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                      Status;\r
+  UINT32                          Value;\r
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
+\r
+  Value   = 0;\r
+  Status  = gBS->LocateProtocol (&gEfiPciRootBridgeIoProtocolGuid, NULL, (VOID **) &PciRootBridgeIo);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "FtwLite: Locate PCI root bridge io protocol - %r", Status));\r
+    return 0;\r
+  }\r
+\r
+  Status = PciRootBridgeIo->Pci.Read (\r
+                                  PciRootBridgeIo,\r
+                                  EfiPciWidthUint32,\r
+                                  EFI_PCI_ADDRESS (\r
+                                    LPC_BUS_NUMBER,\r
+                                    LPC_DEVICE_NUMBER,\r
+                                    LPC_IF,\r
+                                    Offset\r
+                                    ),\r
+                                  1,\r
+                                  &Value\r
+                                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Value;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+GetSwapState (\r
+  IN EFI_FTW_LITE_DEVICE    *FtwLiteDevice,\r
+  OUT BOOLEAN               *SwapState\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get swap state\r
+\r
+Arguments:\r
+\r
+  FtwLiteDevice - Calling context\r
+  SwapState     - Swap state\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - State successfully got\r
+\r
+--*/\r
+{\r
+  //\r
+  // Top swap status is 13 bit\r
+  //\r
+  *SwapState = (BOOLEAN) ((ReadPciRegister (GEN_STATUS) & TOP_SWAP_BIT) != 0);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+SetSwapState (\r
+  IN EFI_FTW_LITE_DEVICE    *FtwLiteDevice,\r
+  IN  BOOLEAN               TopSwap\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+    Set swap state.\r
+\r
+Arguments:\r
+    FtwLiteDevice  - Indicates a pointer to the calling context.  \r
+    TopSwap        - New swap state\r
+\r
+Returns:\r
+    EFI_SUCCESS   - The function completed successfully\r
+\r
+Note:\r
+    the Top-Swap bit (bit 13, D31: F0, Offset D4h). Note that\r
+    software will not be able to clear the Top-Swap bit until the system is\r
+    rebooted without GNT[A]# being pulled down.\r
+\r
+--*/\r
+{\r
+  UINT32                          GenStatus;\r
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
+  EFI_STATUS                      Status;\r
+\r
+  //\r
+  // Top-Swap bit (bit 13, D31: F0, Offset D4h)\r
+  //\r
+  GenStatus = ReadPciRegister (GEN_STATUS);\r
+\r
+  //\r
+  // Set 13 bit, according to input NewSwapState\r
+  //\r
+  if (TopSwap) {\r
+    GenStatus |= TOP_SWAP_BIT;\r
+  } else {\r
+    GenStatus &= ~TOP_SWAP_BIT;\r
+  }\r
+\r
+  Status = gBS->LocateProtocol (&gEfiPciRootBridgeIoProtocolGuid, NULL, (VOID **) &PciRootBridgeIo);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "FtwLite: Locate PCI root bridge io protocol - %r", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Write back the GenStatus register\r
+  //\r
+  Status = PciRootBridgeIo->Pci.Write (\r
+                                  PciRootBridgeIo,\r
+                                  EfiPciWidthUint32,\r
+                                  EFI_PCI_ADDRESS (\r
+                                    LPC_BUS_NUMBER,\r
+                                    LPC_DEVICE_NUMBER,\r
+                                    LPC_IF,\r
+                                    GEN_STATUS\r
+                                    ),\r
+                                  1,\r
+                                  &GenStatus\r
+                                  );\r
+\r
+  DEBUG_CODE_BEGIN ();\r
+    if (TopSwap) {\r
+      DEBUG ((EFI_D_ERROR, "SAR: Set top swap\n"));\r
+    } else {\r
+      DEBUG ((EFI_D_ERROR, "SAR: Clear top swap\n"));\r
+    }\r
+  DEBUG_CODE_END ();\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+IsBootBlock (\r
+  EFI_FTW_LITE_DEVICE                 *FtwLiteDevice,\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *FvBlock,\r
+  EFI_LBA                             Lba\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Check whether the block is a boot block.\r
+\r
+Arguments:\r
+\r
+  FtwLiteDevice - Calling context\r
+  FvBlock       - Fvb protocol instance\r
+  Lba           - Lba value\r
+\r
+Returns:\r
+\r
+  Is a boot block or not\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *BootFvb;\r
+\r
+  Status = GetFvbByAddress (BOOT_BLOCK_BASE, &BootFvb);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+  //\r
+  // Compare the Fvb\r
+  //\r
+  return (BOOLEAN) (FvBlock == BootFvb);\r
+}\r
+\r
+EFI_STATUS\r
+FlushSpareBlockToBootBlock (\r
+  EFI_FTW_LITE_DEVICE      *FtwLiteDevice\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+    Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE.\r
+    Spare block is accessed by FTW backup FVB protocol interface. LBA is \r
+    FtwLiteDevice->FtwSpareLba.\r
+    Boot block is accessed by BootFvb protocol interface. LBA is 0.\r
+\r
+Arguments:\r
+    FtwLiteDevice  - The private data of FTW_LITE driver\r
+\r
+Returns:\r
+    EFI_SUCCESS              - Spare block content is copied to boot block\r
+    EFI_INVALID_PARAMETER    - Input parameter error\r
+    EFI_OUT_OF_RESOURCES     - Allocate memory error\r
+    EFI_ABORTED              - The function could not complete successfully\r
+\r
+Notes:\r
+    FTW will do extra work on boot block update.\r
+    FTW should depend on a protocol of EFI_ADDRESS_RANGE_SWAP_PROTOCOL, \r
+    which is produced by a chipset driver.\r
+\r
+    FTW updating boot block steps:\r
+    1. Erase top swap block (0xFFFE-0xFFFEFFFF) and write data to it ready\r
+    2. Read data from top swap block to memory buffer\r
+    3. SetSwapState(EFI_SWAPPED)\r
+    4. Erasing boot block (0xFFFF-0xFFFFFFFF)\r
+    5. Programming boot block until the boot block is ok.\r
+    6. SetSwapState(UNSWAPPED)\r
+\r
+    Notes:\r
+     1. Since the SwapState bit is saved in CMOS, FTW can restore and continue \r
+     even in the scenario of power failure.\r
+     2. FTW shall not allow to update boot block when battery state is error.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                          Status;\r
+  UINTN                               Length;\r
+  UINT8                               *Buffer;\r
+  UINTN                               Count;\r
+  UINT8                               *Ptr;\r
+  UINTN                               Index;\r
+  BOOLEAN                             TopSwap;\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *BootFvb;\r
+  EFI_LBA                             BootLba;\r
+\r
+  //\r
+  // Allocate a memory buffer\r
+  //\r
+  Length  = FtwLiteDevice->SpareAreaLength;\r
+  Buffer  = AllocatePool (Length);\r
+  if (Buffer == NULL) {\r
+  }\r
+  //\r
+  // Get TopSwap bit state\r
+  //\r
+  Status = GetSwapState (FtwLiteDevice, &TopSwap);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "FtwLite: Get Top Swapped status - %r\n", Status));\r
+    FreePool (Buffer);\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  if (TopSwap) {\r
+    //\r
+    // Get FVB of current boot block\r
+    //\r
+    Status = GetFvbByAddress (FtwLiteDevice->SpareAreaAddress + FTW_BLOCK_SIZE, &BootFvb);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (Buffer);\r
+      return Status;\r
+    }\r
+    //\r
+    // Read data from current boot block\r
+    //\r
+    BootLba = 0;\r
+    Ptr     = Buffer;\r
+    for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
+      Count = FtwLiteDevice->SizeOfSpareBlock;\r
+      Status = BootFvb->Read (\r
+                          BootFvb,\r
+                          BootLba + Index,\r
+                          0,\r
+                          &Count,\r
+                          Ptr\r
+                          );\r
+      if (EFI_ERROR (Status)) {\r
+        FreePool (Buffer);\r
+        return Status;\r
+      }\r
+\r
+      Ptr += Count;\r
+    }\r
+\r
+  } else {\r
+    //\r
+    // Read data from spare block\r
+    //\r
+    Ptr = Buffer;\r
+    for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
+      Count = FtwLiteDevice->SizeOfSpareBlock;\r
+      Status = FtwLiteDevice->FtwBackupFvb->Read (\r
+                                              FtwLiteDevice->FtwBackupFvb,\r
+                                              FtwLiteDevice->FtwSpareLba + Index,\r
+                                              0,\r
+                                              &Count,\r
+                                              Ptr\r
+                                              );\r
+      if (EFI_ERROR (Status)) {\r
+        FreePool (Buffer);\r
+        return Status;\r
+      }\r
+\r
+      Ptr += Count;\r
+    }\r
+    //\r
+    // Set TopSwap bit\r
+    //\r
+    Status = SetSwapState (FtwLiteDevice, TRUE);\r
+    DEBUG ((EFI_D_ERROR, "FtwLite: Set Swap State - %r\n", Status));\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+  //\r
+  // Erase boot block. After setting TopSwap bit, it's spare block now!\r
+  //\r
+  Status = FtwEraseSpareBlock (FtwLiteDevice);\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (Buffer);\r
+    return EFI_ABORTED;\r
+  }\r
+  //\r
+  // Write memory buffer to currenet spare block\r
+  //\r
+  Ptr = Buffer;\r
+  for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
+    Count = FtwLiteDevice->SizeOfSpareBlock;\r
+    Status = FtwLiteDevice->FtwBackupFvb->Write (\r
+                                            FtwLiteDevice->FtwBackupFvb,\r
+                                            FtwLiteDevice->FtwSpareLba + Index,\r
+                                            0,\r
+                                            &Count,\r
+                                            Ptr\r
+                                            );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Write boot block - %r\n", Status));\r
+      FreePool (Buffer);\r
+      return Status;\r
+    }\r
+\r
+    Ptr += Count;\r
+  }\r
+\r
+  FreePool (Buffer);\r
+\r
+  //\r
+  // Clear TopSwap bit\r
+  //\r
+  Status = SetSwapState (FtwLiteDevice, FALSE);\r
+  DEBUG ((EFI_D_ERROR, "FtwLite: Clear Swap State - %r\n", Status));\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return EFI_SUCCESS;\r
+}\r