2 Support a Semi Host file system over a debuggers JTAG
4 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
5 Portions copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 #include <Guid/FileInfo.h>
20 #include <Guid/FileSystemInfo.h>
21 #include <Guid/FileSystemVolumeLabelInfo.h>
23 #include <Library/BaseLib.h>
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/DebugLib.h>
26 #include <Library/MemoryAllocationLib.h>
27 #include <Library/SemihostLib.h>
28 #include <Library/UefiBootServicesTableLib.h>
29 #include <Library/UefiLib.h>
31 #include <Protocol/DevicePath.h>
32 #include <Protocol/SimpleFileSystem.h>
34 #include "SemihostFs.h"
36 #define DEFAULT_SEMIHOST_FS_LABEL L"SemihostFs"
38 STATIC CHAR16
*mSemihostFsLabel
;
40 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gSemihostFs
= {
41 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
,
45 EFI_FILE gSemihostFsFile
= {
46 EFI_FILE_PROTOCOL_REVISION
,
60 // Device path for semi-hosting. It contains our autogened Caller ID GUID.
63 VENDOR_DEVICE_PATH Guid
;
64 EFI_DEVICE_PATH_PROTOCOL End
;
65 } SEMIHOST_DEVICE_PATH
;
67 SEMIHOST_DEVICE_PATH gDevicePath
= {
69 { HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, { sizeof (VENDOR_DEVICE_PATH
), 0 } },
72 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
, { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 } }
87 #define SEMIHOST_FCB_SIGNATURE SIGNATURE_32( 'S', 'H', 'F', 'C' )
88 #define SEMIHOST_FCB_FROM_THIS(a) CR(a, SEMIHOST_FCB, File, SEMIHOST_FCB_SIGNATURE)
89 #define SEMIHOST_FCB_FROM_LINK(a) CR(a, SEMIHOST_FCB, Link, SEMIHOST_FCB_SIGNATURE);
91 EFI_HANDLE gInstallHandle
= NULL
;
92 LIST_ENTRY gFileList
= INITIALIZE_LIST_HEAD_VARIABLE (gFileList
);
99 SEMIHOST_FCB
*Fcb
= AllocateZeroPool (sizeof (SEMIHOST_FCB
));
102 CopyMem (&Fcb
->File
, &gSemihostFsFile
, sizeof (gSemihostFsFile
));
103 Fcb
->Signature
= SEMIHOST_FCB_SIGNATURE
;
114 // Remove Fcb from gFileList.
115 RemoveEntryList (&Fcb
->Link
);
117 // To help debugging...
127 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
131 SEMIHOST_FCB
*RootFcb
= NULL
;
134 return EFI_INVALID_PARAMETER
;
137 RootFcb
= AllocateFCB ();
138 if (RootFcb
== NULL
) {
139 return EFI_OUT_OF_RESOURCES
;
142 RootFcb
->IsRoot
= TRUE
;
143 RootFcb
->Info
.Attribute
= EFI_FILE_READ_ONLY
| EFI_FILE_DIRECTORY
;
145 InsertTailList (&gFileList
, &RootFcb
->Link
);
147 *Root
= &RootFcb
->File
;
153 Open a file on the host system by means of the semihosting interface.
155 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
156 the file handle to source location.
157 @param[out] NewHandle A pointer to the location to return the opened
158 handle for the new file.
159 @param[in] FileName The Null-terminated string of the name of the file
161 @param[in] OpenMode The mode to open the file : Read or Read/Write or
163 @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these
164 are the attribute bits for the newly created file. The
165 mnemonics of the attribute bits are : EFI_FILE_READ_ONLY,
166 EFI_FILE_HIDDEN, EFI_FILE_SYSTEM, EFI_FILE_RESERVED,
167 EFI_FILE_DIRECTORY and EFI_FILE_ARCHIVE.
169 @retval EFI_SUCCESS The file was open.
170 @retval EFI_NOT_FOUND The specified file could not be found.
171 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
172 @retval EFI_WRITE_PROTECTED Attempt to create a directory. This is not possible
173 with the semi-hosting interface.
174 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.
175 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
181 OUT EFI_FILE
**NewHandle
,
187 SEMIHOST_FCB
*FileFcb
;
188 RETURN_STATUS Return
;
190 UINTN SemihostHandle
;
191 CHAR8
*AsciiFileName
;
195 if ((FileName
== NULL
) || (NewHandle
== NULL
)) {
196 return EFI_INVALID_PARAMETER
;
199 if ( (OpenMode
!= EFI_FILE_MODE_READ
) &&
200 (OpenMode
!= (EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
)) &&
201 (OpenMode
!= (EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
)) ) {
202 return EFI_INVALID_PARAMETER
;
205 if ((OpenMode
& EFI_FILE_MODE_CREATE
) &&
206 (Attributes
& EFI_FILE_DIRECTORY
) ) {
207 return EFI_WRITE_PROTECTED
;
210 AsciiFileName
= AllocatePool (StrLen (FileName
) + 1);
211 if (AsciiFileName
== NULL
) {
212 return EFI_OUT_OF_RESOURCES
;
214 UnicodeStrToAsciiStr (FileName
, AsciiFileName
);
216 // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
217 if ((AsciiStrCmp (AsciiFileName
, "\\") == 0) ||
218 (AsciiStrCmp (AsciiFileName
, "/") == 0) ||
219 (AsciiStrCmp (AsciiFileName
, "") == 0) ||
220 (AsciiStrCmp (AsciiFileName
, ".") == 0) ) {
221 FreePool (AsciiFileName
);
222 return (VolumeOpen (&gSemihostFs
, NewHandle
));
226 // No control is done here concerning the file path. It is passed
227 // as it is to the host operating system through the semi-hosting
228 // interface. We first try to open the file in the read or update
229 // mode even if the file creation has been asked for. That way, if
230 // the file already exists, it is not truncated to zero length. In
231 // write mode (bit SEMIHOST_FILE_MODE_WRITE up), if the file already
232 // exists, it is reset to an empty file.
234 if (OpenMode
== EFI_FILE_MODE_READ
) {
235 SemihostMode
= SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
;
237 SemihostMode
= SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
| SEMIHOST_FILE_MODE_UPDATE
;
239 Return
= SemihostFileOpen (AsciiFileName
, SemihostMode
, &SemihostHandle
);
241 if (RETURN_ERROR (Return
)) {
242 if (OpenMode
& EFI_FILE_MODE_CREATE
) {
244 // In the create if does not exist case, if the opening in update
245 // mode failed, create it and open it in update mode. The update
246 // mode allows for both read and write from and to the file.
248 Return
= SemihostFileOpen (
250 SEMIHOST_FILE_MODE_WRITE
| SEMIHOST_FILE_MODE_BINARY
| SEMIHOST_FILE_MODE_UPDATE
,
253 if (RETURN_ERROR (Return
)) {
254 Status
= EFI_DEVICE_ERROR
;
258 Status
= EFI_NOT_FOUND
;
263 // Allocate a control block and fill it
264 FileFcb
= AllocateFCB ();
265 if (FileFcb
== NULL
) {
266 Status
= EFI_OUT_OF_RESOURCES
;
270 FileFcb
->FileName
= AsciiFileName
;
271 FileFcb
->SemihostHandle
= SemihostHandle
;
272 FileFcb
->Position
= 0;
274 FileFcb
->OpenMode
= OpenMode
;
276 Return
= SemihostFileLength (SemihostHandle
, &Length
);
277 if (RETURN_ERROR (Return
)) {
278 Status
= EFI_DEVICE_ERROR
;
283 FileFcb
->Info
.FileSize
= Length
;
284 FileFcb
->Info
.PhysicalSize
= Length
;
285 FileFcb
->Info
.Attribute
= (OpenMode
& EFI_FILE_MODE_CREATE
) ? Attributes
: 0;
287 InsertTailList (&gFileList
, &FileFcb
->Link
);
289 *NewHandle
= &FileFcb
->File
;
295 FreePool (AsciiFileName
);
301 Worker function that truncate a file specified by its name to a given size.
303 @param[in] FileName The Null-terminated string of the name of the file to be opened.
304 @param[in] Size The target size for the file.
306 @retval EFI_SUCCESS The file was truncated.
307 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
318 RETURN_STATUS Return
;
325 Status
= EFI_DEVICE_ERROR
;
329 Return
= SemihostFileOpen (
331 SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
,
334 if (RETURN_ERROR (Return
)) {
338 Buffer
= AllocatePool (Size
);
339 if (Buffer
== NULL
) {
340 Status
= EFI_OUT_OF_RESOURCES
;
346 while (Remaining
> 0) {
348 Return
= SemihostFileRead (FileHandle
, &ToRead
, Buffer
+ Read
);
349 if (RETURN_ERROR (Return
)) {
356 Return
= SemihostFileClose (FileHandle
);
358 if (RETURN_ERROR (Return
)) {
362 Return
= SemihostFileOpen (
364 SEMIHOST_FILE_MODE_WRITE
| SEMIHOST_FILE_MODE_BINARY
,
367 if (RETURN_ERROR (Return
)) {
372 Return
= SemihostFileWrite (FileHandle
, &Size
, Buffer
);
373 if (RETURN_ERROR (Return
)) {
378 Status
= EFI_SUCCESS
;
382 if (FileHandle
!= 0) {
383 SemihostFileClose (FileHandle
);
385 if (Buffer
!= NULL
) {
394 Close a specified file handle.
396 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
399 @retval EFI_SUCCESS The file was closed.
400 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
411 return EFI_INVALID_PARAMETER
;
414 Fcb
= SEMIHOST_FCB_FROM_THIS(This
);
417 SemihostFileClose (Fcb
->SemihostHandle
);
419 // The file size might have been reduced from its actual
420 // size on the host file system with FileSetInfo(). In
421 // that case, the file has to be truncated.
423 if (Fcb
->Info
.FileSize
< Fcb
->Info
.PhysicalSize
) {
424 TruncateFile (Fcb
->FileName
, Fcb
->Info
.FileSize
);
426 FreePool (Fcb
->FileName
);
435 Close and delete a file.
437 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
440 @retval EFI_SUCCESS The file was closed and deleted.
441 @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted.
442 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
451 RETURN_STATUS Return
;
456 return EFI_INVALID_PARAMETER
;
459 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
462 // Get the filename from the Fcb
463 NameSize
= AsciiStrLen (Fcb
->FileName
);
464 FileName
= AllocatePool (NameSize
+ 1);
466 AsciiStrCpy (FileName
, Fcb
->FileName
);
468 // Close the file if it's open. Disregard return status,
469 // since it might give an error if the file isn't open.
472 // Call the semihost interface to delete the file.
473 Return
= SemihostFileRemove (FileName
);
474 if (RETURN_ERROR (Return
)) {
475 return EFI_WARN_DELETE_FAILURE
;
479 return EFI_WARN_DELETE_FAILURE
;
484 Read data from an open file.
486 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
487 is the file handle to read data from.
488 @param[in out] BufferSize On input, the size of the Buffer. On output, the
489 amount of data returned in Buffer. In both cases,
490 the size is measured in bytes.
491 @param[out] Buffer The buffer into which the data is read.
493 @retval EFI_SUCCESS The data was read.
494 @retval EFI_DEVICE_ERROR On entry, the current file position is
495 beyond the end of the file, or the semi-hosting
496 interface reported an error while performing the
498 @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL.
504 IN OUT UINTN
*BufferSize
,
510 RETURN_STATUS Return
;
512 if ((This
== NULL
) || (BufferSize
== NULL
) || (Buffer
== NULL
)) {
513 return EFI_INVALID_PARAMETER
;
516 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
519 // The semi-hosting interface does not allow to list files on the host machine.
520 Status
= EFI_UNSUPPORTED
;
522 Status
= EFI_SUCCESS
;
523 if (Fcb
->Position
>= Fcb
->Info
.FileSize
) {
525 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
526 Status
= EFI_DEVICE_ERROR
;
529 Return
= SemihostFileRead (Fcb
->SemihostHandle
, BufferSize
, Buffer
);
530 if (RETURN_ERROR (Return
)) {
531 Status
= EFI_DEVICE_ERROR
;
533 Fcb
->Position
+= *BufferSize
;
542 Worker function that extends the size of an open file.
544 The extension is filled with zeros.
546 @param[in] Fcb Internal description of the opened file
547 @param[in] Size The number of bytes, the file has to be extended.
549 @retval EFI_SUCCESS The file was extended.
550 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
556 IN SEMIHOST_FCB
*Fcb
,
560 RETURN_STATUS Return
;
562 CHAR8 WriteBuffer
[128];
566 Return
= SemihostFileSeek (Fcb
->SemihostHandle
, Fcb
->Info
.FileSize
);
567 if (RETURN_ERROR (Return
)) {
568 return EFI_DEVICE_ERROR
;
572 SetMem (WriteBuffer
, 0, sizeof(WriteBuffer
));
573 while (Remaining
> 0) {
574 WriteNb
= MIN (Remaining
, sizeof(WriteBuffer
));
576 Return
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, WriteBuffer
);
577 if (RETURN_ERROR (Return
)) {
578 return EFI_DEVICE_ERROR
;
580 Remaining
-= WriteNb
;
587 Write data to an open file.
589 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
590 is the file handle to write data to.
591 @param[in out] BufferSize On input, the size of the Buffer. On output, the
592 size of the data actually written. In both cases,
593 the size is measured in bytes.
594 @param[in] Buffer The buffer of data to write.
596 @retval EFI_SUCCESS The data was written.
597 @retval EFI_ACCESS_DENIED Attempt to write into a read only file or
598 in a file opened in read only mode.
599 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
600 @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL.
606 IN OUT UINTN
*BufferSize
,
613 RETURN_STATUS Return
;
616 if ((This
== NULL
) || (BufferSize
== NULL
) || (Buffer
== NULL
)) {
617 return EFI_INVALID_PARAMETER
;
620 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
622 // We cannot write a read-only file
623 if ((Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
)
624 || !(Fcb
->OpenMode
& EFI_FILE_MODE_WRITE
)) {
625 return EFI_ACCESS_DENIED
;
629 // If the position has been set past the end of the file, first grow the
630 // file from its current size "Fcb->Info.FileSize" to "Fcb->Position"
631 // size, filling the gap with zeros.
633 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
634 Status
= ExtendFile (Fcb
, Fcb
->Position
- Fcb
->Info
.FileSize
);
635 if (EFI_ERROR (Status
)) {
638 Fcb
->Info
.FileSize
= Fcb
->Position
;
641 WriteSize
= *BufferSize
;
642 Return
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, Buffer
);
643 if (RETURN_ERROR (Return
)) {
644 return EFI_DEVICE_ERROR
;
647 Fcb
->Position
+= *BufferSize
;
648 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
649 Fcb
->Info
.FileSize
= Fcb
->Position
;
652 Return
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
653 if (RETURN_ERROR (Return
)) {
654 return EFI_DEVICE_ERROR
;
656 Fcb
->Info
.PhysicalSize
= Length
;
662 Return a file's current position.
664 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
665 the file handle to get the current position on.
666 @param[out] Position The address to return the file's current position value.
668 @retval EFI_SUCCESS The position was returned.
669 @retval EFI_INVALID_PARAMETER The parameter "This" or "Position" is NULL.
680 if ((This
== NULL
) || (Position
== NULL
)) {
681 return EFI_INVALID_PARAMETER
;
684 Fcb
= SEMIHOST_FCB_FROM_THIS(This
);
686 *Position
= Fcb
->Position
;
692 Set a file's current position.
694 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
695 the file handle to set the requested position on.
696 @param[in] Position The byte position from the start of the file to set.
698 @retval EFI_SUCCESS The position was set.
699 @retval EFI_DEVICE_ERROR The semi-hosting positionning operation failed.
700 @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open
702 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
712 RETURN_STATUS Return
;
715 return EFI_INVALID_PARAMETER
;
718 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
722 return EFI_UNSUPPORTED
;
727 // UEFI Spec section 12.5:
728 // "Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to
729 // be set to the end of the file."
731 if (Position
== 0xFFFFFFFFFFFFFFFF) {
732 Position
= Fcb
->Info
.FileSize
;
734 Return
= SemihostFileSeek (Fcb
->SemihostHandle
, MIN (Position
, Fcb
->Info
.FileSize
));
735 if (RETURN_ERROR (Return
)) {
736 return EFI_DEVICE_ERROR
;
740 Fcb
->Position
= Position
;
746 Return information about a file.
748 @param[in] Fcb A pointer to the description of an open file.
749 @param[in out] BufferSize The size, in bytes, of Buffer.
750 @param[out] Buffer A pointer to the data buffer to return. Not NULL if
751 "*BufferSize" is greater than 0.
753 @retval EFI_SUCCESS The information was returned.
754 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
755 BufferSize has been updated with the size needed to
756 complete the request.
761 IN SEMIHOST_FCB
*Fcb
,
762 IN OUT UINTN
*BufferSize
,
766 EFI_FILE_INFO
*Info
= NULL
;
771 if (Fcb
->IsRoot
== TRUE
) {
772 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ sizeof(CHAR16
);
774 NameSize
= AsciiStrLen (Fcb
->FileName
) + 1;
775 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ NameSize
* sizeof (CHAR16
);
778 if (*BufferSize
< ResultSize
) {
779 *BufferSize
= ResultSize
;
780 return EFI_BUFFER_TOO_SMALL
;
785 // Copy the current file info
786 CopyMem (Info
, &Fcb
->Info
, SIZE_OF_EFI_FILE_INFO
);
788 // Fill in the structure
789 Info
->Size
= ResultSize
;
791 if (Fcb
->IsRoot
== TRUE
) {
792 Info
->FileName
[0] = L
'\0';
794 for (Index
= 0; Index
< NameSize
; Index
++) {
795 Info
->FileName
[Index
] = Fcb
->FileName
[Index
];
799 *BufferSize
= ResultSize
;
805 Return information about a file system.
807 @param[in] Fcb A pointer to the description of an open file
808 which belongs to the file system, the information
810 @param[in out] BufferSize The size, in bytes, of Buffer.
811 @param[out] Buffer A pointer to the data buffer to return. Not NULL if
812 "*BufferSize" is greater than 0.
814 @retval EFI_SUCCESS The information was returned.
815 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
816 BufferSize has been updated with the size needed to
817 complete the request.
823 IN SEMIHOST_FCB
*Fcb
,
824 IN OUT UINTN
*BufferSize
,
828 EFI_FILE_SYSTEM_INFO
*Info
;
832 ResultSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (mSemihostFsLabel
);
834 if (*BufferSize
>= ResultSize
) {
835 ZeroMem (Buffer
, ResultSize
);
836 Status
= EFI_SUCCESS
;
840 Info
->Size
= ResultSize
;
841 Info
->ReadOnly
= FALSE
;
842 Info
->VolumeSize
= 0;
846 StrCpy (Info
->VolumeLabel
, mSemihostFsLabel
);
848 Status
= EFI_BUFFER_TOO_SMALL
;
851 *BufferSize
= ResultSize
;
856 Return information about a file or a file system.
858 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
859 is the file handle the requested information is for.
860 @param[in] InformationType The type identifier for the information being requested :
861 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
862 EFI_FILE_SYSTEM_VOLUME_LABEL_ID
863 @param[in out] BufferSize The size, in bytes, of Buffer.
864 @param[out] Buffer A pointer to the data buffer to return. The type of the
865 data inside the buffer is indicated by InformationType.
867 @retval EFI_SUCCESS The information was returned.
868 @retval EFI_UNSUPPORTED The InformationType is not known.
869 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
870 BufferSize has been updated with the size needed to
871 complete the request.
872 @retval EFI_INVALID_PARAMETER The parameter "This" or "InformationType" or "BufferSize"
873 is NULL or "Buffer" is NULL and "*Buffersize" is greater
880 IN EFI_GUID
*InformationType
,
881 IN OUT UINTN
*BufferSize
,
889 if ((This
== NULL
) ||
890 (InformationType
== NULL
) ||
891 (BufferSize
== NULL
) ||
892 ((Buffer
== NULL
) && (*BufferSize
> 0)) ) {
893 return EFI_INVALID_PARAMETER
;
896 Fcb
= SEMIHOST_FCB_FROM_THIS(This
);
898 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
899 Status
= GetFilesystemInfo (Fcb
, BufferSize
, Buffer
);
900 } else if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
901 Status
= GetFileInfo (Fcb
, BufferSize
, Buffer
);
902 } else if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
903 ResultSize
= StrSize (mSemihostFsLabel
);
905 if (*BufferSize
>= ResultSize
) {
906 StrCpy (Buffer
, mSemihostFsLabel
);
907 Status
= EFI_SUCCESS
;
909 Status
= EFI_BUFFER_TOO_SMALL
;
912 *BufferSize
= ResultSize
;
914 Status
= EFI_UNSUPPORTED
;
921 Set information about a file.
923 @param[in] Fcb A pointer to the description of the open file.
924 @param[in] Info A pointer to the file information to write.
926 @retval EFI_SUCCESS The information was set.
927 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
928 to a file that is already present.
929 @retval EFI_ACCESS_DENIED An attempt is being made to change the
930 EFI_FILE_DIRECTORY Attribute.
931 @retval EFI_ACCESS_DENIED The file is a read-only file or has been
932 opened in read-only mode and an attempt is
933 being made to modify a field other than
935 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a
937 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
938 @retval EFI_OUT_OF_RESOURCES A allocation needed to process the request failed.
944 IN SEMIHOST_FCB
*Fcb
,
945 IN EFI_FILE_INFO
*Info
949 RETURN_STATUS Return
;
950 BOOLEAN FileSizeIsDifferent
;
951 BOOLEAN FileNameIsDifferent
;
952 BOOLEAN ReadOnlyIsDifferent
;
953 CHAR8
*AsciiFileName
;
956 UINTN SemihostHandle
;
959 // A directory can not be changed to a file and a file can
960 // not be changed to a directory.
962 if (((Info
->Attribute
& EFI_FILE_DIRECTORY
) != 0) != Fcb
->IsRoot
) {
963 return EFI_ACCESS_DENIED
;
966 AsciiFileName
= AllocatePool (StrLen (Info
->FileName
) + 1);
967 if (AsciiFileName
== NULL
) {
968 return EFI_OUT_OF_RESOURCES
;
970 UnicodeStrToAsciiStr (Info
->FileName
, AsciiFileName
);
972 FileSizeIsDifferent
= (Info
->FileSize
!= Fcb
->Info
.FileSize
);
973 FileNameIsDifferent
= (AsciiStrCmp (AsciiFileName
, Fcb
->FileName
) != 0);
974 ReadOnlyIsDifferent
= CompareMem (
976 &Fcb
->Info
.CreateTime
,
977 3 * sizeof (EFI_TIME
)
981 // For a read-only file or a file opened in read-only mode, only
982 // the Attribute field can be modified. As the root directory is
983 // read-only (i.e. VolumeOpen()), this protects the root directory
986 if ((Fcb
->OpenMode
== EFI_FILE_MODE_READ
) ||
987 (Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
) ) {
988 if (FileSizeIsDifferent
|| FileNameIsDifferent
|| ReadOnlyIsDifferent
) {
989 Status
= EFI_ACCESS_DENIED
;
994 if (ReadOnlyIsDifferent
) {
995 Status
= EFI_WRITE_PROTECTED
;
999 Status
= EFI_DEVICE_ERROR
;
1001 if (FileSizeIsDifferent
) {
1002 FileSize
= Info
->FileSize
;
1003 if (Fcb
->Info
.FileSize
< FileSize
) {
1004 Status
= ExtendFile (Fcb
, FileSize
- Fcb
->Info
.FileSize
);
1005 if (EFI_ERROR (Status
)) {
1009 // The read/write position from the host file system point of view
1010 // is at the end of the file. If the position from this module
1011 // point of view is smaller than the new file size, then
1012 // ask the host file system to move to that position.
1014 if (Fcb
->Position
< FileSize
) {
1015 FileSetPosition (&Fcb
->File
, Fcb
->Position
);
1018 Fcb
->Info
.FileSize
= FileSize
;
1020 Return
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
1021 if (RETURN_ERROR (Return
)) {
1024 Fcb
->Info
.PhysicalSize
= Length
;
1028 // Note down in RAM the Attribute field but we can not ask
1029 // for its modification to the host file system as the
1030 // semi-host interface does not provide this feature.
1032 Fcb
->Info
.Attribute
= Info
->Attribute
;
1034 if (FileNameIsDifferent
) {
1035 Return
= SemihostFileOpen (
1037 SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
,
1040 if (!RETURN_ERROR (Return
)) {
1041 SemihostFileClose (SemihostHandle
);
1042 Status
= EFI_ACCESS_DENIED
;
1046 Return
= SemihostFileRename (Fcb
->FileName
, AsciiFileName
);
1047 if (RETURN_ERROR (Return
)) {
1050 FreePool (Fcb
->FileName
);
1051 Fcb
->FileName
= AsciiFileName
;
1052 AsciiFileName
= NULL
;
1055 Status
= EFI_SUCCESS
;
1058 if (AsciiFileName
!= NULL
) {
1059 FreePool (AsciiFileName
);
1066 Set information about a file or a file system.
1068 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
1069 is the file handle the information is for.
1070 @param[in] InformationType The type identifier for the information being set :
1071 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
1072 EFI_FILE_SYSTEM_VOLUME_LABEL_ID
1073 @param[in] BufferSize The size, in bytes, of Buffer.
1074 @param[in] Buffer A pointer to the data buffer to write. The type of the
1075 data inside the buffer is indicated by InformationType.
1077 @retval EFI_SUCCESS The information was set.
1078 @retval EFI_UNSUPPORTED The InformationType is not known.
1079 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
1080 @retval EFI_ACCESS_DENIED An attempt is being made to change the
1081 EFI_FILE_DIRECTORY Attribute.
1082 @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and
1083 the file is a read-only file or has been
1084 opened in read-only mode and an attempt is
1085 being made to modify a field other than
1087 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
1088 to a file that is already present.
1089 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a
1090 read-only attribute.
1091 @retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by
1092 the data inside the buffer.
1093 @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request failed.
1094 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
1100 IN EFI_GUID
*InformationType
,
1101 IN UINTN BufferSize
,
1106 EFI_FILE_INFO
*Info
;
1107 EFI_FILE_SYSTEM_INFO
*SystemInfo
;
1108 CHAR16
*VolumeLabel
;
1110 if ((This
== NULL
) || (InformationType
== NULL
) || (Buffer
== NULL
)) {
1111 return EFI_INVALID_PARAMETER
;
1114 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
1116 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1118 if (Info
->Size
< (SIZE_OF_EFI_FILE_INFO
+ StrSize (Info
->FileName
))) {
1119 return EFI_INVALID_PARAMETER
;
1121 if (BufferSize
< Info
->Size
) {
1122 return EFI_BAD_BUFFER_SIZE
;
1124 return SetFileInfo (Fcb
, Info
);
1125 } else if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
1126 SystemInfo
= Buffer
;
1127 if (SystemInfo
->Size
<
1128 (SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (SystemInfo
->VolumeLabel
))) {
1129 return EFI_INVALID_PARAMETER
;
1131 if (BufferSize
< SystemInfo
->Size
) {
1132 return EFI_BAD_BUFFER_SIZE
;
1134 Buffer
= SystemInfo
->VolumeLabel
;
1136 if (StrSize (Buffer
) > 0) {
1137 VolumeLabel
= AllocateCopyPool (StrSize (Buffer
), Buffer
);
1138 if (VolumeLabel
!= NULL
) {
1139 FreePool (mSemihostFsLabel
);
1140 mSemihostFsLabel
= VolumeLabel
;
1143 return EFI_OUT_OF_RESOURCES
;
1146 return EFI_INVALID_PARAMETER
;
1148 } else if (!CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1149 return EFI_UNSUPPORTED
;
1151 return EFI_UNSUPPORTED
;
1162 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
1167 if ((Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
)
1168 || !(Fcb
->OpenMode
& EFI_FILE_MODE_WRITE
)) {
1169 return EFI_ACCESS_DENIED
;
1177 SemihostFsEntryPoint (
1178 IN EFI_HANDLE ImageHandle
,
1179 IN EFI_SYSTEM_TABLE
*SystemTable
1184 Status
= EFI_NOT_FOUND
;
1186 if (SemihostConnectionSupported ()) {
1187 mSemihostFsLabel
= AllocateCopyPool (StrSize (DEFAULT_SEMIHOST_FS_LABEL
), DEFAULT_SEMIHOST_FS_LABEL
);
1188 if (mSemihostFsLabel
== NULL
) {
1189 return EFI_OUT_OF_RESOURCES
;
1192 Status
= gBS
->InstallMultipleProtocolInterfaces (
1194 &gEfiSimpleFileSystemProtocolGuid
, &gSemihostFs
,
1195 &gEfiDevicePathProtocolGuid
, &gDevicePath
,
1199 if (EFI_ERROR(Status
)) {
1200 FreePool (mSemihostFsLabel
);