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