]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/LockBoxLib/LockBoxLib.c
OvmfPkg/Virtio: take RingBaseShift in SetQueueAddress()
[mirror_edk2.git] / OvmfPkg / Library / LockBoxLib / LockBoxLib.c
1 /** @file
2
3 Library implementing the LockBox interface for OVMF
4
5 Copyright (C) 2013, Red Hat, Inc.
6 Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
7
8 This program and the accompanying materials are licensed and made available
9 under the terms and conditions of the BSD License which accompanies this
10 distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
14 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16 **/
17
18 #include <Uefi.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/LockBoxLib.h>
22 #include <Library/PcdLib.h>
23 #include <LockBoxLib.h>
24
25 #pragma pack(1)
26 typedef struct {
27 EFI_GUID Guid;
28 EFI_PHYSICAL_ADDRESS OrigAddress;
29 EFI_PHYSICAL_ADDRESS CopyAddress;
30 UINT32 Size;
31 UINT64 Attributes;
32 } LOCK_BOX_ENTRY;
33 #pragma pack()
34
35 LOCK_BOX_GLOBAL *mLockBoxGlobal = NULL;
36 STATIC LOCK_BOX_ENTRY *StartOfEntries = NULL;
37 STATIC LOCK_BOX_ENTRY *EndOfEntries = NULL;
38
39 RETURN_STATUS
40 EFIAPI
41 LockBoxLibInitialize (
42 VOID
43 )
44 {
45 UINTN NumEntries;
46
47 ASSERT (!FeaturePcdGet (PcdSmmSmramRequire));
48
49 if (PcdGet32 (PcdOvmfLockBoxStorageSize) < sizeof (LOCK_BOX_GLOBAL)) {
50 return RETURN_UNSUPPORTED;
51 }
52
53 mLockBoxGlobal = (LOCK_BOX_GLOBAL *)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase);
54 StartOfEntries = ((LOCK_BOX_ENTRY *) (mLockBoxGlobal + 1));
55 NumEntries = ((PcdGet32 (PcdOvmfLockBoxStorageSize) - sizeof (LOCK_BOX_GLOBAL)) /
56 sizeof (LOCK_BOX_ENTRY));
57 EndOfEntries = StartOfEntries + NumEntries;
58 if (mLockBoxGlobal->Signature != LOCK_BOX_GLOBAL_SIGNATURE) {
59 //
60 // Note: This code depends on the lock box being cleared in early
61 // PEI before usage, so the SubPageBuffer and SubPageRemaining
62 // fields don't need to be set to 0.
63 //
64 mLockBoxGlobal->Signature = LOCK_BOX_GLOBAL_SIGNATURE;
65 }
66 return RETURN_SUCCESS;
67 }
68
69
70 /**
71 Find LockBox entry based on GUID.
72
73 @param[in] Guid The GUID to search for.
74
75 @return Address of the LOCK_BOX_ENTRY found.
76
77 If NULL, then the item was not found, and there is no space
78 left to store a new item.
79
80 If non-NULL and LOCK_BOX_ENTRY.Size == 0, then the item was not
81 found, but a new item can be inserted at the returned location.
82
83 If non-NULL and LOCK_BOX_ENTRY.Size > 0, then the item was found.
84 **/
85 STATIC
86 LOCK_BOX_ENTRY *
87 EFIAPI
88 FindHeaderByGuid (
89 IN CONST EFI_GUID *Guid
90 )
91 {
92 LOCK_BOX_ENTRY *Header;
93
94 for (Header = StartOfEntries; Header < EndOfEntries; Header++) {
95 if (Header->Size == 0 || CompareGuid (Guid, &Header->Guid)) {
96 return Header;
97 }
98 }
99
100 return NULL;
101 }
102
103
104 /**
105 This function will save confidential information to lockbox.
106
107 @param Guid the guid to identify the confidential information
108 @param Buffer the address of the confidential information
109 @param Length the length of the confidential information
110
111 @retval RETURN_SUCCESS the information is saved successfully.
112 @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or
113 Length is 0
114 @retval RETURN_ALREADY_STARTED the requested GUID already exist.
115 @retval RETURN_OUT_OF_RESOURCES no enough resource to save the information.
116 @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
117 @retval RETURN_NOT_STARTED it is too early to invoke this interface
118 @retval RETURN_UNSUPPORTED the service is not supported by
119 implementaion.
120 **/
121 RETURN_STATUS
122 EFIAPI
123 SaveLockBox (
124 IN GUID *Guid,
125 IN VOID *Buffer,
126 IN UINTN Length
127 )
128 {
129 LOCK_BOX_ENTRY *Header;
130 VOID *CopyBuffer;
131
132 DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Buffer=%p Length=0x%x\n", __FUNCTION__,
133 Guid, Buffer, (UINT32) Length));
134
135 if (Guid == NULL || Buffer == NULL || Length == 0) {
136 return RETURN_INVALID_PARAMETER;
137 }
138
139 if (Length > 0xFFFFFFFF) {
140 return RETURN_OUT_OF_RESOURCES;
141 }
142
143 Header = FindHeaderByGuid (Guid);
144 if (Header == NULL) {
145 return RETURN_OUT_OF_RESOURCES;
146 }
147
148 if (Header->Size > 0) {
149 return RETURN_ALREADY_STARTED;
150 }
151
152 CopyBuffer = AllocateAcpiNvsPool (Length);
153 if (CopyBuffer == NULL) {
154 return RETURN_OUT_OF_RESOURCES;
155 }
156
157 //
158 // overwrite the current terminator header with new metadata
159 //
160 CopyGuid (&Header->Guid, Guid);
161 Header->OrigAddress = (UINTN) Buffer;
162 Header->CopyAddress = (UINTN) CopyBuffer;
163 Header->Size = (UINT32) Length;
164 Header->Attributes = 0;
165
166 //
167 // copy contents
168 //
169 CopyMem (CopyBuffer, Buffer, Length);
170
171 return RETURN_SUCCESS;
172 }
173
174
175 /**
176 This function will set lockbox attributes.
177
178 @param Guid the guid to identify the confidential information
179 @param Attributes the attributes of the lockbox
180
181 @retval RETURN_SUCCESS the information is saved successfully.
182 @retval RETURN_INVALID_PARAMETER attributes is invalid.
183 @retval RETURN_NOT_FOUND the requested GUID not found.
184 @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
185 @retval RETURN_NOT_STARTED it is too early to invoke this interface
186 @retval RETURN_UNSUPPORTED the service is not supported by
187 implementaion.
188 **/
189 RETURN_STATUS
190 EFIAPI
191 SetLockBoxAttributes (
192 IN GUID *Guid,
193 IN UINT64 Attributes
194 )
195 {
196 LOCK_BOX_ENTRY *Header;
197
198 DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Attributes=0x%Lx\n", __FUNCTION__, Guid,
199 Attributes));
200
201 if (Guid == NULL) {
202 return RETURN_INVALID_PARAMETER;
203 }
204
205 Header = FindHeaderByGuid (Guid);
206 if (!Header || Header->Size == 0) {
207 return RETURN_NOT_FOUND;
208 }
209 Header->Attributes = Attributes;
210
211 return RETURN_SUCCESS;
212 }
213
214
215 /**
216 This function will update confidential information to lockbox.
217
218 @param Guid the guid to identify the original confidential information
219 @param Offset the offset of the original confidential information
220 @param Buffer the address of the updated confidential information
221 @param Length the length of the updated confidential information
222
223 @retval RETURN_SUCCESS the information is saved successfully.
224 @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or
225 Length is 0.
226 @retval RETURN_NOT_FOUND the requested GUID not found.
227 @retval RETURN_BUFFER_TOO_SMALL the original buffer to too small to hold
228 new information.
229 @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
230 @retval RETURN_NOT_STARTED it is too early to invoke this interface
231 @retval RETURN_UNSUPPORTED the service is not supported by
232 implementaion.
233 **/
234 RETURN_STATUS
235 EFIAPI
236 UpdateLockBox (
237 IN GUID *Guid,
238 IN UINTN Offset,
239 IN VOID *Buffer,
240 IN UINTN Length
241 )
242 {
243 LOCK_BOX_ENTRY *Header;
244
245 DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Offset=0x%x Length=0x%x\n", __FUNCTION__,
246 Guid, (UINT32) Offset, (UINT32) Length));
247
248 if (Guid == NULL || Buffer == NULL || Length == 0) {
249 return RETURN_INVALID_PARAMETER;
250 }
251
252 Header = FindHeaderByGuid (Guid);
253 if (!Header || Header->Size == 0) {
254 return RETURN_NOT_FOUND;
255 }
256
257 if (Header->Size < Offset ||
258 Length > Header->Size - Offset) {
259 return RETURN_BUFFER_TOO_SMALL;
260 }
261
262 CopyMem ((UINT8 *)(UINTN) (Header->CopyAddress) + Offset, Buffer, Length);
263
264 return RETURN_SUCCESS;
265 }
266
267
268 /**
269 This function will restore confidential information from lockbox.
270
271 @param Guid the guid to identify the confidential information
272 @param Buffer the address of the restored confidential information
273 NULL means restored to original address, Length MUST be NULL at
274 same time.
275 @param Length the length of the restored confidential information
276
277 @retval RETURN_SUCCESS the information is restored successfully.
278 @retval RETURN_INVALID_PARAMETER the Guid is NULL, or one of Buffer and
279 Length is NULL.
280 @retval RETURN_WRITE_PROTECTED Buffer and Length are NULL, but the LockBox
281 has no LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE
282 attribute.
283 @retval RETURN_BUFFER_TOO_SMALL the Length is too small to hold the
284 confidential information.
285 @retval RETURN_NOT_FOUND the requested GUID not found.
286 @retval RETURN_NOT_STARTED it is too early to invoke this interface
287 @retval RETURN_ACCESS_DENIED not allow to restore to the address
288 @retval RETURN_UNSUPPORTED the service is not supported by
289 implementaion.
290 **/
291 RETURN_STATUS
292 EFIAPI
293 RestoreLockBox (
294 IN GUID *Guid,
295 IN VOID *Buffer, OPTIONAL
296 IN OUT UINTN *Length OPTIONAL
297 )
298 {
299 LOCK_BOX_ENTRY *Header;
300
301 DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Buffer=%p\n", __FUNCTION__, Guid,
302 Buffer));
303
304 if ((Guid == NULL) ||
305 ((Buffer == NULL) && (Length != NULL)) ||
306 ((Buffer != NULL) && (Length == NULL))) {
307 return EFI_INVALID_PARAMETER;
308 }
309
310 Header = FindHeaderByGuid (Guid);
311 if (!Header || Header->Size == 0) {
312 return RETURN_NOT_FOUND;
313 }
314
315 if (Buffer == NULL) {
316 if (!(Header->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE)) {
317 return RETURN_WRITE_PROTECTED;
318 }
319 if (Header->OrigAddress + (Header->Size - 1) > MAX_ADDRESS) {
320 return RETURN_UNSUPPORTED;
321 }
322 Buffer = (VOID *)(UINTN) Header->OrigAddress;
323 }
324
325 //
326 // Set RestoreLength
327 //
328 if (Length != NULL) {
329 if (Header->Size > *Length) {
330 //
331 // Input buffer is too small to hold all data.
332 //
333 *Length = Header->Size;
334 return EFI_BUFFER_TOO_SMALL;
335 }
336 *Length = Header->Size;
337 }
338
339 CopyMem (Buffer, (VOID*)(UINTN) Header->CopyAddress, Header->Size);
340
341 return RETURN_SUCCESS;
342 }
343
344
345 /**
346 This function will restore confidential information from all lockbox which
347 have RestoreInPlace attribute.
348
349 @retval RETURN_SUCCESS the information is restored successfully.
350 @retval RETURN_NOT_STARTED it is too early to invoke this interface
351 @retval RETURN_UNSUPPORTED the service is not supported by
352 implementaion.
353 **/
354 RETURN_STATUS
355 EFIAPI
356 RestoreAllLockBoxInPlace (
357 VOID
358 )
359 {
360 LOCK_BOX_ENTRY *Header;
361
362 for (Header = StartOfEntries;
363 Header < EndOfEntries && Header->Size > 0;
364 Header++) {
365 if (Header->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) {
366 VOID *Buffer;
367
368 if (Header->OrigAddress + (Header->Size - 1) > MAX_ADDRESS) {
369 return RETURN_UNSUPPORTED;
370 }
371 Buffer = (VOID *)(UINTN) Header->OrigAddress;
372 CopyMem (Buffer, (VOID*)(UINTN)Header->CopyAddress, Header->Size);
373 DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Buffer=%p\n", __FUNCTION__,
374 &Header->Guid, Buffer));
375 }
376 }
377 return RETURN_SUCCESS;
378 }