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 autogened 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
);
93 SEMIHOST_FCB
*Fcb
= AllocateZeroPool (sizeof (SEMIHOST_FCB
));
96 CopyMem (&Fcb
->File
, &gSemihostFsFile
, sizeof (gSemihostFsFile
));
97 Fcb
->Signature
= SEMIHOST_FCB_SIGNATURE
;
108 // Remove Fcb from gFileList.
109 RemoveEntryList (&Fcb
->Link
);
111 // To help debugging...
121 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
125 SEMIHOST_FCB
*RootFcb
= NULL
;
128 return EFI_INVALID_PARAMETER
;
131 RootFcb
= AllocateFCB ();
132 if (RootFcb
== NULL
) {
133 return EFI_OUT_OF_RESOURCES
;
136 RootFcb
->IsRoot
= TRUE
;
137 RootFcb
->Info
.Attribute
= EFI_FILE_READ_ONLY
| EFI_FILE_DIRECTORY
;
139 InsertTailList (&gFileList
, &RootFcb
->Link
);
141 *Root
= &RootFcb
->File
;
147 Open a file on the host system by means of the semihosting interface.
149 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
150 the file handle to source location.
151 @param[out] NewHandle A pointer to the location to return the opened
152 handle for the new file.
153 @param[in] FileName The Null-terminated string of the name of the file
155 @param[in] OpenMode The mode to open the file : Read or Read/Write or
157 @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these
158 are the attribute bits for the newly created file. The
159 mnemonics of the attribute bits are : EFI_FILE_READ_ONLY,
160 EFI_FILE_HIDDEN, EFI_FILE_SYSTEM, EFI_FILE_RESERVED,
161 EFI_FILE_DIRECTORY and EFI_FILE_ARCHIVE.
163 @retval EFI_SUCCESS The file was open.
164 @retval EFI_NOT_FOUND The specified file could not be found.
165 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
166 @retval EFI_WRITE_PROTECTED Attempt to create a directory. This is not possible
167 with the semi-hosting interface.
168 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.
169 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
175 OUT EFI_FILE
**NewHandle
,
181 SEMIHOST_FCB
*FileFcb
;
182 RETURN_STATUS Return
;
184 UINTN SemihostHandle
;
185 CHAR8
*AsciiFileName
;
189 if ((FileName
== NULL
) || (NewHandle
== NULL
)) {
190 return EFI_INVALID_PARAMETER
;
193 if ( (OpenMode
!= EFI_FILE_MODE_READ
) &&
194 (OpenMode
!= (EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
)) &&
195 (OpenMode
!= (EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
)) ) {
196 return EFI_INVALID_PARAMETER
;
199 if (((OpenMode
& EFI_FILE_MODE_CREATE
) != 0) &&
200 ((Attributes
& EFI_FILE_DIRECTORY
) != 0)) {
201 return EFI_WRITE_PROTECTED
;
204 Length
= StrLen (FileName
) + 1;
205 AsciiFileName
= AllocatePool (Length
);
206 if (AsciiFileName
== NULL
) {
207 return EFI_OUT_OF_RESOURCES
;
209 UnicodeStrToAsciiStrS (FileName
, AsciiFileName
, Length
);
211 // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
212 if ((AsciiStrCmp (AsciiFileName
, "\\") == 0) ||
213 (AsciiStrCmp (AsciiFileName
, "/") == 0) ||
214 (AsciiStrCmp (AsciiFileName
, "") == 0) ||
215 (AsciiStrCmp (AsciiFileName
, ".") == 0) ) {
216 FreePool (AsciiFileName
);
217 return (VolumeOpen (&gSemihostFs
, NewHandle
));
221 // No control is done here concerning the file path. It is passed
222 // as it is to the host operating system through the semi-hosting
223 // interface. We first try to open the file in the read or update
224 // mode even if the file creation has been asked for. That way, if
225 // the file already exists, it is not truncated to zero length. In
226 // write mode (bit SEMIHOST_FILE_MODE_WRITE up), if the file already
227 // exists, it is reset to an empty file.
229 if (OpenMode
== EFI_FILE_MODE_READ
) {
230 SemihostMode
= SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
;
232 SemihostMode
= SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
| SEMIHOST_FILE_MODE_UPDATE
;
234 Return
= SemihostFileOpen (AsciiFileName
, SemihostMode
, &SemihostHandle
);
236 if (RETURN_ERROR (Return
)) {
237 if ((OpenMode
& EFI_FILE_MODE_CREATE
) != 0) {
239 // In the create if does not exist case, if the opening in update
240 // mode failed, create it and open it in update mode. The update
241 // mode allows for both read and write from and to the file.
243 Return
= SemihostFileOpen (
245 SEMIHOST_FILE_MODE_WRITE
| SEMIHOST_FILE_MODE_BINARY
| SEMIHOST_FILE_MODE_UPDATE
,
248 if (RETURN_ERROR (Return
)) {
249 Status
= EFI_DEVICE_ERROR
;
253 Status
= EFI_NOT_FOUND
;
258 // Allocate a control block and fill it
259 FileFcb
= AllocateFCB ();
260 if (FileFcb
== NULL
) {
261 Status
= EFI_OUT_OF_RESOURCES
;
265 FileFcb
->FileName
= AsciiFileName
;
266 FileFcb
->SemihostHandle
= SemihostHandle
;
267 FileFcb
->Position
= 0;
269 FileFcb
->OpenMode
= OpenMode
;
271 Return
= SemihostFileLength (SemihostHandle
, &Length
);
272 if (RETURN_ERROR (Return
)) {
273 Status
= EFI_DEVICE_ERROR
;
278 FileFcb
->Info
.FileSize
= Length
;
279 FileFcb
->Info
.PhysicalSize
= Length
;
280 FileFcb
->Info
.Attribute
= ((OpenMode
& EFI_FILE_MODE_CREATE
) != 0) ?
283 InsertTailList (&gFileList
, &FileFcb
->Link
);
285 *NewHandle
= &FileFcb
->File
;
291 FreePool (AsciiFileName
);
297 Worker function that truncate a file specified by its name to a given size.
299 @param[in] FileName The Null-terminated string of the name of the file to be opened.
300 @param[in] Size The target size for the file.
302 @retval EFI_SUCCESS The file was truncated.
303 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
314 RETURN_STATUS Return
;
321 Status
= EFI_DEVICE_ERROR
;
325 Return
= SemihostFileOpen (
327 SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
,
330 if (RETURN_ERROR (Return
)) {
334 Buffer
= AllocatePool (Size
);
335 if (Buffer
== NULL
) {
336 Status
= EFI_OUT_OF_RESOURCES
;
342 while (Remaining
> 0) {
344 Return
= SemihostFileRead (FileHandle
, &ToRead
, Buffer
+ Read
);
345 if (RETURN_ERROR (Return
)) {
352 Return
= SemihostFileClose (FileHandle
);
354 if (RETURN_ERROR (Return
)) {
358 Return
= SemihostFileOpen (
360 SEMIHOST_FILE_MODE_WRITE
| SEMIHOST_FILE_MODE_BINARY
,
363 if (RETURN_ERROR (Return
)) {
368 Return
= SemihostFileWrite (FileHandle
, &Size
, Buffer
);
369 if (RETURN_ERROR (Return
)) {
374 Status
= EFI_SUCCESS
;
378 if (FileHandle
!= 0) {
379 SemihostFileClose (FileHandle
);
381 if (Buffer
!= NULL
) {
390 Close a specified file handle.
392 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
395 @retval EFI_SUCCESS The file was closed.
396 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
407 return EFI_INVALID_PARAMETER
;
410 Fcb
= SEMIHOST_FCB_FROM_THIS(This
);
413 SemihostFileClose (Fcb
->SemihostHandle
);
415 // The file size might have been reduced from its actual
416 // size on the host file system with FileSetInfo(). In
417 // that case, the file has to be truncated.
419 if (Fcb
->Info
.FileSize
< Fcb
->Info
.PhysicalSize
) {
420 TruncateFile (Fcb
->FileName
, Fcb
->Info
.FileSize
);
422 FreePool (Fcb
->FileName
);
431 Close and delete a file.
433 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
436 @retval EFI_SUCCESS The file was closed and deleted.
437 @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted.
438 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
447 RETURN_STATUS Return
;
452 return EFI_INVALID_PARAMETER
;
455 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
458 // Get the filename from the Fcb
459 NameSize
= AsciiStrLen (Fcb
->FileName
);
460 FileName
= AllocatePool (NameSize
+ 1);
462 AsciiStrCpyS (FileName
, NameSize
+ 1, Fcb
->FileName
);
464 // Close the file if it's open. Disregard return status,
465 // since it might give an error if the file isn't open.
468 // Call the semihost interface to delete the file.
469 Return
= SemihostFileRemove (FileName
);
470 if (RETURN_ERROR (Return
)) {
471 return EFI_WARN_DELETE_FAILURE
;
475 return EFI_WARN_DELETE_FAILURE
;
480 Read data from an open file.
482 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
483 is the file handle to read data from.
484 @param[in out] BufferSize On input, the size of the Buffer. On output, the
485 amount of data returned in Buffer. In both cases,
486 the size is measured in bytes.
487 @param[out] Buffer The buffer into which the data is read.
489 @retval EFI_SUCCESS The data was read.
490 @retval EFI_DEVICE_ERROR On entry, the current file position is
491 beyond the end of the file, or the semi-hosting
492 interface reported an error while performing the
494 @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL.
500 IN OUT UINTN
*BufferSize
,
506 RETURN_STATUS Return
;
508 if ((This
== NULL
) || (BufferSize
== NULL
) || (Buffer
== NULL
)) {
509 return EFI_INVALID_PARAMETER
;
512 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
515 // The semi-hosting interface does not allow to list files on the host machine.
516 Status
= EFI_UNSUPPORTED
;
518 Status
= EFI_SUCCESS
;
519 if (Fcb
->Position
>= Fcb
->Info
.FileSize
) {
521 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
522 Status
= EFI_DEVICE_ERROR
;
525 Return
= SemihostFileRead (Fcb
->SemihostHandle
, BufferSize
, Buffer
);
526 if (RETURN_ERROR (Return
)) {
527 Status
= EFI_DEVICE_ERROR
;
529 Fcb
->Position
+= *BufferSize
;
538 Worker function that extends the size of an open file.
540 The extension is filled with zeros.
542 @param[in] Fcb Internal description of the opened file
543 @param[in] Size The number of bytes, the file has to be extended.
545 @retval EFI_SUCCESS The file was extended.
546 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
552 IN SEMIHOST_FCB
*Fcb
,
556 RETURN_STATUS Return
;
558 CHAR8 WriteBuffer
[128];
562 Return
= SemihostFileSeek (Fcb
->SemihostHandle
, Fcb
->Info
.FileSize
);
563 if (RETURN_ERROR (Return
)) {
564 return EFI_DEVICE_ERROR
;
568 SetMem (WriteBuffer
, 0, sizeof(WriteBuffer
));
569 while (Remaining
> 0) {
570 WriteNb
= MIN (Remaining
, sizeof(WriteBuffer
));
572 Return
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, WriteBuffer
);
573 if (RETURN_ERROR (Return
)) {
574 return EFI_DEVICE_ERROR
;
576 Remaining
-= WriteNb
;
583 Write data to an open file.
585 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
586 is the file handle to write data to.
587 @param[in out] BufferSize On input, the size of the Buffer. On output, the
588 size of the data actually written. In both cases,
589 the size is measured in bytes.
590 @param[in] Buffer The buffer of data to write.
592 @retval EFI_SUCCESS The data was written.
593 @retval EFI_ACCESS_DENIED Attempt to write into a read only file or
594 in a file opened in read only mode.
595 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
596 @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL.
602 IN OUT UINTN
*BufferSize
,
609 RETURN_STATUS Return
;
612 if ((This
== NULL
) || (BufferSize
== NULL
) || (Buffer
== NULL
)) {
613 return EFI_INVALID_PARAMETER
;
616 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
618 // We cannot write a read-only file
619 if ((Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
)
620 || !(Fcb
->OpenMode
& EFI_FILE_MODE_WRITE
)) {
621 return EFI_ACCESS_DENIED
;
625 // If the position has been set past the end of the file, first grow the
626 // file from its current size "Fcb->Info.FileSize" to "Fcb->Position"
627 // size, filling the gap with zeros.
629 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
630 Status
= ExtendFile (Fcb
, Fcb
->Position
- Fcb
->Info
.FileSize
);
631 if (EFI_ERROR (Status
)) {
634 Fcb
->Info
.FileSize
= Fcb
->Position
;
637 WriteSize
= *BufferSize
;
638 Return
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, Buffer
);
639 if (RETURN_ERROR (Return
)) {
640 return EFI_DEVICE_ERROR
;
643 Fcb
->Position
+= *BufferSize
;
644 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
645 Fcb
->Info
.FileSize
= Fcb
->Position
;
648 Return
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
649 if (RETURN_ERROR (Return
)) {
650 return EFI_DEVICE_ERROR
;
652 Fcb
->Info
.PhysicalSize
= Length
;
658 Return a file's current position.
660 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
661 the file handle to get the current position on.
662 @param[out] Position The address to return the file's current position value.
664 @retval EFI_SUCCESS The position was returned.
665 @retval EFI_INVALID_PARAMETER The parameter "This" or "Position" is NULL.
676 if ((This
== NULL
) || (Position
== NULL
)) {
677 return EFI_INVALID_PARAMETER
;
680 Fcb
= SEMIHOST_FCB_FROM_THIS(This
);
682 *Position
= Fcb
->Position
;
688 Set a file's current position.
690 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
691 the file handle to set the requested position on.
692 @param[in] Position The byte position from the start of the file to set.
694 @retval EFI_SUCCESS The position was set.
695 @retval EFI_DEVICE_ERROR The semi-hosting positioning operation failed.
696 @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open
698 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
708 RETURN_STATUS Return
;
711 return EFI_INVALID_PARAMETER
;
714 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
718 return EFI_UNSUPPORTED
;
723 // UEFI Spec section 12.5:
724 // "Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to
725 // be set to the end of the file."
727 if (Position
== 0xFFFFFFFFFFFFFFFF) {
728 Position
= Fcb
->Info
.FileSize
;
730 Return
= SemihostFileSeek (Fcb
->SemihostHandle
, MIN (Position
, Fcb
->Info
.FileSize
));
731 if (RETURN_ERROR (Return
)) {
732 return EFI_DEVICE_ERROR
;
736 Fcb
->Position
= Position
;
742 Return information about a file.
744 @param[in] Fcb A pointer to the description of an open file.
745 @param[in out] BufferSize The size, in bytes, of Buffer.
746 @param[out] Buffer A pointer to the data buffer to return. Not NULL if
747 "*BufferSize" is greater than 0.
749 @retval EFI_SUCCESS The information was returned.
750 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
751 BufferSize has been updated with the size needed to
752 complete the request.
757 IN SEMIHOST_FCB
*Fcb
,
758 IN OUT UINTN
*BufferSize
,
762 EFI_FILE_INFO
*Info
= NULL
;
767 if (Fcb
->IsRoot
== TRUE
) {
768 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ sizeof(CHAR16
);
770 NameSize
= AsciiStrLen (Fcb
->FileName
) + 1;
771 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ NameSize
* sizeof (CHAR16
);
774 if (*BufferSize
< ResultSize
) {
775 *BufferSize
= ResultSize
;
776 return EFI_BUFFER_TOO_SMALL
;
781 // Copy the current file info
782 CopyMem (Info
, &Fcb
->Info
, SIZE_OF_EFI_FILE_INFO
);
784 // Fill in the structure
785 Info
->Size
= ResultSize
;
787 if (Fcb
->IsRoot
== TRUE
) {
788 Info
->FileName
[0] = L
'\0';
790 for (Index
= 0; Index
< NameSize
; Index
++) {
791 Info
->FileName
[Index
] = Fcb
->FileName
[Index
];
795 *BufferSize
= ResultSize
;
801 Return information about a file system.
803 @param[in] Fcb A pointer to the description of an open file
804 which belongs to the file system, the information
806 @param[in out] BufferSize The size, in bytes, of Buffer.
807 @param[out] Buffer A pointer to the data buffer to return. Not NULL if
808 "*BufferSize" is greater than 0.
810 @retval EFI_SUCCESS The information was returned.
811 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
812 BufferSize has been updated with the size needed to
813 complete the request.
819 IN SEMIHOST_FCB
*Fcb
,
820 IN OUT UINTN
*BufferSize
,
824 EFI_FILE_SYSTEM_INFO
*Info
;
829 StringSize
= StrSize (mSemihostFsLabel
);
830 ResultSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StringSize
;
832 if (*BufferSize
>= ResultSize
) {
833 ZeroMem (Buffer
, ResultSize
);
834 Status
= EFI_SUCCESS
;
838 Info
->Size
= ResultSize
;
839 Info
->ReadOnly
= FALSE
;
840 Info
->VolumeSize
= 0;
844 CopyMem (Info
->VolumeLabel
, mSemihostFsLabel
, StringSize
);
846 Status
= EFI_BUFFER_TOO_SMALL
;
849 *BufferSize
= ResultSize
;
854 Return information about a file or a file system.
856 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
857 is the file handle the requested information is for.
858 @param[in] InformationType The type identifier for the information being requested :
859 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
860 EFI_FILE_SYSTEM_VOLUME_LABEL_ID
861 @param[in out] BufferSize The size, in bytes, of Buffer.
862 @param[out] Buffer A pointer to the data buffer to return. The type of the
863 data inside the buffer is indicated by InformationType.
865 @retval EFI_SUCCESS The information was returned.
866 @retval EFI_UNSUPPORTED The InformationType is not known.
867 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
868 BufferSize has been updated with the size needed to
869 complete the request.
870 @retval EFI_INVALID_PARAMETER The parameter "This" or "InformationType" or "BufferSize"
871 is NULL or "Buffer" is NULL and "*Buffersize" is greater
878 IN EFI_GUID
*InformationType
,
879 IN OUT UINTN
*BufferSize
,
887 if ((This
== NULL
) ||
888 (InformationType
== NULL
) ||
889 (BufferSize
== NULL
) ||
890 ((Buffer
== NULL
) && (*BufferSize
> 0)) ) {
891 return EFI_INVALID_PARAMETER
;
894 Fcb
= SEMIHOST_FCB_FROM_THIS(This
);
896 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
897 Status
= GetFilesystemInfo (Fcb
, BufferSize
, Buffer
);
898 } else if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
899 Status
= GetFileInfo (Fcb
, BufferSize
, Buffer
);
900 } else if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
901 ResultSize
= StrSize (mSemihostFsLabel
);
903 if (*BufferSize
>= ResultSize
) {
904 CopyMem (Buffer
, mSemihostFsLabel
, ResultSize
);
905 Status
= EFI_SUCCESS
;
907 Status
= EFI_BUFFER_TOO_SMALL
;
910 *BufferSize
= ResultSize
;
912 Status
= EFI_UNSUPPORTED
;
919 Set information about a file.
921 @param[in] Fcb A pointer to the description of the open file.
922 @param[in] Info A pointer to the file information to write.
924 @retval EFI_SUCCESS The information was set.
925 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
926 to a file that is already present.
927 @retval EFI_ACCESS_DENIED An attempt is being made to change the
928 EFI_FILE_DIRECTORY Attribute.
929 @retval EFI_ACCESS_DENIED The file is a read-only file or has been
930 opened in read-only mode and an attempt is
931 being made to modify a field other than
933 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a
935 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
936 @retval EFI_OUT_OF_RESOURCES A allocation needed to process the request failed.
942 IN SEMIHOST_FCB
*Fcb
,
943 IN EFI_FILE_INFO
*Info
947 RETURN_STATUS Return
;
948 BOOLEAN FileSizeIsDifferent
;
949 BOOLEAN FileNameIsDifferent
;
950 BOOLEAN ReadOnlyIsDifferent
;
951 CHAR8
*AsciiFileName
;
954 UINTN SemihostHandle
;
957 // A directory can not be changed to a file and a file can
958 // not be changed to a directory.
960 if (((Info
->Attribute
& EFI_FILE_DIRECTORY
) != 0) != Fcb
->IsRoot
) {
961 return EFI_ACCESS_DENIED
;
964 Length
= StrLen (Info
->FileName
) + 1;
965 AsciiFileName
= AllocatePool (Length
);
966 if (AsciiFileName
== NULL
) {
967 return EFI_OUT_OF_RESOURCES
;
969 UnicodeStrToAsciiStrS (Info
->FileName
, AsciiFileName
, Length
);
971 FileSizeIsDifferent
= (Info
->FileSize
!= Fcb
->Info
.FileSize
);
972 FileNameIsDifferent
= (AsciiStrCmp (AsciiFileName
, Fcb
->FileName
) != 0);
973 ReadOnlyIsDifferent
= CompareMem (
975 &Fcb
->Info
.CreateTime
,
976 3 * sizeof (EFI_TIME
)
980 // For a read-only file or a file opened in read-only mode, only
981 // the Attribute field can be modified. As the root directory is
982 // read-only (i.e. VolumeOpen()), this protects the root directory
985 if ((Fcb
->OpenMode
== EFI_FILE_MODE_READ
) ||
986 (Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
) ) {
987 if (FileSizeIsDifferent
|| FileNameIsDifferent
|| ReadOnlyIsDifferent
) {
988 Status
= EFI_ACCESS_DENIED
;
993 if (ReadOnlyIsDifferent
) {
994 Status
= EFI_WRITE_PROTECTED
;
998 Status
= EFI_DEVICE_ERROR
;
1000 if (FileSizeIsDifferent
) {
1001 FileSize
= Info
->FileSize
;
1002 if (Fcb
->Info
.FileSize
< FileSize
) {
1003 Status
= ExtendFile (Fcb
, FileSize
- Fcb
->Info
.FileSize
);
1004 if (EFI_ERROR (Status
)) {
1008 // The read/write position from the host file system point of view
1009 // is at the end of the file. If the position from this module
1010 // point of view is smaller than the new file size, then
1011 // ask the host file system to move to that position.
1013 if (Fcb
->Position
< FileSize
) {
1014 FileSetPosition (&Fcb
->File
, Fcb
->Position
);
1017 Fcb
->Info
.FileSize
= FileSize
;
1019 Return
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
1020 if (RETURN_ERROR (Return
)) {
1023 Fcb
->Info
.PhysicalSize
= Length
;
1027 // Note down in RAM the Attribute field but we can not ask
1028 // for its modification to the host file system as the
1029 // semi-host interface does not provide this feature.
1031 Fcb
->Info
.Attribute
= Info
->Attribute
;
1033 if (FileNameIsDifferent
) {
1034 Return
= SemihostFileOpen (
1036 SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
,
1039 if (!RETURN_ERROR (Return
)) {
1040 SemihostFileClose (SemihostHandle
);
1041 Status
= EFI_ACCESS_DENIED
;
1045 Return
= SemihostFileRename (Fcb
->FileName
, AsciiFileName
);
1046 if (RETURN_ERROR (Return
)) {
1049 FreePool (Fcb
->FileName
);
1050 Fcb
->FileName
= AsciiFileName
;
1051 AsciiFileName
= NULL
;
1054 Status
= EFI_SUCCESS
;
1057 if (AsciiFileName
!= NULL
) {
1058 FreePool (AsciiFileName
);
1065 Set information about a file or a file system.
1067 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
1068 is the file handle the information is for.
1069 @param[in] InformationType The type identifier for the information being set :
1070 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
1071 EFI_FILE_SYSTEM_VOLUME_LABEL_ID
1072 @param[in] BufferSize The size, in bytes, of Buffer.
1073 @param[in] Buffer A pointer to the data buffer to write. The type of the
1074 data inside the buffer is indicated by InformationType.
1076 @retval EFI_SUCCESS The information was set.
1077 @retval EFI_UNSUPPORTED The InformationType is not known.
1078 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
1079 @retval EFI_ACCESS_DENIED An attempt is being made to change the
1080 EFI_FILE_DIRECTORY Attribute.
1081 @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and
1082 the file is a read-only file or has been
1083 opened in read-only mode and an attempt is
1084 being made to modify a field other than
1086 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
1087 to a file that is already present.
1088 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a
1089 read-only attribute.
1090 @retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by
1091 the data inside the buffer.
1092 @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request failed.
1093 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
1099 IN EFI_GUID
*InformationType
,
1100 IN UINTN BufferSize
,
1105 EFI_FILE_INFO
*Info
;
1106 EFI_FILE_SYSTEM_INFO
*SystemInfo
;
1107 CHAR16
*VolumeLabel
;
1109 if ((This
== NULL
) || (InformationType
== NULL
) || (Buffer
== NULL
)) {
1110 return EFI_INVALID_PARAMETER
;
1113 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
1115 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1117 if (Info
->Size
< (SIZE_OF_EFI_FILE_INFO
+ StrSize (Info
->FileName
))) {
1118 return EFI_INVALID_PARAMETER
;
1120 if (BufferSize
< Info
->Size
) {
1121 return EFI_BAD_BUFFER_SIZE
;
1123 return SetFileInfo (Fcb
, Info
);
1124 } else if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
1125 SystemInfo
= Buffer
;
1126 if (SystemInfo
->Size
<
1127 (SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (SystemInfo
->VolumeLabel
))) {
1128 return EFI_INVALID_PARAMETER
;
1130 if (BufferSize
< SystemInfo
->Size
) {
1131 return EFI_BAD_BUFFER_SIZE
;
1133 Buffer
= SystemInfo
->VolumeLabel
;
1135 if (StrSize (Buffer
) > 0) {
1136 VolumeLabel
= AllocateCopyPool (StrSize (Buffer
), Buffer
);
1137 if (VolumeLabel
!= NULL
) {
1138 FreePool (mSemihostFsLabel
);
1139 mSemihostFsLabel
= VolumeLabel
;
1142 return EFI_OUT_OF_RESOURCES
;
1145 return EFI_INVALID_PARAMETER
;
1147 } else if (!CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1148 return EFI_UNSUPPORTED
;
1150 return EFI_UNSUPPORTED
;
1161 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
1166 if ((Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
)
1167 || !(Fcb
->OpenMode
& EFI_FILE_MODE_WRITE
)) {
1168 return EFI_ACCESS_DENIED
;
1176 SemihostFsEntryPoint (
1177 IN EFI_HANDLE ImageHandle
,
1178 IN EFI_SYSTEM_TABLE
*SystemTable
1183 Status
= EFI_NOT_FOUND
;
1185 if (SemihostConnectionSupported ()) {
1186 mSemihostFsLabel
= AllocateCopyPool (StrSize (DEFAULT_SEMIHOST_FS_LABEL
), DEFAULT_SEMIHOST_FS_LABEL
);
1187 if (mSemihostFsLabel
== NULL
) {
1188 return EFI_OUT_OF_RESOURCES
;
1191 Status
= gBS
->InstallMultipleProtocolInterfaces (
1193 &gEfiSimpleFileSystemProtocolGuid
, &gSemihostFs
,
1194 &gEfiDevicePathProtocolGuid
, &gDevicePath
,
1198 if (EFI_ERROR(Status
)) {
1199 FreePool (mSemihostFsLabel
);