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