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