]>
Commit | Line | Data |
---|---|---|
1d112229 RN |
1 | /** @file |
2 | Misc library functions. | |
3 | ||
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 | |
9 | ||
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. | |
12 | ||
13 | **/ | |
14 | ||
15 | #include "InternalBm.h" | |
16 | ||
17 | /** | |
18 | Delete the instance in Multi which matches partly with Single instance | |
19 | ||
20 | @param Multi A pointer to a multi-instance device path data | |
21 | structure. | |
22 | @param Single A pointer to a single-instance device path data | |
23 | structure. | |
24 | ||
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. | |
28 | ||
29 | **/ | |
30 | EFI_DEVICE_PATH_PROTOCOL * | |
31 | BmDelPartMatchInstance ( | |
32 | IN EFI_DEVICE_PATH_PROTOCOL *Multi, | |
33 | IN EFI_DEVICE_PATH_PROTOCOL *Single | |
34 | ) | |
35 | { | |
36 | EFI_DEVICE_PATH_PROTOCOL *Instance; | |
37 | EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; | |
38 | EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath; | |
39 | UINTN InstanceSize; | |
40 | UINTN SingleDpSize; | |
41 | ||
42 | NewDevicePath = NULL; | |
43 | TempNewDevicePath = NULL; | |
44 | ||
45 | if (Multi == NULL || Single == NULL) { | |
46 | return Multi; | |
47 | } | |
48 | ||
49 | Instance = GetNextDevicePathInstance (&Multi, &InstanceSize); | |
50 | SingleDpSize = GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH; | |
51 | InstanceSize -= END_DEVICE_PATH_LENGTH; | |
52 | ||
53 | while (Instance != NULL) { | |
54 | ||
55 | if (CompareMem (Instance, Single, MIN (SingleDpSize, InstanceSize)) != 0) { | |
56 | // | |
57 | // Append the device path instance which does not match with Single | |
58 | // | |
59 | TempNewDevicePath = NewDevicePath; | |
60 | NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance); | |
61 | if (TempNewDevicePath != NULL) { | |
62 | FreePool(TempNewDevicePath); | |
63 | } | |
64 | } | |
65 | FreePool(Instance); | |
66 | Instance = GetNextDevicePathInstance (&Multi, &InstanceSize); | |
67 | InstanceSize -= END_DEVICE_PATH_LENGTH; | |
68 | } | |
69 | ||
70 | return NewDevicePath; | |
71 | } | |
72 | ||
73 | /** | |
74 | Function compares a device path data structure to that of all the nodes of a | |
75 | second device path instance. | |
76 | ||
77 | @param Multi A pointer to a multi-instance device path data | |
78 | structure. | |
79 | @param Single A pointer to a single-instance device path data | |
80 | structure. | |
81 | ||
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. | |
84 | ||
85 | **/ | |
86 | BOOLEAN | |
87 | BmMatchDevicePaths ( | |
88 | IN EFI_DEVICE_PATH_PROTOCOL *Multi, | |
89 | IN EFI_DEVICE_PATH_PROTOCOL *Single | |
90 | ) | |
91 | { | |
92 | EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
93 | EFI_DEVICE_PATH_PROTOCOL *DevicePathInst; | |
94 | UINTN Size; | |
95 | ||
96 | if (Multi == NULL || Single == NULL) { | |
97 | return FALSE; | |
98 | } | |
99 | ||
100 | DevicePath = Multi; | |
101 | DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size); | |
102 | ||
103 | // | |
104 | // Search for the match of 'Single' in 'Multi' | |
105 | // | |
106 | while (DevicePathInst != NULL) { | |
107 | // | |
108 | // If the single device path is found in multiple device paths, | |
109 | // return success | |
110 | // | |
111 | if (CompareMem (Single, DevicePathInst, Size) == 0) { | |
112 | FreePool (DevicePathInst); | |
113 | return TRUE; | |
114 | } | |
115 | ||
116 | FreePool (DevicePathInst); | |
117 | DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size); | |
118 | } | |
119 | ||
120 | return FALSE; | |
121 | } | |
122 | ||
123 | /** | |
124 | Get the headers (dos, image, optional header) from an image | |
125 | ||
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. | |
130 | ||
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. | |
134 | ||
135 | **/ | |
136 | EFI_STATUS | |
137 | BmGetImageHeader ( | |
138 | IN EFI_HANDLE Device, | |
139 | IN CHAR16 *FileName, | |
140 | OUT EFI_IMAGE_DOS_HEADER *DosHeader, | |
141 | OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr | |
142 | ) | |
143 | { | |
144 | EFI_STATUS Status; | |
145 | EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; | |
146 | EFI_FILE_HANDLE Root; | |
147 | EFI_FILE_HANDLE ThisFile; | |
148 | UINTN BufferSize; | |
149 | UINT64 FileSize; | |
150 | EFI_FILE_INFO *Info; | |
151 | ||
152 | Root = NULL; | |
153 | ThisFile = NULL; | |
154 | // | |
155 | // Handle the file system interface to the device | |
156 | // | |
157 | Status = gBS->HandleProtocol ( | |
158 | Device, | |
159 | &gEfiSimpleFileSystemProtocolGuid, | |
160 | (VOID *) &Volume | |
161 | ); | |
162 | if (EFI_ERROR (Status)) { | |
163 | goto Done; | |
164 | } | |
165 | ||
166 | Status = Volume->OpenVolume ( | |
167 | Volume, | |
168 | &Root | |
169 | ); | |
170 | if (EFI_ERROR (Status)) { | |
171 | Root = NULL; | |
172 | goto Done; | |
173 | } | |
174 | ASSERT (Root != NULL); | |
175 | Status = Root->Open (Root, &ThisFile, FileName, EFI_FILE_MODE_READ, 0); | |
176 | if (EFI_ERROR (Status)) { | |
177 | goto Done; | |
178 | } | |
179 | ASSERT (ThisFile != NULL); | |
180 | ||
181 | // | |
182 | // Get file size | |
183 | // | |
184 | BufferSize = SIZE_OF_EFI_FILE_INFO + 200; | |
185 | do { | |
186 | Info = NULL; | |
187 | Status = gBS->AllocatePool (EfiBootServicesData, BufferSize, (VOID **) &Info); | |
188 | if (EFI_ERROR (Status)) { | |
189 | goto Done; | |
190 | } | |
191 | Status = ThisFile->GetInfo ( | |
192 | ThisFile, | |
193 | &gEfiFileInfoGuid, | |
194 | &BufferSize, | |
195 | Info | |
196 | ); | |
197 | if (!EFI_ERROR (Status)) { | |
198 | break; | |
199 | } | |
200 | if (Status != EFI_BUFFER_TOO_SMALL) { | |
201 | FreePool (Info); | |
202 | goto Done; | |
203 | } | |
204 | FreePool (Info); | |
205 | } while (TRUE); | |
206 | ||
207 | FileSize = Info->FileSize; | |
208 | FreePool (Info); | |
209 | ||
210 | // | |
211 | // Read dos header | |
212 | // | |
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; | |
220 | goto Done; | |
221 | } | |
222 | ||
223 | // | |
224 | // Move to PE signature | |
225 | // | |
226 | Status = ThisFile->SetPosition (ThisFile, DosHeader->e_lfanew); | |
227 | if (EFI_ERROR (Status)) { | |
228 | Status = EFI_LOAD_ERROR; | |
229 | goto Done; | |
230 | } | |
231 | ||
232 | // | |
233 | // Read and check PE signature | |
234 | // | |
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; | |
241 | goto Done; | |
242 | } | |
243 | ||
244 | // | |
245 | // Check PE32 or PE32+ magic | |
246 | // | |
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; | |
250 | goto Done; | |
251 | } | |
252 | ||
253 | Done: | |
254 | if (ThisFile != NULL) { | |
255 | ThisFile->Close (ThisFile); | |
256 | } | |
257 | if (Root != NULL) { | |
258 | Root->Close (Root); | |
259 | } | |
260 | return Status; | |
261 | } | |
262 | ||
263 | /** | |
264 | This routine adjust the memory information for different memory type and | |
265 | save them into the variables for next boot. | |
266 | **/ | |
267 | VOID | |
268 | BmSetMemoryTypeInformationVariable ( | |
269 | VOID | |
270 | ) | |
271 | { | |
272 | EFI_STATUS Status; | |
273 | EFI_MEMORY_TYPE_INFORMATION *PreviousMemoryTypeInformation; | |
274 | EFI_MEMORY_TYPE_INFORMATION *CurrentMemoryTypeInformation; | |
275 | UINTN VariableSize; | |
276 | UINTN Index; | |
277 | UINTN Index1; | |
278 | UINT32 Previous; | |
279 | UINT32 Current; | |
280 | UINT32 Next; | |
281 | EFI_HOB_GUID_TYPE *GuidHob; | |
282 | BOOLEAN MemoryTypeInformationModified; | |
283 | BOOLEAN MemoryTypeInformationVariableExists; | |
284 | EFI_BOOT_MODE BootMode; | |
285 | ||
286 | MemoryTypeInformationModified = FALSE; | |
287 | MemoryTypeInformationVariableExists = FALSE; | |
288 | ||
289 | ||
290 | BootMode = GetBootModeHob (); | |
291 | // | |
292 | // In BOOT_IN_RECOVERY_MODE, Variable region is not reliable. | |
293 | // | |
294 | if (BootMode == BOOT_IN_RECOVERY_MODE) { | |
295 | return; | |
296 | } | |
297 | ||
298 | // | |
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. | |
302 | // | |
303 | if (BootMode != BOOT_WITH_DEFAULT_SETTINGS) { | |
304 | VariableSize = 0; | |
305 | Status = gRT->GetVariable ( | |
306 | EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME, | |
307 | &gEfiMemoryTypeInformationGuid, | |
308 | NULL, | |
309 | &VariableSize, | |
310 | NULL | |
311 | ); | |
312 | if (Status == EFI_BUFFER_TOO_SMALL) { | |
313 | MemoryTypeInformationVariableExists = TRUE; | |
314 | } | |
315 | } | |
316 | ||
317 | // | |
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. | |
320 | // | |
321 | Status = EfiGetSystemConfigurationTable ( | |
322 | &gEfiMemoryTypeInformationGuid, | |
323 | (VOID **) &CurrentMemoryTypeInformation | |
324 | ); | |
325 | if (EFI_ERROR (Status) || CurrentMemoryTypeInformation == NULL) { | |
326 | return; | |
327 | } | |
328 | ||
329 | // | |
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 | |
333 | // | |
334 | GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid); | |
335 | if (GuidHob == NULL) { | |
336 | // | |
337 | // If Platform has not built Memory Type Info into the Hob, just return. | |
338 | // | |
339 | return; | |
340 | } | |
341 | PreviousMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob); | |
342 | VariableSize = GET_GUID_HOB_DATA_SIZE (GuidHob); | |
343 | ||
344 | // | |
345 | // Use a heuristic to adjust the Memory Type Information for the next boot | |
346 | // | |
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")); | |
350 | ||
351 | for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) { | |
352 | ||
353 | for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) { | |
354 | if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) { | |
355 | break; | |
356 | } | |
357 | } | |
358 | if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) { | |
359 | continue; | |
360 | } | |
361 | ||
362 | // | |
363 | // Previous is the number of pages pre-allocated | |
364 | // Current is the number of pages actually needed | |
365 | // | |
366 | Previous = PreviousMemoryTypeInformation[Index].NumberOfPages; | |
367 | Current = CurrentMemoryTypeInformation[Index1].NumberOfPages; | |
368 | Next = Previous; | |
369 | ||
370 | // | |
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 | |
375 | // | |
376 | if ((Current + (Current >> 1)) < Previous) { | |
377 | if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) { | |
378 | Next = Current + (Current >> 2); | |
379 | } | |
380 | } else if (Current > Previous) { | |
381 | Next = Current + (Current >> 2); | |
382 | } | |
383 | if (Next > 0 && Next < 4) { | |
384 | Next = 4; | |
385 | } | |
386 | ||
387 | if (Next != Previous) { | |
388 | PreviousMemoryTypeInformation[Index].NumberOfPages = Next; | |
389 | MemoryTypeInformationModified = TRUE; | |
390 | } | |
391 | ||
392 | DEBUG ((EFI_D_INFO, " %02x %08x %08x %08x\n", PreviousMemoryTypeInformation[Index].Type, Previous, Current, Next)); | |
393 | } | |
394 | ||
395 | // | |
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. | |
398 | // | |
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, | |
404 | VariableSize, | |
405 | PreviousMemoryTypeInformation | |
406 | ); | |
407 | ||
408 | if (!EFI_ERROR (Status)) { | |
409 | // | |
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. | |
413 | // | |
414 | if (MemoryTypeInformationModified) { | |
415 | DEBUG ((EFI_D_INFO, "Memory Type Information settings change. Warm Reset!!!\n")); | |
416 | gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); | |
417 | } | |
418 | } else { | |
419 | DEBUG ((EFI_D_ERROR, "Memory Type Information settings cannot be saved. OS S4 may fail!\n")); | |
420 | } | |
421 | } | |
422 | } | |
423 | ||
424 | /** | |
425 | Set the variable and report the error through status code upon failure. | |
426 | ||
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. | |
443 | ||
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. | |
456 | ||
457 | @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found. | |
458 | **/ | |
459 | EFI_STATUS | |
460 | BmSetVariableAndReportStatusCodeOnError ( | |
461 | IN CHAR16 *VariableName, | |
462 | IN EFI_GUID *VendorGuid, | |
463 | IN UINT32 Attributes, | |
464 | IN UINTN DataSize, | |
465 | IN VOID *Data | |
466 | ) | |
467 | { | |
468 | EFI_STATUS Status; | |
469 | EDKII_SET_VARIABLE_STATUS *SetVariableStatus; | |
470 | UINTN NameSize; | |
471 | ||
472 | Status = gRT->SetVariable ( | |
473 | VariableName, | |
474 | VendorGuid, | |
475 | Attributes, | |
476 | DataSize, | |
477 | Data | |
478 | ); | |
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); | |
490 | ||
491 | REPORT_STATUS_CODE_EX ( | |
492 | EFI_ERROR_CODE, | |
493 | PcdGet32 (PcdErrorCodeSetVariable), | |
494 | 0, | |
495 | NULL, | |
496 | &gEdkiiStatusCodeDataTypeVariableGuid, | |
497 | SetVariableStatus, | |
498 | sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize | |
499 | ); | |
500 | ||
501 | FreePool (SetVariableStatus); | |
502 | } | |
503 | } | |
504 | ||
505 | return Status; | |
506 | } | |
507 |