]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/Ia32/Ia32FtwMisc.c
Add comments and DoxyGen format for these files.
[mirror_edk2.git] / MdeModulePkg / Universal / FirmwareVolume / FaultTolerantWriteDxe / Ia32 / Ia32FtwMisc.c
CommitLineData
6cc9ca32
LG
1/** @file\r
2 \r
3 Ia32 platform related code to support FtwLite.\r
4 \r
5Copyright (c) 2006 - 2008, Intel Corporation \r
d7dec593 6All rights reserved. This program and the accompanying materials \r
7are licensed and made available under the terms and conditions of the BSD License \r
8which accompanies this distribution. The full text of the license may be found at \r
9http://opensource.org/licenses/bsd-license.php \r
10 \r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
13\r
6cc9ca32 14**/\r
d7dec593 15\r
16\r
17#include <FtwLite.h>\r
18\r
19//\r
20// MACROs for boot block update\r
21//\r
22#define BOOT_BLOCK_BASE 0xFFFF0000\r
23\r
24//\r
25// (LPC -- D31:F0)\r
26//\r
27#define LPC_BUS_NUMBER 0x00\r
28#define LPC_DEVICE_NUMBER 0x1F\r
29#define LPC_IF 0xF0\r
30//\r
31// Top swap\r
32//\r
33#define GEN_STATUS 0xD4\r
34#define TOP_SWAP_BIT (1 << 13)\r
35\r
36STATIC\r
37UINT32\r
38ReadPciRegister (\r
39 IN UINT32 Offset\r
40 )\r
41/*++\r
42\r
43Routine Description:\r
44\r
45 Read PCI register value.\r
46\r
47Arguments:\r
48\r
49 Offset - Offset of the register\r
50\r
51Returns:\r
52\r
53 The value.\r
54\r
55--*/\r
56{\r
57 EFI_STATUS Status;\r
58 UINT32 Value;\r
59 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
60\r
61 Value = 0;\r
62 Status = gBS->LocateProtocol (&gEfiPciRootBridgeIoProtocolGuid, NULL, (VOID **) &PciRootBridgeIo);\r
63 if (EFI_ERROR (Status)) {\r
64 DEBUG ((EFI_D_ERROR, "FtwLite: Locate PCI root bridge io protocol - %r", Status));\r
65 return 0;\r
66 }\r
67\r
68 Status = PciRootBridgeIo->Pci.Read (\r
69 PciRootBridgeIo,\r
70 EfiPciWidthUint32,\r
71 EFI_PCI_ADDRESS (\r
72 LPC_BUS_NUMBER,\r
73 LPC_DEVICE_NUMBER,\r
74 LPC_IF,\r
75 Offset\r
76 ),\r
77 1,\r
78 &Value\r
79 );\r
80 ASSERT_EFI_ERROR (Status);\r
81\r
82 return Value;\r
83}\r
84\r
85STATIC\r
86EFI_STATUS\r
87GetSwapState (\r
88 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
89 OUT BOOLEAN *SwapState\r
90 )\r
91/*++\r
92\r
93Routine Description:\r
94\r
95 Get swap state\r
96\r
97Arguments:\r
98\r
99 FtwLiteDevice - Calling context\r
100 SwapState - Swap state\r
101\r
102Returns:\r
103\r
104 EFI_SUCCESS - State successfully got\r
105\r
106--*/\r
107{\r
108 //\r
109 // Top swap status is 13 bit\r
110 //\r
111 *SwapState = (BOOLEAN) ((ReadPciRegister (GEN_STATUS) & TOP_SWAP_BIT) != 0);\r
112\r
113 return EFI_SUCCESS;\r
114}\r
115\r
116STATIC\r
117EFI_STATUS\r
118SetSwapState (\r
119 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
120 IN BOOLEAN TopSwap\r
121 )\r
122/*++\r
123\r
124Routine Description:\r
125 Set swap state.\r
126\r
127Arguments:\r
128 FtwLiteDevice - Indicates a pointer to the calling context. \r
129 TopSwap - New swap state\r
130\r
131Returns:\r
132 EFI_SUCCESS - The function completed successfully\r
133\r
134Note:\r
135 the Top-Swap bit (bit 13, D31: F0, Offset D4h). Note that\r
136 software will not be able to clear the Top-Swap bit until the system is\r
137 rebooted without GNT[A]# being pulled down.\r
138\r
139--*/\r
140{\r
141 UINT32 GenStatus;\r
142 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
143 EFI_STATUS Status;\r
144\r
145 //\r
146 // Top-Swap bit (bit 13, D31: F0, Offset D4h)\r
147 //\r
148 GenStatus = ReadPciRegister (GEN_STATUS);\r
149\r
150 //\r
151 // Set 13 bit, according to input NewSwapState\r
152 //\r
153 if (TopSwap) {\r
154 GenStatus |= TOP_SWAP_BIT;\r
155 } else {\r
156 GenStatus &= ~TOP_SWAP_BIT;\r
157 }\r
158\r
159 Status = gBS->LocateProtocol (&gEfiPciRootBridgeIoProtocolGuid, NULL, (VOID **) &PciRootBridgeIo);\r
160 if (EFI_ERROR (Status)) {\r
161 DEBUG ((EFI_D_ERROR, "FtwLite: Locate PCI root bridge io protocol - %r", Status));\r
162 return Status;\r
163 }\r
164 //\r
165 // Write back the GenStatus register\r
166 //\r
167 Status = PciRootBridgeIo->Pci.Write (\r
168 PciRootBridgeIo,\r
169 EfiPciWidthUint32,\r
170 EFI_PCI_ADDRESS (\r
171 LPC_BUS_NUMBER,\r
172 LPC_DEVICE_NUMBER,\r
173 LPC_IF,\r
174 GEN_STATUS\r
175 ),\r
176 1,\r
177 &GenStatus\r
178 );\r
179\r
180 DEBUG_CODE_BEGIN ();\r
181 if (TopSwap) {\r
182 DEBUG ((EFI_D_ERROR, "SAR: Set top swap\n"));\r
183 } else {\r
184 DEBUG ((EFI_D_ERROR, "SAR: Clear top swap\n"));\r
185 }\r
186 DEBUG_CODE_END ();\r
187\r
188 return EFI_SUCCESS;\r
189}\r
190\r
191BOOLEAN\r
192IsBootBlock (\r
193 EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
194 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
195 EFI_LBA Lba\r
196 )\r
197/*++\r
198\r
199Routine Description:\r
200\r
201 Check whether the block is a boot block.\r
202\r
203Arguments:\r
204\r
205 FtwLiteDevice - Calling context\r
206 FvBlock - Fvb protocol instance\r
207 Lba - Lba value\r
208\r
209Returns:\r
210\r
211 Is a boot block or not\r
212\r
213--*/\r
214{\r
215 EFI_STATUS Status;\r
216 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb;\r
217\r
218 Status = GetFvbByAddress (BOOT_BLOCK_BASE, &BootFvb);\r
219 if (EFI_ERROR (Status)) {\r
220 return FALSE;\r
221 }\r
222 //\r
223 // Compare the Fvb\r
224 //\r
225 return (BOOLEAN) (FvBlock == BootFvb);\r
226}\r
227\r
228EFI_STATUS\r
229FlushSpareBlockToBootBlock (\r
230 EFI_FTW_LITE_DEVICE *FtwLiteDevice\r
231 )\r
232/*++\r
233\r
234Routine Description:\r
235 Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE.\r
236 Spare block is accessed by FTW backup FVB protocol interface. LBA is \r
237 FtwLiteDevice->FtwSpareLba.\r
238 Boot block is accessed by BootFvb protocol interface. LBA is 0.\r
239\r
240Arguments:\r
241 FtwLiteDevice - The private data of FTW_LITE driver\r
242\r
243Returns:\r
244 EFI_SUCCESS - Spare block content is copied to boot block\r
245 EFI_INVALID_PARAMETER - Input parameter error\r
246 EFI_OUT_OF_RESOURCES - Allocate memory error\r
247 EFI_ABORTED - The function could not complete successfully\r
248\r
249Notes:\r
250 FTW will do extra work on boot block update.\r
251 FTW should depend on a protocol of EFI_ADDRESS_RANGE_SWAP_PROTOCOL, \r
252 which is produced by a chipset driver.\r
253\r
254 FTW updating boot block steps:\r
255 1. Erase top swap block (0xFFFE-0xFFFEFFFF) and write data to it ready\r
256 2. Read data from top swap block to memory buffer\r
257 3. SetSwapState(EFI_SWAPPED)\r
258 4. Erasing boot block (0xFFFF-0xFFFFFFFF)\r
259 5. Programming boot block until the boot block is ok.\r
260 6. SetSwapState(UNSWAPPED)\r
261\r
262 Notes:\r
263 1. Since the SwapState bit is saved in CMOS, FTW can restore and continue \r
264 even in the scenario of power failure.\r
265 2. FTW shall not allow to update boot block when battery state is error.\r
266\r
267--*/\r
268{\r
269 EFI_STATUS Status;\r
270 UINTN Length;\r
271 UINT8 *Buffer;\r
272 UINTN Count;\r
273 UINT8 *Ptr;\r
274 UINTN Index;\r
275 BOOLEAN TopSwap;\r
276 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb;\r
277 EFI_LBA BootLba;\r
278\r
279 //\r
280 // Allocate a memory buffer\r
281 //\r
282 Length = FtwLiteDevice->SpareAreaLength;\r
283 Buffer = AllocatePool (Length);\r
284 if (Buffer == NULL) {\r
285 }\r
286 //\r
287 // Get TopSwap bit state\r
288 //\r
289 Status = GetSwapState (FtwLiteDevice, &TopSwap);\r
290 if (EFI_ERROR (Status)) {\r
291 DEBUG ((EFI_D_ERROR, "FtwLite: Get Top Swapped status - %r\n", Status));\r
292 FreePool (Buffer);\r
293 return EFI_ABORTED;\r
294 }\r
295\r
296 if (TopSwap) {\r
297 //\r
298 // Get FVB of current boot block\r
299 //\r
300 Status = GetFvbByAddress (FtwLiteDevice->SpareAreaAddress + FTW_BLOCK_SIZE, &BootFvb);\r
301 if (EFI_ERROR (Status)) {\r
302 FreePool (Buffer);\r
303 return Status;\r
304 }\r
305 //\r
306 // Read data from current boot block\r
307 //\r
308 BootLba = 0;\r
309 Ptr = Buffer;\r
310 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
311 Count = FtwLiteDevice->SizeOfSpareBlock;\r
312 Status = BootFvb->Read (\r
313 BootFvb,\r
314 BootLba + Index,\r
315 0,\r
316 &Count,\r
317 Ptr\r
318 );\r
319 if (EFI_ERROR (Status)) {\r
320 FreePool (Buffer);\r
321 return Status;\r
322 }\r
323\r
324 Ptr += Count;\r
325 }\r
326\r
327 } else {\r
328 //\r
329 // Read data from spare block\r
330 //\r
331 Ptr = Buffer;\r
332 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
333 Count = FtwLiteDevice->SizeOfSpareBlock;\r
334 Status = FtwLiteDevice->FtwBackupFvb->Read (\r
335 FtwLiteDevice->FtwBackupFvb,\r
336 FtwLiteDevice->FtwSpareLba + Index,\r
337 0,\r
338 &Count,\r
339 Ptr\r
340 );\r
341 if (EFI_ERROR (Status)) {\r
342 FreePool (Buffer);\r
343 return Status;\r
344 }\r
345\r
346 Ptr += Count;\r
347 }\r
348 //\r
349 // Set TopSwap bit\r
350 //\r
351 Status = SetSwapState (FtwLiteDevice, TRUE);\r
352 DEBUG ((EFI_D_ERROR, "FtwLite: Set Swap State - %r\n", Status));\r
353 ASSERT_EFI_ERROR (Status);\r
354 }\r
355 //\r
356 // Erase boot block. After setting TopSwap bit, it's spare block now!\r
357 //\r
358 Status = FtwEraseSpareBlock (FtwLiteDevice);\r
359 if (EFI_ERROR (Status)) {\r
360 FreePool (Buffer);\r
361 return EFI_ABORTED;\r
362 }\r
363 //\r
364 // Write memory buffer to currenet spare block\r
365 //\r
366 Ptr = Buffer;\r
367 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
368 Count = FtwLiteDevice->SizeOfSpareBlock;\r
369 Status = FtwLiteDevice->FtwBackupFvb->Write (\r
370 FtwLiteDevice->FtwBackupFvb,\r
371 FtwLiteDevice->FtwSpareLba + Index,\r
372 0,\r
373 &Count,\r
374 Ptr\r
375 );\r
376 if (EFI_ERROR (Status)) {\r
377 DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Write boot block - %r\n", Status));\r
378 FreePool (Buffer);\r
379 return Status;\r
380 }\r
381\r
382 Ptr += Count;\r
383 }\r
384\r
385 FreePool (Buffer);\r
386\r
387 //\r
388 // Clear TopSwap bit\r
389 //\r
390 Status = SetSwapState (FtwLiteDevice, FALSE);\r
391 DEBUG ((EFI_D_ERROR, "FtwLite: Clear Swap State - %r\n", Status));\r
392 ASSERT_EFI_ERROR (Status);\r
393\r
394 return EFI_SUCCESS;\r
395}\r