]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Foundation/Library/RuntimeDxe/EfiRuntimeLib/RtDevicePath.c
Sync all bug fixes between EDK1.04 and EDK1.06 into EdkCompatibilityPkg.
[mirror_edk2.git] / EdkCompatibilityPkg / Foundation / Library / RuntimeDxe / EfiRuntimeLib / RtDevicePath.c
1 /*++
2
3 Copyright (c) 2006 - 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 RtDevicePath.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 "EfiRuntimeLib.h"
31 #include "RtDevicePath.h"
32 #include EFI_GUID_DEFINITION (FrameworkDevicePath)
33 #include EFI_PROTOCOL_DEFINITION (DevicePath)
34
35 STATIC
36 VOID *
37 InternalAllocatePool (
38 IN UINTN AllocationSize
39 )
40 /*++
41
42 Routine Description:
43
44 Allocate BootServicesData pool.
45
46 Arguments:
47
48 AllocationSize - The size to allocate
49
50 Returns:
51
52 Pointer of the buffer allocated.
53
54 --*/
55 {
56 VOID *Memory;
57
58 Memory = NULL;
59 gBS->AllocatePool (EfiBootServicesData, AllocationSize, &Memory);
60 return Memory;
61 }
62
63 STATIC
64 VOID *
65 InternalAllocateCopyPool (
66 IN UINTN AllocationSize,
67 IN VOID *Buffer
68 )
69 /*++
70
71 Routine Description:
72
73 Allocate BootServicesData pool and use a buffer provided by
74 caller to fill it.
75
76 Arguments:
77
78 AllocationSize - The size to allocate
79
80 Buffer - Buffer that will be filled into the buffer allocated
81
82 Returns:
83
84 Pointer of the buffer allocated.
85
86 --*/
87 {
88 VOID *Memory;
89
90 Memory = NULL;
91 gBS->AllocatePool (EfiBootServicesData, AllocationSize, &Memory);
92 if (Memory != NULL) {
93 gBS->CopyMem (Memory, Buffer, AllocationSize);
94 }
95
96 return Memory;
97 }
98
99 STATIC
100 VOID *
101 InternalAllocateZeroPool (
102 IN UINTN AllocationSize
103 )
104 /*++
105
106 Routine Description:
107
108 Allocate BootServicesData pool and zero it.
109
110 Arguments:
111
112 AllocationSize - The size to allocate
113
114 Returns:
115
116 Pointer of the buffer allocated.
117
118 --*/
119 {
120 VOID *Memory;
121
122 Memory = InternalAllocatePool (AllocationSize);
123 if (Memory != NULL) {
124 gBS->SetMem (Memory, AllocationSize, 0);
125 }
126
127 return Memory;
128 }
129
130 EFI_DEVICE_PATH_PROTOCOL *
131 RtEfiDevicePathInstance (
132 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
133 OUT UINTN *Size
134 )
135 /*++
136
137 Routine Description:
138 Function retrieves the next device path instance from a device path data structure.
139
140 Arguments:
141 DevicePath - A pointer to a device path data structure.
142
143 Size - A pointer to the size of a device path instance in bytes.
144
145 Returns:
146
147 This function returns a pointer to the current device path instance.
148 In addition, it returns the size in bytes of the current device path instance in Size,
149 and a pointer to the next device path instance in DevicePath.
150 If there are no more device path instances in DevicePath, then DevicePath will be set to NULL.
151
152 --*/
153 {
154 EFI_DEVICE_PATH_PROTOCOL *DevPath;
155 EFI_DEVICE_PATH_PROTOCOL *ReturnValue;
156 UINT8 Temp;
157
158 if (*DevicePath == NULL) {
159 if (Size != NULL) {
160 *Size = 0;
161 }
162
163 return NULL;
164 }
165
166 //
167 // Find the end of the device path instance
168 //
169 DevPath = *DevicePath;
170 while (!IsDevicePathEndType (DevPath)) {
171 DevPath = NextDevicePathNode (DevPath);
172 }
173
174 //
175 // Compute the size of the device path instance
176 //
177 if (Size != NULL) {
178 *Size = ((UINTN) DevPath - (UINTN) (*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
179 }
180
181 //
182 // Make a copy and return the device path instance
183 //
184 Temp = DevPath->SubType;
185 DevPath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
186 ReturnValue = RtEfiDuplicateDevicePath (*DevicePath);
187 DevPath->SubType = Temp;
188
189 //
190 // If DevPath is the end of an entire device path, then another instance
191 // does not follow, so *DevicePath is set to NULL.
192 //
193 if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
194 *DevicePath = NULL;
195 } else {
196 *DevicePath = NextDevicePathNode (DevPath);
197 }
198
199 return ReturnValue;
200 }
201
202 BOOLEAN
203 RtEfiIsDevicePathMultiInstance (
204 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
205 )
206 /*++
207
208 Routine Description:
209 Return TRUE is this is a multi instance device path.
210
211 Arguments:
212 DevicePath - A pointer to a device path data structure.
213
214
215 Returns:
216 TRUE - If DevicePath is multi instance. FALSE - If DevicePath is not multi
217 instance.
218
219 --*/
220 {
221 EFI_DEVICE_PATH_PROTOCOL *Node;
222
223 if (DevicePath == NULL) {
224 return FALSE;
225 }
226
227 Node = DevicePath;
228 while (!EfiIsDevicePathEnd (Node)) {
229 if (EfiIsDevicePathEndInstance (Node)) {
230 return TRUE;
231 }
232
233 Node = EfiNextDevicePathNode (Node);
234 }
235
236 return FALSE;
237 }
238
239 UINTN
240 RtEfiDevicePathSize (
241 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
242 )
243 /*++
244
245 Routine Description:
246
247 Calculate the space size of a device path.
248
249 Arguments:
250
251 DevicePath - A specified device path
252
253 Returns:
254
255 The size.
256
257 --*/
258 {
259 EFI_DEVICE_PATH_PROTOCOL *Start;
260
261 if (DevicePath == NULL) {
262 return 0;
263 }
264
265 //
266 // Search for the end of the device path structure
267 //
268 Start = DevicePath;
269 while (!EfiIsDevicePathEnd (DevicePath)) {
270 DevicePath = EfiNextDevicePathNode (DevicePath);
271 }
272
273 //
274 // Compute the size and add back in the size of the end device path structure
275 //
276 return ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
277 }
278
279 EFI_DEVICE_PATH_PROTOCOL *
280 RtEfiDevicePathFromHandle (
281 IN EFI_HANDLE Handle
282 )
283 /*++
284
285 Routine Description:
286
287 Get the device path protocol interface installed on a specified handle.
288
289 Arguments:
290
291 Handle - a specified handle
292
293 Returns:
294
295 The device path protocol interface installed on that handle.
296
297 --*/
298 {
299 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
300
301 DevicePath = NULL;
302 gBS->HandleProtocol (
303 Handle,
304 &gEfiDevicePathProtocolGuid,
305 (VOID *) &DevicePath
306 );
307 return DevicePath;
308 }
309
310 EFI_DEVICE_PATH_PROTOCOL *
311 RtEfiDuplicateDevicePath (
312 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
313 )
314 /*++
315
316 Routine Description:
317
318 Duplicate a device path structure.
319
320 Arguments:
321
322 DevicePath - The device path to duplicated.
323
324 Returns:
325
326 The duplicated device path.
327
328 --*/
329 {
330 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
331 UINTN Size;
332
333 if (DevicePath == NULL) {
334 return NULL;
335 }
336
337 //
338 // Compute the size
339 //
340 Size = RtEfiDevicePathSize (DevicePath);
341 if (Size == 0) {
342 return NULL;
343 }
344
345 //
346 // Allocate space for duplicate device path
347 //
348 NewDevicePath = InternalAllocateCopyPool (Size, DevicePath);
349
350 return NewDevicePath;
351 }
352
353 EFI_DEVICE_PATH_PROTOCOL *
354 RtEfiAppendDevicePath (
355 IN EFI_DEVICE_PATH_PROTOCOL *Src1,
356 IN EFI_DEVICE_PATH_PROTOCOL *Src2
357 )
358 /*++
359
360 Routine Description:
361 Function is used to append a Src1 and Src2 together.
362
363 Arguments:
364 Src1 - A pointer to a device path data structure.
365
366 Src2 - A pointer to a device path data structure.
367
368 Returns:
369
370 A pointer to the new device path is returned.
371 NULL is returned if space for the new device path could not be allocated from pool.
372 It is up to the caller to free the memory used by Src1 and Src2 if they are no longer needed.
373
374 --*/
375 {
376 UINTN Size;
377 UINTN Size1;
378 UINTN Size2;
379 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
380 EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath;
381
382 //
383 // If there's only 1 path, just duplicate it
384 //
385 if (!Src1) {
386 ASSERT (!IsDevicePathUnpacked (Src2));
387 return RtEfiDuplicateDevicePath (Src2);
388 }
389
390 if (!Src2) {
391 ASSERT (!IsDevicePathUnpacked (Src1));
392 return RtEfiDuplicateDevicePath (Src1);
393 }
394
395 //
396 // Allocate space for the combined device path. It only has one end node of
397 // length EFI_DEVICE_PATH_PROTOCOL
398 //
399 Size1 = RtEfiDevicePathSize (Src1);
400 Size2 = RtEfiDevicePathSize (Src2);
401 Size = Size1 + Size2 - sizeof (EFI_DEVICE_PATH_PROTOCOL);
402
403 NewDevicePath = InternalAllocateCopyPool (Size, Src1);
404
405 if (NewDevicePath != NULL) {
406
407 //
408 // Over write Src1 EndNode and do the copy
409 //
410 SecondDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath + (Size1 - sizeof (EFI_DEVICE_PATH_PROTOCOL)));
411 EfiCopyMem (SecondDevicePath, Src2, Size2);
412 }
413
414 return NewDevicePath;
415 }
416
417 EFI_DEVICE_PATH_PROTOCOL *
418 RtEfiAppendDevicePathNode (
419 IN EFI_DEVICE_PATH_PROTOCOL *Src1,
420 IN EFI_DEVICE_PATH_PROTOCOL *Node
421 )
422 /*++
423
424 Routine Description:
425 Function is used to append a device path node to the end of another device path.
426
427 Arguments:
428 Src1 - A pointer to a device path data structure.
429
430 Node - A pointer to a device path data structure.
431
432 Returns:
433 This function returns a pointer to the new device path.
434 If there is not enough temporary pool memory available to complete this function,
435 then NULL is returned.
436
437
438 --*/
439 {
440 EFI_DEVICE_PATH_PROTOCOL *Temp;
441 EFI_DEVICE_PATH_PROTOCOL *NextNode;
442 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
443 UINTN NodeLength;
444
445 //
446 // Build a Node that has a terminator on it
447 //
448 NodeLength = DevicePathNodeLength (Node);
449
450 Temp = InternalAllocateCopyPool (NodeLength + sizeof (EFI_DEVICE_PATH_PROTOCOL), Node);
451 if (Temp == NULL) {
452 return NULL;
453 }
454
455 //
456 // Add and end device path node to convert Node to device path
457 //
458 NextNode = NextDevicePathNode (Temp);
459 SetDevicePathEndNode (NextNode);
460
461 //
462 // Append device paths
463 //
464 NewDevicePath = RtEfiAppendDevicePath (Src1, Temp);
465 gBS->FreePool (Temp);
466 return NewDevicePath;
467 }
468
469 EFI_DEVICE_PATH_PROTOCOL *
470 RtEfiFileDevicePath (
471 IN EFI_HANDLE Device OPTIONAL,
472 IN CHAR16 *FileName
473 )
474 /*++
475
476 Routine Description:
477
478 This function allocates a device path for a file and appends it to an existiong
479 device path.
480
481 Arguments:
482 Device - A pointer to a device handle.
483
484 FileName - A pointer to a Null-terminated Unicodestring.
485
486 Returns:
487 A device path contain the file name.
488
489 --*/
490 {
491 UINTN Size;
492 FILEPATH_DEVICE_PATH *FilePath;
493 EFI_DEVICE_PATH_PROTOCOL *Eop;
494 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
495
496 for (Size = 0; FileName[Size] != 0; Size++)
497 ;
498 Size = (Size + 1) * 2;
499
500 FilePath = InternalAllocateZeroPool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + sizeof (EFI_DEVICE_PATH_PROTOCOL));
501
502 DevicePath = NULL;
503
504 if (FilePath != NULL) {
505
506 //
507 // Build a file path
508 //
509 FilePath->Header.Type = MEDIA_DEVICE_PATH;
510 FilePath->Header.SubType = MEDIA_FILEPATH_DP;
511 SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH);
512 EfiCopyMem (FilePath->PathName, FileName, Size);
513 Eop = NextDevicePathNode (&FilePath->Header);
514 SetDevicePathEndNode (Eop);
515
516 //
517 // Append file path to device's device path
518 //
519
520 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) FilePath;
521 if (Device != NULL) {
522 DevicePath = RtEfiAppendDevicePath (
523 RtEfiDevicePathFromHandle (Device),
524 DevicePath
525 );
526
527 gBS->FreePool (FilePath);
528 }
529 }
530
531 return DevicePath;
532 }
533
534 EFI_DEVICE_PATH_PROTOCOL *
535 RtEfiAppendDevicePathInstance (
536 IN EFI_DEVICE_PATH_PROTOCOL *Src,
537 IN EFI_DEVICE_PATH_PROTOCOL *Instance
538 )
539 /*++
540
541 Routine Description:
542
543 Append a device path instance to another.
544
545 Arguments:
546
547 Src - The device path instance to be appended with.
548 Instance - The device path instance appending the other.
549
550 Returns:
551
552 The contaction of these two.
553
554 --*/
555 {
556 UINT8 *Ptr;
557 EFI_DEVICE_PATH_PROTOCOL *DevPath;
558 UINTN SrcSize;
559 UINTN InstanceSize;
560
561 if (Src == NULL) {
562 return RtEfiDuplicateDevicePath (Instance);
563 }
564
565 SrcSize = RtEfiDevicePathSize (Src);
566 InstanceSize = RtEfiDevicePathSize (Instance);
567
568 Ptr = InternalAllocateCopyPool (SrcSize + InstanceSize, Src);
569 if (Ptr != NULL) {
570
571 DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
572
573 while (!IsDevicePathEnd (DevPath)) {
574 DevPath = NextDevicePathNode (DevPath);
575 }
576 //
577 // Convert the End to an End Instance, since we are
578 // appending another instacne after this one its a good
579 // idea.
580 //
581 DevPath->SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE;
582
583 DevPath = NextDevicePathNode (DevPath);
584 EfiCopyMem (DevPath, Instance, InstanceSize);
585 }
586
587 return (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
588 }
589
590 VOID
591 EFIAPI
592 RtEfiInitializeFwVolDevicepathNode (
593 IN MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvDevicePathNode,
594 IN EFI_GUID *NameGuid
595 )
596 /*++
597
598 Routine Description:
599
600 Initialize a Firmware Volume (FV) Media Device Path node.
601
602 Arguments:
603
604 FvDevicePathNode - Pointer to a FV device path node to initialize
605 NameGuid - FV file name to use in FvDevicePathNode
606
607 Returns:
608
609 None
610
611 --*/
612 {
613 FvDevicePathNode->Header.Type = MEDIA_DEVICE_PATH;
614 FvDevicePathNode->Header.SubType = MEDIA_FV_FILEPATH_DP;
615 SetDevicePathNodeLength (&FvDevicePathNode->Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH));
616
617 EfiCopyMem (&FvDevicePathNode->NameGuid, NameGuid, sizeof(EFI_GUID));
618 }
619
620 EFI_GUID *
621 EFIAPI
622 RtEfiGetNameGuidFromFwVolDevicePathNode (
623 IN MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvDevicePathNode
624 )
625 /*++
626
627 Routine Description:
628
629 Check to see if the Firmware Volume (FV) Media Device Path is valid.
630
631 Arguments:
632
633 FvDevicePathNode - Pointer to FV device path to check
634
635 Returns:
636
637 NULL - FvDevicePathNode is not valid.
638 Other - FvDevicePathNode is valid and pointer to NameGuid was returned.
639
640 --*/
641 {
642 if (DevicePathType (&FvDevicePathNode->Header) == MEDIA_DEVICE_PATH &&
643 DevicePathSubType (&FvDevicePathNode->Header) == MEDIA_FV_FILEPATH_DP) {
644 return &FvDevicePathNode->NameGuid;
645 }
646
647 return NULL;
648 }
649