3 * EFI host environment code.
7 * Copyright (c) 2006 Christoph Pfisterer
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are
13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the
21 * * Neither the name of Christoph Pfisterer nor the names of the
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 * Changes by Roderick Smith are licensed under the preceding terms.
43 #ifdef __MAKEWITH_GNUEFI
44 #include "edk2/DriverBinding.h"
45 #include "edk2/ComponentName.h"
47 #include "../include/refit_call_wrapper.h"
52 /** The file system type name to use. */
56 #ifdef __MAKEWITH_GNUEFI
58 #define EFI_DISK_IO_PROTOCOL_GUID \
60 0xce345171, 0xba0b, 0x11d2, {0x8e, 0x4f, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
63 #define EFI_BLOCK_IO_PROTOCOL_GUID \
65 0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
68 EFI_GUID gEfiDriverBindingProtocolGuid
= EFI_DRIVER_BINDING_PROTOCOL_GUID
;
69 EFI_GUID gEfiComponentNameProtocolGuid
= EFI_COMPONENT_NAME_PROTOCOL_GUID
;
70 EFI_GUID gEfiDiskIoProtocolGuid
= EFI_DISK_IO_PROTOCOL_GUID
;
71 EFI_GUID gEfiBlockIoProtocolGuid
= EFI_BLOCK_IO_PROTOCOL_GUID
;
72 EFI_GUID gEfiFileInfoGuid
= EFI_FILE_INFO_ID
;
73 EFI_GUID gEfiFileSystemInfoGuid
= EFI_FILE_SYSTEM_INFO_ID
;
74 EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid
= EFI_FILE_SYSTEM_VOLUME_LABEL_INFO_ID
;
75 #define gEfiSimpleFileSystemProtocolGuid FileSystemProtocol
78 /** Helper macro for stringification. */
79 #define FSW_EFI_STRINGIFY(x) #x
80 /** Expands to the EFI driver name given the file system type name. */
81 #define FSW_EFI_DRIVER_NAME(t) L"rEFInd 0.10.1 " FSW_EFI_STRINGIFY(t) L" File System Driver"
83 // function prototypes
85 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
86 IN EFI_HANDLE ControllerHandle
,
87 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
);
88 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
89 IN EFI_HANDLE ControllerHandle
,
90 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
);
91 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
92 IN EFI_HANDLE ControllerHandle
,
93 IN UINTN NumberOfChildren
,
94 IN EFI_HANDLE
*ChildHandleBuffer
);
96 EFI_STATUS EFIAPI
fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
98 OUT CHAR16
**DriverName
);
99 EFI_STATUS EFIAPI
fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
100 IN EFI_HANDLE ControllerHandle
,
101 IN EFI_HANDLE ChildHandle OPTIONAL
,
103 OUT CHAR16
**ControllerName
);
105 void EFIAPI
fsw_efi_change_blocksize(struct fsw_volume
*vol
,
106 fsw_u32 old_phys_blocksize
, fsw_u32 old_log_blocksize
,
107 fsw_u32 new_phys_blocksize
, fsw_u32 new_log_blocksize
);
108 fsw_status_t EFIAPI
fsw_efi_read_block(struct fsw_volume
*vol
, fsw_u64 phys_bno
, void *buffer
);
110 EFI_STATUS
fsw_efi_map_status(fsw_status_t fsw_status
, FSW_VOLUME_DATA
*Volume
);
112 EFI_STATUS EFIAPI
fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE
*This
,
113 OUT EFI_FILE
**Root
);
114 EFI_STATUS
fsw_efi_dnode_to_FileHandle(IN
struct fsw_dnode
*dno
,
115 OUT EFI_FILE
**NewFileHandle
);
117 EFI_STATUS
fsw_efi_file_read(IN FSW_FILE_DATA
*File
,
118 IN OUT UINTN
*BufferSize
,
120 EFI_STATUS
fsw_efi_file_getpos(IN FSW_FILE_DATA
*File
,
121 OUT UINT64
*Position
);
122 EFI_STATUS
fsw_efi_file_setpos(IN FSW_FILE_DATA
*File
,
125 EFI_STATUS
fsw_efi_dir_open(IN FSW_FILE_DATA
*File
,
126 OUT EFI_FILE
**NewHandle
,
129 IN UINT64 Attributes
);
130 EFI_STATUS
fsw_efi_dir_read(IN FSW_FILE_DATA
*File
,
131 IN OUT UINTN
*BufferSize
,
133 EFI_STATUS
fsw_efi_dir_setpos(IN FSW_FILE_DATA
*File
,
136 EFI_STATUS
fsw_efi_dnode_getinfo(IN FSW_FILE_DATA
*File
,
137 IN EFI_GUID
*InformationType
,
138 IN OUT UINTN
*BufferSize
,
140 EFI_STATUS
fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA
*Volume
,
141 IN
struct fsw_dnode
*dno
,
142 IN OUT UINTN
*BufferSize
,
146 * Structure for holding disk cache data.
149 #define CACHE_SIZE 131072 /* 128KiB */
154 FSW_VOLUME_DATA
*Volume
; // NOTE: Do not deallocate; copied here to ID volume
157 #define NUM_CACHES 2 /* Don't increase without modifying fsw_efi_read_block() */
158 static struct cache_data Caches
[NUM_CACHES
];
159 static int LastRead
= -1;
162 * Interface structure for the EFI Driver Binding protocol.
165 EFI_DRIVER_BINDING_PROTOCOL fsw_efi_DriverBinding_table
= {
166 fsw_efi_DriverBinding_Supported
,
167 fsw_efi_DriverBinding_Start
,
168 fsw_efi_DriverBinding_Stop
,
175 * Interface structure for the EFI Component Name protocol.
178 EFI_COMPONENT_NAME_PROTOCOL fsw_efi_ComponentName_table
= {
179 fsw_efi_ComponentName_GetDriverName
,
180 fsw_efi_ComponentName_GetControllerName
,
185 * Dispatch table for our FSW host driver.
188 struct fsw_host_table fsw_efi_host_table
= {
189 FSW_STRING_TYPE_UTF16
,
191 fsw_efi_change_blocksize
,
195 extern struct fsw_fstype_table
FSW_FSTYPE_TABLE_NAME(FSTYPE
);
198 static VOID EFIAPI
fsw_efi_clear_cache(VOID
) {
202 for (i
= 0; i
< NUM_CACHES
; i
++) {
203 if (Caches
[i
].Cache
!= NULL
) {
204 FreePool(Caches
[i
].Cache
);
205 Caches
[i
].Cache
= NULL
;
207 Caches
[i
].CacheStart
= 0;
208 Caches
[i
].CacheValid
= FALSE
;
209 Caches
[i
].Volume
= NULL
;
212 } // VOID EFIAPI fsw_efi_clear_cache();
215 * Image entry point. Installs the Driver Binding and Component Name protocols
216 * on the image's handle. Actually mounting a file system is initiated through
217 * the Driver Binding protocol at the firmware's request.
219 EFI_STATUS EFIAPI
fsw_efi_main(IN EFI_HANDLE ImageHandle
,
220 IN EFI_SYSTEM_TABLE
*SystemTable
)
224 #ifndef __MAKEWITH_TIANO
225 // Not available in EDK2 toolkit
226 InitializeLib(ImageHandle
, SystemTable
);
229 // complete Driver Binding protocol instance
230 fsw_efi_DriverBinding_table
.ImageHandle
= ImageHandle
;
231 fsw_efi_DriverBinding_table
.DriverBindingHandle
= ImageHandle
;
232 // install Driver Binding protocol
233 Status
= refit_call4_wrapper(BS
->InstallProtocolInterface
, &fsw_efi_DriverBinding_table
.DriverBindingHandle
,
234 &gEfiDriverBindingProtocolGuid
,
235 EFI_NATIVE_INTERFACE
,
236 &fsw_efi_DriverBinding_table
);
237 if (EFI_ERROR (Status
)) {
241 // install Component Name protocol
242 Status
= refit_call4_wrapper(BS
->InstallProtocolInterface
, &fsw_efi_DriverBinding_table
.DriverBindingHandle
,
243 &gEfiComponentNameProtocolGuid
,
244 EFI_NATIVE_INTERFACE
,
245 &fsw_efi_ComponentName_table
);
246 if (EFI_ERROR (Status
)) {
250 // OverrideFunctions();
253 // Status = BS->LocateProtocol(&gMsgLogProtocolGuid, NULL, (VOID **) &Msg);
254 // if (!EFI_ERROR(Status) && (Msg != NULL)) {
255 // msgCursor = Msg->Cursor;
256 // BootLog("MsgLog installed into VBoxFs\n");
262 #ifdef __MAKEWITH_GNUEFI
263 EFI_DRIVER_ENTRY_POINT(fsw_efi_main
)
267 * Driver Binding EFI protocol, Supported function. This function is called by EFI
268 * to test if this driver can handle a certain device. Our implementation only checks
269 * if the device is a disk (i.e. that it supports the Block I/O and Disk I/O protocols)
270 * and implicitly checks if the disk is already in use by another driver.
273 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
274 IN EFI_HANDLE ControllerHandle
,
275 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
)
280 // we check for both DiskIO and BlockIO protocols
282 // first, open DiskIO
283 Status
= refit_call6_wrapper(BS
->OpenProtocol
, ControllerHandle
,
284 &gEfiDiskIoProtocolGuid
,
286 This
->DriverBindingHandle
,
288 EFI_OPEN_PROTOCOL_BY_DRIVER
);
289 if (EFI_ERROR(Status
))
292 // we were just checking, close it again
293 refit_call4_wrapper(BS
->CloseProtocol
, ControllerHandle
,
294 &gEfiDiskIoProtocolGuid
,
295 This
->DriverBindingHandle
,
298 // next, check BlockIO without actually opening it
299 Status
= refit_call6_wrapper(BS
->OpenProtocol
, ControllerHandle
,
300 &gEfiBlockIoProtocolGuid
,
302 This
->DriverBindingHandle
,
304 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
309 * Driver Binding EFI protocol, Start function. This function is called by EFI
310 * to start driving the given device. It is still possible at this point to
311 * return EFI_UNSUPPORTED, and in fact we will do so if the file system driver
312 * cannot find the superblock signature (or equivalent) that it expects.
314 * This function allocates memory for a per-volume structure, opens the
315 * required protocols (just Disk I/O in our case, Block I/O is only looked
316 * at to get the MediaId field), and lets the FSW core mount the file system.
317 * If successful, an EFI Simple File System protocol is exported on the
321 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
322 IN EFI_HANDLE ControllerHandle
,
323 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
)
326 EFI_BLOCK_IO
*BlockIo
;
328 FSW_VOLUME_DATA
*Volume
;
331 Print(L
"fsw_efi_DriverBinding_Start\n");
334 // open consumed protocols
335 Status
= refit_call6_wrapper(BS
->OpenProtocol
, ControllerHandle
,
336 &gEfiBlockIoProtocolGuid
,
338 This
->DriverBindingHandle
,
340 EFI_OPEN_PROTOCOL_GET_PROTOCOL
); // NOTE: we only want to look at the MediaId
341 if (EFI_ERROR(Status
)) {
342 // Print(L"Fsw ERROR: OpenProtocol(BlockIo) returned %x\n", Status);
346 Status
= refit_call6_wrapper(BS
->OpenProtocol
, ControllerHandle
,
347 &gEfiDiskIoProtocolGuid
,
349 This
->DriverBindingHandle
,
351 EFI_OPEN_PROTOCOL_BY_DRIVER
);
352 if (EFI_ERROR(Status
)) {
353 Print(L
"Fsw ERROR: OpenProtocol(DiskIo) returned %x\n", Status
);
357 // allocate volume structure
358 Volume
= AllocateZeroPool(sizeof(FSW_VOLUME_DATA
));
359 Volume
->Signature
= FSW_VOLUME_DATA_SIGNATURE
;
360 Volume
->Handle
= ControllerHandle
;
361 Volume
->DiskIo
= DiskIo
;
362 Volume
->MediaId
= BlockIo
->Media
->MediaId
;
363 Volume
->LastIOStatus
= EFI_SUCCESS
;
365 // mount the filesystem
366 Status
= fsw_efi_map_status(fsw_mount(Volume
, &fsw_efi_host_table
,
367 &FSW_FSTYPE_TABLE_NAME(FSTYPE
), &Volume
->vol
),
370 if (!EFI_ERROR(Status
)) {
371 // register the SimpleFileSystem protocol
372 Volume
->FileSystem
.Revision
= EFI_FILE_IO_INTERFACE_REVISION
;
373 Volume
->FileSystem
.OpenVolume
= fsw_efi_FileSystem_OpenVolume
;
374 Status
= refit_call4_wrapper(BS
->InstallMultipleProtocolInterfaces
, &ControllerHandle
,
375 &gEfiSimpleFileSystemProtocolGuid
,
378 if (EFI_ERROR(Status
)) {
379 // Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned %x\n", Status);
383 // on errors, close the opened protocols
384 if (EFI_ERROR(Status
)) {
385 if (Volume
->vol
!= NULL
)
386 fsw_unmount(Volume
->vol
);
389 refit_call4_wrapper(BS
->CloseProtocol
, ControllerHandle
,
390 &gEfiDiskIoProtocolGuid
,
391 This
->DriverBindingHandle
,
398 * Driver Binding EFI protocol, Stop function. This function is called by EFI
399 * to stop the driver on the given device. This translates to an unmount
400 * call for the FSW core.
402 * We assume that all file handles on the volume have been closed before
403 * the driver is stopped. At least with the EFI shell, that is actually the
404 * case; it closes all file handles between commands.
407 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
408 IN EFI_HANDLE ControllerHandle
,
409 IN UINTN NumberOfChildren
,
410 IN EFI_HANDLE
*ChildHandleBuffer
)
413 EFI_FILE_IO_INTERFACE
*FileSystem
;
414 FSW_VOLUME_DATA
*Volume
;
417 Print(L
"fsw_efi_DriverBinding_Stop\n");
420 // get the installed SimpleFileSystem interface
421 Status
= refit_call6_wrapper(BS
->OpenProtocol
, ControllerHandle
,
422 &gEfiSimpleFileSystemProtocolGuid
,
423 (VOID
**) &FileSystem
,
424 This
->DriverBindingHandle
,
426 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
427 if (EFI_ERROR(Status
))
428 return EFI_UNSUPPORTED
;
430 // get private data structure
431 Volume
= FSW_VOLUME_FROM_FILE_SYSTEM(FileSystem
);
433 // uninstall Simple File System protocol
434 Status
= refit_call4_wrapper(BS
->UninstallMultipleProtocolInterfaces
, ControllerHandle
,
435 &gEfiSimpleFileSystemProtocolGuid
, &Volume
->FileSystem
,
437 if (EFI_ERROR(Status
)) {
438 // Print(L"Fsw ERROR: UninstallMultipleProtocolInterfaces returned %x\n", Status);
442 Print(L
"fsw_efi_DriverBinding_Stop: protocol uninstalled successfully\n");
445 // release private data structure
446 if (Volume
->vol
!= NULL
)
447 fsw_unmount(Volume
->vol
);
450 // close the consumed protocols
451 Status
= refit_call4_wrapper(BS
->CloseProtocol
, ControllerHandle
,
452 &gEfiDiskIoProtocolGuid
,
453 This
->DriverBindingHandle
,
457 fsw_efi_clear_cache();
463 * Component Name EFI protocol, GetDriverName function. Used by the EFI
464 * environment to inquire the name of this driver. The name returned is
465 * based on the file system type actually used in compilation.
468 EFI_STATUS EFIAPI
fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
470 OUT CHAR16
**DriverName
)
472 if (Language
== NULL
|| DriverName
== NULL
)
473 return EFI_INVALID_PARAMETER
;
475 if (Language
[0] == 'e' && Language
[1] == 'n' && Language
[2] == 'g' && Language
[3] == 0) {
476 *DriverName
= FSW_EFI_DRIVER_NAME(FSTYPE
);
479 return EFI_UNSUPPORTED
;
483 * Component Name EFI protocol, GetControllerName function. Not implemented
484 * because this is not a "bus" driver in the sense of the EFI Driver Model.
487 EFI_STATUS EFIAPI
fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
488 IN EFI_HANDLE ControllerHandle
,
489 IN EFI_HANDLE ChildHandle OPTIONAL
,
491 OUT CHAR16
**ControllerName
)
493 return EFI_UNSUPPORTED
;
497 * FSW interface function for block size changes. This function is called by the FSW core
498 * when the file system driver changes the block sizes for the volume.
501 void EFIAPI
fsw_efi_change_blocksize(struct fsw_volume
*vol
,
502 fsw_u32 old_phys_blocksize
, fsw_u32 old_log_blocksize
,
503 fsw_u32 new_phys_blocksize
, fsw_u32 new_log_blocksize
)
509 * FSW interface function to read data blocks. This function is called by the FSW core
510 * to read a block of data from the device. The buffer is allocated by the core code.
511 * Two caches are maintained, so as to improve performance on some systems. (VirtualBox
512 * is particularly susceptible to performance problems with an uncached driver -- the
513 * ext2 driver can take 200 seconds to load a Linux kernel under VirtualBox, whereas
514 * the time is more like 3 seconds with a cache!) Two independent caches are maintained
515 * because the ext2fs driver tends to alternate between accessing two parts of the
519 fsw_status_t EFIAPI
fsw_efi_read_block(struct fsw_volume
*vol
, fsw_u64 phys_bno
, void *buffer
) {
520 int i
, ReadCache
= -1;
521 FSW_VOLUME_DATA
*Volume
= (FSW_VOLUME_DATA
*)vol
->host_data
;
522 EFI_STATUS Status
= EFI_SUCCESS
;
523 BOOLEAN ReadOneBlock
= FALSE
;
524 UINT64 StartRead
= (UINT64
) phys_bno
* (UINT64
) vol
->phys_blocksize
;
527 return (fsw_status_t
) EFI_BAD_BUFFER_SIZE
;
529 // Initialize static data structures, if necessary....
531 fsw_efi_clear_cache();
534 // Look for a cache hit on the current query....
537 if ((Caches
[i
].Volume
== Volume
) &&
538 (Caches
[i
].CacheValid
== TRUE
) &&
539 (StartRead
>= Caches
[i
].CacheStart
) &&
540 ((StartRead
+ vol
->phys_blocksize
) <= (Caches
[i
].CacheStart
+ CACHE_SIZE
))) {
544 } while ((i
< NUM_CACHES
) && (ReadCache
< 0));
546 // No cache hit found; load new cache and pass it on....
550 ReadCache
= 1 - LastRead
; // NOTE: If NUM_CACHES > 2, this must become more complex
551 Caches
[ReadCache
].CacheValid
= FALSE
;
552 if (Caches
[ReadCache
].Cache
== NULL
)
553 Caches
[ReadCache
].Cache
= AllocatePool(CACHE_SIZE
);
554 if (Caches
[ReadCache
].Cache
!= NULL
) {
555 // TODO: Below call hangs on my 32-bit Mac Mini when compiled with GNU-EFI.
556 // The same binary is fine under VirtualBox, and the same call is fine when
557 // compiled with Tianocore. Further clue: Omitting "Status =" avoids the
558 // hang but produces a failure to mount the filesystem, even when the same
559 // change is made to later similar call. Calling Volume->DiskIo->ReadDisk()
560 // directly (without refit_call5_wrapper()) changes nothing. Placing Print()
561 // statements at the start and end of the function, and before and after the
562 // ReadDisk() call, suggests that when it fails, the program is executing
563 // code starting mid-function, so there seems to be something messed up in
564 // the way the function is being called. FIGURE THIS OUT!
565 Status
= refit_call5_wrapper(Volume
->DiskIo
->ReadDisk
, Volume
->DiskIo
, Volume
->MediaId
,
566 StartRead
, (UINTN
) CACHE_SIZE
, (VOID
*) Caches
[ReadCache
].Cache
);
567 if (!EFI_ERROR(Status
)) {
568 Caches
[ReadCache
].CacheStart
= StartRead
;
569 Caches
[ReadCache
].CacheValid
= TRUE
;
570 Caches
[ReadCache
].Volume
= Volume
;
571 LastRead
= ReadCache
;
577 } // if cache memory allocated
578 } // if (ReadCache < 0)
580 if (Caches
[ReadCache
].Cache
!= NULL
&& Caches
[ReadCache
].CacheValid
== TRUE
&& vol
->phys_blocksize
> 0) {
581 CopyMem(buffer
, &Caches
[ReadCache
].Cache
[StartRead
- Caches
[ReadCache
].CacheStart
], vol
->phys_blocksize
);
586 if (ReadOneBlock
) { // Something's failed, so try a simple disk read of one block....
587 Status
= refit_call5_wrapper(Volume
->DiskIo
->ReadDisk
, Volume
->DiskIo
, Volume
->MediaId
,
588 phys_bno
* vol
->phys_blocksize
,
589 (UINTN
) vol
->phys_blocksize
,
592 Volume
->LastIOStatus
= Status
;
595 } // fsw_status_t *fsw_efi_read_block()
598 * Map FSW status codes to EFI status codes. The FSW_IO_ERROR code is only produced
599 * by fsw_efi_read_block, so we map it back to the EFI status code remembered from
600 * the last I/O operation.
603 EFI_STATUS
fsw_efi_map_status(fsw_status_t fsw_status
, FSW_VOLUME_DATA
*Volume
)
605 switch (fsw_status
) {
608 case FSW_OUT_OF_MEMORY
:
609 return EFI_VOLUME_CORRUPTED
;
611 return Volume
->LastIOStatus
;
612 case FSW_UNSUPPORTED
:
613 return EFI_UNSUPPORTED
;
615 return EFI_NOT_FOUND
;
616 case FSW_VOLUME_CORRUPTED
:
617 return EFI_VOLUME_CORRUPTED
;
619 return EFI_DEVICE_ERROR
;
624 * File System EFI protocol, OpenVolume function. Creates a file handle for
625 * the root directory and returns it. Note that this function may be called
626 * multiple times and returns a new file handle each time. Each returned
627 * handle is closed by the client using it.
630 EFI_STATUS EFIAPI
fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE
*This
,
634 FSW_VOLUME_DATA
*Volume
= FSW_VOLUME_FROM_FILE_SYSTEM(This
);
637 Print(L
"fsw_efi_FileSystem_OpenVolume\n");
640 fsw_efi_clear_cache();
641 Status
= fsw_efi_dnode_to_FileHandle(Volume
->vol
->root
, Root
);
647 * File Handle EFI protocol, Open function. Dispatches the call
648 * based on the kind of file handle.
651 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Open(IN EFI_FILE
*This
,
652 OUT EFI_FILE
**NewHandle
,
655 IN UINT64 Attributes
)
657 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
659 if (File
->Type
== FSW_EFI_FILE_TYPE_DIR
)
660 return fsw_efi_dir_open(File
, NewHandle
, FileName
, OpenMode
, Attributes
);
661 // not supported for regular files
662 return EFI_UNSUPPORTED
;
666 * File Handle EFI protocol, Close function. Closes the FSW shandle
667 * and frees the memory used for the structure.
670 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Close(IN EFI_FILE
*This
)
672 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
675 Print(L
"fsw_efi_FileHandle_Close\n");
678 fsw_shandle_close(&File
->shand
);
685 * File Handle EFI protocol, Delete function. Calls through to Close
686 * and returns a warning because this driver is read-only.
689 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Delete(IN EFI_FILE
*This
)
693 Status
= refit_call1_wrapper(This
->Close
, This
);
694 if (Status
== EFI_SUCCESS
) {
695 // this driver is read-only
696 Status
= EFI_WARN_DELETE_FAILURE
;
703 * File Handle EFI protocol, Read function. Dispatches the call
704 * based on the kind of file handle.
707 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Read(IN EFI_FILE
*This
,
708 IN OUT UINTN
*BufferSize
,
711 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
713 if (File
->Type
== FSW_EFI_FILE_TYPE_FILE
)
714 return fsw_efi_file_read(File
, BufferSize
, Buffer
);
715 else if (File
->Type
== FSW_EFI_FILE_TYPE_DIR
)
716 return fsw_efi_dir_read(File
, BufferSize
, Buffer
);
717 return EFI_UNSUPPORTED
;
721 * File Handle EFI protocol, Write function. Returns unsupported status
722 * because this driver is read-only.
725 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Write(IN EFI_FILE
*This
,
726 IN OUT UINTN
*BufferSize
,
729 // this driver is read-only
730 return EFI_WRITE_PROTECTED
;
734 * File Handle EFI protocol, GetPosition function. Dispatches the call
735 * based on the kind of file handle.
738 EFI_STATUS EFIAPI
fsw_efi_FileHandle_GetPosition(IN EFI_FILE
*This
,
739 OUT UINT64
*Position
)
741 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
743 if (File
->Type
== FSW_EFI_FILE_TYPE_FILE
)
744 return fsw_efi_file_getpos(File
, Position
);
745 // not defined for directories
746 return EFI_UNSUPPORTED
;
750 * File Handle EFI protocol, SetPosition function. Dispatches the call
751 * based on the kind of file handle.
754 EFI_STATUS EFIAPI
fsw_efi_FileHandle_SetPosition(IN EFI_FILE
*This
,
757 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
759 if (File
->Type
== FSW_EFI_FILE_TYPE_FILE
)
760 return fsw_efi_file_setpos(File
, Position
);
761 else if (File
->Type
== FSW_EFI_FILE_TYPE_DIR
)
762 return fsw_efi_dir_setpos(File
, Position
);
763 return EFI_UNSUPPORTED
;
767 * File Handle EFI protocol, GetInfo function. Dispatches to the common
768 * function implementing this.
771 EFI_STATUS EFIAPI
fsw_efi_FileHandle_GetInfo(IN EFI_FILE
*This
,
772 IN EFI_GUID
*InformationType
,
773 IN OUT UINTN
*BufferSize
,
776 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
778 return fsw_efi_dnode_getinfo(File
, InformationType
, BufferSize
, Buffer
);
782 * File Handle EFI protocol, SetInfo function. Returns unsupported status
783 * because this driver is read-only.
786 EFI_STATUS EFIAPI
fsw_efi_FileHandle_SetInfo(IN EFI_FILE
*This
,
787 IN EFI_GUID
*InformationType
,
791 // this driver is read-only
792 return EFI_WRITE_PROTECTED
;
796 * File Handle EFI protocol, Flush function. Returns unsupported status
797 * because this driver is read-only.
800 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Flush(IN EFI_FILE
*This
)
802 // this driver is read-only
803 return EFI_WRITE_PROTECTED
;
807 * Set up a file handle for a dnode. This function allocates a data structure
808 * for a file handle, opens a FSW shandle and populates the EFI_FILE structure
809 * with the interface functions.
812 EFI_STATUS
fsw_efi_dnode_to_FileHandle(IN
struct fsw_dnode
*dno
,
813 OUT EFI_FILE
**NewFileHandle
)
818 // make sure the dnode has complete info
819 Status
= fsw_efi_map_status(fsw_dnode_fill(dno
), (FSW_VOLUME_DATA
*)dno
->vol
->host_data
);
820 if (EFI_ERROR(Status
))
824 if (dno
->type
!= FSW_DNODE_TYPE_FILE
&& dno
->type
!= FSW_DNODE_TYPE_DIR
)
825 return EFI_UNSUPPORTED
;
827 // allocate file structure
828 File
= AllocateZeroPool(sizeof(FSW_FILE_DATA
));
829 File
->Signature
= FSW_FILE_DATA_SIGNATURE
;
830 if (dno
->type
== FSW_DNODE_TYPE_FILE
)
831 File
->Type
= FSW_EFI_FILE_TYPE_FILE
;
832 else if (dno
->type
== FSW_DNODE_TYPE_DIR
)
833 File
->Type
= FSW_EFI_FILE_TYPE_DIR
;
836 Status
= fsw_efi_map_status(fsw_shandle_open(dno
, &File
->shand
),
837 (FSW_VOLUME_DATA
*)dno
->vol
->host_data
);
838 if (EFI_ERROR(Status
)) {
843 // populate the file handle
844 File
->FileHandle
.Revision
= EFI_FILE_HANDLE_REVISION
;
845 File
->FileHandle
.Open
= fsw_efi_FileHandle_Open
;
846 File
->FileHandle
.Close
= fsw_efi_FileHandle_Close
;
847 File
->FileHandle
.Delete
= fsw_efi_FileHandle_Delete
;
848 File
->FileHandle
.Read
= fsw_efi_FileHandle_Read
;
849 File
->FileHandle
.Write
= fsw_efi_FileHandle_Write
;
850 File
->FileHandle
.GetPosition
= fsw_efi_FileHandle_GetPosition
;
851 File
->FileHandle
.SetPosition
= fsw_efi_FileHandle_SetPosition
;
852 File
->FileHandle
.GetInfo
= fsw_efi_FileHandle_GetInfo
;
853 File
->FileHandle
.SetInfo
= fsw_efi_FileHandle_SetInfo
;
854 File
->FileHandle
.Flush
= fsw_efi_FileHandle_Flush
;
856 *NewFileHandle
= &File
->FileHandle
;
861 * Data read function for regular files. Calls through to fsw_shandle_read.
864 EFI_STATUS
fsw_efi_file_read(IN FSW_FILE_DATA
*File
,
865 IN OUT UINTN
*BufferSize
,
872 Print(L
"fsw_efi_file_read %d bytes\n", *BufferSize
);
875 buffer_size
= (fsw_u32
)*BufferSize
;
876 Status
= fsw_efi_map_status(fsw_shandle_read(&File
->shand
, &buffer_size
, Buffer
),
877 (FSW_VOLUME_DATA
*)File
->shand
.dnode
->vol
->host_data
);
878 *BufferSize
= buffer_size
;
884 * Get file position for regular files.
887 EFI_STATUS
fsw_efi_file_getpos(IN FSW_FILE_DATA
*File
,
888 OUT UINT64
*Position
)
890 *Position
= File
->shand
.pos
;
895 * Set file position for regular files. EFI specifies the all-ones value
896 * to be a special value for the end of the file.
899 EFI_STATUS
fsw_efi_file_setpos(IN FSW_FILE_DATA
*File
, IN UINT64 Position
)
901 if (Position
== 0xFFFFFFFFFFFFFFFFULL
)
902 File
->shand
.pos
= File
->shand
.dnode
->size
;
904 File
->shand
.pos
= Position
;
909 * Open function used to open new file handles relative to a directory.
910 * In EFI, the "open file" function is implemented by directory file handles
911 * and is passed a relative or volume-absolute path to the file or directory
912 * to open. We use fsw_dnode_lookup_path to find the node plus an additional
913 * call to fsw_dnode_resolve because EFI has no concept of symbolic links.
916 EFI_STATUS
fsw_efi_dir_open(IN FSW_FILE_DATA
*File
,
917 OUT EFI_FILE
**NewHandle
,
920 IN UINT64 Attributes
)
923 FSW_VOLUME_DATA
*Volume
= (FSW_VOLUME_DATA
*)File
->shand
.dnode
->vol
->host_data
;
924 struct fsw_dnode
*dno
;
925 struct fsw_dnode
*target_dno
;
926 struct fsw_string lookup_path
;
929 Print(L
"fsw_efi_dir_open: '%s'\n", FileName
);
932 if (OpenMode
!= EFI_FILE_MODE_READ
)
933 return EFI_WRITE_PROTECTED
;
935 lookup_path
.type
= FSW_STRING_TYPE_UTF16
;
936 lookup_path
.len
= (int)StrLen(FileName
);
937 lookup_path
.size
= lookup_path
.len
* sizeof(fsw_u16
);
938 lookup_path
.data
= FileName
;
940 // resolve the path (symlinks along the way are automatically resolved)
941 Status
= fsw_efi_map_status(fsw_dnode_lookup_path(File
->shand
.dnode
, &lookup_path
, '\\', &dno
), Volume
);
942 if (EFI_ERROR(Status
))
945 // if the final node is a symlink, also resolve it
946 Status
= fsw_efi_map_status(fsw_dnode_resolve(dno
, &target_dno
), Volume
);
947 fsw_dnode_release(dno
);
948 if (EFI_ERROR(Status
))
952 // make a new EFI handle for the target dnode
953 Status
= fsw_efi_dnode_to_FileHandle(dno
, NewHandle
);
954 fsw_dnode_release(dno
);
959 * Read function for directories. A file handle read on a directory retrieves
960 * the next directory entry.
963 EFI_STATUS
fsw_efi_dir_read(IN FSW_FILE_DATA
*File
,
964 IN OUT UINTN
*BufferSize
,
968 FSW_VOLUME_DATA
*Volume
= (FSW_VOLUME_DATA
*)File
->shand
.dnode
->vol
->host_data
;
969 struct fsw_dnode
*dno
;
972 Print(L
"fsw_efi_dir_read...\n");
975 // read the next entry
976 Status
= fsw_efi_map_status(fsw_dnode_dir_read(&File
->shand
, &dno
), Volume
);
977 if (Status
== EFI_NOT_FOUND
) {
981 Print(L
"...no more entries\n");
985 if (EFI_ERROR(Status
))
988 // get info into buffer
989 Status
= fsw_efi_dnode_fill_FileInfo(Volume
, dno
, BufferSize
, Buffer
);
990 fsw_dnode_release(dno
);
995 * Set file position for directories. The only allowed set position operation
996 * for directories is to rewind the directory completely by setting the
1000 EFI_STATUS
fsw_efi_dir_setpos(IN FSW_FILE_DATA
*File
, IN UINT64 Position
)
1002 if (Position
== 0) {
1003 File
->shand
.pos
= 0;
1006 // directories can only rewind to the start
1007 return EFI_UNSUPPORTED
;
1012 * Get file or volume information. This function implements the GetInfo call
1013 * for all file handles. Control is dispatched according to the type of information
1014 * requested by the caller.
1017 EFI_STATUS
fsw_efi_dnode_getinfo(IN FSW_FILE_DATA
*File
,
1018 IN EFI_GUID
*InformationType
,
1019 IN OUT UINTN
*BufferSize
,
1023 FSW_VOLUME_DATA
*Volume
= (FSW_VOLUME_DATA
*)File
->shand
.dnode
->vol
->host_data
;
1024 EFI_FILE_SYSTEM_INFO
*FSInfo
;
1026 struct fsw_volume_stat vsb
;
1029 if (CompareGuid(InformationType
, &gEfiFileInfoGuid
)) {
1031 Print(L
"fsw_efi_dnode_getinfo: FILE_INFO\n");
1034 Status
= fsw_efi_dnode_fill_FileInfo(Volume
, File
->shand
.dnode
, BufferSize
, Buffer
);
1036 } else if (CompareGuid(InformationType
, &gEfiFileSystemInfoGuid
)) {
1038 Print(L
"fsw_efi_dnode_getinfo: FILE_SYSTEM_INFO\n");
1041 // check buffer size
1042 RequiredSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ fsw_efi_strsize(&Volume
->vol
->label
);
1043 if (*BufferSize
< RequiredSize
) {
1044 *BufferSize
= RequiredSize
;
1045 return EFI_BUFFER_TOO_SMALL
;
1049 FSInfo
= (EFI_FILE_SYSTEM_INFO
*)Buffer
;
1050 FSInfo
->Size
= RequiredSize
;
1051 FSInfo
->ReadOnly
= TRUE
;
1052 FSInfo
->BlockSize
= Volume
->vol
->log_blocksize
;
1053 fsw_efi_strcpy(FSInfo
->VolumeLabel
, &Volume
->vol
->label
);
1055 // get the missing info from the fs driver
1056 ZeroMem(&vsb
, sizeof(struct fsw_volume_stat
));
1057 Status
= fsw_efi_map_status(fsw_volume_stat(Volume
->vol
, &vsb
), Volume
);
1058 if (EFI_ERROR(Status
))
1060 FSInfo
->VolumeSize
= vsb
.total_bytes
;
1061 FSInfo
->FreeSpace
= vsb
.free_bytes
;
1063 // prepare for return
1064 *BufferSize
= RequiredSize
;
1065 Status
= EFI_SUCCESS
;
1067 } else if (CompareGuid(InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1069 Print(L
"fsw_efi_dnode_getinfo: FILE_SYSTEM_VOLUME_LABEL\n");
1072 // check buffer size
1073 RequiredSize
= SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO
+ fsw_efi_strsize(&Volume
->vol
->label
);
1074 if (*BufferSize
< RequiredSize
) {
1075 *BufferSize
= RequiredSize
;
1076 return EFI_BUFFER_TOO_SMALL
;
1079 // copy volume label
1080 fsw_efi_strcpy(((EFI_FILE_SYSTEM_VOLUME_LABEL_INFO
*)Buffer
)->VolumeLabel
, &Volume
->vol
->label
);
1082 // prepare for return
1083 *BufferSize
= RequiredSize
;
1084 Status
= EFI_SUCCESS
;
1087 Status
= EFI_UNSUPPORTED
;
1094 * Time mapping callback for the fsw_dnode_stat call. This function converts
1095 * a Posix style timestamp into an EFI_TIME structure and writes it to the
1096 * appropriate member of the EFI_FILE_INFO structure that we're filling.
1099 void fsw_store_time_posix(struct fsw_dnode_stat
*sb
, int which
, fsw_u32 posix_time
)
1101 EFI_FILE_INFO
*FileInfo
= (EFI_FILE_INFO
*)sb
->host_data
;
1103 if (which
== FSW_DNODE_STAT_CTIME
)
1104 fsw_efi_decode_time(&FileInfo
->CreateTime
, posix_time
);
1105 else if (which
== FSW_DNODE_STAT_MTIME
)
1106 fsw_efi_decode_time(&FileInfo
->ModificationTime
, posix_time
);
1107 else if (which
== FSW_DNODE_STAT_ATIME
)
1108 fsw_efi_decode_time(&FileInfo
->LastAccessTime
, posix_time
);
1112 * Mode mapping callback for the fsw_dnode_stat call. This function looks at
1113 * the Posix mode passed by the file system driver and makes appropriate
1114 * adjustments to the EFI_FILE_INFO structure that we're filling.
1117 void fsw_store_attr_posix(struct fsw_dnode_stat
*sb
, fsw_u16 posix_mode
)
1119 EFI_FILE_INFO
*FileInfo
= (EFI_FILE_INFO
*)sb
->host_data
;
1121 if ((posix_mode
& S_IWUSR
) == 0)
1122 FileInfo
->Attribute
|= EFI_FILE_READ_ONLY
;
1125 void fsw_store_attr_efi(struct fsw_dnode_stat
*sb
, fsw_u16 attr
)
1127 EFI_FILE_INFO
*FileInfo
= (EFI_FILE_INFO
*)sb
->host_data
;
1129 FileInfo
->Attribute
|= attr
;
1133 * Common function to fill an EFI_FILE_INFO with information about a dnode.
1136 EFI_STATUS
fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA
*Volume
,
1137 IN
struct fsw_dnode
*dno
,
1138 IN OUT UINTN
*BufferSize
,
1142 EFI_FILE_INFO
*FileInfo
;
1144 struct fsw_dnode_stat sb
;
1146 // make sure the dnode has complete info
1147 Status
= fsw_efi_map_status(fsw_dnode_fill(dno
), Volume
);
1148 if (EFI_ERROR(Status
))
1151 // TODO: check/assert that the dno's name is in UTF16
1153 // check buffer size
1154 RequiredSize
= SIZE_OF_EFI_FILE_INFO
+ fsw_efi_strsize(&dno
->name
);
1155 if (*BufferSize
< RequiredSize
) {
1156 // TODO: wind back the directory in this case
1159 Print(L
"...BUFFER TOO SMALL\n");
1161 *BufferSize
= RequiredSize
;
1162 return EFI_BUFFER_TOO_SMALL
;
1166 ZeroMem(Buffer
, RequiredSize
);
1167 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
1168 FileInfo
->Size
= RequiredSize
;
1169 FileInfo
->FileSize
= dno
->size
;
1170 FileInfo
->Attribute
= 0;
1171 if (dno
->type
== FSW_DNODE_TYPE_DIR
)
1172 FileInfo
->Attribute
|= EFI_FILE_DIRECTORY
;
1173 fsw_efi_strcpy(FileInfo
->FileName
, &dno
->name
);
1175 // get the missing info from the fs driver
1176 ZeroMem(&sb
, sizeof(struct fsw_dnode_stat
));
1177 sb
.host_data
= FileInfo
;
1178 Status
= fsw_efi_map_status(fsw_dnode_stat(dno
, &sb
), Volume
);
1179 if (EFI_ERROR(Status
))
1181 FileInfo
->PhysicalSize
= sb
.used_bytes
;
1183 // prepare for return
1184 *BufferSize
= RequiredSize
;
1186 Print(L
"...returning '%s'\n", FileInfo
->FileName
);