1 /*++
2 
3 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution.  The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8 
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 Module Name:
13 
14   DevicePath.c
15 
16 Abstract:
17 
18   Device Path services. The thing to remember is device paths are built out of
19   nodes. The device path is terminated by an end node that is length
20   sizeof(EFI_DEVICE_PATH_PROTOCOL). That would be why there is sizeof(EFI_DEVICE_PATH_PROTOCOL)
21   all over this file.
22 
23   The only place where multi-instance device paths are supported is in
24   environment varibles. Multi-instance device paths should never be placed
25   on a Handle.
26 
27 --*/
28 
29 #include "Tiano.h"
30 #include "EfiDriverLib.h"
31 #include EFI_PROTOCOL_DEFINITION (DevicePath)
32 
33 EFI_DEVICE_PATH_PROTOCOL *
EfiDevicePathInstance(IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,OUT UINTN * Size)34 EfiDevicePathInstance (
35   IN OUT EFI_DEVICE_PATH_PROTOCOL   **DevicePath,
36   OUT UINTN                         *Size
37   )
38 /*++
39 
40 Routine Description:
41   Function retrieves the next device path instance from a device path data structure.
42 
43 Arguments:
44   DevicePath           - A pointer to a device path data structure.
45 
46   Size                 - A pointer to the size of a device path instance in bytes.
47 
48 Returns:
49 
50   This function returns a pointer to the current device path instance.
51   In addition, it returns the size in bytes of the current device path instance in Size,
52   and a pointer to the next device path instance in DevicePath.
53   If there are no more device path instances in DevicePath, then DevicePath will be set to NULL.
54 
55 --*/
56 {
57   EFI_DEVICE_PATH_PROTOCOL  *DevPath;
58   EFI_DEVICE_PATH_PROTOCOL  *ReturnValue;
59   UINT8                     Temp;
60 
61   if (*DevicePath == NULL) {
62     if (Size != NULL) {
63       *Size = 0;
64     }
65 
66     return NULL;
67   }
68 
69   //
70   // Find the end of the device path instance
71   //
72   DevPath = *DevicePath;
73   while (!IsDevicePathEndType (DevPath)) {
74     DevPath = NextDevicePathNode (DevPath);
75   }
76 
77   //
78   // Compute the size of the device path instance
79   //
80   if (Size != NULL) {
81     *Size = ((UINTN) DevPath - (UINTN) (*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
82   }
83 
84   //
85   // Make a copy and return the device path instance
86   //
87   Temp              = DevPath->SubType;
88   DevPath->SubType  = END_ENTIRE_DEVICE_PATH_SUBTYPE;
89   ReturnValue       = EfiDuplicateDevicePath (*DevicePath);
90   DevPath->SubType  = Temp;
91 
92   //
93   // If DevPath is the end of an entire device path, then another instance
94   // does not follow, so *DevicePath is set to NULL.
95   //
96   if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
97     *DevicePath = NULL;
98   } else {
99     *DevicePath = NextDevicePathNode (DevPath);
100   }
101 
102   return ReturnValue;
103 }
104 
105 BOOLEAN
EfiIsDevicePathMultiInstance(IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)106 EfiIsDevicePathMultiInstance (
107   IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath
108   )
109 /*++
110 
111 Routine Description:
112   Return TRUE is this is a multi instance device path.
113 
114 Arguments:
115   DevicePath  - A pointer to a device path data structure.
116 
117 
118 Returns:
119   TRUE - If DevicePath is multi instance. FALSE - If DevicePath is not multi
120   instance.
121 
122 --*/
123 {
124   EFI_DEVICE_PATH_PROTOCOL  *Node;
125 
126   if (DevicePath == NULL) {
127     return FALSE;
128   }
129 
130   Node = DevicePath;
131   while (!EfiIsDevicePathEnd (Node)) {
132     if (EfiIsDevicePathEndInstance (Node)) {
133       return TRUE;
134     }
135 
136     Node = EfiNextDevicePathNode (Node);
137   }
138 
139   return FALSE;
140 }
141 
142 UINTN
EfiDevicePathSize(IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)143 EfiDevicePathSize (
144   IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath
145   )
146 /*++
147 
148 Routine Description:
149 
150   Calculate the space size of a device path.
151 
152 Arguments:
153 
154   DevicePath  - A specified device path
155 
156 Returns:
157 
158   The size.
159 
160 --*/
161 {
162   EFI_DEVICE_PATH_PROTOCOL  *Start;
163 
164   if (DevicePath == NULL) {
165     return 0;
166   }
167 
168   //
169   // Search for the end of the device path structure
170   //
171   Start = DevicePath;
172   while (!EfiIsDevicePathEnd (DevicePath)) {
173     DevicePath = EfiNextDevicePathNode (DevicePath);
174   }
175 
176   //
177   // Compute the size and add back in the size of the end device path structure
178   //
179   return ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
180 }
181 
182 EFI_DEVICE_PATH_PROTOCOL *
EfiDevicePathFromHandle(IN EFI_HANDLE Handle)183 EfiDevicePathFromHandle (
184   IN EFI_HANDLE  Handle
185   )
186 /*++
187 
188 Routine Description:
189 
190   Get the device path protocol interface installed on a specified handle.
191 
192 Arguments:
193 
194   Handle  - a specified handle
195 
196 Returns:
197 
198   The device path protocol interface installed on that handle.
199 
200 --*/
201 {
202   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
203 
204   DevicePath = NULL;
205   gBS->HandleProtocol (
206         Handle,
207         &gEfiDevicePathProtocolGuid,
208         (VOID *) &DevicePath
209         );
210   return DevicePath;
211 }
212 
213 EFI_DEVICE_PATH_PROTOCOL *
EfiDuplicateDevicePath(IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)214 EfiDuplicateDevicePath (
215   IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath
216   )
217 /*++
218 
219 Routine Description:
220 
221   Duplicate a device path structure.
222 
223 Arguments:
224 
225   DevicePath  - The device path to duplicated.
226 
227 Returns:
228 
229   The duplicated device path.
230 
231 --*/
232 {
233   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
234   UINTN                     Size;
235 
236   if (DevicePath == NULL) {
237     return NULL;
238   }
239 
240   //
241   // Compute the size
242   //
243   Size = EfiDevicePathSize (DevicePath);
244   if (Size == 0) {
245     return NULL;
246   }
247 
248   //
249   // Allocate space for duplicate device path
250   //
251   NewDevicePath = EfiLibAllocateCopyPool (Size, DevicePath);
252 
253   return NewDevicePath;
254 }
255 
256 EFI_DEVICE_PATH_PROTOCOL *
EfiAppendDevicePath(IN EFI_DEVICE_PATH_PROTOCOL * Src1,IN EFI_DEVICE_PATH_PROTOCOL * Src2)257 EfiAppendDevicePath (
258   IN EFI_DEVICE_PATH_PROTOCOL  *Src1,
259   IN EFI_DEVICE_PATH_PROTOCOL  *Src2
260   )
261 /*++
262 
263 Routine Description:
264   Function is used to append a Src1 and Src2 together.
265 
266 Arguments:
267   Src1  - A pointer to a device path data structure.
268 
269   Src2  - A pointer to a device path data structure.
270 
271 Returns:
272 
273   A pointer to the new device path is returned.
274   NULL is returned if space for the new device path could not be allocated from pool.
275   It is up to the caller to free the memory used by Src1 and Src2 if they are no longer needed.
276 
277 --*/
278 {
279   UINTN                     Size;
280   UINTN                     Size1;
281   UINTN                     Size2;
282   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
283   EFI_DEVICE_PATH_PROTOCOL  *SecondDevicePath;
284 
285   //
286   // If there's only 1 path, just duplicate it
287   //
288   if (!Src1) {
289     ASSERT (!IsDevicePathUnpacked (Src2));
290     return EfiDuplicateDevicePath (Src2);
291   }
292 
293   if (!Src2) {
294     ASSERT (!IsDevicePathUnpacked (Src1));
295     return EfiDuplicateDevicePath (Src1);
296   }
297 
298   //
299   // Allocate space for the combined device path. It only has one end node of
300   // length EFI_DEVICE_PATH_PROTOCOL
301   //
302   Size1         = EfiDevicePathSize (Src1);
303   Size2         = EfiDevicePathSize (Src2);
304   Size          = Size1 + Size2 - sizeof (EFI_DEVICE_PATH_PROTOCOL);
305 
306   NewDevicePath = EfiLibAllocateCopyPool (Size, Src1);
307 
308   if (NewDevicePath != NULL) {
309 
310     //
311     // Over write Src1 EndNode and do the copy
312     //
313     SecondDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath + (Size1 - sizeof (EFI_DEVICE_PATH_PROTOCOL)));
314     EfiCopyMem (SecondDevicePath, Src2, Size2);
315   }
316 
317   return NewDevicePath;
318 }
319 
320 EFI_DEVICE_PATH_PROTOCOL *
EfiAppendDevicePathNode(IN EFI_DEVICE_PATH_PROTOCOL * Src1,IN EFI_DEVICE_PATH_PROTOCOL * Node)321 EfiAppendDevicePathNode (
322   IN EFI_DEVICE_PATH_PROTOCOL  *Src1,
323   IN EFI_DEVICE_PATH_PROTOCOL  *Node
324   )
325 /*++
326 
327 Routine Description:
328   Function is used to append a device path node to the end of another device path.
329 
330 Arguments:
331   Src1  - A pointer to a device path data structure.
332 
333   Node - A pointer to a device path data structure.
334 
335 Returns:
336   This function returns a pointer to the new device path.
337   If there is not enough temporary pool memory available to complete this function,
338   then NULL is returned.
339 
340 
341 --*/
342 {
343   EFI_DEVICE_PATH_PROTOCOL  *Temp;
344   EFI_DEVICE_PATH_PROTOCOL  *NextNode;
345   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
346   UINTN                     NodeLength;
347 
348   //
349   // Build a Node that has a terminator on it
350   //
351   NodeLength  = DevicePathNodeLength (Node);
352 
353   Temp        = EfiLibAllocateCopyPool (NodeLength + sizeof (EFI_DEVICE_PATH_PROTOCOL), Node);
354   if (Temp == NULL) {
355     return NULL;
356   }
357 
358   //
359   // Add and end device path node to convert Node to device path
360   //
361   NextNode = NextDevicePathNode (Temp);
362   SetDevicePathEndNode (NextNode);
363 
364   //
365   // Append device paths
366   //
367   NewDevicePath = EfiAppendDevicePath (Src1, Temp);
368   gBS->FreePool (Temp);
369   return NewDevicePath;
370 }
371 
372 EFI_DEVICE_PATH_PROTOCOL *
EfiFileDevicePath(IN EFI_HANDLE Device OPTIONAL,IN CHAR16 * FileName)373 EfiFileDevicePath (
374   IN EFI_HANDLE               Device  OPTIONAL,
375   IN CHAR16                   *FileName
376   )
377 /*++
378 
379 Routine Description:
380 
381   This function allocates a device path for a file and appends it to an existiong
382   device path.
383 
384 Arguments:
385   Device     - A pointer to a device handle.
386 
387   FileName   - A pointer to a Null-terminated Unicodestring.
388 
389 Returns:
390   A device path contain the file name.
391 
392 --*/
393 {
394   UINTN                     Size;
395   FILEPATH_DEVICE_PATH      *FilePath;
396   EFI_DEVICE_PATH_PROTOCOL  *Eop;
397   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
398 
399   for (Size = 0; FileName[Size] != 0; Size++)
400     ;
401   Size        = (Size + 1) * 2;
402 
403   FilePath    = EfiLibAllocateZeroPool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + sizeof (EFI_DEVICE_PATH_PROTOCOL));
404 
405   DevicePath  = NULL;
406 
407   if (FilePath != NULL) {
408 
409     //
410     // Build a file path
411     //
412     FilePath->Header.Type     = MEDIA_DEVICE_PATH;
413     FilePath->Header.SubType  = MEDIA_FILEPATH_DP;
414     SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH);
415     EfiCopyMem (FilePath->PathName, FileName, Size);
416     Eop = NextDevicePathNode (&FilePath->Header);
417     SetDevicePathEndNode (Eop);
418 
419     //
420     // Append file path to device's device path
421     //
422 
423     DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) FilePath;
424     if (Device != NULL) {
425       DevicePath = EfiAppendDevicePath (
426                     EfiDevicePathFromHandle (Device),
427                     DevicePath
428                     );
429 
430       gBS->FreePool (FilePath);
431     }
432   }
433 
434   return DevicePath;
435 }
436 
437 EFI_DEVICE_PATH_PROTOCOL *
EfiAppendDevicePathInstance(IN EFI_DEVICE_PATH_PROTOCOL * Src,IN EFI_DEVICE_PATH_PROTOCOL * Instance)438 EfiAppendDevicePathInstance (
439   IN EFI_DEVICE_PATH_PROTOCOL  *Src,
440   IN EFI_DEVICE_PATH_PROTOCOL  *Instance
441   )
442 /*++
443 
444 Routine Description:
445 
446   Append a device path instance to another.
447 
448 Arguments:
449 
450   Src       - The device path instance to be appended with.
451   Instance  - The device path instance appending the other.
452 
453 Returns:
454 
455   The contaction of these two.
456 
457 --*/
458 {
459   UINT8                     *Ptr;
460   EFI_DEVICE_PATH_PROTOCOL  *DevPath;
461   UINTN                     SrcSize;
462   UINTN                     InstanceSize;
463 
464   if (Src == NULL) {
465     return EfiDuplicateDevicePath (Instance);
466   }
467 
468   SrcSize       = EfiDevicePathSize (Src);
469   InstanceSize  = EfiDevicePathSize (Instance);
470 
471   Ptr           = EfiLibAllocateCopyPool (SrcSize + InstanceSize, Src);
472   if (Ptr != NULL) {
473 
474     DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
475 
476     while (!IsDevicePathEnd (DevPath)) {
477       DevPath = NextDevicePathNode (DevPath);
478     }
479     //
480     // Convert the End to an End Instance, since we are
481     //  appending another instacne after this one its a good
482     //  idea.
483     //
484     DevPath->SubType  = END_INSTANCE_DEVICE_PATH_SUBTYPE;
485 
486     DevPath           = NextDevicePathNode (DevPath);
487     EfiCopyMem (DevPath, Instance, InstanceSize);
488   }
489 
490   return (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
491 }
492 
493 VOID
494 EFIAPI
EfiInitializeFwVolDevicepathNode(IN MEDIA_FW_VOL_FILEPATH_DEVICE_PATH * FvDevicePathNode,IN EFI_GUID * NameGuid)495 EfiInitializeFwVolDevicepathNode (
496   IN  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH     *FvDevicePathNode,
497   IN EFI_GUID                               *NameGuid
498   )
499 /*++
500 
501 Routine Description:
502 
503   Initialize a Firmware Volume (FV) Media Device Path node.
504 
505 Arguments:
506 
507   FvDevicePathNode  - Pointer to a FV device path node to initialize
508   NameGuid          - FV file name to use in FvDevicePathNode
509 
510 Returns:
511 
512   None
513 
514 --*/
515 {
516   FvDevicePathNode->Header.Type     = MEDIA_DEVICE_PATH;
517   FvDevicePathNode->Header.SubType  = MEDIA_FV_FILEPATH_DP;
518   SetDevicePathNodeLength (&FvDevicePathNode->Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH));
519 
520   EfiCopyMem (&FvDevicePathNode->NameGuid, NameGuid, sizeof(EFI_GUID));
521 }
522 
523 EFI_GUID *
524 EFIAPI
EfiGetNameGuidFromFwVolDevicePathNode(IN MEDIA_FW_VOL_FILEPATH_DEVICE_PATH * FvDevicePathNode)525 EfiGetNameGuidFromFwVolDevicePathNode (
526   IN  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH   *FvDevicePathNode
527   )
528 /*++
529 
530 Routine Description:
531 
532   Check to see if the Firmware Volume (FV) Media Device Path is valid.
533 
534 Arguments:
535 
536   FvDevicePathNode  - Pointer to FV device path to check
537 
538 Returns:
539 
540   NULL              - FvDevicePathNode is not valid.
541   Other             - FvDevicePathNode is valid and pointer to NameGuid was returned.
542 
543 --*/
544 {
545   if (DevicePathType (&FvDevicePathNode->Header) == MEDIA_DEVICE_PATH &&
546       DevicePathSubType (&FvDevicePathNode->Header) == MEDIA_FV_FILEPATH_DP) {
547     return &FvDevicePathNode->NameGuid;
548   }
549 
550   return NULL;
551 }
552