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 - 2021, Arm Limited. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include <Guid/FileInfo.h>
14 #include <Guid/FileSystemInfo.h>
15 #include <Guid/FileSystemVolumeLabelInfo.h>
17 #include <Library/BaseLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/MemoryAllocationLib.h>
21 #include <Library/SemihostLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/UefiLib.h>
25 #include <Protocol/DevicePath.h>
26 #include <Protocol/SimpleFileSystem.h>
28 #include "SemihostFs.h"
30 #define DEFAULT_SEMIHOST_FS_LABEL L"SemihostFs"
32 STATIC CHAR16
*mSemihostFsLabel
;
34 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gSemihostFs
= {
35 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
,
39 EFI_FILE gSemihostFsFile
= {
40 EFI_FILE_PROTOCOL_REVISION
,
54 // Device path for semi-hosting. It contains our auto-generated Caller ID GUID.
57 VENDOR_DEVICE_PATH Guid
;
58 EFI_DEVICE_PATH_PROTOCOL End
;
59 } SEMIHOST_DEVICE_PATH
;
61 SEMIHOST_DEVICE_PATH gDevicePath
= {
63 { HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, { sizeof (VENDOR_DEVICE_PATH
), 0 } },
66 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
, { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 } }
81 #define SEMIHOST_FCB_SIGNATURE SIGNATURE_32( 'S', 'H', 'F', 'C' )
82 #define SEMIHOST_FCB_FROM_THIS(a) CR(a, SEMIHOST_FCB, File, SEMIHOST_FCB_SIGNATURE)
83 #define SEMIHOST_FCB_FROM_LINK(a) CR(a, SEMIHOST_FCB, Link, SEMIHOST_FCB_SIGNATURE);
85 EFI_HANDLE gInstallHandle
= NULL
;
86 LIST_ENTRY gFileList
= INITIALIZE_LIST_HEAD_VARIABLE (gFileList
);
95 Fcb
= AllocateZeroPool (sizeof (SEMIHOST_FCB
));
97 CopyMem (&Fcb
->File
, &gSemihostFsFile
, sizeof (gSemihostFsFile
));
98 Fcb
->Signature
= SEMIHOST_FCB_SIGNATURE
;
109 // Remove Fcb from gFileList.
110 RemoveEntryList (&Fcb
->Link
);
112 // To help debugging...
122 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
126 SEMIHOST_FCB
*RootFcb
;
129 return EFI_INVALID_PARAMETER
;
132 RootFcb
= AllocateFCB ();
133 if (RootFcb
== NULL
) {
134 return EFI_OUT_OF_RESOURCES
;
137 RootFcb
->IsRoot
= TRUE
;
138 RootFcb
->Info
.Attribute
= EFI_FILE_READ_ONLY
| EFI_FILE_DIRECTORY
;
140 InsertTailList (&gFileList
, &RootFcb
->Link
);
142 *Root
= &RootFcb
->File
;
148 Open a file on the host system by means of the semihosting interface.
150 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
151 the file handle to source location.
152 @param[out] NewHandle A pointer to the location to return the opened
153 handle for the new file.
154 @param[in] FileName The Null-terminated string of the name of the file
156 @param[in] OpenMode The mode to open the file : Read or Read/Write or
158 @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these
159 are the attribute bits for the newly created file. The
160 mnemonics of the attribute bits are : EFI_FILE_READ_ONLY,
161 EFI_FILE_HIDDEN, EFI_FILE_SYSTEM, EFI_FILE_RESERVED,
162 EFI_FILE_DIRECTORY and EFI_FILE_ARCHIVE.
164 @retval EFI_SUCCESS The file was open.
165 @retval EFI_NOT_FOUND The specified file could not be found.
166 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
167 @retval EFI_WRITE_PROTECTED Attempt to create a directory. This is not possible
168 with the semi-hosting interface.
169 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.
170 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
176 OUT EFI_FILE
**NewHandle
,
182 SEMIHOST_FCB
*FileFcb
;
183 RETURN_STATUS Return
;
185 UINTN SemihostHandle
;
186 CHAR8
*AsciiFileName
;
190 if ((FileName
== NULL
) || (NewHandle
== NULL
)) {
191 return EFI_INVALID_PARAMETER
;
194 if ( (OpenMode
!= EFI_FILE_MODE_READ
) &&
195 (OpenMode
!= (EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
)) &&
196 (OpenMode
!= (EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
)) ) {
197 return EFI_INVALID_PARAMETER
;
200 if (((OpenMode
& EFI_FILE_MODE_CREATE
) != 0) &&
201 ((Attributes
& EFI_FILE_DIRECTORY
) != 0)) {
202 return EFI_WRITE_PROTECTED
;
205 Length
= StrLen (FileName
) + 1;
206 AsciiFileName
= AllocatePool (Length
);
207 if (AsciiFileName
== NULL
) {
208 return EFI_OUT_OF_RESOURCES
;
210 UnicodeStrToAsciiStrS (FileName
, AsciiFileName
, Length
);
212 // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
213 if ((AsciiStrCmp (AsciiFileName
, "\\") == 0) ||
214 (AsciiStrCmp (AsciiFileName
, "/") == 0) ||
215 (AsciiStrCmp (AsciiFileName
, "") == 0) ||
216 (AsciiStrCmp (AsciiFileName
, ".") == 0) ) {
217 FreePool (AsciiFileName
);
218 return (VolumeOpen (&gSemihostFs
, NewHandle
));
222 // No control is done here concerning the file path. It is passed
223 // as it is to the host operating system through the semi-hosting
224 // interface. We first try to open the file in the read or update
225 // mode even if the file creation has been asked for. That way, if
226 // the file already exists, it is not truncated to zero length. In
227 // write mode (bit SEMIHOST_FILE_MODE_WRITE up), if the file already
228 // exists, it is reset to an empty file.
230 if (OpenMode
== EFI_FILE_MODE_READ
) {
231 SemihostMode
= SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
;
233 SemihostMode
= SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
| SEMIHOST_FILE_MODE_UPDATE
;
235 Return
= SemihostFileOpen (AsciiFileName
, SemihostMode
, &SemihostHandle
);
237 if (RETURN_ERROR (Return
)) {
238 if ((OpenMode
& EFI_FILE_MODE_CREATE
) != 0) {
240 // In the create if does not exist case, if the opening in update
241 // mode failed, create it and open it in update mode. The update
242 // mode allows for both read and write from and to the file.
244 Return
= SemihostFileOpen (
246 SEMIHOST_FILE_MODE_WRITE
| SEMIHOST_FILE_MODE_BINARY
| SEMIHOST_FILE_MODE_UPDATE
,
249 if (RETURN_ERROR (Return
)) {
250 Status
= EFI_DEVICE_ERROR
;
254 Status
= EFI_NOT_FOUND
;
259 // Allocate a control block and fill it
260 FileFcb
= AllocateFCB ();
261 if (FileFcb
== NULL
) {
262 Status
= EFI_OUT_OF_RESOURCES
;
266 FileFcb
->FileName
= AsciiFileName
;
267 FileFcb
->SemihostHandle
= SemihostHandle
;
268 FileFcb
->Position
= 0;
270 FileFcb
->OpenMode
= OpenMode
;
272 Return
= SemihostFileLength (SemihostHandle
, &Length
);
273 if (RETURN_ERROR (Return
)) {
274 Status
= EFI_DEVICE_ERROR
;
279 FileFcb
->Info
.FileSize
= Length
;
280 FileFcb
->Info
.PhysicalSize
= Length
;
281 FileFcb
->Info
.Attribute
= ((OpenMode
& EFI_FILE_MODE_CREATE
) != 0) ?
284 InsertTailList (&gFileList
, &FileFcb
->Link
);
286 *NewHandle
= &FileFcb
->File
;
292 FreePool (AsciiFileName
);
298 Worker function that truncate a file specified by its name to a given size.
300 @param[in] FileName The Null-terminated string of the name of the file to be opened.
301 @param[in] Size The target size for the file.
303 @retval EFI_SUCCESS The file was truncated.
304 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
315 RETURN_STATUS Return
;
322 Status
= EFI_DEVICE_ERROR
;
326 Return
= SemihostFileOpen (
328 SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
,
331 if (RETURN_ERROR (Return
)) {
335 Buffer
= AllocatePool (Size
);
336 if (Buffer
== NULL
) {
337 Status
= EFI_OUT_OF_RESOURCES
;
343 while (Remaining
> 0) {
345 Return
= SemihostFileRead (FileHandle
, &ToRead
, Buffer
+ Read
);
346 if (RETURN_ERROR (Return
)) {
353 Return
= SemihostFileClose (FileHandle
);
355 if (RETURN_ERROR (Return
)) {
359 Return
= SemihostFileOpen (
361 SEMIHOST_FILE_MODE_WRITE
| SEMIHOST_FILE_MODE_BINARY
,
364 if (RETURN_ERROR (Return
)) {
369 Return
= SemihostFileWrite (FileHandle
, &Size
, Buffer
);
370 if (RETURN_ERROR (Return
)) {
375 Status
= EFI_SUCCESS
;
379 if (FileHandle
!= 0) {
380 SemihostFileClose (FileHandle
);
382 if (Buffer
!= NULL
) {
391 Close a specified file handle.
393 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
396 @retval EFI_SUCCESS The file was closed.
397 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
408 return EFI_INVALID_PARAMETER
;
411 Fcb
= SEMIHOST_FCB_FROM_THIS(This
);
414 SemihostFileClose (Fcb
->SemihostHandle
);
416 // The file size might have been reduced from its actual
417 // size on the host file system with FileSetInfo(). In
418 // that case, the file has to be truncated.
420 if (Fcb
->Info
.FileSize
< Fcb
->Info
.PhysicalSize
) {
421 TruncateFile (Fcb
->FileName
, Fcb
->Info
.FileSize
);
423 FreePool (Fcb
->FileName
);
432 Close and delete a file.
434 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
437 @retval EFI_SUCCESS The file was closed and deleted.
438 @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted.
439 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
448 RETURN_STATUS Return
;
453 return EFI_INVALID_PARAMETER
;
456 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
459 // Get the filename from the Fcb
460 NameSize
= AsciiStrLen (Fcb
->FileName
);
461 FileName
= AllocatePool (NameSize
+ 1);
463 AsciiStrCpyS (FileName
, NameSize
+ 1, Fcb
->FileName
);
465 // Close the file if it's open. Disregard return status,
466 // since it might give an error if the file isn't open.
469 // Call the semihost interface to delete the file.
470 Return
= SemihostFileRemove (FileName
);
471 if (RETURN_ERROR (Return
)) {
472 return EFI_WARN_DELETE_FAILURE
;
476 return EFI_WARN_DELETE_FAILURE
;
481 Read data from an open file.
483 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
484 is the file handle to read data from.
485 @param[in out] BufferSize On input, the size of the Buffer. On output, the
486 amount of data returned in Buffer. In both cases,
487 the size is measured in bytes.
488 @param[out] Buffer The buffer into which the data is read.
490 @retval EFI_SUCCESS The data was read.
491 @retval EFI_DEVICE_ERROR On entry, the current file position is
492 beyond the end of the file, or the semi-hosting
493 interface reported an error while performing the
495 @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL.
501 IN OUT UINTN
*BufferSize
,
507 RETURN_STATUS Return
;
509 if ((This
== NULL
) || (BufferSize
== NULL
) || (Buffer
== NULL
)) {
510 return EFI_INVALID_PARAMETER
;
513 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
516 // The semi-hosting interface does not allow to list files on the host machine.
517 Status
= EFI_UNSUPPORTED
;
519 Status
= EFI_SUCCESS
;
520 if (Fcb
->Position
>= Fcb
->Info
.FileSize
) {
522 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
523 Status
= EFI_DEVICE_ERROR
;
526 Return
= SemihostFileRead (Fcb
->SemihostHandle
, BufferSize
, Buffer
);
527 if (RETURN_ERROR (Return
)) {
528 Status
= EFI_DEVICE_ERROR
;
530 Fcb
->Position
+= *BufferSize
;
539 Worker function that extends the size of an open file.
541 The extension is filled with zeros.
543 @param[in] Fcb Internal description of the opened file
544 @param[in] Size The number of bytes, the file has to be extended.
546 @retval EFI_SUCCESS The file was extended.
547 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
553 IN SEMIHOST_FCB
*Fcb
,
557 RETURN_STATUS Return
;
559 CHAR8 WriteBuffer
[128];
563 Return
= SemihostFileSeek (Fcb
->SemihostHandle
, Fcb
->Info
.FileSize
);
564 if (RETURN_ERROR (Return
)) {
565 return EFI_DEVICE_ERROR
;
569 SetMem (WriteBuffer
, 0, sizeof(WriteBuffer
));
570 while (Remaining
> 0) {
571 WriteNb
= MIN (Remaining
, sizeof(WriteBuffer
));
573 Return
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, WriteBuffer
);
574 if (RETURN_ERROR (Return
)) {
575 return EFI_DEVICE_ERROR
;
577 Remaining
-= WriteNb
;
584 Write data to an open file.
586 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
587 is the file handle to write data to.
588 @param[in out] BufferSize On input, the size of the Buffer. On output, the
589 size of the data actually written. In both cases,
590 the size is measured in bytes.
591 @param[in] Buffer The buffer of data to write.
593 @retval EFI_SUCCESS The data was written.
594 @retval EFI_ACCESS_DENIED Attempt to write into a read only file or
595 in a file opened in read only mode.
596 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
597 @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL.
603 IN OUT UINTN
*BufferSize
,
610 RETURN_STATUS Return
;
613 if ((This
== NULL
) || (BufferSize
== NULL
) || (Buffer
== NULL
)) {
614 return EFI_INVALID_PARAMETER
;
617 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
619 // We cannot write a read-only file
620 if ((Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
)
621 || !(Fcb
->OpenMode
& EFI_FILE_MODE_WRITE
)) {
622 return EFI_ACCESS_DENIED
;
626 // If the position has been set past the end of the file, first grow the
627 // file from its current size "Fcb->Info.FileSize" to "Fcb->Position"
628 // size, filling the gap with zeros.
630 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
631 Status
= ExtendFile (Fcb
, Fcb
->Position
- Fcb
->Info
.FileSize
);
632 if (EFI_ERROR (Status
)) {
635 Fcb
->Info
.FileSize
= Fcb
->Position
;
638 WriteSize
= *BufferSize
;
639 Return
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, Buffer
);
640 if (RETURN_ERROR (Return
)) {
641 return EFI_DEVICE_ERROR
;
644 Fcb
->Position
+= *BufferSize
;
645 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
646 Fcb
->Info
.FileSize
= Fcb
->Position
;
649 Return
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
650 if (RETURN_ERROR (Return
)) {
651 return EFI_DEVICE_ERROR
;
653 Fcb
->Info
.PhysicalSize
= Length
;
659 Return a file's current position.
661 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
662 the file handle to get the current position on.
663 @param[out] Position The address to return the file's current position value.
665 @retval EFI_SUCCESS The position was returned.
666 @retval EFI_INVALID_PARAMETER The parameter "This" or "Position" is NULL.
677 if ((This
== NULL
) || (Position
== NULL
)) {
678 return EFI_INVALID_PARAMETER
;
681 Fcb
= SEMIHOST_FCB_FROM_THIS(This
);
683 *Position
= Fcb
->Position
;
689 Set a file's current position.
691 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
692 the file handle to set the requested position on.
693 @param[in] Position The byte position from the start of the file to set.
695 @retval EFI_SUCCESS The position was set.
696 @retval EFI_DEVICE_ERROR The semi-hosting positioning operation failed.
697 @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open
699 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
709 RETURN_STATUS Return
;
712 return EFI_INVALID_PARAMETER
;
715 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
719 return EFI_UNSUPPORTED
;
724 // UEFI Spec section 12.5:
725 // "Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to
726 // be set to the end of the file."
728 if (Position
== 0xFFFFFFFFFFFFFFFF) {
729 Position
= Fcb
->Info
.FileSize
;
731 Return
= SemihostFileSeek (Fcb
->SemihostHandle
, MIN (Position
, Fcb
->Info
.FileSize
));
732 if (RETURN_ERROR (Return
)) {
733 return EFI_DEVICE_ERROR
;
737 Fcb
->Position
= Position
;
743 Return information about a file.
745 @param[in] Fcb A pointer to the description of an open file.
746 @param[in out] BufferSize The size, in bytes, of Buffer.
747 @param[out] Buffer A pointer to the data buffer to return. Not NULL if
748 "*BufferSize" is greater than 0.
750 @retval EFI_SUCCESS The information was returned.
751 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
752 BufferSize has been updated with the size needed to
753 complete the request.
758 IN SEMIHOST_FCB
*Fcb
,
759 IN OUT UINTN
*BufferSize
,
770 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ sizeof(CHAR16
);
772 NameSize
= AsciiStrLen (Fcb
->FileName
) + 1;
773 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ NameSize
* sizeof (CHAR16
);
776 if (*BufferSize
< ResultSize
) {
777 *BufferSize
= ResultSize
;
778 return EFI_BUFFER_TOO_SMALL
;
783 // Copy the current file info
784 CopyMem (Info
, &Fcb
->Info
, SIZE_OF_EFI_FILE_INFO
);
786 // Fill in the structure
787 Info
->Size
= ResultSize
;
790 Info
->FileName
[0] = L
'\0';
792 for (Index
= 0; Index
< NameSize
; Index
++) {
793 Info
->FileName
[Index
] = Fcb
->FileName
[Index
];
797 *BufferSize
= ResultSize
;
803 Return information about a file system.
805 @param[in] Fcb A pointer to the description of an open file
806 which belongs to the file system, the information
808 @param[in out] BufferSize The size, in bytes, of Buffer.
809 @param[out] Buffer A pointer to the data buffer to return. Not NULL if
810 "*BufferSize" is greater than 0.
812 @retval EFI_SUCCESS The information was returned.
813 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
814 BufferSize has been updated with the size needed to
815 complete the request.
821 IN SEMIHOST_FCB
*Fcb
,
822 IN OUT UINTN
*BufferSize
,
826 EFI_FILE_SYSTEM_INFO
*Info
;
831 StringSize
= StrSize (mSemihostFsLabel
);
832 ResultSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StringSize
;
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 CopyMem (Info
->VolumeLabel
, mSemihostFsLabel
, StringSize
);
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 CopyMem (Buffer
, mSemihostFsLabel
, ResultSize
);
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 Length
= StrLen (Info
->FileName
) + 1;
967 AsciiFileName
= AllocatePool (Length
);
968 if (AsciiFileName
== NULL
) {
969 return EFI_OUT_OF_RESOURCES
;
971 UnicodeStrToAsciiStrS (Info
->FileName
, AsciiFileName
, Length
);
973 FileSizeIsDifferent
= (Info
->FileSize
!= Fcb
->Info
.FileSize
);
974 FileNameIsDifferent
= (AsciiStrCmp (AsciiFileName
, Fcb
->FileName
) != 0);
975 ReadOnlyIsDifferent
= CompareMem (
977 &Fcb
->Info
.CreateTime
,
978 3 * sizeof (EFI_TIME
)
982 // For a read-only file or a file opened in read-only mode, only
983 // the Attribute field can be modified. As the root directory is
984 // read-only (i.e. VolumeOpen()), this protects the root directory
987 if ((Fcb
->OpenMode
== EFI_FILE_MODE_READ
) ||
988 (Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
) ) {
989 if (FileSizeIsDifferent
|| FileNameIsDifferent
|| ReadOnlyIsDifferent
) {
990 Status
= EFI_ACCESS_DENIED
;
995 if (ReadOnlyIsDifferent
) {
996 Status
= EFI_WRITE_PROTECTED
;
1000 Status
= EFI_DEVICE_ERROR
;
1002 if (FileSizeIsDifferent
) {
1003 FileSize
= Info
->FileSize
;
1004 if (Fcb
->Info
.FileSize
< FileSize
) {
1005 Status
= ExtendFile (Fcb
, FileSize
- Fcb
->Info
.FileSize
);
1006 if (EFI_ERROR (Status
)) {
1010 // The read/write position from the host file system point of view
1011 // is at the end of the file. If the position from this module
1012 // point of view is smaller than the new file size, then
1013 // ask the host file system to move to that position.
1015 if (Fcb
->Position
< FileSize
) {
1016 FileSetPosition (&Fcb
->File
, Fcb
->Position
);
1019 Fcb
->Info
.FileSize
= FileSize
;
1021 Return
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
1022 if (RETURN_ERROR (Return
)) {
1025 Fcb
->Info
.PhysicalSize
= Length
;
1029 // Note down in RAM the Attribute field but we can not ask
1030 // for its modification to the host file system as the
1031 // semi-host interface does not provide this feature.
1033 Fcb
->Info
.Attribute
= Info
->Attribute
;
1035 if (FileNameIsDifferent
) {
1036 Return
= SemihostFileOpen (
1038 SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
,
1041 if (!RETURN_ERROR (Return
)) {
1042 SemihostFileClose (SemihostHandle
);
1043 Status
= EFI_ACCESS_DENIED
;
1047 Return
= SemihostFileRename (Fcb
->FileName
, AsciiFileName
);
1048 if (RETURN_ERROR (Return
)) {
1051 FreePool (Fcb
->FileName
);
1052 Fcb
->FileName
= AsciiFileName
;
1053 AsciiFileName
= NULL
;
1056 Status
= EFI_SUCCESS
;
1059 if (AsciiFileName
!= NULL
) {
1060 FreePool (AsciiFileName
);
1067 Set information about a file or a file system.
1069 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
1070 is the file handle the information is for.
1071 @param[in] InformationType The type identifier for the information being set :
1072 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
1073 EFI_FILE_SYSTEM_VOLUME_LABEL_ID
1074 @param[in] BufferSize The size, in bytes, of Buffer.
1075 @param[in] Buffer A pointer to the data buffer to write. The type of the
1076 data inside the buffer is indicated by InformationType.
1078 @retval EFI_SUCCESS The information was set.
1079 @retval EFI_UNSUPPORTED The InformationType is not known.
1080 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
1081 @retval EFI_ACCESS_DENIED An attempt is being made to change the
1082 EFI_FILE_DIRECTORY Attribute.
1083 @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and
1084 the file is a read-only file or has been
1085 opened in read-only mode and an attempt is
1086 being made to modify a field other than
1088 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
1089 to a file that is already present.
1090 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a
1091 read-only attribute.
1092 @retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by
1093 the data inside the buffer.
1094 @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request failed.
1095 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
1101 IN EFI_GUID
*InformationType
,
1102 IN UINTN BufferSize
,
1107 EFI_FILE_INFO
*Info
;
1108 EFI_FILE_SYSTEM_INFO
*SystemInfo
;
1109 CHAR16
*VolumeLabel
;
1111 if ((This
== NULL
) || (InformationType
== NULL
) || (Buffer
== NULL
)) {
1112 return EFI_INVALID_PARAMETER
;
1115 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
1117 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1119 if (Info
->Size
< (SIZE_OF_EFI_FILE_INFO
+ StrSize (Info
->FileName
))) {
1120 return EFI_INVALID_PARAMETER
;
1122 if (BufferSize
< Info
->Size
) {
1123 return EFI_BAD_BUFFER_SIZE
;
1125 return SetFileInfo (Fcb
, Info
);
1126 } else if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
1127 SystemInfo
= Buffer
;
1128 if (SystemInfo
->Size
<
1129 (SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (SystemInfo
->VolumeLabel
))) {
1130 return EFI_INVALID_PARAMETER
;
1132 if (BufferSize
< SystemInfo
->Size
) {
1133 return EFI_BAD_BUFFER_SIZE
;
1135 Buffer
= SystemInfo
->VolumeLabel
;
1137 if (StrSize (Buffer
) > 0) {
1138 VolumeLabel
= AllocateCopyPool (StrSize (Buffer
), Buffer
);
1139 if (VolumeLabel
!= NULL
) {
1140 FreePool (mSemihostFsLabel
);
1141 mSemihostFsLabel
= VolumeLabel
;
1144 return EFI_OUT_OF_RESOURCES
;
1147 return EFI_INVALID_PARAMETER
;
1149 } else if (!CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1150 return EFI_UNSUPPORTED
;
1152 return EFI_UNSUPPORTED
;
1163 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
1168 if ((Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
)
1169 || !(Fcb
->OpenMode
& EFI_FILE_MODE_WRITE
)) {
1170 return EFI_ACCESS_DENIED
;
1178 SemihostFsEntryPoint (
1179 IN EFI_HANDLE ImageHandle
,
1180 IN EFI_SYSTEM_TABLE
*SystemTable
1185 Status
= EFI_NOT_FOUND
;
1187 if (SemihostConnectionSupported ()) {
1188 mSemihostFsLabel
= AllocateCopyPool (StrSize (DEFAULT_SEMIHOST_FS_LABEL
), DEFAULT_SEMIHOST_FS_LABEL
);
1189 if (mSemihostFsLabel
== NULL
) {
1190 return EFI_OUT_OF_RESOURCES
;
1193 Status
= gBS
->InstallMultipleProtocolInterfaces (
1195 &gEfiSimpleFileSystemProtocolGuid
, &gSemihostFs
,
1196 &gEfiDevicePathProtocolGuid
, &gDevicePath
,
1200 if (EFI_ERROR(Status
)) {
1201 FreePool (mSemihostFsLabel
);