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 }
67 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
, { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 }
83 #define SEMIHOST_FCB_SIGNATURE SIGNATURE_32( 'S', 'H', 'F', 'C' )
84 #define SEMIHOST_FCB_FROM_THIS(a) CR(a, SEMIHOST_FCB, File, SEMIHOST_FCB_SIGNATURE)
85 #define SEMIHOST_FCB_FROM_LINK(a) CR(a, SEMIHOST_FCB, Link, SEMIHOST_FCB_SIGNATURE);
87 EFI_HANDLE gInstallHandle
= NULL
;
88 LIST_ENTRY gFileList
= INITIALIZE_LIST_HEAD_VARIABLE (gFileList
);
97 Fcb
= AllocateZeroPool (sizeof (SEMIHOST_FCB
));
99 CopyMem (&Fcb
->File
, &gSemihostFsFile
, sizeof (gSemihostFsFile
));
100 Fcb
->Signature
= SEMIHOST_FCB_SIGNATURE
;
111 // Remove Fcb from gFileList.
112 RemoveEntryList (&Fcb
->Link
);
114 // 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
)))
198 return EFI_INVALID_PARAMETER
;
201 if (((OpenMode
& EFI_FILE_MODE_CREATE
) != 0) &&
202 ((Attributes
& EFI_FILE_DIRECTORY
) != 0))
204 return EFI_WRITE_PROTECTED
;
207 Length
= StrLen (FileName
) + 1;
208 AsciiFileName
= AllocatePool (Length
);
209 if (AsciiFileName
== NULL
) {
210 return EFI_OUT_OF_RESOURCES
;
213 UnicodeStrToAsciiStrS (FileName
, AsciiFileName
, Length
);
215 // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
216 if ((AsciiStrCmp (AsciiFileName
, "\\") == 0) ||
217 (AsciiStrCmp (AsciiFileName
, "/") == 0) ||
218 (AsciiStrCmp (AsciiFileName
, "") == 0) ||
219 (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
;
240 Return
= SemihostFileOpen (AsciiFileName
, SemihostMode
, &SemihostHandle
);
242 if (RETURN_ERROR (Return
)) {
243 if ((OpenMode
& EFI_FILE_MODE_CREATE
) != 0) {
245 // In the create if does not exist case, if the opening in update
246 // mode failed, create it and open it in update mode. The update
247 // mode allows for both read and write from and to the file.
249 Return
= SemihostFileOpen (
251 SEMIHOST_FILE_MODE_WRITE
| SEMIHOST_FILE_MODE_BINARY
| SEMIHOST_FILE_MODE_UPDATE
,
254 if (RETURN_ERROR (Return
)) {
255 Status
= EFI_DEVICE_ERROR
;
259 Status
= EFI_NOT_FOUND
;
264 // Allocate a control block and fill it
265 FileFcb
= AllocateFCB ();
266 if (FileFcb
== NULL
) {
267 Status
= EFI_OUT_OF_RESOURCES
;
271 FileFcb
->FileName
= AsciiFileName
;
272 FileFcb
->SemihostHandle
= SemihostHandle
;
273 FileFcb
->Position
= 0;
275 FileFcb
->OpenMode
= OpenMode
;
277 Return
= SemihostFileLength (SemihostHandle
, &Length
);
278 if (RETURN_ERROR (Return
)) {
279 Status
= EFI_DEVICE_ERROR
;
284 FileFcb
->Info
.FileSize
= Length
;
285 FileFcb
->Info
.PhysicalSize
= Length
;
286 FileFcb
->Info
.Attribute
= ((OpenMode
& EFI_FILE_MODE_CREATE
) != 0) ?
289 InsertTailList (&gFileList
, &FileFcb
->Link
);
291 *NewHandle
= &FileFcb
->File
;
297 FreePool (AsciiFileName
);
303 Worker function that truncate a file specified by its name to a given size.
305 @param[in] FileName The Null-terminated string of the name of the file to be opened.
306 @param[in] Size The target size for the file.
308 @retval EFI_SUCCESS The file was truncated.
309 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
320 RETURN_STATUS Return
;
327 Status
= EFI_DEVICE_ERROR
;
331 Return
= SemihostFileOpen (
333 SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
,
336 if (RETURN_ERROR (Return
)) {
340 Buffer
= AllocatePool (Size
);
341 if (Buffer
== NULL
) {
342 Status
= EFI_OUT_OF_RESOURCES
;
348 while (Remaining
> 0) {
350 Return
= SemihostFileRead (FileHandle
, &ToRead
, Buffer
+ Read
);
351 if (RETURN_ERROR (Return
)) {
359 Return
= SemihostFileClose (FileHandle
);
361 if (RETURN_ERROR (Return
)) {
365 Return
= SemihostFileOpen (
367 SEMIHOST_FILE_MODE_WRITE
| SEMIHOST_FILE_MODE_BINARY
,
370 if (RETURN_ERROR (Return
)) {
375 Return
= SemihostFileWrite (FileHandle
, &Size
, Buffer
);
376 if (RETURN_ERROR (Return
)) {
381 Status
= EFI_SUCCESS
;
385 if (FileHandle
!= 0) {
386 SemihostFileClose (FileHandle
);
389 if (Buffer
!= NULL
) {
397 Close a specified file handle.
399 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
402 @retval EFI_SUCCESS The file was closed.
403 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
414 return EFI_INVALID_PARAMETER
;
417 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
420 SemihostFileClose (Fcb
->SemihostHandle
);
422 // The file size might have been reduced from its actual
423 // size on the host file system with FileSetInfo(). In
424 // that case, the file has to be truncated.
426 if (Fcb
->Info
.FileSize
< Fcb
->Info
.PhysicalSize
) {
427 TruncateFile (Fcb
->FileName
, Fcb
->Info
.FileSize
);
430 FreePool (Fcb
->FileName
);
439 Close and delete a file.
441 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
444 @retval EFI_SUCCESS The file was closed and deleted.
445 @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted.
446 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
455 RETURN_STATUS Return
;
460 return EFI_INVALID_PARAMETER
;
463 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
466 // Get the filename from the Fcb
467 NameSize
= AsciiStrLen (Fcb
->FileName
);
468 FileName
= AllocatePool (NameSize
+ 1);
470 AsciiStrCpyS (FileName
, NameSize
+ 1, Fcb
->FileName
);
472 // Close the file if it's open. Disregard return status,
473 // since it might give an error if the file isn't open.
476 // Call the semihost interface to delete the file.
477 Return
= SemihostFileRemove (FileName
);
478 if (RETURN_ERROR (Return
)) {
479 return EFI_WARN_DELETE_FAILURE
;
484 return EFI_WARN_DELETE_FAILURE
;
489 Read data from an open file.
491 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
492 is the file handle to read data from.
493 @param[in out] BufferSize On input, the size of the Buffer. On output, the
494 amount of data returned in Buffer. In both cases,
495 the size is measured in bytes.
496 @param[out] Buffer The buffer into which the data is read.
498 @retval EFI_SUCCESS The data was read.
499 @retval EFI_DEVICE_ERROR On entry, the current file position is
500 beyond the end of the file, or the semi-hosting
501 interface reported an error while performing the
503 @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL.
509 IN OUT UINTN
*BufferSize
,
515 RETURN_STATUS Return
;
517 if ((This
== NULL
) || (BufferSize
== NULL
) || (Buffer
== NULL
)) {
518 return EFI_INVALID_PARAMETER
;
521 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
524 // The semi-hosting interface does not allow to list files on the host machine.
525 Status
= EFI_UNSUPPORTED
;
527 Status
= EFI_SUCCESS
;
528 if (Fcb
->Position
>= Fcb
->Info
.FileSize
) {
530 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
531 Status
= EFI_DEVICE_ERROR
;
534 Return
= SemihostFileRead (Fcb
->SemihostHandle
, BufferSize
, Buffer
);
535 if (RETURN_ERROR (Return
)) {
536 Status
= EFI_DEVICE_ERROR
;
538 Fcb
->Position
+= *BufferSize
;
547 Worker function that extends the size of an open file.
549 The extension is filled with zeros.
551 @param[in] Fcb Internal description of the opened file
552 @param[in] Size The number of bytes, the file has to be extended.
554 @retval EFI_SUCCESS The file was extended.
555 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
561 IN SEMIHOST_FCB
*Fcb
,
565 RETURN_STATUS Return
;
567 CHAR8 WriteBuffer
[128];
571 Return
= SemihostFileSeek (Fcb
->SemihostHandle
, Fcb
->Info
.FileSize
);
572 if (RETURN_ERROR (Return
)) {
573 return EFI_DEVICE_ERROR
;
577 SetMem (WriteBuffer
, 0, sizeof (WriteBuffer
));
578 while (Remaining
> 0) {
579 WriteNb
= MIN (Remaining
, sizeof (WriteBuffer
));
581 Return
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, WriteBuffer
);
582 if (RETURN_ERROR (Return
)) {
583 return EFI_DEVICE_ERROR
;
586 Remaining
-= WriteNb
;
593 Write data to an open file.
595 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
596 is the file handle to write data to.
597 @param[in out] BufferSize On input, the size of the Buffer. On output, the
598 size of the data actually written. In both cases,
599 the size is measured in bytes.
600 @param[in] Buffer The buffer of data to write.
602 @retval EFI_SUCCESS The data was written.
603 @retval EFI_ACCESS_DENIED Attempt to write into a read only file or
604 in a file opened in read only mode.
605 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
606 @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL.
612 IN OUT UINTN
*BufferSize
,
619 RETURN_STATUS Return
;
622 if ((This
== NULL
) || (BufferSize
== NULL
) || (Buffer
== NULL
)) {
623 return EFI_INVALID_PARAMETER
;
626 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
628 // We cannot write a read-only file
629 if ( (Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
)
630 || !(Fcb
->OpenMode
& EFI_FILE_MODE_WRITE
))
632 return EFI_ACCESS_DENIED
;
636 // If the position has been set past the end of the file, first grow the
637 // file from its current size "Fcb->Info.FileSize" to "Fcb->Position"
638 // size, filling the gap with zeros.
640 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
641 Status
= ExtendFile (Fcb
, Fcb
->Position
- Fcb
->Info
.FileSize
);
642 if (EFI_ERROR (Status
)) {
646 Fcb
->Info
.FileSize
= Fcb
->Position
;
649 WriteSize
= *BufferSize
;
650 Return
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, Buffer
);
651 if (RETURN_ERROR (Return
)) {
652 return EFI_DEVICE_ERROR
;
655 Fcb
->Position
+= *BufferSize
;
656 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
657 Fcb
->Info
.FileSize
= Fcb
->Position
;
660 Return
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
661 if (RETURN_ERROR (Return
)) {
662 return EFI_DEVICE_ERROR
;
665 Fcb
->Info
.PhysicalSize
= Length
;
671 Return a file's current position.
673 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
674 the file handle to get the current position on.
675 @param[out] Position The address to return the file's current position value.
677 @retval EFI_SUCCESS The position was returned.
678 @retval EFI_INVALID_PARAMETER The parameter "This" or "Position" is NULL.
689 if ((This
== NULL
) || (Position
== NULL
)) {
690 return EFI_INVALID_PARAMETER
;
693 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
695 *Position
= Fcb
->Position
;
701 Set a file's current position.
703 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
704 the file handle to set the requested position on.
705 @param[in] Position The byte position from the start of the file to set.
707 @retval EFI_SUCCESS The position was set.
708 @retval EFI_DEVICE_ERROR The semi-hosting positioning operation failed.
709 @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open
711 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
721 RETURN_STATUS Return
;
724 return EFI_INVALID_PARAMETER
;
727 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
731 return EFI_UNSUPPORTED
;
735 // UEFI Spec section 12.5:
736 // "Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to
737 // be set to the end of the file."
739 if (Position
== 0xFFFFFFFFFFFFFFFF) {
740 Position
= Fcb
->Info
.FileSize
;
743 Return
= SemihostFileSeek (Fcb
->SemihostHandle
, MIN (Position
, Fcb
->Info
.FileSize
));
744 if (RETURN_ERROR (Return
)) {
745 return EFI_DEVICE_ERROR
;
749 Fcb
->Position
= Position
;
755 Return information about a file.
757 @param[in] Fcb A pointer to the description of an open file.
758 @param[in out] BufferSize The size, in bytes, of Buffer.
759 @param[out] Buffer A pointer to the data buffer to return. Not NULL if
760 "*BufferSize" is greater than 0.
762 @retval EFI_SUCCESS The information was returned.
763 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
764 BufferSize has been updated with the size needed to
765 complete the request.
770 IN SEMIHOST_FCB
*Fcb
,
771 IN OUT UINTN
*BufferSize
,
782 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ sizeof (CHAR16
);
784 NameSize
= AsciiStrLen (Fcb
->FileName
) + 1;
785 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ NameSize
* sizeof (CHAR16
);
788 if (*BufferSize
< ResultSize
) {
789 *BufferSize
= ResultSize
;
790 return EFI_BUFFER_TOO_SMALL
;
795 // Copy the current file info
796 CopyMem (Info
, &Fcb
->Info
, SIZE_OF_EFI_FILE_INFO
);
798 // Fill in the structure
799 Info
->Size
= ResultSize
;
802 Info
->FileName
[0] = L
'\0';
804 for (Index
= 0; Index
< NameSize
; Index
++) {
805 Info
->FileName
[Index
] = Fcb
->FileName
[Index
];
809 *BufferSize
= ResultSize
;
815 Return information about a file system.
817 @param[in] Fcb A pointer to the description of an open file
818 which belongs to the file system, the information
820 @param[in out] BufferSize The size, in bytes, of Buffer.
821 @param[out] Buffer A pointer to the data buffer to return. Not NULL if
822 "*BufferSize" is greater than 0.
824 @retval EFI_SUCCESS The information was returned.
825 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
826 BufferSize has been updated with the size needed to
827 complete the request.
833 IN SEMIHOST_FCB
*Fcb
,
834 IN OUT UINTN
*BufferSize
,
838 EFI_FILE_SYSTEM_INFO
*Info
;
843 StringSize
= StrSize (mSemihostFsLabel
);
844 ResultSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StringSize
;
846 if (*BufferSize
>= ResultSize
) {
847 ZeroMem (Buffer
, ResultSize
);
848 Status
= EFI_SUCCESS
;
852 Info
->Size
= ResultSize
;
853 Info
->ReadOnly
= FALSE
;
854 Info
->VolumeSize
= 0;
858 CopyMem (Info
->VolumeLabel
, mSemihostFsLabel
, StringSize
);
860 Status
= EFI_BUFFER_TOO_SMALL
;
863 *BufferSize
= ResultSize
;
868 Return information about a file or a file system.
870 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
871 is the file handle the requested information is for.
872 @param[in] InformationType The type identifier for the information being requested :
873 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
874 EFI_FILE_SYSTEM_VOLUME_LABEL_ID
875 @param[in out] BufferSize The size, in bytes, of Buffer.
876 @param[out] Buffer A pointer to the data buffer to return. The type of the
877 data inside the buffer is indicated by InformationType.
879 @retval EFI_SUCCESS The information was returned.
880 @retval EFI_UNSUPPORTED The InformationType is not known.
881 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
882 BufferSize has been updated with the size needed to
883 complete the request.
884 @retval EFI_INVALID_PARAMETER The parameter "This" or "InformationType" or "BufferSize"
885 is NULL or "Buffer" is NULL and "*Buffersize" is greater
892 IN EFI_GUID
*InformationType
,
893 IN OUT UINTN
*BufferSize
,
901 if ((This
== NULL
) ||
902 (InformationType
== NULL
) ||
903 (BufferSize
== NULL
) ||
904 ((Buffer
== NULL
) && (*BufferSize
> 0)))
906 return EFI_INVALID_PARAMETER
;
909 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
911 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
912 Status
= GetFilesystemInfo (Fcb
, BufferSize
, Buffer
);
913 } else if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
914 Status
= GetFileInfo (Fcb
, BufferSize
, Buffer
);
915 } else if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
916 ResultSize
= StrSize (mSemihostFsLabel
);
918 if (*BufferSize
>= ResultSize
) {
919 CopyMem (Buffer
, mSemihostFsLabel
, ResultSize
);
920 Status
= EFI_SUCCESS
;
922 Status
= EFI_BUFFER_TOO_SMALL
;
925 *BufferSize
= ResultSize
;
927 Status
= EFI_UNSUPPORTED
;
934 Set information about a file.
936 @param[in] Fcb A pointer to the description of the open file.
937 @param[in] Info A pointer to the file information to write.
939 @retval EFI_SUCCESS The information was set.
940 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
941 to a file that is already present.
942 @retval EFI_ACCESS_DENIED An attempt is being made to change the
943 EFI_FILE_DIRECTORY Attribute.
944 @retval EFI_ACCESS_DENIED The file is a read-only file or has been
945 opened in read-only mode and an attempt is
946 being made to modify a field other than
948 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a
950 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
951 @retval EFI_OUT_OF_RESOURCES A allocation needed to process the request failed.
957 IN SEMIHOST_FCB
*Fcb
,
958 IN EFI_FILE_INFO
*Info
962 RETURN_STATUS Return
;
963 BOOLEAN FileSizeIsDifferent
;
964 BOOLEAN FileNameIsDifferent
;
965 BOOLEAN ReadOnlyIsDifferent
;
966 CHAR8
*AsciiFileName
;
969 UINTN SemihostHandle
;
972 // A directory can not be changed to a file and a file can
973 // not be changed to a directory.
975 if (((Info
->Attribute
& EFI_FILE_DIRECTORY
) != 0) != Fcb
->IsRoot
) {
976 return EFI_ACCESS_DENIED
;
979 Length
= StrLen (Info
->FileName
) + 1;
980 AsciiFileName
= AllocatePool (Length
);
981 if (AsciiFileName
== NULL
) {
982 return EFI_OUT_OF_RESOURCES
;
985 UnicodeStrToAsciiStrS (Info
->FileName
, AsciiFileName
, Length
);
987 FileSizeIsDifferent
= (Info
->FileSize
!= Fcb
->Info
.FileSize
);
988 FileNameIsDifferent
= (AsciiStrCmp (AsciiFileName
, Fcb
->FileName
) != 0);
989 ReadOnlyIsDifferent
= CompareMem (
991 &Fcb
->Info
.CreateTime
,
992 3 * sizeof (EFI_TIME
)
996 // For a read-only file or a file opened in read-only mode, only
997 // the Attribute field can be modified. As the root directory is
998 // read-only (i.e. VolumeOpen()), this protects the root directory
1001 if ((Fcb
->OpenMode
== EFI_FILE_MODE_READ
) ||
1002 (Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
))
1004 if (FileSizeIsDifferent
|| FileNameIsDifferent
|| ReadOnlyIsDifferent
) {
1005 Status
= EFI_ACCESS_DENIED
;
1010 if (ReadOnlyIsDifferent
) {
1011 Status
= EFI_WRITE_PROTECTED
;
1015 Status
= EFI_DEVICE_ERROR
;
1017 if (FileSizeIsDifferent
) {
1018 FileSize
= Info
->FileSize
;
1019 if (Fcb
->Info
.FileSize
< FileSize
) {
1020 Status
= ExtendFile (Fcb
, FileSize
- Fcb
->Info
.FileSize
);
1021 if (EFI_ERROR (Status
)) {
1026 // The read/write position from the host file system point of view
1027 // is at the end of the file. If the position from this module
1028 // point of view is smaller than the new file size, then
1029 // ask the host file system to move to that position.
1031 if (Fcb
->Position
< FileSize
) {
1032 FileSetPosition (&Fcb
->File
, Fcb
->Position
);
1036 Fcb
->Info
.FileSize
= FileSize
;
1038 Return
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
1039 if (RETURN_ERROR (Return
)) {
1043 Fcb
->Info
.PhysicalSize
= Length
;
1047 // Note down in RAM the Attribute field but we can not ask
1048 // for its modification to the host file system as the
1049 // semi-host interface does not provide this feature.
1051 Fcb
->Info
.Attribute
= Info
->Attribute
;
1053 if (FileNameIsDifferent
) {
1054 Return
= SemihostFileOpen (
1056 SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
,
1059 if (!RETURN_ERROR (Return
)) {
1060 SemihostFileClose (SemihostHandle
);
1061 Status
= EFI_ACCESS_DENIED
;
1065 Return
= SemihostFileRename (Fcb
->FileName
, AsciiFileName
);
1066 if (RETURN_ERROR (Return
)) {
1070 FreePool (Fcb
->FileName
);
1071 Fcb
->FileName
= AsciiFileName
;
1072 AsciiFileName
= NULL
;
1075 Status
= EFI_SUCCESS
;
1078 if (AsciiFileName
!= NULL
) {
1079 FreePool (AsciiFileName
);
1086 Set information about a file or a file system.
1088 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
1089 is the file handle the information is for.
1090 @param[in] InformationType The type identifier for the information being set :
1091 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
1092 EFI_FILE_SYSTEM_VOLUME_LABEL_ID
1093 @param[in] BufferSize The size, in bytes, of Buffer.
1094 @param[in] Buffer A pointer to the data buffer to write. The type of the
1095 data inside the buffer is indicated by InformationType.
1097 @retval EFI_SUCCESS The information was set.
1098 @retval EFI_UNSUPPORTED The InformationType is not known.
1099 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
1100 @retval EFI_ACCESS_DENIED An attempt is being made to change the
1101 EFI_FILE_DIRECTORY Attribute.
1102 @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and
1103 the file is a read-only file or has been
1104 opened in read-only mode and an attempt is
1105 being made to modify a field other than
1107 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
1108 to a file that is already present.
1109 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a
1110 read-only attribute.
1111 @retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by
1112 the data inside the buffer.
1113 @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request failed.
1114 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
1120 IN EFI_GUID
*InformationType
,
1121 IN UINTN BufferSize
,
1126 EFI_FILE_INFO
*Info
;
1127 EFI_FILE_SYSTEM_INFO
*SystemInfo
;
1128 CHAR16
*VolumeLabel
;
1130 if ((This
== NULL
) || (InformationType
== NULL
) || (Buffer
== NULL
)) {
1131 return EFI_INVALID_PARAMETER
;
1134 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
1136 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1138 if (Info
->Size
< (SIZE_OF_EFI_FILE_INFO
+ StrSize (Info
->FileName
))) {
1139 return EFI_INVALID_PARAMETER
;
1142 if (BufferSize
< Info
->Size
) {
1143 return EFI_BAD_BUFFER_SIZE
;
1146 return SetFileInfo (Fcb
, Info
);
1147 } else if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
1148 SystemInfo
= Buffer
;
1149 if (SystemInfo
->Size
<
1150 (SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (SystemInfo
->VolumeLabel
)))
1152 return EFI_INVALID_PARAMETER
;
1155 if (BufferSize
< SystemInfo
->Size
) {
1156 return EFI_BAD_BUFFER_SIZE
;
1159 Buffer
= SystemInfo
->VolumeLabel
;
1161 if (StrSize (Buffer
) > 0) {
1162 VolumeLabel
= AllocateCopyPool (StrSize (Buffer
), Buffer
);
1163 if (VolumeLabel
!= NULL
) {
1164 FreePool (mSemihostFsLabel
);
1165 mSemihostFsLabel
= VolumeLabel
;
1168 return EFI_OUT_OF_RESOURCES
;
1171 return EFI_INVALID_PARAMETER
;
1173 } else if (!CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1174 return EFI_UNSUPPORTED
;
1176 return EFI_UNSUPPORTED
;
1187 Fcb
= SEMIHOST_FCB_FROM_THIS (File
);
1192 if ( (Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
)
1193 || !(Fcb
->OpenMode
& EFI_FILE_MODE_WRITE
))
1195 return EFI_ACCESS_DENIED
;
1203 SemihostFsEntryPoint (
1204 IN EFI_HANDLE ImageHandle
,
1205 IN EFI_SYSTEM_TABLE
*SystemTable
1210 Status
= EFI_NOT_FOUND
;
1212 if (SemihostConnectionSupported ()) {
1213 mSemihostFsLabel
= AllocateCopyPool (StrSize (DEFAULT_SEMIHOST_FS_LABEL
), DEFAULT_SEMIHOST_FS_LABEL
);
1214 if (mSemihostFsLabel
== NULL
) {
1215 return EFI_OUT_OF_RESOURCES
;
1218 Status
= gBS
->InstallMultipleProtocolInterfaces (
1220 &gEfiSimpleFileSystemProtocolGuid
,
1222 &gEfiDevicePathProtocolGuid
,
1227 if (EFI_ERROR (Status
)) {
1228 FreePool (mSemihostFsLabel
);