]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.c
*BaseSmbusLib: (new version)
[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 DevicePath A pointer to a device path data structure.
159
160 @param DevicePathNode 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 *DevicePath,
171 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathNode
172 )
173 {
174 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
175 EFI_DEVICE_PATH_PROTOCOL *NextNode;
176 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
177 UINTN NodeLength;
178
179 //
180 // Build a Node that has a terminator on it
181 //
182 NodeLength = DevicePathNodeLength (DevicePathNode);
183
184 TempDevicePath = AllocatePool (NodeLength + sizeof (EFI_DEVICE_PATH_PROTOCOL));
185 if (TempDevicePath == NULL) {
186 return NULL;
187 }
188 TempDevicePath = CopyMem (TempDevicePath, DevicePathNode, NodeLength);
189 //
190 // Add and end device path node to convert Node to device path
191 //
192 NextNode = NextDevicePathNode (TempDevicePath);
193 SetDevicePathEndNode (NextNode);
194 //
195 // Append device paths
196 //
197 NewDevicePath = AppendDevicePath (DevicePath, TempDevicePath);
198
199 FreePool (TempDevicePath);
200
201 return NewDevicePath;
202 }
203
204 /**
205 This function appends the device path instance Instance to the device path Source.
206 If Source is NULL, then a new device path with one instance is created.
207
208 @param Source A pointer to a device path data structure.
209 @param Instance A pointer to a device path instance.
210
211 @return A pointer to the new device path.
212 If there is not enough temporary pool memory available to complete this function,
213 then NULL is returned.
214
215 **/
216 EFI_DEVICE_PATH_PROTOCOL *
217 EFIAPI
218 AppendDevicePathInstance (
219 IN CONST EFI_DEVICE_PATH_PROTOCOL *Source,
220 IN CONST EFI_DEVICE_PATH_PROTOCOL *Instance
221 )
222 {
223 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
224 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
225 UINTN SrcSize;
226 UINTN InstanceSize;
227
228 if (Source == NULL) {
229 return DuplicateDevicePath (Instance);
230 }
231
232 SrcSize = GetDevicePathSize (Source);
233 InstanceSize = GetDevicePathSize (Instance);
234
235 NewDevicePath = AllocatePool (SrcSize + InstanceSize);
236 if (NewDevicePath != NULL) {
237
238 DevicePath = CopyMem (NewDevicePath, Source, SrcSize);;
239
240 while (!IsDevicePathEnd (DevicePath)) {
241 DevicePath = NextDevicePathNode (DevicePath);
242 }
243
244 DevicePath->SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE;
245
246 DevicePath = NextDevicePathNode (DevicePath);
247 CopyMem (DevicePath, Instance, InstanceSize);
248 }
249
250 return NewDevicePath;
251 }
252
253 /**
254 Function retrieves the next device path instance from a device path data structure.
255
256 @param DevicePath A pointer to a device path data structure.
257
258 @param Size A pointer to the size of a device path instance in bytes.
259
260 @return This function returns a pointer to the current device path instance.
261 In addition, it returns the size in bytes of the current device path instance in Size,
262 and a pointer to the next device path instance in DevicePath.
263 If there are no more device path instances in DevicePath, then DevicePath will be set to NULL.
264
265 **/
266 EFI_DEVICE_PATH_PROTOCOL *
267 EFIAPI
268 GetNextDevicePathInstance (
269 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
270 OUT UINTN *Size
271 )
272 {
273 EFI_DEVICE_PATH_PROTOCOL *DevPath;
274 EFI_DEVICE_PATH_PROTOCOL *ReturnValue;
275 UINT8 Temp;
276
277 ASSERT (DevicePath != NULL);
278 ASSERT (Size != NULL);
279 if (*DevicePath == NULL) {
280 *Size = 0;
281 return NULL;
282 }
283
284 //
285 // Find the end of the device path instance
286 //
287 DevPath = *DevicePath;
288 while (!IsDevicePathEndType (DevPath)) {
289 DevPath = NextDevicePathNode (DevPath);
290 }
291
292 //
293 // Compute the size of the device path instance
294 //
295 *Size = ((UINTN) DevPath - (UINTN) (*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
296
297 //
298 // Make a copy and return the device path instance
299 //
300 Temp = DevPath->SubType;
301 DevPath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
302 ReturnValue = DuplicateDevicePath (*DevicePath);
303 DevPath->SubType = Temp;
304
305 //
306 // If DevPath is the end of an entire device path, then another instance
307 // does not follow, so *DevicePath is set to NULL.
308 //
309 if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
310 *DevicePath = NULL;
311 } else {
312 *DevicePath = NextDevicePathNode (DevPath);
313 }
314
315 return ReturnValue;
316 }
317
318 /**
319 Return TRUE is this is a multi instance device path.
320
321 @param DevicePath A pointer to a device path data structure.
322
323 @retval TRUE If DevicePath is multi-instance.
324 @retval FALSE If DevicePath is not multi-instance or DevicePath is NULL.
325
326 **/
327 BOOLEAN
328 EFIAPI
329 IsDevicePathMultiInstance (
330 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
331 )
332 {
333 CONST EFI_DEVICE_PATH_PROTOCOL *Node;
334
335 if (DevicePath == NULL) {
336 return FALSE;
337 }
338
339 Node = DevicePath;
340 while (!EfiIsDevicePathEnd (Node)) {
341 if (EfiIsDevicePathEndInstance (Node)) {
342 return TRUE;
343 }
344
345 Node = EfiNextDevicePathNode (Node);
346 }
347
348 return FALSE;
349 }
350
351 /**
352 This function retrieves the device path protocol from a handle.
353
354 @param Handle The handle from which to retrieve the device path protocol.
355
356 @return This function returns the device path protocol from the handle specified by Handle.
357 If Handle is NULL or Handle does not contain a device path protocol, then NULL is returned.
358
359 **/
360 EFI_DEVICE_PATH_PROTOCOL *
361 EFIAPI
362 DevicePathFromHandle (
363 IN EFI_HANDLE Handle
364 )
365 {
366 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
367 EFI_STATUS Status;
368
369 Status = gBS->HandleProtocol (
370 Handle,
371 &gEfiDevicePathProtocolGuid,
372 (VOID *) &DevicePath
373 );
374 if (EFI_ERROR (Status)) {
375 DevicePath = NULL;
376 }
377 return DevicePath;
378 }
379
380 /**
381 This function allocates a device path for a file and appends it to an existing device path.
382
383 @param Device A pointer to a device handle. This parameter is optional and may be NULL.
384 @param FileName A pointer to a Null-terminated Unicode string.
385
386 @return If Device is a valid device handle that contains a device path protocol,
387 then a device path for the file specified by FileName is allocated
388 and appended to the device path associated with the handle Device. The allocated device path is returned.
389 If Device is NULL or Device is a handle that does not support the device path protocol,
390 then a device path containing a single device path node for the file specified by FileName
391 is allocated and returned.
392
393 **/
394 EFI_DEVICE_PATH_PROTOCOL *
395 EFIAPI
396 FileDevicePath (
397 IN EFI_HANDLE Device, OPTIONAL
398 IN CONST CHAR16 *FileName
399 )
400 {
401 UINTN FileNameSize;
402 UINTN FilePathNodeSize;
403 FILEPATH_DEVICE_PATH *FilePathNode;
404 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
405
406 DevicePath = NULL;
407
408 FileNameSize = StrSize (FileName);
409 FilePathNodeSize = FileNameSize + SIZE_OF_FILEPATH_DEVICE_PATH;
410 FilePathNode = AllocatePool (FilePathNodeSize);
411 if (FilePathNode != NULL) {
412 //
413 // Build a file path node
414 //
415 FilePathNode->Header.Type = MEDIA_DEVICE_PATH;
416 FilePathNode->Header.SubType = MEDIA_FILEPATH_DP;
417 SetDevicePathNodeLength (&FilePathNode->Header, FilePathNodeSize);
418 CopyMem (FilePathNode->PathName, FileName, FileNameSize);
419
420 //
421 // Append file path node to device's device path
422 //
423 if (Device != NULL) {
424 DevicePath = DevicePathFromHandle (Device);
425 }
426 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) FilePathNode);
427 FreePool (FilePathNode);
428 }
429 return DevicePath;
430 }
431