Update the return status to comply to PI spec.
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / FwVol / FwVolRead.c
1 /*++
2
3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. 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 FwVolRead.c
15
16 Abstract:
17
18 Implements read firmware file
19
20 --*/
21
22 #include <DxeMain.h>
23
24 /*++
25
26 Required Alignment Alignment Value in FFS Alignment Value in
27 (bytes) Attributes Field Firmware Volume Interfaces
28 1 0 0
29 2 0 1
30 4 0 2
31 8 0 3
32 16 1 4
33 128 2 7
34 512 3 9
35 1 KB 4 10
36 4 KB 5 12
37 32 KB 6 15
38 64 KB 7 16
39
40 --*/
41
42 UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16};
43
44
45 STATIC
46 EFI_FV_FILE_ATTRIBUTES
47 FfsAttributes2FvFileAttributes (
48 IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes
49 )
50 /*++
51
52 Routine Description:
53 Convert the FFS File Attributes to FV File Attributes
54
55 Arguments:
56 FfsAttributes - The attributes of UINT8 type.
57
58 Returns:
59 The attributes of EFI_FV_FILE_ATTRIBUTES
60
61 --*/
62 {
63 FfsAttributes = (EFI_FFS_FILE_ATTRIBUTES)((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3);
64 ASSERT (FfsAttributes < 8);
65
66 return (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[FfsAttributes];
67 }
68
69
70 EFI_STATUS
71 EFIAPI
72 FvGetNextFile (
73 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
74 IN OUT VOID *Key,
75 IN OUT EFI_FV_FILETYPE *FileType,
76 OUT EFI_GUID *NameGuid,
77 OUT EFI_FV_FILE_ATTRIBUTES *Attributes,
78 OUT UINTN *Size
79 )
80 /*++
81
82 Routine Description:
83 Given the input key, search for the next matching file in the volume.
84
85 Arguments:
86 This - Indicates the calling context.
87 FileType - FileType is a pointer to a caller allocated
88 EFI_FV_FILETYPE. The GetNextFile() API can filter it's
89 search for files based on the value of *FileType input.
90 A *FileType input of 0 causes GetNextFile() to search for
91 files of all types. If a file is found, the file's type
92 is returned in *FileType. *FileType is not modified if
93 no file is found.
94 Key - Key is a pointer to a caller allocated buffer that
95 contains implementation specific data that is used to
96 track where to begin the search for the next file.
97 The size of the buffer must be at least This->KeySize
98 bytes long. To reinitialize the search and begin from
99 the beginning of the firmware volume, the entire buffer
100 must be cleared to zero. Other than clearing the buffer
101 to initiate a new search, the caller must not modify the
102 data in the buffer between calls to GetNextFile().
103 NameGuid - NameGuid is a pointer to a caller allocated EFI_GUID.
104 If a file is found, the file's name is returned in
105 *NameGuid. *NameGuid is not modified if no file is
106 found.
107 Attributes - Attributes is a pointer to a caller allocated
108 EFI_FV_FILE_ATTRIBUTES. If a file is found, the file's
109 attributes are returned in *Attributes. *Attributes is
110 not modified if no file is found.
111 Size - Size is a pointer to a caller allocated UINTN.
112 If a file is found, the file's size is returned in *Size.
113 *Size is not modified if no file is found.
114
115 Returns:
116 EFI_SUCCESS - Successfully find the file.
117 EFI_DEVICE_ERROR - Device error.
118 EFI_ACCESS_DENIED - Fv could not read.
119 EFI_NOT_FOUND - No matching file found.
120 EFI_INVALID_PARAMETER - Invalid parameter
121
122 --*/
123 {
124 EFI_STATUS Status;
125 FV_DEVICE *FvDevice;
126 EFI_FV_ATTRIBUTES FvAttributes;
127 EFI_FFS_FILE_HEADER *FfsFileHeader;
128 UINTN *KeyValue;
129 LIST_ENTRY *Link;
130 FFS_FILE_LIST_ENTRY *FfsFileEntry;
131 UINTN FileLength;
132
133 FvDevice = FV_DEVICE_FROM_THIS (This);
134
135 Status = FvGetVolumeAttributes (This, &FvAttributes);
136 if (EFI_ERROR (Status)){
137 return Status;
138 }
139
140 //
141 // Check if read operation is enabled
142 //
143 if ((FvAttributes & EFI_FV2_READ_STATUS) == 0) {
144 return EFI_ACCESS_DENIED;
145 }
146
147 if (*FileType > EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
148 //
149 // File type needs to be in 0 - 0x0B
150 //
151 return EFI_NOT_FOUND;
152 }
153
154 KeyValue = (UINTN *)Key;
155 for (;;) {
156 if (*KeyValue == 0) {
157 //
158 // Search for 1st matching file
159 //
160 Link = &FvDevice->FfsFileListHeader;
161 } else {
162 //
163 // Key is pointer to FFsFileEntry, so get next one
164 //
165 Link = (LIST_ENTRY *)(*KeyValue);
166 }
167
168 if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
169 //
170 // Next is end of list so we did not find data
171 //
172 return EFI_NOT_FOUND;
173 }
174
175 FfsFileEntry = (FFS_FILE_LIST_ENTRY *)Link->ForwardLink;
176 FfsFileHeader = (EFI_FFS_FILE_HEADER *)FfsFileEntry->FfsHeader;
177
178 //
179 // remember the key
180 //
181 *KeyValue = (UINTN)FfsFileEntry;
182
183 if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
184 //
185 // we ignore pad files
186 //
187 continue;
188 }
189
190 if (*FileType == 0) {
191 //
192 // Process all file types so we have a match
193 //
194 break;
195 }
196
197 if (*FileType == FfsFileHeader->Type) {
198 //
199 // Found a matching file type
200 //
201 break;
202 }
203
204 }
205
206 //
207 // Return FileType, NameGuid, and Attributes
208 //
209 *FileType = FfsFileHeader->Type;
210 CopyMem (NameGuid, &FfsFileHeader->Name, sizeof (EFI_GUID));
211 *Attributes = FfsAttributes2FvFileAttributes (FfsFileHeader->Attributes);
212
213 //
214 // Read four bytes out of the 3 byte array and throw out extra data
215 //
216 FileLength = *(UINT32 *)&FfsFileHeader->Size[0] & 0x00FFFFFF;
217
218 //
219 // we need to substract the header size
220 //
221 *Size = FileLength - sizeof(EFI_FFS_FILE_HEADER);
222
223 return EFI_SUCCESS;
224 }
225
226
227 EFI_STATUS
228 EFIAPI
229 FvReadFile (
230 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
231 IN CONST EFI_GUID *NameGuid,
232 IN OUT VOID **Buffer,
233 IN OUT UINTN *BufferSize,
234 OUT EFI_FV_FILETYPE *FoundType,
235 OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes,
236 OUT UINT32 *AuthenticationStatus
237 )
238 /*++
239
240 Routine Description:
241 Locates a file in the firmware volume and
242 copies it to the supplied buffer.
243
244 Arguments:
245 This - Indicates the calling context.
246 NameGuid - Pointer to an EFI_GUID, which is the filename.
247 Buffer - Buffer is a pointer to pointer to a buffer in
248 which the file or section contents or are returned.
249 BufferSize - BufferSize is a pointer to caller allocated
250 UINTN. On input *BufferSize indicates the size
251 in bytes of the memory region pointed to by
252 Buffer. On output, *BufferSize contains the number
253 of bytes required to read the file.
254 FoundType - FoundType is a pointer to a caller allocated
255 EFI_FV_FILETYPE that on successful return from Read()
256 contains the type of file read. This output reflects
257 the file type irrespective of the value of the
258 SectionType input.
259 FileAttributes - FileAttributes is a pointer to a caller allocated
260 EFI_FV_FILE_ATTRIBUTES. On successful return from
261 Read(), *FileAttributes contains the attributes of
262 the file read.
263 AuthenticationStatus - AuthenticationStatus is a pointer to a caller
264 allocated UINTN in which the authentication status
265 is returned.
266 Returns:
267 EFI_SUCCESS - Successfully read to memory buffer.
268 EFI_WARN_BUFFER_TOO_SMALL - Buffer too small.
269 EFI_NOT_FOUND - Not found.
270 EFI_DEVICE_ERROR - Device error.
271 EFI_ACCESS_DENIED - Could not read.
272 EFI_INVALID_PARAMETER - Invalid parameter.
273 EFI_OUT_OF_RESOURCES - Not enough buffer to be allocated.
274
275 --*/
276 {
277 EFI_STATUS Status;
278 FV_DEVICE *FvDevice;
279 EFI_GUID SearchNameGuid;
280 EFI_FV_FILETYPE LocalFoundType;
281 EFI_FV_FILE_ATTRIBUTES LocalAttributes;
282 UINTN FileSize;
283 UINT8 *SrcPtr;
284 EFI_FFS_FILE_HEADER *FfsHeader;
285 UINTN InputBufferSize;
286
287 if (NULL == NameGuid) {
288 return EFI_INVALID_PARAMETER;
289 }
290
291 FvDevice = FV_DEVICE_FROM_THIS (This);
292
293
294 //
295 // Keep looking until we find the matching NameGuid.
296 // The Key is really an FfsFileEntry
297 //
298 FvDevice->LastKey = 0;
299 do {
300 LocalFoundType = 0;
301 Status = FvGetNextFile (
302 This,
303 &FvDevice->LastKey,
304 &LocalFoundType,
305 &SearchNameGuid,
306 &LocalAttributes,
307 &FileSize
308 );
309 if (EFI_ERROR (Status)) {
310 return EFI_NOT_FOUND;
311 }
312 } while (!CompareGuid (&SearchNameGuid, NameGuid));
313
314 //
315 // Get a pointer to the header
316 //
317 FfsHeader = FvDevice->LastKey->FfsHeader;
318
319 //
320 // Remember callers buffer size
321 //
322 InputBufferSize = *BufferSize;
323
324 //
325 // Calculate return values
326 //
327 *FoundType = FfsHeader->Type;
328 *FileAttributes = FfsAttributes2FvFileAttributes (FfsHeader->Attributes);
329 *AuthenticationStatus = 0;
330 *BufferSize = FileSize;
331
332 if (Buffer == NULL) {
333 //
334 // If Buffer is NULL, we only want to get the information colected so far
335 //
336 return EFI_SUCCESS;
337 }
338
339 //
340 // Skip over file header
341 //
342 SrcPtr = ((UINT8 *)FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);
343
344 Status = EFI_SUCCESS;
345 if (*Buffer == NULL) {
346 //
347 // Caller passed in a pointer so allocate buffer for them
348 //
349 *Buffer = CoreAllocateBootServicesPool (FileSize);
350 if (*Buffer == NULL) {
351 return EFI_OUT_OF_RESOURCES;
352 }
353 } else if (FileSize > InputBufferSize) {
354 //
355 // Callers buffer was not big enough
356 //
357 Status = EFI_WARN_BUFFER_TOO_SMALL;
358 FileSize = InputBufferSize;
359 }
360
361 //
362 // Copy data into callers buffer
363 //
364 CopyMem (*Buffer, SrcPtr, FileSize);
365
366 return Status;
367 }
368
369
370 EFI_STATUS
371 EFIAPI
372 FvReadFileSection (
373 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
374 IN CONST EFI_GUID *NameGuid,
375 IN EFI_SECTION_TYPE SectionType,
376 IN UINTN SectionInstance,
377 IN OUT VOID **Buffer,
378 IN OUT UINTN *BufferSize,
379 OUT UINT32 *AuthenticationStatus
380 )
381 /*++
382
383 Routine Description:
384 Locates a section in a given FFS File and
385 copies it to the supplied buffer (not including section header).
386
387 Arguments:
388 This - Indicates the calling context.
389 NameGuid - Pointer to an EFI_GUID, which is the filename.
390 SectionType - Indicates the section type to return.
391 SectionInstance - Indicates which instance of sections with a type of
392 SectionType to return.
393 Buffer - Buffer is a pointer to pointer to a buffer in which
394 the file or section contents or are returned.
395 BufferSize - BufferSize is a pointer to caller allocated UINTN.
396 AuthenticationStatus -AuthenticationStatus is a pointer to a caller
397 allocated UINT32 in which the authentication status
398 is returned.
399
400 Returns:
401 EFI_SUCCESS - Successfully read the file section into buffer.
402 EFI_WARN_BUFFER_TOO_SMALL - Buffer too small.
403 EFI_NOT_FOUND - Section not found.
404 EFI_DEVICE_ERROR - Device error.
405 EFI_ACCESS_DENIED - Could not read.
406 EFI_INVALID_PARAMETER - Invalid parameter.
407
408 --*/
409 {
410 EFI_STATUS Status;
411 FV_DEVICE *FvDevice;
412 EFI_FV_FILETYPE FileType;
413 EFI_FV_FILE_ATTRIBUTES FileAttributes;
414 UINTN FileSize;
415 UINT8 *FileBuffer;
416 EFI_SECTION_EXTRACTION_PROTOCOL *Sep;
417 FFS_FILE_LIST_ENTRY *FfsEntry;
418
419 if (NULL == NameGuid || Buffer == NULL) {
420 return EFI_INVALID_PARAMETER;
421 }
422
423 FvDevice = FV_DEVICE_FROM_THIS (This);
424
425 //
426 // Read the whole file into buffer
427 //
428 FileBuffer = NULL;
429 Status = FvReadFile (
430 This,
431 NameGuid,
432 (VOID **)&FileBuffer,
433 &FileSize,
434 &FileType,
435 &FileAttributes,
436 AuthenticationStatus
437 );
438 //
439 // Get the last key used by our call to FvReadFile as it is the FfsEntry for this file.
440 //
441 FfsEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->LastKey;
442
443 if (EFI_ERROR (Status)) {
444 return Status;
445 }
446
447 //
448 // Check to see that the file actually HAS sections before we go any further.
449 //
450 if (FileType == EFI_FV_FILETYPE_RAW) {
451 Status = EFI_NOT_FOUND;
452 goto Done;
453 }
454
455 //
456 // Use FfsEntry to cache Section Extraction Protocol Inforomation
457 //
458 if (FfsEntry->StreamHandle == 0) {
459 //
460 // Located the protocol
461 //
462 Status = CoreLocateProtocol (&gEfiSectionExtractionProtocolGuid, NULL, (VOID **)&Sep);
463 //
464 // Section Extraction Protocol is part of Dxe Core so this should never fail
465 //
466 ASSERT_EFI_ERROR (Status);
467
468 Status = Sep->OpenSectionStream (
469 Sep,
470 FileSize,
471 FileBuffer,
472 &FfsEntry->StreamHandle
473 );
474 if (EFI_ERROR (Status)) {
475 goto Done;
476 }
477
478 FfsEntry->Sep = Sep;
479 } else {
480 //
481 // Get cached copy of Sep
482 //
483 Sep = FfsEntry->Sep;
484 }
485
486 //
487 // If SectionType == 0 We need the whole section stream
488 //
489 Status = Sep->GetSection (
490 Sep,
491 FfsEntry->StreamHandle,
492 (SectionType == 0) ? NULL : &SectionType,
493 NULL,
494 (SectionType == 0) ? 0 : SectionInstance,
495 Buffer,
496 BufferSize,
497 AuthenticationStatus
498 );
499
500 //
501 // Close of stream defered to close of FfsHeader list to allow SEP to cache data
502 //
503
504 Done:
505 CoreFreePool (FileBuffer);
506
507 return Status;
508 }
509