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