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 - 2013, 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
->OpenMode
& EFI_FILE_READ_ONLY
) {
349 return EFI_ACCESS_DENIED
;
352 Status
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, Buffer
);
354 if (!EFI_ERROR(Status
)) {
355 // Semihost write return the number of bytes *NOT* written.
356 *BufferSize
-= WriteSize
;
357 Fcb
->Position
+= *BufferSize
;
369 SEMIHOST_FCB
*Fcb
= NULL
;
371 if (Position
== NULL
) {
372 return EFI_INVALID_PARAMETER
;
375 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
377 *Position
= Fcb
->Position
;
388 SEMIHOST_FCB
*Fcb
= NULL
;
392 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
395 Status
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
396 if (!EFI_ERROR(Status
) && (Length
< Position
)) {
400 Status
= SemihostFileSeek (Fcb
->SemihostHandle
, (UINT32
)Position
);
401 if (!EFI_ERROR(Status
)) {
402 Fcb
->Position
= Position
;
405 Fcb
->Position
= Position
;
406 Status
= EFI_SUCCESS
;
415 IN SEMIHOST_FCB
*Fcb
,
416 IN OUT UINTN
*BufferSize
,
420 EFI_FILE_INFO
*Info
= NULL
;
425 if (Fcb
->IsRoot
== TRUE
) {
426 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ sizeof(CHAR16
);
428 NameSize
= AsciiStrLen (Fcb
->FileName
) + 1;
429 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ NameSize
* sizeof (CHAR16
);
432 if (*BufferSize
< ResultSize
) {
433 *BufferSize
= ResultSize
;
434 return EFI_BUFFER_TOO_SMALL
;
439 // Copy the current file info
440 CopyMem (Info
, &Fcb
->Info
, SIZE_OF_EFI_FILE_INFO
);
442 // Fill in the structure
443 Info
->Size
= ResultSize
;
445 if (Fcb
->IsRoot
== TRUE
) {
446 Info
->FileName
[0] = L
'\0';
448 for (Index
= 0; Index
< NameSize
; Index
++) {
449 Info
->FileName
[Index
] = Fcb
->FileName
[Index
];
453 *BufferSize
= ResultSize
;
461 IN SEMIHOST_FCB
*Fcb
,
462 IN OUT UINTN
*BufferSize
,
466 EFI_FILE_SYSTEM_INFO
*Info
= NULL
;
468 UINTN ResultSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (mSemihostFsLabel
);
470 if (*BufferSize
>= ResultSize
) {
471 ZeroMem (Buffer
, ResultSize
);
472 Status
= EFI_SUCCESS
;
476 Info
->Size
= ResultSize
;
477 Info
->ReadOnly
= FALSE
;
478 Info
->VolumeSize
= 0;
482 StrCpy (Info
->VolumeLabel
, mSemihostFsLabel
);
484 Status
= EFI_BUFFER_TOO_SMALL
;
487 *BufferSize
= ResultSize
;
494 IN EFI_GUID
*InformationType
,
495 IN OUT UINTN
*BufferSize
,
503 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
505 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
) != 0) {
506 Status
= GetFilesystemInfo (Fcb
, BufferSize
, Buffer
);
507 } else if (CompareGuid (InformationType
, &gEfiFileInfoGuid
) != 0) {
508 Status
= GetFileInfo (Fcb
, BufferSize
, Buffer
);
509 } else if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
) != 0) {
510 ResultSize
= StrSize (mSemihostFsLabel
);
512 if (*BufferSize
>= ResultSize
) {
513 StrCpy (Buffer
, mSemihostFsLabel
);
514 Status
= EFI_SUCCESS
;
516 Status
= EFI_BUFFER_TOO_SMALL
;
519 *BufferSize
= ResultSize
;
521 Status
= EFI_UNSUPPORTED
;
530 IN EFI_GUID
*InformationType
,
537 if (Buffer
== NULL
) {
538 return EFI_INVALID_PARAMETER
;
541 Status
= EFI_UNSUPPORTED
;
543 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
) != 0) {
544 //Status = SetFilesystemInfo (Fcb, BufferSize, Buffer);
545 } else if (CompareGuid (InformationType
, &gEfiFileInfoGuid
) != 0) {
546 //Status = SetFileInfo (Fcb, BufferSize, Buffer);
547 } else if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
) != 0) {
548 if (StrSize (Buffer
) > 0) {
549 FreePool (mSemihostFsLabel
);
550 mSemihostFsLabel
= AllocateCopyPool (StrSize (Buffer
), Buffer
);
551 Status
= EFI_SUCCESS
;
565 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
570 if (Fcb
->Info
.Attribute
& EFI_FILE_READ_ONLY
) {
571 return EFI_ACCESS_DENIED
;
579 SemihostFsEntryPoint (
580 IN EFI_HANDLE ImageHandle
,
581 IN EFI_SYSTEM_TABLE
*SystemTable
586 Status
= EFI_NOT_FOUND
;
588 if (SemihostConnectionSupported ()) {
589 mSemihostFsLabel
= AllocateCopyPool (StrSize (DEFAULT_SEMIHOST_FS_LABEL
), DEFAULT_SEMIHOST_FS_LABEL
);
590 if (mSemihostFsLabel
== NULL
) {
591 return EFI_OUT_OF_RESOURCES
;
594 Status
= gBS
->InstallMultipleProtocolInterfaces (
596 &gEfiSimpleFileSystemProtocolGuid
, &gSemihostFs
,
597 &gEfiDevicePathProtocolGuid
, &gDevicePath
,
601 if (EFI_ERROR(Status
)) {
602 FreePool (mSemihostFsLabel
);