--- /dev/null
+/*++\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