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