]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/Ia32/Ia32FtwMisc.c
Initial import.
[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 (LPC_BUS_NUMBER,
177 LPC_DEVICE_NUMBER,
178 LPC_IF,
179 GEN_STATUS),
180 1,
181 &GenStatus
182 );
183
184 DEBUG_CODE (
185 if (TopSwap) {
186 DEBUG ((EFI_D_ERROR, "SAR: Set top swap\n"));
187 } else {
188 DEBUG ((EFI_D_ERROR, "SAR: Clear top swap\n"));
189 }
190 );
191
192 return EFI_SUCCESS;
193 }
194
195 BOOLEAN
196 IsBootBlock (
197 EFI_FTW_LITE_DEVICE *FtwLiteDevice,
198 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
199 EFI_LBA Lba
200 )
201 /*++
202
203 Routine Description:
204
205 Check whether the block is a boot block.
206
207 Arguments:
208
209 FtwLiteDevice - Calling context
210 FvBlock - Fvb protocol instance
211 Lba - Lba value
212
213 Returns:
214
215 Is a boot block or not
216
217 --*/
218 {
219 EFI_STATUS Status;
220 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb;
221
222 Status = GetFvbByAddress (BOOT_BLOCK_BASE, &BootFvb);
223 if (EFI_ERROR (Status)) {
224 return FALSE;
225 }
226 //
227 // Compare the Fvb
228 //
229 return (BOOLEAN) (FvBlock == BootFvb);
230 }
231
232 EFI_STATUS
233 FlushSpareBlockToBootBlock (
234 EFI_FTW_LITE_DEVICE *FtwLiteDevice
235 )
236 /*++
237
238 Routine Description:
239 Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE.
240 Spare block is accessed by FTW backup FVB protocol interface. LBA is
241 FtwLiteDevice->FtwSpareLba.
242 Boot block is accessed by BootFvb protocol interface. LBA is 0.
243
244 Arguments:
245 FtwLiteDevice - The private data of FTW_LITE driver
246
247 Returns:
248 EFI_SUCCESS - Spare block content is copied to boot block
249 EFI_INVALID_PARAMETER - Input parameter error
250 EFI_OUT_OF_RESOURCES - Allocate memory error
251 EFI_ABORTED - The function could not complete successfully
252
253 Notes:
254 FTW will do extra work on boot block update.
255 FTW should depend on a protocol of EFI_ADDRESS_RANGE_SWAP_PROTOCOL,
256 which is produced by a chipset driver.
257
258 FTW updating boot block steps:
259 1. Erase top swap block (0xFFFE-0xFFFEFFFF) and write data to it ready
260 2. Read data from top swap block to memory buffer
261 3. SetSwapState(EFI_SWAPPED)
262 4. Erasing boot block (0xFFFF-0xFFFFFFFF)
263 5. Programming boot block until the boot block is ok.
264 6. SetSwapState(UNSWAPPED)
265
266 Notes:
267 1. Since the SwapState bit is saved in CMOS, FTW can restore and continue
268 even in the scenario of power failure.
269 2. FTW shall not allow to update boot block when battery state is error.
270
271 --*/
272 {
273 EFI_STATUS Status;
274 UINTN Length;
275 UINT8 *Buffer;
276 UINTN Count;
277 UINT8 *Ptr;
278 UINTN Index;
279 BOOLEAN TopSwap;
280 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb;
281 EFI_LBA BootLba;
282
283 //
284 // Allocate a memory buffer
285 //
286 Length = FtwLiteDevice->SpareAreaLength;
287 Buffer = AllocatePool (Length);
288 if (Buffer == NULL) {
289 }
290 //
291 // Get TopSwap bit state
292 //
293 Status = GetSwapState (FtwLiteDevice, &TopSwap);
294 if (EFI_ERROR (Status)) {
295 DEBUG ((EFI_D_ERROR, "FtwLite: Get Top Swapped status - %r\n", Status));
296 gBS->FreePool (Buffer);
297 return EFI_ABORTED;
298 }
299
300 if (TopSwap) {
301 //
302 // Get FVB of current boot block
303 //
304 Status = GetFvbByAddress (FtwLiteDevice->SpareAreaAddress + FTW_BLOCK_SIZE, &BootFvb);
305 if (EFI_ERROR (Status)) {
306 gBS->FreePool (Buffer);
307 return Status;
308 }
309 //
310 // Read data from current boot block
311 //
312 BootLba = 0;
313 Ptr = Buffer;
314 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
315 Count = FtwLiteDevice->SizeOfSpareBlock;
316 Status = BootFvb->Read (
317 BootFvb,
318 BootLba + Index,
319 0,
320 &Count,
321 Ptr
322 );
323 if (EFI_ERROR (Status)) {
324 gBS->FreePool (Buffer);
325 return Status;
326 }
327
328 Ptr += Count;
329 }
330
331 } else {
332 //
333 // Read data from spare block
334 //
335 Ptr = Buffer;
336 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
337 Count = FtwLiteDevice->SizeOfSpareBlock;
338 Status = FtwLiteDevice->FtwBackupFvb->Read (
339 FtwLiteDevice->FtwBackupFvb,
340 FtwLiteDevice->FtwSpareLba + Index,
341 0,
342 &Count,
343 Ptr
344 );
345 if (EFI_ERROR (Status)) {
346 gBS->FreePool (Buffer);
347 return Status;
348 }
349
350 Ptr += Count;
351 }
352 //
353 // Set TopSwap bit
354 //
355 Status = SetSwapState (FtwLiteDevice, TRUE);
356 DEBUG ((EFI_D_ERROR, "FtwLite: Set Swap State - %r\n", Status));
357 ASSERT_EFI_ERROR (Status);
358 }
359 //
360 // Erase boot block. After setting TopSwap bit, it's spare block now!
361 //
362 Status = FtwEraseSpareBlock (FtwLiteDevice);
363 if (EFI_ERROR (Status)) {
364 gBS->FreePool (Buffer);
365 return EFI_ABORTED;
366 }
367 //
368 // Write memory buffer to currenet spare block
369 //
370 Ptr = Buffer;
371 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
372 Count = FtwLiteDevice->SizeOfSpareBlock;
373 Status = FtwLiteDevice->FtwBackupFvb->Write (
374 FtwLiteDevice->FtwBackupFvb,
375 FtwLiteDevice->FtwSpareLba + Index,
376 0,
377 &Count,
378 Ptr
379 );
380 if (EFI_ERROR (Status)) {
381 DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Write boot block - %r\n", Status));
382 gBS->FreePool (Buffer);
383 return Status;
384 }
385
386 Ptr += Count;
387 }
388
389 gBS->FreePool (Buffer);
390
391 //
392 // Clear TopSwap bit
393 //
394 Status = SetSwapState (FtwLiteDevice, FALSE);
395 DEBUG ((EFI_D_ERROR, "FtwLite: Clear Swap State - %r\n", Status));
396 ASSERT_EFI_ERROR (Status);
397
398 return EFI_SUCCESS;
399 }