Home | History | Annotate | Download | only in EfiRuntimeLib
      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 
    650