]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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
f66c2b32 5 Portions copyright (c) 2011 - 2021, Arm Limited. All rights reserved.<BR>\r
c63626b7 6\r
4059386c 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
2ef2b01e
A
8\r
9**/\r
10\r
11#include <Uefi.h>\r
12\r
13#include <Guid/FileInfo.h>\r
14#include <Guid/FileSystemInfo.h>\r
09f2cf82 15#include <Guid/FileSystemVolumeLabelInfo.h>\r
2ef2b01e
A
16\r
17#include <Library/BaseLib.h>\r
3402aac7 18#include <Library/BaseMemoryLib.h>\r
2ef2b01e
A
19#include <Library/DebugLib.h>\r
20#include <Library/MemoryAllocationLib.h>\r
21#include <Library/SemihostLib.h>\r
22#include <Library/UefiBootServicesTableLib.h>\r
23#include <Library/UefiLib.h>\r
24\r
25#include <Protocol/DevicePath.h>\r
26#include <Protocol/SimpleFileSystem.h>\r
27\r
28#include "SemihostFs.h"\r
29\r
429309e0 30#define DEFAULT_SEMIHOST_FS_LABEL L"SemihostFs"\r
09f2cf82 31\r
429309e0 32STATIC CHAR16 *mSemihostFsLabel;\r
2ef2b01e 33\r
429309e0 34EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gSemihostFs = {\r
2ef2b01e
A
35 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,\r
36 VolumeOpen\r
37};\r
38\r
429309e0 39EFI_FILE gSemihostFsFile = {\r
2ef2b01e
A
40 EFI_FILE_PROTOCOL_REVISION,\r
41 FileOpen,\r
42 FileClose,\r
43 FileDelete,\r
44 FileRead,\r
45 FileWrite,\r
46 FileGetPosition,\r
47 FileSetPosition,\r
48 FileGetInfo,\r
49 FileSetInfo,\r
50 FileFlush\r
51};\r
52\r
53//\r
b8de64be 54// Device path for semi-hosting. It contains our auto-generated Caller ID GUID.\r
2ef2b01e
A
55//\r
56typedef struct {\r
429309e0
MK
57 VENDOR_DEVICE_PATH Guid;\r
58 EFI_DEVICE_PATH_PROTOCOL End;\r
2ef2b01e
A
59} SEMIHOST_DEVICE_PATH;\r
60\r
429309e0 61SEMIHOST_DEVICE_PATH gDevicePath = {\r
2ef2b01e 62 {\r
429309e0
MK
63 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 }\r
64 },\r
2ef2b01e
A
65 EFI_CALLER_ID_GUID\r
66 },\r
429309e0
MK
67 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }\r
68 }\r
2ef2b01e
A
69};\r
70\r
71typedef struct {\r
429309e0
MK
72 LIST_ENTRY Link;\r
73 UINT64 Signature;\r
74 EFI_FILE File;\r
75 CHAR8 *FileName;\r
76 UINT64 OpenMode;\r
77 UINT32 Position;\r
78 UINTN SemihostHandle;\r
79 BOOLEAN IsRoot;\r
80 EFI_FILE_INFO Info;\r
2ef2b01e
A
81} SEMIHOST_FCB;\r
82\r
429309e0
MK
83#define SEMIHOST_FCB_SIGNATURE SIGNATURE_32( 'S', 'H', 'F', 'C' )\r
84#define SEMIHOST_FCB_FROM_THIS(a) CR(a, SEMIHOST_FCB, File, SEMIHOST_FCB_SIGNATURE)\r
85#define SEMIHOST_FCB_FROM_LINK(a) CR(a, SEMIHOST_FCB, Link, SEMIHOST_FCB_SIGNATURE);\r
2ef2b01e
A
86\r
87EFI_HANDLE gInstallHandle = NULL;\r
429309e0 88LIST_ENTRY gFileList = INITIALIZE_LIST_HEAD_VARIABLE (gFileList);\r
2ef2b01e
A
89\r
90SEMIHOST_FCB *\r
91AllocateFCB (\r
92 VOID\r
93 )\r
94{\r
429309e0 95 SEMIHOST_FCB *Fcb;\r
2ef2b01e 96\r
88a7d4aa 97 Fcb = AllocateZeroPool (sizeof (SEMIHOST_FCB));\r
2ef2b01e
A
98 if (Fcb != NULL) {\r
99 CopyMem (&Fcb->File, &gSemihostFsFile, sizeof (gSemihostFsFile));\r
100 Fcb->Signature = SEMIHOST_FCB_SIGNATURE;\r
101 }\r
102\r
103 return Fcb;\r
104}\r
105\r
106VOID\r
107FreeFCB (\r
429309e0 108 IN SEMIHOST_FCB *Fcb\r
2ef2b01e
A
109 )\r
110{\r
111 // Remove Fcb from gFileList.\r
112 RemoveEntryList (&Fcb->Link);\r
113\r
114 // To help debugging...\r
115 Fcb->Signature = 0;\r
116\r
117 FreePool (Fcb);\r
118}\r
119\r
2ef2b01e
A
120EFI_STATUS\r
121VolumeOpen (\r
429309e0
MK
122 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,\r
123 OUT EFI_FILE **Root\r
2ef2b01e
A
124 )\r
125{\r
429309e0 126 SEMIHOST_FCB *RootFcb;\r
3402aac7 127\r
2ef2b01e
A
128 if (Root == NULL) {\r
129 return EFI_INVALID_PARAMETER;\r
130 }\r
131\r
132 RootFcb = AllocateFCB ();\r
133 if (RootFcb == NULL) {\r
134 return EFI_OUT_OF_RESOURCES;\r
135 }\r
3402aac7 136\r
429309e0 137 RootFcb->IsRoot = TRUE;\r
09f2cf82 138 RootFcb->Info.Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;\r
2ef2b01e
A
139\r
140 InsertTailList (&gFileList, &RootFcb->Link);\r
141\r
142 *Root = &RootFcb->File;\r
143\r
144 return EFI_SUCCESS;\r
145}\r
146\r
fdd12bd5
RC
147/**\r
148 Open a file on the host system by means of the semihosting interface.\r
149\r
150 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is\r
151 the file handle to source location.\r
152 @param[out] NewHandle A pointer to the location to return the opened\r
153 handle for the new file.\r
154 @param[in] FileName The Null-terminated string of the name of the file\r
155 to be opened.\r
156 @param[in] OpenMode The mode to open the file : Read or Read/Write or\r
157 Read/Write/Create\r
158 @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these\r
159 are the attribute bits for the newly created file. The\r
160 mnemonics of the attribute bits are : EFI_FILE_READ_ONLY,\r
161 EFI_FILE_HIDDEN, EFI_FILE_SYSTEM, EFI_FILE_RESERVED,\r
162 EFI_FILE_DIRECTORY and EFI_FILE_ARCHIVE.\r
163\r
164 @retval EFI_SUCCESS The file was open.\r
165 @retval EFI_NOT_FOUND The specified file could not be found.\r
166 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.\r
167 @retval EFI_WRITE_PROTECTED Attempt to create a directory. This is not possible\r
168 with the semi-hosting interface.\r
169 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.\r
170 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
171\r
172**/\r
2ef2b01e
A
173EFI_STATUS\r
174FileOpen (\r
fdd12bd5
RC
175 IN EFI_FILE *This,\r
176 OUT EFI_FILE **NewHandle,\r
177 IN CHAR16 *FileName,\r
178 IN UINT64 OpenMode,\r
179 IN UINT64 Attributes\r
2ef2b01e
A
180 )\r
181{\r
fdd12bd5
RC
182 SEMIHOST_FCB *FileFcb;\r
183 RETURN_STATUS Return;\r
184 EFI_STATUS Status;\r
185 UINTN SemihostHandle;\r
186 CHAR8 *AsciiFileName;\r
187 UINT32 SemihostMode;\r
188 UINTN Length;\r
2ef2b01e
A
189\r
190 if ((FileName == NULL) || (NewHandle == NULL)) {\r
191 return EFI_INVALID_PARAMETER;\r
192 }\r
193\r
429309e0
MK
194 if ((OpenMode != EFI_FILE_MODE_READ) &&\r
195 (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE)) &&\r
196 (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE)))\r
197 {\r
fdd12bd5
RC
198 return EFI_INVALID_PARAMETER;\r
199 }\r
200\r
f66c2b32 201 if (((OpenMode & EFI_FILE_MODE_CREATE) != 0) &&\r
429309e0
MK
202 ((Attributes & EFI_FILE_DIRECTORY) != 0))\r
203 {\r
fdd12bd5 204 return EFI_WRITE_PROTECTED;\r
09f2cf82 205 }\r
206\r
429309e0 207 Length = StrLen (FileName) + 1;\r
f6c4d99a 208 AsciiFileName = AllocatePool (Length);\r
2ef2b01e
A
209 if (AsciiFileName == NULL) {\r
210 return EFI_OUT_OF_RESOURCES;\r
211 }\r
429309e0 212\r
f6c4d99a 213 UnicodeStrToAsciiStrS (FileName, AsciiFileName, Length);\r
2ef2b01e 214\r
fdd12bd5 215 // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory\r
1ea31716 216 if ((AsciiStrCmp (AsciiFileName, "\\") == 0) ||\r
217 (AsciiStrCmp (AsciiFileName, "/") == 0) ||\r
218 (AsciiStrCmp (AsciiFileName, "") == 0) ||\r
429309e0
MK
219 (AsciiStrCmp (AsciiFileName, ".") == 0))\r
220 {\r
2ef2b01e 221 FreePool (AsciiFileName);\r
fdd12bd5
RC
222 return (VolumeOpen (&gSemihostFs, NewHandle));\r
223 }\r
224\r
225 //\r
226 // No control is done here concerning the file path. It is passed\r
227 // as it is to the host operating system through the semi-hosting\r
228 // interface. We first try to open the file in the read or update\r
229 // mode even if the file creation has been asked for. That way, if\r
230 // the file already exists, it is not truncated to zero length. In\r
231 // write mode (bit SEMIHOST_FILE_MODE_WRITE up), if the file already\r
232 // exists, it is reset to an empty file.\r
233 //\r
234 if (OpenMode == EFI_FILE_MODE_READ) {\r
235 SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY;\r
2ef2b01e 236 } else {\r
fdd12bd5
RC
237 SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY | SEMIHOST_FILE_MODE_UPDATE;\r
238 }\r
429309e0 239\r
fdd12bd5 240 Return = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);\r
2ef2b01e 241\r
fdd12bd5 242 if (RETURN_ERROR (Return)) {\r
f66c2b32 243 if ((OpenMode & EFI_FILE_MODE_CREATE) != 0) {\r
fdd12bd5
RC
244 //\r
245 // In the create if does not exist case, if the opening in update\r
246 // mode failed, create it and open it in update mode. The update\r
247 // mode allows for both read and write from and to the file.\r
248 //\r
249 Return = SemihostFileOpen (\r
250 AsciiFileName,\r
251 SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY | SEMIHOST_FILE_MODE_UPDATE,\r
252 &SemihostHandle\r
253 );\r
254 if (RETURN_ERROR (Return)) {\r
255 Status = EFI_DEVICE_ERROR;\r
256 goto Error;\r
257 }\r
258 } else {\r
259 Status = EFI_NOT_FOUND;\r
260 goto Error;\r
2ef2b01e 261 }\r
2ef2b01e
A
262 }\r
263\r
264 // Allocate a control block and fill it\r
265 FileFcb = AllocateFCB ();\r
266 if (FileFcb == NULL) {\r
fdd12bd5
RC
267 Status = EFI_OUT_OF_RESOURCES;\r
268 goto Error;\r
2ef2b01e
A
269 }\r
270\r
271 FileFcb->FileName = AsciiFileName;\r
272 FileFcb->SemihostHandle = SemihostHandle;\r
273 FileFcb->Position = 0;\r
fdd12bd5 274 FileFcb->IsRoot = 0;\r
09f2cf82 275 FileFcb->OpenMode = OpenMode;\r
276\r
fdd12bd5
RC
277 Return = SemihostFileLength (SemihostHandle, &Length);\r
278 if (RETURN_ERROR (Return)) {\r
279 Status = EFI_DEVICE_ERROR;\r
280 FreeFCB (FileFcb);\r
281 goto Error;\r
09f2cf82 282 }\r
2ef2b01e 283\r
fdd12bd5
RC
284 FileFcb->Info.FileSize = Length;\r
285 FileFcb->Info.PhysicalSize = Length;\r
f66c2b32 286 FileFcb->Info.Attribute = ((OpenMode & EFI_FILE_MODE_CREATE) != 0) ?\r
429309e0 287 Attributes : 0;\r
fdd12bd5 288\r
2ef2b01e
A
289 InsertTailList (&gFileList, &FileFcb->Link);\r
290\r
291 *NewHandle = &FileFcb->File;\r
292\r
fdd12bd5
RC
293 return EFI_SUCCESS;\r
294\r
295Error:\r
296\r
297 FreePool (AsciiFileName);\r
298\r
2ef2b01e
A
299 return Status;\r
300}\r
301\r
daefd574
RC
302/**\r
303 Worker function that truncate a file specified by its name to a given size.\r
304\r
305 @param[in] FileName The Null-terminated string of the name of the file to be opened.\r
306 @param[in] Size The target size for the file.\r
307\r
308 @retval EFI_SUCCESS The file was truncated.\r
309 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.\r
310\r
311**/\r
312STATIC\r
313EFI_STATUS\r
314TruncateFile (\r
315 IN CHAR8 *FileName,\r
429309e0 316 IN UINTN Size\r
daefd574
RC
317 )\r
318{\r
319 EFI_STATUS Status;\r
320 RETURN_STATUS Return;\r
321 UINTN FileHandle;\r
322 UINT8 *Buffer;\r
323 UINTN Remaining;\r
324 UINTN Read;\r
325 UINTN ToRead;\r
326\r
327 Status = EFI_DEVICE_ERROR;\r
328 FileHandle = 0;\r
329 Buffer = NULL;\r
330\r
331 Return = SemihostFileOpen (\r
332 FileName,\r
333 SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY,\r
334 &FileHandle\r
335 );\r
336 if (RETURN_ERROR (Return)) {\r
337 goto Error;\r
338 }\r
339\r
340 Buffer = AllocatePool (Size);\r
341 if (Buffer == NULL) {\r
342 Status = EFI_OUT_OF_RESOURCES;\r
343 goto Error;\r
344 }\r
345\r
429309e0 346 Read = 0;\r
daefd574
RC
347 Remaining = Size;\r
348 while (Remaining > 0) {\r
349 ToRead = Remaining;\r
350 Return = SemihostFileRead (FileHandle, &ToRead, Buffer + Read);\r
351 if (RETURN_ERROR (Return)) {\r
352 goto Error;\r
353 }\r
429309e0 354\r
daefd574
RC
355 Remaining -= ToRead;\r
356 Read += ToRead;\r
357 }\r
358\r
429309e0 359 Return = SemihostFileClose (FileHandle);\r
daefd574
RC
360 FileHandle = 0;\r
361 if (RETURN_ERROR (Return)) {\r
362 goto Error;\r
363 }\r
364\r
365 Return = SemihostFileOpen (\r
366 FileName,\r
367 SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY,\r
368 &FileHandle\r
369 );\r
370 if (RETURN_ERROR (Return)) {\r
371 goto Error;\r
372 }\r
373\r
374 if (Size > 0) {\r
375 Return = SemihostFileWrite (FileHandle, &Size, Buffer);\r
376 if (RETURN_ERROR (Return)) {\r
377 goto Error;\r
378 }\r
379 }\r
380\r
381 Status = EFI_SUCCESS;\r
2ef2b01e 382\r
daefd574
RC
383Error:\r
384\r
385 if (FileHandle != 0) {\r
386 SemihostFileClose (FileHandle);\r
387 }\r
429309e0 388\r
daefd574
RC
389 if (Buffer != NULL) {\r
390 FreePool (Buffer);\r
391 }\r
392\r
393 return (Status);\r
daefd574
RC
394}\r
395\r
396/**\r
397 Close a specified file handle.\r
398\r
399 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file\r
400 handle to close.\r
401\r
402 @retval EFI_SUCCESS The file was closed.\r
403 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.\r
404\r
405**/\r
2ef2b01e
A
406EFI_STATUS\r
407FileClose (\r
daefd574 408 IN EFI_FILE *This\r
2ef2b01e
A
409 )\r
410{\r
429309e0 411 SEMIHOST_FCB *Fcb;\r
2ef2b01e 412\r
daefd574
RC
413 if (This == NULL) {\r
414 return EFI_INVALID_PARAMETER;\r
415 }\r
2ef2b01e 416\r
429309e0 417 Fcb = SEMIHOST_FCB_FROM_THIS (This);\r
daefd574
RC
418\r
419 if (!Fcb->IsRoot) {\r
420 SemihostFileClose (Fcb->SemihostHandle);\r
421 //\r
422 // The file size might have been reduced from its actual\r
423 // size on the host file system with FileSetInfo(). In\r
424 // that case, the file has to be truncated.\r
425 //\r
426 if (Fcb->Info.FileSize < Fcb->Info.PhysicalSize) {\r
427 TruncateFile (Fcb->FileName, Fcb->Info.FileSize);\r
2ef2b01e 428 }\r
429309e0 429\r
daefd574 430 FreePool (Fcb->FileName);\r
2ef2b01e 431 }\r
3402aac7 432\r
daefd574
RC
433 FreeFCB (Fcb);\r
434\r
435 return EFI_SUCCESS;\r
2ef2b01e
A
436}\r
437\r
daefd574
RC
438/**\r
439 Close and delete a file.\r
440\r
441 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file\r
442 handle to delete.\r
443\r
444 @retval EFI_SUCCESS The file was closed and deleted.\r
445 @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted.\r
446 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.\r
447\r
448**/\r
2ef2b01e
A
449EFI_STATUS\r
450FileDelete (\r
429309e0 451 IN EFI_FILE *This\r
2ef2b01e
A
452 )\r
453{\r
daefd574
RC
454 SEMIHOST_FCB *Fcb;\r
455 RETURN_STATUS Return;\r
456 CHAR8 *FileName;\r
457 UINTN NameSize;\r
2ef2b01e 458\r
daefd574
RC
459 if (This == NULL) {\r
460 return EFI_INVALID_PARAMETER;\r
461 }\r
462\r
463 Fcb = SEMIHOST_FCB_FROM_THIS (This);\r
2ef2b01e 464\r
3bb46df2 465 if (!Fcb->IsRoot) {\r
466 // Get the filename from the Fcb\r
467 NameSize = AsciiStrLen (Fcb->FileName);\r
468 FileName = AllocatePool (NameSize + 1);\r
2ef2b01e 469\r
f6c4d99a 470 AsciiStrCpyS (FileName, NameSize + 1, Fcb->FileName);\r
2ef2b01e 471\r
3bb46df2 472 // Close the file if it's open. Disregard return status,\r
473 // since it might give an error if the file isn't open.\r
daefd574 474 This->Close (This);\r
3bb46df2 475\r
476 // Call the semihost interface to delete the file.\r
daefd574
RC
477 Return = SemihostFileRemove (FileName);\r
478 if (RETURN_ERROR (Return)) {\r
479 return EFI_WARN_DELETE_FAILURE;\r
09f2cf82 480 }\r
429309e0 481\r
daefd574 482 return EFI_SUCCESS;\r
3bb46df2 483 } else {\r
daefd574 484 return EFI_WARN_DELETE_FAILURE;\r
3bb46df2 485 }\r
2ef2b01e
A
486}\r
487\r
daefd574
RC
488/**\r
489 Read data from an open file.\r
490\r
491 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that\r
492 is the file handle to read data from.\r
493 @param[in out] BufferSize On input, the size of the Buffer. On output, the\r
494 amount of data returned in Buffer. In both cases,\r
495 the size is measured in bytes.\r
496 @param[out] Buffer The buffer into which the data is read.\r
497\r
498 @retval EFI_SUCCESS The data was read.\r
499 @retval EFI_DEVICE_ERROR On entry, the current file position is\r
500 beyond the end of the file, or the semi-hosting\r
501 interface reported an error while performing the\r
502 read operation.\r
503 @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL.\r
504\r
505**/\r
2ef2b01e
A
506EFI_STATUS\r
507FileRead (\r
daefd574
RC
508 IN EFI_FILE *This,\r
509 IN OUT UINTN *BufferSize,\r
510 OUT VOID *Buffer\r
2ef2b01e
A
511 )\r
512{\r
daefd574
RC
513 SEMIHOST_FCB *Fcb;\r
514 EFI_STATUS Status;\r
515 RETURN_STATUS Return;\r
2ef2b01e 516\r
daefd574
RC
517 if ((This == NULL) || (BufferSize == NULL) || (Buffer == NULL)) {\r
518 return EFI_INVALID_PARAMETER;\r
519 }\r
2ef2b01e 520\r
daefd574
RC
521 Fcb = SEMIHOST_FCB_FROM_THIS (This);\r
522\r
523 if (Fcb->IsRoot) {\r
524 // The semi-hosting interface does not allow to list files on the host machine.\r
2ef2b01e
A
525 Status = EFI_UNSUPPORTED;\r
526 } else {\r
daefd574
RC
527 Status = EFI_SUCCESS;\r
528 if (Fcb->Position >= Fcb->Info.FileSize) {\r
529 *BufferSize = 0;\r
530 if (Fcb->Position > Fcb->Info.FileSize) {\r
531 Status = EFI_DEVICE_ERROR;\r
532 }\r
533 } else {\r
534 Return = SemihostFileRead (Fcb->SemihostHandle, BufferSize, Buffer);\r
535 if (RETURN_ERROR (Return)) {\r
536 Status = EFI_DEVICE_ERROR;\r
537 } else {\r
538 Fcb->Position += *BufferSize;\r
539 }\r
2ef2b01e
A
540 }\r
541 }\r
542\r
543 return Status;\r
544}\r
545\r
daefd574
RC
546/**\r
547 Worker function that extends the size of an open file.\r
548\r
549 The extension is filled with zeros.\r
550\r
551 @param[in] Fcb Internal description of the opened file\r
552 @param[in] Size The number of bytes, the file has to be extended.\r
553\r
554 @retval EFI_SUCCESS The file was extended.\r
555 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.\r
556\r
557**/\r
558STATIC\r
559EFI_STATUS\r
560ExtendFile (\r
561 IN SEMIHOST_FCB *Fcb,\r
562 IN UINTN Size\r
563 )\r
564{\r
565 RETURN_STATUS Return;\r
566 UINTN Remaining;\r
567 CHAR8 WriteBuffer[128];\r
568 UINTN WriteNb;\r
569 UINTN WriteSize;\r
570\r
571 Return = SemihostFileSeek (Fcb->SemihostHandle, Fcb->Info.FileSize);\r
572 if (RETURN_ERROR (Return)) {\r
573 return EFI_DEVICE_ERROR;\r
574 }\r
575\r
576 Remaining = Size;\r
429309e0 577 SetMem (WriteBuffer, 0, sizeof (WriteBuffer));\r
daefd574 578 while (Remaining > 0) {\r
429309e0 579 WriteNb = MIN (Remaining, sizeof (WriteBuffer));\r
daefd574 580 WriteSize = WriteNb;\r
429309e0 581 Return = SemihostFileWrite (Fcb->SemihostHandle, &WriteSize, WriteBuffer);\r
daefd574
RC
582 if (RETURN_ERROR (Return)) {\r
583 return EFI_DEVICE_ERROR;\r
584 }\r
429309e0 585\r
daefd574
RC
586 Remaining -= WriteNb;\r
587 }\r
588\r
589 return EFI_SUCCESS;\r
590}\r
591\r
592/**\r
593 Write data to an open file.\r
594\r
595 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that\r
596 is the file handle to write data to.\r
597 @param[in out] BufferSize On input, the size of the Buffer. On output, the\r
598 size of the data actually written. In both cases,\r
599 the size is measured in bytes.\r
600 @param[in] Buffer The buffer of data to write.\r
601\r
602 @retval EFI_SUCCESS The data was written.\r
603 @retval EFI_ACCESS_DENIED Attempt to write into a read only file or\r
604 in a file opened in read only mode.\r
605 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.\r
606 @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL.\r
607\r
608**/\r
2ef2b01e
A
609EFI_STATUS\r
610FileWrite (\r
429309e0
MK
611 IN EFI_FILE *This,\r
612 IN OUT UINTN *BufferSize,\r
613 IN VOID *Buffer\r
2ef2b01e
A
614 )\r
615{\r
daefd574
RC
616 SEMIHOST_FCB *Fcb;\r
617 EFI_STATUS Status;\r
618 UINTN WriteSize;\r
619 RETURN_STATUS Return;\r
620 UINTN Length;\r
2ef2b01e 621\r
daefd574
RC
622 if ((This == NULL) || (BufferSize == NULL) || (Buffer == NULL)) {\r
623 return EFI_INVALID_PARAMETER;\r
624 }\r
625\r
626 Fcb = SEMIHOST_FCB_FROM_THIS (This);\r
2ef2b01e 627\r
09f2cf82 628 // We cannot write a read-only file\r
429309e0
MK
629 if ( (Fcb->Info.Attribute & EFI_FILE_READ_ONLY)\r
630 || !(Fcb->OpenMode & EFI_FILE_MODE_WRITE))\r
631 {\r
09f2cf82 632 return EFI_ACCESS_DENIED;\r
633 }\r
634\r
daefd574
RC
635 //\r
636 // If the position has been set past the end of the file, first grow the\r
637 // file from its current size "Fcb->Info.FileSize" to "Fcb->Position"\r
638 // size, filling the gap with zeros.\r
639 //\r
640 if (Fcb->Position > Fcb->Info.FileSize) {\r
641 Status = ExtendFile (Fcb, Fcb->Position - Fcb->Info.FileSize);\r
642 if (EFI_ERROR (Status)) {\r
643 return Status;\r
644 }\r
429309e0 645\r
daefd574
RC
646 Fcb->Info.FileSize = Fcb->Position;\r
647 }\r
2ef2b01e 648\r
daefd574 649 WriteSize = *BufferSize;\r
429309e0 650 Return = SemihostFileWrite (Fcb->SemihostHandle, &WriteSize, Buffer);\r
daefd574
RC
651 if (RETURN_ERROR (Return)) {\r
652 return EFI_DEVICE_ERROR;\r
2ef2b01e 653 }\r
3402aac7 654\r
daefd574
RC
655 Fcb->Position += *BufferSize;\r
656 if (Fcb->Position > Fcb->Info.FileSize) {\r
657 Fcb->Info.FileSize = Fcb->Position;\r
658 }\r
659\r
660 Return = SemihostFileLength (Fcb->SemihostHandle, &Length);\r
661 if (RETURN_ERROR (Return)) {\r
662 return EFI_DEVICE_ERROR;\r
663 }\r
429309e0 664\r
daefd574
RC
665 Fcb->Info.PhysicalSize = Length;\r
666\r
667 return EFI_SUCCESS;\r
2ef2b01e
A
668}\r
669\r
daefd574
RC
670/**\r
671 Return a file's current position.\r
672\r
673 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is\r
674 the file handle to get the current position on.\r
675 @param[out] Position The address to return the file's current position value.\r
676\r
677 @retval EFI_SUCCESS The position was returned.\r
678 @retval EFI_INVALID_PARAMETER The parameter "This" or "Position" is NULL.\r
679\r
680**/\r
2ef2b01e
A
681EFI_STATUS\r
682FileGetPosition (\r
429309e0
MK
683 IN EFI_FILE *This,\r
684 OUT UINT64 *Position\r
2ef2b01e
A
685 )\r
686{\r
429309e0 687 SEMIHOST_FCB *Fcb;\r
3402aac7 688\r
daefd574 689 if ((This == NULL) || (Position == NULL)) {\r
2ef2b01e
A
690 return EFI_INVALID_PARAMETER;\r
691 }\r
692\r
429309e0 693 Fcb = SEMIHOST_FCB_FROM_THIS (This);\r
2ef2b01e
A
694\r
695 *Position = Fcb->Position;\r
696\r
697 return EFI_SUCCESS;\r
698}\r
699\r
daefd574
RC
700/**\r
701 Set a file's current position.\r
702\r
703 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is\r
704 the file handle to set the requested position on.\r
705 @param[in] Position The byte position from the start of the file to set.\r
706\r
707 @retval EFI_SUCCESS The position was set.\r
ff5fef14 708 @retval EFI_DEVICE_ERROR The semi-hosting positioning operation failed.\r
daefd574
RC
709 @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open\r
710 directories.\r
711 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.\r
712\r
713**/\r
2ef2b01e
A
714EFI_STATUS\r
715FileSetPosition (\r
429309e0
MK
716 IN EFI_FILE *This,\r
717 IN UINT64 Position\r
2ef2b01e
A
718 )\r
719{\r
daefd574
RC
720 SEMIHOST_FCB *Fcb;\r
721 RETURN_STATUS Return;\r
2ef2b01e 722\r
daefd574
RC
723 if (This == NULL) {\r
724 return EFI_INVALID_PARAMETER;\r
725 }\r
2ef2b01e 726\r
daefd574 727 Fcb = SEMIHOST_FCB_FROM_THIS (This);\r
2ef2b01e 728\r
daefd574
RC
729 if (Fcb->IsRoot) {\r
730 if (Position != 0) {\r
731 return EFI_UNSUPPORTED;\r
732 }\r
429309e0 733 } else {\r
daefd574
RC
734 //\r
735 // UEFI Spec section 12.5:\r
736 // "Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to\r
737 // be set to the end of the file."\r
738 //\r
739 if (Position == 0xFFFFFFFFFFFFFFFF) {\r
740 Position = Fcb->Info.FileSize;\r
741 }\r
429309e0 742\r
daefd574
RC
743 Return = SemihostFileSeek (Fcb->SemihostHandle, MIN (Position, Fcb->Info.FileSize));\r
744 if (RETURN_ERROR (Return)) {\r
745 return EFI_DEVICE_ERROR;\r
3bb46df2 746 }\r
2ef2b01e
A
747 }\r
748\r
daefd574
RC
749 Fcb->Position = Position;\r
750\r
751 return EFI_SUCCESS;\r
2ef2b01e
A
752}\r
753\r
daefd574
RC
754/**\r
755 Return information about a file.\r
756\r
757 @param[in] Fcb A pointer to the description of an open file.\r
758 @param[in out] BufferSize The size, in bytes, of Buffer.\r
759 @param[out] Buffer A pointer to the data buffer to return. Not NULL if\r
760 "*BufferSize" is greater than 0.\r
761\r
762 @retval EFI_SUCCESS The information was returned.\r
763 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.\r
764 BufferSize has been updated with the size needed to\r
765 complete the request.\r
766**/\r
2ef2b01e
A
767STATIC\r
768EFI_STATUS\r
769GetFileInfo (\r
770 IN SEMIHOST_FCB *Fcb,\r
daefd574
RC
771 IN OUT UINTN *BufferSize,\r
772 OUT VOID *Buffer\r
2ef2b01e
A
773 )\r
774{\r
429309e0
MK
775 EFI_FILE_INFO *Info;\r
776 UINTN NameSize;\r
777 UINTN ResultSize;\r
778 UINTN Index;\r
2ef2b01e 779\r
17ad8ce7 780 if (Fcb->IsRoot) {\r
429309e0
MK
781 NameSize = 0;\r
782 ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof (CHAR16);\r
2ef2b01e
A
783 } else {\r
784 NameSize = AsciiStrLen (Fcb->FileName) + 1;\r
785 ResultSize = SIZE_OF_EFI_FILE_INFO + NameSize * sizeof (CHAR16);\r
786 }\r
787\r
788 if (*BufferSize < ResultSize) {\r
789 *BufferSize = ResultSize;\r
790 return EFI_BUFFER_TOO_SMALL;\r
791 }\r
792\r
793 Info = Buffer;\r
794\r
09f2cf82 795 // Copy the current file info\r
796 CopyMem (Info, &Fcb->Info, SIZE_OF_EFI_FILE_INFO);\r
2ef2b01e
A
797\r
798 // Fill in the structure\r
799 Info->Size = ResultSize;\r
800\r
17ad8ce7 801 if (Fcb->IsRoot) {\r
429309e0 802 Info->FileName[0] = L'\0';\r
2ef2b01e 803 } else {\r
2ef2b01e 804 for (Index = 0; Index < NameSize; Index++) {\r
3402aac7 805 Info->FileName[Index] = Fcb->FileName[Index];\r
2ef2b01e
A
806 }\r
807 }\r
808\r
3402aac7 809 *BufferSize = ResultSize;\r
2ef2b01e
A
810\r
811 return EFI_SUCCESS;\r
812}\r
813\r
daefd574
RC
814/**\r
815 Return information about a file system.\r
816\r
817 @param[in] Fcb A pointer to the description of an open file\r
818 which belongs to the file system, the information\r
819 is requested for.\r
820 @param[in out] BufferSize The size, in bytes, of Buffer.\r
821 @param[out] Buffer A pointer to the data buffer to return. Not NULL if\r
822 "*BufferSize" is greater than 0.\r
823\r
824 @retval EFI_SUCCESS The information was returned.\r
825 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.\r
826 BufferSize has been updated with the size needed to\r
827 complete the request.\r
828\r
829**/\r
2ef2b01e
A
830STATIC\r
831EFI_STATUS\r
832GetFilesystemInfo (\r
429309e0
MK
833 IN SEMIHOST_FCB *Fcb,\r
834 IN OUT UINTN *BufferSize,\r
835 OUT VOID *Buffer\r
2ef2b01e
A
836 )\r
837{\r
daefd574
RC
838 EFI_FILE_SYSTEM_INFO *Info;\r
839 EFI_STATUS Status;\r
840 UINTN ResultSize;\r
f6c4d99a 841 UINTN StringSize;\r
daefd574 842\r
f6c4d99a
AB
843 StringSize = StrSize (mSemihostFsLabel);\r
844 ResultSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StringSize;\r
3402aac7 845\r
09f2cf82 846 if (*BufferSize >= ResultSize) {\r
2ef2b01e
A
847 ZeroMem (Buffer, ResultSize);\r
848 Status = EFI_SUCCESS;\r
3402aac7 849\r
2ef2b01e
A
850 Info = Buffer;\r
851\r
852 Info->Size = ResultSize;\r
853 Info->ReadOnly = FALSE;\r
854 Info->VolumeSize = 0;\r
855 Info->FreeSpace = 0;\r
856 Info->BlockSize = 0;\r
857\r
f6c4d99a 858 CopyMem (Info->VolumeLabel, mSemihostFsLabel, StringSize);\r
2ef2b01e
A
859 } else {\r
860 Status = EFI_BUFFER_TOO_SMALL;\r
861 }\r
862\r
3402aac7 863 *BufferSize = ResultSize;\r
2ef2b01e
A
864 return Status;\r
865}\r
866\r
daefd574
RC
867/**\r
868 Return information about a file or a file system.\r
869\r
870 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that\r
871 is the file handle the requested information is for.\r
872 @param[in] InformationType The type identifier for the information being requested :\r
873 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or\r
874 EFI_FILE_SYSTEM_VOLUME_LABEL_ID\r
875 @param[in out] BufferSize The size, in bytes, of Buffer.\r
876 @param[out] Buffer A pointer to the data buffer to return. The type of the\r
877 data inside the buffer is indicated by InformationType.\r
878\r
879 @retval EFI_SUCCESS The information was returned.\r
880 @retval EFI_UNSUPPORTED The InformationType is not known.\r
881 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.\r
882 BufferSize has been updated with the size needed to\r
883 complete the request.\r
884 @retval EFI_INVALID_PARAMETER The parameter "This" or "InformationType" or "BufferSize"\r
885 is NULL or "Buffer" is NULL and "*Buffersize" is greater\r
886 than 0.\r
887\r
888**/\r
2ef2b01e
A
889EFI_STATUS\r
890FileGetInfo (\r
daefd574
RC
891 IN EFI_FILE *This,\r
892 IN EFI_GUID *InformationType,\r
893 IN OUT UINTN *BufferSize,\r
894 OUT VOID *Buffer\r
2ef2b01e
A
895 )\r
896{\r
429309e0
MK
897 SEMIHOST_FCB *Fcb;\r
898 EFI_STATUS Status;\r
899 UINTN ResultSize;\r
3402aac7 900\r
daefd574
RC
901 if ((This == NULL) ||\r
902 (InformationType == NULL) ||\r
903 (BufferSize == NULL) ||\r
429309e0
MK
904 ((Buffer == NULL) && (*BufferSize > 0)))\r
905 {\r
daefd574
RC
906 return EFI_INVALID_PARAMETER;\r
907 }\r
908\r
429309e0 909 Fcb = SEMIHOST_FCB_FROM_THIS (This);\r
3402aac7 910\r
daefd574 911 if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {\r
09f2cf82 912 Status = GetFilesystemInfo (Fcb, BufferSize, Buffer);\r
daefd574 913 } else if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
09f2cf82 914 Status = GetFileInfo (Fcb, BufferSize, Buffer);\r
daefd574 915 } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
09f2cf82 916 ResultSize = StrSize (mSemihostFsLabel);\r
917\r
918 if (*BufferSize >= ResultSize) {\r
f6c4d99a 919 CopyMem (Buffer, mSemihostFsLabel, ResultSize);\r
09f2cf82 920 Status = EFI_SUCCESS;\r
921 } else {\r
922 Status = EFI_BUFFER_TOO_SMALL;\r
923 }\r
924\r
925 *BufferSize = ResultSize;\r
926 } else {\r
927 Status = EFI_UNSUPPORTED;\r
2ef2b01e 928 }\r
09f2cf82 929\r
2ef2b01e
A
930 return Status;\r
931}\r
932\r
daefd574
RC
933/**\r
934 Set information about a file.\r
935\r
936 @param[in] Fcb A pointer to the description of the open file.\r
937 @param[in] Info A pointer to the file information to write.\r
938\r
939 @retval EFI_SUCCESS The information was set.\r
940 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file\r
941 to a file that is already present.\r
942 @retval EFI_ACCESS_DENIED An attempt is being made to change the\r
943 EFI_FILE_DIRECTORY Attribute.\r
944 @retval EFI_ACCESS_DENIED The file is a read-only file or has been\r
945 opened in read-only mode and an attempt is\r
946 being made to modify a field other than\r
947 Attribute.\r
948 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a\r
949 read-only attribute.\r
950 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.\r
951 @retval EFI_OUT_OF_RESOURCES A allocation needed to process the request failed.\r
952\r
953**/\r
954STATIC\r
955EFI_STATUS\r
956SetFileInfo (\r
957 IN SEMIHOST_FCB *Fcb,\r
958 IN EFI_FILE_INFO *Info\r
959 )\r
960{\r
961 EFI_STATUS Status;\r
962 RETURN_STATUS Return;\r
963 BOOLEAN FileSizeIsDifferent;\r
964 BOOLEAN FileNameIsDifferent;\r
965 BOOLEAN ReadOnlyIsDifferent;\r
966 CHAR8 *AsciiFileName;\r
967 UINTN FileSize;\r
968 UINTN Length;\r
969 UINTN SemihostHandle;\r
970\r
971 //\r
972 // A directory can not be changed to a file and a file can\r
973 // not be changed to a directory.\r
974 //\r
975 if (((Info->Attribute & EFI_FILE_DIRECTORY) != 0) != Fcb->IsRoot) {\r
976 return EFI_ACCESS_DENIED;\r
977 }\r
978\r
429309e0 979 Length = StrLen (Info->FileName) + 1;\r
f6c4d99a 980 AsciiFileName = AllocatePool (Length);\r
daefd574
RC
981 if (AsciiFileName == NULL) {\r
982 return EFI_OUT_OF_RESOURCES;\r
983 }\r
429309e0 984\r
f6c4d99a 985 UnicodeStrToAsciiStrS (Info->FileName, AsciiFileName, Length);\r
daefd574
RC
986\r
987 FileSizeIsDifferent = (Info->FileSize != Fcb->Info.FileSize);\r
988 FileNameIsDifferent = (AsciiStrCmp (AsciiFileName, Fcb->FileName) != 0);\r
989 ReadOnlyIsDifferent = CompareMem (\r
990 &Info->CreateTime,\r
991 &Fcb->Info.CreateTime,\r
992 3 * sizeof (EFI_TIME)\r
993 ) != 0;\r
994\r
995 //\r
996 // For a read-only file or a file opened in read-only mode, only\r
997 // the Attribute field can be modified. As the root directory is\r
998 // read-only (i.e. VolumeOpen()), this protects the root directory\r
999 // description.\r
1000 //\r
1001 if ((Fcb->OpenMode == EFI_FILE_MODE_READ) ||\r
429309e0
MK
1002 (Fcb->Info.Attribute & EFI_FILE_READ_ONLY))\r
1003 {\r
daefd574
RC
1004 if (FileSizeIsDifferent || FileNameIsDifferent || ReadOnlyIsDifferent) {\r
1005 Status = EFI_ACCESS_DENIED;\r
1006 goto Error;\r
1007 }\r
1008 }\r
1009\r
1010 if (ReadOnlyIsDifferent) {\r
1011 Status = EFI_WRITE_PROTECTED;\r
1012 goto Error;\r
1013 }\r
1014\r
1015 Status = EFI_DEVICE_ERROR;\r
1016\r
1017 if (FileSizeIsDifferent) {\r
1018 FileSize = Info->FileSize;\r
1019 if (Fcb->Info.FileSize < FileSize) {\r
1020 Status = ExtendFile (Fcb, FileSize - Fcb->Info.FileSize);\r
1021 if (EFI_ERROR (Status)) {\r
1022 goto Error;\r
1023 }\r
429309e0 1024\r
daefd574
RC
1025 //\r
1026 // The read/write position from the host file system point of view\r
1027 // is at the end of the file. If the position from this module\r
1028 // point of view is smaller than the new file size, then\r
1029 // ask the host file system to move to that position.\r
1030 //\r
1031 if (Fcb->Position < FileSize) {\r
1032 FileSetPosition (&Fcb->File, Fcb->Position);\r
1033 }\r
1034 }\r
429309e0 1035\r
daefd574
RC
1036 Fcb->Info.FileSize = FileSize;\r
1037\r
1038 Return = SemihostFileLength (Fcb->SemihostHandle, &Length);\r
1039 if (RETURN_ERROR (Return)) {\r
1040 goto Error;\r
1041 }\r
429309e0 1042\r
daefd574
RC
1043 Fcb->Info.PhysicalSize = Length;\r
1044 }\r
1045\r
1046 //\r
1047 // Note down in RAM the Attribute field but we can not ask\r
1048 // for its modification to the host file system as the\r
1049 // semi-host interface does not provide this feature.\r
1050 //\r
1051 Fcb->Info.Attribute = Info->Attribute;\r
1052\r
1053 if (FileNameIsDifferent) {\r
1054 Return = SemihostFileOpen (\r
1055 AsciiFileName,\r
1056 SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY,\r
1057 &SemihostHandle\r
1058 );\r
1059 if (!RETURN_ERROR (Return)) {\r
1060 SemihostFileClose (SemihostHandle);\r
1061 Status = EFI_ACCESS_DENIED;\r
1062 goto Error;\r
1063 }\r
1064\r
1065 Return = SemihostFileRename (Fcb->FileName, AsciiFileName);\r
1066 if (RETURN_ERROR (Return)) {\r
1067 goto Error;\r
1068 }\r
429309e0 1069\r
daefd574
RC
1070 FreePool (Fcb->FileName);\r
1071 Fcb->FileName = AsciiFileName;\r
1072 AsciiFileName = NULL;\r
1073 }\r
1074\r
1075 Status = EFI_SUCCESS;\r
1076\r
1077Error:\r
1078 if (AsciiFileName != NULL) {\r
1079 FreePool (AsciiFileName);\r
1080 }\r
1081\r
1082 return Status;\r
1083}\r
1084\r
1085/**\r
1086 Set information about a file or a file system.\r
1087\r
1088 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that\r
1089 is the file handle the information is for.\r
1090 @param[in] InformationType The type identifier for the information being set :\r
1091 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or\r
1092 EFI_FILE_SYSTEM_VOLUME_LABEL_ID\r
1093 @param[in] BufferSize The size, in bytes, of Buffer.\r
1094 @param[in] Buffer A pointer to the data buffer to write. The type of the\r
1095 data inside the buffer is indicated by InformationType.\r
1096\r
1097 @retval EFI_SUCCESS The information was set.\r
1098 @retval EFI_UNSUPPORTED The InformationType is not known.\r
1099 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.\r
1100 @retval EFI_ACCESS_DENIED An attempt is being made to change the\r
1101 EFI_FILE_DIRECTORY Attribute.\r
1102 @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and\r
1103 the file is a read-only file or has been\r
1104 opened in read-only mode and an attempt is\r
1105 being made to modify a field other than\r
1106 Attribute.\r
1107 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file\r
1108 to a file that is already present.\r
1109 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a\r
1110 read-only attribute.\r
1111 @retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by\r
1112 the data inside the buffer.\r
1113 @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request failed.\r
1114 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
1115\r
1116**/\r
2ef2b01e
A
1117EFI_STATUS\r
1118FileSetInfo (\r
daefd574
RC
1119 IN EFI_FILE *This,\r
1120 IN EFI_GUID *InformationType,\r
1121 IN UINTN BufferSize,\r
1122 IN VOID *Buffer\r
2ef2b01e
A
1123 )\r
1124{\r
daefd574
RC
1125 SEMIHOST_FCB *Fcb;\r
1126 EFI_FILE_INFO *Info;\r
1127 EFI_FILE_SYSTEM_INFO *SystemInfo;\r
1128 CHAR16 *VolumeLabel;\r
09f2cf82 1129\r
daefd574 1130 if ((This == NULL) || (InformationType == NULL) || (Buffer == NULL)) {\r
09f2cf82 1131 return EFI_INVALID_PARAMETER;\r
1132 }\r
1133\r
daefd574
RC
1134 Fcb = SEMIHOST_FCB_FROM_THIS (This);\r
1135\r
1136 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
1137 Info = Buffer;\r
1138 if (Info->Size < (SIZE_OF_EFI_FILE_INFO + StrSize (Info->FileName))) {\r
1139 return EFI_INVALID_PARAMETER;\r
1140 }\r
429309e0 1141\r
daefd574
RC
1142 if (BufferSize < Info->Size) {\r
1143 return EFI_BAD_BUFFER_SIZE;\r
1144 }\r
429309e0 1145\r
daefd574
RC
1146 return SetFileInfo (Fcb, Info);\r
1147 } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {\r
1148 SystemInfo = Buffer;\r
1149 if (SystemInfo->Size <\r
429309e0
MK
1150 (SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (SystemInfo->VolumeLabel)))\r
1151 {\r
daefd574
RC
1152 return EFI_INVALID_PARAMETER;\r
1153 }\r
429309e0 1154\r
daefd574
RC
1155 if (BufferSize < SystemInfo->Size) {\r
1156 return EFI_BAD_BUFFER_SIZE;\r
1157 }\r
429309e0 1158\r
daefd574 1159 Buffer = SystemInfo->VolumeLabel;\r
09f2cf82 1160\r
09f2cf82 1161 if (StrSize (Buffer) > 0) {\r
daefd574
RC
1162 VolumeLabel = AllocateCopyPool (StrSize (Buffer), Buffer);\r
1163 if (VolumeLabel != NULL) {\r
1164 FreePool (mSemihostFsLabel);\r
1165 mSemihostFsLabel = VolumeLabel;\r
1166 return EFI_SUCCESS;\r
1167 } else {\r
1168 return EFI_OUT_OF_RESOURCES;\r
1169 }\r
1170 } else {\r
1171 return EFI_INVALID_PARAMETER;\r
09f2cf82 1172 }\r
daefd574
RC
1173 } else if (!CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
1174 return EFI_UNSUPPORTED;\r
1175 } else {\r
1176 return EFI_UNSUPPORTED;\r
09f2cf82 1177 }\r
2ef2b01e
A
1178}\r
1179\r
1180EFI_STATUS\r
1181FileFlush (\r
429309e0 1182 IN EFI_FILE *File\r
2ef2b01e
A
1183 )\r
1184{\r
429309e0 1185 SEMIHOST_FCB *Fcb;\r
09f2cf82 1186\r
429309e0 1187 Fcb = SEMIHOST_FCB_FROM_THIS (File);\r
09f2cf82 1188\r
1189 if (Fcb->IsRoot) {\r
1190 return EFI_SUCCESS;\r
1191 } else {\r
429309e0
MK
1192 if ( (Fcb->Info.Attribute & EFI_FILE_READ_ONLY)\r
1193 || !(Fcb->OpenMode & EFI_FILE_MODE_WRITE))\r
1194 {\r
09f2cf82 1195 return EFI_ACCESS_DENIED;\r
1196 } else {\r
1197 return EFI_SUCCESS;\r
1198 }\r
1199 }\r
2ef2b01e
A
1200}\r
1201\r
1202EFI_STATUS\r
1203SemihostFsEntryPoint (\r
429309e0
MK
1204 IN EFI_HANDLE ImageHandle,\r
1205 IN EFI_SYSTEM_TABLE *SystemTable\r
2ef2b01e
A
1206 )\r
1207{\r
429309e0 1208 EFI_STATUS Status;\r
09f2cf82 1209\r
1210 Status = EFI_NOT_FOUND;\r
2ef2b01e
A
1211\r
1212 if (SemihostConnectionSupported ()) {\r
09f2cf82 1213 mSemihostFsLabel = AllocateCopyPool (StrSize (DEFAULT_SEMIHOST_FS_LABEL), DEFAULT_SEMIHOST_FS_LABEL);\r
1214 if (mSemihostFsLabel == NULL) {\r
1215 return EFI_OUT_OF_RESOURCES;\r
1216 }\r
1217\r
2ef2b01e 1218 Status = gBS->InstallMultipleProtocolInterfaces (\r
3402aac7 1219 &gInstallHandle,\r
429309e0
MK
1220 &gEfiSimpleFileSystemProtocolGuid,\r
1221 &gSemihostFs,\r
1222 &gEfiDevicePathProtocolGuid,\r
1223 &gDevicePath,\r
2ef2b01e
A
1224 NULL\r
1225 );\r
09f2cf82 1226\r
429309e0 1227 if (EFI_ERROR (Status)) {\r
09f2cf82 1228 FreePool (mSemihostFsLabel);\r
1229 }\r
2ef2b01e 1230 }\r
3402aac7 1231\r
2ef2b01e
A
1232 return Status;\r
1233}\r