2 Misc library functions.
4 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "InternalBm.h"
18 Delete the instance in Multi which matches partly with Single instance
20 @param Multi A pointer to a multi-instance device path data
22 @param Single A pointer to a single-instance device path data
25 @return This function will remove the device path instances in Multi which partly
26 match with the Single, and return the result device path. If there is no
27 remaining device path as a result, this function will return NULL.
30 EFI_DEVICE_PATH_PROTOCOL
*
31 BmDelPartMatchInstance (
32 IN EFI_DEVICE_PATH_PROTOCOL
*Multi
,
33 IN EFI_DEVICE_PATH_PROTOCOL
*Single
36 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
37 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
38 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
43 TempNewDevicePath
= NULL
;
45 if (Multi
== NULL
|| Single
== NULL
) {
49 Instance
= GetNextDevicePathInstance (&Multi
, &InstanceSize
);
50 SingleDpSize
= GetDevicePathSize (Single
) - END_DEVICE_PATH_LENGTH
;
51 InstanceSize
-= END_DEVICE_PATH_LENGTH
;
53 while (Instance
!= NULL
) {
55 if (CompareMem (Instance
, Single
, MIN (SingleDpSize
, InstanceSize
)) != 0) {
57 // Append the device path instance which does not match with Single
59 TempNewDevicePath
= NewDevicePath
;
60 NewDevicePath
= AppendDevicePathInstance (NewDevicePath
, Instance
);
61 if (TempNewDevicePath
!= NULL
) {
62 FreePool(TempNewDevicePath
);
66 Instance
= GetNextDevicePathInstance (&Multi
, &InstanceSize
);
67 InstanceSize
-= END_DEVICE_PATH_LENGTH
;
74 Function compares a device path data structure to that of all the nodes of a
75 second device path instance.
77 @param Multi A pointer to a multi-instance device path data
79 @param Single A pointer to a single-instance device path data
82 @retval TRUE If the Single device path is contained within Multi device path.
83 @retval FALSE The Single device path is not match within Multi device path.
88 IN EFI_DEVICE_PATH_PROTOCOL
*Multi
,
89 IN EFI_DEVICE_PATH_PROTOCOL
*Single
92 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
93 EFI_DEVICE_PATH_PROTOCOL
*DevicePathInst
;
96 if (Multi
== NULL
|| Single
== NULL
) {
101 DevicePathInst
= GetNextDevicePathInstance (&DevicePath
, &Size
);
104 // Search for the match of 'Single' in 'Multi'
106 while (DevicePathInst
!= NULL
) {
108 // If the single device path is found in multiple device paths,
111 if (CompareMem (Single
, DevicePathInst
, Size
) == 0) {
112 FreePool (DevicePathInst
);
116 FreePool (DevicePathInst
);
117 DevicePathInst
= GetNextDevicePathInstance (&DevicePath
, &Size
);
124 Get the headers (dos, image, optional header) from an image
126 @param Device SimpleFileSystem device handle
127 @param FileName File name for the image
128 @param DosHeader Pointer to dos header
129 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
131 @retval EFI_SUCCESS Successfully get the machine type.
132 @retval EFI_NOT_FOUND The file is not found.
133 @retval EFI_LOAD_ERROR File is not a valid image file.
138 IN EFI_HANDLE Device
,
140 OUT EFI_IMAGE_DOS_HEADER
*DosHeader
,
141 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
145 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Volume
;
146 EFI_FILE_HANDLE Root
;
147 EFI_FILE_HANDLE ThisFile
;
155 // Handle the file system interface to the device
157 Status
= gBS
->HandleProtocol (
159 &gEfiSimpleFileSystemProtocolGuid
,
162 if (EFI_ERROR (Status
)) {
166 Status
= Volume
->OpenVolume (
170 if (EFI_ERROR (Status
)) {
174 ASSERT (Root
!= NULL
);
175 Status
= Root
->Open (Root
, &ThisFile
, FileName
, EFI_FILE_MODE_READ
, 0);
176 if (EFI_ERROR (Status
)) {
179 ASSERT (ThisFile
!= NULL
);
184 BufferSize
= SIZE_OF_EFI_FILE_INFO
+ 200;
187 Status
= gBS
->AllocatePool (EfiBootServicesData
, BufferSize
, (VOID
**) &Info
);
188 if (EFI_ERROR (Status
)) {
191 Status
= ThisFile
->GetInfo (
197 if (!EFI_ERROR (Status
)) {
200 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
207 FileSize
= Info
->FileSize
;
213 BufferSize
= sizeof (EFI_IMAGE_DOS_HEADER
);
214 Status
= ThisFile
->Read (ThisFile
, &BufferSize
, DosHeader
);
215 if (EFI_ERROR (Status
) ||
216 BufferSize
< sizeof (EFI_IMAGE_DOS_HEADER
) ||
217 FileSize
<= DosHeader
->e_lfanew
||
218 DosHeader
->e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
219 Status
= EFI_LOAD_ERROR
;
224 // Move to PE signature
226 Status
= ThisFile
->SetPosition (ThisFile
, DosHeader
->e_lfanew
);
227 if (EFI_ERROR (Status
)) {
228 Status
= EFI_LOAD_ERROR
;
233 // Read and check PE signature
235 BufferSize
= sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
);
236 Status
= ThisFile
->Read (ThisFile
, &BufferSize
, Hdr
.Pe32
);
237 if (EFI_ERROR (Status
) ||
238 BufferSize
< sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
) ||
239 Hdr
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
240 Status
= EFI_LOAD_ERROR
;
245 // Check PE32 or PE32+ magic
247 if (Hdr
.Pe32
->OptionalHeader
.Magic
!= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
&&
248 Hdr
.Pe32
->OptionalHeader
.Magic
!= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
249 Status
= EFI_LOAD_ERROR
;
254 if (ThisFile
!= NULL
) {
255 ThisFile
->Close (ThisFile
);
264 This routine adjust the memory information for different memory type and
265 save them into the variables for next boot.
268 BmSetMemoryTypeInformationVariable (
273 EFI_MEMORY_TYPE_INFORMATION
*PreviousMemoryTypeInformation
;
274 EFI_MEMORY_TYPE_INFORMATION
*CurrentMemoryTypeInformation
;
281 EFI_HOB_GUID_TYPE
*GuidHob
;
282 BOOLEAN MemoryTypeInformationModified
;
283 BOOLEAN MemoryTypeInformationVariableExists
;
284 EFI_BOOT_MODE BootMode
;
286 MemoryTypeInformationModified
= FALSE
;
287 MemoryTypeInformationVariableExists
= FALSE
;
290 BootMode
= GetBootModeHob ();
292 // In BOOT_IN_RECOVERY_MODE, Variable region is not reliable.
294 if (BootMode
== BOOT_IN_RECOVERY_MODE
) {
299 // Only check the the Memory Type Information variable in the boot mode
300 // other than BOOT_WITH_DEFAULT_SETTINGS because the Memory Type
301 // Information is not valid in this boot mode.
303 if (BootMode
!= BOOT_WITH_DEFAULT_SETTINGS
) {
305 Status
= gRT
->GetVariable (
306 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME
,
307 &gEfiMemoryTypeInformationGuid
,
312 if (Status
== EFI_BUFFER_TOO_SMALL
) {
313 MemoryTypeInformationVariableExists
= TRUE
;
318 // Retrieve the current memory usage statistics. If they are not found, then
319 // no adjustments can be made to the Memory Type Information variable.
321 Status
= EfiGetSystemConfigurationTable (
322 &gEfiMemoryTypeInformationGuid
,
323 (VOID
**) &CurrentMemoryTypeInformation
325 if (EFI_ERROR (Status
) || CurrentMemoryTypeInformation
== NULL
) {
330 // Get the Memory Type Information settings from Hob if they exist,
331 // PEI is responsible for getting them from variable and build a Hob to save them.
332 // If the previous Memory Type Information is not available, then set defaults
334 GuidHob
= GetFirstGuidHob (&gEfiMemoryTypeInformationGuid
);
335 if (GuidHob
== NULL
) {
337 // If Platform has not built Memory Type Info into the Hob, just return.
341 PreviousMemoryTypeInformation
= GET_GUID_HOB_DATA (GuidHob
);
342 VariableSize
= GET_GUID_HOB_DATA_SIZE (GuidHob
);
345 // Use a heuristic to adjust the Memory Type Information for the next boot
347 DEBUG ((EFI_D_INFO
, "Memory Previous Current Next \n"));
348 DEBUG ((EFI_D_INFO
, " Type Pages Pages Pages \n"));
349 DEBUG ((EFI_D_INFO
, "====== ======== ======== ========\n"));
351 for (Index
= 0; PreviousMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
353 for (Index1
= 0; CurrentMemoryTypeInformation
[Index1
].Type
!= EfiMaxMemoryType
; Index1
++) {
354 if (PreviousMemoryTypeInformation
[Index
].Type
== CurrentMemoryTypeInformation
[Index1
].Type
) {
358 if (CurrentMemoryTypeInformation
[Index1
].Type
== EfiMaxMemoryType
) {
363 // Previous is the number of pages pre-allocated
364 // Current is the number of pages actually needed
366 Previous
= PreviousMemoryTypeInformation
[Index
].NumberOfPages
;
367 Current
= CurrentMemoryTypeInformation
[Index1
].NumberOfPages
;
371 // Inconsistent Memory Reserved across bootings may lead to S4 fail
372 // Write next varible to 125% * current when the pre-allocated memory is:
373 // 1. More than 150% of needed memory and boot mode is BOOT_WITH_DEFAULT_SETTING
374 // 2. Less than the needed memory
376 if ((Current
+ (Current
>> 1)) < Previous
) {
377 if (BootMode
== BOOT_WITH_DEFAULT_SETTINGS
) {
378 Next
= Current
+ (Current
>> 2);
380 } else if (Current
> Previous
) {
381 Next
= Current
+ (Current
>> 2);
383 if (Next
> 0 && Next
< 4) {
387 if (Next
!= Previous
) {
388 PreviousMemoryTypeInformation
[Index
].NumberOfPages
= Next
;
389 MemoryTypeInformationModified
= TRUE
;
392 DEBUG ((EFI_D_INFO
, " %02x %08x %08x %08x\n", PreviousMemoryTypeInformation
[Index
].Type
, Previous
, Current
, Next
));
396 // If any changes were made to the Memory Type Information settings, then set the new variable value;
397 // Or create the variable in first boot.
399 if (MemoryTypeInformationModified
|| !MemoryTypeInformationVariableExists
) {
400 Status
= BmSetVariableAndReportStatusCodeOnError (
401 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME
,
402 &gEfiMemoryTypeInformationGuid
,
403 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
405 PreviousMemoryTypeInformation
408 if (!EFI_ERROR (Status
)) {
410 // If the Memory Type Information settings have been modified, then reset the platform
411 // so the new Memory Type Information setting will be used to guarantee that an S4
412 // entry/resume cycle will not fail.
414 if (MemoryTypeInformationModified
) {
415 DEBUG ((EFI_D_INFO
, "Memory Type Information settings change. Warm Reset!!!\n"));
416 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
419 DEBUG ((EFI_D_ERROR
, "Memory Type Information settings cannot be saved. OS S4 may fail!\n"));
425 Set the variable and report the error through status code upon failure.
427 @param VariableName A Null-terminated string that is the name of the vendor's variable.
428 Each VariableName is unique for each VendorGuid. VariableName must
429 contain 1 or more characters. If VariableName is an empty string,
430 then EFI_INVALID_PARAMETER is returned.
431 @param VendorGuid A unique identifier for the vendor.
432 @param Attributes Attributes bitmask to set for the variable.
433 @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,
434 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or
435 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
436 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
437 set, then a SetVariable() call with a DataSize of zero will not cause any change to
438 the variable value (the timestamp associated with the variable may be updated however
439 even if no new data value is provided,see the description of the
440 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
441 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
442 @param Data The contents for the variable.
444 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
445 defined by the Attributes.
446 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the
447 DataSize exceeds the maximum allowed.
448 @retval EFI_INVALID_PARAMETER VariableName is an empty string.
449 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
450 @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
451 @retval EFI_WRITE_PROTECTED The variable in question is read-only.
452 @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
453 @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
454 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo
455 does NOT pass the validation check carried out by the firmware.
457 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
460 BmSetVariableAndReportStatusCodeOnError (
461 IN CHAR16
*VariableName
,
462 IN EFI_GUID
*VendorGuid
,
463 IN UINT32 Attributes
,
469 EDKII_SET_VARIABLE_STATUS
*SetVariableStatus
;
472 Status
= gRT
->SetVariable (
479 if (EFI_ERROR (Status
)) {
480 NameSize
= StrSize (VariableName
);
481 SetVariableStatus
= AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS
) + NameSize
+ DataSize
);
482 if (SetVariableStatus
!= NULL
) {
483 CopyGuid (&SetVariableStatus
->Guid
, VendorGuid
);
484 SetVariableStatus
->NameSize
= NameSize
;
485 SetVariableStatus
->DataSize
= DataSize
;
486 SetVariableStatus
->SetStatus
= Status
;
487 SetVariableStatus
->Attributes
= Attributes
;
488 CopyMem (SetVariableStatus
+ 1, VariableName
, NameSize
);
489 CopyMem (((UINT8
*) (SetVariableStatus
+ 1)) + NameSize
, Data
, DataSize
);
491 REPORT_STATUS_CODE_EX (
493 PcdGet32 (PcdErrorCodeSetVariable
),
496 &gEdkiiStatusCodeDataTypeVariableGuid
,
498 sizeof (EDKII_SET_VARIABLE_STATUS
) + NameSize
+ DataSize
501 FreePool (SetVariableStatus
);