2 Reset Architectural and Reset Notification protocols implementation.
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
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
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.
16 #include "ResetSystem.h"
18 GLOBAL_REMOVE_IF_UNREFERENCED CHAR16
*mResetTypeStr
[] = {
19 L
"Cold", L
"Warm", L
"Shutdown", L
"PlatformSpecific"
23 // The current ResetSystem() notification recursion depth
25 UINTN mResetNotifyDepth
= 0;
28 Register a notification function to be called when ResetSystem() is called.
30 The RegisterResetNotify() function registers a notification function that is called when
31 ResetSystem()is called and prior to completing the reset of the platform.
32 The registered functions must not perform a platform reset themselves. These
33 notifications are intended only for the notification of components which may need some
34 special-purpose maintenance prior to the platform resetting.
35 The list of registered reset notification functions are processed if ResetSystem()is called
36 before ExitBootServices(). The list of registered reset notification functions is ignored if
37 ResetSystem()is called after ExitBootServices().
39 @param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.
40 @param[in] ResetFunction Points to the function to be called when a ResetSystem() is executed.
42 @retval EFI_SUCCESS The reset notification function was successfully registered.
43 @retval EFI_INVALID_PARAMETER ResetFunction is NULL.
44 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to register the reset notification function.
45 @retval EFI_ALREADY_STARTED The reset notification function specified by ResetFunction has already been registered.
51 IN EFI_RESET_NOTIFICATION_PROTOCOL
*This
,
52 IN EFI_RESET_SYSTEM ResetFunction
55 RESET_NOTIFICATION_INSTANCE
*Instance
;
57 RESET_NOTIFY_ENTRY
*Entry
;
59 if (ResetFunction
== NULL
) {
60 return EFI_INVALID_PARAMETER
;
63 Instance
= RESET_NOTIFICATION_INSTANCE_FROM_THIS (This
);
65 for ( Link
= GetFirstNode (&Instance
->ResetNotifies
)
66 ; !IsNull (&Instance
->ResetNotifies
, Link
)
67 ; Link
= GetNextNode (&Instance
->ResetNotifies
, Link
)
69 Entry
= RESET_NOTIFY_ENTRY_FROM_LINK (Link
);
70 if (Entry
->ResetNotify
== ResetFunction
) {
71 return EFI_ALREADY_STARTED
;
75 ASSERT (IsNull (&Instance
->ResetNotifies
, Link
));
76 Entry
= AllocatePool (sizeof (*Entry
));
78 return EFI_OUT_OF_RESOURCES
;
80 Entry
->Signature
= RESET_NOTIFY_ENTRY_SIGNATURE
;
81 Entry
->ResetNotify
= ResetFunction
;
82 InsertTailList (&Instance
->ResetNotifies
, &Entry
->Link
);
87 Unregister a notification function.
89 The UnregisterResetNotify() function removes the previously registered
90 notification using RegisterResetNotify().
92 @param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.
93 @param[in] ResetFunction The pointer to the ResetFunction being unregistered.
95 @retval EFI_SUCCESS The reset notification function was unregistered.
96 @retval EFI_INVALID_PARAMETER ResetFunction is NULL.
97 @retval EFI_INVALID_PARAMETER The reset notification function specified by ResetFunction was not previously
98 registered using RegisterResetNotify().
103 UnregisterResetNotify (
104 IN EFI_RESET_NOTIFICATION_PROTOCOL
*This
,
105 IN EFI_RESET_SYSTEM ResetFunction
108 RESET_NOTIFICATION_INSTANCE
*Instance
;
110 RESET_NOTIFY_ENTRY
*Entry
;
112 if (ResetFunction
== NULL
) {
113 return EFI_INVALID_PARAMETER
;
116 Instance
= RESET_NOTIFICATION_INSTANCE_FROM_THIS (This
);
118 for ( Link
= GetFirstNode (&Instance
->ResetNotifies
)
119 ; !IsNull (&Instance
->ResetNotifies
, Link
)
120 ; Link
= GetNextNode (&Instance
->ResetNotifies
, Link
)
122 Entry
= RESET_NOTIFY_ENTRY_FROM_LINK (Link
);
123 if (Entry
->ResetNotify
== ResetFunction
) {
124 RemoveEntryList (&Entry
->Link
);
130 return EFI_INVALID_PARAMETER
;
133 RESET_NOTIFICATION_INSTANCE mResetNotification
= {
134 RESET_NOTIFICATION_INSTANCE_SIGNATURE
,
137 UnregisterResetNotify
139 INITIALIZE_LIST_HEAD_VARIABLE (mResetNotification
.ResetNotifies
)
142 RESET_NOTIFICATION_INSTANCE mPlatformSpecificResetFilter
= {
143 RESET_NOTIFICATION_INSTANCE_SIGNATURE
,
146 UnregisterResetNotify
148 INITIALIZE_LIST_HEAD_VARIABLE (mPlatformSpecificResetFilter
.ResetNotifies
)
151 RESET_NOTIFICATION_INSTANCE mPlatformSpecificResetHandler
= {
152 RESET_NOTIFICATION_INSTANCE_SIGNATURE
,
155 UnregisterResetNotify
157 INITIALIZE_LIST_HEAD_VARIABLE (mPlatformSpecificResetHandler
.ResetNotifies
)
161 The driver's entry point.
163 It initializes the Reset Architectural Protocol.
165 @param[in] ImageHandle The firmware allocated handle for the EFI image.
166 @param[in] SystemTable A pointer to the EFI System Table.
168 @retval EFI_SUCCESS The entry point is executed successfully.
169 @retval other Cannot install ResetArch protocol.
174 InitializeResetSystem (
175 IN EFI_HANDLE ImageHandle
,
176 IN EFI_SYSTEM_TABLE
*SystemTable
183 // Make sure the Reset Architectural Protocol is not already installed in the system
185 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gEfiResetArchProtocolGuid
);
188 // Hook the runtime service table
190 gRT
->ResetSystem
= RuntimeServiceResetSystem
;
193 // Now install the Reset RT AP on a new handle
196 Status
= gBS
->InstallMultipleProtocolInterfaces (
198 &gEfiResetArchProtocolGuid
, NULL
,
199 &gEfiResetNotificationProtocolGuid
, &mResetNotification
.ResetNotification
,
200 &gEdkiiPlatformSpecificResetFilterProtocolGuid
, &mPlatformSpecificResetFilter
.ResetNotification
,
201 &gEdkiiPlatformSpecificResetHandlerProtocolGuid
, &mPlatformSpecificResetHandler
.ResetNotification
,
204 ASSERT_EFI_ERROR (Status
);
210 Resets the entire platform.
212 @param[in] ResetType The type of reset to perform.
213 @param[in] ResetStatus The status code for the reset.
214 @param[in] DataSize The size, in bytes, of ResetData.
215 @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or
216 EfiResetShutdown the data buffer starts with a Null-terminated
217 string, optionally followed by additional binary data.
218 The string is a description that the caller may use to further
219 indicate the reason for the system reset. ResetData is only
220 valid if ResetStatus is something other than EFI_SUCCESS
221 unless the ResetType is EfiResetPlatformSpecific
222 where a minimum amount of ResetData is always required.
223 For a ResetType of EfiResetPlatformSpecific the data buffer
224 also starts with a Null-terminated string that is followed
225 by an EFI_GUID that describes the specific type of reset to perform.
229 RuntimeServiceResetSystem (
230 IN EFI_RESET_TYPE ResetType
,
231 IN EFI_STATUS ResetStatus
,
233 IN VOID
*ResetData OPTIONAL
237 RESET_NOTIFY_ENTRY
*Entry
;
240 // Only do REPORT_STATUS_CODE() on first call to RuntimeServiceResetSystem()
242 if (mResetNotifyDepth
== 0) {
244 // Indicate reset system runtime service is called.
246 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_EFI_RUNTIME_SERVICE
| EFI_SW_RS_PC_RESET_SYSTEM
));
251 DEBUG_INFO
, "DXE ResetSystem2: ResetType %s, Call Depth = %d.\n",
252 mResetTypeStr
[ResetType
], mResetNotifyDepth
255 if (mResetNotifyDepth
<= MAX_RESET_NOTIFY_DEPTH
) {
256 if (!EfiAtRuntime ()) {
258 // Call reset notification functions registered through the
259 // EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PROTOCOL.
261 for ( Link
= GetFirstNode (&mPlatformSpecificResetFilter
.ResetNotifies
)
262 ; !IsNull (&mPlatformSpecificResetFilter
.ResetNotifies
, Link
)
263 ; Link
= GetNextNode (&mPlatformSpecificResetFilter
.ResetNotifies
, Link
)
265 Entry
= RESET_NOTIFY_ENTRY_FROM_LINK (Link
);
266 Entry
->ResetNotify (ResetType
, ResetStatus
, DataSize
, ResetData
);
269 // Call reset notification functions registered through the
270 // EFI_RESET_NOTIFICATION_PROTOCOL.
272 for ( Link
= GetFirstNode (&mResetNotification
.ResetNotifies
)
273 ; !IsNull (&mResetNotification
.ResetNotifies
, Link
)
274 ; Link
= GetNextNode (&mResetNotification
.ResetNotifies
, Link
)
276 Entry
= RESET_NOTIFY_ENTRY_FROM_LINK (Link
);
277 Entry
->ResetNotify (ResetType
, ResetStatus
, DataSize
, ResetData
);
280 // call reset notification functions registered through the
281 // EDKII_PLATFORM_SPECIFIC_RESET_HANDLER_PROTOCOL.
283 for ( Link
= GetFirstNode (&mPlatformSpecificResetHandler
.ResetNotifies
)
284 ; !IsNull (&mPlatformSpecificResetHandler
.ResetNotifies
, Link
)
285 ; Link
= GetNextNode (&mPlatformSpecificResetHandler
.ResetNotifies
, Link
)
287 Entry
= RESET_NOTIFY_ENTRY_FROM_LINK (Link
);
288 Entry
->ResetNotify (ResetType
, ResetStatus
, DataSize
, ResetData
);
292 ASSERT (ResetType
< ARRAY_SIZE (mResetTypeStr
));
293 DEBUG ((DEBUG_ERROR
, "DXE ResetSystem2: Maximum reset call depth is met. Use the current reset type: %s!\n", mResetTypeStr
[ResetType
]));
306 case EfiResetShutdown
:
310 case EfiResetPlatformSpecific
:
311 ResetPlatformSpecific (DataSize
, ResetData
);
319 // Given we should have reset getting here would be bad