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