1 /* $Id: fsw_efi.c 29125 2010-05-06 09:43:05Z vboxsync $ */
3 * fsw_efi.c - EFI host environment code.
7 * Copyright (C) 2010 Oracle Corporation
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 * This code is based on:
21 * Copyright (c) 2006 Christoph Pfisterer
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions are
27 * * Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
30 * * Redistributions in binary form must reproduce the above copyright
31 * notice, this list of conditions and the following disclaimer in the
32 * documentation and/or other materials provided with the
35 * * Neither the name of Christoph Pfisterer nor the names of the
36 * contributors may be used to endorse or promote products derived
37 * from this software without specific prior written permission.
39 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
40 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
41 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
42 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
43 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
45 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
46 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
47 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
48 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
49 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 #ifdef __MAKEWITH_GNUEFI
55 #include "edk2/DriverBinding.h"
56 #include "edk2/ComponentName.h"
58 #include "../include/refit_call_wrapper.h"
63 #error FSTYPE must be defined!
69 #define DBG(x...) AsciiPrint(x)
71 #define DBG(x...) BootLog(x)
76 #ifdef __MAKEWITH_GNUEFI
78 #define EFI_DISK_IO_PROTOCOL_GUID \
80 0xce345171, 0xba0b, 0x11d2, {0x8e, 0x4f, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
83 #define EFI_BLOCK_IO_PROTOCOL_GUID \
85 0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
88 EFI_GUID gEfiDriverBindingProtocolGuid
= EFI_DRIVER_BINDING_PROTOCOL_GUID
;
89 EFI_GUID gEfiComponentNameProtocolGuid
= EFI_COMPONENT_NAME_PROTOCOL_GUID
;
90 EFI_GUID gEfiDiskIoProtocolGuid
= EFI_DISK_IO_PROTOCOL_GUID
;
91 EFI_GUID gEfiBlockIoProtocolGuid
= EFI_BLOCK_IO_PROTOCOL_GUID
;
92 EFI_GUID gEfiFileInfoGuid
= EFI_FILE_INFO_ID
;
93 EFI_GUID gEfiFileSystemInfoGuid
= EFI_FILE_SYSTEM_INFO_ID
;
94 EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid
= EFI_FILE_SYSTEM_VOLUME_LABEL_INFO_ID
;
95 #define SimpleFileSystemProtocol FileSystemProtocol
98 /** Helper macro for stringification. */
99 #define FSW_EFI_STRINGIFY(x) #x
100 /** Expands to the EFI driver name given the file system type name. */
101 #define FSW_EFI_DRIVER_NAME(t) L"rEFInd 0.7.0.3 " FSW_EFI_STRINGIFY(t) L" File System Driver"
103 // function prototypes
105 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
106 IN EFI_HANDLE ControllerHandle
,
107 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
);
108 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
109 IN EFI_HANDLE ControllerHandle
,
110 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
);
111 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
112 IN EFI_HANDLE ControllerHandle
,
113 IN UINTN NumberOfChildren
,
114 IN EFI_HANDLE
*ChildHandleBuffer
);
116 EFI_STATUS EFIAPI
fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
118 OUT CHAR16
**DriverName
);
119 EFI_STATUS EFIAPI
fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
120 IN EFI_HANDLE ControllerHandle
,
121 IN EFI_HANDLE ChildHandle OPTIONAL
,
123 OUT CHAR16
**ControllerName
);
125 void fsw_efi_change_blocksize(struct fsw_volume
*vol
,
126 fsw_u32 old_phys_blocksize
, fsw_u32 old_log_blocksize
,
127 fsw_u32 new_phys_blocksize
, fsw_u32 new_log_blocksize
);
128 fsw_status_t
fsw_efi_read_block(struct fsw_volume
*vol
, fsw_u64 phys_bno
, void *buffer
);
130 EFI_STATUS
fsw_efi_map_status(fsw_status_t fsw_status
, FSW_VOLUME_DATA
*Volume
);
132 EFI_STATUS EFIAPI
fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE
*This
,
133 OUT EFI_FILE
**Root
);
134 EFI_STATUS
fsw_efi_dnode_to_FileHandle(IN
struct fsw_dnode
*dno
,
135 OUT EFI_FILE
**NewFileHandle
);
137 EFI_STATUS
fsw_efi_file_read(IN FSW_FILE_DATA
*File
,
138 IN OUT UINTN
*BufferSize
,
140 EFI_STATUS
fsw_efi_file_getpos(IN FSW_FILE_DATA
*File
,
141 OUT UINT64
*Position
);
142 EFI_STATUS
fsw_efi_file_setpos(IN FSW_FILE_DATA
*File
,
145 EFI_STATUS
fsw_efi_dir_open(IN FSW_FILE_DATA
*File
,
146 OUT EFI_FILE
**NewHandle
,
149 IN UINT64 Attributes
);
150 EFI_STATUS
fsw_efi_dir_read(IN FSW_FILE_DATA
*File
,
151 IN OUT UINTN
*BufferSize
,
153 EFI_STATUS
fsw_efi_dir_setpos(IN FSW_FILE_DATA
*File
,
156 EFI_STATUS
fsw_efi_dnode_getinfo(IN FSW_FILE_DATA
*File
,
157 IN EFI_GUID
*InformationType
,
158 IN OUT UINTN
*BufferSize
,
160 EFI_STATUS
fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA
*Volume
,
161 IN
struct fsw_dnode
*dno
,
162 IN OUT UINTN
*BufferSize
,
166 * Structure for holding disk cache data.
169 #define CACHE_SIZE 131072 /* 128KiB */
174 FSW_VOLUME_DATA
*Volume
; // NOTE: Do not deallocate; copied here to ID volume
177 #define NUM_CACHES 2 /* Don't increase without modifying fsw_efi_read_block() */
178 static struct cache_data Caches
[NUM_CACHES
];
179 static int LastRead
= -1;
182 * Interface structure for the EFI Driver Binding protocol.
185 EFI_DRIVER_BINDING_PROTOCOL fsw_efi_DriverBinding_table
= {
186 fsw_efi_DriverBinding_Supported
,
187 fsw_efi_DriverBinding_Start
,
188 fsw_efi_DriverBinding_Stop
,
195 * Interface structure for the EFI Component Name protocol.
198 EFI_COMPONENT_NAME_PROTOCOL fsw_efi_ComponentName_table
= {
199 fsw_efi_ComponentName_GetDriverName
,
200 fsw_efi_ComponentName_GetControllerName
,
205 * Dispatch table for our FSW host driver.
208 struct fsw_host_table fsw_efi_host_table
= {
209 FSW_STRING_TYPE_UTF16
,
211 fsw_efi_change_blocksize
,
215 extern struct fsw_fstype_table
FSW_FSTYPE_TABLE_NAME(FSTYPE
);
217 //#include "OverrideFunctions-kabyl.edk2.c.include"
219 static VOID EFIAPI
fsw_efi_clear_cache(VOID
) {
223 for (i
= 0; i
< NUM_CACHES
; i
++) {
224 if (Caches
[i
].Cache
!= NULL
) {
225 FreePool(Caches
[i
].Cache
);
226 Caches
[i
].Cache
= NULL
;
228 Caches
[i
].CacheStart
= 0;
229 Caches
[i
].CacheValid
= FALSE
;
230 Caches
[i
].Volume
= NULL
;
233 } // VOID EFIAPI fsw_efi_clear_cache();
236 * Image entry point. Installs the Driver Binding and Component Name protocols
237 * on the image's handle. Actually mounting a file system is initiated through
238 * the Driver Binding protocol at the firmware's request.
240 EFI_STATUS EFIAPI
fsw_efi_main(IN EFI_HANDLE ImageHandle
,
241 IN EFI_SYSTEM_TABLE
*SystemTable
)
245 #ifndef HOST_EFI_EDK2
246 // Not available in EDK2 toolkit
247 InitializeLib(ImageHandle
, SystemTable
);
250 // complete Driver Binding protocol instance
251 fsw_efi_DriverBinding_table
.ImageHandle
= ImageHandle
;
252 fsw_efi_DriverBinding_table
.DriverBindingHandle
= ImageHandle
;
253 // install Driver Binding protocol
254 Status
= refit_call4_wrapper(BS
->InstallProtocolInterface
, &fsw_efi_DriverBinding_table
.DriverBindingHandle
,
255 &gEfiDriverBindingProtocolGuid
,
256 EFI_NATIVE_INTERFACE
,
257 &fsw_efi_DriverBinding_table
);
258 if (EFI_ERROR (Status
)) {
262 // install Component Name protocol
263 Status
= refit_call4_wrapper(BS
->InstallProtocolInterface
, &fsw_efi_DriverBinding_table
.DriverBindingHandle
,
264 &gEfiComponentNameProtocolGuid
,
265 EFI_NATIVE_INTERFACE
,
266 &fsw_efi_ComponentName_table
);
267 if (EFI_ERROR (Status
)) {
271 // OverrideFunctions();
274 // Status = BS->LocateProtocol(&gMsgLogProtocolGuid, NULL, (VOID **) &Msg);
275 // if (!EFI_ERROR(Status) && (Msg != NULL)) {
276 // msgCursor = Msg->Cursor;
277 // BootLog("MsgLog installed into VBoxFs\n");
283 #ifdef __MAKEWITH_GNUEFI
284 EFI_DRIVER_ENTRY_POINT(fsw_efi_main
)
288 * Driver Binding EFI protocol, Supported function. This function is called by EFI
289 * to test if this driver can handle a certain device. Our implementation only checks
290 * if the device is a disk (i.e. that it supports the Block I/O and Disk I/O protocols)
291 * and implicitly checks if the disk is already in use by another driver.
294 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
295 IN EFI_HANDLE ControllerHandle
,
296 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
)
301 // we check for both DiskIO and BlockIO protocols
303 // first, open DiskIO
304 Status
= refit_call6_wrapper(BS
->OpenProtocol
, ControllerHandle
,
305 &PROTO_NAME(DiskIoProtocol
),
307 This
->DriverBindingHandle
,
309 EFI_OPEN_PROTOCOL_BY_DRIVER
);
310 if (EFI_ERROR(Status
))
313 // we were just checking, close it again
314 refit_call4_wrapper(BS
->CloseProtocol
, ControllerHandle
,
315 &PROTO_NAME(DiskIoProtocol
),
316 This
->DriverBindingHandle
,
319 // next, check BlockIO without actually opening it
320 Status
= refit_call6_wrapper(BS
->OpenProtocol
, ControllerHandle
,
321 &PROTO_NAME(BlockIoProtocol
),
323 This
->DriverBindingHandle
,
325 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
330 * Driver Binding EFI protocol, Start function. This function is called by EFI
331 * to start driving the given device. It is still possible at this point to
332 * return EFI_UNSUPPORTED, and in fact we will do so if the file system driver
333 * cannot find the superblock signature (or equivalent) that it expects.
335 * This function allocates memory for a per-volume structure, opens the
336 * required protocols (just Disk I/O in our case, Block I/O is only looked
337 * at to get the MediaId field), and lets the FSW core mount the file system.
338 * If successful, an EFI Simple File System protocol is exported on the
342 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
343 IN EFI_HANDLE ControllerHandle
,
344 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
)
347 EFI_BLOCK_IO
*BlockIo
;
349 FSW_VOLUME_DATA
*Volume
;
352 Print(L
"fsw_efi_DriverBinding_Start\n");
355 // open consumed protocols
356 Status
= refit_call6_wrapper(BS
->OpenProtocol
, ControllerHandle
,
357 &PROTO_NAME(BlockIoProtocol
),
359 This
->DriverBindingHandle
,
361 EFI_OPEN_PROTOCOL_GET_PROTOCOL
); // NOTE: we only want to look at the MediaId
362 if (EFI_ERROR(Status
)) {
363 // Print(L"Fsw ERROR: OpenProtocol(BlockIo) returned %x\n", Status);
367 Status
= refit_call6_wrapper(BS
->OpenProtocol
, ControllerHandle
,
368 &PROTO_NAME(DiskIoProtocol
),
370 This
->DriverBindingHandle
,
372 EFI_OPEN_PROTOCOL_BY_DRIVER
);
373 if (EFI_ERROR(Status
)) {
377 // allocate volume structure
378 Volume
= AllocateZeroPool(sizeof(FSW_VOLUME_DATA
));
379 Volume
->Signature
= FSW_VOLUME_DATA_SIGNATURE
;
380 Volume
->Handle
= ControllerHandle
;
381 Volume
->DiskIo
= DiskIo
;
382 Volume
->MediaId
= BlockIo
->Media
->MediaId
;
383 Volume
->LastIOStatus
= EFI_SUCCESS
;
385 // mount the filesystem
386 Status
= fsw_efi_map_status(fsw_mount(Volume
, &fsw_efi_host_table
,
387 &FSW_FSTYPE_TABLE_NAME(FSTYPE
), &Volume
->vol
),
390 if (!EFI_ERROR(Status
)) {
391 // register the SimpleFileSystem protocol
392 Volume
->FileSystem
.Revision
= EFI_FILE_IO_INTERFACE_REVISION
;
393 Volume
->FileSystem
.OpenVolume
= fsw_efi_FileSystem_OpenVolume
;
394 Status
= refit_call4_wrapper(BS
->InstallMultipleProtocolInterfaces
, &ControllerHandle
,
395 &PROTO_NAME(SimpleFileSystemProtocol
),
398 if (EFI_ERROR(Status
)) {
399 // Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned %x\n", Status);
403 // on errors, close the opened protocols
404 if (EFI_ERROR(Status
)) {
405 if (Volume
->vol
!= NULL
)
406 fsw_unmount(Volume
->vol
);
409 refit_call4_wrapper(BS
->CloseProtocol
, ControllerHandle
,
410 &PROTO_NAME(DiskIoProtocol
),
411 This
->DriverBindingHandle
,
419 * Driver Binding EFI protocol, Stop function. This function is called by EFI
420 * to stop the driver on the given device. This translates to an unmount
421 * call for the FSW core.
423 * We assume that all file handles on the volume have been closed before
424 * the driver is stopped. At least with the EFI shell, that is actually the
425 * case; it closes all file handles between commands.
428 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
429 IN EFI_HANDLE ControllerHandle
,
430 IN UINTN NumberOfChildren
,
431 IN EFI_HANDLE
*ChildHandleBuffer
)
434 EFI_FILE_IO_INTERFACE
*FileSystem
;
435 FSW_VOLUME_DATA
*Volume
;
439 Print(L
"fsw_efi_DriverBinding_Stop\n");
442 // get the installed SimpleFileSystem interface
443 Status
= refit_call6_wrapper(BS
->OpenProtocol
, ControllerHandle
,
444 &PROTO_NAME(SimpleFileSystemProtocol
),
445 (VOID
**) &FileSystem
,
446 This
->DriverBindingHandle
,
448 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
449 if (EFI_ERROR(Status
))
450 return EFI_UNSUPPORTED
;
452 // get private data structure
453 Volume
= FSW_VOLUME_FROM_FILE_SYSTEM(FileSystem
);
455 // uninstall Simple File System protocol
456 Status
= refit_call4_wrapper(BS
->UninstallMultipleProtocolInterfaces
, ControllerHandle
,
457 &PROTO_NAME(SimpleFileSystemProtocol
), &Volume
->FileSystem
,
459 if (EFI_ERROR(Status
)) {
460 // Print(L"Fsw ERROR: UninstallMultipleProtocolInterfaces returned %x\n", Status);
464 Print(L
"fsw_efi_DriverBinding_Stop: protocol uninstalled successfully\n");
467 // release private data structure
468 if (Volume
->vol
!= NULL
)
469 fsw_unmount(Volume
->vol
);
472 // close the consumed protocols
473 Status
= refit_call4_wrapper(BS
->CloseProtocol
, ControllerHandle
,
474 &PROTO_NAME(DiskIoProtocol
),
475 This
->DriverBindingHandle
,
479 fsw_efi_clear_cache();
485 * Component Name EFI protocol, GetDriverName function. Used by the EFI
486 * environment to inquire the name of this driver. The name returned is
487 * based on the file system type actually used in compilation.
490 EFI_STATUS EFIAPI
fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
492 OUT CHAR16
**DriverName
)
494 if (Language
== NULL
|| DriverName
== NULL
)
495 return EFI_INVALID_PARAMETER
;
497 if (Language
[0] == 'e' && Language
[1] == 'n' && Language
[2] == 'g' && Language
[3] == 0) {
498 *DriverName
= FSW_EFI_DRIVER_NAME(FSTYPE
);
501 return EFI_UNSUPPORTED
;
505 * Component Name EFI protocol, GetControllerName function. Not implemented
506 * because this is not a "bus" driver in the sense of the EFI Driver Model.
509 EFI_STATUS EFIAPI
fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
510 IN EFI_HANDLE ControllerHandle
,
511 IN EFI_HANDLE ChildHandle OPTIONAL
,
513 OUT CHAR16
**ControllerName
)
515 return EFI_UNSUPPORTED
;
519 * FSW interface function for block size changes. This function is called by the FSW core
520 * when the file system driver changes the block sizes for the volume.
523 void fsw_efi_change_blocksize(struct fsw_volume
*vol
,
524 fsw_u32 old_phys_blocksize
, fsw_u32 old_log_blocksize
,
525 fsw_u32 new_phys_blocksize
, fsw_u32 new_log_blocksize
)
531 * FSW interface function to read data blocks. This function is called by the FSW core
532 * to read a block of data from the device. The buffer is allocated by the core code.
533 * Two caches are maintained, so as to improve performance on some systems. (VirtualBox
534 * is particularly susceptible to performance problems with an uncached driver -- the
535 * ext2 driver can take 200 seconds to load a Linux kernel under VirtualBox, whereas
536 * the time is more like 3 seconds with a cache!) Two independent caches are maintained
537 * because the ext2fs driver tends to alternate between accessing two parts of the
541 fsw_status_t
fsw_efi_read_block(struct fsw_volume
*vol
, fsw_u64 phys_bno
, void *buffer
) {
542 int i
, ReadCache
= -1;
543 FSW_VOLUME_DATA
*Volume
= (FSW_VOLUME_DATA
*)vol
->host_data
;
544 EFI_STATUS Status
= EFI_SUCCESS
;
545 BOOLEAN ReadOneBlock
= FALSE
;
546 fsw_u64 StartRead
= phys_bno
* vol
->phys_blocksize
;
549 return (fsw_status_t
) EFI_BAD_BUFFER_SIZE
;
551 // Initialize static data structures, if necessary....
553 fsw_efi_clear_cache();
556 // Look for a cache hit on the current query....
559 if ((Caches
[i
].Volume
== Volume
) &&
560 (StartRead
>= Caches
[i
].CacheStart
) &&
561 ((StartRead
+ vol
->phys_blocksize
) <= (Caches
[i
].CacheStart
+ CACHE_SIZE
))) {
565 } while ((i
< NUM_CACHES
) && (ReadCache
< 0));
567 // No cache hit found; load new cache and pass it on....
571 ReadCache
= 1 - LastRead
; // NOTE: If NUM_CACHES > 2, this must become more complex
572 if (Caches
[ReadCache
].Cache
== NULL
)
573 Caches
[ReadCache
].Cache
= AllocatePool(CACHE_SIZE
);
574 if (Caches
[ReadCache
].Cache
!= NULL
) {
575 Status
= refit_call5_wrapper(Volume
->DiskIo
->ReadDisk
, Volume
->DiskIo
, Volume
->MediaId
,
576 StartRead
, CACHE_SIZE
, Caches
[ReadCache
].Cache
);
577 if (!EFI_ERROR(Status
)) {
578 Caches
[ReadCache
].CacheStart
= StartRead
;
579 Caches
[ReadCache
].CacheValid
= TRUE
;
580 Caches
[ReadCache
].Volume
= Volume
;
581 LastRead
= ReadCache
;
587 } // if cache memory allocated
588 } // if (ReadCache < 0)
590 if (Caches
[ReadCache
].Cache
!= NULL
) {
591 CopyMem(buffer
, &Caches
[ReadCache
].Cache
[StartRead
- Caches
[ReadCache
].CacheStart
], vol
->phys_blocksize
);
596 if (ReadOneBlock
) { // Something's failed, so try a simple disk read of one block....
597 Status
= refit_call5_wrapper(Volume
->DiskIo
->ReadDisk
, Volume
->DiskIo
, Volume
->MediaId
,
598 phys_bno
* vol
->phys_blocksize
,
602 Volume
->LastIOStatus
= Status
;
605 } // fsw_status_t *fsw_efi_read_block()
608 * Map FSW status codes to EFI status codes. The FSW_IO_ERROR code is only produced
609 * by fsw_efi_read_block, so we map it back to the EFI status code remembered from
610 * the last I/O operation.
613 EFI_STATUS
fsw_efi_map_status(fsw_status_t fsw_status
, FSW_VOLUME_DATA
*Volume
)
615 switch (fsw_status
) {
618 case FSW_OUT_OF_MEMORY
:
619 return EFI_VOLUME_CORRUPTED
;
621 return Volume
->LastIOStatus
;
622 case FSW_UNSUPPORTED
:
623 return EFI_UNSUPPORTED
;
625 return EFI_NOT_FOUND
;
626 case FSW_VOLUME_CORRUPTED
:
627 return EFI_VOLUME_CORRUPTED
;
629 return EFI_DEVICE_ERROR
;
634 * File System EFI protocol, OpenVolume function. Creates a file handle for
635 * the root directory and returns it. Note that this function may be called
636 * multiple times and returns a new file handle each time. Each returned
637 * handle is closed by the client using it.
640 EFI_STATUS EFIAPI
fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE
*This
,
644 FSW_VOLUME_DATA
*Volume
= FSW_VOLUME_FROM_FILE_SYSTEM(This
);
647 Print(L
"fsw_efi_FileSystem_OpenVolume\n");
650 fsw_efi_clear_cache();
651 Status
= fsw_efi_dnode_to_FileHandle(Volume
->vol
->root
, Root
);
657 * File Handle EFI protocol, Open function. Dispatches the call
658 * based on the kind of file handle.
661 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Open(IN EFI_FILE
*This
,
662 OUT EFI_FILE
**NewHandle
,
665 IN UINT64 Attributes
)
667 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
669 if (File
->Type
== FSW_EFI_FILE_TYPE_DIR
)
670 return fsw_efi_dir_open(File
, NewHandle
, FileName
, OpenMode
, Attributes
);
671 // not supported for regular files
672 return EFI_UNSUPPORTED
;
676 * File Handle EFI protocol, Close function. Closes the FSW shandle
677 * and frees the memory used for the structure.
680 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Close(IN EFI_FILE
*This
)
682 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
685 Print(L
"fsw_efi_FileHandle_Close\n");
688 fsw_shandle_close(&File
->shand
);
695 * File Handle EFI protocol, Delete function. Calls through to Close
696 * and returns a warning because this driver is read-only.
699 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Delete(IN EFI_FILE
*This
)
703 Status
= refit_call1_wrapper(This
->Close
, This
);
704 if (Status
== EFI_SUCCESS
) {
705 // this driver is read-only
706 Status
= EFI_WARN_DELETE_FAILURE
;
713 * File Handle EFI protocol, Read function. Dispatches the call
714 * based on the kind of file handle.
717 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Read(IN EFI_FILE
*This
,
718 IN OUT UINTN
*BufferSize
,
721 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
723 if (File
->Type
== FSW_EFI_FILE_TYPE_FILE
)
724 return fsw_efi_file_read(File
, BufferSize
, Buffer
);
725 else if (File
->Type
== FSW_EFI_FILE_TYPE_DIR
)
726 return fsw_efi_dir_read(File
, BufferSize
, Buffer
);
727 return EFI_UNSUPPORTED
;
731 * File Handle EFI protocol, Write function. Returns unsupported status
732 * because this driver is read-only.
735 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Write(IN EFI_FILE
*This
,
736 IN OUT UINTN
*BufferSize
,
739 // this driver is read-only
740 return EFI_WRITE_PROTECTED
;
744 * File Handle EFI protocol, GetPosition function. Dispatches the call
745 * based on the kind of file handle.
748 EFI_STATUS EFIAPI
fsw_efi_FileHandle_GetPosition(IN EFI_FILE
*This
,
749 OUT UINT64
*Position
)
751 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
753 if (File
->Type
== FSW_EFI_FILE_TYPE_FILE
)
754 return fsw_efi_file_getpos(File
, Position
);
755 // not defined for directories
756 return EFI_UNSUPPORTED
;
760 * File Handle EFI protocol, SetPosition function. Dispatches the call
761 * based on the kind of file handle.
764 EFI_STATUS EFIAPI
fsw_efi_FileHandle_SetPosition(IN EFI_FILE
*This
,
767 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
769 if (File
->Type
== FSW_EFI_FILE_TYPE_FILE
)
770 return fsw_efi_file_setpos(File
, Position
);
771 else if (File
->Type
== FSW_EFI_FILE_TYPE_DIR
)
772 return fsw_efi_dir_setpos(File
, Position
);
773 return EFI_UNSUPPORTED
;
777 * File Handle EFI protocol, GetInfo function. Dispatches to the common
778 * function implementing this.
781 EFI_STATUS EFIAPI
fsw_efi_FileHandle_GetInfo(IN EFI_FILE
*This
,
782 IN EFI_GUID
*InformationType
,
783 IN OUT UINTN
*BufferSize
,
786 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
788 return fsw_efi_dnode_getinfo(File
, InformationType
, BufferSize
, Buffer
);
792 * File Handle EFI protocol, SetInfo function. Returns unsupported status
793 * because this driver is read-only.
796 EFI_STATUS EFIAPI
fsw_efi_FileHandle_SetInfo(IN EFI_FILE
*This
,
797 IN EFI_GUID
*InformationType
,
801 // this driver is read-only
802 return EFI_WRITE_PROTECTED
;
806 * File Handle EFI protocol, Flush function. Returns unsupported status
807 * because this driver is read-only.
810 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Flush(IN EFI_FILE
*This
)
812 // this driver is read-only
813 return EFI_WRITE_PROTECTED
;
817 * Set up a file handle for a dnode. This function allocates a data structure
818 * for a file handle, opens a FSW shandle and populates the EFI_FILE structure
819 * with the interface functions.
822 EFI_STATUS
fsw_efi_dnode_to_FileHandle(IN
struct fsw_dnode
*dno
,
823 OUT EFI_FILE
**NewFileHandle
)
828 // make sure the dnode has complete info
829 Status
= fsw_efi_map_status(fsw_dnode_fill(dno
), (FSW_VOLUME_DATA
*)dno
->vol
->host_data
);
830 if (EFI_ERROR(Status
))
834 if (dno
->type
!= FSW_DNODE_TYPE_FILE
&& dno
->type
!= FSW_DNODE_TYPE_DIR
)
835 return EFI_UNSUPPORTED
;
837 // allocate file structure
838 File
= AllocateZeroPool(sizeof(FSW_FILE_DATA
));
839 File
->Signature
= FSW_FILE_DATA_SIGNATURE
;
840 if (dno
->type
== FSW_DNODE_TYPE_FILE
)
841 File
->Type
= FSW_EFI_FILE_TYPE_FILE
;
842 else if (dno
->type
== FSW_DNODE_TYPE_DIR
)
843 File
->Type
= FSW_EFI_FILE_TYPE_DIR
;
846 Status
= fsw_efi_map_status(fsw_shandle_open(dno
, &File
->shand
),
847 (FSW_VOLUME_DATA
*)dno
->vol
->host_data
);
848 if (EFI_ERROR(Status
)) {
853 // populate the file handle
854 File
->FileHandle
.Revision
= EFI_FILE_HANDLE_REVISION
;
855 File
->FileHandle
.Open
= fsw_efi_FileHandle_Open
;
856 File
->FileHandle
.Close
= fsw_efi_FileHandle_Close
;
857 File
->FileHandle
.Delete
= fsw_efi_FileHandle_Delete
;
858 File
->FileHandle
.Read
= fsw_efi_FileHandle_Read
;
859 File
->FileHandle
.Write
= fsw_efi_FileHandle_Write
;
860 File
->FileHandle
.GetPosition
= fsw_efi_FileHandle_GetPosition
;
861 File
->FileHandle
.SetPosition
= fsw_efi_FileHandle_SetPosition
;
862 File
->FileHandle
.GetInfo
= fsw_efi_FileHandle_GetInfo
;
863 File
->FileHandle
.SetInfo
= fsw_efi_FileHandle_SetInfo
;
864 File
->FileHandle
.Flush
= fsw_efi_FileHandle_Flush
;
866 *NewFileHandle
= &File
->FileHandle
;
871 * Data read function for regular files. Calls through to fsw_shandle_read.
874 EFI_STATUS
fsw_efi_file_read(IN FSW_FILE_DATA
*File
,
875 IN OUT UINTN
*BufferSize
,
882 Print(L
"fsw_efi_file_read %d bytes\n", *BufferSize
);
885 buffer_size
= (fsw_u32
)*BufferSize
;
886 Status
= fsw_efi_map_status(fsw_shandle_read(&File
->shand
, &buffer_size
, Buffer
),
887 (FSW_VOLUME_DATA
*)File
->shand
.dnode
->vol
->host_data
);
888 *BufferSize
= buffer_size
;
894 * Get file position for regular files.
897 EFI_STATUS
fsw_efi_file_getpos(IN FSW_FILE_DATA
*File
,
898 OUT UINT64
*Position
)
900 *Position
= File
->shand
.pos
;
905 * Set file position for regular files. EFI specifies the all-ones value
906 * to be a special value for the end of the file.
909 EFI_STATUS
fsw_efi_file_setpos(IN FSW_FILE_DATA
*File
, IN UINT64 Position
)
911 if (Position
== 0xFFFFFFFFFFFFFFFFULL
)
912 File
->shand
.pos
= File
->shand
.dnode
->size
;
914 File
->shand
.pos
= Position
;
919 * Open function used to open new file handles relative to a directory.
920 * In EFI, the "open file" function is implemented by directory file handles
921 * and is passed a relative or volume-absolute path to the file or directory
922 * to open. We use fsw_dnode_lookup_path to find the node plus an additional
923 * call to fsw_dnode_resolve because EFI has no concept of symbolic links.
926 EFI_STATUS
fsw_efi_dir_open(IN FSW_FILE_DATA
*File
,
927 OUT EFI_FILE
**NewHandle
,
930 IN UINT64 Attributes
)
933 FSW_VOLUME_DATA
*Volume
= (FSW_VOLUME_DATA
*)File
->shand
.dnode
->vol
->host_data
;
934 struct fsw_dnode
*dno
;
935 struct fsw_dnode
*target_dno
;
936 struct fsw_string lookup_path
;
939 Print(L
"fsw_efi_dir_open: '%s'\n", FileName
);
942 if (OpenMode
!= EFI_FILE_MODE_READ
)
943 return EFI_WRITE_PROTECTED
;
945 lookup_path
.type
= FSW_STRING_TYPE_UTF16
;
946 lookup_path
.len
= (int)StrLen(FileName
);
947 lookup_path
.size
= lookup_path
.len
* sizeof(fsw_u16
);
948 lookup_path
.data
= FileName
;
950 // resolve the path (symlinks along the way are automatically resolved)
951 Status
= fsw_efi_map_status(fsw_dnode_lookup_path(File
->shand
.dnode
, &lookup_path
, '\\', &dno
), Volume
);
952 if (EFI_ERROR(Status
))
955 // if the final node is a symlink, also resolve it
956 Status
= fsw_efi_map_status(fsw_dnode_resolve(dno
, &target_dno
), Volume
);
957 fsw_dnode_release(dno
);
958 if (EFI_ERROR(Status
))
962 // make a new EFI handle for the target dnode
963 Status
= fsw_efi_dnode_to_FileHandle(dno
, NewHandle
);
964 fsw_dnode_release(dno
);
969 * Read function for directories. A file handle read on a directory retrieves
970 * the next directory entry.
973 EFI_STATUS
fsw_efi_dir_read(IN FSW_FILE_DATA
*File
,
974 IN OUT UINTN
*BufferSize
,
978 FSW_VOLUME_DATA
*Volume
= (FSW_VOLUME_DATA
*)File
->shand
.dnode
->vol
->host_data
;
979 struct fsw_dnode
*dno
;
982 Print(L
"fsw_efi_dir_read...\n");
985 // read the next entry
986 Status
= fsw_efi_map_status(fsw_dnode_dir_read(&File
->shand
, &dno
), Volume
);
987 if (Status
== EFI_NOT_FOUND
) {
991 Print(L
"...no more entries\n");
995 if (EFI_ERROR(Status
))
998 // get info into buffer
999 Status
= fsw_efi_dnode_fill_FileInfo(Volume
, dno
, BufferSize
, Buffer
);
1000 fsw_dnode_release(dno
);
1005 * Set file position for directories. The only allowed set position operation
1006 * for directories is to rewind the directory completely by setting the
1010 EFI_STATUS
fsw_efi_dir_setpos(IN FSW_FILE_DATA
*File
, IN UINT64 Position
)
1012 if (Position
== 0) {
1013 File
->shand
.pos
= 0;
1016 // directories can only rewind to the start
1017 return EFI_UNSUPPORTED
;
1022 * Get file or volume information. This function implements the GetInfo call
1023 * for all file handles. Control is dispatched according to the type of information
1024 * requested by the caller.
1027 EFI_STATUS
fsw_efi_dnode_getinfo(IN FSW_FILE_DATA
*File
,
1028 IN EFI_GUID
*InformationType
,
1029 IN OUT UINTN
*BufferSize
,
1033 FSW_VOLUME_DATA
*Volume
= (FSW_VOLUME_DATA
*)File
->shand
.dnode
->vol
->host_data
;
1034 EFI_FILE_SYSTEM_INFO
*FSInfo
;
1036 struct fsw_volume_stat vsb
;
1039 if (CompareGuid(InformationType
, &gEfiFileInfoGuid
)) {
1041 Print(L
"fsw_efi_dnode_getinfo: FILE_INFO\n");
1044 Status
= fsw_efi_dnode_fill_FileInfo(Volume
, File
->shand
.dnode
, BufferSize
, Buffer
);
1046 } else if (CompareGuid(InformationType
, &gEfiFileSystemInfoGuid
)) {
1048 Print(L
"fsw_efi_dnode_getinfo: FILE_SYSTEM_INFO\n");
1051 // check buffer size
1052 RequiredSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ fsw_efi_strsize(&Volume
->vol
->label
);
1053 if (*BufferSize
< RequiredSize
) {
1054 *BufferSize
= RequiredSize
;
1055 return EFI_BUFFER_TOO_SMALL
;
1059 FSInfo
= (EFI_FILE_SYSTEM_INFO
*)Buffer
;
1060 FSInfo
->Size
= RequiredSize
;
1061 FSInfo
->ReadOnly
= TRUE
;
1062 FSInfo
->BlockSize
= Volume
->vol
->log_blocksize
;
1063 fsw_efi_strcpy(FSInfo
->VolumeLabel
, &Volume
->vol
->label
);
1065 // get the missing info from the fs driver
1066 ZeroMem(&vsb
, sizeof(struct fsw_volume_stat
));
1067 Status
= fsw_efi_map_status(fsw_volume_stat(Volume
->vol
, &vsb
), Volume
);
1068 if (EFI_ERROR(Status
))
1070 FSInfo
->VolumeSize
= vsb
.total_bytes
;
1071 FSInfo
->FreeSpace
= vsb
.free_bytes
;
1073 // prepare for return
1074 *BufferSize
= RequiredSize
;
1075 Status
= EFI_SUCCESS
;
1077 } else if (CompareGuid(InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1079 Print(L
"fsw_efi_dnode_getinfo: FILE_SYSTEM_VOLUME_LABEL\n");
1082 // check buffer size
1083 RequiredSize
= SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO
+ fsw_efi_strsize(&Volume
->vol
->label
);
1084 if (*BufferSize
< RequiredSize
) {
1085 *BufferSize
= RequiredSize
;
1086 return EFI_BUFFER_TOO_SMALL
;
1089 // copy volume label
1090 fsw_efi_strcpy(((EFI_FILE_SYSTEM_VOLUME_LABEL_INFO
*)Buffer
)->VolumeLabel
, &Volume
->vol
->label
);
1092 // prepare for return
1093 *BufferSize
= RequiredSize
;
1094 Status
= EFI_SUCCESS
;
1097 Status
= EFI_UNSUPPORTED
;
1104 * Time mapping callback for the fsw_dnode_stat call. This function converts
1105 * a Posix style timestamp into an EFI_TIME structure and writes it to the
1106 * appropriate member of the EFI_FILE_INFO structure that we're filling.
1109 static void fsw_efi_store_time_posix(struct fsw_dnode_stat
*sb
, int which
, fsw_u32 posix_time
)
1111 EFI_FILE_INFO
*FileInfo
= (EFI_FILE_INFO
*)sb
->host_data
;
1113 if (which
== FSW_DNODE_STAT_CTIME
)
1114 fsw_efi_decode_time(&FileInfo
->CreateTime
, posix_time
);
1115 else if (which
== FSW_DNODE_STAT_MTIME
)
1116 fsw_efi_decode_time(&FileInfo
->ModificationTime
, posix_time
);
1117 else if (which
== FSW_DNODE_STAT_ATIME
)
1118 fsw_efi_decode_time(&FileInfo
->LastAccessTime
, posix_time
);
1122 * Mode mapping callback for the fsw_dnode_stat call. This function looks at
1123 * the Posix mode passed by the file system driver and makes appropriate
1124 * adjustments to the EFI_FILE_INFO structure that we're filling.
1127 static void fsw_efi_store_attr_posix(struct fsw_dnode_stat
*sb
, fsw_u16 posix_mode
)
1129 EFI_FILE_INFO
*FileInfo
= (EFI_FILE_INFO
*)sb
->host_data
;
1131 if ((posix_mode
& S_IWUSR
) == 0)
1132 FileInfo
->Attribute
|= EFI_FILE_READ_ONLY
;
1136 * Common function to fill an EFI_FILE_INFO with information about a dnode.
1139 EFI_STATUS
fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA
*Volume
,
1140 IN
struct fsw_dnode
*dno
,
1141 IN OUT UINTN
*BufferSize
,
1145 EFI_FILE_INFO
*FileInfo
;
1147 struct fsw_dnode_stat sb
;
1149 // make sure the dnode has complete info
1150 Status
= fsw_efi_map_status(fsw_dnode_fill(dno
), Volume
);
1151 if (EFI_ERROR(Status
))
1154 // TODO: check/assert that the dno's name is in UTF16
1156 // check buffer size
1157 RequiredSize
= SIZE_OF_EFI_FILE_INFO
+ fsw_efi_strsize(&dno
->name
);
1158 if (*BufferSize
< RequiredSize
) {
1159 // TODO: wind back the directory in this case
1162 Print(L
"...BUFFER TOO SMALL\n");
1164 *BufferSize
= RequiredSize
;
1165 return EFI_BUFFER_TOO_SMALL
;
1169 ZeroMem(Buffer
, RequiredSize
);
1170 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
1171 FileInfo
->Size
= RequiredSize
;
1172 FileInfo
->FileSize
= dno
->size
;
1173 FileInfo
->Attribute
= 0;
1174 if (dno
->type
== FSW_DNODE_TYPE_DIR
)
1175 FileInfo
->Attribute
|= EFI_FILE_DIRECTORY
;
1176 fsw_efi_strcpy(FileInfo
->FileName
, &dno
->name
);
1178 // get the missing info from the fs driver
1179 ZeroMem(&sb
, sizeof(struct fsw_dnode_stat
));
1180 sb
.store_time_posix
= fsw_efi_store_time_posix
;
1181 sb
.store_attr_posix
= fsw_efi_store_attr_posix
;
1182 sb
.host_data
= FileInfo
;
1183 Status
= fsw_efi_map_status(fsw_dnode_stat(dno
, &sb
), Volume
);
1184 if (EFI_ERROR(Status
))
1186 FileInfo
->PhysicalSize
= sb
.used_bytes
;
1188 // prepare for return
1189 *BufferSize
= RequiredSize
;
1191 Print(L
"...returning '%s'\n", FileInfo
->FileName
);