]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.c
8dc84f48b7e3bfe95815eb40255015035a416e96
[mirror_edk2.git] / MdePkg / Library / UefiDevicePathLib / UefiDevicePathLib.c
1 /** @file
2 Device Path services. The thing to remember is device paths are built out of
3 nodes. The device path is terminated by an end node that is length
4 sizeof(EFI_DEVICE_PATH_PROTOCOL). That would be why there is sizeof(EFI_DEVICE_PATH_PROTOCOL)
5 all over this file.
6
7 The only place where multi-instance device paths are supported is in
8 environment varibles. Multi-instance device paths should never be placed
9 on a Handle.
10
11 Copyright (c) 2006, Intel Corporation
12 All rights reserved. This program and the accompanying materials
13 are licensed and made available under the terms and conditions of the BSD License
14 which accompanies this distribution. The full text of the license may be found at
15 http://opensource.org/licenses/bsd-license.php
16
17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19
20 Module Name: UefiDevicePathLib.c
21
22 **/
23
24 /**
25 This function returns the size, in bytes,
26 of the device path data structure specified by DevicePath.
27 If DevicePath is NULL, then 0 is returned.
28
29 @param DevicePath A pointer to a device path data structure.
30
31 @return The size of a device path in bytes.
32
33 **/
34 UINTN
35 EFIAPI
36 GetDevicePathSize (
37 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
38 )
39 {
40 CONST EFI_DEVICE_PATH_PROTOCOL *Start;
41
42 if (DevicePath == NULL) {
43 return 0;
44 }
45
46 //
47 // Search for the end of the device path structure
48 //
49 Start = DevicePath;
50 while (!EfiIsDevicePathEnd (DevicePath)) {
51 DevicePath = EfiNextDevicePathNode (DevicePath);
52 }
53
54 //
55 // Compute the size and add back in the size of the end device path structure
56 //
57 return ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
58 }
59
60 /**
61 This function allocates space for a new copy of the device path
62 specified by DevicePath.
63
64 @param DevicePath A pointer to a device path data structure.
65
66 @return The duplicated device path.
67
68 **/
69 EFI_DEVICE_PATH_PROTOCOL *
70 EFIAPI
71 DuplicateDevicePath (
72 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
73 )
74 {
75 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
76 UINTN Size;
77
78 //
79 // Compute the size
80 //
81 Size = GetDevicePathSize (DevicePath);
82 if (Size == 0) {
83 return NULL;
84 }
85
86 //
87 // Allocate space for duplicate device path
88 //
89 NewDevicePath = AllocateCopyPool (Size, DevicePath);
90
91 return NewDevicePath;
92 }
93
94 /**
95 This function appends the device path SecondDevicePath
96 to every device path instance in FirstDevicePath.
97
98 @param FirstDevicePath A pointer to a device path data structure.
99
100 @param SecondDevicePath A pointer to a device path data structure.
101
102 @return A pointer to the new device path is returned.
103 NULL is returned if space for the new device path could not be allocated from pool.
104 It is up to the caller to free the memory used by FirstDevicePath and SecondDevicePath
105 if they are no longer needed.
106
107 **/
108 EFI_DEVICE_PATH_PROTOCOL *
109 EFIAPI
110 AppendDevicePath (
111 IN CONST EFI_DEVICE_PATH_PROTOCOL *FirstDevicePath,
112 IN CONST EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath
113 )
114 {
115 UINTN Size;
116 UINTN Size1;
117 UINTN Size2;
118 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
119 EFI_DEVICE_PATH_PROTOCOL *DevicePath2;
120
121 //
122 // If there's only 1 path, just duplicate it
123 //
124 if (FirstDevicePath == NULL) {
125 return DuplicateDevicePath (SecondDevicePath);
126 }
127
128 if (SecondDevicePath == NULL) {
129 return DuplicateDevicePath (FirstDevicePath);
130 }
131
132 //
133 // Allocate space for the combined device path. It only has one end node of
134 // length EFI_DEVICE_PATH_PROTOCOL
135 //
136 Size1 = GetDevicePathSize (FirstDevicePath);
137 Size2 = GetDevicePathSize (SecondDevicePath);
138 Size = Size1 + Size2 - sizeof (EFI_DEVICE_PATH_PROTOCOL);
139
140 NewDevicePath = AllocatePool (Size);
141
142 if (NewDevicePath != NULL) {
143 NewDevicePath = CopyMem (NewDevicePath, FirstDevicePath, Size1);
144 //
145 // Over write Src1 EndNode and do the copy
146 //
147 DevicePath2 = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath + (Size1 - sizeof (EFI_DEVICE_PATH_PROTOCOL)));
148 CopyMem (DevicePath2, SecondDevicePath, Size2);
149 }
150
151 return NewDevicePath;
152 }
153
154 /**
155 This function appends the device path node SecondDevicePath
156 to every device path instance in FirstDevicePath.
157
158 @param FirstDevicePath A pointer to a device path data structure.
159
160 @param SecondDevicePath A pointer to a single device path node.
161
162 @return A pointer to the new device path.
163 If there is not enough temporary pool memory available to complete this function,
164 then NULL is returned.
165
166 **/
167 EFI_DEVICE_PATH_PROTOCOL *
168 EFIAPI
169 AppendDevicePathNode (
170 IN CONST EFI_DEVICE_PATH_PROTOCOL *FirstDevicePath,
171 IN CONST EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath
172 )
173 {
174 EFI_DEVICE_PATH_PROTOCOL *NextNode;
175 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
176 UINTN NodeLength;
177 UINTN Size1;
178
179 //
180 // Build a Node that has a terminator on it
181 //
182 NodeLength = DevicePathNodeLength (SecondDevicePath);
183 Size1 = GetDevicePathSize (FirstDevicePath);
184
185 NewDevicePath = AllocatePool (NodeLength + Size1);
186 if (NewDevicePath != NULL) {
187 //
188 // Copy the first device path to the new device path
189 //
190 NewDevicePath = CopyMem (NewDevicePath, FirstDevicePath, Size1);
191
192 //
193 // Copy the device path node to the new device path
194 //
195 NextNode = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath + (Size1 - sizeof (EFI_DEVICE_PATH_PROTOCOL)));
196 NextNode = CopyMem (NextNode, SecondDevicePath, NodeLength);
197
198 //
199 // Terminate the whole device path
200 //
201 NextNode = NextDevicePathNode (NextNode);
202 SetDevicePathEndNode (NextNode);
203 }
204 return NewDevicePath;
205 }
206
207 /**
208 This function appends the device path instance Instance to the device path Source.
209 If Source is NULL, then a new device path with one instance is created.
210
211 @param Source A pointer to a device path data structure.
212 @param Instance A pointer to a device path instance.
213
214 @return A pointer to the new device path.
215 If there is not enough temporary pool memory available to complete this function,
216 then NULL is returned.
217
218 **/
219 EFI_DEVICE_PATH_PROTOCOL *
220 EFIAPI
221 AppendDevicePathInstance (
222 IN CONST EFI_DEVICE_PATH_PROTOCOL *Source,
223 IN CONST EFI_DEVICE_PATH_PROTOCOL *Instance
224 )
225 {
226 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
227 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
228 UINTN SrcSize;
229 UINTN InstanceSize;
230
231 if (Source == NULL) {
232 return DuplicateDevicePath (Instance);
233 }
234
235 SrcSize = GetDevicePathSize (Source);
236 InstanceSize = GetDevicePathSize (Instance);
237
238 NewDevicePath = AllocatePool (SrcSize + InstanceSize);
239 if (NewDevicePath != NULL) {
240
241 DevicePath = CopyMem (NewDevicePath, Source, SrcSize);;
242
243 while (!IsDevicePathEnd (DevicePath)) {
244 DevicePath = NextDevicePathNode (DevicePath);
245 }
246
247 DevicePath->SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE;
248
249 DevicePath = NextDevicePathNode (DevicePath);
250 CopyMem (DevicePath, Instance, InstanceSize);
251 }
252
253 return NewDevicePath;
254 }
255
256 /**
257 Function retrieves the next device path instance from a device path data structure.
258
259 @param DevicePath A pointer to a device path data structure.
260
261 @param Size A pointer to the size of a device path instance in bytes.
262
263 @return This function returns a pointer to the current device path instance.
264 In addition, it returns the size in bytes of the current device path instance in Size,
265 and a pointer to the next device path instance in DevicePath.
266 If there are no more device path instances in DevicePath, then DevicePath will be set to NULL.
267
268 **/
269 EFI_DEVICE_PATH_PROTOCOL *
270 EFIAPI
271 GetNextDevicePathInstance (
272 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
273 OUT UINTN *Size
274 )
275 {
276 EFI_DEVICE_PATH_PROTOCOL *DevPath;
277 EFI_DEVICE_PATH_PROTOCOL *ReturnValue;
278 UINT8 Temp;
279
280 ASSERT (DevicePath != NULL);
281 ASSERT (Size != NULL);
282 if (*DevicePath == NULL) {
283 *Size = 0;
284 return NULL;
285 }
286
287 //
288 // Find the end of the device path instance
289 //
290 DevPath = *DevicePath;
291 while (!IsDevicePathEndType (DevPath)) {
292 DevPath = NextDevicePathNode (DevPath);
293 }
294
295 //
296 // Compute the size of the device path instance
297 //
298 *Size = ((UINTN) DevPath - (UINTN) (*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
299
300 //
301 // Make a copy and return the device path instance
302 //
303 Temp = DevPath->SubType;
304 DevPath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
305 ReturnValue = DuplicateDevicePath (*DevicePath);
306 DevPath->SubType = Temp;
307
308 //
309 // If DevPath is the end of an entire device path, then another instance
310 // does not follow, so *DevicePath is set to NULL.
311 //
312 if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
313 *DevicePath = NULL;
314 } else {
315 *DevicePath = NextDevicePathNode (DevPath);
316 }
317
318 return ReturnValue;
319 }
320
321 /**
322 Return TRUE is this is a multi instance device path.
323
324 @param DevicePath A pointer to a device path data structure.
325
326 @retval TRUE If DevicePath is multi-instance.
327 @retval FALSE If DevicePath is not multi-instance or DevicePath is NULL.
328
329 **/
330 BOOLEAN
331 EFIAPI
332 IsDevicePathMultiInstance (
333 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
334 )
335 {
336 CONST EFI_DEVICE_PATH_PROTOCOL *Node;
337
338 if (DevicePath == NULL) {
339 return FALSE;
340 }
341
342 Node = DevicePath;
343 while (!EfiIsDevicePathEnd (Node)) {
344 if (EfiIsDevicePathEndInstance (Node)) {
345 return TRUE;
346 }
347
348 Node = EfiNextDevicePathNode (Node);
349 }
350
351 return FALSE;
352 }
353
354 /**
355 This function retrieves the device path protocol from a handle.
356
357 @param Handle The handle from which to retrieve the device path protocol.
358
359 @return This function returns the device path protocol from the handle specified by Handle.
360 If Handle is NULL or Handle does not contain a device path protocol, then NULL is returned.
361
362 **/
363 EFI_DEVICE_PATH_PROTOCOL *
364 EFIAPI
365 DevicePathFromHandle (
366 IN EFI_HANDLE Handle
367 )
368 {
369 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
370 EFI_STATUS Status;
371
372 Status = gBS->HandleProtocol (
373 Handle,
374 &gEfiDevicePathProtocolGuid,
375 (VOID *) &DevicePath
376 );
377 if (EFI_ERROR (Status)) {
378 DevicePath = NULL;
379 }
380 return DevicePath;
381 }
382
383 /**
384 This function allocates a device path for a file and appends it to an existing device path.
385
386 @param Device A pointer to a device handle. This parameter is optional and may be NULL.
387 @param FileName A pointer to a Null-terminated Unicode string.
388
389 @return If Device is a valid device handle that contains a device path protocol,
390 then a device path for the file specified by FileName is allocated
391 and appended to the device path associated with the handle Device. The allocated device path is returned.
392 If Device is NULL or Device is a handle that does not support the device path protocol,
393 then a device path containing a single device path node for the file specified by FileName
394 is allocated and returned.
395
396 **/
397 EFI_DEVICE_PATH_PROTOCOL *
398 EFIAPI
399 FileDevicePath (
400 IN EFI_HANDLE Device, OPTIONAL
401 IN CONST CHAR16 *FileName
402 )
403 {
404 UINTN FileNameSize;
405 UINTN FilePathNodeSize;
406 FILEPATH_DEVICE_PATH *FilePathNode;
407 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
408
409 DevicePath = NULL;
410
411 FileNameSize = StrSize (FileName);
412 FilePathNodeSize = FileNameSize + SIZE_OF_FILEPATH_DEVICE_PATH;
413 FilePathNode = AllocatePool (FilePathNodeSize);
414 if (FilePathNode != NULL) {
415 //
416 // Build a file path node
417 //
418 FilePathNode->Header.Type = MEDIA_DEVICE_PATH;
419 FilePathNode->Header.SubType = MEDIA_FILEPATH_DP;
420 SetDevicePathNodeLength (&FilePathNode->Header, FilePathNodeSize);
421 CopyMem (FilePathNode->PathName, FileName, FileNameSize);
422
423 //
424 // Append file path node to device's device path
425 //
426 if (Device != NULL) {
427 DevicePath = DevicePathFromHandle (Device);
428 }
429 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) FilePathNode);
430 FreePool (FilePathNode);
431 }
432 return DevicePath;
433 }
434