]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c
UefiCpuPkg CpuDxe: Add nasm source file in CpuDxe.inf
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmMisc.c
CommitLineData
067ed98a
RN
1/** @file\r
2 Misc library functions.\r
3\r
4Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
fb5848c5 5(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
067ed98a
RN
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "InternalBm.h"\r
17\r
18/**\r
19 Delete the instance in Multi which matches partly with Single instance\r
20\r
21 @param Multi A pointer to a multi-instance device path data\r
22 structure.\r
23 @param Single A pointer to a single-instance device path data\r
24 structure.\r
25\r
26 @return This function will remove the device path instances in Multi which partly\r
27 match with the Single, and return the result device path. If there is no\r
28 remaining device path as a result, this function will return NULL.\r
29\r
30**/\r
31EFI_DEVICE_PATH_PROTOCOL *\r
32BmDelPartMatchInstance (\r
33 IN EFI_DEVICE_PATH_PROTOCOL *Multi,\r
34 IN EFI_DEVICE_PATH_PROTOCOL *Single\r
35 )\r
36{\r
37 EFI_DEVICE_PATH_PROTOCOL *Instance;\r
38 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
39 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;\r
40 UINTN InstanceSize;\r
41 UINTN SingleDpSize;\r
42\r
43 NewDevicePath = NULL;\r
44 TempNewDevicePath = NULL;\r
45\r
46 if (Multi == NULL || Single == NULL) {\r
47 return Multi;\r
48 }\r
49\r
50 Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);\r
51 SingleDpSize = GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH;\r
52 InstanceSize -= END_DEVICE_PATH_LENGTH;\r
53\r
54 while (Instance != NULL) {\r
55\r
56 if (CompareMem (Instance, Single, MIN (SingleDpSize, InstanceSize)) != 0) {\r
57 //\r
58 // Append the device path instance which does not match with Single\r
59 //\r
60 TempNewDevicePath = NewDevicePath;\r
61 NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance);\r
62 if (TempNewDevicePath != NULL) {\r
63 FreePool(TempNewDevicePath);\r
64 }\r
65 }\r
66 FreePool(Instance);\r
67 Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);\r
68 InstanceSize -= END_DEVICE_PATH_LENGTH;\r
69 }\r
70\r
71 return NewDevicePath;\r
72}\r
73\r
74/**\r
75 Function compares a device path data structure to that of all the nodes of a\r
76 second device path instance.\r
77\r
78 @param Multi A pointer to a multi-instance device path data\r
79 structure.\r
80 @param Single A pointer to a single-instance device path data\r
81 structure.\r
82\r
83 @retval TRUE If the Single device path is contained within Multi device path.\r
84 @retval FALSE The Single device path is not match within Multi device path.\r
85\r
86**/\r
87BOOLEAN\r
88BmMatchDevicePaths (\r
89 IN EFI_DEVICE_PATH_PROTOCOL *Multi,\r
90 IN EFI_DEVICE_PATH_PROTOCOL *Single\r
91 )\r
92{\r
93 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
94 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;\r
95 UINTN Size;\r
96\r
97 if (Multi == NULL || Single == NULL) {\r
98 return FALSE;\r
99 }\r
100\r
101 DevicePath = Multi;\r
102 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
103\r
104 //\r
105 // Search for the match of 'Single' in 'Multi'\r
106 //\r
107 while (DevicePathInst != NULL) {\r
108 //\r
109 // If the single device path is found in multiple device paths,\r
110 // return success\r
111 //\r
112 if (CompareMem (Single, DevicePathInst, Size) == 0) {\r
113 FreePool (DevicePathInst);\r
114 return TRUE;\r
115 }\r
116\r
117 FreePool (DevicePathInst);\r
118 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
119 }\r
120\r
121 return FALSE;\r
122}\r
123\r
124/**\r
125 This routine adjust the memory information for different memory type and \r
665b26ba
RN
126 save them into the variables for next boot. It resets the system when\r
127 memory information is updated and the current boot option belongs to\r
024bdafc
RN
128 boot category instead of application category. It doesn't count the\r
129 reserved memory occupied by RAM Disk.\r
665b26ba 130\r
024bdafc
RN
131 @param Boot TRUE if current boot option belongs to boot\r
132 category instead of application category.\r
133 @param RamDiskSizeInPages Reserved memory size in pages occupied by\r
134 RAM Disk.\r
067ed98a
RN
135**/\r
136VOID\r
137BmSetMemoryTypeInformationVariable (\r
024bdafc
RN
138 IN BOOLEAN Boot,\r
139 IN UINTN RamDiskSizeInPages\r
067ed98a
RN
140 )\r
141{\r
142 EFI_STATUS Status;\r
143 EFI_MEMORY_TYPE_INFORMATION *PreviousMemoryTypeInformation;\r
144 EFI_MEMORY_TYPE_INFORMATION *CurrentMemoryTypeInformation;\r
145 UINTN VariableSize;\r
146 UINTN Index;\r
147 UINTN Index1;\r
148 UINT32 Previous;\r
149 UINT32 Current;\r
150 UINT32 Next;\r
151 EFI_HOB_GUID_TYPE *GuidHob;\r
152 BOOLEAN MemoryTypeInformationModified;\r
153 BOOLEAN MemoryTypeInformationVariableExists;\r
154 EFI_BOOT_MODE BootMode;\r
155\r
156 MemoryTypeInformationModified = FALSE;\r
157 MemoryTypeInformationVariableExists = FALSE;\r
158\r
159\r
160 BootMode = GetBootModeHob ();\r
161 //\r
162 // In BOOT_IN_RECOVERY_MODE, Variable region is not reliable.\r
163 //\r
164 if (BootMode == BOOT_IN_RECOVERY_MODE) {\r
165 return;\r
166 }\r
167\r
168 //\r
169 // Only check the the Memory Type Information variable in the boot mode \r
170 // other than BOOT_WITH_DEFAULT_SETTINGS because the Memory Type\r
171 // Information is not valid in this boot mode.\r
172 //\r
173 if (BootMode != BOOT_WITH_DEFAULT_SETTINGS) {\r
174 VariableSize = 0;\r
175 Status = gRT->GetVariable (\r
176 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,\r
177 &gEfiMemoryTypeInformationGuid,\r
178 NULL, \r
179 &VariableSize, \r
180 NULL\r
181 );\r
182 if (Status == EFI_BUFFER_TOO_SMALL) {\r
183 MemoryTypeInformationVariableExists = TRUE;\r
184 }\r
185 }\r
186\r
187 //\r
188 // Retrieve the current memory usage statistics. If they are not found, then\r
189 // no adjustments can be made to the Memory Type Information variable.\r
190 //\r
191 Status = EfiGetSystemConfigurationTable (\r
192 &gEfiMemoryTypeInformationGuid,\r
193 (VOID **) &CurrentMemoryTypeInformation\r
194 );\r
195 if (EFI_ERROR (Status) || CurrentMemoryTypeInformation == NULL) {\r
196 return;\r
197 }\r
198\r
199 //\r
200 // Get the Memory Type Information settings from Hob if they exist,\r
201 // PEI is responsible for getting them from variable and build a Hob to save them.\r
202 // If the previous Memory Type Information is not available, then set defaults\r
203 //\r
204 GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);\r
205 if (GuidHob == NULL) {\r
206 //\r
207 // If Platform has not built Memory Type Info into the Hob, just return.\r
208 //\r
209 return;\r
210 }\r
211 PreviousMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);\r
212 VariableSize = GET_GUID_HOB_DATA_SIZE (GuidHob);\r
213\r
214 //\r
215 // Use a heuristic to adjust the Memory Type Information for the next boot\r
216 //\r
217 DEBUG ((EFI_D_INFO, "Memory Previous Current Next \n"));\r
218 DEBUG ((EFI_D_INFO, " Type Pages Pages Pages \n"));\r
219 DEBUG ((EFI_D_INFO, "====== ======== ======== ========\n"));\r
220\r
221 for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
222\r
223 for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) {\r
224 if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) {\r
225 break;\r
226 }\r
227 }\r
228 if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) {\r
229 continue;\r
230 }\r
231\r
024bdafc
RN
232 //\r
233 // Do not count the reserved memory occupied by RAM Disk.\r
234 //\r
fb5848c5
SW
235 if ((CurrentMemoryTypeInformation[Index1].Type == EfiReservedMemoryType) &&\r
236 (CurrentMemoryTypeInformation[Index1].NumberOfPages > ((UINT32) RamDiskSizeInPages))) {\r
54241797 237 CurrentMemoryTypeInformation[Index1].NumberOfPages -= (UINT32) RamDiskSizeInPages;\r
024bdafc
RN
238 }\r
239\r
067ed98a
RN
240 //\r
241 // Previous is the number of pages pre-allocated\r
242 // Current is the number of pages actually needed\r
243 //\r
244 Previous = PreviousMemoryTypeInformation[Index].NumberOfPages;\r
245 Current = CurrentMemoryTypeInformation[Index1].NumberOfPages;\r
246 Next = Previous;\r
247\r
248 //\r
249 // Inconsistent Memory Reserved across bootings may lead to S4 fail\r
250 // Write next varible to 125% * current when the pre-allocated memory is:\r
251 // 1. More than 150% of needed memory and boot mode is BOOT_WITH_DEFAULT_SETTING\r
252 // 2. Less than the needed memory\r
253 //\r
254 if ((Current + (Current >> 1)) < Previous) {\r
255 if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {\r
256 Next = Current + (Current >> 2);\r
257 }\r
258 } else if (Current > Previous) {\r
259 Next = Current + (Current >> 2);\r
260 }\r
261 if (Next > 0 && Next < 4) {\r
262 Next = 4;\r
263 }\r
264\r
265 if (Next != Previous) {\r
266 PreviousMemoryTypeInformation[Index].NumberOfPages = Next;\r
267 MemoryTypeInformationModified = TRUE;\r
268 }\r
269\r
270 DEBUG ((EFI_D_INFO, " %02x %08x %08x %08x\n", PreviousMemoryTypeInformation[Index].Type, Previous, Current, Next));\r
271 }\r
272\r
273 //\r
274 // If any changes were made to the Memory Type Information settings, then set the new variable value;\r
275 // Or create the variable in first boot.\r
276 //\r
277 if (MemoryTypeInformationModified || !MemoryTypeInformationVariableExists) {\r
278 Status = BmSetVariableAndReportStatusCodeOnError (\r
279 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,\r
280 &gEfiMemoryTypeInformationGuid,\r
281 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
282 VariableSize,\r
283 PreviousMemoryTypeInformation\r
284 );\r
285\r
286 if (!EFI_ERROR (Status)) {\r
287 //\r
665b26ba
RN
288 // If the Memory Type Information settings have been modified and the boot option belongs to boot category,\r
289 // then reset the platform so the new Memory Type Information setting will be used to guarantee that an S4\r
067ed98a
RN
290 // entry/resume cycle will not fail.\r
291 //\r
665b26ba 292 if (MemoryTypeInformationModified && Boot && PcdGetBool (PcdResetOnMemoryTypeInformationChange)) {\r
067ed98a
RN
293 DEBUG ((EFI_D_INFO, "Memory Type Information settings change. Warm Reset!!!\n"));\r
294 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
295 }\r
296 } else {\r
297 DEBUG ((EFI_D_ERROR, "Memory Type Information settings cannot be saved. OS S4 may fail!\n"));\r
298 }\r
299 }\r
300}\r
301\r
302/**\r
303 Set the variable and report the error through status code upon failure.\r
304\r
305 @param VariableName A Null-terminated string that is the name of the vendor's variable.\r
306 Each VariableName is unique for each VendorGuid. VariableName must\r
307 contain 1 or more characters. If VariableName is an empty string,\r
308 then EFI_INVALID_PARAMETER is returned.\r
309 @param VendorGuid A unique identifier for the vendor.\r
310 @param Attributes Attributes bitmask to set for the variable.\r
311 @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, \r
312 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or \r
313 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero \r
314 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is \r
315 set, then a SetVariable() call with a DataSize of zero will not cause any change to \r
316 the variable value (the timestamp associated with the variable may be updated however \r
317 even if no new data value is provided,see the description of the \r
318 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not \r
319 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). \r
320 @param Data The contents for the variable.\r
321\r
322 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as\r
323 defined by the Attributes.\r
324 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the\r
325 DataSize exceeds the maximum allowed.\r
326 @retval EFI_INVALID_PARAMETER VariableName is an empty string.\r
327 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.\r
328 @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.\r
329 @retval EFI_WRITE_PROTECTED The variable in question is read-only.\r
330 @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.\r
331 @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS \r
332 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo \r
333 does NOT pass the validation check carried out by the firmware.\r
334\r
335 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.\r
336**/\r
337EFI_STATUS\r
338BmSetVariableAndReportStatusCodeOnError (\r
339 IN CHAR16 *VariableName,\r
340 IN EFI_GUID *VendorGuid,\r
341 IN UINT32 Attributes,\r
342 IN UINTN DataSize,\r
343 IN VOID *Data\r
344 )\r
345{\r
346 EFI_STATUS Status;\r
347 EDKII_SET_VARIABLE_STATUS *SetVariableStatus;\r
348 UINTN NameSize;\r
349\r
350 Status = gRT->SetVariable (\r
351 VariableName,\r
352 VendorGuid,\r
353 Attributes,\r
354 DataSize,\r
355 Data\r
356 );\r
357 if (EFI_ERROR (Status)) {\r
358 NameSize = StrSize (VariableName);\r
359 SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);\r
360 if (SetVariableStatus != NULL) {\r
361 CopyGuid (&SetVariableStatus->Guid, VendorGuid);\r
362 SetVariableStatus->NameSize = NameSize;\r
363 SetVariableStatus->DataSize = DataSize;\r
364 SetVariableStatus->SetStatus = Status;\r
365 SetVariableStatus->Attributes = Attributes;\r
366 CopyMem (SetVariableStatus + 1, VariableName, NameSize);\r
367 CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize);\r
368\r
369 REPORT_STATUS_CODE_EX (\r
370 EFI_ERROR_CODE,\r
371 PcdGet32 (PcdErrorCodeSetVariable),\r
372 0,\r
373 NULL,\r
374 &gEdkiiStatusCodeDataTypeVariableGuid,\r
375 SetVariableStatus,\r
376 sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize\r
377 );\r
378\r
379 FreePool (SetVariableStatus);\r
380 }\r
381 }\r
382\r
383 return Status;\r
384}\r
385\r
386\r
387/**\r
388 Print the device path info.\r
389\r
390 @param DevicePath The device path need to print.\r
391**/\r
392VOID\r
393BmPrintDp (\r
394 EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
395 )\r
396{\r
397 CHAR16 *Str;\r
398\r
399 Str = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
400 DEBUG ((EFI_D_INFO, "%s", Str));\r
401 if (Str != NULL) {\r
402 FreePool (Str);\r
403 }\r
404}\r
418e8cd9
RN
405\r
406/**\r
407 Convert a single character to number.\r
408 It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'\r
409\r
410 @param Char The input char which need to convert to int.\r
411\r
412 @return The converted 8-bit number or (UINTN) -1 if conversion failed.\r
413**/\r
414UINTN\r
415BmCharToUint (\r
416 IN CHAR16 Char\r
417 )\r
418{\r
419 if ((Char >= L'0') && (Char <= L'9')) {\r
420 return (UINTN) (Char - L'0');\r
421 }\r
422\r
423 if ((Char >= L'A') && (Char <= L'F')) {\r
424 return (UINTN) (Char - L'A' + 0xA);\r
425 }\r
426\r
427 ASSERT (FALSE);\r
428 return (UINTN) -1;\r
429}\r
430\r