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 } 379