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
;
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 Status
= EFI_UNSUPPORTED
;
296 Status
= SemihostFileRead (Fcb
->SemihostHandle
, BufferSize
, Buffer
);
297 if (!EFI_ERROR (Status
)) {
298 Fcb
->Position
+= *BufferSize
;
308 IN OUT UINTN
*BufferSize
,
312 SEMIHOST_FCB
*Fcb
= NULL
;
314 UINTN WriteSize
= *BufferSize
;
316 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
318 Status
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, Buffer
);
320 if (!EFI_ERROR(Status
)) {
321 // Semihost write return the number of bytes *NOT* written.
322 *BufferSize
-= WriteSize
;
323 Fcb
->Position
+= *BufferSize
;
335 SEMIHOST_FCB
*Fcb
= NULL
;
337 if (Position
== NULL
) {
338 return EFI_INVALID_PARAMETER
;
341 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
343 *Position
= Fcb
->Position
;
354 SEMIHOST_FCB
*Fcb
= NULL
;
358 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
361 Status
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
362 if (!EFI_ERROR(Status
) && (Length
< Position
)) {
366 Status
= SemihostFileSeek (Fcb
->SemihostHandle
, (UINT32
)Position
);
367 if (!EFI_ERROR(Status
)) {
368 Fcb
->Position
= Position
;
371 Fcb
->Position
= Position
;
372 Status
= EFI_SUCCESS
;
381 IN SEMIHOST_FCB
*Fcb
,
382 IN OUT UINTN
*BufferSize
,
386 EFI_FILE_INFO
*Info
= NULL
;
393 if (Fcb
->IsRoot
== TRUE
) {
394 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ sizeof(CHAR16
);
396 NameSize
= AsciiStrLen (Fcb
->FileName
) + 1;
397 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ NameSize
* sizeof (CHAR16
);
400 if (*BufferSize
< ResultSize
) {
401 *BufferSize
= ResultSize
;
402 return EFI_BUFFER_TOO_SMALL
;
407 // Zero out the structure
408 ZeroMem (Info
, SIZE_OF_EFI_FILE_INFO
);
410 // Fill in the structure
411 Info
->Size
= ResultSize
;
413 if (Fcb
->IsRoot
== TRUE
) {
414 Info
->Attribute
= EFI_FILE_READ_ONLY
| EFI_FILE_DIRECTORY
;
415 Info
->FileName
[0] = L
'\0';
417 Status
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
418 if (EFI_ERROR(Status
)) {
422 Info
->FileSize
= Length
;
423 Info
->PhysicalSize
= Length
;
425 for (Index
= 0; Index
< NameSize
; Index
++) {
426 Info
->FileName
[Index
] = Fcb
->FileName
[Index
];
431 *BufferSize
= ResultSize
;
439 IN SEMIHOST_FCB
*Fcb
,
440 IN OUT UINTN
*BufferSize
,
444 EFI_FILE_SYSTEM_INFO
*Info
= NULL
;
446 STATIC CHAR16 Label
[] = L
"SemihostFs";
447 UINTN ResultSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize(Label
);
449 if(*BufferSize
>= ResultSize
) {
450 ZeroMem (Buffer
, ResultSize
);
451 Status
= EFI_SUCCESS
;
455 Info
->Size
= ResultSize
;
456 Info
->ReadOnly
= FALSE
;
457 Info
->VolumeSize
= 0;
461 StrCpy (Info
->VolumeLabel
, Label
);
463 Status
= EFI_BUFFER_TOO_SMALL
;
466 *BufferSize
= ResultSize
;
473 IN EFI_GUID
*InformationType
,
474 IN OUT UINTN
*BufferSize
,
478 SEMIHOST_FCB
*Fcb
= NULL
;
479 EFI_STATUS Status
= EFI_UNSUPPORTED
;
481 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
483 if (CompareGuid(InformationType
, &gEfiFileSystemInfoGuid
) != 0) {
484 Status
= GetFilesystemInfo(Fcb
, BufferSize
, Buffer
);
485 } else if (CompareGuid(InformationType
, &gEfiFileInfoGuid
) != 0) {
486 Status
= GetFileInfo(Fcb
, BufferSize
, Buffer
);
495 IN EFI_GUID
*InformationType
,
500 return EFI_UNSUPPORTED
;
512 SemihostFsEntryPoint (
513 IN EFI_HANDLE ImageHandle
,
514 IN EFI_SYSTEM_TABLE
*SystemTable
517 EFI_STATUS Status
= EFI_NOT_FOUND
;
519 if (SemihostConnectionSupported ()) {
520 Status
= gBS
->InstallMultipleProtocolInterfaces (
522 &gEfiSimpleFileSystemProtocolGuid
, &gSemihostFs
,
523 &gEfiDevicePathProtocolGuid
, &gDevicePath
,