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