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