Update the copyright notice format
[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 // Get the filename from the Fcb
267 NameSize = AsciiStrLen (Fcb->FileName);
268 FileName = AllocatePool (NameSize + 1);
269
270 AsciiStrCpy (FileName, Fcb->FileName);
271
272 // Close the file if it's open. Disregard return status,
273 // since it might give an error if the file isn't open.
274 File->Close (File);
275
276 // Call the semihost interface to delete the file.
277 Status = SemihostFileRemove (FileName);
278
279 return Status;
280 }
281
282 EFI_STATUS
283 FileRead (
284 IN EFI_FILE *File,
285 IN OUT UINTN *BufferSize,
286 OUT VOID *Buffer
287 )
288 {
289 SEMIHOST_FCB *Fcb = NULL;
290 EFI_STATUS Status;
291
292 Fcb = SEMIHOST_FCB_FROM_THIS(File);
293
294 if (Fcb->IsRoot == TRUE) {
295 Status = EFI_UNSUPPORTED;
296 } else {
297 Status = SemihostFileRead (Fcb->SemihostHandle, BufferSize, Buffer);
298 if (!EFI_ERROR (Status)) {
299 Fcb->Position += *BufferSize;
300 }
301 }
302
303 return Status;
304 }
305
306 EFI_STATUS
307 FileWrite (
308 IN EFI_FILE *File,
309 IN OUT UINTN *BufferSize,
310 IN VOID *Buffer
311 )
312 {
313 SEMIHOST_FCB *Fcb = NULL;
314 EFI_STATUS Status;
315 UINTN WriteSize = *BufferSize;
316
317 Fcb = SEMIHOST_FCB_FROM_THIS(File);
318
319 Status = SemihostFileWrite (Fcb->SemihostHandle, &WriteSize, Buffer);
320
321 if (!EFI_ERROR(Status)) {
322 // Semihost write return the number of bytes *NOT* written.
323 *BufferSize -= WriteSize;
324 Fcb->Position += *BufferSize;
325 }
326
327 return Status;
328 }
329
330 EFI_STATUS
331 FileGetPosition (
332 IN EFI_FILE *File,
333 OUT UINT64 *Position
334 )
335 {
336 SEMIHOST_FCB *Fcb = NULL;
337
338 if (Position == NULL) {
339 return EFI_INVALID_PARAMETER;
340 }
341
342 Fcb = SEMIHOST_FCB_FROM_THIS(File);
343
344 *Position = Fcb->Position;
345
346 return EFI_SUCCESS;
347 }
348
349 EFI_STATUS
350 FileSetPosition (
351 IN EFI_FILE *File,
352 IN UINT64 Position
353 )
354 {
355 SEMIHOST_FCB *Fcb = NULL;
356 UINT32 Length;
357 EFI_STATUS Status;
358
359 Fcb = SEMIHOST_FCB_FROM_THIS(File);
360
361 Status = SemihostFileLength (Fcb->SemihostHandle, &Length);
362 if (!EFI_ERROR(Status) && (Length < Position)) {
363 Position = Length;
364 }
365
366 Status = SemihostFileSeek (Fcb->SemihostHandle, (UINT32)Position);
367 if (!EFI_ERROR(Status)) {
368 Fcb->Position = Position;
369 }
370
371 return Status;
372 }
373
374 STATIC
375 EFI_STATUS
376 GetFileInfo (
377 IN SEMIHOST_FCB *Fcb,
378 IN OUT UINTN *BufferSize,
379 OUT VOID *Buffer
380 )
381 {
382 EFI_FILE_INFO *Info = NULL;
383 UINTN NameSize = 0;
384 UINTN ResultSize;
385 UINTN Index;
386 UINT32 Length;
387 EFI_STATUS Status;
388
389 if (Fcb->IsRoot == TRUE) {
390 ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);
391 } else {
392 NameSize = AsciiStrLen (Fcb->FileName) + 1;
393 ResultSize = SIZE_OF_EFI_FILE_INFO + NameSize * sizeof (CHAR16);
394 }
395
396 if (*BufferSize < ResultSize) {
397 *BufferSize = ResultSize;
398 return EFI_BUFFER_TOO_SMALL;
399 }
400
401 Info = Buffer;
402
403 // Zero out the structure
404 ZeroMem (Info, SIZE_OF_EFI_FILE_INFO);
405
406 // Fill in the structure
407 Info->Size = ResultSize;
408
409 if (Fcb->IsRoot == TRUE) {
410 Info->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
411 Info->FileName[0] = L'\0';
412 } else {
413 Status = SemihostFileLength (Fcb->SemihostHandle, &Length);
414 if (EFI_ERROR(Status)) {
415 return Status;
416 }
417
418 Info->FileSize = Length;
419 Info->PhysicalSize = Length;
420
421 for (Index = 0; Index < NameSize; Index++) {
422 Info->FileName[Index] = Fcb->FileName[Index];
423 }
424 }
425
426
427 *BufferSize = ResultSize;
428
429 return EFI_SUCCESS;
430 }
431
432 STATIC
433 EFI_STATUS
434 GetFilesystemInfo (
435 IN SEMIHOST_FCB *Fcb,
436 IN OUT UINTN *BufferSize,
437 OUT VOID *Buffer
438 )
439 {
440 EFI_FILE_SYSTEM_INFO *Info = NULL;
441 EFI_STATUS Status;
442 STATIC CHAR16 Label[] = L"SemihostFs";
443 UINTN ResultSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize(Label);
444
445 if(*BufferSize >= ResultSize) {
446 ZeroMem (Buffer, ResultSize);
447 Status = EFI_SUCCESS;
448
449 Info = Buffer;
450
451 Info->Size = ResultSize;
452 Info->ReadOnly = FALSE;
453 Info->VolumeSize = 0;
454 Info->FreeSpace = 0;
455 Info->BlockSize = 0;
456
457 StrCpy (Info->VolumeLabel, Label);
458 } else {
459 Status = EFI_BUFFER_TOO_SMALL;
460 }
461
462 *BufferSize = ResultSize;
463 return Status;
464 }
465
466 EFI_STATUS
467 FileGetInfo (
468 IN EFI_FILE *File,
469 IN EFI_GUID *InformationType,
470 IN OUT UINTN *BufferSize,
471 OUT VOID *Buffer
472 )
473 {
474 SEMIHOST_FCB *Fcb = NULL;
475 EFI_STATUS Status = EFI_UNSUPPORTED;
476
477 Fcb = SEMIHOST_FCB_FROM_THIS(File);
478
479 if (CompareGuid(InformationType, &gEfiFileSystemInfoGuid) != 0) {
480 Status = GetFilesystemInfo(Fcb, BufferSize, Buffer);
481 } else if (CompareGuid(InformationType, &gEfiFileInfoGuid) != 0) {
482 Status = GetFileInfo(Fcb, BufferSize, Buffer);
483 }
484
485 return Status;
486 }
487
488 EFI_STATUS
489 FileSetInfo (
490 IN EFI_FILE *File,
491 IN EFI_GUID *InformationType,
492 IN UINTN BufferSize,
493 IN VOID *Buffer
494 )
495 {
496 return EFI_UNSUPPORTED;
497 }
498
499 EFI_STATUS
500 FileFlush (
501 IN EFI_FILE *File
502 )
503 {
504 return EFI_SUCCESS;
505 }
506
507 EFI_STATUS
508 SemihostFsEntryPoint (
509 IN EFI_HANDLE ImageHandle,
510 IN EFI_SYSTEM_TABLE *SystemTable
511 )
512 {
513 EFI_STATUS Status = EFI_NOT_FOUND;
514
515 if (SemihostConnectionSupported ()) {
516 Status = gBS->InstallMultipleProtocolInterfaces (
517 &gInstallHandle,
518 &gEfiSimpleFileSystemProtocolGuid, &gSemihostFs,
519 &gEfiDevicePathProtocolGuid, &gDevicePath,
520 NULL
521 );
522 }
523
524 return Status;
525 }
526