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>
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
;
161 if ((FileName
== NULL
) || (NewHandle
== NULL
)) {
162 return EFI_INVALID_PARAMETER
;
165 // Semihost interface requires ASCII filenames
166 AsciiFileName
= AllocatePool ((StrLen (FileName
) + 1) * sizeof (CHAR8
));
167 if (AsciiFileName
== NULL
) {
168 return EFI_OUT_OF_RESOURCES
;
170 UnicodeStrToAsciiStr (FileName
, AsciiFileName
);
172 if ((AsciiStrCmp (AsciiFileName
, "\\") == 0) ||
173 (AsciiStrCmp (AsciiFileName
, "/") == 0) ||
174 (AsciiStrCmp (AsciiFileName
, "") == 0) ||
175 (AsciiStrCmp (AsciiFileName
, ".") == 0)) {
176 // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
179 // Root directory node doesn't have a name.
180 FreePool (AsciiFileName
);
181 AsciiFileName
= NULL
;
183 // Translate EFI_FILE_MODE into Semihosting mode
184 if (OpenMode
& EFI_FILE_MODE_WRITE
) {
185 SemihostMode
= SEMIHOST_FILE_MODE_WRITE
| SEMIHOST_FILE_MODE_BINARY
;
186 } else if (OpenMode
& EFI_FILE_MODE_READ
) {
187 SemihostMode
= SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
;
189 return EFI_UNSUPPORTED
;
192 // Add the creation flag if necessary
193 if (OpenMode
& EFI_FILE_MODE_CREATE
) {
194 SemihostMode
|= SEMIHOST_FILE_MODE_CREATE
;
197 // Call the semihosting interface to open the file.
198 Status
= SemihostFileOpen (AsciiFileName
, SemihostMode
, &SemihostHandle
);
199 if (EFI_ERROR(Status
)) {
206 // Allocate a control block and fill it
207 FileFcb
= AllocateFCB ();
208 if (FileFcb
== NULL
) {
209 return EFI_OUT_OF_RESOURCES
;
212 FileFcb
->FileName
= AsciiFileName
;
213 FileFcb
->SemihostHandle
= SemihostHandle
;
214 FileFcb
->Position
= 0;
215 FileFcb
->IsRoot
= IsRoot
;
217 InsertTailList (&gFileList
, &FileFcb
->Link
);
219 *NewHandle
= &FileFcb
->File
;
230 SEMIHOST_FCB
*Fcb
= NULL
;
231 EFI_STATUS Status
= EFI_SUCCESS
;
233 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
235 if (Fcb
->IsRoot
== TRUE
) {
237 Status
= EFI_SUCCESS
;
239 Status
= SemihostFileClose (Fcb
->SemihostHandle
);
240 if (!EFI_ERROR(Status
)) {
241 FreePool (Fcb
->FileName
);
254 SEMIHOST_FCB
*Fcb
= NULL
;
259 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
262 // Get the filename from the Fcb
263 NameSize
= AsciiStrLen (Fcb
->FileName
);
264 FileName
= AllocatePool (NameSize
+ 1);
266 AsciiStrCpy (FileName
, Fcb
->FileName
);
268 // Close the file if it's open. Disregard return status,
269 // since it might give an error if the file isn't open.
272 // Call the semihost interface to delete the file.
273 Status
= SemihostFileRemove (FileName
);
275 Status
= EFI_UNSUPPORTED
;
284 IN OUT UINTN
*BufferSize
,
288 SEMIHOST_FCB
*Fcb
= NULL
;
291 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
293 if (Fcb
->IsRoot
== TRUE
) {
294 // By design, the Semihosting feature does not allow to list files on the host machine.
295 Status
= EFI_UNSUPPORTED
;
297 Status
= SemihostFileRead (Fcb
->SemihostHandle
, BufferSize
, Buffer
);
298 if (!EFI_ERROR (Status
)) {
299 Fcb
->Position
+= *BufferSize
;
309 IN OUT UINTN
*BufferSize
,
313 SEMIHOST_FCB
*Fcb
= NULL
;
315 UINTN WriteSize
= *BufferSize
;
317 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
319 Status
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, Buffer
);
321 if (!EFI_ERROR(Status
)) {
322 // Semihost write return the number of bytes *NOT* written.
323 *BufferSize
-= WriteSize
;
324 Fcb
->Position
+= *BufferSize
;
336 SEMIHOST_FCB
*Fcb
= NULL
;
338 if (Position
== NULL
) {
339 return EFI_INVALID_PARAMETER
;
342 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
344 *Position
= Fcb
->Position
;
355 SEMIHOST_FCB
*Fcb
= NULL
;
359 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
362 Status
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
363 if (!EFI_ERROR(Status
) && (Length
< Position
)) {
367 Status
= SemihostFileSeek (Fcb
->SemihostHandle
, (UINT32
)Position
);
368 if (!EFI_ERROR(Status
)) {
369 Fcb
->Position
= Position
;
372 Fcb
->Position
= Position
;
373 Status
= EFI_SUCCESS
;
382 IN SEMIHOST_FCB
*Fcb
,
383 IN OUT UINTN
*BufferSize
,
387 EFI_FILE_INFO
*Info
= NULL
;
394 if (Fcb
->IsRoot
== TRUE
) {
395 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ sizeof(CHAR16
);
397 NameSize
= AsciiStrLen (Fcb
->FileName
) + 1;
398 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ NameSize
* sizeof (CHAR16
);
401 if (*BufferSize
< ResultSize
) {
402 *BufferSize
= ResultSize
;
403 return EFI_BUFFER_TOO_SMALL
;
408 // Zero out the structure
409 ZeroMem (Info
, SIZE_OF_EFI_FILE_INFO
);
411 // Fill in the structure
412 Info
->Size
= ResultSize
;
414 if (Fcb
->IsRoot
== TRUE
) {
415 Info
->Attribute
= EFI_FILE_READ_ONLY
| EFI_FILE_DIRECTORY
;
416 Info
->FileName
[0] = L
'\0';
418 Status
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
419 if (EFI_ERROR(Status
)) {
423 Info
->FileSize
= Length
;
424 Info
->PhysicalSize
= Length
;
426 for (Index
= 0; Index
< NameSize
; Index
++) {
427 Info
->FileName
[Index
] = Fcb
->FileName
[Index
];
432 *BufferSize
= ResultSize
;
440 IN SEMIHOST_FCB
*Fcb
,
441 IN OUT UINTN
*BufferSize
,
445 EFI_FILE_SYSTEM_INFO
*Info
= NULL
;
447 STATIC CHAR16 Label
[] = L
"SemihostFs";
448 UINTN ResultSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize(Label
);
450 if(*BufferSize
>= ResultSize
) {
451 ZeroMem (Buffer
, ResultSize
);
452 Status
= EFI_SUCCESS
;
456 Info
->Size
= ResultSize
;
457 Info
->ReadOnly
= FALSE
;
458 Info
->VolumeSize
= 0;
462 StrCpy (Info
->VolumeLabel
, Label
);
464 Status
= EFI_BUFFER_TOO_SMALL
;
467 *BufferSize
= ResultSize
;
474 IN EFI_GUID
*InformationType
,
475 IN OUT UINTN
*BufferSize
,
479 SEMIHOST_FCB
*Fcb
= NULL
;
480 EFI_STATUS Status
= EFI_UNSUPPORTED
;
482 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
484 if (CompareGuid(InformationType
, &gEfiFileSystemInfoGuid
) != 0) {
485 Status
= GetFilesystemInfo(Fcb
, BufferSize
, Buffer
);
486 } else if (CompareGuid(InformationType
, &gEfiFileInfoGuid
) != 0) {
487 Status
= GetFileInfo(Fcb
, BufferSize
, Buffer
);
496 IN EFI_GUID
*InformationType
,
501 return EFI_UNSUPPORTED
;
513 SemihostFsEntryPoint (
514 IN EFI_HANDLE ImageHandle
,
515 IN EFI_SYSTEM_TABLE
*SystemTable
518 EFI_STATUS Status
= EFI_NOT_FOUND
;
520 if (SemihostConnectionSupported ()) {
521 Status
= gBS
->InstallMultipleProtocolInterfaces (
523 &gEfiSimpleFileSystemProtocolGuid
, &gSemihostFs
,
524 &gEfiDevicePathProtocolGuid
, &gDevicePath
,