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