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