add ia32 and x64 direcotry for EdkFvbServiceLib
[mirror_edk2.git] / MdeModulePkg / Universal / VariableRuntimeDxe / reclaim.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 reclaim.c
15
16 Abstract:
17
18 Handles non-volatile variable store garbage collection, using FTW
19 (Fault Tolerant Write) protocol.
20
21 Revision History
22
23 --*/
24
25
26 #include "reclaim.h"
27 #include "Common/Variable.h"
28
29 EFI_STATUS
30 GetFvbHandleByAddress (
31 IN EFI_PHYSICAL_ADDRESS Address,
32 OUT EFI_HANDLE *FvbHandle
33 )
34 {
35 EFI_STATUS Status;
36 EFI_HANDLE *HandleBuffer;
37 UINTN HandleCount;
38 UINTN Index;
39 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
40 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
41 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
42
43 *FvbHandle = NULL;
44 //
45 // Locate all handles of Fvb protocol
46 //
47 Status = gBS->LocateHandleBuffer (
48 ByProtocol,
49 &gEfiFirmwareVolumeBlockProtocolGuid,
50 NULL,
51 &HandleCount,
52 &HandleBuffer
53 );
54 if (EFI_ERROR (Status)) {
55 return EFI_NOT_FOUND;
56 }
57 //
58 // Get the FVB to access variable store
59 //
60 for (Index = 0; Index < HandleCount; Index += 1) {
61 Status = gBS->HandleProtocol (
62 HandleBuffer[Index],
63 &gEfiFirmwareVolumeBlockProtocolGuid,
64 (VOID **) &Fvb
65 );
66 if (EFI_ERROR (Status)) {
67 Status = EFI_NOT_FOUND;
68 break;
69 }
70 //
71 // Compare the address and select the right one
72 //
73 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
74 if (EFI_ERROR (Status)) {
75 continue;
76 }
77
78 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
79 if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) {
80 *FvbHandle = HandleBuffer[Index];
81 Status = EFI_SUCCESS;
82 break;
83 }
84 }
85
86 FreePool (HandleBuffer);
87 return Status;
88 }
89
90 STATIC
91 EFI_STATUS
92 GetLbaAndOffsetByAddress (
93 IN EFI_PHYSICAL_ADDRESS Address,
94 OUT EFI_LBA *Lba,
95 OUT UINTN *Offset
96 )
97 {
98 EFI_STATUS Status;
99 EFI_HANDLE FvbHandle;
100 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
101 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
102 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
103 EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;
104 UINT32 LbaIndex;
105
106 *Lba = (EFI_LBA) (-1);
107 *Offset = 0;
108
109 //
110 // Get the proper FVB
111 //
112 Status = GetFvbHandleByAddress (Address, &FvbHandle);
113 if (EFI_ERROR (Status)) {
114 return Status;
115 }
116
117 Status = gBS->HandleProtocol (
118 FvbHandle,
119 &gEfiFirmwareVolumeBlockProtocolGuid,
120 (VOID **) &Fvb
121 );
122 if (EFI_ERROR (Status)) {
123 return Status;
124 }
125 //
126 // Get the Base Address of FV
127 //
128 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
129 if (EFI_ERROR (Status)) {
130 return Status;
131 }
132
133 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
134
135 //
136 // Get the (LBA, Offset) of Address
137 //
138 if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) {
139 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
140 //
141 // BUGBUG: Assume one FV has one type of BlockLength
142 //
143 FvbMapEntry = &FwVolHeader->BlockMap[0];
144 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
145 if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) {
146 //
147 // Found the (Lba, Offset)
148 //
149 *Lba = LbaIndex - 1;
150 *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
151 return EFI_SUCCESS;
152 }
153 }
154 }
155 }
156
157 return EFI_ABORTED;
158 }
159
160 EFI_STATUS
161 FtwVariableSpace (
162 IN EFI_PHYSICAL_ADDRESS VariableBase,
163 IN UINT8 *Buffer,
164 IN UINTN BufferSize
165 )
166 /*++
167
168 Routine Description:
169 Write a buffer to Variable space, in the working block.
170
171 Arguments:
172 FvbHandle - Indicates a handle to FVB to access variable store
173 Buffer - Point to the input buffer
174 BufferSize - The number of bytes of the input Buffer
175
176 Returns:
177 EFI_SUCCESS - The function completed successfully
178 EFI_ABORTED - The function could not complete successfully
179 EFI_NOT_FOUND - Locate FVB protocol by handle fails
180
181 --*/
182 {
183 EFI_STATUS Status;
184 EFI_HANDLE FvbHandle;
185 EFI_FTW_LITE_PROTOCOL *FtwLiteProtocol;
186 EFI_LBA VarLba;
187 UINTN VarOffset;
188 UINT8 *FtwBuffer;
189 UINTN FtwBufferSize;
190
191 //
192 // Locate fault tolerant write protocol
193 //
194 Status = gBS->LocateProtocol (
195 &gEfiFaultTolerantWriteLiteProtocolGuid,
196 NULL,
197 (VOID **) &FtwLiteProtocol
198 );
199 if (EFI_ERROR (Status)) {
200 return EFI_NOT_FOUND;
201 }
202 //
203 // Locate Fvb handle by address
204 //
205 Status = GetFvbHandleByAddress (VariableBase, &FvbHandle);
206 if (EFI_ERROR (Status)) {
207 return Status;
208 }
209 //
210 // Get LBA and Offset by address
211 //
212 Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset);
213 if (EFI_ERROR (Status)) {
214 return EFI_ABORTED;
215 }
216 //
217 // Prepare for the variable data
218 //
219 FtwBufferSize = ((VARIABLE_STORE_HEADER *) ((UINTN) VariableBase))->Size;
220 FtwBuffer = AllocateRuntimePool (FtwBufferSize);
221 if (FtwBuffer == NULL) {
222 return EFI_OUT_OF_RESOURCES;
223 }
224
225 SetMem (FtwBuffer, FtwBufferSize, (UINT8) 0xff);
226 CopyMem (FtwBuffer, Buffer, BufferSize);
227
228 //
229 // FTW write record
230 //
231 Status = FtwLiteProtocol->Write (
232 FtwLiteProtocol,
233 FvbHandle,
234 VarLba, // LBA
235 VarOffset, // Offset
236 &FtwBufferSize, // NumBytes,
237 FtwBuffer
238 );
239
240 FreePool (FtwBuffer);
241 return Status;
242 }