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, 2012, 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>
22 #include <Library/BaseLib.h>
23 #include <Library/BaseMemoryLib.h>
24 #include <Library/DebugLib.h>
25 #include <Library/MemoryAllocationLib.h>
26 #include <Library/SemihostLib.h>
27 #include <Library/UefiBootServicesTableLib.h>
28 #include <Library/UefiLib.h>
30 #include <Protocol/DevicePath.h>
31 #include <Protocol/SimpleFileSystem.h>
33 #include "SemihostFs.h"
36 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gSemihostFs
= {
37 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
,
41 EFI_FILE gSemihostFsFile
= {
42 EFI_FILE_PROTOCOL_REVISION
,
56 // Device path for SemiHosting. It contains our autogened Caller ID GUID.
59 VENDOR_DEVICE_PATH Guid
;
60 EFI_DEVICE_PATH_PROTOCOL End
;
61 } SEMIHOST_DEVICE_PATH
;
63 SEMIHOST_DEVICE_PATH gDevicePath
= {
65 { HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, sizeof (VENDOR_DEVICE_PATH
), 0 },
68 { 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
;
138 InsertTailList (&gFileList
, &RootFcb
->Link
);
140 *Root
= &RootFcb
->File
;
148 OUT EFI_FILE
**NewHandle
,
154 SEMIHOST_FCB
*FileFcb
= NULL
;
155 EFI_STATUS Status
= EFI_SUCCESS
;
156 UINTN SemihostHandle
;
157 CHAR8
*AsciiFileName
;
163 if ((FileName
== NULL
) || (NewHandle
== NULL
)) {
164 return EFI_INVALID_PARAMETER
;
167 // Semihost interface requires ASCII filesnames
168 Length
= StrSize (FileName
);
170 AsciiFileName
= AllocatePool (Length
);
171 if (AsciiFileName
== NULL
) {
172 return EFI_OUT_OF_RESOURCES
;
175 AsciiPtr
= AsciiFileName
;
178 *AsciiPtr
++ = *FileName
++ & 0xFF;
181 if ((AsciiStrCmp (AsciiFileName
, "\\") == 0) ||
182 (AsciiStrCmp (AsciiFileName
, "/") == 0) ||
183 (AsciiStrCmp (AsciiFileName
, "") == 0) ||
184 (AsciiStrCmp (AsciiFileName
, ".") == 0)) {
185 // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
188 // Root directory node doesn't have a name.
189 FreePool (AsciiFileName
);
190 AsciiFileName
= NULL
;
192 // Translate EFI_FILE_MODE into Semihosting mode
193 if (OpenMode
& EFI_FILE_MODE_WRITE
) {
194 SemihostMode
= SEMIHOST_FILE_MODE_WRITE
| SEMIHOST_FILE_MODE_BINARY
;
195 } else if (OpenMode
& EFI_FILE_MODE_READ
) {
196 SemihostMode
= SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
;
198 return EFI_UNSUPPORTED
;
201 // Add the creation flag if necessary
202 if (OpenMode
& EFI_FILE_MODE_CREATE
) {
203 SemihostMode
|= SEMIHOST_FILE_MODE_CREATE
;
206 // Call the semihosting interface to open the file.
207 Status
= SemihostFileOpen (AsciiFileName
, SemihostMode
, &SemihostHandle
);
208 if (EFI_ERROR(Status
)) {
215 // Allocate a control block and fill it
216 FileFcb
= AllocateFCB ();
217 if (FileFcb
== NULL
) {
218 return EFI_OUT_OF_RESOURCES
;
221 FileFcb
->FileName
= AsciiFileName
;
222 FileFcb
->SemihostHandle
= SemihostHandle
;
223 FileFcb
->Position
= 0;
224 FileFcb
->IsRoot
= IsRoot
;
226 InsertTailList (&gFileList
, &FileFcb
->Link
);
228 *NewHandle
= &FileFcb
->File
;
239 SEMIHOST_FCB
*Fcb
= NULL
;
240 EFI_STATUS Status
= EFI_SUCCESS
;
242 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
244 if (Fcb
->IsRoot
== TRUE
) {
246 Status
= EFI_SUCCESS
;
248 Status
= SemihostFileClose (Fcb
->SemihostHandle
);
249 if (!EFI_ERROR(Status
)) {
250 FreePool (Fcb
->FileName
);
263 SEMIHOST_FCB
*Fcb
= NULL
;
268 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
271 // Get the filename from the Fcb
272 NameSize
= AsciiStrLen (Fcb
->FileName
);
273 FileName
= AllocatePool (NameSize
+ 1);
275 AsciiStrCpy (FileName
, Fcb
->FileName
);
277 // Close the file if it's open. Disregard return status,
278 // since it might give an error if the file isn't open.
281 // Call the semihost interface to delete the file.
282 Status
= SemihostFileRemove (FileName
);
284 Status
= EFI_UNSUPPORTED
;
293 IN OUT UINTN
*BufferSize
,
297 SEMIHOST_FCB
*Fcb
= NULL
;
300 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
302 if (Fcb
->IsRoot
== TRUE
) {
303 Status
= EFI_UNSUPPORTED
;
305 Status
= SemihostFileRead (Fcb
->SemihostHandle
, BufferSize
, Buffer
);
306 if (!EFI_ERROR (Status
)) {
307 Fcb
->Position
+= *BufferSize
;
317 IN OUT UINTN
*BufferSize
,
321 SEMIHOST_FCB
*Fcb
= NULL
;
323 UINTN WriteSize
= *BufferSize
;
325 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
327 Status
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, Buffer
);
329 if (!EFI_ERROR(Status
)) {
330 // Semihost write return the number of bytes *NOT* written.
331 *BufferSize
-= WriteSize
;
332 Fcb
->Position
+= *BufferSize
;
344 SEMIHOST_FCB
*Fcb
= NULL
;
346 if (Position
== NULL
) {
347 return EFI_INVALID_PARAMETER
;
350 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
352 *Position
= Fcb
->Position
;
363 SEMIHOST_FCB
*Fcb
= NULL
;
367 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
370 Status
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
371 if (!EFI_ERROR(Status
) && (Length
< Position
)) {
375 Status
= SemihostFileSeek (Fcb
->SemihostHandle
, (UINT32
)Position
);
376 if (!EFI_ERROR(Status
)) {
377 Fcb
->Position
= Position
;
380 Fcb
->Position
= Position
;
381 Status
= EFI_SUCCESS
;
390 IN SEMIHOST_FCB
*Fcb
,
391 IN OUT UINTN
*BufferSize
,
395 EFI_FILE_INFO
*Info
= NULL
;
402 if (Fcb
->IsRoot
== TRUE
) {
403 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ sizeof(CHAR16
);
405 NameSize
= AsciiStrLen (Fcb
->FileName
) + 1;
406 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ NameSize
* sizeof (CHAR16
);
409 if (*BufferSize
< ResultSize
) {
410 *BufferSize
= ResultSize
;
411 return EFI_BUFFER_TOO_SMALL
;
416 // Zero out the structure
417 ZeroMem (Info
, SIZE_OF_EFI_FILE_INFO
);
419 // Fill in the structure
420 Info
->Size
= ResultSize
;
422 if (Fcb
->IsRoot
== TRUE
) {
423 Info
->Attribute
= EFI_FILE_READ_ONLY
| EFI_FILE_DIRECTORY
;
424 Info
->FileName
[0] = L
'\0';
426 Status
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
427 if (EFI_ERROR(Status
)) {
431 Info
->FileSize
= Length
;
432 Info
->PhysicalSize
= Length
;
434 for (Index
= 0; Index
< NameSize
; Index
++) {
435 Info
->FileName
[Index
] = Fcb
->FileName
[Index
];
440 *BufferSize
= ResultSize
;
448 IN SEMIHOST_FCB
*Fcb
,
449 IN OUT UINTN
*BufferSize
,
453 EFI_FILE_SYSTEM_INFO
*Info
= NULL
;
455 STATIC CHAR16 Label
[] = L
"SemihostFs";
456 UINTN ResultSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize(Label
);
458 if(*BufferSize
>= ResultSize
) {
459 ZeroMem (Buffer
, ResultSize
);
460 Status
= EFI_SUCCESS
;
464 Info
->Size
= ResultSize
;
465 Info
->ReadOnly
= FALSE
;
466 Info
->VolumeSize
= 0;
470 StrCpy (Info
->VolumeLabel
, Label
);
472 Status
= EFI_BUFFER_TOO_SMALL
;
475 *BufferSize
= ResultSize
;
482 IN EFI_GUID
*InformationType
,
483 IN OUT UINTN
*BufferSize
,
487 SEMIHOST_FCB
*Fcb
= NULL
;
488 EFI_STATUS Status
= EFI_UNSUPPORTED
;
490 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
492 if (CompareGuid(InformationType
, &gEfiFileSystemInfoGuid
) != 0) {
493 Status
= GetFilesystemInfo(Fcb
, BufferSize
, Buffer
);
494 } else if (CompareGuid(InformationType
, &gEfiFileInfoGuid
) != 0) {
495 Status
= GetFileInfo(Fcb
, BufferSize
, Buffer
);
504 IN EFI_GUID
*InformationType
,
509 return EFI_UNSUPPORTED
;
521 SemihostFsEntryPoint (
522 IN EFI_HANDLE ImageHandle
,
523 IN EFI_SYSTEM_TABLE
*SystemTable
526 EFI_STATUS Status
= EFI_NOT_FOUND
;
528 if (SemihostConnectionSupported ()) {
529 Status
= gBS
->InstallMultipleProtocolInterfaces (
531 &gEfiSimpleFileSystemProtocolGuid
, &gSemihostFs
,
532 &gEfiDevicePathProtocolGuid
, &gDevicePath
,