Adjust directory structures.
[mirror_edk2.git] / MdeModulePkg / Universal / FirmwareVolume / FaultTolerantWriteDxe / Ia32 / Ia32FtwMisc.c
1 /*++
2
3 Copyright (c) 2006 - 2007, 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 (
80 LPC_BUS_NUMBER,
81 LPC_DEVICE_NUMBER,
82 LPC_IF,
83 Offset
84 ),
85 1,
86 &Value
87 );
88 ASSERT_EFI_ERROR (Status);
89
90 return Value;
91 }
92
93 STATIC
94 EFI_STATUS
95 GetSwapState (
96 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
97 OUT BOOLEAN *SwapState
98 )
99 /*++
100
101 Routine Description:
102
103 Get swap state
104
105 Arguments:
106
107 FtwLiteDevice - Calling context
108 SwapState - Swap state
109
110 Returns:
111
112 EFI_SUCCESS - State successfully got
113
114 --*/
115 {
116 //
117 // Top swap status is 13 bit
118 //
119 *SwapState = (BOOLEAN) ((ReadPciRegister (GEN_STATUS) & TOP_SWAP_BIT) != 0);
120
121 return EFI_SUCCESS;
122 }
123
124 STATIC
125 EFI_STATUS
126 SetSwapState (
127 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
128 IN BOOLEAN TopSwap
129 )
130 /*++
131
132 Routine Description:
133 Set swap state.
134
135 Arguments:
136 FtwLiteDevice - Indicates a pointer to the calling context.
137 TopSwap - New swap state
138
139 Returns:
140 EFI_SUCCESS - The function completed successfully
141
142 Note:
143 the Top-Swap bit (bit 13, D31: F0, Offset D4h). Note that
144 software will not be able to clear the Top-Swap bit until the system is
145 rebooted without GNT[A]# being pulled down.
146
147 --*/
148 {
149 UINT32 GenStatus;
150 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
151 EFI_STATUS Status;
152
153 //
154 // Top-Swap bit (bit 13, D31: F0, Offset D4h)
155 //
156 GenStatus = ReadPciRegister (GEN_STATUS);
157
158 //
159 // Set 13 bit, according to input NewSwapState
160 //
161 if (TopSwap) {
162 GenStatus |= TOP_SWAP_BIT;
163 } else {
164 GenStatus &= ~TOP_SWAP_BIT;
165 }
166
167 Status = gBS->LocateProtocol (&gEfiPciRootBridgeIoProtocolGuid, NULL, (VOID **) &PciRootBridgeIo);
168 if (EFI_ERROR (Status)) {
169 DEBUG ((EFI_D_ERROR, "FtwLite: Locate PCI root bridge io protocol - %r", Status));
170 return Status;
171 }
172 //
173 // Write back the GenStatus register
174 //
175 Status = PciRootBridgeIo->Pci.Write (
176 PciRootBridgeIo,
177 EfiPciWidthUint32,
178 EFI_PCI_ADDRESS (
179 LPC_BUS_NUMBER,
180 LPC_DEVICE_NUMBER,
181 LPC_IF,
182 GEN_STATUS
183 ),
184 1,
185 &GenStatus
186 );
187
188 DEBUG_CODE_BEGIN ();
189 if (TopSwap) {
190 DEBUG ((EFI_D_ERROR, "SAR: Set top swap\n"));
191 } else {
192 DEBUG ((EFI_D_ERROR, "SAR: Clear top swap\n"));
193 }
194 DEBUG_CODE_END ();
195
196 return EFI_SUCCESS;
197 }
198
199 BOOLEAN
200 IsBootBlock (
201 EFI_FTW_LITE_DEVICE *FtwLiteDevice,
202 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
203 EFI_LBA Lba
204 )
205 /*++
206
207 Routine Description:
208
209 Check whether the block is a boot block.
210
211 Arguments:
212
213 FtwLiteDevice - Calling context
214 FvBlock - Fvb protocol instance
215 Lba - Lba value
216
217 Returns:
218
219 Is a boot block or not
220
221 --*/
222 {
223 EFI_STATUS Status;
224 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb;
225
226 Status = GetFvbByAddress (BOOT_BLOCK_BASE, &BootFvb);
227 if (EFI_ERROR (Status)) {
228 return FALSE;
229 }
230 //
231 // Compare the Fvb
232 //
233 return (BOOLEAN) (FvBlock == BootFvb);
234 }
235
236 EFI_STATUS
237 FlushSpareBlockToBootBlock (
238 EFI_FTW_LITE_DEVICE *FtwLiteDevice
239 )
240 /*++
241
242 Routine Description:
243 Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE.
244 Spare block is accessed by FTW backup FVB protocol interface. LBA is
245 FtwLiteDevice->FtwSpareLba.
246 Boot block is accessed by BootFvb protocol interface. LBA is 0.
247
248 Arguments:
249 FtwLiteDevice - The private data of FTW_LITE driver
250
251 Returns:
252 EFI_SUCCESS - Spare block content is copied to boot block
253 EFI_INVALID_PARAMETER - Input parameter error
254 EFI_OUT_OF_RESOURCES - Allocate memory error
255 EFI_ABORTED - The function could not complete successfully
256
257 Notes:
258 FTW will do extra work on boot block update.
259 FTW should depend on a protocol of EFI_ADDRESS_RANGE_SWAP_PROTOCOL,
260 which is produced by a chipset driver.
261
262 FTW updating boot block steps:
263 1. Erase top swap block (0xFFFE-0xFFFEFFFF) and write data to it ready
264 2. Read data from top swap block to memory buffer
265 3. SetSwapState(EFI_SWAPPED)
266 4. Erasing boot block (0xFFFF-0xFFFFFFFF)
267 5. Programming boot block until the boot block is ok.
268 6. SetSwapState(UNSWAPPED)
269
270 Notes:
271 1. Since the SwapState bit is saved in CMOS, FTW can restore and continue
272 even in the scenario of power failure.
273 2. FTW shall not allow to update boot block when battery state is error.
274
275 --*/
276 {
277 EFI_STATUS Status;
278 UINTN Length;
279 UINT8 *Buffer;
280 UINTN Count;
281 UINT8 *Ptr;
282 UINTN Index;
283 BOOLEAN TopSwap;
284 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb;
285 EFI_LBA BootLba;
286
287 //
288 // Allocate a memory buffer
289 //
290 Length = FtwLiteDevice->SpareAreaLength;
291 Buffer = AllocatePool (Length);
292 if (Buffer == NULL) {
293 }
294 //
295 // Get TopSwap bit state
296 //
297 Status = GetSwapState (FtwLiteDevice, &TopSwap);
298 if (EFI_ERROR (Status)) {
299 DEBUG ((EFI_D_ERROR, "FtwLite: Get Top Swapped status - %r\n", Status));
300 FreePool (Buffer);
301 return EFI_ABORTED;
302 }
303
304 if (TopSwap) {
305 //
306 // Get FVB of current boot block
307 //
308 Status = GetFvbByAddress (FtwLiteDevice->SpareAreaAddress + FTW_BLOCK_SIZE, &BootFvb);
309 if (EFI_ERROR (Status)) {
310 FreePool (Buffer);
311 return Status;
312 }
313 //
314 // Read data from current boot block
315 //
316 BootLba = 0;
317 Ptr = Buffer;
318 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
319 Count = FtwLiteDevice->SizeOfSpareBlock;
320 Status = BootFvb->Read (
321 BootFvb,
322 BootLba + Index,
323 0,
324 &Count,
325 Ptr
326 );
327 if (EFI_ERROR (Status)) {
328 FreePool (Buffer);
329 return Status;
330 }
331
332 Ptr += Count;
333 }
334
335 } else {
336 //
337 // Read data from spare block
338 //
339 Ptr = Buffer;
340 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
341 Count = FtwLiteDevice->SizeOfSpareBlock;
342 Status = FtwLiteDevice->FtwBackupFvb->Read (
343 FtwLiteDevice->FtwBackupFvb,
344 FtwLiteDevice->FtwSpareLba + Index,
345 0,
346 &Count,
347 Ptr
348 );
349 if (EFI_ERROR (Status)) {
350 FreePool (Buffer);
351 return Status;
352 }
353
354 Ptr += Count;
355 }
356 //
357 // Set TopSwap bit
358 //
359 Status = SetSwapState (FtwLiteDevice, TRUE);
360 DEBUG ((EFI_D_ERROR, "FtwLite: Set Swap State - %r\n", Status));
361 ASSERT_EFI_ERROR (Status);
362 }
363 //
364 // Erase boot block. After setting TopSwap bit, it's spare block now!
365 //
366 Status = FtwEraseSpareBlock (FtwLiteDevice);
367 if (EFI_ERROR (Status)) {
368 FreePool (Buffer);
369 return EFI_ABORTED;
370 }
371 //
372 // Write memory buffer to currenet spare block
373 //
374 Ptr = Buffer;
375 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
376 Count = FtwLiteDevice->SizeOfSpareBlock;
377 Status = FtwLiteDevice->FtwBackupFvb->Write (
378 FtwLiteDevice->FtwBackupFvb,
379 FtwLiteDevice->FtwSpareLba + Index,
380 0,
381 &Count,
382 Ptr
383 );
384 if (EFI_ERROR (Status)) {
385 DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Write boot block - %r\n", Status));
386 FreePool (Buffer);
387 return Status;
388 }
389
390 Ptr += Count;
391 }
392
393 FreePool (Buffer);
394
395 //
396 // Clear TopSwap bit
397 //
398 Status = SetSwapState (FtwLiteDevice, FALSE);
399 DEBUG ((EFI_D_ERROR, "FtwLite: Clear Swap State - %r\n", Status));
400 ASSERT_EFI_ERROR (Status);
401
402 return EFI_SUCCESS;
403 }