]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.c
ARM Packages: Minor typo, mispellings and coding style changes
[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
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
10
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.
13
14 **/
15
16 #include <Uefi.h>
17
18 #include <Guid/FileInfo.h>
19 #include <Guid/FileSystemInfo.h>
20
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>
28
29 #include <Protocol/DevicePath.h>
30 #include <Protocol/SimpleFileSystem.h>
31
32 #include "SemihostFs.h"
33
34
35 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gSemihostFs = {
36 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
37 VolumeOpen
38 };
39
40 EFI_FILE gSemihostFsFile = {
41 EFI_FILE_PROTOCOL_REVISION,
42 FileOpen,
43 FileClose,
44 FileDelete,
45 FileRead,
46 FileWrite,
47 FileGetPosition,
48 FileSetPosition,
49 FileGetInfo,
50 FileSetInfo,
51 FileFlush
52 };
53
54 //
55 // Device path for SemiHosting. It contains our autogened Caller ID GUID.
56 //
57 typedef struct {
58 VENDOR_DEVICE_PATH Guid;
59 EFI_DEVICE_PATH_PROTOCOL End;
60 } SEMIHOST_DEVICE_PATH;
61
62 SEMIHOST_DEVICE_PATH gDevicePath = {
63 {
64 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH), 0 },
65 EFI_CALLER_ID_GUID
66 },
67 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, sizeof (EFI_DEVICE_PATH_PROTOCOL), 0}
68 };
69
70 typedef struct {
71 LIST_ENTRY Link;
72 UINT64 Signature;
73 EFI_FILE File;
74 CHAR8 *FileName;
75 UINT32 Position;
76 UINT32 SemihostHandle;
77 BOOLEAN IsRoot;
78 } SEMIHOST_FCB;
79
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);
83
84 EFI_HANDLE gInstallHandle = NULL;
85 LIST_ENTRY gFileList = INITIALIZE_LIST_HEAD_VARIABLE (gFileList);
86
87 SEMIHOST_FCB *
88 AllocateFCB (
89 VOID
90 )
91 {
92 SEMIHOST_FCB *Fcb = AllocateZeroPool (sizeof (SEMIHOST_FCB));
93
94 if (Fcb != NULL) {
95 CopyMem (&Fcb->File, &gSemihostFsFile, sizeof (gSemihostFsFile));
96 Fcb->Signature = SEMIHOST_FCB_SIGNATURE;
97 }
98
99 return Fcb;
100 }
101
102 VOID
103 FreeFCB (
104 IN SEMIHOST_FCB *Fcb
105 )
106 {
107 // Remove Fcb from gFileList.
108 RemoveEntryList (&Fcb->Link);
109
110 // To help debugging...
111 Fcb->Signature = 0;
112
113 FreePool (Fcb);
114 }
115
116
117
118 EFI_STATUS
119 VolumeOpen (
120 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
121 OUT EFI_FILE **Root
122 )
123 {
124 SEMIHOST_FCB *RootFcb = NULL;
125
126 if (Root == NULL) {
127 return EFI_INVALID_PARAMETER;
128 }
129
130 RootFcb = AllocateFCB ();
131 if (RootFcb == NULL) {
132 return EFI_OUT_OF_RESOURCES;
133 }
134
135 RootFcb->IsRoot = TRUE;
136
137 InsertTailList (&gFileList, &RootFcb->Link);
138
139 *Root = &RootFcb->File;
140
141 return EFI_SUCCESS;
142 }
143
144 EFI_STATUS
145 FileOpen (
146 IN EFI_FILE *File,
147 OUT EFI_FILE **NewHandle,
148 IN CHAR16 *FileName,
149 IN UINT64 OpenMode,
150 IN UINT64 Attributes
151 )
152 {
153 SEMIHOST_FCB *FileFcb = NULL;
154 EFI_STATUS Status = EFI_SUCCESS;
155 UINT32 SemihostHandle;
156 CHAR8 *AsciiFileName;
157 CHAR8 *AsciiPtr;
158 UINTN Length;
159 UINT32 SemihostMode;
160 BOOLEAN IsRoot;
161
162 if ((FileName == NULL) || (NewHandle == NULL)) {
163 return EFI_INVALID_PARAMETER;
164 }
165
166 // Semihost interface requires ASCII filesnames
167 Length = StrSize (FileName);
168
169 AsciiFileName = AllocatePool (Length);
170 if (AsciiFileName == NULL) {
171 return EFI_OUT_OF_RESOURCES;
172 }
173
174 AsciiPtr = AsciiFileName;
175
176 while (Length--) {
177 *AsciiPtr++ = *FileName++ & 0xFF;
178 }
179
180 if ((AsciiStrCmp (AsciiFileName, "\\") == 0) || (AsciiStrCmp (AsciiFileName, "/") == 0) || (AsciiStrCmp (AsciiFileName, "") == 0)) {
181 // Opening '/', '\', or the NULL pathname is trying to open the root directory
182 IsRoot = TRUE;
183
184 // Root directory node doesn't have a name.
185 FreePool (AsciiFileName);
186 AsciiFileName = NULL;
187 } else {
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;
193 } else {
194 return EFI_UNSUPPORTED;
195 }
196
197 // Add the creation flag if necessary
198 if (OpenMode & EFI_FILE_MODE_CREATE) {
199 SemihostMode |= SEMIHOST_FILE_MODE_CREATE;
200 }
201
202 // Call the semihosting interface to open the file.
203 Status = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);
204 if (EFI_ERROR(Status)) {
205 return Status;
206 }
207
208 IsRoot = FALSE;
209 }
210
211 // Allocate a control block and fill it
212 FileFcb = AllocateFCB ();
213 if (FileFcb == NULL) {
214 return EFI_OUT_OF_RESOURCES;
215 }
216
217 FileFcb->FileName = AsciiFileName;
218 FileFcb->SemihostHandle = SemihostHandle;
219 FileFcb->Position = 0;
220 FileFcb->IsRoot = IsRoot;
221
222 InsertTailList (&gFileList, &FileFcb->Link);
223
224 *NewHandle = &FileFcb->File;
225
226 return Status;
227 }
228
229
230 EFI_STATUS
231 FileClose (
232 IN EFI_FILE *File
233 )
234 {
235 SEMIHOST_FCB *Fcb = NULL;
236 EFI_STATUS Status = EFI_SUCCESS;
237
238 Fcb = SEMIHOST_FCB_FROM_THIS(File);
239
240 if (Fcb->IsRoot == TRUE) {
241 FreeFCB (Fcb);
242 Status = EFI_SUCCESS;
243 } else {
244 Status = SemihostFileClose (Fcb->SemihostHandle);
245 if (!EFI_ERROR(Status)) {
246 FreePool (Fcb->FileName);
247 FreeFCB (Fcb);
248 }
249 }
250
251 return Status;
252 }
253
254 EFI_STATUS
255 FileDelete (
256 IN EFI_FILE *File
257 )
258 {
259 SEMIHOST_FCB *Fcb = NULL;
260 EFI_STATUS Status;
261 CHAR8 *FileName;
262 UINTN NameSize;
263
264 Fcb = SEMIHOST_FCB_FROM_THIS(File);
265
266 if (!Fcb->IsRoot) {
267 // Get the filename from the Fcb
268 NameSize = AsciiStrLen (Fcb->FileName);
269 FileName = AllocatePool (NameSize + 1);
270
271 AsciiStrCpy (FileName, Fcb->FileName);
272
273 // Close the file if it's open. Disregard return status,
274 // since it might give an error if the file isn't open.
275 File->Close (File);
276
277 // Call the semihost interface to delete the file.
278 Status = SemihostFileRemove (FileName);
279 } else {
280 Status = EFI_UNSUPPORTED;
281 }
282
283 return Status;
284 }
285
286 EFI_STATUS
287 FileRead (
288 IN EFI_FILE *File,
289 IN OUT UINTN *BufferSize,
290 OUT VOID *Buffer
291 )
292 {
293 SEMIHOST_FCB *Fcb = NULL;
294 EFI_STATUS Status;
295
296 Fcb = SEMIHOST_FCB_FROM_THIS(File);
297
298 if (Fcb->IsRoot == TRUE) {
299 Status = EFI_UNSUPPORTED;
300 } else {
301 Status = SemihostFileRead (Fcb->SemihostHandle, BufferSize, Buffer);
302 if (!EFI_ERROR (Status)) {
303 Fcb->Position += *BufferSize;
304 }
305 }
306
307 return Status;
308 }
309
310 EFI_STATUS
311 FileWrite (
312 IN EFI_FILE *File,
313 IN OUT UINTN *BufferSize,
314 IN VOID *Buffer
315 )
316 {
317 SEMIHOST_FCB *Fcb = NULL;
318 EFI_STATUS Status;
319 UINTN WriteSize = *BufferSize;
320
321 Fcb = SEMIHOST_FCB_FROM_THIS(File);
322
323 Status = SemihostFileWrite (Fcb->SemihostHandle, &WriteSize, Buffer);
324
325 if (!EFI_ERROR(Status)) {
326 // Semihost write return the number of bytes *NOT* written.
327 *BufferSize -= WriteSize;
328 Fcb->Position += *BufferSize;
329 }
330
331 return Status;
332 }
333
334 EFI_STATUS
335 FileGetPosition (
336 IN EFI_FILE *File,
337 OUT UINT64 *Position
338 )
339 {
340 SEMIHOST_FCB *Fcb = NULL;
341
342 if (Position == NULL) {
343 return EFI_INVALID_PARAMETER;
344 }
345
346 Fcb = SEMIHOST_FCB_FROM_THIS(File);
347
348 *Position = Fcb->Position;
349
350 return EFI_SUCCESS;
351 }
352
353 EFI_STATUS
354 FileSetPosition (
355 IN EFI_FILE *File,
356 IN UINT64 Position
357 )
358 {
359 SEMIHOST_FCB *Fcb = NULL;
360 UINT32 Length;
361 EFI_STATUS Status;
362
363 Fcb = SEMIHOST_FCB_FROM_THIS(File);
364
365 if (!Fcb->IsRoot) {
366 Status = SemihostFileLength (Fcb->SemihostHandle, &Length);
367 if (!EFI_ERROR(Status) && (Length < Position)) {
368 Position = Length;
369 }
370
371 Status = SemihostFileSeek (Fcb->SemihostHandle, (UINT32)Position);
372 if (!EFI_ERROR(Status)) {
373 Fcb->Position = Position;
374 }
375 } else {
376 Fcb->Position = Position;
377 Status = EFI_SUCCESS;
378 }
379
380 return Status;
381 }
382
383 STATIC
384 EFI_STATUS
385 GetFileInfo (
386 IN SEMIHOST_FCB *Fcb,
387 IN OUT UINTN *BufferSize,
388 OUT VOID *Buffer
389 )
390 {
391 EFI_FILE_INFO *Info = NULL;
392 UINTN NameSize = 0;
393 UINTN ResultSize;
394 UINTN Index;
395 UINT32 Length;
396 EFI_STATUS Status;
397
398 if (Fcb->IsRoot == TRUE) {
399 ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);
400 } else {
401 NameSize = AsciiStrLen (Fcb->FileName) + 1;
402 ResultSize = SIZE_OF_EFI_FILE_INFO + NameSize * sizeof (CHAR16);
403 }
404
405 if (*BufferSize < ResultSize) {
406 *BufferSize = ResultSize;
407 return EFI_BUFFER_TOO_SMALL;
408 }
409
410 Info = Buffer;
411
412 // Zero out the structure
413 ZeroMem (Info, SIZE_OF_EFI_FILE_INFO);
414
415 // Fill in the structure
416 Info->Size = ResultSize;
417
418 if (Fcb->IsRoot == TRUE) {
419 Info->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
420 Info->FileName[0] = L'\0';
421 } else {
422 Status = SemihostFileLength (Fcb->SemihostHandle, &Length);
423 if (EFI_ERROR(Status)) {
424 return Status;
425 }
426
427 Info->FileSize = Length;
428 Info->PhysicalSize = Length;
429
430 for (Index = 0; Index < NameSize; Index++) {
431 Info->FileName[Index] = Fcb->FileName[Index];
432 }
433 }
434
435
436 *BufferSize = ResultSize;
437
438 return EFI_SUCCESS;
439 }
440
441 STATIC
442 EFI_STATUS
443 GetFilesystemInfo (
444 IN SEMIHOST_FCB *Fcb,
445 IN OUT UINTN *BufferSize,
446 OUT VOID *Buffer
447 )
448 {
449 EFI_FILE_SYSTEM_INFO *Info = NULL;
450 EFI_STATUS Status;
451 STATIC CHAR16 Label[] = L"SemihostFs";
452 UINTN ResultSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize(Label);
453
454 if(*BufferSize >= ResultSize) {
455 ZeroMem (Buffer, ResultSize);
456 Status = EFI_SUCCESS;
457
458 Info = Buffer;
459
460 Info->Size = ResultSize;
461 Info->ReadOnly = FALSE;
462 Info->VolumeSize = 0;
463 Info->FreeSpace = 0;
464 Info->BlockSize = 0;
465
466 StrCpy (Info->VolumeLabel, Label);
467 } else {
468 Status = EFI_BUFFER_TOO_SMALL;
469 }
470
471 *BufferSize = ResultSize;
472 return Status;
473 }
474
475 EFI_STATUS
476 FileGetInfo (
477 IN EFI_FILE *File,
478 IN EFI_GUID *InformationType,
479 IN OUT UINTN *BufferSize,
480 OUT VOID *Buffer
481 )
482 {
483 SEMIHOST_FCB *Fcb = NULL;
484 EFI_STATUS Status = EFI_UNSUPPORTED;
485
486 Fcb = SEMIHOST_FCB_FROM_THIS(File);
487
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);
492 }
493
494 return Status;
495 }
496
497 EFI_STATUS
498 FileSetInfo (
499 IN EFI_FILE *File,
500 IN EFI_GUID *InformationType,
501 IN UINTN BufferSize,
502 IN VOID *Buffer
503 )
504 {
505 return EFI_UNSUPPORTED;
506 }
507
508 EFI_STATUS
509 FileFlush (
510 IN EFI_FILE *File
511 )
512 {
513 return EFI_SUCCESS;
514 }
515
516 EFI_STATUS
517 SemihostFsEntryPoint (
518 IN EFI_HANDLE ImageHandle,
519 IN EFI_SYSTEM_TABLE *SystemTable
520 )
521 {
522 EFI_STATUS Status = EFI_NOT_FOUND;
523
524 if (SemihostConnectionSupported ()) {
525 Status = gBS->InstallMultipleProtocolInterfaces (
526 &gInstallHandle,
527 &gEfiSimpleFileSystemProtocolGuid, &gSemihostFs,
528 &gEfiDevicePathProtocolGuid, &gDevicePath,
529 NULL
530 );
531 }
532
533 return Status;
534 }
535