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 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
) &&
200 (Attributes
& EFI_FILE_DIRECTORY
) ) {
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
) {
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
) ? Attributes
: 0;
282 InsertTailList (&gFileList
, &FileFcb
->Link
);
284 *NewHandle
= &FileFcb
->File
;
290 FreePool (AsciiFileName
);
296 Worker function that truncate a file specified by its name to a given size.
298 @param[in] FileName The Null-terminated string of the name of the file to be opened.
299 @param[in] Size The target size for the file.
301 @retval EFI_SUCCESS The file was truncated.
302 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
313 RETURN_STATUS Return
;
320 Status
= EFI_DEVICE_ERROR
;
324 Return
= SemihostFileOpen (
326 SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
,
329 if (RETURN_ERROR (Return
)) {
333 Buffer
= AllocatePool (Size
);
334 if (Buffer
== NULL
) {
335 Status
= EFI_OUT_OF_RESOURCES
;
341 while (Remaining
> 0) {
343 Return
= SemihostFileRead (FileHandle
, &ToRead
, Buffer
+ Read
);
344 if (RETURN_ERROR (Return
)) {
351 Return
= SemihostFileClose (FileHandle
);
353 if (RETURN_ERROR (Return
)) {
357 Return
= SemihostFileOpen (
359 SEMIHOST_FILE_MODE_WRITE
| SEMIHOST_FILE_MODE_BINARY
,
362 if (RETURN_ERROR (Return
)) {
367 Return
= SemihostFileWrite (FileHandle
, &Size
, Buffer
);
368 if (RETURN_ERROR (Return
)) {
373 Status
= EFI_SUCCESS
;
377 if (FileHandle
!= 0) {
378 SemihostFileClose (FileHandle
);
380 if (Buffer
!= NULL
) {
389 Close a specified file handle.
391 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
394 @retval EFI_SUCCESS The file was closed.
395 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
406 return EFI_INVALID_PARAMETER
;
409 Fcb
= SEMIHOST_FCB_FROM_THIS(This
);
412 SemihostFileClose (Fcb
->SemihostHandle
);
414 // The file size might have been reduced from its actual
415 // size on the host file system with FileSetInfo(). In
416 // that case, the file has to be truncated.
418 if (Fcb
->Info
.FileSize
< Fcb
->Info
.PhysicalSize
) {
419 TruncateFile (Fcb
->FileName
, Fcb
->Info
.FileSize
);
421 FreePool (Fcb
->FileName
);
430 Close and delete a file.
432 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
435 @retval EFI_SUCCESS The file was closed and deleted.
436 @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted.
437 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
446 RETURN_STATUS Return
;
451 return EFI_INVALID_PARAMETER
;
454 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
457 // Get the filename from the Fcb
458 NameSize
= AsciiStrLen (Fcb
->FileName
);
459 FileName
= AllocatePool (NameSize
+ 1);
461 AsciiStrCpyS (FileName
, NameSize
+ 1, Fcb
->FileName
);
463 // Close the file if it's open. Disregard return status,
464 // since it might give an error if the file isn't open.
467 // Call the semihost interface to delete the file.
468 Return
= SemihostFileRemove (FileName
);
469 if (RETURN_ERROR (Return
)) {
470 return EFI_WARN_DELETE_FAILURE
;
474 return EFI_WARN_DELETE_FAILURE
;
479 Read data from an open file.
481 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
482 is the file handle to read data from.
483 @param[in out] BufferSize On input, the size of the Buffer. On output, the
484 amount of data returned in Buffer. In both cases,
485 the size is measured in bytes.
486 @param[out] Buffer The buffer into which the data is read.
488 @retval EFI_SUCCESS The data was read.
489 @retval EFI_DEVICE_ERROR On entry, the current file position is
490 beyond the end of the file, or the semi-hosting
491 interface reported an error while performing the
493 @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL.
499 IN OUT UINTN
*BufferSize
,
505 RETURN_STATUS Return
;
507 if ((This
== NULL
) || (BufferSize
== NULL
) || (Buffer
== NULL
)) {
508 return EFI_INVALID_PARAMETER
;
511 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
514 // The semi-hosting interface does not allow to list files on the host machine.
515 Status
= EFI_UNSUPPORTED
;
517 Status
= EFI_SUCCESS
;
518 if (Fcb
->Position
>= Fcb
->Info
.FileSize
) {
520 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
521 Status
= EFI_DEVICE_ERROR
;
524 Return
= SemihostFileRead (Fcb
->SemihostHandle
, BufferSize
, Buffer
);
525 if (RETURN_ERROR (Return
)) {
526 Status
= EFI_DEVICE_ERROR
;
528 Fcb
->Position
+= *BufferSize
;
537 Worker function that extends the size of an open file.
539 The extension is filled with zeros.
541 @param[in] Fcb Internal description of the opened file
542 @param[in] Size The number of bytes, the file has to be extended.
544 @retval EFI_SUCCESS The file was extended.
545 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
551 IN SEMIHOST_FCB
*Fcb
,
555 RETURN_STATUS Return
;
557 CHAR8 WriteBuffer
[128];
561 Return
= SemihostFileSeek (Fcb
->SemihostHandle
, Fcb
->Info
.FileSize
);
562 if (RETURN_ERROR (Return
)) {
563 return EFI_DEVICE_ERROR
;
567 SetMem (WriteBuffer
, 0, sizeof(WriteBuffer
));
568 while (Remaining
> 0) {
569 WriteNb
= MIN (Remaining
, sizeof(WriteBuffer
));
571 Return
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, WriteBuffer
);
572 if (RETURN_ERROR (Return
)) {
573 return EFI_DEVICE_ERROR
;
575 Remaining
-= WriteNb
;
582 Write data to an open file.
584 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
585 is the file handle to write data to.
586 @param[in out] BufferSize On input, the size of the Buffer. On output, the
587 size of the data actually written. In both cases,
588 the size is measured in bytes.
589 @param[in] Buffer The buffer of data to write.
591 @retval EFI_SUCCESS The data was written.
592 @retval EFI_ACCESS_DENIED Attempt to write into a read only file or
593 in a file opened in read only mode.
594 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
595 @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL.
601 IN OUT UINTN
*BufferSize
,
608 RETURN_STATUS Return
;
611 if ((This
== NULL
) || (BufferSize
== NULL
) || (Buffer
== NULL
)) {
612 return EFI_INVALID_PARAMETER
;
615 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
617 // We cannot write a read-only file
618 if ((Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
)
619 || !(Fcb
->OpenMode
& EFI_FILE_MODE_WRITE
)) {
620 return EFI_ACCESS_DENIED
;
624 // If the position has been set past the end of the file, first grow the
625 // file from its current size "Fcb->Info.FileSize" to "Fcb->Position"
626 // size, filling the gap with zeros.
628 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
629 Status
= ExtendFile (Fcb
, Fcb
->Position
- Fcb
->Info
.FileSize
);
630 if (EFI_ERROR (Status
)) {
633 Fcb
->Info
.FileSize
= Fcb
->Position
;
636 WriteSize
= *BufferSize
;
637 Return
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, Buffer
);
638 if (RETURN_ERROR (Return
)) {
639 return EFI_DEVICE_ERROR
;
642 Fcb
->Position
+= *BufferSize
;
643 if (Fcb
->Position
> Fcb
->Info
.FileSize
) {
644 Fcb
->Info
.FileSize
= Fcb
->Position
;
647 Return
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
648 if (RETURN_ERROR (Return
)) {
649 return EFI_DEVICE_ERROR
;
651 Fcb
->Info
.PhysicalSize
= Length
;
657 Return a file's current position.
659 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
660 the file handle to get the current position on.
661 @param[out] Position The address to return the file's current position value.
663 @retval EFI_SUCCESS The position was returned.
664 @retval EFI_INVALID_PARAMETER The parameter "This" or "Position" is NULL.
675 if ((This
== NULL
) || (Position
== NULL
)) {
676 return EFI_INVALID_PARAMETER
;
679 Fcb
= SEMIHOST_FCB_FROM_THIS(This
);
681 *Position
= Fcb
->Position
;
687 Set a file's current position.
689 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
690 the file handle to set the requested position on.
691 @param[in] Position The byte position from the start of the file to set.
693 @retval EFI_SUCCESS The position was set.
694 @retval EFI_DEVICE_ERROR The semi-hosting positioning operation failed.
695 @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open
697 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.
707 RETURN_STATUS Return
;
710 return EFI_INVALID_PARAMETER
;
713 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
717 return EFI_UNSUPPORTED
;
722 // UEFI Spec section 12.5:
723 // "Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to
724 // be set to the end of the file."
726 if (Position
== 0xFFFFFFFFFFFFFFFF) {
727 Position
= Fcb
->Info
.FileSize
;
729 Return
= SemihostFileSeek (Fcb
->SemihostHandle
, MIN (Position
, Fcb
->Info
.FileSize
));
730 if (RETURN_ERROR (Return
)) {
731 return EFI_DEVICE_ERROR
;
735 Fcb
->Position
= Position
;
741 Return information about a file.
743 @param[in] Fcb A pointer to the description of an open file.
744 @param[in out] BufferSize The size, in bytes, of Buffer.
745 @param[out] Buffer A pointer to the data buffer to return. Not NULL if
746 "*BufferSize" is greater than 0.
748 @retval EFI_SUCCESS The information was returned.
749 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
750 BufferSize has been updated with the size needed to
751 complete the request.
756 IN SEMIHOST_FCB
*Fcb
,
757 IN OUT UINTN
*BufferSize
,
761 EFI_FILE_INFO
*Info
= NULL
;
766 if (Fcb
->IsRoot
== TRUE
) {
767 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ sizeof(CHAR16
);
769 NameSize
= AsciiStrLen (Fcb
->FileName
) + 1;
770 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ NameSize
* sizeof (CHAR16
);
773 if (*BufferSize
< ResultSize
) {
774 *BufferSize
= ResultSize
;
775 return EFI_BUFFER_TOO_SMALL
;
780 // Copy the current file info
781 CopyMem (Info
, &Fcb
->Info
, SIZE_OF_EFI_FILE_INFO
);
783 // Fill in the structure
784 Info
->Size
= ResultSize
;
786 if (Fcb
->IsRoot
== TRUE
) {
787 Info
->FileName
[0] = L
'\0';
789 for (Index
= 0; Index
< NameSize
; Index
++) {
790 Info
->FileName
[Index
] = Fcb
->FileName
[Index
];
794 *BufferSize
= ResultSize
;
800 Return information about a file system.
802 @param[in] Fcb A pointer to the description of an open file
803 which belongs to the file system, the information
805 @param[in out] BufferSize The size, in bytes, of Buffer.
806 @param[out] Buffer A pointer to the data buffer to return. Not NULL if
807 "*BufferSize" is greater than 0.
809 @retval EFI_SUCCESS The information was returned.
810 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
811 BufferSize has been updated with the size needed to
812 complete the request.
818 IN SEMIHOST_FCB
*Fcb
,
819 IN OUT UINTN
*BufferSize
,
823 EFI_FILE_SYSTEM_INFO
*Info
;
828 StringSize
= StrSize (mSemihostFsLabel
);
829 ResultSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StringSize
;
831 if (*BufferSize
>= ResultSize
) {
832 ZeroMem (Buffer
, ResultSize
);
833 Status
= EFI_SUCCESS
;
837 Info
->Size
= ResultSize
;
838 Info
->ReadOnly
= FALSE
;
839 Info
->VolumeSize
= 0;
843 CopyMem (Info
->VolumeLabel
, mSemihostFsLabel
, StringSize
);
845 Status
= EFI_BUFFER_TOO_SMALL
;
848 *BufferSize
= ResultSize
;
853 Return information about a file or a file system.
855 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
856 is the file handle the requested information is for.
857 @param[in] InformationType The type identifier for the information being requested :
858 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
859 EFI_FILE_SYSTEM_VOLUME_LABEL_ID
860 @param[in out] BufferSize The size, in bytes, of Buffer.
861 @param[out] Buffer A pointer to the data buffer to return. The type of the
862 data inside the buffer is indicated by InformationType.
864 @retval EFI_SUCCESS The information was returned.
865 @retval EFI_UNSUPPORTED The InformationType is not known.
866 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.
867 BufferSize has been updated with the size needed to
868 complete the request.
869 @retval EFI_INVALID_PARAMETER The parameter "This" or "InformationType" or "BufferSize"
870 is NULL or "Buffer" is NULL and "*Buffersize" is greater
877 IN EFI_GUID
*InformationType
,
878 IN OUT UINTN
*BufferSize
,
886 if ((This
== NULL
) ||
887 (InformationType
== NULL
) ||
888 (BufferSize
== NULL
) ||
889 ((Buffer
== NULL
) && (*BufferSize
> 0)) ) {
890 return EFI_INVALID_PARAMETER
;
893 Fcb
= SEMIHOST_FCB_FROM_THIS(This
);
895 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
896 Status
= GetFilesystemInfo (Fcb
, BufferSize
, Buffer
);
897 } else if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
898 Status
= GetFileInfo (Fcb
, BufferSize
, Buffer
);
899 } else if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
900 ResultSize
= StrSize (mSemihostFsLabel
);
902 if (*BufferSize
>= ResultSize
) {
903 CopyMem (Buffer
, mSemihostFsLabel
, ResultSize
);
904 Status
= EFI_SUCCESS
;
906 Status
= EFI_BUFFER_TOO_SMALL
;
909 *BufferSize
= ResultSize
;
911 Status
= EFI_UNSUPPORTED
;
918 Set information about a file.
920 @param[in] Fcb A pointer to the description of the open file.
921 @param[in] Info A pointer to the file information to write.
923 @retval EFI_SUCCESS The information was set.
924 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
925 to a file that is already present.
926 @retval EFI_ACCESS_DENIED An attempt is being made to change the
927 EFI_FILE_DIRECTORY Attribute.
928 @retval EFI_ACCESS_DENIED The file is a read-only file or has been
929 opened in read-only mode and an attempt is
930 being made to modify a field other than
932 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a
934 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
935 @retval EFI_OUT_OF_RESOURCES A allocation needed to process the request failed.
941 IN SEMIHOST_FCB
*Fcb
,
942 IN EFI_FILE_INFO
*Info
946 RETURN_STATUS Return
;
947 BOOLEAN FileSizeIsDifferent
;
948 BOOLEAN FileNameIsDifferent
;
949 BOOLEAN ReadOnlyIsDifferent
;
950 CHAR8
*AsciiFileName
;
953 UINTN SemihostHandle
;
956 // A directory can not be changed to a file and a file can
957 // not be changed to a directory.
959 if (((Info
->Attribute
& EFI_FILE_DIRECTORY
) != 0) != Fcb
->IsRoot
) {
960 return EFI_ACCESS_DENIED
;
963 Length
= StrLen (Info
->FileName
) + 1;
964 AsciiFileName
= AllocatePool (Length
);
965 if (AsciiFileName
== NULL
) {
966 return EFI_OUT_OF_RESOURCES
;
968 UnicodeStrToAsciiStrS (Info
->FileName
, AsciiFileName
, Length
);
970 FileSizeIsDifferent
= (Info
->FileSize
!= Fcb
->Info
.FileSize
);
971 FileNameIsDifferent
= (AsciiStrCmp (AsciiFileName
, Fcb
->FileName
) != 0);
972 ReadOnlyIsDifferent
= CompareMem (
974 &Fcb
->Info
.CreateTime
,
975 3 * sizeof (EFI_TIME
)
979 // For a read-only file or a file opened in read-only mode, only
980 // the Attribute field can be modified. As the root directory is
981 // read-only (i.e. VolumeOpen()), this protects the root directory
984 if ((Fcb
->OpenMode
== EFI_FILE_MODE_READ
) ||
985 (Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
) ) {
986 if (FileSizeIsDifferent
|| FileNameIsDifferent
|| ReadOnlyIsDifferent
) {
987 Status
= EFI_ACCESS_DENIED
;
992 if (ReadOnlyIsDifferent
) {
993 Status
= EFI_WRITE_PROTECTED
;
997 Status
= EFI_DEVICE_ERROR
;
999 if (FileSizeIsDifferent
) {
1000 FileSize
= Info
->FileSize
;
1001 if (Fcb
->Info
.FileSize
< FileSize
) {
1002 Status
= ExtendFile (Fcb
, FileSize
- Fcb
->Info
.FileSize
);
1003 if (EFI_ERROR (Status
)) {
1007 // The read/write position from the host file system point of view
1008 // is at the end of the file. If the position from this module
1009 // point of view is smaller than the new file size, then
1010 // ask the host file system to move to that position.
1012 if (Fcb
->Position
< FileSize
) {
1013 FileSetPosition (&Fcb
->File
, Fcb
->Position
);
1016 Fcb
->Info
.FileSize
= FileSize
;
1018 Return
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
1019 if (RETURN_ERROR (Return
)) {
1022 Fcb
->Info
.PhysicalSize
= Length
;
1026 // Note down in RAM the Attribute field but we can not ask
1027 // for its modification to the host file system as the
1028 // semi-host interface does not provide this feature.
1030 Fcb
->Info
.Attribute
= Info
->Attribute
;
1032 if (FileNameIsDifferent
) {
1033 Return
= SemihostFileOpen (
1035 SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
,
1038 if (!RETURN_ERROR (Return
)) {
1039 SemihostFileClose (SemihostHandle
);
1040 Status
= EFI_ACCESS_DENIED
;
1044 Return
= SemihostFileRename (Fcb
->FileName
, AsciiFileName
);
1045 if (RETURN_ERROR (Return
)) {
1048 FreePool (Fcb
->FileName
);
1049 Fcb
->FileName
= AsciiFileName
;
1050 AsciiFileName
= NULL
;
1053 Status
= EFI_SUCCESS
;
1056 if (AsciiFileName
!= NULL
) {
1057 FreePool (AsciiFileName
);
1064 Set information about a file or a file system.
1066 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
1067 is the file handle the information is for.
1068 @param[in] InformationType The type identifier for the information being set :
1069 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
1070 EFI_FILE_SYSTEM_VOLUME_LABEL_ID
1071 @param[in] BufferSize The size, in bytes, of Buffer.
1072 @param[in] Buffer A pointer to the data buffer to write. The type of the
1073 data inside the buffer is indicated by InformationType.
1075 @retval EFI_SUCCESS The information was set.
1076 @retval EFI_UNSUPPORTED The InformationType is not known.
1077 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
1078 @retval EFI_ACCESS_DENIED An attempt is being made to change the
1079 EFI_FILE_DIRECTORY Attribute.
1080 @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and
1081 the file is a read-only file or has been
1082 opened in read-only mode and an attempt is
1083 being made to modify a field other than
1085 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
1086 to a file that is already present.
1087 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a
1088 read-only attribute.
1089 @retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by
1090 the data inside the buffer.
1091 @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request failed.
1092 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
1098 IN EFI_GUID
*InformationType
,
1099 IN UINTN BufferSize
,
1104 EFI_FILE_INFO
*Info
;
1105 EFI_FILE_SYSTEM_INFO
*SystemInfo
;
1106 CHAR16
*VolumeLabel
;
1108 if ((This
== NULL
) || (InformationType
== NULL
) || (Buffer
== NULL
)) {
1109 return EFI_INVALID_PARAMETER
;
1112 Fcb
= SEMIHOST_FCB_FROM_THIS (This
);
1114 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1116 if (Info
->Size
< (SIZE_OF_EFI_FILE_INFO
+ StrSize (Info
->FileName
))) {
1117 return EFI_INVALID_PARAMETER
;
1119 if (BufferSize
< Info
->Size
) {
1120 return EFI_BAD_BUFFER_SIZE
;
1122 return SetFileInfo (Fcb
, Info
);
1123 } else if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
1124 SystemInfo
= Buffer
;
1125 if (SystemInfo
->Size
<
1126 (SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (SystemInfo
->VolumeLabel
))) {
1127 return EFI_INVALID_PARAMETER
;
1129 if (BufferSize
< SystemInfo
->Size
) {
1130 return EFI_BAD_BUFFER_SIZE
;
1132 Buffer
= SystemInfo
->VolumeLabel
;
1134 if (StrSize (Buffer
) > 0) {
1135 VolumeLabel
= AllocateCopyPool (StrSize (Buffer
), Buffer
);
1136 if (VolumeLabel
!= NULL
) {
1137 FreePool (mSemihostFsLabel
);
1138 mSemihostFsLabel
= VolumeLabel
;
1141 return EFI_OUT_OF_RESOURCES
;
1144 return EFI_INVALID_PARAMETER
;
1146 } else if (!CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1147 return EFI_UNSUPPORTED
;
1149 return EFI_UNSUPPORTED
;
1160 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
1165 if ((Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
)
1166 || !(Fcb
->OpenMode
& EFI_FILE_MODE_WRITE
)) {
1167 return EFI_ACCESS_DENIED
;
1175 SemihostFsEntryPoint (
1176 IN EFI_HANDLE ImageHandle
,
1177 IN EFI_SYSTEM_TABLE
*SystemTable
1182 Status
= EFI_NOT_FOUND
;
1184 if (SemihostConnectionSupported ()) {
1185 mSemihostFsLabel
= AllocateCopyPool (StrSize (DEFAULT_SEMIHOST_FS_LABEL
), DEFAULT_SEMIHOST_FS_LABEL
);
1186 if (mSemihostFsLabel
== NULL
) {
1187 return EFI_OUT_OF_RESOURCES
;
1190 Status
= gBS
->InstallMultipleProtocolInterfaces (
1192 &gEfiSimpleFileSystemProtocolGuid
, &gSemihostFs
,
1193 &gEfiDevicePathProtocolGuid
, &gDevicePath
,
1197 if (EFI_ERROR(Status
)) {
1198 FreePool (mSemihostFsLabel
);