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