]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/ResetSystemPei/ResetSystem.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / ResetSystemPei / ResetSystem.c
1 /** @file
2 Implementation of Reset2, ResetFilter and ResetHandler PPIs.
3
4 Copyright (c) 2017 - 2018, 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 (CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetFilterPpiGuid) ||
112 CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetNotificationPpiGuid) ||
113 CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetHandlerPpiGuid)
114 );
115
116 Hob = GetFirstGuidHob (ResetFilter->Guid);
117 if (Hob == NULL) {
118 //
119 // When the GUIDed HOB doesn't exist, create it.
120 //
121 List = (RESET_FILTER_LIST *)BuildGuidHob (
122 ResetFilter->Guid,
123 sizeof (RESET_FILTER_LIST) + sizeof (EFI_RESET_SYSTEM) * PcdGet32 (PcdMaximumPeiResetNotifies)
124 );
125 if (List == NULL) {
126 return EFI_OUT_OF_RESOURCES;
127 }
128 List->Signature = RESET_FILTER_LIST_SIGNATURE;
129 List->Count = PcdGet32 (PcdMaximumPeiResetNotifies);
130 ZeroMem (List->ResetFilters, sizeof (EFI_RESET_SYSTEM) * List->Count);
131 List->ResetFilters[0] = ResetFunction;
132 return EFI_SUCCESS;
133 } else {
134 List = (RESET_FILTER_LIST *)GET_GUID_HOB_DATA (Hob);
135 ASSERT (List->Signature == RESET_FILTER_LIST_SIGNATURE);
136 //
137 // Firstly check whether the ResetFunction is already registerred.
138 //
139 for (Index = 0; Index < List->Count; Index++) {
140 if (List->ResetFilters[Index] == ResetFunction) {
141 break;
142 }
143 }
144 if (Index != List->Count) {
145 return EFI_ALREADY_STARTED;
146 }
147
148 //
149 // Secondly find the first free slot.
150 //
151 for (Index = 0; Index < List->Count; Index++) {
152 if (List->ResetFilters[Index] == NULL) {
153 break;
154 }
155 }
156
157 if (Index == List->Count) {
158 return EFI_OUT_OF_RESOURCES;
159 }
160 List->ResetFilters[Index] = ResetFunction;
161 return EFI_SUCCESS;
162 }
163 }
164
165 /**
166 Unregister a notification function.
167
168 The UnregisterResetNotify() function removes the previously registered
169 notification using RegisterResetNotify().
170
171 @param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.
172 @param[in] ResetFunction The pointer to the ResetFunction being unregistered.
173
174 @retval EFI_SUCCESS The reset notification function was unregistered.
175 @retval EFI_INVALID_PARAMETER ResetFunction is NULL.
176 @retval EFI_INVALID_PARAMETER The reset notification function specified by ResetFunction was not previously
177 registered using RegisterResetNotify().
178
179 **/
180 EFI_STATUS
181 EFIAPI
182 UnregisterResetNotify (
183 IN EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PPI *This,
184 IN EFI_RESET_SYSTEM ResetFunction
185 )
186 {
187
188 RESET_FILTER_INSTANCE *ResetFilter;
189 RESET_FILTER_LIST *List;
190 VOID *Hob;
191 UINTN Index;
192
193 if (ResetFunction == NULL) {
194 return EFI_INVALID_PARAMETER;
195 }
196
197 ResetFilter = (RESET_FILTER_INSTANCE *)This;
198 ASSERT (CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetFilterPpiGuid) ||
199 CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetNotificationPpiGuid) ||
200 CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetHandlerPpiGuid)
201 );
202
203 Hob = GetFirstGuidHob (ResetFilter->Guid);
204 if (Hob == NULL) {
205 return EFI_INVALID_PARAMETER;
206 }
207
208 List = (RESET_FILTER_LIST *)GET_GUID_HOB_DATA (Hob);
209 ASSERT (List->Signature == RESET_FILTER_LIST_SIGNATURE);
210 for (Index = 0; Index < List->Count; Index++) {
211 if (List->ResetFilters[Index] == ResetFunction) {
212 break;
213 }
214 }
215
216 if (Index == List->Count) {
217 return EFI_INVALID_PARAMETER;
218 }
219
220 List->ResetFilters[Index] = NULL;
221 return EFI_SUCCESS;
222 }
223
224
225 /**
226 The PEIM's entry point.
227
228 It initializes the Reset2, ResetFilter and ResetHandler PPIs.
229
230 @param[in] FileHandle Handle of the file being invoked.
231 @param[in] PeiServices Describes the list of possible PEI Services.
232
233 @retval EFI_SUCCESS The entry point is executed successfully.
234 @retval EFI_ALREADY_STARTED The Reset2 PPI was already installed.
235 @retval others Status code returned from PeiServicesInstallPpi().
236
237 **/
238 EFI_STATUS
239 EFIAPI
240 InitializeResetSystem (
241 IN EFI_PEI_FILE_HANDLE FileHandle,
242 IN CONST EFI_PEI_SERVICES **PeiServices
243 )
244 {
245 EFI_STATUS Status;
246 VOID *Ppi;
247
248 Status = PeiServicesLocatePpi (&gEfiPeiReset2PpiGuid, 0, NULL, (VOID **)&Ppi);
249 if (Status != EFI_NOT_FOUND) {
250 return EFI_ALREADY_STARTED;
251 }
252
253 PeiServicesInstallPpi (mPpiListReset);
254
255 return Status;
256 }
257
258 /**
259 Resets the entire platform.
260
261 @param[in] ResetType The type of reset to perform.
262 @param[in] ResetStatus The status code for the reset.
263 @param[in] DataSize The size, in bytes, of ResetData.
264 @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or
265 EfiResetShutdown the data buffer starts with a Null-terminated
266 string, optionally followed by additional binary data.
267 The string is a description that the caller may use to further
268 indicate the reason for the system reset. ResetData is only
269 valid if ResetStatus is something other than EFI_SUCCESS
270 unless the ResetType is EfiResetPlatformSpecific
271 where a minimum amount of ResetData is always required.
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 // Only do REPORT_STATUS_CODE() on first call to ResetSystem()
304 //
305 if (*RecursionDepthPointer == 0) {
306 //
307 // Indicate reset system PEI service is called.
308 //
309 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_SERVICE | EFI_SW_PS_PC_RESET_SYSTEM));
310 }
311
312 //
313 // Increase the call depth
314 //
315 (*RecursionDepthPointer)++;
316 DEBUG ((DEBUG_INFO, "PEI ResetSystem2: Reset call depth = %d.\n", *RecursionDepthPointer));
317
318 if (*RecursionDepthPointer <= MAX_RESET_NOTIFY_DEPTH) {
319 //
320 // Iteratively call Reset Filters and Reset Handlers.
321 //
322 for (OrderIndex = 0; OrderIndex < ARRAY_SIZE (mProcessingOrder); OrderIndex++) {
323 Hob = GetFirstGuidHob (mProcessingOrder[OrderIndex]);
324 if (Hob != NULL) {
325 List = (RESET_FILTER_LIST *)GET_GUID_HOB_DATA (Hob);
326 ASSERT (List->Signature == RESET_FILTER_LIST_SIGNATURE);
327
328 for (Index = 0; Index < List->Count; Index++) {
329 if (List->ResetFilters[Index] != NULL) {
330 List->ResetFilters[Index] (ResetType, ResetStatus, DataSize, ResetData);
331 }
332 }
333 }
334 }
335 } else {
336 ASSERT (ResetType < ARRAY_SIZE (mResetTypeStr));
337 DEBUG ((DEBUG_ERROR, "PEI ResetSystem2: Maximum reset call depth is met. Use the current reset type: %s!\n", mResetTypeStr[ResetType]));
338 }
339
340 switch (ResetType) {
341 case EfiResetWarm:
342 ResetWarm ();
343 break;
344
345 case EfiResetCold:
346 ResetCold ();
347 break;
348
349 case EfiResetShutdown:
350 ResetShutdown ();
351 return ;
352
353 case EfiResetPlatformSpecific:
354 ResetPlatformSpecific (DataSize, ResetData);
355 return;
356
357 default:
358 return ;
359 }
360
361 //
362 // Given we should have reset getting here would be bad
363 //
364 ASSERT (FALSE);
365 }