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