]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystem.c
MdeModulePkg/ResetSystemRuntimeDxe: Add more info in debug message
[mirror_edk2.git] / MdeModulePkg / Universal / ResetSystemRuntimeDxe / ResetSystem.c
CommitLineData
51a0c5f2 1/** @file\r
cf6da556 2 Reset Architectural and Reset Notification protocols implementation.\r
51a0c5f2 3\r
d1102dba 4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
51a0c5f2 5\r
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "ResetSystem.h"\r
17\r
4bf95a9f
RN
18GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mResetTypeStr[] = {\r
19 L"Cold", L"Warm", L"Shutdown", L"PlatformSpecific"\r
20};\r
21\r
99a6529e
MK
22//\r
23// The current ResetSystem() notification recursion depth\r
24//\r
25UINTN mResetNotifyDepth = 0;\r
26\r
cf6da556
RN
27/**\r
28 Register a notification function to be called when ResetSystem() is called.\r
29\r
30 The RegisterResetNotify() function registers a notification function that is called when\r
31 ResetSystem()is called and prior to completing the reset of the platform.\r
32 The registered functions must not perform a platform reset themselves. These\r
33 notifications are intended only for the notification of components which may need some\r
34 special-purpose maintenance prior to the platform resetting.\r
35 The list of registered reset notification functions are processed if ResetSystem()is called\r
36 before ExitBootServices(). The list of registered reset notification functions is ignored if\r
37 ResetSystem()is called after ExitBootServices().\r
38\r
39 @param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.\r
40 @param[in] ResetFunction Points to the function to be called when a ResetSystem() is executed.\r
41\r
42 @retval EFI_SUCCESS The reset notification function was successfully registered.\r
43 @retval EFI_INVALID_PARAMETER ResetFunction is NULL.\r
44 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to register the reset notification function.\r
45 @retval EFI_ALREADY_STARTED The reset notification function specified by ResetFunction has already been registered.\r
46\r
47**/\r
48EFI_STATUS\r
49EFIAPI\r
50RegisterResetNotify (\r
51 IN EFI_RESET_NOTIFICATION_PROTOCOL *This,\r
52 IN EFI_RESET_SYSTEM ResetFunction\r
53 )\r
54{\r
55 RESET_NOTIFICATION_INSTANCE *Instance;\r
56 LIST_ENTRY *Link;\r
57 RESET_NOTIFY_ENTRY *Entry;\r
58\r
59 if (ResetFunction == NULL) {\r
60 return EFI_INVALID_PARAMETER;\r
61 }\r
62\r
63 Instance = RESET_NOTIFICATION_INSTANCE_FROM_THIS (This);\r
64\r
65 for ( Link = GetFirstNode (&Instance->ResetNotifies)\r
66 ; !IsNull (&Instance->ResetNotifies, Link)\r
67 ; Link = GetNextNode (&Instance->ResetNotifies, Link)\r
68 ) {\r
69 Entry = RESET_NOTIFY_ENTRY_FROM_LINK (Link);\r
70 if (Entry->ResetNotify == ResetFunction) {\r
71 return EFI_ALREADY_STARTED;\r
72 }\r
73 }\r
74\r
75 ASSERT (IsNull (&Instance->ResetNotifies, Link));\r
76 Entry = AllocatePool (sizeof (*Entry));\r
77 if (Entry == NULL) {\r
78 return EFI_OUT_OF_RESOURCES;\r
79 }\r
80 Entry->Signature = RESET_NOTIFY_ENTRY_SIGNATURE;\r
81 Entry->ResetNotify = ResetFunction;\r
82 InsertTailList (&Instance->ResetNotifies, &Entry->Link);\r
83 return EFI_SUCCESS;\r
84}\r
85\r
86/**\r
87 Unregister a notification function.\r
88\r
89 The UnregisterResetNotify() function removes the previously registered\r
90 notification using RegisterResetNotify().\r
91\r
92 @param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.\r
93 @param[in] ResetFunction The pointer to the ResetFunction being unregistered.\r
94\r
95 @retval EFI_SUCCESS The reset notification function was unregistered.\r
96 @retval EFI_INVALID_PARAMETER ResetFunction is NULL.\r
97 @retval EFI_INVALID_PARAMETER The reset notification function specified by ResetFunction was not previously\r
98 registered using RegisterResetNotify().\r
99\r
100**/\r
101EFI_STATUS\r
102EFIAPI\r
103UnregisterResetNotify (\r
104 IN EFI_RESET_NOTIFICATION_PROTOCOL *This,\r
105 IN EFI_RESET_SYSTEM ResetFunction\r
106 )\r
107{\r
108 RESET_NOTIFICATION_INSTANCE *Instance;\r
109 LIST_ENTRY *Link;\r
110 RESET_NOTIFY_ENTRY *Entry;\r
111\r
112 if (ResetFunction == NULL) {\r
113 return EFI_INVALID_PARAMETER;\r
114 }\r
115\r
116 Instance = RESET_NOTIFICATION_INSTANCE_FROM_THIS (This);\r
117\r
118 for ( Link = GetFirstNode (&Instance->ResetNotifies)\r
119 ; !IsNull (&Instance->ResetNotifies, Link)\r
120 ; Link = GetNextNode (&Instance->ResetNotifies, Link)\r
121 ) {\r
122 Entry = RESET_NOTIFY_ENTRY_FROM_LINK (Link);\r
123 if (Entry->ResetNotify == ResetFunction) {\r
124 RemoveEntryList (&Entry->Link);\r
125 FreePool (Entry);\r
126 return EFI_SUCCESS;\r
127 }\r
128 }\r
129\r
130 return EFI_INVALID_PARAMETER;\r
131}\r
132\r
133RESET_NOTIFICATION_INSTANCE mResetNotification = {\r
134 RESET_NOTIFICATION_INSTANCE_SIGNATURE,\r
135 {\r
136 RegisterResetNotify,\r
137 UnregisterResetNotify\r
138 },\r
139 INITIALIZE_LIST_HEAD_VARIABLE (mResetNotification.ResetNotifies)\r
140};\r
141\r
99a6529e
MK
142RESET_NOTIFICATION_INSTANCE mPlatformSpecificResetFilter = {\r
143 RESET_NOTIFICATION_INSTANCE_SIGNATURE,\r
144 {\r
145 RegisterResetNotify,\r
146 UnregisterResetNotify\r
147 },\r
148 INITIALIZE_LIST_HEAD_VARIABLE (mPlatformSpecificResetFilter.ResetNotifies)\r
149};\r
150\r
151RESET_NOTIFICATION_INSTANCE mPlatformSpecificResetHandler = {\r
152 RESET_NOTIFICATION_INSTANCE_SIGNATURE,\r
153 {\r
154 RegisterResetNotify,\r
155 UnregisterResetNotify\r
156 },\r
157 INITIALIZE_LIST_HEAD_VARIABLE (mPlatformSpecificResetHandler.ResetNotifies)\r
158};\r
159\r
51a0c5f2 160/**\r
161 The driver's entry point.\r
162\r
163 It initializes the Reset Architectural Protocol.\r
164\r
d1102dba 165 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
51a0c5f2 166 @param[in] SystemTable A pointer to the EFI System Table.\r
d1102dba 167\r
51a0c5f2 168 @retval EFI_SUCCESS The entry point is executed successfully.\r
169 @retval other Cannot install ResetArch protocol.\r
170\r
171**/\r
172EFI_STATUS\r
173EFIAPI\r
174InitializeResetSystem (\r
175 IN EFI_HANDLE ImageHandle,\r
176 IN EFI_SYSTEM_TABLE *SystemTable\r
177 )\r
178{\r
179 EFI_STATUS Status;\r
34861f43 180 EFI_HANDLE Handle;\r
51a0c5f2 181\r
182 //\r
183 // Make sure the Reset Architectural Protocol is not already installed in the system\r
184 //\r
185 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiResetArchProtocolGuid);\r
186\r
187 //\r
188 // Hook the runtime service table\r
189 //\r
190 gRT->ResetSystem = ResetSystem;\r
191\r
192 //\r
193 // Now install the Reset RT AP on a new handle\r
194 //\r
34861f43 195 Handle = NULL;\r
51a0c5f2 196 Status = gBS->InstallMultipleProtocolInterfaces (\r
34861f43 197 &Handle,\r
cf6da556
RN
198 &gEfiResetArchProtocolGuid, NULL,\r
199 &gEfiResetNotificationProtocolGuid, &mResetNotification.ResetNotification,\r
99a6529e
MK
200 &gEdkiiPlatformSpecificResetFilterProtocolGuid, &mPlatformSpecificResetFilter.ResetNotification,\r
201 &gEdkiiPlatformSpecificResetHandlerProtocolGuid, &mPlatformSpecificResetHandler.ResetNotification,\r
51a0c5f2 202 NULL\r
203 );\r
204 ASSERT_EFI_ERROR (Status);\r
205\r
206 return Status;\r
207}\r
208\r
51a0c5f2 209/**\r
d1102dba 210 Put the system into S3 power state.\r
51a0c5f2 211**/\r
212VOID\r
213DoS3 (\r
214 VOID\r
215 )\r
216{\r
217 EnterS3WithImmediateWake ();\r
218\r
219 //\r
220 // Should not return\r
221 //\r
222 CpuDeadLoop ();\r
223}\r
224\r
225/**\r
226 Resets the entire platform.\r
227\r
228 @param[in] ResetType The type of reset to perform.\r
229 @param[in] ResetStatus The status code for the reset.\r
37078045 230 @param[in] DataSize The size, in bytes, of ResetData.\r
51a0c5f2 231 @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or\r
232 EfiResetShutdown the data buffer starts with a Null-terminated\r
233 string, optionally followed by additional binary data.\r
37078045
RN
234 The string is a description that the caller may use to further\r
235 indicate the reason for the system reset. ResetData is only\r
236 valid if ResetStatus is something other than EFI_SUCCESS\r
237 unless the ResetType is EfiResetPlatformSpecific\r
238 where a minimum amount of ResetData is always required.\r
eeeabe40
SZ
239 For a ResetType of EfiResetPlatformSpecific the data buffer\r
240 also starts with a Null-terminated string that is followed\r
241 by an EFI_GUID that describes the specific type of reset to perform.\r
51a0c5f2 242**/\r
243VOID\r
244EFIAPI\r
245ResetSystem (\r
246 IN EFI_RESET_TYPE ResetType,\r
247 IN EFI_STATUS ResetStatus,\r
248 IN UINTN DataSize,\r
249 IN VOID *ResetData OPTIONAL\r
250 )\r
251{\r
cf6da556
RN
252 EFI_STATUS Status;\r
253 UINTN Size;\r
254 UINTN CapsuleDataPtr;\r
255 LIST_ENTRY *Link;\r
256 RESET_NOTIFY_ENTRY *Entry;\r
99a6529e 257\r
37623a5c 258 //\r
99a6529e 259 // Only do REPORT_STATUS_CODE() on first call to ResetSystem()\r
37623a5c 260 //\r
99a6529e
MK
261 if (mResetNotifyDepth == 0) {\r
262 //\r
263 // Indicate reset system runtime service is called.\r
264 //\r
265 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_EFI_RUNTIME_SERVICE | EFI_SW_RS_PC_RESET_SYSTEM));\r
266 }\r
51a0c5f2 267\r
99a6529e 268 mResetNotifyDepth++;\r
9c227e07
RN
269 DEBUG ((\r
270 DEBUG_INFO, "DXE ResetSystem2: ResetType %s, Call Depth = %d.\n",\r
271 mResetTypeStr[ResetType], mResetNotifyDepth\r
272 ));\r
4bf95a9f
RN
273\r
274 if (mResetNotifyDepth <= MAX_RESET_NOTIFY_DEPTH) {\r
275 if (!EfiAtRuntime ()) {\r
276 //\r
277 // Call reset notification functions registered through the\r
278 // EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PROTOCOL.\r
279 //\r
280 for ( Link = GetFirstNode (&mPlatformSpecificResetFilter.ResetNotifies)\r
281 ; !IsNull (&mPlatformSpecificResetFilter.ResetNotifies, Link)\r
282 ; Link = GetNextNode (&mPlatformSpecificResetFilter.ResetNotifies, Link)\r
283 ) {\r
284 Entry = RESET_NOTIFY_ENTRY_FROM_LINK (Link);\r
285 Entry->ResetNotify (ResetType, ResetStatus, DataSize, ResetData);\r
286 }\r
287 //\r
288 // Call reset notification functions registered through the\r
289 // EFI_RESET_NOTIFICATION_PROTOCOL.\r
290 //\r
291 for ( Link = GetFirstNode (&mResetNotification.ResetNotifies)\r
292 ; !IsNull (&mResetNotification.ResetNotifies, Link)\r
293 ; Link = GetNextNode (&mResetNotification.ResetNotifies, Link)\r
294 ) {\r
295 Entry = RESET_NOTIFY_ENTRY_FROM_LINK (Link);\r
296 Entry->ResetNotify (ResetType, ResetStatus, DataSize, ResetData);\r
297 }\r
298 //\r
d1102dba 299 // call reset notification functions registered through the\r
4bf95a9f
RN
300 // EDKII_PLATFORM_SPECIFIC_RESET_HANDLER_PROTOCOL.\r
301 //\r
302 for ( Link = GetFirstNode (&mPlatformSpecificResetHandler.ResetNotifies)\r
303 ; !IsNull (&mPlatformSpecificResetHandler.ResetNotifies, Link)\r
304 ; Link = GetNextNode (&mPlatformSpecificResetHandler.ResetNotifies, Link)\r
305 ) {\r
306 Entry = RESET_NOTIFY_ENTRY_FROM_LINK (Link);\r
307 Entry->ResetNotify (ResetType, ResetStatus, DataSize, ResetData);\r
308 }\r
cf6da556 309 }\r
4bf95a9f
RN
310 } else {\r
311 ASSERT (ResetType < ARRAY_SIZE (mResetTypeStr));\r
312 DEBUG ((DEBUG_ERROR, "DXE ResetSystem2: Maximum reset call depth is met. Use the current reset type: %s!\n", mResetTypeStr[ResetType]));\r
cf6da556
RN
313 }\r
314\r
51a0c5f2 315 switch (ResetType) {\r
316 case EfiResetWarm:\r
317\r
318 //\r
319 //Check if there are pending capsules to process\r
320 //\r
321 Size = sizeof (CapsuleDataPtr);\r
322 Status = EfiGetVariable (\r
323 EFI_CAPSULE_VARIABLE_NAME,\r
324 &gEfiCapsuleVendorGuid,\r
325 NULL,\r
326 &Size,\r
327 (VOID *) &CapsuleDataPtr\r
328 );\r
329\r
330 if (Status == EFI_SUCCESS) {\r
331 //\r
332 //Process capsules across a system reset.\r
333 //\r
334 DoS3();\r
335 }\r
336\r
337 ResetWarm ();\r
51a0c5f2 338 break;\r
339\r
340 case EfiResetCold:\r
341 ResetCold ();\r
342 break;\r
343\r
344 case EfiResetShutdown:\r
345 ResetShutdown ();\r
346 return ;\r
347\r
37078045
RN
348 case EfiResetPlatformSpecific:\r
349 ResetPlatformSpecific (DataSize, ResetData);\r
350 return;\r
351\r
51a0c5f2 352 default:\r
353 return ;\r
354 }\r
355\r
356 //\r
357 // Given we should have reset getting here would be bad\r
358 //\r
359 ASSERT (FALSE);\r
360}\r