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 SemiHosting. 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
;
155 OUT EFI_FILE
**NewHandle
,
161 SEMIHOST_FCB
*FileFcb
= NULL
;
162 EFI_STATUS Status
= EFI_SUCCESS
;
163 UINTN SemihostHandle
;
164 CHAR8
*AsciiFileName
;
169 if ((FileName
== NULL
) || (NewHandle
== NULL
)) {
170 return EFI_INVALID_PARAMETER
;
173 // Semihosting does not support directories
174 if (Attributes
& EFI_FILE_DIRECTORY
) {
175 return EFI_UNSUPPORTED
;
178 // Semihost interface requires ASCII filenames
179 AsciiFileName
= AllocatePool ((StrLen (FileName
) + 1) * sizeof (CHAR8
));
180 if (AsciiFileName
== NULL
) {
181 return EFI_OUT_OF_RESOURCES
;
183 UnicodeStrToAsciiStr (FileName
, AsciiFileName
);
185 if ((AsciiStrCmp (AsciiFileName
, "\\") == 0) ||
186 (AsciiStrCmp (AsciiFileName
, "/") == 0) ||
187 (AsciiStrCmp (AsciiFileName
, "") == 0) ||
188 (AsciiStrCmp (AsciiFileName
, ".") == 0)) {
189 // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
192 // Root directory node doesn't have a name.
193 FreePool (AsciiFileName
);
194 AsciiFileName
= NULL
;
196 // Translate EFI_FILE_MODE into Semihosting mode
197 if (OpenMode
& EFI_FILE_MODE_WRITE
) {
198 SemihostMode
= SEMIHOST_FILE_MODE_WRITE
| SEMIHOST_FILE_MODE_BINARY
;
199 } else if (OpenMode
& EFI_FILE_MODE_READ
) {
200 SemihostMode
= SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
;
202 return EFI_UNSUPPORTED
;
205 // Add the creation flag if necessary
206 if (OpenMode
& EFI_FILE_MODE_CREATE
) {
207 SemihostMode
|= SEMIHOST_FILE_MODE_CREATE
;
210 // Call the semihosting interface to open the file.
211 Status
= SemihostFileOpen (AsciiFileName
, SemihostMode
, &SemihostHandle
);
212 if (EFI_ERROR(Status
)) {
219 // Allocate a control block and fill it
220 FileFcb
= AllocateFCB ();
221 if (FileFcb
== NULL
) {
222 return EFI_OUT_OF_RESOURCES
;
225 FileFcb
->FileName
= AsciiFileName
;
226 FileFcb
->SemihostHandle
= SemihostHandle
;
227 FileFcb
->Position
= 0;
228 FileFcb
->IsRoot
= IsRoot
;
229 FileFcb
->OpenMode
= OpenMode
;
232 Status
= SemihostFileLength (SemihostHandle
, &Length
);
233 if (EFI_ERROR(Status
)) {
237 FileFcb
->Info
.FileSize
= Length
;
238 FileFcb
->Info
.PhysicalSize
= Length
;
239 FileFcb
->Info
.Attribute
= Attributes
;
242 InsertTailList (&gFileList
, &FileFcb
->Link
);
244 *NewHandle
= &FileFcb
->File
;
255 SEMIHOST_FCB
*Fcb
= NULL
;
256 EFI_STATUS Status
= EFI_SUCCESS
;
258 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
260 if (Fcb
->IsRoot
== TRUE
) {
262 Status
= EFI_SUCCESS
;
264 Status
= SemihostFileClose (Fcb
->SemihostHandle
);
265 if (!EFI_ERROR(Status
)) {
266 FreePool (Fcb
->FileName
);
279 SEMIHOST_FCB
*Fcb
= NULL
;
284 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
287 // Get the filename from the Fcb
288 NameSize
= AsciiStrLen (Fcb
->FileName
);
289 FileName
= AllocatePool (NameSize
+ 1);
291 AsciiStrCpy (FileName
, Fcb
->FileName
);
293 // Close the file if it's open. Disregard return status,
294 // since it might give an error if the file isn't open.
297 // Call the semihost interface to delete the file.
298 Status
= SemihostFileRemove (FileName
);
299 if (EFI_ERROR(Status
)) {
300 Status
= EFI_WARN_DELETE_FAILURE
;
303 Status
= EFI_WARN_DELETE_FAILURE
;
312 IN OUT UINTN
*BufferSize
,
316 SEMIHOST_FCB
*Fcb
= NULL
;
319 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
321 if (Fcb
->IsRoot
== TRUE
) {
322 // By design, the Semihosting feature does not allow to list files on the host machine.
323 Status
= EFI_UNSUPPORTED
;
325 Status
= SemihostFileRead (Fcb
->SemihostHandle
, BufferSize
, Buffer
);
326 if (!EFI_ERROR (Status
)) {
327 Fcb
->Position
+= *BufferSize
;
337 IN OUT UINTN
*BufferSize
,
341 SEMIHOST_FCB
*Fcb
= NULL
;
343 UINTN WriteSize
= *BufferSize
;
345 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
347 // We cannot write a read-only file
348 if ((Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
)
349 || !(Fcb
->OpenMode
& EFI_FILE_MODE_WRITE
)) {
350 return EFI_ACCESS_DENIED
;
353 Status
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, Buffer
);
355 if (!EFI_ERROR(Status
)) {
356 // Semihost write return the number of bytes *NOT* written.
357 *BufferSize
-= WriteSize
;
358 Fcb
->Position
+= *BufferSize
;
370 SEMIHOST_FCB
*Fcb
= NULL
;
372 if (Position
== NULL
) {
373 return EFI_INVALID_PARAMETER
;
376 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
378 *Position
= Fcb
->Position
;
389 SEMIHOST_FCB
*Fcb
= NULL
;
393 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
396 Status
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
397 if (!EFI_ERROR(Status
) && (Length
< Position
)) {
401 Status
= SemihostFileSeek (Fcb
->SemihostHandle
, (UINT32
)Position
);
402 if (!EFI_ERROR(Status
)) {
403 Fcb
->Position
= Position
;
406 Fcb
->Position
= Position
;
407 Status
= EFI_SUCCESS
;
416 IN SEMIHOST_FCB
*Fcb
,
417 IN OUT UINTN
*BufferSize
,
421 EFI_FILE_INFO
*Info
= NULL
;
426 if (Fcb
->IsRoot
== TRUE
) {
427 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ sizeof(CHAR16
);
429 NameSize
= AsciiStrLen (Fcb
->FileName
) + 1;
430 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ NameSize
* sizeof (CHAR16
);
433 if (*BufferSize
< ResultSize
) {
434 *BufferSize
= ResultSize
;
435 return EFI_BUFFER_TOO_SMALL
;
440 // Copy the current file info
441 CopyMem (Info
, &Fcb
->Info
, SIZE_OF_EFI_FILE_INFO
);
443 // Fill in the structure
444 Info
->Size
= ResultSize
;
446 if (Fcb
->IsRoot
== TRUE
) {
447 Info
->FileName
[0] = L
'\0';
449 for (Index
= 0; Index
< NameSize
; Index
++) {
450 Info
->FileName
[Index
] = Fcb
->FileName
[Index
];
454 *BufferSize
= ResultSize
;
462 IN SEMIHOST_FCB
*Fcb
,
463 IN OUT UINTN
*BufferSize
,
467 EFI_FILE_SYSTEM_INFO
*Info
= NULL
;
469 UINTN ResultSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (mSemihostFsLabel
);
471 if (*BufferSize
>= ResultSize
) {
472 ZeroMem (Buffer
, ResultSize
);
473 Status
= EFI_SUCCESS
;
477 Info
->Size
= ResultSize
;
478 Info
->ReadOnly
= FALSE
;
479 Info
->VolumeSize
= 0;
483 StrCpy (Info
->VolumeLabel
, mSemihostFsLabel
);
485 Status
= EFI_BUFFER_TOO_SMALL
;
488 *BufferSize
= ResultSize
;
495 IN EFI_GUID
*InformationType
,
496 IN OUT UINTN
*BufferSize
,
504 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
506 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
) != 0) {
507 Status
= GetFilesystemInfo (Fcb
, BufferSize
, Buffer
);
508 } else if (CompareGuid (InformationType
, &gEfiFileInfoGuid
) != 0) {
509 Status
= GetFileInfo (Fcb
, BufferSize
, Buffer
);
510 } else if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
) != 0) {
511 ResultSize
= StrSize (mSemihostFsLabel
);
513 if (*BufferSize
>= ResultSize
) {
514 StrCpy (Buffer
, mSemihostFsLabel
);
515 Status
= EFI_SUCCESS
;
517 Status
= EFI_BUFFER_TOO_SMALL
;
520 *BufferSize
= ResultSize
;
522 Status
= EFI_UNSUPPORTED
;
531 IN EFI_GUID
*InformationType
,
538 if (Buffer
== NULL
) {
539 return EFI_INVALID_PARAMETER
;
542 Status
= EFI_UNSUPPORTED
;
544 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
) != 0) {
545 //Status = SetFilesystemInfo (Fcb, BufferSize, Buffer);
546 } else if (CompareGuid (InformationType
, &gEfiFileInfoGuid
) != 0) {
547 // Semihosting does not give us access to setting file info, but
548 // if we fail here we cannot create new files.
549 Status
= EFI_SUCCESS
;
550 } else if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
) != 0) {
551 if (StrSize (Buffer
) > 0) {
552 FreePool (mSemihostFsLabel
);
553 mSemihostFsLabel
= AllocateCopyPool (StrSize (Buffer
), Buffer
);
554 Status
= EFI_SUCCESS
;
568 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
573 if ((Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
)
574 || !(Fcb
->OpenMode
& EFI_FILE_MODE_WRITE
)) {
575 return EFI_ACCESS_DENIED
;
583 SemihostFsEntryPoint (
584 IN EFI_HANDLE ImageHandle
,
585 IN EFI_SYSTEM_TABLE
*SystemTable
590 Status
= EFI_NOT_FOUND
;
592 if (SemihostConnectionSupported ()) {
593 mSemihostFsLabel
= AllocateCopyPool (StrSize (DEFAULT_SEMIHOST_FS_LABEL
), DEFAULT_SEMIHOST_FS_LABEL
);
594 if (mSemihostFsLabel
== NULL
) {
595 return EFI_OUT_OF_RESOURCES
;
598 Status
= gBS
->InstallMultipleProtocolInterfaces (
600 &gEfiSimpleFileSystemProtocolGuid
, &gSemihostFs
,
601 &gEfiDevicePathProtocolGuid
, &gDevicePath
,
605 if (EFI_ERROR(Status
)) {
606 FreePool (mSemihostFsLabel
);