]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.c
ArmPkg: Moved ARMv7 specific files to a 'Arm' subdirectory
[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
1ea31716 180 if ((AsciiStrCmp (AsciiFileName, "\\") == 0) ||\r
181 (AsciiStrCmp (AsciiFileName, "/") == 0) ||\r
182 (AsciiStrCmp (AsciiFileName, "") == 0) ||\r
183 (AsciiStrCmp (AsciiFileName, ".") == 0)) {\r
184 // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory\r
2ef2b01e
A
185 IsRoot = TRUE;\r
186\r
187 // Root directory node doesn't have a name.\r
188 FreePool (AsciiFileName);\r
189 AsciiFileName = NULL;\r
190 } else {\r
191 // Translate EFI_FILE_MODE into Semihosting mode\r
192 if (OpenMode & EFI_FILE_MODE_WRITE) {\r
193 SemihostMode = SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY;\r
194 } else if (OpenMode & EFI_FILE_MODE_READ) {\r
195 SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY;\r
196 } else {\r
197 return EFI_UNSUPPORTED;\r
198 }\r
199\r
200 // Add the creation flag if necessary\r
201 if (OpenMode & EFI_FILE_MODE_CREATE) {\r
202 SemihostMode |= SEMIHOST_FILE_MODE_CREATE;\r
203 }\r
204\r
205 // Call the semihosting interface to open the file.\r
206 Status = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);\r
207 if (EFI_ERROR(Status)) {\r
208 return Status;\r
209 }\r
210 \r
211 IsRoot = FALSE;\r
212 }\r
213\r
214 // Allocate a control block and fill it\r
215 FileFcb = AllocateFCB ();\r
216 if (FileFcb == NULL) {\r
217 return EFI_OUT_OF_RESOURCES;\r
218 }\r
219\r
220 FileFcb->FileName = AsciiFileName;\r
221 FileFcb->SemihostHandle = SemihostHandle;\r
222 FileFcb->Position = 0;\r
223 FileFcb->IsRoot = IsRoot;\r
224\r
225 InsertTailList (&gFileList, &FileFcb->Link);\r
226\r
227 *NewHandle = &FileFcb->File;\r
228\r
229 return Status;\r
230}\r
231\r
232\r
233EFI_STATUS\r
234FileClose (\r
235 IN EFI_FILE *File\r
236 )\r
237{\r
238 SEMIHOST_FCB *Fcb = NULL;\r
239 EFI_STATUS Status = EFI_SUCCESS;\r
240\r
241 Fcb = SEMIHOST_FCB_FROM_THIS(File);\r
242\r
243 if (Fcb->IsRoot == TRUE) {\r
244 FreeFCB (Fcb);\r
245 Status = EFI_SUCCESS;\r
246 } else {\r
247 Status = SemihostFileClose (Fcb->SemihostHandle);\r
248 if (!EFI_ERROR(Status)) {\r
249 FreePool (Fcb->FileName);\r
250 FreeFCB (Fcb);\r
251 }\r
252 }\r
253 \r
254 return Status;\r
255}\r
256\r
257EFI_STATUS\r
258FileDelete (\r
259 IN EFI_FILE *File\r
260 )\r
261{\r
262 SEMIHOST_FCB *Fcb = NULL;\r
263 EFI_STATUS Status;\r
264 CHAR8 *FileName;\r
265 UINTN NameSize;\r
266\r
267 Fcb = SEMIHOST_FCB_FROM_THIS(File);\r
268\r
3bb46df2 269 if (!Fcb->IsRoot) {\r
270 // Get the filename from the Fcb\r
271 NameSize = AsciiStrLen (Fcb->FileName);\r
272 FileName = AllocatePool (NameSize + 1);\r
2ef2b01e 273\r
3bb46df2 274 AsciiStrCpy (FileName, Fcb->FileName);\r
2ef2b01e 275\r
3bb46df2 276 // Close the file if it's open. Disregard return status,\r
277 // since it might give an error if the file isn't open.\r
278 File->Close (File);\r
279\r
280 // Call the semihost interface to delete the file.\r
281 Status = SemihostFileRemove (FileName);\r
282 } else {\r
283 Status = EFI_UNSUPPORTED;\r
284 }\r
2ef2b01e
A
285\r
286 return Status;\r
287}\r
288\r
289EFI_STATUS\r
290FileRead (\r
291 IN EFI_FILE *File,\r
292 IN OUT UINTN *BufferSize,\r
293 OUT VOID *Buffer\r
294 )\r
295{\r
296 SEMIHOST_FCB *Fcb = NULL;\r
297 EFI_STATUS Status;\r
298\r
299 Fcb = SEMIHOST_FCB_FROM_THIS(File);\r
300\r
301 if (Fcb->IsRoot == TRUE) {\r
302 Status = EFI_UNSUPPORTED;\r
303 } else {\r
304 Status = SemihostFileRead (Fcb->SemihostHandle, BufferSize, Buffer);\r
305 if (!EFI_ERROR (Status)) {\r
306 Fcb->Position += *BufferSize;\r
307 }\r
308 }\r
309\r
310 return Status;\r
311}\r
312\r
313EFI_STATUS\r
314FileWrite (\r
315 IN EFI_FILE *File,\r
316 IN OUT UINTN *BufferSize,\r
317 IN VOID *Buffer\r
318 )\r
319{\r
320 SEMIHOST_FCB *Fcb = NULL;\r
321 EFI_STATUS Status;\r
322 UINTN WriteSize = *BufferSize;\r
323\r
324 Fcb = SEMIHOST_FCB_FROM_THIS(File);\r
325\r
326 Status = SemihostFileWrite (Fcb->SemihostHandle, &WriteSize, Buffer);\r
327\r
328 if (!EFI_ERROR(Status)) {\r
329 // Semihost write return the number of bytes *NOT* written.\r
330 *BufferSize -= WriteSize;\r
331 Fcb->Position += *BufferSize;\r
332 }\r
333 \r
334 return Status;\r
335}\r
336\r
337EFI_STATUS\r
338FileGetPosition (\r
339 IN EFI_FILE *File,\r
340 OUT UINT64 *Position\r
341 )\r
342{\r
343 SEMIHOST_FCB *Fcb = NULL;\r
344 \r
345 if (Position == NULL) {\r
346 return EFI_INVALID_PARAMETER;\r
347 }\r
348\r
349 Fcb = SEMIHOST_FCB_FROM_THIS(File);\r
350\r
351 *Position = Fcb->Position;\r
352\r
353 return EFI_SUCCESS;\r
354}\r
355\r
356EFI_STATUS\r
357FileSetPosition (\r
358 IN EFI_FILE *File,\r
359 IN UINT64 Position\r
360 )\r
361{\r
362 SEMIHOST_FCB *Fcb = NULL;\r
363 UINT32 Length;\r
364 EFI_STATUS Status;\r
365\r
366 Fcb = SEMIHOST_FCB_FROM_THIS(File);\r
367\r
3bb46df2 368 if (!Fcb->IsRoot) {\r
369 Status = SemihostFileLength (Fcb->SemihostHandle, &Length);\r
370 if (!EFI_ERROR(Status) && (Length < Position)) {\r
371 Position = Length;\r
372 }\r
2ef2b01e 373\r
3bb46df2 374 Status = SemihostFileSeek (Fcb->SemihostHandle, (UINT32)Position);\r
375 if (!EFI_ERROR(Status)) {\r
376 Fcb->Position = Position;\r
377 }\r
378 } else {\r
2ef2b01e 379 Fcb->Position = Position;\r
3bb46df2 380 Status = EFI_SUCCESS;\r
2ef2b01e
A
381 }\r
382\r
383 return Status;\r
384}\r
385\r
386STATIC\r
387EFI_STATUS\r
388GetFileInfo (\r
389 IN SEMIHOST_FCB *Fcb,\r
390 IN OUT UINTN *BufferSize,\r
391 OUT VOID *Buffer\r
392 )\r
393{\r
394 EFI_FILE_INFO *Info = NULL;\r
395 UINTN NameSize = 0;\r
396 UINTN ResultSize;\r
397 UINTN Index;\r
398 UINT32 Length;\r
399 EFI_STATUS Status;\r
400\r
401 if (Fcb->IsRoot == TRUE) {\r
402 ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);\r
403 } else {\r
404 NameSize = AsciiStrLen (Fcb->FileName) + 1;\r
405 ResultSize = SIZE_OF_EFI_FILE_INFO + NameSize * sizeof (CHAR16);\r
406 }\r
407\r
408 if (*BufferSize < ResultSize) {\r
409 *BufferSize = ResultSize;\r
410 return EFI_BUFFER_TOO_SMALL;\r
411 }\r
412\r
413 Info = Buffer;\r
414\r
415 // Zero out the structure\r
416 ZeroMem (Info, SIZE_OF_EFI_FILE_INFO);\r
417\r
418 // Fill in the structure\r
419 Info->Size = ResultSize;\r
420\r
421 if (Fcb->IsRoot == TRUE) {\r
422 Info->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;\r
423 Info->FileName[0] = L'\0';\r
424 } else {\r
425 Status = SemihostFileLength (Fcb->SemihostHandle, &Length);\r
426 if (EFI_ERROR(Status)) {\r
427 return Status;\r
428 }\r
429\r
430 Info->FileSize = Length;\r
431 Info->PhysicalSize = Length;\r
432\r
433 for (Index = 0; Index < NameSize; Index++) {\r
434 Info->FileName[Index] = Fcb->FileName[Index]; \r
435 }\r
436 }\r
437\r
438\r
439 *BufferSize = ResultSize; \r
440\r
441 return EFI_SUCCESS;\r
442}\r
443\r
444STATIC\r
445EFI_STATUS\r
446GetFilesystemInfo (\r
447 IN SEMIHOST_FCB *Fcb,\r
448 IN OUT UINTN *BufferSize,\r
449 OUT VOID *Buffer\r
450 )\r
451{\r
452 EFI_FILE_SYSTEM_INFO *Info = NULL;\r
453 EFI_STATUS Status;\r
454 STATIC CHAR16 Label[] = L"SemihostFs";\r
455 UINTN ResultSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize(Label);\r
456 \r
457 if(*BufferSize >= ResultSize) {\r
458 ZeroMem (Buffer, ResultSize);\r
459 Status = EFI_SUCCESS;\r
460 \r
461 Info = Buffer;\r
462\r
463 Info->Size = ResultSize;\r
464 Info->ReadOnly = FALSE;\r
465 Info->VolumeSize = 0;\r
466 Info->FreeSpace = 0;\r
467 Info->BlockSize = 0;\r
468\r
469 StrCpy (Info->VolumeLabel, Label);\r
470 } else {\r
471 Status = EFI_BUFFER_TOO_SMALL;\r
472 }\r
473\r
474 *BufferSize = ResultSize; \r
475 return Status;\r
476}\r
477\r
478EFI_STATUS\r
479FileGetInfo (\r
480 IN EFI_FILE *File,\r
481 IN EFI_GUID *InformationType,\r
482 IN OUT UINTN *BufferSize,\r
483 OUT VOID *Buffer\r
484 )\r
485{\r
486 SEMIHOST_FCB *Fcb = NULL;\r
487 EFI_STATUS Status = EFI_UNSUPPORTED;\r
488 \r
489 Fcb = SEMIHOST_FCB_FROM_THIS(File);\r
490 \r
491 if (CompareGuid(InformationType, &gEfiFileSystemInfoGuid) != 0) {\r
492 Status = GetFilesystemInfo(Fcb, BufferSize, Buffer); \r
493 } else if (CompareGuid(InformationType, &gEfiFileInfoGuid) != 0) {\r
494 Status = GetFileInfo(Fcb, BufferSize, Buffer); \r
495 }\r
496 \r
497 return Status;\r
498}\r
499\r
500EFI_STATUS\r
501FileSetInfo (\r
502 IN EFI_FILE *File,\r
503 IN EFI_GUID *InformationType,\r
504 IN UINTN BufferSize,\r
505 IN VOID *Buffer\r
506 )\r
507{\r
508 return EFI_UNSUPPORTED;\r
509}\r
510\r
511EFI_STATUS\r
512FileFlush (\r
513 IN EFI_FILE *File\r
514 )\r
515{\r
516 return EFI_SUCCESS;\r
517}\r
518\r
519EFI_STATUS\r
520SemihostFsEntryPoint (\r
521 IN EFI_HANDLE ImageHandle,\r
522 IN EFI_SYSTEM_TABLE *SystemTable\r
523 )\r
524{\r
525 EFI_STATUS Status = EFI_NOT_FOUND;\r
526\r
527 if (SemihostConnectionSupported ()) {\r
528 Status = gBS->InstallMultipleProtocolInterfaces (\r
529 &gInstallHandle, \r
530 &gEfiSimpleFileSystemProtocolGuid, &gSemihostFs, \r
531 &gEfiDevicePathProtocolGuid, &gDevicePath,\r
532 NULL\r
533 );\r
534 }\r
535 \r
536 return Status;\r
537}\r
538\r