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