MdeModulePkg/ResetUtilityLib: Fix GCC build failure
[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 This program and the accompanying materials are licensed and made available under
8 the terms and conditions of the BSD License that accompanies this distribution.
9 The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php.
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16 #include <Uefi.h>
17 #include <Library/BaseLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/ResetSystemLib.h>
21
22 typedef struct {
23 CHAR16 NullTerminator;
24 GUID ResetSubtype;
25 } RESET_UTILITY_GUID_SPECIFIC_RESET_DATA;
26
27 /**
28 This is a shorthand helper function to reset with a subtype so that
29 the caller doesn't have to bother with a function that has half a dozen
30 parameters.
31
32 This will generate a reset with status EFI_SUCCESS, a NULL string, and
33 no custom data. The subtype will be formatted in such a way that it can be
34 picked up by notification registrations and custom handlers.
35
36 NOTE: This call will fail if the architectural ResetSystem underpinnings
37 are not initialized. For DXE, you can add gEfiResetArchProtocolGuid
38 to your DEPEX.
39
40 @param[in] ResetSubtype GUID pointer for the reset subtype to be used.
41
42 **/
43 VOID
44 EFIAPI
45 ResetPlatformSpecificGuid (
46 IN CONST GUID *ResetSubtype
47 )
48 {
49 RESET_UTILITY_GUID_SPECIFIC_RESET_DATA ResetData;
50
51 ResetData.NullTerminator = CHAR_NULL;
52 CopyGuid (&ResetData.ResetSubtype, ResetSubtype);
53 ResetPlatformSpecific (sizeof (ResetData), &ResetData);
54 }
55
56 /**
57 This function examines the DataSize and ResetData parameters passed to
58 to ResetSystem() and detemrines if the ResetData contains a Null-terminated
59 Unicode string followed by a GUID specific subtype. If the GUID specific
60 subtype is present, then a pointer to the GUID value in ResetData is returned.
61
62 @param[in] DataSize The size, in bytes, of ResetData.
63 @param[in] ResetData Pointer to the data buffer passed into ResetSystem().
64
65 @retval Pointer Pointer to the GUID value in ResetData.
66 @retval NULL ResetData is NULL.
67 @retval NULL ResetData does not start with a Null-terminated
68 Unicode string.
69 @retval NULL A Null-terminated Unicode string is present, but there
70 are less than sizeof (GUID) bytes after the string.
71 @retval NULL No subtype is found.
72
73 **/
74 GUID *
75 EFIAPI
76 GetResetPlatformSpecificGuid (
77 IN UINTN DataSize,
78 IN CONST VOID *ResetData
79 )
80 {
81 UINTN ResetDataStringSize;
82 GUID *ResetSubtypeGuid;
83
84 //
85 // Make sure parameters are valid
86 //
87 if ((ResetData == NULL) || (DataSize < sizeof (GUID))) {
88 return NULL;
89 }
90
91 //
92 // Determine the number of bytes in the Null-terminated Unicode string
93 // at the beginning of ResetData including the Null terminator.
94 //
95 ResetDataStringSize = StrnSizeS (ResetData, (DataSize / sizeof (CHAR16)));
96
97 //
98 // Now, assuming that we have enough data for a GUID after the string, the
99 // GUID should be immediately after the string itself.
100 //
101 if ((ResetDataStringSize < DataSize) && (DataSize - ResetDataStringSize) >= sizeof (GUID)) {
102 ResetSubtypeGuid = (GUID *)((UINT8 *)ResetData + ResetDataStringSize);
103 DEBUG ((DEBUG_VERBOSE, "%a - Detected reset subtype %g...\n", __FUNCTION__, ResetSubtypeGuid));
104 return ResetSubtypeGuid;
105 }
106 return NULL;
107 }
108
109 /**
110 This is a helper function that creates the reset data buffer that can be
111 passed into ResetSystem().
112
113 The reset data buffer is returned in ResetData and contains ResetString
114 followed by the ResetSubtype GUID followed by the ExtraData.
115
116 NOTE: Strings are internally limited by MAX_UINT16.
117
118 @param[in, out] ResetDataSize On input, the size of the ResetData buffer. On
119 output, either the total number of bytes
120 copied, or the required buffer size.
121 @param[in, out] ResetData A pointer to the buffer in which to place the
122 final structure.
123 @param[in] ResetSubtype Pointer to the GUID specific subtype. This
124 parameter is optional and may be NULL.
125 @param[in] ResetString Pointer to a Null-terminated Unicode string
126 that describes the reset. This parameter is
127 optional and may be NULL.
128 @param[in] ExtraDataSize The size, in bytes, of ExtraData buffer.
129 @param[in] ExtraData Pointer to a buffer of extra data. This
130 parameter is optional and may be NULL.
131
132 @retval RETURN_SUCCESS ResetDataSize and ResetData are updated.
133 @retval RETURN_INVALID_PARAMETER ResetDataSize is NULL.
134 @retval RETURN_INVALID_PARAMETER ResetData is NULL.
135 @retval RETURN_INVALID_PARAMETER ExtraData was provided without a
136 ResetSubtype. This is not supported by the
137 UEFI spec.
138 @retval RETURN_BUFFER_TOO_SMALL An insufficient buffer was provided.
139 ResetDataSize is updated with minimum size
140 required.
141 **/
142 RETURN_STATUS
143 EFIAPI
144 BuildResetData (
145 IN OUT UINTN *ResetDataSize,
146 IN OUT VOID *ResetData,
147 IN CONST GUID *ResetSubtype OPTIONAL,
148 IN CONST CHAR16 *ResetString OPTIONAL,
149 IN UINTN ExtraDataSize OPTIONAL,
150 IN CONST VOID *ExtraData OPTIONAL
151 )
152 {
153 UINTN ResetStringSize;
154 UINTN ResetDataBufferSize;
155 UINT8 *Data;
156
157 //
158 // If the size return pointer is NULL.
159 //
160 if (ResetDataSize == NULL) {
161 return RETURN_INVALID_PARAMETER;
162 }
163 //
164 // If extra data is indicated, but pointer is NULL.
165 //
166 if (ExtraDataSize > 0 && ExtraData == NULL) {
167 return RETURN_INVALID_PARAMETER;
168 }
169 //
170 // If extra data is indicated, but no subtype GUID is supplied.
171 //
172 if (ResetSubtype == NULL && ExtraDataSize > 0) {
173 return RETURN_INVALID_PARAMETER;
174 }
175
176 //
177 // Determine the final string.
178 //
179 if (ResetString == NULL) {
180 ResetString = L""; // Use an empty string.
181 }
182
183 //
184 // Calculate the total buffer required for ResetData.
185 //
186 ResetStringSize = StrnSizeS (ResetString, MAX_UINT16);
187 ResetDataBufferSize = ResetStringSize + ExtraDataSize;
188 if (ResetSubtype != NULL) {
189 ResetDataBufferSize += sizeof (GUID);
190 }
191
192 //
193 // At this point, if the buffer isn't large enough (or if
194 // the buffer is NULL) we cannot proceed.
195 //
196 if (*ResetDataSize < ResetDataBufferSize) {
197 *ResetDataSize = ResetDataBufferSize;
198 return RETURN_BUFFER_TOO_SMALL;
199 }
200 *ResetDataSize = ResetDataBufferSize;
201 if (ResetData == NULL) {
202 return RETURN_INVALID_PARAMETER;
203 }
204
205 //
206 // Fill in ResetData with ResetString, the ResetSubtype GUID, and extra data
207 //
208 Data = (UINT8 *)ResetData;
209 CopyMem (Data, ResetString, ResetStringSize);
210 Data += ResetStringSize;
211 if (ResetSubtype != NULL) {
212 CopyMem (Data, ResetSubtype, sizeof (GUID));
213 Data += sizeof (GUID);
214 }
215 if (ExtraDataSize > 0) {
216 CopyMem (Data, ExtraData, ExtraDataSize);
217 }
218
219 return RETURN_SUCCESS;
220 }