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