]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/ResetUtilityLib/ResetUtility.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Library / ResetUtilityLib / ResetUtility.c
CommitLineData
e12ceb40
MK
1/** @file\r
2 This contains the business logic for the module-specific Reset Helper functions.\r
3\r
0851d7a5 4 Copyright (c) 2017 - 2019 Intel Corporation. All rights reserved.<BR>\r
e12ceb40
MK
5 Copyright (c) 2016 Microsoft Corporation. All rights reserved.<BR>\r
6\r
9d510e61 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
e12ceb40
MK
8\r
9**/\r
10#include <Uefi.h>\r
11#include <Library/BaseLib.h>\r
12#include <Library/DebugLib.h>\r
13#include <Library/BaseMemoryLib.h>\r
14#include <Library/ResetSystemLib.h>\r
15\r
93f5a54f 16#pragma pack(1)\r
e12ceb40 17typedef struct {\r
1436aea4
MK
18 CHAR16 NullTerminator;\r
19 GUID ResetSubtype;\r
e12ceb40 20} RESET_UTILITY_GUID_SPECIFIC_RESET_DATA;\r
93f5a54f
RN
21#pragma pack()\r
22\r
a9521a6b
VC
23STATIC_ASSERT (\r
24 sizeof (RESET_UTILITY_GUID_SPECIFIC_RESET_DATA) == 18,\r
25 "sizeof (RESET_UTILITY_GUID_SPECIFIC_RESET_DATA) is expected to be 18 bytes"\r
26 );\r
e12ceb40
MK
27\r
28/**\r
0851d7a5
BB
29 This is a shorthand helper function to reset with reset type and a subtype\r
30 so that the caller doesn't have to bother with a function that has half\r
31 a dozen parameters.\r
e12ceb40
MK
32\r
33 This will generate a reset with status EFI_SUCCESS, a NULL string, and\r
34 no custom data. The subtype will be formatted in such a way that it can be\r
35 picked up by notification registrations and custom handlers.\r
36\r
37 NOTE: This call will fail if the architectural ResetSystem underpinnings\r
38 are not initialized. For DXE, you can add gEfiResetArchProtocolGuid\r
39 to your DEPEX.\r
40\r
0851d7a5 41 @param[in] ResetType The default EFI_RESET_TYPE of the reset.\r
e12ceb40
MK
42 @param[in] ResetSubtype GUID pointer for the reset subtype to be used.\r
43\r
44**/\r
45VOID\r
46EFIAPI\r
0851d7a5 47ResetSystemWithSubtype (\r
1436aea4
MK
48 IN EFI_RESET_TYPE ResetType,\r
49 IN CONST GUID *ResetSubtype\r
e12ceb40
MK
50 )\r
51{\r
52 RESET_UTILITY_GUID_SPECIFIC_RESET_DATA ResetData;\r
53\r
54 ResetData.NullTerminator = CHAR_NULL;\r
93f5a54f
RN
55 CopyGuid (\r
56 (GUID *)((UINT8 *)&ResetData + OFFSET_OF (RESET_UTILITY_GUID_SPECIFIC_RESET_DATA, ResetSubtype)),\r
57 ResetSubtype\r
58 );\r
0851d7a5
BB
59\r
60 ResetSystem (ResetType, EFI_SUCCESS, sizeof (ResetData), &ResetData);\r
61}\r
62\r
63/**\r
64 This is a shorthand helper function to reset with the reset type\r
65 'EfiResetPlatformSpecific' and a subtype so that the caller doesn't\r
66 have to bother with a function that has half a dozen parameters.\r
67\r
68 This will generate a reset with status EFI_SUCCESS, a NULL string, and\r
69 no custom data. The subtype will be formatted in such a way that it can be\r
70 picked up by notification registrations and custom handlers.\r
71\r
72 NOTE: This call will fail if the architectural ResetSystem underpinnings\r
73 are not initialized. For DXE, you can add gEfiResetArchProtocolGuid\r
74 to your DEPEX.\r
75\r
76 @param[in] ResetSubtype GUID pointer for the reset subtype to be used.\r
77\r
78**/\r
79VOID\r
80EFIAPI\r
81ResetPlatformSpecificGuid (\r
1436aea4 82 IN CONST GUID *ResetSubtype\r
0851d7a5
BB
83 )\r
84{\r
85 ResetSystemWithSubtype (EfiResetPlatformSpecific, ResetSubtype);\r
e12ceb40
MK
86}\r
87\r
88/**\r
89 This function examines the DataSize and ResetData parameters passed to\r
90 to ResetSystem() and detemrines if the ResetData contains a Null-terminated\r
d1102dba 91 Unicode string followed by a GUID specific subtype. If the GUID specific\r
e12ceb40
MK
92 subtype is present, then a pointer to the GUID value in ResetData is returned.\r
93\r
94 @param[in] DataSize The size, in bytes, of ResetData.\r
95 @param[in] ResetData Pointer to the data buffer passed into ResetSystem().\r
96\r
97 @retval Pointer Pointer to the GUID value in ResetData.\r
98 @retval NULL ResetData is NULL.\r
99 @retval NULL ResetData does not start with a Null-terminated\r
100 Unicode string.\r
101 @retval NULL A Null-terminated Unicode string is present, but there\r
102 are less than sizeof (GUID) bytes after the string.\r
103 @retval NULL No subtype is found.\r
104\r
105**/\r
106GUID *\r
107EFIAPI\r
108GetResetPlatformSpecificGuid (\r
109 IN UINTN DataSize,\r
110 IN CONST VOID *ResetData\r
111 )\r
112{\r
1436aea4
MK
113 UINTN ResetDataStringSize;\r
114 GUID *ResetSubtypeGuid;\r
e12ceb40
MK
115\r
116 //\r
117 // Make sure parameters are valid\r
118 //\r
119 if ((ResetData == NULL) || (DataSize < sizeof (GUID))) {\r
120 return NULL;\r
121 }\r
122\r
123 //\r
124 // Determine the number of bytes in the Null-terminated Unicode string\r
125 // at the beginning of ResetData including the Null terminator.\r
126 //\r
127 ResetDataStringSize = StrnSizeS (ResetData, (DataSize / sizeof (CHAR16)));\r
128\r
129 //\r
130 // Now, assuming that we have enough data for a GUID after the string, the\r
131 // GUID should be immediately after the string itself.\r
132 //\r
1436aea4 133 if ((ResetDataStringSize < DataSize) && ((DataSize - ResetDataStringSize) >= sizeof (GUID))) {\r
e12ceb40 134 ResetSubtypeGuid = (GUID *)((UINT8 *)ResetData + ResetDataStringSize);\r
5eecb45a 135 DEBUG ((DEBUG_VERBOSE, "%a - Detected reset subtype %g...\n", __FUNCTION__, ResetSubtypeGuid));\r
e12ceb40
MK
136 return ResetSubtypeGuid;\r
137 }\r
1436aea4 138\r
e12ceb40
MK
139 return NULL;\r
140}\r
141\r
142/**\r
d1102dba 143 This is a helper function that creates the reset data buffer that can be\r
e12ceb40
MK
144 passed into ResetSystem().\r
145\r
146 The reset data buffer is returned in ResetData and contains ResetString\r
147 followed by the ResetSubtype GUID followed by the ExtraData.\r
148\r
149 NOTE: Strings are internally limited by MAX_UINT16.\r
150\r
151 @param[in, out] ResetDataSize On input, the size of the ResetData buffer. On\r
152 output, either the total number of bytes\r
153 copied, or the required buffer size.\r
154 @param[in, out] ResetData A pointer to the buffer in which to place the\r
155 final structure.\r
156 @param[in] ResetSubtype Pointer to the GUID specific subtype. This\r
157 parameter is optional and may be NULL.\r
158 @param[in] ResetString Pointer to a Null-terminated Unicode string\r
159 that describes the reset. This parameter is\r
160 optional and may be NULL.\r
161 @param[in] ExtraDataSize The size, in bytes, of ExtraData buffer.\r
162 @param[in] ExtraData Pointer to a buffer of extra data. This\r
163 parameter is optional and may be NULL.\r
164\r
165 @retval RETURN_SUCCESS ResetDataSize and ResetData are updated.\r
166 @retval RETURN_INVALID_PARAMETER ResetDataSize is NULL.\r
167 @retval RETURN_INVALID_PARAMETER ResetData is NULL.\r
168 @retval RETURN_INVALID_PARAMETER ExtraData was provided without a\r
169 ResetSubtype. This is not supported by the\r
170 UEFI spec.\r
171 @retval RETURN_BUFFER_TOO_SMALL An insufficient buffer was provided.\r
172 ResetDataSize is updated with minimum size\r
173 required.\r
174**/\r
175RETURN_STATUS\r
176EFIAPI\r
177BuildResetData (\r
1436aea4
MK
178 IN OUT UINTN *ResetDataSize,\r
179 IN OUT VOID *ResetData,\r
180 IN CONST GUID *ResetSubtype OPTIONAL,\r
181 IN CONST CHAR16 *ResetString OPTIONAL,\r
182 IN UINTN ExtraDataSize OPTIONAL,\r
183 IN CONST VOID *ExtraData OPTIONAL\r
e12ceb40
MK
184 )\r
185{\r
186 UINTN ResetStringSize;\r
187 UINTN ResetDataBufferSize;\r
188 UINT8 *Data;\r
189\r
190 //\r
191 // If the size return pointer is NULL.\r
192 //\r
193 if (ResetDataSize == NULL) {\r
194 return RETURN_INVALID_PARAMETER;\r
195 }\r
1436aea4 196\r
e12ceb40
MK
197 //\r
198 // If extra data is indicated, but pointer is NULL.\r
199 //\r
1436aea4 200 if ((ExtraDataSize > 0) && (ExtraData == NULL)) {\r
e12ceb40
MK
201 return RETURN_INVALID_PARAMETER;\r
202 }\r
1436aea4 203\r
e12ceb40
MK
204 //\r
205 // If extra data is indicated, but no subtype GUID is supplied.\r
206 //\r
1436aea4 207 if ((ResetSubtype == NULL) && (ExtraDataSize > 0)) {\r
e12ceb40
MK
208 return RETURN_INVALID_PARAMETER;\r
209 }\r
210\r
211 //\r
212 // Determine the final string.\r
213 //\r
214 if (ResetString == NULL) {\r
215 ResetString = L""; // Use an empty string.\r
216 }\r
d1102dba 217\r
e12ceb40
MK
218 //\r
219 // Calculate the total buffer required for ResetData.\r
220 //\r
221 ResetStringSize = StrnSizeS (ResetString, MAX_UINT16);\r
222 ResetDataBufferSize = ResetStringSize + ExtraDataSize;\r
223 if (ResetSubtype != NULL) {\r
224 ResetDataBufferSize += sizeof (GUID);\r
225 }\r
226\r
227 //\r
228 // At this point, if the buffer isn't large enough (or if\r
229 // the buffer is NULL) we cannot proceed.\r
230 //\r
231 if (*ResetDataSize < ResetDataBufferSize) {\r
232 *ResetDataSize = ResetDataBufferSize;\r
233 return RETURN_BUFFER_TOO_SMALL;\r
234 }\r
1436aea4 235\r
e12ceb40
MK
236 *ResetDataSize = ResetDataBufferSize;\r
237 if (ResetData == NULL) {\r
238 return RETURN_INVALID_PARAMETER;\r
239 }\r
240\r
241 //\r
242 // Fill in ResetData with ResetString, the ResetSubtype GUID, and extra data\r
243 //\r
244 Data = (UINT8 *)ResetData;\r
245 CopyMem (Data, ResetString, ResetStringSize);\r
246 Data += ResetStringSize;\r
247 if (ResetSubtype != NULL) {\r
248 CopyMem (Data, ResetSubtype, sizeof (GUID));\r
249 Data += sizeof (GUID);\r
250 }\r
1436aea4 251\r
e12ceb40
MK
252 if (ExtraDataSize > 0) {\r
253 CopyMem (Data, ExtraData, ExtraDataSize);\r
254 }\r
d1102dba 255\r
e12ceb40
MK
256 return RETURN_SUCCESS;\r
257}\r