]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
MdeModulePkg: Add the alignment check for FTW spare area address and length, and...
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Reclaim.c
1 /** @file
2
3 Handles non-volatile variable store garbage collection, using FTW
4 (Fault Tolerant Write) protocol.
5
6 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "Variable.h"
18
19 /**
20 Gets LBA of block and offset by given address.
21
22 This function gets the Logical Block Address (LBA) of a firmware
23 volume block containing the given address, and the offset of the
24 address on the block.
25
26 @param Address Address which should be contained
27 by returned FVB handle.
28 @param Lba Pointer to LBA for output.
29 @param Offset Pointer to offset for output.
30
31 @retval EFI_SUCCESS LBA and offset successfully returned.
32 @retval EFI_NOT_FOUND Fail to find FVB handle by address.
33 @retval EFI_ABORTED Fail to find valid LBA and offset.
34
35 **/
36 EFI_STATUS
37 GetLbaAndOffsetByAddress (
38 IN EFI_PHYSICAL_ADDRESS Address,
39 OUT EFI_LBA *Lba,
40 OUT UINTN *Offset
41 )
42 {
43 EFI_STATUS Status;
44 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
45 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
46 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
47 EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;
48 UINT32 LbaIndex;
49
50 *Lba = (EFI_LBA) (-1);
51 *Offset = 0;
52
53 //
54 // Get the proper FVB protocol.
55 //
56 Status = GetFvbInfoByAddress (Address, NULL, &Fvb);
57 if (EFI_ERROR (Status)) {
58 return Status;
59 }
60
61 //
62 // Get the Base Address of FV.
63 //
64 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
65 if (EFI_ERROR (Status)) {
66 return Status;
67 }
68
69 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
70
71 //
72 // Get the (LBA, Offset) of Address.
73 //
74 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
75 //
76 // BUGBUG: Assume one FV has one type of BlockLength.
77 //
78 FvbMapEntry = &FwVolHeader->BlockMap[0];
79 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
80 if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) {
81 //
82 // Found the (Lba, Offset).
83 //
84 *Lba = LbaIndex - 1;
85 *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
86 return EFI_SUCCESS;
87 }
88 }
89 }
90
91 return EFI_ABORTED;
92 }
93
94 /**
95 Writes a buffer to variable storage space, in the working block.
96
97 This function writes a buffer to variable storage space into a firmware
98 volume block device. The destination is specified by parameter
99 VariableBase. Fault Tolerant Write protocol is used for writing.
100
101 @param VariableBase Base address of variable to write
102 @param Buffer Point to the data buffer.
103 @param BufferSize The number of bytes of the data Buffer.
104
105 @retval EFI_SUCCESS The function completed successfully.
106 @retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol.
107 @retval EFI_ABORTED The function could not complete successfully.
108
109 **/
110 EFI_STATUS
111 FtwVariableSpace (
112 IN EFI_PHYSICAL_ADDRESS VariableBase,
113 IN UINT8 *Buffer,
114 IN UINTN BufferSize
115 )
116 {
117 EFI_STATUS Status;
118 EFI_HANDLE FvbHandle;
119 EFI_LBA VarLba;
120 UINTN VarOffset;
121 UINT8 *FtwBuffer;
122 UINTN FtwBufferSize;
123 EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
124
125 //
126 // Locate fault tolerant write protocol.
127 //
128 Status = GetFtwProtocol((VOID **) &FtwProtocol);
129 if (EFI_ERROR (Status)) {
130 return EFI_NOT_FOUND;
131 }
132 //
133 // Locate Fvb handle by address.
134 //
135 Status = GetFvbInfoByAddress (VariableBase, &FvbHandle, NULL);
136 if (EFI_ERROR (Status)) {
137 return Status;
138 }
139 //
140 // Get LBA and Offset by address.
141 //
142 Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset);
143 if (EFI_ERROR (Status)) {
144 return EFI_ABORTED;
145 }
146 //
147 // Prepare for the variable data.
148 //
149 FtwBufferSize = ((VARIABLE_STORE_HEADER *) ((UINTN) VariableBase))->Size;
150 FtwBuffer = AllocatePool (FtwBufferSize);
151 if (FtwBuffer == NULL) {
152 return EFI_OUT_OF_RESOURCES;
153 }
154
155 SetMem (FtwBuffer, FtwBufferSize, (UINT8) 0xff);
156 CopyMem (FtwBuffer, Buffer, BufferSize);
157
158 //
159 // FTW write record.
160 //
161 Status = FtwProtocol->Write (
162 FtwProtocol,
163 VarLba, // LBA
164 VarOffset, // Offset
165 FtwBufferSize, // NumBytes
166 NULL, // PrivateData NULL
167 FvbHandle, // Fvb Handle
168 FtwBuffer // write buffer
169 );
170
171 FreePool (FtwBuffer);
172 return Status;
173 }