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