]> code.delx.au - refind/blob - EfiLib/gnuefi-helper.c
Work around problem with (bogus, I think) "invalid parameter" errors
[refind] / EfiLib / gnuefi-helper.c
1 /*
2 * EfiLib/gnuefi.h
3 * GNU-EFI support in legacy boot code
4 *
5 * Copyright (c) 2014 Roderick W. Smith
6 * With extensive borrowing from other sources (mostly Tianocore)
7 *
8 * This software is licensed under the terms of the GNU GPLv3,
9 * a copy of which should come with this file.
10 *
11 */
12
13 #include "gnuefi-helper.h"
14 #include "DevicePathUtilities.h"
15 #include "refit_call_wrapper.h"
16 #include "LegacyBios.h"
17
18 EFI_GUID gEfiDevicePathUtilitiesProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
19 EFI_GUID gEfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }};
20 EFI_GUID gEfiLegacyBiosProtocolGuid = { 0xdb9a1e3d, 0x45cb, 0x4abb, { 0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d }};
21
22 /**
23 Convert a Null-terminated Unicode string to a Null-terminated
24 ASCII string and returns the ASCII string.
25
26 This function converts the content of the Unicode string Source
27 to the ASCII string Destination by copying the lower 8 bits of
28 each Unicode character. It returns Destination. The function terminates
29 the ASCII string Destination by appending a Null-terminator character
30 at the end. The caller is responsible to make sure Destination points
31 to a buffer with size equal or greater than (StrLen (Source) + 1) in bytes.
32
33 If Destination is NULL, then ASSERT().
34 If Source is NULL, then ASSERT().
35 If Source is not aligned on a 16-bit boundary, then ASSERT().
36 If Source and Destination overlap, then ASSERT().
37
38 If any Unicode characters in Source contain non-zero value in
39 the upper 8 bits, then ASSERT().
40
41 If PcdMaximumUnicodeStringLength is not zero, and Source contains
42 more than PcdMaximumUnicodeStringLength Unicode characters not including
43 the Null-terminator, then ASSERT().
44
45 If PcdMaximumAsciiStringLength is not zero, and Source contains more
46 than PcdMaximumAsciiStringLength Unicode characters not including the
47 Null-terminator, then ASSERT().
48
49 @param Source Pointer to a Null-terminated Unicode string.
50 @param Destination Pointer to a Null-terminated ASCII string.
51
52 @reture Destination
53
54 **/
55 CHAR8 *
56 UnicodeStrToAsciiStr (
57 IN CHAR16 *Source,
58 OUT CHAR8 *Destination
59 )
60 {
61 ASSERT (Destination != NULL);
62 ASSERT (Source != NULL);
63 ASSERT (((UINTN) Source & 0x01) == 0);
64
65 //
66 // Source and Destination should not overlap
67 //
68 ASSERT ((UINTN) ((CHAR16 *) Destination - Source) > StrLen (Source));
69 ASSERT ((UINTN) ((CHAR8 *) Source - Destination) > StrLen (Source));
70
71 // //
72 // // If PcdMaximumUnicodeStringLength is not zero,
73 // // length of Source should not more than PcdMaximumUnicodeStringLength
74 // //
75 // if (PcdGet32 (PcdMaximumUnicodeStringLength) != 0) {
76 // ASSERT (StrLen (Source) < PcdGet32 (PcdMaximumUnicodeStringLength));
77 // }
78
79 while (*Source != '\0') {
80 //
81 // If any Unicode characters in Source contain
82 // non-zero value in the upper 8 bits, then ASSERT().
83 //
84 ASSERT (*Source < 0x100);
85 *(Destination++) = (CHAR8) *(Source++);
86 }
87
88 *Destination = '\0';
89
90 return Destination;
91 }
92
93 /**
94 Returns the length of a Null-terminated ASCII string.
95
96 This function returns the number of ASCII characters in the Null-terminated
97 ASCII string specified by String.
98
99 If String is NULL, then ASSERT().
100 If PcdMaximumAsciiStringLength is not zero and String contains more than
101 PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator,
102 then ASSERT().
103
104 @param String Pointer to a Null-terminated ASCII string.
105
106 @return The length of String.
107
108 **/
109 UINTN
110 AsciiStrLen (
111 IN CONST CHAR8 *String
112 )
113 {
114 UINTN Length;
115
116 ASSERT (String != NULL);
117
118 for (Length = 0; *String != '\0'; String++, Length++) {
119 // //
120 // // If PcdMaximumUnicodeStringLength is not zero,
121 // // length should not more than PcdMaximumUnicodeStringLength
122 // //
123 // if (PcdGet32 (PcdMaximumAsciiStringLength) != 0) {
124 // ASSERT (Length < PcdGet32 (PcdMaximumAsciiStringLength));
125 // }
126 }
127 return Length;
128 }
129
130 /**
131 Determine whether a given device path is valid.
132 If DevicePath is NULL, then ASSERT().
133
134 @param DevicePath A pointer to a device path data structure.
135 @param MaxSize The maximum size of the device path data structure.
136
137 @retval TRUE DevicePath is valid.
138 @retval FALSE The length of any node node in the DevicePath is less
139 than sizeof (EFI_DEVICE_PATH_PROTOCOL).
140 @retval FALSE If MaxSize is not zero, the size of the DevicePath
141 exceeds MaxSize.
142 @retval FALSE If PcdMaximumDevicePathNodeCount is not zero, the node
143 count of the DevicePath exceeds PcdMaximumDevicePathNodeCount.
144 **/
145 BOOLEAN
146 EFIAPI
147 IsDevicePathValid (
148 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
149 IN UINTN MaxSize
150 )
151 {
152 UINTN Count;
153 UINTN Size;
154 UINTN NodeLength;
155
156 ASSERT (DevicePath != NULL);
157
158 for (Count = 0, Size = 0; !IsDevicePathEnd (DevicePath); DevicePath = NextDevicePathNode (DevicePath)) {
159 NodeLength = DevicePathNodeLength (DevicePath);
160 if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
161 return FALSE;
162 }
163
164 if (MaxSize > 0) {
165 Size += NodeLength;
166 if (Size + END_DEVICE_PATH_LENGTH > MaxSize) {
167 return FALSE;
168 }
169 }
170
171 // if (PcdGet32 (PcdMaximumDevicePathNodeCount) > 0) {
172 // Count++;
173 // if (Count >= PcdGet32 (PcdMaximumDevicePathNodeCount)) {
174 // return FALSE;
175 // }
176 // }
177 }
178
179 //
180 // Only return TRUE when the End Device Path node is valid.
181 //
182 return (BOOLEAN) (DevicePathNodeLength (DevicePath) == END_DEVICE_PATH_LENGTH);
183 }
184
185 /**
186 Returns the size of a device path in bytes.
187
188 This function returns the size, in bytes, of the device path data structure
189 specified by DevicePath including the end of device path node.
190 If DevicePath is NULL or invalid, then 0 is returned.
191
192 @param DevicePath A pointer to a device path data structure.
193
194 @retval 0 If DevicePath is NULL or invalid.
195 @retval Others The size of a device path in bytes.
196
197 **/
198 UINTN
199 EFIAPI
200 GetDevicePathSize (
201 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
202 )
203 {
204 CONST EFI_DEVICE_PATH_PROTOCOL *Start;
205
206 if (DevicePath == NULL) {
207 return 0;
208 }
209
210 if (!IsDevicePathValid (DevicePath, 0)) {
211 return 0;
212 }
213
214 //
215 // Search for the end of the device path structure
216 //
217 Start = DevicePath;
218 while (!IsDevicePathEnd (DevicePath)) {
219 DevicePath = NextDevicePathNode (DevicePath);
220 }
221
222 //
223 // Compute the size and add back in the size of the end device path structure
224 //
225 return ((UINTN) DevicePath - (UINTN) Start) + DevicePathNodeLength (DevicePath);
226 }
227
228 /**
229 Creates a copy of the current device path instance and returns a pointer to the next device path
230 instance.
231
232 This function creates a copy of the current device path instance. It also updates
233 DevicePath to point to the next device path instance in the device path (or NULL
234 if no more) and updates Size to hold the size of the device path instance copy.
235 If DevicePath is NULL, then NULL is returned.
236 If DevicePath points to a invalid device path, then NULL is returned.
237 If there is not enough memory to allocate space for the new device path, then
238 NULL is returned.
239 The memory is allocated from EFI boot services memory. It is the responsibility
240 of the caller to free the memory allocated.
241 If Size is NULL, then ASSERT().
242
243 @param DevicePath On input, this holds the pointer to the current
244 device path instance. On output, this holds
245 the pointer to the next device path instance
246 or NULL if there are no more device path
247 instances in the device path pointer to a
248 device path data structure.
249 @param Size On output, this holds the size of the device
250 path instance, in bytes or zero, if DevicePath
251 is NULL.
252
253 @return A pointer to the current device path instance.
254
255 **/
256 EFI_DEVICE_PATH_PROTOCOL *
257 EFIAPI
258 GetNextDevicePathInstance (
259 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
260 OUT UINTN *Size
261 )
262 {
263 EFI_DEVICE_PATH_PROTOCOL *DevPath;
264 EFI_DEVICE_PATH_PROTOCOL *ReturnValue;
265 UINT8 Temp;
266
267 ASSERT (Size != NULL);
268
269 if (DevicePath == NULL || *DevicePath == NULL) {
270 *Size = 0;
271 return NULL;
272 }
273
274 if (!IsDevicePathValid (*DevicePath, 0)) {
275 return NULL;
276 }
277
278 //
279 // Find the end of the device path instance
280 //
281 DevPath = *DevicePath;
282 while (!IsDevicePathEndType (DevPath)) {
283 DevPath = NextDevicePathNode (DevPath);
284 }
285
286 //
287 // Compute the size of the device path instance
288 //
289 *Size = ((UINTN) DevPath - (UINTN) (*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
290
291 //
292 // Make a copy and return the device path instance
293 //
294 Temp = DevPath->SubType;
295 DevPath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
296 ReturnValue = DuplicateDevicePath (*DevicePath);
297 DevPath->SubType = Temp;
298
299 //
300 // If DevPath is the end of an entire device path, then another instance
301 // does not follow, so *DevicePath is set to NULL.
302 //
303 if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
304 *DevicePath = NULL;
305 } else {
306 *DevicePath = NextDevicePathNode (DevPath);
307 }
308
309 return ReturnValue;
310 }