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