2 Reset Architectural and Reset Notification protocols implementation.
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "ResetSystem.h"
12 GLOBAL_REMOVE_IF_UNREFERENCED CHAR16
*mResetTypeStr
[] = {
13 L
"Cold", L
"Warm", L
"Shutdown", L
"PlatformSpecific"
17 // The current ResetSystem() notification recursion depth
19 UINTN mResetNotifyDepth
= 0;
22 Register a notification function to be called when ResetSystem() is called.
24 The RegisterResetNotify() function registers a notification function that is called when
25 ResetSystem()is called and prior to completing the reset of the platform.
26 The registered functions must not perform a platform reset themselves. These
27 notifications are intended only for the notification of components which may need some
28 special-purpose maintenance prior to the platform resetting.
29 The list of registered reset notification functions are processed if ResetSystem()is called
30 before ExitBootServices(). The list of registered reset notification functions is ignored if
31 ResetSystem()is called after ExitBootServices().
33 @param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.
34 @param[in] ResetFunction Points to the function to be called when a ResetSystem() is executed.
36 @retval EFI_SUCCESS The reset notification function was successfully registered.
37 @retval EFI_INVALID_PARAMETER ResetFunction is NULL.
38 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to register the reset notification function.
39 @retval EFI_ALREADY_STARTED The reset notification function specified by ResetFunction has already been registered.
45 IN EFI_RESET_NOTIFICATION_PROTOCOL
*This
,
46 IN EFI_RESET_SYSTEM ResetFunction
49 RESET_NOTIFICATION_INSTANCE
*Instance
;
51 RESET_NOTIFY_ENTRY
*Entry
;
53 if (ResetFunction
== NULL
) {
54 return EFI_INVALID_PARAMETER
;
57 Instance
= RESET_NOTIFICATION_INSTANCE_FROM_THIS (This
);
59 for ( Link
= GetFirstNode (&Instance
->ResetNotifies
)
60 ; !IsNull (&Instance
->ResetNotifies
, Link
)
61 ; Link
= GetNextNode (&Instance
->ResetNotifies
, Link
)
63 Entry
= RESET_NOTIFY_ENTRY_FROM_LINK (Link
);
64 if (Entry
->ResetNotify
== ResetFunction
) {
65 return EFI_ALREADY_STARTED
;
69 ASSERT (IsNull (&Instance
->ResetNotifies
, Link
));
70 Entry
= AllocatePool (sizeof (*Entry
));
72 return EFI_OUT_OF_RESOURCES
;
74 Entry
->Signature
= RESET_NOTIFY_ENTRY_SIGNATURE
;
75 Entry
->ResetNotify
= ResetFunction
;
76 InsertTailList (&Instance
->ResetNotifies
, &Entry
->Link
);
81 Unregister a notification function.
83 The UnregisterResetNotify() function removes the previously registered
84 notification using RegisterResetNotify().
86 @param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.
87 @param[in] ResetFunction The pointer to the ResetFunction being unregistered.
89 @retval EFI_SUCCESS The reset notification function was unregistered.
90 @retval EFI_INVALID_PARAMETER ResetFunction is NULL.
91 @retval EFI_INVALID_PARAMETER The reset notification function specified by ResetFunction was not previously
92 registered using RegisterResetNotify().
97 UnregisterResetNotify (
98 IN EFI_RESET_NOTIFICATION_PROTOCOL
*This
,
99 IN EFI_RESET_SYSTEM ResetFunction
102 RESET_NOTIFICATION_INSTANCE
*Instance
;
104 RESET_NOTIFY_ENTRY
*Entry
;
106 if (ResetFunction
== NULL
) {
107 return EFI_INVALID_PARAMETER
;
110 Instance
= RESET_NOTIFICATION_INSTANCE_FROM_THIS (This
);
112 for ( Link
= GetFirstNode (&Instance
->ResetNotifies
)
113 ; !IsNull (&Instance
->ResetNotifies
, Link
)
114 ; Link
= GetNextNode (&Instance
->ResetNotifies
, Link
)
116 Entry
= RESET_NOTIFY_ENTRY_FROM_LINK (Link
);
117 if (Entry
->ResetNotify
== ResetFunction
) {
118 RemoveEntryList (&Entry
->Link
);
124 return EFI_INVALID_PARAMETER
;
127 RESET_NOTIFICATION_INSTANCE mResetNotification
= {
128 RESET_NOTIFICATION_INSTANCE_SIGNATURE
,
131 UnregisterResetNotify
133 INITIALIZE_LIST_HEAD_VARIABLE (mResetNotification
.ResetNotifies
)
136 RESET_NOTIFICATION_INSTANCE mPlatformSpecificResetFilter
= {
137 RESET_NOTIFICATION_INSTANCE_SIGNATURE
,
140 UnregisterResetNotify
142 INITIALIZE_LIST_HEAD_VARIABLE (mPlatformSpecificResetFilter
.ResetNotifies
)
145 RESET_NOTIFICATION_INSTANCE mPlatformSpecificResetHandler
= {
146 RESET_NOTIFICATION_INSTANCE_SIGNATURE
,
149 UnregisterResetNotify
151 INITIALIZE_LIST_HEAD_VARIABLE (mPlatformSpecificResetHandler
.ResetNotifies
)
155 The driver's entry point.
157 It initializes the Reset Architectural Protocol.
159 @param[in] ImageHandle The firmware allocated handle for the EFI image.
160 @param[in] SystemTable A pointer to the EFI System Table.
162 @retval EFI_SUCCESS The entry point is executed successfully.
163 @retval other Cannot install ResetArch protocol.
168 InitializeResetSystem (
169 IN EFI_HANDLE ImageHandle
,
170 IN EFI_SYSTEM_TABLE
*SystemTable
177 // Make sure the Reset Architectural Protocol is not already installed in the system
179 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gEfiResetArchProtocolGuid
);
182 // Hook the runtime service table
184 gRT
->ResetSystem
= RuntimeServiceResetSystem
;
187 // Now install the Reset RT AP on a new handle
190 Status
= gBS
->InstallMultipleProtocolInterfaces (
192 &gEfiResetArchProtocolGuid
, NULL
,
193 &gEfiResetNotificationProtocolGuid
, &mResetNotification
.ResetNotification
,
194 &gEdkiiPlatformSpecificResetFilterProtocolGuid
, &mPlatformSpecificResetFilter
.ResetNotification
,
195 &gEdkiiPlatformSpecificResetHandlerProtocolGuid
, &mPlatformSpecificResetHandler
.ResetNotification
,
198 ASSERT_EFI_ERROR (Status
);
204 Resets the entire platform.
206 @param[in] ResetType The type of reset to perform.
207 @param[in] ResetStatus The status code for the reset.
208 @param[in] DataSize The size, in bytes, of ResetData.
209 @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or
210 EfiResetShutdown the data buffer starts with a Null-terminated
211 string, optionally followed by additional binary data.
212 The string is a description that the caller may use to further
213 indicate the reason for the system reset. ResetData is only
214 valid if ResetStatus is something other than EFI_SUCCESS
215 unless the ResetType is EfiResetPlatformSpecific
216 where a minimum amount of ResetData is always required.
217 For a ResetType of EfiResetPlatformSpecific the data buffer
218 also starts with a Null-terminated string that is followed
219 by an EFI_GUID that describes the specific type of reset to perform.
223 RuntimeServiceResetSystem (
224 IN EFI_RESET_TYPE ResetType
,
225 IN EFI_STATUS ResetStatus
,
227 IN VOID
*ResetData OPTIONAL
231 RESET_NOTIFY_ENTRY
*Entry
;
234 // Only do REPORT_STATUS_CODE() on first call to RuntimeServiceResetSystem()
236 if (mResetNotifyDepth
== 0) {
238 // Indicate reset system runtime service is called.
240 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_EFI_RUNTIME_SERVICE
| EFI_SW_RS_PC_RESET_SYSTEM
));
245 DEBUG_INFO
, "DXE ResetSystem2: ResetType %s, Call Depth = %d.\n",
246 mResetTypeStr
[ResetType
], mResetNotifyDepth
249 if (mResetNotifyDepth
<= MAX_RESET_NOTIFY_DEPTH
) {
250 if (!EfiAtRuntime ()) {
252 // Call reset notification functions registered through the
253 // EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PROTOCOL.
255 for ( Link
= GetFirstNode (&mPlatformSpecificResetFilter
.ResetNotifies
)
256 ; !IsNull (&mPlatformSpecificResetFilter
.ResetNotifies
, Link
)
257 ; Link
= GetNextNode (&mPlatformSpecificResetFilter
.ResetNotifies
, Link
)
259 Entry
= RESET_NOTIFY_ENTRY_FROM_LINK (Link
);
260 Entry
->ResetNotify (ResetType
, ResetStatus
, DataSize
, ResetData
);
263 // Call reset notification functions registered through the
264 // EFI_RESET_NOTIFICATION_PROTOCOL.
266 for ( Link
= GetFirstNode (&mResetNotification
.ResetNotifies
)
267 ; !IsNull (&mResetNotification
.ResetNotifies
, Link
)
268 ; Link
= GetNextNode (&mResetNotification
.ResetNotifies
, Link
)
270 Entry
= RESET_NOTIFY_ENTRY_FROM_LINK (Link
);
271 Entry
->ResetNotify (ResetType
, ResetStatus
, DataSize
, ResetData
);
274 // call reset notification functions registered through the
275 // EDKII_PLATFORM_SPECIFIC_RESET_HANDLER_PROTOCOL.
277 for ( Link
= GetFirstNode (&mPlatformSpecificResetHandler
.ResetNotifies
)
278 ; !IsNull (&mPlatformSpecificResetHandler
.ResetNotifies
, Link
)
279 ; Link
= GetNextNode (&mPlatformSpecificResetHandler
.ResetNotifies
, Link
)
281 Entry
= RESET_NOTIFY_ENTRY_FROM_LINK (Link
);
282 Entry
->ResetNotify (ResetType
, ResetStatus
, DataSize
, ResetData
);
286 ASSERT (ResetType
< ARRAY_SIZE (mResetTypeStr
));
287 DEBUG ((DEBUG_ERROR
, "DXE ResetSystem2: Maximum reset call depth is met. Use the current reset type: %s!\n", mResetTypeStr
[ResetType
]));
300 case EfiResetShutdown
:
304 case EfiResetPlatformSpecific
:
305 ResetPlatformSpecific (DataSize
, ResetData
);
313 // Given we should have reset getting here would be bad