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 Length
= StrLen (FileName
) + 1;
211 AsciiFileName
= AllocatePool (Length
);
212 if (AsciiFileName
== NULL
) {
213 return EFI_OUT_OF_RESOURCES
;
215 UnicodeStrToAsciiStrS (FileName
, AsciiFileName
, Length
);
217 // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
218 if ((AsciiStrCmp (AsciiFileName
, "\\") == 0) ||
219 (AsciiStrCmp (AsciiFileName
, "/") == 0) ||
220 (AsciiStrCmp (AsciiFileName
, "") == 0) ||
221 (AsciiStrCmp (AsciiFileName
, ".") == 0) ) {
222 FreePool (AsciiFileName
);
223 return (VolumeOpen (&gSemihostFs
, NewHandle
));
227 // No control is done here concerning the file path. It is passed
228 // as it is to the host operating system through the semi-hosting
229 // interface. We first try to open the file in the read or update
230 // mode even if the file creation has been asked for. That way, if
231 // the file already exists, it is not truncated to zero length. In
232 // write mode (bit SEMIHOST_FILE_MODE_WRITE up), if the file already
233 // exists, it is reset to an empty file.
235 if (OpenMode
== EFI_FILE_MODE_READ
) {
236 SemihostMode
= SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
;
238 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
) {
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
) ? Attributes
: 0;
288 InsertTailList (&gFileList
, &FileFcb
->Link
);
290 *NewHandle
= &FileFcb
->File
;
296 FreePool (AsciiFileName
);
302 Worker function that truncate a file specified by its name to a given size.
304 @param[in] FileName The Null-terminated string of the name of the file to be opened.
305 @param[in] Size The target size for the file.
307 @retval EFI_SUCCESS The file was truncated.
308 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
319 RETURN_STATUS Return
;
326 Status
= EFI_DEVICE_ERROR
;
330 Return
= SemihostFileOpen (
332 SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
,
335 if (RETURN_ERROR (Return
)) {
339 Buffer
= AllocatePool (Size
);
340 if (Buffer
== NULL
) {
341 Status
= EFI_OUT_OF_RESOURCES
;
347 while (Remaining
> 0) {
349 Return
= SemihostFileRead (FileHandle
, &ToRead
, Buffer
+ Read
);
350 if (RETURN_ERROR (Return
)) {
357 Return
= SemihostFileClose (FileHandle
);
359 if (RETURN_ERROR (Return
)) {
363 Return
= SemihostFileOpen (
365 SEMIHOST_FILE_MODE_WRITE
| SEMIHOST_FILE_MODE_BINARY
,
368 if (RETURN_ERROR (Return
)) {
373 Return
= SemihostFileWrite (FileHandle
, &Size
, Buffer
);
374 if (RETURN_ERROR (Return
)) {
379 Status
= EFI_SUCCESS
;
383 if (FileHandle
!= 0) {
384 SemihostFileClose (FileHandle
);
386 if (Buffer
!= NULL
) {
395 Close a specified file handle.
397 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
400 @retval EFI_SUCCESS The file was closed.
401 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
412 return EFI_INVALID_PARAMETER
;
415 Fcb
= SEMIHOST_FCB_FROM_THIS(This
);
418 SemihostFileClose (Fcb
->SemihostHandle
);
420 // The file size might have been reduced from its actual
421 // size on the host file system with FileSetInfo(). In
422 // that case, the file has to be truncated.
424 if (Fcb
->Info
.FileSize
< Fcb
->Info
.PhysicalSize
) {
425 TruncateFile (Fcb
->FileName
, Fcb
->Info
.FileSize
);
427 FreePool (Fcb
->FileName
);
436 Close and delete a file.
438 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
441 @retval EFI_SUCCESS The file was closed and deleted.
442 @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted.
443 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
452 RETURN_STATUS Return
;
457 return EFI_INVALID_PARAMETER
;
460 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
463 // Get the filename from the Fcb
464 NameSize
= AsciiStrLen (Fcb
->FileName
);
465 FileName
= AllocatePool (NameSize
+ 1);
467 AsciiStrCpyS (FileName
, NameSize
+ 1, Fcb
->FileName
);
469 // Close the file if it's open. Disregard return status,
470 // since it might give an error if the file isn't open.
473 // Call the semihost interface to delete the file.
474 Return
= SemihostFileRemove (FileName
);
475 if (RETURN_ERROR (Return
)) {
476 return EFI_WARN_DELETE_FAILURE
;
480 return EFI_WARN_DELETE_FAILURE
;
485 Read data from an open file.
487 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
488 is the file handle to read data from.
489 @param[in out] BufferSize On input, the size of the Buffer. On output, the
490 amount of data returned in Buffer. In both cases,
491 the size is measured in bytes.
492 @param[out] Buffer The buffer into which the data is read.
494 @retval EFI_SUCCESS The data was read.
495 @retval EFI_DEVICE_ERROR On entry, the current file position is
496 beyond the end of the file, or the semi-hosting
497 interface reported an error while performing the
499 @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL.
505 IN OUT UINTN
*BufferSize
,
511 RETURN_STATUS Return
;
513 if ((This
== NULL
) || (BufferSize
== NULL
) || (Buffer
== NULL
)) {
514 return EFI_INVALID_PARAMETER
;
517 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
520 // The semi-hosting interface does not allow to list files on the host machine.
521 Status
= EFI_UNSUPPORTED
;
523 Status
= EFI_SUCCESS
;
524 if (Fcb
->Position
>= Fcb
->Info
.FileSize
) {
526 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
527 Status
= EFI_DEVICE_ERROR
;
530 Return
= SemihostFileRead (Fcb
->SemihostHandle
, BufferSize
, Buffer
);
531 if (RETURN_ERROR (Return
)) {
532 Status
= EFI_DEVICE_ERROR
;
534 Fcb
->Position
+= *BufferSize
;
543 Worker function that extends the size of an open file.
545 The extension is filled with zeros.
547 @param[in] Fcb Internal description of the opened file
548 @param[in] Size The number of bytes, the file has to be extended.
550 @retval EFI_SUCCESS The file was extended.
551 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
557 IN SEMIHOST_FCB
*Fcb
,
561 RETURN_STATUS Return
;
563 CHAR8 WriteBuffer
[128];
567 Return
= SemihostFileSeek (Fcb
->SemihostHandle
, Fcb
->Info
.FileSize
);
568 if (RETURN_ERROR (Return
)) {
569 return EFI_DEVICE_ERROR
;
573 SetMem (WriteBuffer
, 0, sizeof(WriteBuffer
));
574 while (Remaining
> 0) {
575 WriteNb
= MIN (Remaining
, sizeof(WriteBuffer
));
577 Return
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, WriteBuffer
);
578 if (RETURN_ERROR (Return
)) {
579 return EFI_DEVICE_ERROR
;
581 Remaining
-= WriteNb
;
588 Write data to an open file.
590 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
591 is the file handle to write data to.
592 @param[in out] BufferSize On input, the size of the Buffer. On output, the
593 size of the data actually written. In both cases,
594 the size is measured in bytes.
595 @param[in] Buffer The buffer of data to write.
597 @retval EFI_SUCCESS The data was written.
598 @retval EFI_ACCESS_DENIED Attempt to write into a read only file or
599 in a file opened in read only mode.
600 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
601 @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL.
607 IN OUT UINTN
*BufferSize
,
614 RETURN_STATUS Return
;
617 if ((This
== NULL
) || (BufferSize
== NULL
) || (Buffer
== NULL
)) {
618 return EFI_INVALID_PARAMETER
;
621 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
623 // We cannot write a read-only file
624 if ((Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
)
625 || !(Fcb
->OpenMode
& EFI_FILE_MODE_WRITE
)) {
626 return EFI_ACCESS_DENIED
;
630 // If the position has been set past the end of the file, first grow the
631 // file from its current size "Fcb->Info.FileSize" to "Fcb->Position"
632 // size, filling the gap with zeros.
634 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
635 Status
= ExtendFile (Fcb
, Fcb
->Position
- Fcb
->Info
.FileSize
);
636 if (EFI_ERROR (Status
)) {
639 Fcb
->Info
.FileSize
= Fcb
->Position
;
642 WriteSize
= *BufferSize
;
643 Return
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, Buffer
);
644 if (RETURN_ERROR (Return
)) {
645 return EFI_DEVICE_ERROR
;
648 Fcb
->Position
+= *BufferSize
;
649 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
650 Fcb
->Info
.FileSize
= Fcb
->Position
;
653 Return
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
654 if (RETURN_ERROR (Return
)) {
655 return EFI_DEVICE_ERROR
;
657 Fcb
->Info
.PhysicalSize
= Length
;
663 Return a file's current position.
665 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
666 the file handle to get the current position on.
667 @param[out] Position The address to return the file's current position value.
669 @retval EFI_SUCCESS The position was returned.
670 @retval EFI_INVALID_PARAMETER The parameter "This" or "Position" is NULL.
681 if ((This
== NULL
) || (Position
== NULL
)) {
682 return EFI_INVALID_PARAMETER
;
685 Fcb
= SEMIHOST_FCB_FROM_THIS(This
);
687 *Position
= Fcb
->Position
;
693 Set a file's current position.
695 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
696 the file handle to set the requested position on.
697 @param[in] Position The byte position from the start of the file to set.
699 @retval EFI_SUCCESS The position was set.
700 @retval EFI_DEVICE_ERROR The semi-hosting positionning operation failed.
701 @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open
703 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
713 RETURN_STATUS Return
;
716 return EFI_INVALID_PARAMETER
;
719 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
723 return EFI_UNSUPPORTED
;
728 // UEFI Spec section 12.5:
729 // "Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to
730 // be set to the end of the file."
732 if (Position
== 0xFFFFFFFFFFFFFFFF) {
733 Position
= Fcb
->Info
.FileSize
;
735 Return
= SemihostFileSeek (Fcb
->SemihostHandle
, MIN (Position
, Fcb
->Info
.FileSize
));
736 if (RETURN_ERROR (Return
)) {
737 return EFI_DEVICE_ERROR
;
741 Fcb
->Position
= Position
;
747 Return information about a file.
749 @param[in] Fcb A pointer to the description of an open file.
750 @param[in out] BufferSize The size, in bytes, of Buffer.
751 @param[out] Buffer A pointer to the data buffer to return. Not NULL if
752 "*BufferSize" is greater than 0.
754 @retval EFI_SUCCESS The information was returned.
755 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
756 BufferSize has been updated with the size needed to
757 complete the request.
762 IN SEMIHOST_FCB
*Fcb
,
763 IN OUT UINTN
*BufferSize
,
767 EFI_FILE_INFO
*Info
= NULL
;
772 if (Fcb
->IsRoot
== TRUE
) {
773 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ sizeof(CHAR16
);
775 NameSize
= AsciiStrLen (Fcb
->FileName
) + 1;
776 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ NameSize
* sizeof (CHAR16
);
779 if (*BufferSize
< ResultSize
) {
780 *BufferSize
= ResultSize
;
781 return EFI_BUFFER_TOO_SMALL
;
786 // Copy the current file info
787 CopyMem (Info
, &Fcb
->Info
, SIZE_OF_EFI_FILE_INFO
);
789 // Fill in the structure
790 Info
->Size
= ResultSize
;
792 if (Fcb
->IsRoot
== TRUE
) {
793 Info
->FileName
[0] = L
'\0';
795 for (Index
= 0; Index
< NameSize
; Index
++) {
796 Info
->FileName
[Index
] = Fcb
->FileName
[Index
];
800 *BufferSize
= ResultSize
;
806 Return information about a file system.
808 @param[in] Fcb A pointer to the description of an open file
809 which belongs to the file system, the information
811 @param[in out] BufferSize The size, in bytes, of Buffer.
812 @param[out] Buffer A pointer to the data buffer to return. Not NULL if
813 "*BufferSize" is greater than 0.
815 @retval EFI_SUCCESS The information was returned.
816 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
817 BufferSize has been updated with the size needed to
818 complete the request.
824 IN SEMIHOST_FCB
*Fcb
,
825 IN OUT UINTN
*BufferSize
,
829 EFI_FILE_SYSTEM_INFO
*Info
;
834 StringSize
= StrSize (mSemihostFsLabel
);
835 ResultSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StringSize
;
837 if (*BufferSize
>= ResultSize
) {
838 ZeroMem (Buffer
, ResultSize
);
839 Status
= EFI_SUCCESS
;
843 Info
->Size
= ResultSize
;
844 Info
->ReadOnly
= FALSE
;
845 Info
->VolumeSize
= 0;
849 CopyMem (Info
->VolumeLabel
, mSemihostFsLabel
, StringSize
);
851 Status
= EFI_BUFFER_TOO_SMALL
;
854 *BufferSize
= ResultSize
;
859 Return information about a file or a file system.
861 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
862 is the file handle the requested information is for.
863 @param[in] InformationType The type identifier for the information being requested :
864 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
865 EFI_FILE_SYSTEM_VOLUME_LABEL_ID
866 @param[in out] BufferSize The size, in bytes, of Buffer.
867 @param[out] Buffer A pointer to the data buffer to return. The type of the
868 data inside the buffer is indicated by InformationType.
870 @retval EFI_SUCCESS The information was returned.
871 @retval EFI_UNSUPPORTED The InformationType is not known.
872 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
873 BufferSize has been updated with the size needed to
874 complete the request.
875 @retval EFI_INVALID_PARAMETER The parameter "This" or "InformationType" or "BufferSize"
876 is NULL or "Buffer" is NULL and "*Buffersize" is greater
883 IN EFI_GUID
*InformationType
,
884 IN OUT UINTN
*BufferSize
,
892 if ((This
== NULL
) ||
893 (InformationType
== NULL
) ||
894 (BufferSize
== NULL
) ||
895 ((Buffer
== NULL
) && (*BufferSize
> 0)) ) {
896 return EFI_INVALID_PARAMETER
;
899 Fcb
= SEMIHOST_FCB_FROM_THIS(This
);
901 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
902 Status
= GetFilesystemInfo (Fcb
, BufferSize
, Buffer
);
903 } else if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
904 Status
= GetFileInfo (Fcb
, BufferSize
, Buffer
);
905 } else if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
906 ResultSize
= StrSize (mSemihostFsLabel
);
908 if (*BufferSize
>= ResultSize
) {
909 CopyMem (Buffer
, mSemihostFsLabel
, ResultSize
);
910 Status
= EFI_SUCCESS
;
912 Status
= EFI_BUFFER_TOO_SMALL
;
915 *BufferSize
= ResultSize
;
917 Status
= EFI_UNSUPPORTED
;
924 Set information about a file.
926 @param[in] Fcb A pointer to the description of the open file.
927 @param[in] Info A pointer to the file information to write.
929 @retval EFI_SUCCESS The information was set.
930 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
931 to a file that is already present.
932 @retval EFI_ACCESS_DENIED An attempt is being made to change the
933 EFI_FILE_DIRECTORY Attribute.
934 @retval EFI_ACCESS_DENIED The file is a read-only file or has been
935 opened in read-only mode and an attempt is
936 being made to modify a field other than
938 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a
940 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
941 @retval EFI_OUT_OF_RESOURCES A allocation needed to process the request failed.
947 IN SEMIHOST_FCB
*Fcb
,
948 IN EFI_FILE_INFO
*Info
952 RETURN_STATUS Return
;
953 BOOLEAN FileSizeIsDifferent
;
954 BOOLEAN FileNameIsDifferent
;
955 BOOLEAN ReadOnlyIsDifferent
;
956 CHAR8
*AsciiFileName
;
959 UINTN SemihostHandle
;
962 // A directory can not be changed to a file and a file can
963 // not be changed to a directory.
965 if (((Info
->Attribute
& EFI_FILE_DIRECTORY
) != 0) != Fcb
->IsRoot
) {
966 return EFI_ACCESS_DENIED
;
969 Length
= StrLen (Info
->FileName
) + 1;
970 AsciiFileName
= AllocatePool (Length
);
971 if (AsciiFileName
== NULL
) {
972 return EFI_OUT_OF_RESOURCES
;
974 UnicodeStrToAsciiStrS (Info
->FileName
, AsciiFileName
, Length
);
976 FileSizeIsDifferent
= (Info
->FileSize
!= Fcb
->Info
.FileSize
);
977 FileNameIsDifferent
= (AsciiStrCmp (AsciiFileName
, Fcb
->FileName
) != 0);
978 ReadOnlyIsDifferent
= CompareMem (
980 &Fcb
->Info
.CreateTime
,
981 3 * sizeof (EFI_TIME
)
985 // For a read-only file or a file opened in read-only mode, only
986 // the Attribute field can be modified. As the root directory is
987 // read-only (i.e. VolumeOpen()), this protects the root directory
990 if ((Fcb
->OpenMode
== EFI_FILE_MODE_READ
) ||
991 (Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
) ) {
992 if (FileSizeIsDifferent
|| FileNameIsDifferent
|| ReadOnlyIsDifferent
) {
993 Status
= EFI_ACCESS_DENIED
;
998 if (ReadOnlyIsDifferent
) {
999 Status
= EFI_WRITE_PROTECTED
;
1003 Status
= EFI_DEVICE_ERROR
;
1005 if (FileSizeIsDifferent
) {
1006 FileSize
= Info
->FileSize
;
1007 if (Fcb
->Info
.FileSize
< FileSize
) {
1008 Status
= ExtendFile (Fcb
, FileSize
- Fcb
->Info
.FileSize
);
1009 if (EFI_ERROR (Status
)) {
1013 // The read/write position from the host file system point of view
1014 // is at the end of the file. If the position from this module
1015 // point of view is smaller than the new file size, then
1016 // ask the host file system to move to that position.
1018 if (Fcb
->Position
< FileSize
) {
1019 FileSetPosition (&Fcb
->File
, Fcb
->Position
);
1022 Fcb
->Info
.FileSize
= FileSize
;
1024 Return
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
1025 if (RETURN_ERROR (Return
)) {
1028 Fcb
->Info
.PhysicalSize
= Length
;
1032 // Note down in RAM the Attribute field but we can not ask
1033 // for its modification to the host file system as the
1034 // semi-host interface does not provide this feature.
1036 Fcb
->Info
.Attribute
= Info
->Attribute
;
1038 if (FileNameIsDifferent
) {
1039 Return
= SemihostFileOpen (
1041 SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
,
1044 if (!RETURN_ERROR (Return
)) {
1045 SemihostFileClose (SemihostHandle
);
1046 Status
= EFI_ACCESS_DENIED
;
1050 Return
= SemihostFileRename (Fcb
->FileName
, AsciiFileName
);
1051 if (RETURN_ERROR (Return
)) {
1054 FreePool (Fcb
->FileName
);
1055 Fcb
->FileName
= AsciiFileName
;
1056 AsciiFileName
= NULL
;
1059 Status
= EFI_SUCCESS
;
1062 if (AsciiFileName
!= NULL
) {
1063 FreePool (AsciiFileName
);
1070 Set information about a file or a file system.
1072 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
1073 is the file handle the information is for.
1074 @param[in] InformationType The type identifier for the information being set :
1075 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
1076 EFI_FILE_SYSTEM_VOLUME_LABEL_ID
1077 @param[in] BufferSize The size, in bytes, of Buffer.
1078 @param[in] Buffer A pointer to the data buffer to write. The type of the
1079 data inside the buffer is indicated by InformationType.
1081 @retval EFI_SUCCESS The information was set.
1082 @retval EFI_UNSUPPORTED The InformationType is not known.
1083 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
1084 @retval EFI_ACCESS_DENIED An attempt is being made to change the
1085 EFI_FILE_DIRECTORY Attribute.
1086 @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and
1087 the file is a read-only file or has been
1088 opened in read-only mode and an attempt is
1089 being made to modify a field other than
1091 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
1092 to a file that is already present.
1093 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a
1094 read-only attribute.
1095 @retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by
1096 the data inside the buffer.
1097 @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request failed.
1098 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
1104 IN EFI_GUID
*InformationType
,
1105 IN UINTN BufferSize
,
1110 EFI_FILE_INFO
*Info
;
1111 EFI_FILE_SYSTEM_INFO
*SystemInfo
;
1112 CHAR16
*VolumeLabel
;
1114 if ((This
== NULL
) || (InformationType
== NULL
) || (Buffer
== NULL
)) {
1115 return EFI_INVALID_PARAMETER
;
1118 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
1120 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1122 if (Info
->Size
< (SIZE_OF_EFI_FILE_INFO
+ StrSize (Info
->FileName
))) {
1123 return EFI_INVALID_PARAMETER
;
1125 if (BufferSize
< Info
->Size
) {
1126 return EFI_BAD_BUFFER_SIZE
;
1128 return SetFileInfo (Fcb
, Info
);
1129 } else if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
1130 SystemInfo
= Buffer
;
1131 if (SystemInfo
->Size
<
1132 (SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (SystemInfo
->VolumeLabel
))) {
1133 return EFI_INVALID_PARAMETER
;
1135 if (BufferSize
< SystemInfo
->Size
) {
1136 return EFI_BAD_BUFFER_SIZE
;
1138 Buffer
= SystemInfo
->VolumeLabel
;
1140 if (StrSize (Buffer
) > 0) {
1141 VolumeLabel
= AllocateCopyPool (StrSize (Buffer
), Buffer
);
1142 if (VolumeLabel
!= NULL
) {
1143 FreePool (mSemihostFsLabel
);
1144 mSemihostFsLabel
= VolumeLabel
;
1147 return EFI_OUT_OF_RESOURCES
;
1150 return EFI_INVALID_PARAMETER
;
1152 } else if (!CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1153 return EFI_UNSUPPORTED
;
1155 return EFI_UNSUPPORTED
;
1166 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
1171 if ((Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
)
1172 || !(Fcb
->OpenMode
& EFI_FILE_MODE_WRITE
)) {
1173 return EFI_ACCESS_DENIED
;
1181 SemihostFsEntryPoint (
1182 IN EFI_HANDLE ImageHandle
,
1183 IN EFI_SYSTEM_TABLE
*SystemTable
1188 Status
= EFI_NOT_FOUND
;
1190 if (SemihostConnectionSupported ()) {
1191 mSemihostFsLabel
= AllocateCopyPool (StrSize (DEFAULT_SEMIHOST_FS_LABEL
), DEFAULT_SEMIHOST_FS_LABEL
);
1192 if (mSemihostFsLabel
== NULL
) {
1193 return EFI_OUT_OF_RESOURCES
;
1196 Status
= gBS
->InstallMultipleProtocolInterfaces (
1198 &gEfiSimpleFileSystemProtocolGuid
, &gSemihostFs
,
1199 &gEfiDevicePathProtocolGuid
, &gDevicePath
,
1203 if (EFI_ERROR(Status
)) {
1204 FreePool (mSemihostFsLabel
);