1 /*++ @file
2   Produce Simple File System abstractions for directories on your PC using Posix APIs.
3   The configuration of what devices to mount or emulate comes from UNIX
4   environment variables. The variables must be visible to the Microsoft*
5   Developer Studio for them to work.
6 
7 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
8 Portions copyright (c) 2011, Apple Inc. All rights reserved.
9 SPDX-License-Identifier: BSD-2-Clause-Patent
10 
11 **/
12 
13 #include "EmuSimpleFileSystem.h"
14 
15 
16 
17 
18 /**
19   Opens a new file relative to the source file's location.
20 
21   @param  This       The protocol instance pointer.
22   @param  NewHandle  Returns File Handle for FileName.
23   @param  FileName   Null terminated string. "\", ".", and ".." are supported.
24   @param  OpenMode   Open mode for file.
25   @param  Attributes Only used for EFI_FILE_MODE_CREATE.
26 
27   @retval EFI_SUCCESS          The device was opened.
28   @retval EFI_NOT_FOUND        The specified file could not be found on the device.
29   @retval EFI_NO_MEDIA         The device has no media.
30   @retval EFI_MEDIA_CHANGED    The media has changed.
31   @retval EFI_DEVICE_ERROR     The device reported an error.
32   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
33   @retval EFI_ACCESS_DENIED    The service denied access to the file.
34   @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
35   @retval EFI_VOLUME_FULL      The volume is full.
36 
37 **/
38 EFI_STATUS
39 EFIAPI
EmuSimpleFileSystemOpen(IN EFI_FILE_PROTOCOL * This,OUT EFI_FILE_PROTOCOL ** NewHandle,IN CHAR16 * FileName,IN UINT64 OpenMode,IN UINT64 Attributes)40 EmuSimpleFileSystemOpen (
41   IN  EFI_FILE_PROTOCOL   *This,
42   OUT EFI_FILE_PROTOCOL   **NewHandle,
43   IN  CHAR16              *FileName,
44   IN  UINT64              OpenMode,
45   IN  UINT64              Attributes
46   )
47 {
48   EFI_STATUS                        Status;
49   EFI_TPL                           OldTpl;
50   EMU_EFI_FILE_PRIVATE              *PrivateFile;
51   EMU_EFI_FILE_PRIVATE              *NewPrivateFile;
52 
53   //
54   // Check for obvious invalid parameters.
55   //
56   if (This == NULL || NewHandle == NULL || FileName == NULL) {
57     return EFI_INVALID_PARAMETER;
58   }
59 
60   switch (OpenMode) {
61   case EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:
62     if (Attributes &~EFI_FILE_VALID_ATTR) {
63       return EFI_INVALID_PARAMETER;
64     }
65 
66     if (Attributes & EFI_FILE_READ_ONLY) {
67       return EFI_INVALID_PARAMETER;
68     }
69 
70   //
71   // fall through
72   //
73   case EFI_FILE_MODE_READ:
74   case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:
75     break;
76 
77   default:
78     return EFI_INVALID_PARAMETER;
79   }
80 
81   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
82 
83   PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
84 
85   NewPrivateFile = AllocateCopyPool (sizeof (EMU_EFI_FILE_PRIVATE), PrivateFile);
86   if (NewPrivateFile == NULL) {
87     Status = EFI_OUT_OF_RESOURCES;
88     goto Done;
89   }
90 
91 
92   Status = PrivateFile->Io->Open (PrivateFile->Io, &NewPrivateFile->Io, FileName, OpenMode, Attributes);
93   if (!EFI_ERROR (Status)) {
94     *NewHandle = &NewPrivateFile->EfiFile;
95   } else {
96     *NewHandle = NULL;
97     FreePool (NewPrivateFile);
98   }
99 
100 Done:
101   gBS->RestoreTPL (OldTpl);
102 
103   return Status;
104 }
105 
106 
107 
108 /**
109   Close the file handle
110 
111   @param  This          Protocol instance pointer.
112 
113   @retval EFI_SUCCESS   The file was closed.
114 
115 **/
116 EFI_STATUS
117 EFIAPI
EmuSimpleFileSystemClose(IN EFI_FILE_PROTOCOL * This)118 EmuSimpleFileSystemClose (
119   IN EFI_FILE_PROTOCOL  *This
120   )
121 {
122   EFI_STATUS              Status;
123   EMU_EFI_FILE_PRIVATE    *PrivateFile;
124   EFI_TPL                 OldTpl;
125 
126   if (This == NULL) {
127     return EFI_INVALID_PARAMETER;
128   }
129 
130   PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
131 
132   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
133 
134   Status = PrivateFile->Io->Close (PrivateFile->Io);
135   if (!EFI_ERROR (Status)) {
136     gBS->FreePool (PrivateFile);
137   }
138 
139   gBS->RestoreTPL (OldTpl);
140 
141   return Status;
142 }
143 
144 
145 /**
146   Close and delete the file handle.
147 
148   @param  This                     Protocol instance pointer.
149 
150   @retval EFI_SUCCESS              The file was closed and deleted.
151   @retval EFI_WARN_DELETE_FAILURE  The handle was closed but the file was not deleted.
152 
153 **/
154 EFI_STATUS
155 EFIAPI
EmuSimpleFileSystemDelete(IN EFI_FILE_PROTOCOL * This)156 EmuSimpleFileSystemDelete (
157   IN EFI_FILE_PROTOCOL  *This
158   )
159 {
160   EFI_STATUS              Status;
161   EMU_EFI_FILE_PRIVATE    *PrivateFile;
162   EFI_TPL                 OldTpl;
163 
164   if (This == NULL) {
165     return EFI_INVALID_PARAMETER;
166   }
167 
168   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
169 
170   PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
171 
172   Status = PrivateFile->Io->Delete (PrivateFile->Io);
173   if (!EFI_ERROR (Status)) {
174     gBS->FreePool (PrivateFile);
175   }
176 
177   gBS->RestoreTPL (OldTpl);
178 
179   return Status;
180 }
181 
182 
183 /**
184   Read data from the file.
185 
186   @param  This       Protocol instance pointer.
187   @param  BufferSize On input size of buffer, on output amount of data in buffer.
188   @param  Buffer     The buffer in which data is read.
189 
190   @retval EFI_SUCCESS          Data was read.
191   @retval EFI_NO_MEDIA         The device has no media.
192   @retval EFI_DEVICE_ERROR     The device reported an error.
193   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
194   @retval EFI_BUFFER_TO_SMALL  BufferSize is too small. BufferSize contains required size.
195 
196 **/
197 EFI_STATUS
198 EFIAPI
EmuSimpleFileSystemRead(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,OUT VOID * Buffer)199 EmuSimpleFileSystemRead (
200   IN     EFI_FILE_PROTOCOL  *This,
201   IN OUT UINTN              *BufferSize,
202   OUT    VOID               *Buffer
203   )
204 {
205   EFI_STATUS              Status;
206   EMU_EFI_FILE_PRIVATE    *PrivateFile;
207   EFI_TPL                 OldTpl;
208 
209   if (This == NULL || BufferSize == NULL) {
210     return EFI_INVALID_PARAMETER;
211   }
212 
213   if ((*BufferSize != 0) && (Buffer == NULL)) {
214     // Buffer can be NULL  if *BufferSize is zero
215     return EFI_INVALID_PARAMETER;
216   }
217 
218   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
219 
220   PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
221 
222   Status = PrivateFile->Io->Read (PrivateFile->Io, BufferSize, Buffer);
223 
224   gBS->RestoreTPL (OldTpl);
225   return Status;
226 }
227 
228 
229 /**
230   Write data to a file.
231 
232   @param  This       Protocol instance pointer.
233   @param  BufferSize On input size of buffer, on output amount of data in buffer.
234   @param  Buffer     The buffer in which data to write.
235 
236   @retval EFI_SUCCESS          Data was written.
237   @retval EFI_UNSUPPORTED      Writes to Open directory are not supported.
238   @retval EFI_NO_MEDIA         The device has no media.
239   @retval EFI_DEVICE_ERROR     The device reported an error.
240   @retval EFI_DEVICE_ERROR     An attempt was made to write to a deleted file.
241   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
242   @retval EFI_WRITE_PROTECTED  The device is write protected.
243   @retval EFI_ACCESS_DENIED    The file was open for read only.
244   @retval EFI_VOLUME_FULL      The volume is full.
245 
246 **/
247 EFI_STATUS
248 EFIAPI
EmuSimpleFileSystemWrite(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)249 EmuSimpleFileSystemWrite (
250   IN     EFI_FILE_PROTOCOL  *This,
251   IN OUT UINTN              *BufferSize,
252   IN     VOID               *Buffer
253   )
254 {
255   EFI_STATUS            Status;
256   EMU_EFI_FILE_PRIVATE *PrivateFile;
257   EFI_TPL               OldTpl;
258 
259   if (This == NULL || BufferSize == NULL || Buffer == NULL) {
260     return EFI_INVALID_PARAMETER;
261   }
262 
263   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
264 
265   PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
266 
267   Status = PrivateFile->Io->Write (PrivateFile->Io, BufferSize, Buffer);
268 
269   gBS->RestoreTPL (OldTpl);
270   return Status;
271 }
272 
273 
274 /**
275   Get a file's current position
276 
277   @param  This            Protocol instance pointer.
278   @param  Position        Byte position from the start of the file.
279 
280   @retval EFI_SUCCESS     Position was updated.
281   @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
282 
283 **/
284 EFI_STATUS
285 EFIAPI
EmuSimpleFileSystemGetPosition(IN EFI_FILE_PROTOCOL * This,OUT UINT64 * Position)286 EmuSimpleFileSystemGetPosition (
287   IN  EFI_FILE_PROTOCOL   *This,
288   OUT UINT64              *Position
289   )
290 {
291   EFI_STATUS            Status;
292   EMU_EFI_FILE_PRIVATE *PrivateFile;
293   EFI_TPL               OldTpl;
294 
295   if (This == NULL || Position == NULL) {
296     return EFI_INVALID_PARAMETER;
297   }
298 
299   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
300 
301   PrivateFile   = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
302 
303   Status = PrivateFile->Io->GetPosition (PrivateFile->Io, Position);
304 
305   gBS->RestoreTPL (OldTpl);
306   return Status;
307 }
308 
309 
310 
311 /**
312   Set file's current position
313 
314   @param  This            Protocol instance pointer.
315   @param  Position        Byte position from the start of the file.
316 
317   @retval EFI_SUCCESS     Position was updated.
318   @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
319 
320 **/
321 EFI_STATUS
322 EFIAPI
EmuSimpleFileSystemSetPosition(IN EFI_FILE_PROTOCOL * This,IN UINT64 Position)323 EmuSimpleFileSystemSetPosition (
324   IN EFI_FILE_PROTOCOL  *This,
325   IN UINT64             Position
326   )
327 {
328   EFI_STATUS              Status;
329   EMU_EFI_FILE_PRIVATE    *PrivateFile;
330   EFI_TPL                 OldTpl;
331 
332   if (This == NULL) {
333     return EFI_INVALID_PARAMETER;
334   }
335 
336   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
337 
338   PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
339 
340   Status = PrivateFile->Io->SetPosition (PrivateFile->Io, Position);
341 
342   gBS->RestoreTPL (OldTpl);
343   return Status;
344 }
345 
346 
347 /**
348   Get information about a file.
349 
350   @param  This            Protocol instance pointer.
351   @param  InformationType Type of information to return in Buffer.
352   @param  BufferSize      On input size of buffer, on output amount of data in buffer.
353   @param  Buffer          The buffer to return data.
354 
355   @retval EFI_SUCCESS          Data was returned.
356   @retval EFI_UNSUPPORTED      InformationType is not supported.
357   @retval EFI_NO_MEDIA         The device has no media.
358   @retval EFI_DEVICE_ERROR     The device reported an error.
359   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
360   @retval EFI_WRITE_PROTECTED  The device is write protected.
361   @retval EFI_ACCESS_DENIED    The file was open for read only.
362   @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
363 
364 **/
365 EFI_STATUS
366 EFIAPI
EmuSimpleFileSystemGetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN OUT UINTN * BufferSize,OUT VOID * Buffer)367 EmuSimpleFileSystemGetInfo (
368   IN     EFI_FILE_PROTOCOL  *This,
369   IN     EFI_GUID           *InformationType,
370   IN OUT UINTN              *BufferSize,
371   OUT    VOID               *Buffer
372   )
373 {
374   EFI_STATUS                        Status;
375   EMU_EFI_FILE_PRIVATE              *PrivateFile;
376   EFI_TPL                           OldTpl;
377 
378   if (This == NULL || InformationType == NULL || BufferSize == NULL) {
379     return EFI_INVALID_PARAMETER;
380   }
381 
382   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
383 
384   PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
385 
386   Status = PrivateFile->Io->GetInfo (PrivateFile->Io, InformationType, BufferSize, Buffer);
387 
388   gBS->RestoreTPL (OldTpl);
389   return Status;
390 }
391 
392 
393 /**
394   Set information about a file
395 
396   @param  File            Protocol instance pointer.
397   @param  InformationType Type of information in Buffer.
398   @param  BufferSize      Size of buffer.
399   @param  Buffer          The data to write.
400 
401   @retval EFI_SUCCESS          Data was set.
402   @retval EFI_UNSUPPORTED      InformationType is not supported.
403   @retval EFI_NO_MEDIA         The device has no media.
404   @retval EFI_DEVICE_ERROR     The device reported an error.
405   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
406   @retval EFI_WRITE_PROTECTED  The device is write protected.
407   @retval EFI_ACCESS_DENIED    The file was open for read only.
408 
409 **/
410 EFI_STATUS
411 EFIAPI
EmuSimpleFileSystemSetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN UINTN BufferSize,IN VOID * Buffer)412 EmuSimpleFileSystemSetInfo (
413   IN EFI_FILE_PROTOCOL*This,
414   IN EFI_GUID         *InformationType,
415   IN UINTN            BufferSize,
416   IN VOID             *Buffer
417   )
418 {
419   EFI_STATUS                        Status;
420   EMU_EFI_FILE_PRIVATE              *PrivateFile;
421   EFI_TPL                           OldTpl;
422 
423   //
424   // Check for invalid parameters.
425   //
426   if (This == NULL || InformationType == NULL || BufferSize == 0 || Buffer == NULL) {
427     return EFI_INVALID_PARAMETER;
428   }
429 
430   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
431 
432   PrivateFile               = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
433 
434   Status = PrivateFile->Io->SetInfo (PrivateFile->Io, InformationType, BufferSize, Buffer);
435 
436   gBS->RestoreTPL (OldTpl);
437   return Status;
438 }
439 
440 
441 /**
442   Flush data back for the file handle.
443 
444   @param  This Protocol instance pointer.
445 
446   @retval EFI_SUCCESS          Data was flushed.
447   @retval EFI_UNSUPPORTED      Writes to Open directory are not supported.
448   @retval EFI_NO_MEDIA         The device has no media.
449   @retval EFI_DEVICE_ERROR     The device reported an error.
450   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
451   @retval EFI_WRITE_PROTECTED  The device is write protected.
452   @retval EFI_ACCESS_DENIED    The file was open for read only.
453   @retval EFI_VOLUME_FULL      The volume is full.
454 
455 **/
456 EFI_STATUS
457 EFIAPI
EmuSimpleFileSystemFlush(IN EFI_FILE_PROTOCOL * This)458 EmuSimpleFileSystemFlush (
459   IN EFI_FILE_PROTOCOL  *This
460   )
461 {
462   EFI_STATUS                Status;
463   EMU_EFI_FILE_PRIVATE      *PrivateFile;
464   EFI_TPL                   OldTpl;
465 
466   if (This == NULL) {
467     return EFI_INVALID_PARAMETER;
468   }
469 
470   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
471 
472   PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
473 
474   Status = PrivateFile->Io->Flush (PrivateFile->Io);
475 
476   gBS->RestoreTPL (OldTpl);
477   return Status;
478 }
479 
480 
481 
482 /**
483   Open the root directory on a volume.
484 
485   @param  This Protocol instance pointer.
486   @param  Root Returns an Open file handle for the root directory
487 
488   @retval EFI_SUCCESS          The device was opened.
489   @retval EFI_UNSUPPORTED      This volume does not support the file system.
490   @retval EFI_NO_MEDIA         The device has no media.
491   @retval EFI_DEVICE_ERROR     The device reported an error.
492   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
493   @retval EFI_ACCESS_DENIED    The service denied access to the file.
494   @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
495 
496 **/
497 EFI_STATUS
498 EFIAPI
EmuSimpleFileSystemOpenVolume(IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL * This,OUT EFI_FILE_PROTOCOL ** Root)499 EmuSimpleFileSystemOpenVolume (
500   IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *This,
501   OUT EFI_FILE_PROTOCOL               **Root
502   )
503 {
504   EFI_STATUS                        Status;
505   EMU_SIMPLE_FILE_SYSTEM_PRIVATE    *Private;
506   EMU_EFI_FILE_PRIVATE              *PrivateFile;
507   EFI_TPL                           OldTpl;
508 
509   Status = EFI_UNSUPPORTED;
510 
511   if (This == NULL || Root == NULL) {
512     return EFI_INVALID_PARAMETER;
513   }
514 
515   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
516 
517   Private = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This);
518 
519   PrivateFile = AllocatePool (sizeof (EMU_EFI_FILE_PRIVATE));
520   if (PrivateFile == NULL) {
521     Status = EFI_OUT_OF_RESOURCES;
522     goto Done;
523   }
524 
525   PrivateFile->Signature            = EMU_EFI_FILE_PRIVATE_SIGNATURE;
526   PrivateFile->IoThunk              = Private->IoThunk;
527   PrivateFile->SimpleFileSystem     = This;
528 
529   ZeroMem (&PrivateFile->EfiFile, sizeof (PrivateFile->EfiFile));
530   PrivateFile->EfiFile.Revision     = EFI_FILE_PROTOCOL_REVISION;
531   PrivateFile->EfiFile.Open         = EmuSimpleFileSystemOpen;
532   PrivateFile->EfiFile.Close        = EmuSimpleFileSystemClose;
533   PrivateFile->EfiFile.Delete       = EmuSimpleFileSystemDelete;
534   PrivateFile->EfiFile.Read         = EmuSimpleFileSystemRead;
535   PrivateFile->EfiFile.Write        = EmuSimpleFileSystemWrite;
536   PrivateFile->EfiFile.GetPosition  = EmuSimpleFileSystemGetPosition;
537   PrivateFile->EfiFile.SetPosition  = EmuSimpleFileSystemSetPosition;
538   PrivateFile->EfiFile.GetInfo      = EmuSimpleFileSystemGetInfo;
539   PrivateFile->EfiFile.SetInfo      = EmuSimpleFileSystemSetInfo;
540   PrivateFile->EfiFile.Flush        = EmuSimpleFileSystemFlush;
541 
542   *Root = &PrivateFile->EfiFile;
543 
544   Status = Private->Io->OpenVolume (Private->Io, &PrivateFile->Io);
545   if (EFI_ERROR (Status)) {
546     goto Done;
547   }
548 
549   AddUnicodeString2 (
550     "eng",
551     gEmuSimpleFileSystemComponentName.SupportedLanguages,
552     &Private->ControllerNameTable,
553     Private->IoThunk->ConfigString,
554     TRUE
555     );
556 
557   AddUnicodeString2 (
558     "en",
559     gEmuSimpleFileSystemComponentName.SupportedLanguages,
560     &Private->ControllerNameTable,
561     Private->IoThunk->ConfigString,
562     FALSE
563     );
564 
565 
566 Done:
567   if (EFI_ERROR (Status)) {
568     if (PrivateFile) {
569       gBS->FreePool (PrivateFile);
570     }
571 
572     *Root = NULL;
573   }
574 
575   gBS->RestoreTPL (OldTpl);
576 
577   return Status;
578 }
579 
580 /**
581   Tests to see if this driver supports a given controller. If a child device is provided,
582   it further tests to see if this driver supports creating a handle for the specified child device.
583 
584   This function checks to see if the driver specified by This supports the device specified by
585   ControllerHandle. Drivers will typically use the device path attached to
586   ControllerHandle and/or the services from the bus I/O abstraction attached to
587   ControllerHandle to determine if the driver supports ControllerHandle. This function
588   may be called many times during platform initialization. In order to reduce boot times, the tests
589   performed by this function must be very small, and take as little time as possible to execute. This
590   function must not change the state of any hardware devices, and this function must be aware that the
591   device specified by ControllerHandle may already be managed by the same driver or a
592   different driver. This function must match its calls to AllocatePages() with FreePages(),
593   AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
594   Because ControllerHandle may have been previously started by the same driver, if a protocol is
595   already in the opened state, then it must not be closed with CloseProtocol(). This is required
596   to guarantee the state of ControllerHandle is not modified by this function.
597 
598   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
599   @param[in]  ControllerHandle     The handle of the controller to test. This handle
600                                    must support a protocol interface that supplies
601                                    an I/O abstraction to the driver.
602   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
603                                    parameter is ignored by device drivers, and is optional for bus
604                                    drivers. For bus drivers, if this parameter is not NULL, then
605                                    the bus driver must determine if the bus controller specified
606                                    by ControllerHandle and the child controller specified
607                                    by RemainingDevicePath are both supported by this
608                                    bus driver.
609 
610   @retval EFI_SUCCESS              The device specified by ControllerHandle and
611                                    RemainingDevicePath is supported by the driver specified by This.
612   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
613                                    RemainingDevicePath is already being managed by the driver
614                                    specified by This.
615   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
616                                    RemainingDevicePath is already being managed by a different
617                                    driver or an application that requires exclusive access.
618                                    Currently not implemented.
619   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
620                                    RemainingDevicePath is not supported by the driver specified by This.
621 **/
622 EFI_STATUS
623 EFIAPI
EmuSimpleFileSystemDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)624 EmuSimpleFileSystemDriverBindingSupported (
625   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
626   IN  EFI_HANDLE                   ControllerHandle,
627   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
628   )
629 {
630   EFI_STATUS              Status;
631   EMU_IO_THUNK_PROTOCOL  *EmuIoThunk;
632 
633   //
634   // Open the IO Abstraction(s) needed to perform the supported test
635   //
636   Status = gBS->OpenProtocol (
637                   ControllerHandle,
638                   &gEmuIoThunkProtocolGuid,
639                   (VOID **)&EmuIoThunk,
640                   This->DriverBindingHandle,
641                   ControllerHandle,
642                   EFI_OPEN_PROTOCOL_BY_DRIVER
643                   );
644   if (EFI_ERROR (Status)) {
645     return Status;
646   }
647 
648   //
649   // Make sure GUID is for a File System handle.
650   //
651   Status = EFI_UNSUPPORTED;
652   if (CompareGuid (EmuIoThunk->Protocol, &gEfiSimpleFileSystemProtocolGuid)) {
653     Status = EFI_SUCCESS;
654   }
655 
656   //
657   // Close the I/O Abstraction(s) used to perform the supported test
658   //
659   gBS->CloseProtocol (
660         ControllerHandle,
661         &gEmuIoThunkProtocolGuid,
662         This->DriverBindingHandle,
663         ControllerHandle
664         );
665 
666   return Status;
667 }
668 
669 
670 
671 /**
672   Starts a device controller or a bus controller.
673 
674   The Start() function is designed to be invoked from the EFI boot service ConnectController().
675   As a result, much of the error checking on the parameters to Start() has been moved into this
676   common boot service. It is legal to call Start() from other locations,
677   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
678   1. ControllerHandle must be a valid EFI_HANDLE.
679   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
680      EFI_DEVICE_PATH_PROTOCOL.
681   3. Prior to calling Start(), the Supported() function for the driver specified by This must
682      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
683 
684   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
685   @param[in]  ControllerHandle     The handle of the controller to start. This handle
686                                    must support a protocol interface that supplies
687                                    an I/O abstraction to the driver.
688   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
689                                    parameter is ignored by device drivers, and is optional for bus
690                                    drivers. For a bus driver, if this parameter is NULL, then handles
691                                    for all the children of Controller are created by this driver.
692                                    If this parameter is not NULL and the first Device Path Node is
693                                    not the End of Device Path Node, then only the handle for the
694                                    child device specified by the first Device Path Node of
695                                    RemainingDevicePath is created by this driver.
696                                    If the first Device Path Node of RemainingDevicePath is
697                                    the End of Device Path Node, no child handle is created by this
698                                    driver.
699 
700   @retval EFI_SUCCESS              The device was started.
701   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
702   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
703   @retval Others                   The driver failded to start the device.
704 
705 **/
706 EFI_STATUS
707 EFIAPI
EmuSimpleFileSystemDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)708 EmuSimpleFileSystemDriverBindingStart (
709   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
710   IN  EFI_HANDLE                    ControllerHandle,
711   IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath
712   )
713 {
714   EFI_STATUS                        Status;
715   EMU_IO_THUNK_PROTOCOL             *EmuIoThunk;
716   EMU_SIMPLE_FILE_SYSTEM_PRIVATE    *Private;
717 
718   Private = NULL;
719 
720   //
721   // Open the IO Abstraction(s) needed
722   //
723   Status = gBS->OpenProtocol (
724                   ControllerHandle,
725                   &gEmuIoThunkProtocolGuid,
726                   (VOID **)&EmuIoThunk,
727                   This->DriverBindingHandle,
728                   ControllerHandle,
729                   EFI_OPEN_PROTOCOL_BY_DRIVER
730                   );
731   if (EFI_ERROR (Status)) {
732     return Status;
733   }
734 
735   //
736   // Validate GUID
737   //
738   if (!CompareGuid (EmuIoThunk->Protocol, &gEfiSimpleFileSystemProtocolGuid)) {
739     Status = EFI_UNSUPPORTED;
740     goto Done;
741   }
742 
743   Private = AllocateZeroPool (sizeof (EMU_SIMPLE_FILE_SYSTEM_PRIVATE));
744   if (Private == NULL) {
745     Status = EFI_OUT_OF_RESOURCES;
746     goto Done;
747   }
748 
749   Status = EmuIoThunk->Open (EmuIoThunk);
750   if (EFI_ERROR (Status)) {
751     goto Done;
752   }
753 
754   Private->Signature = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE;
755   Private->IoThunk   = EmuIoThunk;
756   Private->Io        = EmuIoThunk->Interface;
757 
758   Private->SimpleFileSystem.Revision    = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
759   Private->SimpleFileSystem.OpenVolume  = EmuSimpleFileSystemOpenVolume;
760 
761   Private->ControllerNameTable = NULL;
762 
763   AddUnicodeString2 (
764     "eng",
765     gEmuSimpleFileSystemComponentName.SupportedLanguages,
766     &Private->ControllerNameTable,
767     EmuIoThunk->ConfigString,
768     TRUE
769     );
770 
771   AddUnicodeString2 (
772     "en",
773     gEmuSimpleFileSystemComponentName2.SupportedLanguages,
774     &Private->ControllerNameTable,
775     EmuIoThunk->ConfigString,
776     FALSE
777     );
778 
779   Status = gBS->InstallMultipleProtocolInterfaces (
780                   &ControllerHandle,
781                   &gEfiSimpleFileSystemProtocolGuid,  &Private->SimpleFileSystem,
782                   NULL
783                   );
784 
785 Done:
786   if (EFI_ERROR (Status)) {
787     if (Private != NULL) {
788       if (Private->ControllerNameTable != NULL) {
789         FreeUnicodeStringTable (Private->ControllerNameTable);
790       }
791 
792       gBS->FreePool (Private);
793 
794     }
795 
796     gBS->CloseProtocol (
797           ControllerHandle,
798           &gEmuIoThunkProtocolGuid,
799           This->DriverBindingHandle,
800           ControllerHandle
801           );
802   }
803 
804   return Status;
805 }
806 
807 
808 /**
809   Stops a device controller or a bus controller.
810 
811   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
812   As a result, much of the error checking on the parameters to Stop() has been moved
813   into this common boot service. It is legal to call Stop() from other locations,
814   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
815   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
816      same driver's Start() function.
817   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
818      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
819      Start() function, and the Start() function must have called OpenProtocol() on
820      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
821 
822   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
823   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
824                                 support a bus specific I/O protocol for the driver
825                                 to use to stop the device.
826   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
827   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
828                                 if NumberOfChildren is 0.
829 
830   @retval EFI_SUCCESS           The device was stopped.
831   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
832 
833 **/
834 EFI_STATUS
835 EFIAPI
EmuSimpleFileSystemDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)836 EmuSimpleFileSystemDriverBindingStop (
837   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
838   IN  EFI_HANDLE                   ControllerHandle,
839   IN  UINTN                        NumberOfChildren,
840   IN  EFI_HANDLE                   *ChildHandleBuffer
841   )
842 {
843   EFI_STATUS                        Status;
844   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *SimpleFileSystem;
845   EMU_SIMPLE_FILE_SYSTEM_PRIVATE    *Private;
846 
847   //
848   // Get our context back
849   //
850   Status = gBS->OpenProtocol (
851                   ControllerHandle,
852                   &gEfiSimpleFileSystemProtocolGuid,
853                   (VOID **)&SimpleFileSystem,
854                   This->DriverBindingHandle,
855                   ControllerHandle,
856                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
857                   );
858   if (EFI_ERROR (Status)) {
859     return EFI_UNSUPPORTED;
860   }
861 
862   Private = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (SimpleFileSystem);
863 
864   //
865   // Uninstall the Simple File System Protocol from ControllerHandle
866   //
867   Status = gBS->UninstallMultipleProtocolInterfaces (
868                   ControllerHandle,
869                   &gEfiSimpleFileSystemProtocolGuid,  &Private->SimpleFileSystem,
870                   NULL
871                   );
872   if (!EFI_ERROR (Status)) {
873     Status = gBS->CloseProtocol (
874                     ControllerHandle,
875                     &gEmuIoThunkProtocolGuid,
876                     This->DriverBindingHandle,
877                     ControllerHandle
878                     );
879     ASSERT_EFI_ERROR (Status);
880     //
881     // Destroy the IO interface.
882     //
883     Status = Private->IoThunk->Close (Private->IoThunk);
884     ASSERT_EFI_ERROR (Status);
885     //
886     // Free our instance data
887     //
888     FreeUnicodeStringTable (Private->ControllerNameTable);
889     gBS->FreePool (Private);
890   }
891 
892   return Status;
893 }
894 
895 
896 EFI_DRIVER_BINDING_PROTOCOL gEmuSimpleFileSystemDriverBinding = {
897   EmuSimpleFileSystemDriverBindingSupported,
898   EmuSimpleFileSystemDriverBindingStart,
899   EmuSimpleFileSystemDriverBindingStop,
900   0xa,
901   NULL,
902   NULL
903 };
904 
905 
906 
907 
908 /**
909   The user Entry Point for module EmuSimpleFileSystem. The user code starts with this function.
910 
911   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
912   @param[in] SystemTable    A pointer to the EFI System Table.
913 
914   @retval EFI_SUCCESS       The entry point is executed successfully.
915   @retval other             Some error occurs when executing this entry point.
916 
917 **/
918 EFI_STATUS
919 EFIAPI
InitializeEmuSimpleFileSystem(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)920 InitializeEmuSimpleFileSystem(
921   IN EFI_HANDLE           ImageHandle,
922   IN EFI_SYSTEM_TABLE     *SystemTable
923   )
924 {
925   EFI_STATUS              Status;
926 
927   Status = EfiLibInstallDriverBindingComponentName2 (
928              ImageHandle,
929              SystemTable,
930              &gEmuSimpleFileSystemDriverBinding,
931              ImageHandle,
932              &gEmuSimpleFileSystemComponentName,
933              &gEmuSimpleFileSystemComponentName2
934              );
935   ASSERT_EFI_ERROR (Status);
936 
937   return Status;
938 }
939