]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.c
ARM Packages: Removed trailing spaces
[mirror_edk2.git] / ArmPkg / Filesystem / SemihostFs / Arm / SemihostFs.c
1 /** @file
2 Support a Semi Host file system over a debuggers JTAG
3
4 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
5 Portions copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
6
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
11
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.
14
15 **/
16
17 #include <Uefi.h>
18
19 #include <Guid/FileInfo.h>
20 #include <Guid/FileSystemInfo.h>
21 #include <Guid/FileSystemVolumeLabelInfo.h>
22
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>
30
31 #include <Protocol/DevicePath.h>
32 #include <Protocol/SimpleFileSystem.h>
33
34 #include "SemihostFs.h"
35
36 #define DEFAULT_SEMIHOST_FS_LABEL L"SemihostFs"
37
38 STATIC CHAR16 *mSemihostFsLabel;
39
40 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gSemihostFs = {
41 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
42 VolumeOpen
43 };
44
45 EFI_FILE gSemihostFsFile = {
46 EFI_FILE_PROTOCOL_REVISION,
47 FileOpen,
48 FileClose,
49 FileDelete,
50 FileRead,
51 FileWrite,
52 FileGetPosition,
53 FileSetPosition,
54 FileGetInfo,
55 FileSetInfo,
56 FileFlush
57 };
58
59 //
60 // Device path for SemiHosting. It contains our autogened Caller ID GUID.
61 //
62 typedef struct {
63 VENDOR_DEVICE_PATH Guid;
64 EFI_DEVICE_PATH_PROTOCOL End;
65 } SEMIHOST_DEVICE_PATH;
66
67 SEMIHOST_DEVICE_PATH gDevicePath = {
68 {
69 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 } },
70 EFI_CALLER_ID_GUID
71 },
72 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } }
73 };
74
75 typedef struct {
76 LIST_ENTRY Link;
77 UINT64 Signature;
78 EFI_FILE File;
79 CHAR8 *FileName;
80 UINT64 OpenMode;
81 UINT32 Position;
82 UINTN SemihostHandle;
83 BOOLEAN IsRoot;
84 EFI_FILE_INFO Info;
85 } SEMIHOST_FCB;
86
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);
90
91 EFI_HANDLE gInstallHandle = NULL;
92 LIST_ENTRY gFileList = INITIALIZE_LIST_HEAD_VARIABLE (gFileList);
93
94 SEMIHOST_FCB *
95 AllocateFCB (
96 VOID
97 )
98 {
99 SEMIHOST_FCB *Fcb = AllocateZeroPool (sizeof (SEMIHOST_FCB));
100
101 if (Fcb != NULL) {
102 CopyMem (&Fcb->File, &gSemihostFsFile, sizeof (gSemihostFsFile));
103 Fcb->Signature = SEMIHOST_FCB_SIGNATURE;
104 }
105
106 return Fcb;
107 }
108
109 VOID
110 FreeFCB (
111 IN SEMIHOST_FCB *Fcb
112 )
113 {
114 // Remove Fcb from gFileList.
115 RemoveEntryList (&Fcb->Link);
116
117 // To help debugging...
118 Fcb->Signature = 0;
119
120 FreePool (Fcb);
121 }
122
123
124
125 EFI_STATUS
126 VolumeOpen (
127 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
128 OUT EFI_FILE **Root
129 )
130 {
131 SEMIHOST_FCB *RootFcb = NULL;
132
133 if (Root == NULL) {
134 return EFI_INVALID_PARAMETER;
135 }
136
137 RootFcb = AllocateFCB ();
138 if (RootFcb == NULL) {
139 return EFI_OUT_OF_RESOURCES;
140 }
141
142 RootFcb->IsRoot = TRUE;
143 RootFcb->Info.Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
144
145 InsertTailList (&gFileList, &RootFcb->Link);
146
147 *Root = &RootFcb->File;
148
149 return EFI_SUCCESS;
150 }
151
152 EFI_STATUS
153 FileOpen (
154 IN EFI_FILE *File,
155 OUT EFI_FILE **NewHandle,
156 IN CHAR16 *FileName,
157 IN UINT64 OpenMode,
158 IN UINT64 Attributes
159 )
160 {
161 SEMIHOST_FCB *FileFcb = NULL;
162 EFI_STATUS Status = EFI_SUCCESS;
163 UINTN SemihostHandle;
164 CHAR8 *AsciiFileName;
165 UINT32 SemihostMode;
166 BOOLEAN IsRoot;
167 UINTN Length;
168
169 if ((FileName == NULL) || (NewHandle == NULL)) {
170 return EFI_INVALID_PARAMETER;
171 }
172
173 // Semihosting does not support directories
174 if (Attributes & EFI_FILE_DIRECTORY) {
175 return EFI_UNSUPPORTED;
176 }
177
178 // Semihost interface requires ASCII filenames
179 AsciiFileName = AllocatePool ((StrLen (FileName) + 1) * sizeof (CHAR8));
180 if (AsciiFileName == NULL) {
181 return EFI_OUT_OF_RESOURCES;
182 }
183 UnicodeStrToAsciiStr (FileName, AsciiFileName);
184
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
190 IsRoot = TRUE;
191
192 // Root directory node doesn't have a name.
193 FreePool (AsciiFileName);
194 AsciiFileName = NULL;
195 } else {
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;
201 } else {
202 return EFI_UNSUPPORTED;
203 }
204
205 // Add the creation flag if necessary
206 if (OpenMode & EFI_FILE_MODE_CREATE) {
207 SemihostMode |= SEMIHOST_FILE_MODE_CREATE;
208 }
209
210 // Call the semihosting interface to open the file.
211 Status = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);
212 if (EFI_ERROR(Status)) {
213 return Status;
214 }
215
216 IsRoot = FALSE;
217 }
218
219 // Allocate a control block and fill it
220 FileFcb = AllocateFCB ();
221 if (FileFcb == NULL) {
222 return EFI_OUT_OF_RESOURCES;
223 }
224
225 FileFcb->FileName = AsciiFileName;
226 FileFcb->SemihostHandle = SemihostHandle;
227 FileFcb->Position = 0;
228 FileFcb->IsRoot = IsRoot;
229 FileFcb->OpenMode = OpenMode;
230
231 if (!IsRoot) {
232 Status = SemihostFileLength (SemihostHandle, &Length);
233 if (EFI_ERROR(Status)) {
234 return Status;
235 }
236
237 FileFcb->Info.FileSize = Length;
238 FileFcb->Info.PhysicalSize = Length;
239 FileFcb->Info.Attribute = Attributes;
240 }
241
242 InsertTailList (&gFileList, &FileFcb->Link);
243
244 *NewHandle = &FileFcb->File;
245
246 return Status;
247 }
248
249
250 EFI_STATUS
251 FileClose (
252 IN EFI_FILE *File
253 )
254 {
255 SEMIHOST_FCB *Fcb = NULL;
256 EFI_STATUS Status = EFI_SUCCESS;
257
258 Fcb = SEMIHOST_FCB_FROM_THIS(File);
259
260 if (Fcb->IsRoot == TRUE) {
261 FreeFCB (Fcb);
262 Status = EFI_SUCCESS;
263 } else {
264 Status = SemihostFileClose (Fcb->SemihostHandle);
265 if (!EFI_ERROR(Status)) {
266 FreePool (Fcb->FileName);
267 FreeFCB (Fcb);
268 }
269 }
270
271 return Status;
272 }
273
274 EFI_STATUS
275 FileDelete (
276 IN EFI_FILE *File
277 )
278 {
279 SEMIHOST_FCB *Fcb = NULL;
280 EFI_STATUS Status;
281 CHAR8 *FileName;
282 UINTN NameSize;
283
284 Fcb = SEMIHOST_FCB_FROM_THIS(File);
285
286 if (!Fcb->IsRoot) {
287 // Get the filename from the Fcb
288 NameSize = AsciiStrLen (Fcb->FileName);
289 FileName = AllocatePool (NameSize + 1);
290
291 AsciiStrCpy (FileName, Fcb->FileName);
292
293 // Close the file if it's open. Disregard return status,
294 // since it might give an error if the file isn't open.
295 File->Close (File);
296
297 // Call the semihost interface to delete the file.
298 Status = SemihostFileRemove (FileName);
299 if (EFI_ERROR(Status)) {
300 Status = EFI_WARN_DELETE_FAILURE;
301 }
302 } else {
303 Status = EFI_WARN_DELETE_FAILURE;
304 }
305
306 return Status;
307 }
308
309 EFI_STATUS
310 FileRead (
311 IN EFI_FILE *File,
312 IN OUT UINTN *BufferSize,
313 OUT VOID *Buffer
314 )
315 {
316 SEMIHOST_FCB *Fcb = NULL;
317 EFI_STATUS Status;
318
319 Fcb = SEMIHOST_FCB_FROM_THIS(File);
320
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;
324 } else {
325 Status = SemihostFileRead (Fcb->SemihostHandle, BufferSize, Buffer);
326 if (!EFI_ERROR (Status)) {
327 Fcb->Position += *BufferSize;
328 }
329 }
330
331 return Status;
332 }
333
334 EFI_STATUS
335 FileWrite (
336 IN EFI_FILE *File,
337 IN OUT UINTN *BufferSize,
338 IN VOID *Buffer
339 )
340 {
341 SEMIHOST_FCB *Fcb = NULL;
342 EFI_STATUS Status;
343 UINTN WriteSize = *BufferSize;
344
345 Fcb = SEMIHOST_FCB_FROM_THIS(File);
346
347 // We cannot write a read-only file
348 if ((Fcb->Info.Attribute & EFI_FILE_READ_ONLY)
349 || !(Fcb->OpenMode & EFI_FILE_MODE_WRITE)) {
350 return EFI_ACCESS_DENIED;
351 }
352
353 Status = SemihostFileWrite (Fcb->SemihostHandle, &WriteSize, Buffer);
354
355 if (!EFI_ERROR(Status)) {
356 // Semihost write return the number of bytes *NOT* written.
357 *BufferSize -= WriteSize;
358 Fcb->Position += *BufferSize;
359 }
360
361 return Status;
362 }
363
364 EFI_STATUS
365 FileGetPosition (
366 IN EFI_FILE *File,
367 OUT UINT64 *Position
368 )
369 {
370 SEMIHOST_FCB *Fcb = NULL;
371
372 if (Position == NULL) {
373 return EFI_INVALID_PARAMETER;
374 }
375
376 Fcb = SEMIHOST_FCB_FROM_THIS(File);
377
378 *Position = Fcb->Position;
379
380 return EFI_SUCCESS;
381 }
382
383 EFI_STATUS
384 FileSetPosition (
385 IN EFI_FILE *File,
386 IN UINT64 Position
387 )
388 {
389 SEMIHOST_FCB *Fcb = NULL;
390 UINTN Length;
391 EFI_STATUS Status;
392
393 Fcb = SEMIHOST_FCB_FROM_THIS(File);
394
395 if (!Fcb->IsRoot) {
396 Status = SemihostFileLength (Fcb->SemihostHandle, &Length);
397 if (!EFI_ERROR(Status) && (Length < Position)) {
398 Position = Length;
399 }
400
401 Status = SemihostFileSeek (Fcb->SemihostHandle, (UINT32)Position);
402 if (!EFI_ERROR(Status)) {
403 Fcb->Position = Position;
404 }
405 } else {
406 Fcb->Position = Position;
407 Status = EFI_SUCCESS;
408 }
409
410 return Status;
411 }
412
413 STATIC
414 EFI_STATUS
415 GetFileInfo (
416 IN SEMIHOST_FCB *Fcb,
417 IN OUT UINTN *BufferSize,
418 OUT VOID *Buffer
419 )
420 {
421 EFI_FILE_INFO *Info = NULL;
422 UINTN NameSize = 0;
423 UINTN ResultSize;
424 UINTN Index;
425
426 if (Fcb->IsRoot == TRUE) {
427 ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);
428 } else {
429 NameSize = AsciiStrLen (Fcb->FileName) + 1;
430 ResultSize = SIZE_OF_EFI_FILE_INFO + NameSize * sizeof (CHAR16);
431 }
432
433 if (*BufferSize < ResultSize) {
434 *BufferSize = ResultSize;
435 return EFI_BUFFER_TOO_SMALL;
436 }
437
438 Info = Buffer;
439
440 // Copy the current file info
441 CopyMem (Info, &Fcb->Info, SIZE_OF_EFI_FILE_INFO);
442
443 // Fill in the structure
444 Info->Size = ResultSize;
445
446 if (Fcb->IsRoot == TRUE) {
447 Info->FileName[0] = L'\0';
448 } else {
449 for (Index = 0; Index < NameSize; Index++) {
450 Info->FileName[Index] = Fcb->FileName[Index];
451 }
452 }
453
454 *BufferSize = ResultSize;
455
456 return EFI_SUCCESS;
457 }
458
459 STATIC
460 EFI_STATUS
461 GetFilesystemInfo (
462 IN SEMIHOST_FCB *Fcb,
463 IN OUT UINTN *BufferSize,
464 OUT VOID *Buffer
465 )
466 {
467 EFI_FILE_SYSTEM_INFO *Info = NULL;
468 EFI_STATUS Status;
469 UINTN ResultSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (mSemihostFsLabel);
470
471 if (*BufferSize >= ResultSize) {
472 ZeroMem (Buffer, ResultSize);
473 Status = EFI_SUCCESS;
474
475 Info = Buffer;
476
477 Info->Size = ResultSize;
478 Info->ReadOnly = FALSE;
479 Info->VolumeSize = 0;
480 Info->FreeSpace = 0;
481 Info->BlockSize = 0;
482
483 StrCpy (Info->VolumeLabel, mSemihostFsLabel);
484 } else {
485 Status = EFI_BUFFER_TOO_SMALL;
486 }
487
488 *BufferSize = ResultSize;
489 return Status;
490 }
491
492 EFI_STATUS
493 FileGetInfo (
494 IN EFI_FILE *File,
495 IN EFI_GUID *InformationType,
496 IN OUT UINTN *BufferSize,
497 OUT VOID *Buffer
498 )
499 {
500 SEMIHOST_FCB *Fcb;
501 EFI_STATUS Status;
502 UINTN ResultSize;
503
504 Fcb = SEMIHOST_FCB_FROM_THIS(File);
505
506 if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) != 0) {
507 Status = GetFilesystemInfo (Fcb, BufferSize, Buffer);
508 } else if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {
509 Status = GetFileInfo (Fcb, BufferSize, Buffer);
510 } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid) != 0) {
511 ResultSize = StrSize (mSemihostFsLabel);
512
513 if (*BufferSize >= ResultSize) {
514 StrCpy (Buffer, mSemihostFsLabel);
515 Status = EFI_SUCCESS;
516 } else {
517 Status = EFI_BUFFER_TOO_SMALL;
518 }
519
520 *BufferSize = ResultSize;
521 } else {
522 Status = EFI_UNSUPPORTED;
523 }
524
525 return Status;
526 }
527
528 EFI_STATUS
529 FileSetInfo (
530 IN EFI_FILE *File,
531 IN EFI_GUID *InformationType,
532 IN UINTN BufferSize,
533 IN VOID *Buffer
534 )
535 {
536 EFI_STATUS Status;
537
538 if (Buffer == NULL) {
539 return EFI_INVALID_PARAMETER;
540 }
541
542 Status = EFI_UNSUPPORTED;
543
544 if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) != 0) {
545 //Status = SetFilesystemInfo (Fcb, BufferSize, Buffer);
546 } else if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {
547 // Semihosting does not give us access to setting file info, but
548 // if we fail here we cannot create new files.
549 Status = EFI_SUCCESS;
550 } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid) != 0) {
551 if (StrSize (Buffer) > 0) {
552 FreePool (mSemihostFsLabel);
553 mSemihostFsLabel = AllocateCopyPool (StrSize (Buffer), Buffer);
554 Status = EFI_SUCCESS;
555 }
556 }
557
558 return Status;
559 }
560
561 EFI_STATUS
562 FileFlush (
563 IN EFI_FILE *File
564 )
565 {
566 SEMIHOST_FCB *Fcb;
567
568 Fcb = SEMIHOST_FCB_FROM_THIS(File);
569
570 if (Fcb->IsRoot) {
571 return EFI_SUCCESS;
572 } else {
573 if ((Fcb->Info.Attribute & EFI_FILE_READ_ONLY)
574 || !(Fcb->OpenMode & EFI_FILE_MODE_WRITE)) {
575 return EFI_ACCESS_DENIED;
576 } else {
577 return EFI_SUCCESS;
578 }
579 }
580 }
581
582 EFI_STATUS
583 SemihostFsEntryPoint (
584 IN EFI_HANDLE ImageHandle,
585 IN EFI_SYSTEM_TABLE *SystemTable
586 )
587 {
588 EFI_STATUS Status;
589
590 Status = EFI_NOT_FOUND;
591
592 if (SemihostConnectionSupported ()) {
593 mSemihostFsLabel = AllocateCopyPool (StrSize (DEFAULT_SEMIHOST_FS_LABEL), DEFAULT_SEMIHOST_FS_LABEL);
594 if (mSemihostFsLabel == NULL) {
595 return EFI_OUT_OF_RESOURCES;
596 }
597
598 Status = gBS->InstallMultipleProtocolInterfaces (
599 &gInstallHandle,
600 &gEfiSimpleFileSystemProtocolGuid, &gSemihostFs,
601 &gEfiDevicePathProtocolGuid, &gDevicePath,
602 NULL
603 );
604
605 if (EFI_ERROR(Status)) {
606 FreePool (mSemihostFsLabel);
607 }
608 }
609
610 return Status;
611 }