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