]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/ResetSystemPei/ResetSystem.c
MdeModulePkg/Variable: Make only EFI_VARIABLE_NON_VOLATILE invalid
[mirror_edk2.git] / MdeModulePkg / Universal / ResetSystemPei / ResetSystem.c
1 /** @file
2 Implementation of Reset2, ResetFilter and ResetHandler PPIs.
3
4 Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "ResetSystem.h"
11
12 GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mResetTypeStr[] = {
13 L"Cold", L"Warm", L"Shutdown", L"PlatformSpecific"
14 };
15
16 EFI_PEI_RESET2_PPI mPpiReset2 = {
17 ResetSystem2
18 };
19
20 EFI_GUID *mProcessingOrder[] = {
21 &gEdkiiPlatformSpecificResetFilterPpiGuid,
22 &gEdkiiPlatformSpecificResetNotificationPpiGuid,
23 &gEdkiiPlatformSpecificResetHandlerPpiGuid
24 };
25
26 RESET_FILTER_INSTANCE mResetFilter = {
27 {
28 RegisterResetNotify,
29 UnregisterResetNotify
30 },
31 &gEdkiiPlatformSpecificResetFilterPpiGuid
32 };
33
34 RESET_FILTER_INSTANCE mResetNotification = {
35 {
36 RegisterResetNotify,
37 UnregisterResetNotify
38 },
39 &gEdkiiPlatformSpecificResetNotificationPpiGuid
40 };
41
42 RESET_FILTER_INSTANCE mResetHandler = {
43 {
44 RegisterResetNotify,
45 UnregisterResetNotify
46 },
47 &gEdkiiPlatformSpecificResetHandlerPpiGuid
48 };
49
50 EFI_PEI_PPI_DESCRIPTOR mPpiListReset[] = {
51 {
52 EFI_PEI_PPI_DESCRIPTOR_PPI,
53 &gEfiPeiReset2PpiGuid,
54 &mPpiReset2
55 },
56 {
57 EFI_PEI_PPI_DESCRIPTOR_PPI,
58 &gEdkiiPlatformSpecificResetFilterPpiGuid,
59 &mResetFilter.ResetFilter
60 },
61 {
62 EFI_PEI_PPI_DESCRIPTOR_PPI,
63 &gEdkiiPlatformSpecificResetNotificationPpiGuid,
64 &mResetNotification.ResetFilter
65 },
66 {
67 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
68 &gEdkiiPlatformSpecificResetHandlerPpiGuid,
69 &mResetHandler.ResetFilter
70 }
71 };
72
73 /**
74 Register a notification function to be called when ResetSystem() is called.
75
76 The RegisterResetNotify() function registers a notification function that is called when
77 ResetSystem() is called and prior to completing the reset of the platform.
78 The registered functions must not perform a platform reset themselves. These
79 notifications are intended only for the notification of components which may need some
80 special-purpose maintenance prior to the platform resetting.
81 The list of registered reset notification functions are processed if ResetSystem()is called
82 before ExitBootServices(). The list of registered reset notification functions is ignored if
83 ResetSystem() is called after ExitBootServices().
84
85 @param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.
86 @param[in] ResetFunction Points to the function to be called when a ResetSystem() is executed.
87
88 @retval EFI_SUCCESS The reset notification function was successfully registered.
89 @retval EFI_INVALID_PARAMETER ResetFunction is NULL.
90 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to register the reset notification function.
91 @retval EFI_ALREADY_STARTED The reset notification function specified by ResetFunction has already been registered.
92
93 **/
94 EFI_STATUS
95 EFIAPI
96 RegisterResetNotify (
97 IN EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PPI *This,
98 IN EFI_RESET_SYSTEM ResetFunction
99 )
100 {
101 RESET_FILTER_INSTANCE *ResetFilter;
102 RESET_FILTER_LIST *List;
103 VOID *Hob;
104 UINTN Index;
105
106 if (ResetFunction == NULL) {
107 return EFI_INVALID_PARAMETER;
108 }
109
110 ResetFilter = (RESET_FILTER_INSTANCE *)This;
111 ASSERT (
112 CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetFilterPpiGuid) ||
113 CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetNotificationPpiGuid) ||
114 CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetHandlerPpiGuid)
115 );
116
117 Hob = GetFirstGuidHob (ResetFilter->Guid);
118 if (Hob == NULL) {
119 //
120 // When the GUIDed HOB doesn't exist, create it.
121 //
122 List = (RESET_FILTER_LIST *)BuildGuidHob (
123 ResetFilter->Guid,
124 sizeof (RESET_FILTER_LIST) + sizeof (EFI_RESET_SYSTEM) * PcdGet32 (PcdMaximumPeiResetNotifies)
125 );
126 if (List == NULL) {
127 return EFI_OUT_OF_RESOURCES;
128 }
129
130 List->Signature = RESET_FILTER_LIST_SIGNATURE;
131 List->Count = PcdGet32 (PcdMaximumPeiResetNotifies);
132 ZeroMem (List->ResetFilters, sizeof (EFI_RESET_SYSTEM) * List->Count);
133 List->ResetFilters[0] = ResetFunction;
134 return EFI_SUCCESS;
135 } else {
136 List = (RESET_FILTER_LIST *)GET_GUID_HOB_DATA (Hob);
137 ASSERT (List->Signature == RESET_FILTER_LIST_SIGNATURE);
138 //
139 // Firstly check whether the ResetFunction is already registerred.
140 //
141 for (Index = 0; Index < List->Count; Index++) {
142 if (List->ResetFilters[Index] == ResetFunction) {
143 break;
144 }
145 }
146
147 if (Index != List->Count) {
148 return EFI_ALREADY_STARTED;
149 }
150
151 //
152 // Secondly find the first free slot.
153 //
154 for (Index = 0; Index < List->Count; Index++) {
155 if (List->ResetFilters[Index] == NULL) {
156 break;
157 }
158 }
159
160 if (Index == List->Count) {
161 return EFI_OUT_OF_RESOURCES;
162 }
163
164 List->ResetFilters[Index] = ResetFunction;
165 return EFI_SUCCESS;
166 }
167 }
168
169 /**
170 Unregister a notification function.
171
172 The UnregisterResetNotify() function removes the previously registered
173 notification using RegisterResetNotify().
174
175 @param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.
176 @param[in] ResetFunction The pointer to the ResetFunction being unregistered.
177
178 @retval EFI_SUCCESS The reset notification function was unregistered.
179 @retval EFI_INVALID_PARAMETER ResetFunction is NULL.
180 @retval EFI_INVALID_PARAMETER The reset notification function specified by ResetFunction was not previously
181 registered using RegisterResetNotify().
182
183 **/
184 EFI_STATUS
185 EFIAPI
186 UnregisterResetNotify (
187 IN EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PPI *This,
188 IN EFI_RESET_SYSTEM ResetFunction
189 )
190 {
191 RESET_FILTER_INSTANCE *ResetFilter;
192 RESET_FILTER_LIST *List;
193 VOID *Hob;
194 UINTN Index;
195
196 if (ResetFunction == NULL) {
197 return EFI_INVALID_PARAMETER;
198 }
199
200 ResetFilter = (RESET_FILTER_INSTANCE *)This;
201 ASSERT (
202 CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetFilterPpiGuid) ||
203 CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetNotificationPpiGuid) ||
204 CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetHandlerPpiGuid)
205 );
206
207 Hob = GetFirstGuidHob (ResetFilter->Guid);
208 if (Hob == NULL) {
209 return EFI_INVALID_PARAMETER;
210 }
211
212 List = (RESET_FILTER_LIST *)GET_GUID_HOB_DATA (Hob);
213 ASSERT (List->Signature == RESET_FILTER_LIST_SIGNATURE);
214 for (Index = 0; Index < List->Count; Index++) {
215 if (List->ResetFilters[Index] == ResetFunction) {
216 break;
217 }
218 }
219
220 if (Index == List->Count) {
221 return EFI_INVALID_PARAMETER;
222 }
223
224 List->ResetFilters[Index] = NULL;
225 return EFI_SUCCESS;
226 }
227
228 /**
229 The PEIM's entry point.
230
231 It initializes the Reset2, ResetFilter and ResetHandler PPIs.
232
233 @param[in] FileHandle Handle of the file being invoked.
234 @param[in] PeiServices Describes the list of possible PEI Services.
235
236 @retval EFI_SUCCESS The entry point is executed successfully.
237 @retval EFI_ALREADY_STARTED The Reset2 PPI was already installed.
238 @retval others Status code returned from PeiServicesInstallPpi().
239
240 **/
241 EFI_STATUS
242 EFIAPI
243 InitializeResetSystem (
244 IN EFI_PEI_FILE_HANDLE FileHandle,
245 IN CONST EFI_PEI_SERVICES **PeiServices
246 )
247 {
248 EFI_STATUS Status;
249 VOID *Ppi;
250
251 Status = PeiServicesLocatePpi (&gEfiPeiReset2PpiGuid, 0, NULL, (VOID **)&Ppi);
252 if (Status != EFI_NOT_FOUND) {
253 return EFI_ALREADY_STARTED;
254 }
255
256 PeiServicesInstallPpi (mPpiListReset);
257
258 return Status;
259 }
260
261 /**
262 Resets the entire platform.
263
264 @param[in] ResetType The type of reset to perform.
265 @param[in] ResetStatus The status code for the reset.
266 @param[in] DataSize The size, in bytes, of ResetData.
267 @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or
268 EfiResetShutdown the data buffer starts with a Null-terminated
269 string, optionally followed by additional binary data.
270 The string is a description that the caller may use to further
271 indicate the reason for the system reset.
272 For a ResetType of EfiResetPlatformSpecific the data buffer
273 also starts with a Null-terminated string that is followed
274 by an EFI_GUID that describes the specific type of reset to perform.
275 **/
276 VOID
277 EFIAPI
278 ResetSystem2 (
279 IN EFI_RESET_TYPE ResetType,
280 IN EFI_STATUS ResetStatus,
281 IN UINTN DataSize,
282 IN VOID *ResetData OPTIONAL
283 )
284 {
285 VOID *Hob;
286 UINTN Index;
287 RESET_FILTER_LIST *List;
288 UINTN OrderIndex;
289 UINT8 RecursionDepth;
290 UINT8 *RecursionDepthPointer;
291
292 //
293 // The recursion depth is stored in GUIDed HOB using gEfiCallerIdGuid.
294 //
295 Hob = GetFirstGuidHob (&gEfiCallerIdGuid);
296 if (Hob == NULL) {
297 RecursionDepth = 0;
298 RecursionDepthPointer = BuildGuidDataHob (&gEfiCallerIdGuid, &RecursionDepth, sizeof (RecursionDepth));
299 } else {
300 RecursionDepthPointer = (UINT8 *)GET_GUID_HOB_DATA (Hob);
301 }
302
303 //
304 // Only do REPORT_STATUS_CODE() on first call to ResetSystem()
305 //
306 if (*RecursionDepthPointer == 0) {
307 //
308 // Indicate reset system PEI service is called.
309 //
310 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_SERVICE | EFI_SW_PS_PC_RESET_SYSTEM));
311 }
312
313 //
314 // Increase the call depth
315 //
316 (*RecursionDepthPointer)++;
317 DEBUG ((DEBUG_INFO, "PEI ResetSystem2: Reset call depth = %d.\n", *RecursionDepthPointer));
318
319 if (*RecursionDepthPointer <= MAX_RESET_NOTIFY_DEPTH) {
320 //
321 // Iteratively call Reset Filters and Reset Handlers.
322 //
323 for (OrderIndex = 0; OrderIndex < ARRAY_SIZE (mProcessingOrder); OrderIndex++) {
324 Hob = GetFirstGuidHob (mProcessingOrder[OrderIndex]);
325 if (Hob != NULL) {
326 List = (RESET_FILTER_LIST *)GET_GUID_HOB_DATA (Hob);
327 ASSERT (List->Signature == RESET_FILTER_LIST_SIGNATURE);
328
329 for (Index = 0; Index < List->Count; Index++) {
330 if (List->ResetFilters[Index] != NULL) {
331 List->ResetFilters[Index](ResetType, ResetStatus, DataSize, ResetData);
332 }
333 }
334 }
335 }
336 } else {
337 ASSERT (ResetType < ARRAY_SIZE (mResetTypeStr));
338 DEBUG ((DEBUG_ERROR, "PEI ResetSystem2: Maximum reset call depth is met. Use the current reset type: %s!\n", mResetTypeStr[ResetType]));
339 }
340
341 switch (ResetType) {
342 case EfiResetWarm:
343 ResetWarm ();
344 break;
345
346 case EfiResetCold:
347 ResetCold ();
348 break;
349
350 case EfiResetShutdown:
351 ResetShutdown ();
352 return;
353
354 case EfiResetPlatformSpecific:
355 ResetPlatformSpecific (DataSize, ResetData);
356 return;
357
358 default:
359 return;
360 }
361
362 //
363 // Given we should have reset getting here would be bad
364 //
365 ASSERT (FALSE);
366 }