]>
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 | ||
1d112229 RN |
123 | /** |
124 | This routine adjust the memory information for different memory type and | |
125 | save them into the variables for next boot. | |
126 | **/ | |
127 | VOID | |
128 | BmSetMemoryTypeInformationVariable ( | |
129 | VOID | |
130 | ) | |
131 | { | |
132 | EFI_STATUS Status; | |
133 | EFI_MEMORY_TYPE_INFORMATION *PreviousMemoryTypeInformation; | |
134 | EFI_MEMORY_TYPE_INFORMATION *CurrentMemoryTypeInformation; | |
135 | UINTN VariableSize; | |
136 | UINTN Index; | |
137 | UINTN Index1; | |
138 | UINT32 Previous; | |
139 | UINT32 Current; | |
140 | UINT32 Next; | |
141 | EFI_HOB_GUID_TYPE *GuidHob; | |
142 | BOOLEAN MemoryTypeInformationModified; | |
143 | BOOLEAN MemoryTypeInformationVariableExists; | |
144 | EFI_BOOT_MODE BootMode; | |
145 | ||
146 | MemoryTypeInformationModified = FALSE; | |
147 | MemoryTypeInformationVariableExists = FALSE; | |
148 | ||
149 | ||
150 | BootMode = GetBootModeHob (); | |
151 | // | |
152 | // In BOOT_IN_RECOVERY_MODE, Variable region is not reliable. | |
153 | // | |
154 | if (BootMode == BOOT_IN_RECOVERY_MODE) { | |
155 | return; | |
156 | } | |
157 | ||
158 | // | |
159 | // Only check the the Memory Type Information variable in the boot mode | |
160 | // other than BOOT_WITH_DEFAULT_SETTINGS because the Memory Type | |
161 | // Information is not valid in this boot mode. | |
162 | // | |
163 | if (BootMode != BOOT_WITH_DEFAULT_SETTINGS) { | |
164 | VariableSize = 0; | |
165 | Status = gRT->GetVariable ( | |
166 | EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME, | |
167 | &gEfiMemoryTypeInformationGuid, | |
168 | NULL, | |
169 | &VariableSize, | |
170 | NULL | |
171 | ); | |
172 | if (Status == EFI_BUFFER_TOO_SMALL) { | |
173 | MemoryTypeInformationVariableExists = TRUE; | |
174 | } | |
175 | } | |
176 | ||
177 | // | |
178 | // Retrieve the current memory usage statistics. If they are not found, then | |
179 | // no adjustments can be made to the Memory Type Information variable. | |
180 | // | |
181 | Status = EfiGetSystemConfigurationTable ( | |
182 | &gEfiMemoryTypeInformationGuid, | |
183 | (VOID **) &CurrentMemoryTypeInformation | |
184 | ); | |
185 | if (EFI_ERROR (Status) || CurrentMemoryTypeInformation == NULL) { | |
186 | return; | |
187 | } | |
188 | ||
189 | // | |
190 | // Get the Memory Type Information settings from Hob if they exist, | |
191 | // PEI is responsible for getting them from variable and build a Hob to save them. | |
192 | // If the previous Memory Type Information is not available, then set defaults | |
193 | // | |
194 | GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid); | |
195 | if (GuidHob == NULL) { | |
196 | // | |
197 | // If Platform has not built Memory Type Info into the Hob, just return. | |
198 | // | |
199 | return; | |
200 | } | |
201 | PreviousMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob); | |
202 | VariableSize = GET_GUID_HOB_DATA_SIZE (GuidHob); | |
203 | ||
204 | // | |
205 | // Use a heuristic to adjust the Memory Type Information for the next boot | |
206 | // | |
207 | DEBUG ((EFI_D_INFO, "Memory Previous Current Next \n")); | |
208 | DEBUG ((EFI_D_INFO, " Type Pages Pages Pages \n")); | |
209 | DEBUG ((EFI_D_INFO, "====== ======== ======== ========\n")); | |
210 | ||
211 | for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) { | |
212 | ||
213 | for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) { | |
214 | if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) { | |
215 | break; | |
216 | } | |
217 | } | |
218 | if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) { | |
219 | continue; | |
220 | } | |
221 | ||
222 | // | |
223 | // Previous is the number of pages pre-allocated | |
224 | // Current is the number of pages actually needed | |
225 | // | |
226 | Previous = PreviousMemoryTypeInformation[Index].NumberOfPages; | |
227 | Current = CurrentMemoryTypeInformation[Index1].NumberOfPages; | |
228 | Next = Previous; | |
229 | ||
230 | // | |
231 | // Inconsistent Memory Reserved across bootings may lead to S4 fail | |
232 | // Write next varible to 125% * current when the pre-allocated memory is: | |
233 | // 1. More than 150% of needed memory and boot mode is BOOT_WITH_DEFAULT_SETTING | |
234 | // 2. Less than the needed memory | |
235 | // | |
236 | if ((Current + (Current >> 1)) < Previous) { | |
237 | if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) { | |
238 | Next = Current + (Current >> 2); | |
239 | } | |
240 | } else if (Current > Previous) { | |
241 | Next = Current + (Current >> 2); | |
242 | } | |
243 | if (Next > 0 && Next < 4) { | |
244 | Next = 4; | |
245 | } | |
246 | ||
247 | if (Next != Previous) { | |
248 | PreviousMemoryTypeInformation[Index].NumberOfPages = Next; | |
249 | MemoryTypeInformationModified = TRUE; | |
250 | } | |
251 | ||
252 | DEBUG ((EFI_D_INFO, " %02x %08x %08x %08x\n", PreviousMemoryTypeInformation[Index].Type, Previous, Current, Next)); | |
253 | } | |
254 | ||
255 | // | |
256 | // If any changes were made to the Memory Type Information settings, then set the new variable value; | |
257 | // Or create the variable in first boot. | |
258 | // | |
259 | if (MemoryTypeInformationModified || !MemoryTypeInformationVariableExists) { | |
260 | Status = BmSetVariableAndReportStatusCodeOnError ( | |
261 | EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME, | |
262 | &gEfiMemoryTypeInformationGuid, | |
263 | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, | |
264 | VariableSize, | |
265 | PreviousMemoryTypeInformation | |
266 | ); | |
267 | ||
268 | if (!EFI_ERROR (Status)) { | |
269 | // | |
270 | // If the Memory Type Information settings have been modified, then reset the platform | |
271 | // so the new Memory Type Information setting will be used to guarantee that an S4 | |
272 | // entry/resume cycle will not fail. | |
273 | // | |
274 | if (MemoryTypeInformationModified) { | |
275 | DEBUG ((EFI_D_INFO, "Memory Type Information settings change. Warm Reset!!!\n")); | |
276 | gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); | |
277 | } | |
278 | } else { | |
279 | DEBUG ((EFI_D_ERROR, "Memory Type Information settings cannot be saved. OS S4 may fail!\n")); | |
280 | } | |
281 | } | |
282 | } | |
283 | ||
284 | /** | |
285 | Set the variable and report the error through status code upon failure. | |
286 | ||
287 | @param VariableName A Null-terminated string that is the name of the vendor's variable. | |
288 | Each VariableName is unique for each VendorGuid. VariableName must | |
289 | contain 1 or more characters. If VariableName is an empty string, | |
290 | then EFI_INVALID_PARAMETER is returned. | |
291 | @param VendorGuid A unique identifier for the vendor. | |
292 | @param Attributes Attributes bitmask to set for the variable. | |
293 | @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, | |
294 | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or | |
295 | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero | |
296 | causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is | |
297 | set, then a SetVariable() call with a DataSize of zero will not cause any change to | |
298 | the variable value (the timestamp associated with the variable may be updated however | |
299 | even if no new data value is provided,see the description of the | |
300 | EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not | |
301 | be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). | |
302 | @param Data The contents for the variable. | |
303 | ||
304 | @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as | |
305 | defined by the Attributes. | |
306 | @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the | |
307 | DataSize exceeds the maximum allowed. | |
308 | @retval EFI_INVALID_PARAMETER VariableName is an empty string. | |
309 | @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. | |
310 | @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error. | |
311 | @retval EFI_WRITE_PROTECTED The variable in question is read-only. | |
312 | @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted. | |
313 | @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | |
314 | or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo | |
315 | does NOT pass the validation check carried out by the firmware. | |
316 | ||
317 | @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found. | |
318 | **/ | |
319 | EFI_STATUS | |
320 | BmSetVariableAndReportStatusCodeOnError ( | |
321 | IN CHAR16 *VariableName, | |
322 | IN EFI_GUID *VendorGuid, | |
323 | IN UINT32 Attributes, | |
324 | IN UINTN DataSize, | |
325 | IN VOID *Data | |
326 | ) | |
327 | { | |
328 | EFI_STATUS Status; | |
329 | EDKII_SET_VARIABLE_STATUS *SetVariableStatus; | |
330 | UINTN NameSize; | |
331 | ||
332 | Status = gRT->SetVariable ( | |
333 | VariableName, | |
334 | VendorGuid, | |
335 | Attributes, | |
336 | DataSize, | |
337 | Data | |
338 | ); | |
339 | if (EFI_ERROR (Status)) { | |
340 | NameSize = StrSize (VariableName); | |
341 | SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize); | |
342 | if (SetVariableStatus != NULL) { | |
343 | CopyGuid (&SetVariableStatus->Guid, VendorGuid); | |
344 | SetVariableStatus->NameSize = NameSize; | |
345 | SetVariableStatus->DataSize = DataSize; | |
346 | SetVariableStatus->SetStatus = Status; | |
347 | SetVariableStatus->Attributes = Attributes; | |
348 | CopyMem (SetVariableStatus + 1, VariableName, NameSize); | |
349 | CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize); | |
350 | ||
351 | REPORT_STATUS_CODE_EX ( | |
352 | EFI_ERROR_CODE, | |
353 | PcdGet32 (PcdErrorCodeSetVariable), | |
354 | 0, | |
355 | NULL, | |
356 | &gEdkiiStatusCodeDataTypeVariableGuid, | |
357 | SetVariableStatus, | |
358 | sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize | |
359 | ); | |
360 | ||
361 | FreePool (SetVariableStatus); | |
362 | } | |
363 | } | |
364 | ||
365 | return Status; | |
366 | } | |
367 | ||
1634214d RN |
368 | |
369 | /** | |
370 | Print the device path info. | |
371 | ||
372 | @param DevicePath The device path need to print. | |
373 | **/ | |
374 | VOID | |
375 | BmPrintDp ( | |
376 | EFI_DEVICE_PATH_PROTOCOL *DevicePath | |
377 | ) | |
378 | { | |
379 | CHAR16 *Str; | |
380 | ||
381 | Str = ConvertDevicePathToText (DevicePath, FALSE, FALSE); | |
382 | DEBUG ((EFI_D_INFO, "%s", Str)); | |
383 | if (Str != NULL) { | |
384 | FreePool (Str); | |
385 | } | |
386 | } |