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