2 Support a Semi Host file system over a debuggers JTAG
4 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include <Guid/FileInfo.h>
19 #include <Guid/FileSystemInfo.h>
21 #include <Library/BaseLib.h>
22 #include <Library/BaseMemoryLib.h>
23 #include <Library/DebugLib.h>
24 #include <Library/MemoryAllocationLib.h>
25 #include <Library/SemihostLib.h>
26 #include <Library/UefiBootServicesTableLib.h>
27 #include <Library/UefiLib.h>
29 #include <Protocol/DevicePath.h>
30 #include <Protocol/SimpleFileSystem.h>
32 #include "SemihostFs.h"
35 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gSemihostFs
= {
36 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
,
40 EFI_FILE gSemihostFsFile
= {
41 EFI_FILE_PROTOCOL_REVISION
,
55 // Device path for SemiHosting. It contains our autogened Caller ID GUID.
58 VENDOR_DEVICE_PATH Guid
;
59 EFI_DEVICE_PATH_PROTOCOL End
;
60 } SEMIHOST_DEVICE_PATH
;
62 SEMIHOST_DEVICE_PATH gDevicePath
= {
64 { HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, sizeof (VENDOR_DEVICE_PATH
), 0 },
67 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
, sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0}
76 UINT32 SemihostHandle
;
80 #define SEMIHOST_FCB_SIGNATURE SIGNATURE_32( 'S', 'H', 'F', 'C' )
81 #define SEMIHOST_FCB_FROM_THIS(a) CR(a, SEMIHOST_FCB, File, SEMIHOST_FCB_SIGNATURE)
82 #define SEMIHOST_FCB_FROM_LINK(a) CR(a, SEMIHOST_FCB, Link, SEMIHOST_FCB_SIGNATURE);
84 EFI_HANDLE gInstallHandle
= NULL
;
85 LIST_ENTRY gFileList
= INITIALIZE_LIST_HEAD_VARIABLE (gFileList
);
92 SEMIHOST_FCB
*Fcb
= AllocateZeroPool (sizeof (SEMIHOST_FCB
));
95 CopyMem (&Fcb
->File
, &gSemihostFsFile
, sizeof (gSemihostFsFile
));
96 Fcb
->Signature
= SEMIHOST_FCB_SIGNATURE
;
107 // Remove Fcb from gFileList.
108 RemoveEntryList (&Fcb
->Link
);
110 // To help debugging...
120 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
124 SEMIHOST_FCB
*RootFcb
= NULL
;
127 return EFI_INVALID_PARAMETER
;
130 RootFcb
= AllocateFCB ();
131 if (RootFcb
== NULL
) {
132 return EFI_OUT_OF_RESOURCES
;
135 RootFcb
->IsRoot
= TRUE
;
137 InsertTailList (&gFileList
, &RootFcb
->Link
);
139 *Root
= &RootFcb
->File
;
147 OUT EFI_FILE
**NewHandle
,
153 SEMIHOST_FCB
*FileFcb
= NULL
;
154 EFI_STATUS Status
= EFI_SUCCESS
;
155 UINT32 SemihostHandle
;
156 CHAR8
*AsciiFileName
;
162 if ((FileName
== NULL
) || (NewHandle
== NULL
)) {
163 return EFI_INVALID_PARAMETER
;
166 // Semihost interface requires ASCII filesnames
167 Length
= StrSize (FileName
);
169 AsciiFileName
= AllocatePool (Length
);
170 if (AsciiFileName
== NULL
) {
171 return EFI_OUT_OF_RESOURCES
;
174 AsciiPtr
= AsciiFileName
;
177 *AsciiPtr
++ = *FileName
++ & 0xFF;
180 if ((AsciiStrCmp (AsciiFileName
, "\\") == 0) || (AsciiStrCmp (AsciiFileName
, "/") == 0) || (AsciiStrCmp (AsciiFileName
, "") == 0)) {
181 // Opening '/', '\', or the NULL pathname is trying to open the root directory
184 // Root directory node doesn't have a name.
185 FreePool (AsciiFileName
);
186 AsciiFileName
= NULL
;
188 // Translate EFI_FILE_MODE into Semihosting mode
189 if (OpenMode
& EFI_FILE_MODE_WRITE
) {
190 SemihostMode
= SEMIHOST_FILE_MODE_WRITE
| SEMIHOST_FILE_MODE_BINARY
;
191 } else if (OpenMode
& EFI_FILE_MODE_READ
) {
192 SemihostMode
= SEMIHOST_FILE_MODE_READ
| SEMIHOST_FILE_MODE_BINARY
;
194 return EFI_UNSUPPORTED
;
197 // Add the creation flag if necessary
198 if (OpenMode
& EFI_FILE_MODE_CREATE
) {
199 SemihostMode
|= SEMIHOST_FILE_MODE_CREATE
;
202 // Call the semihosting interface to open the file.
203 Status
= SemihostFileOpen (AsciiFileName
, SemihostMode
, &SemihostHandle
);
204 if (EFI_ERROR(Status
)) {
211 // Allocate a control block and fill it
212 FileFcb
= AllocateFCB ();
213 if (FileFcb
== NULL
) {
214 return EFI_OUT_OF_RESOURCES
;
217 FileFcb
->FileName
= AsciiFileName
;
218 FileFcb
->SemihostHandle
= SemihostHandle
;
219 FileFcb
->Position
= 0;
220 FileFcb
->IsRoot
= IsRoot
;
222 InsertTailList (&gFileList
, &FileFcb
->Link
);
224 *NewHandle
= &FileFcb
->File
;
235 SEMIHOST_FCB
*Fcb
= NULL
;
236 EFI_STATUS Status
= EFI_SUCCESS
;
238 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
240 if (Fcb
->IsRoot
== TRUE
) {
242 Status
= EFI_SUCCESS
;
244 Status
= SemihostFileClose (Fcb
->SemihostHandle
);
245 if (!EFI_ERROR(Status
)) {
246 FreePool (Fcb
->FileName
);
259 SEMIHOST_FCB
*Fcb
= NULL
;
264 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
267 // Get the filename from the Fcb
268 NameSize
= AsciiStrLen (Fcb
->FileName
);
269 FileName
= AllocatePool (NameSize
+ 1);
271 AsciiStrCpy (FileName
, Fcb
->FileName
);
273 // Close the file if it's open. Disregard return status,
274 // since it might give an error if the file isn't open.
277 // Call the semihost interface to delete the file.
278 Status
= SemihostFileRemove (FileName
);
280 Status
= EFI_UNSUPPORTED
;
289 IN OUT UINTN
*BufferSize
,
293 SEMIHOST_FCB
*Fcb
= NULL
;
296 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
298 if (Fcb
->IsRoot
== TRUE
) {
299 Status
= EFI_UNSUPPORTED
;
301 Status
= SemihostFileRead (Fcb
->SemihostHandle
, BufferSize
, Buffer
);
302 if (!EFI_ERROR (Status
)) {
303 Fcb
->Position
+= *BufferSize
;
313 IN OUT UINTN
*BufferSize
,
317 SEMIHOST_FCB
*Fcb
= NULL
;
319 UINTN WriteSize
= *BufferSize
;
321 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
323 Status
= SemihostFileWrite (Fcb
->SemihostHandle
, &WriteSize
, Buffer
);
325 if (!EFI_ERROR(Status
)) {
326 // Semihost write return the number of bytes *NOT* written.
327 *BufferSize
-= WriteSize
;
328 Fcb
->Position
+= *BufferSize
;
340 SEMIHOST_FCB
*Fcb
= NULL
;
342 if (Position
== NULL
) {
343 return EFI_INVALID_PARAMETER
;
346 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
348 *Position
= Fcb
->Position
;
359 SEMIHOST_FCB
*Fcb
= NULL
;
363 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
366 Status
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
367 if (!EFI_ERROR(Status
) && (Length
< Position
)) {
371 Status
= SemihostFileSeek (Fcb
->SemihostHandle
, (UINT32
)Position
);
372 if (!EFI_ERROR(Status
)) {
373 Fcb
->Position
= Position
;
376 Fcb
->Position
= Position
;
377 Status
= EFI_SUCCESS
;
386 IN SEMIHOST_FCB
*Fcb
,
387 IN OUT UINTN
*BufferSize
,
391 EFI_FILE_INFO
*Info
= NULL
;
398 if (Fcb
->IsRoot
== TRUE
) {
399 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ sizeof(CHAR16
);
401 NameSize
= AsciiStrLen (Fcb
->FileName
) + 1;
402 ResultSize
= SIZE_OF_EFI_FILE_INFO
+ NameSize
* sizeof (CHAR16
);
405 if (*BufferSize
< ResultSize
) {
406 *BufferSize
= ResultSize
;
407 return EFI_BUFFER_TOO_SMALL
;
412 // Zero out the structure
413 ZeroMem (Info
, SIZE_OF_EFI_FILE_INFO
);
415 // Fill in the structure
416 Info
->Size
= ResultSize
;
418 if (Fcb
->IsRoot
== TRUE
) {
419 Info
->Attribute
= EFI_FILE_READ_ONLY
| EFI_FILE_DIRECTORY
;
420 Info
->FileName
[0] = L
'\0';
422 Status
= SemihostFileLength (Fcb
->SemihostHandle
, &Length
);
423 if (EFI_ERROR(Status
)) {
427 Info
->FileSize
= Length
;
428 Info
->PhysicalSize
= Length
;
430 for (Index
= 0; Index
< NameSize
; Index
++) {
431 Info
->FileName
[Index
] = Fcb
->FileName
[Index
];
436 *BufferSize
= ResultSize
;
444 IN SEMIHOST_FCB
*Fcb
,
445 IN OUT UINTN
*BufferSize
,
449 EFI_FILE_SYSTEM_INFO
*Info
= NULL
;
451 STATIC CHAR16 Label
[] = L
"SemihostFs";
452 UINTN ResultSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize(Label
);
454 if(*BufferSize
>= ResultSize
) {
455 ZeroMem (Buffer
, ResultSize
);
456 Status
= EFI_SUCCESS
;
460 Info
->Size
= ResultSize
;
461 Info
->ReadOnly
= FALSE
;
462 Info
->VolumeSize
= 0;
466 StrCpy (Info
->VolumeLabel
, Label
);
468 Status
= EFI_BUFFER_TOO_SMALL
;
471 *BufferSize
= ResultSize
;
478 IN EFI_GUID
*InformationType
,
479 IN OUT UINTN
*BufferSize
,
483 SEMIHOST_FCB
*Fcb
= NULL
;
484 EFI_STATUS Status
= EFI_UNSUPPORTED
;
486 Fcb
= SEMIHOST_FCB_FROM_THIS(File
);
488 if (CompareGuid(InformationType
, &gEfiFileSystemInfoGuid
) != 0) {
489 Status
= GetFilesystemInfo(Fcb
, BufferSize
, Buffer
);
490 } else if (CompareGuid(InformationType
, &gEfiFileInfoGuid
) != 0) {
491 Status
= GetFileInfo(Fcb
, BufferSize
, Buffer
);
500 IN EFI_GUID
*InformationType
,
505 return EFI_UNSUPPORTED
;
517 SemihostFsEntryPoint (
518 IN EFI_HANDLE ImageHandle
,
519 IN EFI_SYSTEM_TABLE
*SystemTable
522 EFI_STATUS Status
= EFI_NOT_FOUND
;
524 if (SemihostConnectionSupported ()) {
525 Status
= gBS
->InstallMultipleProtocolInterfaces (
527 &gEfiSimpleFileSystemProtocolGuid
, &gSemihostFs
,
528 &gEfiDevicePathProtocolGuid
, &gDevicePath
,