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