]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystem.c
MdeModulePkg/ResetSystem: Implement ResetNotification protocol
[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
34861f43 4 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>\r
51a0c5f2 5\r
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "ResetSystem.h"\r
17\r
cf6da556
RN
18/**\r
19 Register a notification function to be called when ResetSystem() is called.\r
20\r
21 The RegisterResetNotify() function registers a notification function that is called when\r
22 ResetSystem()is called and prior to completing the reset of the platform.\r
23 The registered functions must not perform a platform reset themselves. These\r
24 notifications are intended only for the notification of components which may need some\r
25 special-purpose maintenance prior to the platform resetting.\r
26 The list of registered reset notification functions are processed if ResetSystem()is called\r
27 before ExitBootServices(). The list of registered reset notification functions is ignored if\r
28 ResetSystem()is called after ExitBootServices().\r
29\r
30 @param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.\r
31 @param[in] ResetFunction Points to the function to be called when a ResetSystem() is executed.\r
32\r
33 @retval EFI_SUCCESS The reset notification function was successfully registered.\r
34 @retval EFI_INVALID_PARAMETER ResetFunction is NULL.\r
35 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to register the reset notification function.\r
36 @retval EFI_ALREADY_STARTED The reset notification function specified by ResetFunction has already been registered.\r
37\r
38**/\r
39EFI_STATUS\r
40EFIAPI\r
41RegisterResetNotify (\r
42 IN EFI_RESET_NOTIFICATION_PROTOCOL *This,\r
43 IN EFI_RESET_SYSTEM ResetFunction\r
44 )\r
45{\r
46 RESET_NOTIFICATION_INSTANCE *Instance;\r
47 LIST_ENTRY *Link;\r
48 RESET_NOTIFY_ENTRY *Entry;\r
49\r
50 if (ResetFunction == NULL) {\r
51 return EFI_INVALID_PARAMETER;\r
52 }\r
53\r
54 Instance = RESET_NOTIFICATION_INSTANCE_FROM_THIS (This);\r
55\r
56 for ( Link = GetFirstNode (&Instance->ResetNotifies)\r
57 ; !IsNull (&Instance->ResetNotifies, Link)\r
58 ; Link = GetNextNode (&Instance->ResetNotifies, Link)\r
59 ) {\r
60 Entry = RESET_NOTIFY_ENTRY_FROM_LINK (Link);\r
61 if (Entry->ResetNotify == ResetFunction) {\r
62 return EFI_ALREADY_STARTED;\r
63 }\r
64 }\r
65\r
66 ASSERT (IsNull (&Instance->ResetNotifies, Link));\r
67 Entry = AllocatePool (sizeof (*Entry));\r
68 if (Entry == NULL) {\r
69 return EFI_OUT_OF_RESOURCES;\r
70 }\r
71 Entry->Signature = RESET_NOTIFY_ENTRY_SIGNATURE;\r
72 Entry->ResetNotify = ResetFunction;\r
73 InsertTailList (&Instance->ResetNotifies, &Entry->Link);\r
74 return EFI_SUCCESS;\r
75}\r
76\r
77/**\r
78 Unregister a notification function.\r
79\r
80 The UnregisterResetNotify() function removes the previously registered\r
81 notification using RegisterResetNotify().\r
82\r
83 @param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.\r
84 @param[in] ResetFunction The pointer to the ResetFunction being unregistered.\r
85\r
86 @retval EFI_SUCCESS The reset notification function was unregistered.\r
87 @retval EFI_INVALID_PARAMETER ResetFunction is NULL.\r
88 @retval EFI_INVALID_PARAMETER The reset notification function specified by ResetFunction was not previously\r
89 registered using RegisterResetNotify().\r
90\r
91**/\r
92EFI_STATUS\r
93EFIAPI\r
94UnregisterResetNotify (\r
95 IN EFI_RESET_NOTIFICATION_PROTOCOL *This,\r
96 IN EFI_RESET_SYSTEM ResetFunction\r
97 )\r
98{\r
99 RESET_NOTIFICATION_INSTANCE *Instance;\r
100 LIST_ENTRY *Link;\r
101 RESET_NOTIFY_ENTRY *Entry;\r
102\r
103 if (ResetFunction == NULL) {\r
104 return EFI_INVALID_PARAMETER;\r
105 }\r
106\r
107 Instance = RESET_NOTIFICATION_INSTANCE_FROM_THIS (This);\r
108\r
109 for ( Link = GetFirstNode (&Instance->ResetNotifies)\r
110 ; !IsNull (&Instance->ResetNotifies, Link)\r
111 ; Link = GetNextNode (&Instance->ResetNotifies, Link)\r
112 ) {\r
113 Entry = RESET_NOTIFY_ENTRY_FROM_LINK (Link);\r
114 if (Entry->ResetNotify == ResetFunction) {\r
115 RemoveEntryList (&Entry->Link);\r
116 FreePool (Entry);\r
117 return EFI_SUCCESS;\r
118 }\r
119 }\r
120\r
121 return EFI_INVALID_PARAMETER;\r
122}\r
123\r
124RESET_NOTIFICATION_INSTANCE mResetNotification = {\r
125 RESET_NOTIFICATION_INSTANCE_SIGNATURE,\r
126 {\r
127 RegisterResetNotify,\r
128 UnregisterResetNotify\r
129 },\r
130 INITIALIZE_LIST_HEAD_VARIABLE (mResetNotification.ResetNotifies)\r
131};\r
132\r
51a0c5f2 133/**\r
134 The driver's entry point.\r
135\r
136 It initializes the Reset Architectural Protocol.\r
137\r
138 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
139 @param[in] SystemTable A pointer to the EFI System Table.\r
140 \r
141 @retval EFI_SUCCESS The entry point is executed successfully.\r
142 @retval other Cannot install ResetArch protocol.\r
143\r
144**/\r
145EFI_STATUS\r
146EFIAPI\r
147InitializeResetSystem (\r
148 IN EFI_HANDLE ImageHandle,\r
149 IN EFI_SYSTEM_TABLE *SystemTable\r
150 )\r
151{\r
152 EFI_STATUS Status;\r
34861f43 153 EFI_HANDLE Handle;\r
51a0c5f2 154\r
155 //\r
156 // Make sure the Reset Architectural Protocol is not already installed in the system\r
157 //\r
158 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiResetArchProtocolGuid);\r
159\r
160 //\r
161 // Hook the runtime service table\r
162 //\r
163 gRT->ResetSystem = ResetSystem;\r
164\r
165 //\r
166 // Now install the Reset RT AP on a new handle\r
167 //\r
34861f43 168 Handle = NULL;\r
51a0c5f2 169 Status = gBS->InstallMultipleProtocolInterfaces (\r
34861f43 170 &Handle,\r
cf6da556
RN
171 &gEfiResetArchProtocolGuid, NULL,\r
172 &gEfiResetNotificationProtocolGuid, &mResetNotification.ResetNotification,\r
51a0c5f2 173 NULL\r
174 );\r
175 ASSERT_EFI_ERROR (Status);\r
176\r
177 return Status;\r
178}\r
179\r
51a0c5f2 180/**\r
181 Put the system into S3 power state. \r
182**/\r
183VOID\r
184DoS3 (\r
185 VOID\r
186 )\r
187{\r
188 EnterS3WithImmediateWake ();\r
189\r
190 //\r
191 // Should not return\r
192 //\r
193 CpuDeadLoop ();\r
194}\r
195\r
196/**\r
197 Resets the entire platform.\r
198\r
199 @param[in] ResetType The type of reset to perform.\r
200 @param[in] ResetStatus The status code for the reset.\r
37078045 201 @param[in] DataSize The size, in bytes, of ResetData.\r
51a0c5f2 202 @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or\r
203 EfiResetShutdown the data buffer starts with a Null-terminated\r
204 string, optionally followed by additional binary data.\r
37078045
RN
205 The string is a description that the caller may use to further\r
206 indicate the reason for the system reset. ResetData is only\r
207 valid if ResetStatus is something other than EFI_SUCCESS\r
208 unless the ResetType is EfiResetPlatformSpecific\r
209 where a minimum amount of ResetData is always required.\r
51a0c5f2 210**/\r
211VOID\r
212EFIAPI\r
213ResetSystem (\r
214 IN EFI_RESET_TYPE ResetType,\r
215 IN EFI_STATUS ResetStatus,\r
216 IN UINTN DataSize,\r
217 IN VOID *ResetData OPTIONAL\r
218 )\r
219{\r
cf6da556
RN
220 EFI_STATUS Status;\r
221 UINTN Size;\r
222 UINTN CapsuleDataPtr;\r
223 LIST_ENTRY *Link;\r
224 RESET_NOTIFY_ENTRY *Entry;\r
37623a5c 225 \r
226 //\r
227 // Indicate reset system runtime service is called.\r
228 //\r
229 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_EFI_RUNTIME_SERVICE | EFI_SW_RS_PC_RESET_SYSTEM));\r
51a0c5f2 230\r
cf6da556
RN
231 if (!EfiAtRuntime ()) {\r
232 for ( Link = GetFirstNode (&mResetNotification.ResetNotifies)\r
233 ; !IsNull (&mResetNotification.ResetNotifies, Link)\r
234 ; Link = GetNextNode (&mResetNotification.ResetNotifies, Link)\r
235 ) {\r
236 Entry = RESET_NOTIFY_ENTRY_FROM_LINK (Link);\r
237 Entry->ResetNotify (ResetType, ResetStatus, DataSize, ResetData);\r
238 }\r
239 }\r
240\r
51a0c5f2 241 switch (ResetType) {\r
242 case EfiResetWarm:\r
243\r
244 //\r
245 //Check if there are pending capsules to process\r
246 //\r
247 Size = sizeof (CapsuleDataPtr);\r
248 Status = EfiGetVariable (\r
249 EFI_CAPSULE_VARIABLE_NAME,\r
250 &gEfiCapsuleVendorGuid,\r
251 NULL,\r
252 &Size,\r
253 (VOID *) &CapsuleDataPtr\r
254 );\r
255\r
256 if (Status == EFI_SUCCESS) {\r
257 //\r
258 //Process capsules across a system reset.\r
259 //\r
260 DoS3();\r
261 }\r
262\r
263 ResetWarm ();\r
264\r
265 break;\r
266\r
267 case EfiResetCold:\r
268 ResetCold ();\r
269 break;\r
270\r
271 case EfiResetShutdown:\r
272 ResetShutdown ();\r
273 return ;\r
274\r
37078045
RN
275 case EfiResetPlatformSpecific:\r
276 ResetPlatformSpecific (DataSize, ResetData);\r
277 return;\r
278\r
51a0c5f2 279 default:\r
280 return ;\r
281 }\r
282\r
283 //\r
284 // Given we should have reset getting here would be bad\r
285 //\r
286 ASSERT (FALSE);\r
287}\r