X-Git-Url: https://code.delx.au/refind/blobdiff_plain/38c626aab2a451ca669576e4c57e5fbf5da987ad..45db1723901c7accd95b4cf996c2bb4bdca59fff:/filesystems/fsw_efi.c diff --git a/filesystems/fsw_efi.c b/filesystems/fsw_efi.c index e7d2400..88bcfc7 100644 --- a/filesystems/fsw_efi.c +++ b/filesystems/fsw_efi.c @@ -50,20 +50,20 @@ */ #include "fsw_efi.h" +#include "fsw_core.h" +#ifdef __MAKEWITH_GNUEFI +#include "edk2/DriverBinding.h" +#include "edk2/ComponentName.h" +#endif +#include "../include/refit_call_wrapper.h" #define DEBUG_LEVEL 0 #ifndef FSTYPE -#ifdef VBOX #error FSTYPE must be defined! -#else -#define FSTYPE ext2 -#endif #endif #define DEBUG_VBFS 1 -// CHAR8 *msgCursor; -// MESSAGE_LOG_PROTOCOL *Msg = NULL; #if DEBUG_VBFS==2 #define DBG(x...) AsciiPrint(x) @@ -73,11 +73,32 @@ #define DBG(x...) #endif +#ifdef __MAKEWITH_GNUEFI + +#define EFI_DISK_IO_PROTOCOL_GUID \ + { \ + 0xce345171, 0xba0b, 0x11d2, {0x8e, 0x4f, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +#define EFI_BLOCK_IO_PROTOCOL_GUID \ + { \ + 0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +EFI_GUID gEfiDriverBindingProtocolGuid = EFI_DRIVER_BINDING_PROTOCOL_GUID; +EFI_GUID gEfiComponentNameProtocolGuid = EFI_COMPONENT_NAME_PROTOCOL_GUID; +EFI_GUID gEfiDiskIoProtocolGuid = EFI_DISK_IO_PROTOCOL_GUID; +EFI_GUID gEfiBlockIoProtocolGuid = EFI_BLOCK_IO_PROTOCOL_GUID; +EFI_GUID gEfiFileInfoGuid = EFI_FILE_INFO_ID; +EFI_GUID gEfiFileSystemInfoGuid = EFI_FILE_SYSTEM_INFO_ID; +EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = EFI_FILE_SYSTEM_VOLUME_LABEL_INFO_ID; +#define SimpleFileSystemProtocol FileSystemProtocol +#endif /** Helper macro for stringification. */ #define FSW_EFI_STRINGIFY(x) #x /** Expands to the EFI driver name given the file system type name. */ -#define FSW_EFI_DRIVER_NAME(t) L"Fsw " FSW_EFI_STRINGIFY(t) L" File System Driver" +#define FSW_EFI_DRIVER_NAME(t) L"rEFInd 0.6.12.2 " FSW_EFI_STRINGIFY(t) L" File System Driver" // function prototypes @@ -161,7 +182,7 @@ EFI_DRIVER_BINDING_PROTOCOL fsw_efi_DriverBinding_table = { EFI_COMPONENT_NAME_PROTOCOL fsw_efi_ComponentName_table = { fsw_efi_ComponentName_GetDriverName, fsw_efi_ComponentName_GetControllerName, - "eng" + (CHAR8*) "eng" }; /** @@ -189,7 +210,8 @@ EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE ImageHandle, { EFI_STATUS Status; -#ifndef VBOX +#ifndef HOST_EFI_EDK2 + // Not available in EDK2 toolkit InitializeLib(ImageHandle, SystemTable); #endif @@ -197,8 +219,8 @@ EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE ImageHandle, fsw_efi_DriverBinding_table.ImageHandle = ImageHandle; fsw_efi_DriverBinding_table.DriverBindingHandle = ImageHandle; // install Driver Binding protocol - Status = BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.DriverBindingHandle, - &PROTO_NAME(DriverBindingProtocol), + Status = refit_call4_wrapper(BS->InstallProtocolInterface, &fsw_efi_DriverBinding_table.DriverBindingHandle, + &gEfiDriverBindingProtocolGuid, EFI_NATIVE_INTERFACE, &fsw_efi_DriverBinding_table); if (EFI_ERROR (Status)) { @@ -206,8 +228,8 @@ EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE ImageHandle, } // install Component Name protocol - Status = BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.DriverBindingHandle, - &PROTO_NAME(ComponentNameProtocol), + Status = refit_call4_wrapper(BS->InstallProtocolInterface, &fsw_efi_DriverBinding_table.DriverBindingHandle, + &gEfiComponentNameProtocolGuid, EFI_NATIVE_INTERFACE, &fsw_efi_ComponentName_table); if (EFI_ERROR (Status)) { @@ -226,6 +248,10 @@ EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE ImageHandle, return EFI_SUCCESS; } +#ifdef __MAKEWITH_GNUEFI +EFI_DRIVER_ENTRY_POINT(fsw_efi_main) +#endif + /** * Driver Binding EFI protocol, Supported function. This function is called by EFI * to test if this driver can handle a certain device. Our implementation only checks @@ -243,7 +269,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL // we check for both DiskIO and BlockIO protocols // first, open DiskIO - Status = BS->OpenProtocol(ControllerHandle, + Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, &PROTO_NAME(DiskIoProtocol), (VOID **) &DiskIo, This->DriverBindingHandle, @@ -253,13 +279,13 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL return Status; // we were just checking, close it again - BS->CloseProtocol(ControllerHandle, + refit_call4_wrapper(BS->CloseProtocol, ControllerHandle, &PROTO_NAME(DiskIoProtocol), This->DriverBindingHandle, ControllerHandle); // next, check BlockIO without actually opening it - Status = BS->OpenProtocol(ControllerHandle, + Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, &PROTO_NAME(BlockIoProtocol), NULL, This->DriverBindingHandle, @@ -295,7 +321,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *T #endif // open consumed protocols - Status = BS->OpenProtocol(ControllerHandle, + Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, &PROTO_NAME(BlockIoProtocol), (VOID **) &BlockIo, This->DriverBindingHandle, @@ -306,14 +332,13 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *T return Status; } - Status = BS->OpenProtocol(ControllerHandle, + Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, &PROTO_NAME(DiskIoProtocol), (VOID **) &DiskIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); if (EFI_ERROR(Status)) { - Print(L"Fsw ERROR: OpenProtocol(DiskIo) returned %r\n", Status); return Status; } @@ -334,7 +359,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *T // register the SimpleFileSystem protocol Volume->FileSystem.Revision = EFI_FILE_IO_INTERFACE_REVISION; Volume->FileSystem.OpenVolume = fsw_efi_FileSystem_OpenVolume; - Status = BS->InstallMultipleProtocolInterfaces(&ControllerHandle, + Status = refit_call4_wrapper(BS->InstallMultipleProtocolInterfaces, &ControllerHandle, &PROTO_NAME(SimpleFileSystemProtocol), &Volume->FileSystem, NULL); @@ -349,7 +374,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *T fsw_unmount(Volume->vol); FreePool(Volume); - BS->CloseProtocol(ControllerHandle, + refit_call4_wrapper(BS->CloseProtocol, ControllerHandle, &PROTO_NAME(DiskIoProtocol), This->DriverBindingHandle, ControllerHandle); @@ -382,7 +407,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *T #endif // get the installed SimpleFileSystem interface - Status = BS->OpenProtocol(ControllerHandle, + Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, &PROTO_NAME(SimpleFileSystemProtocol), (VOID **) &FileSystem, This->DriverBindingHandle, @@ -395,7 +420,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *T Volume = FSW_VOLUME_FROM_FILE_SYSTEM(FileSystem); // uninstall Simple File System protocol - Status = BS->UninstallMultipleProtocolInterfaces(ControllerHandle, + Status = refit_call4_wrapper(BS->UninstallMultipleProtocolInterfaces, ControllerHandle, &PROTO_NAME(SimpleFileSystemProtocol), &Volume->FileSystem, NULL); if (EFI_ERROR(Status)) { @@ -412,7 +437,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *T FreePool(Volume); // close the consumed protocols - Status = BS->CloseProtocol(ControllerHandle, + Status = refit_call4_wrapper(BS->CloseProtocol, ControllerHandle, &PROTO_NAME(DiskIoProtocol), This->DriverBindingHandle, ControllerHandle); @@ -471,23 +496,87 @@ void fsw_efi_change_blocksize(struct fsw_volume *vol, * to read a block of data from the device. The buffer is allocated by the core code. */ + +#if CACHE != 0 +/** + * This version implements a primitive cache that greatly improves performance of most + * filesystems under VirtualBox, and slightly improves it on a handful of other systems. + */ +#define CACHE_SIZE 131072 /* 128KiB */ fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer) { - EFI_STATUS Status; - FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)vol->host_data; + EFI_STATUS Status = EFI_SUCCESS; + FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)vol->host_data; + static fsw_u8 *Cache = NULL; + static fsw_u64 CacheStart = 0; + static BOOLEAN CacheValid = FALSE; + static FSW_VOLUME_DATA *PrevVol = NULL; + fsw_u64 StartRead = (fsw_u64) phys_bno * vol->phys_blocksize; // FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_efi_read_block: %d (%d)\n"), phys_bno, vol->phys_blocksize)); + if (Cache == NULL) { + Cache = AllocatePool(CACHE_SIZE); + } + + if ((PrevVol != Volume) || (StartRead < CacheStart) || ((StartRead + vol->phys_blocksize) > CacheStart + CACHE_SIZE)) { + CacheStart = StartRead; + CacheValid = FALSE; + PrevVol = Volume; + } + // read from disk - Status = Volume->DiskIo->ReadDisk(Volume->DiskIo, Volume->MediaId, - (UINT64)phys_bno * vol->phys_blocksize, - vol->phys_blocksize, - buffer); + if (!CacheValid && (Cache != NULL)) { + Status = refit_call5_wrapper(Volume->DiskIo->ReadDisk, Volume->DiskIo, Volume->MediaId, + StartRead, CACHE_SIZE, Cache); + if (!EFI_ERROR(Status)) + CacheValid = TRUE; + } // if (!CacheValid) + + if (CacheValid) { + if (buffer != NULL) { + CopyMem(buffer, &Cache[StartRead - CacheStart], vol->phys_blocksize); + } else { + Status = EFI_BAD_BUFFER_SIZE; + } // if/else buffer OK + } else { + // Unable to use cache; load without cache.... + Status = refit_call5_wrapper(Volume->DiskIo->ReadDisk, Volume->DiskIo, Volume->MediaId, + (UINT64)phys_bno * vol->phys_blocksize, + vol->phys_blocksize, + buffer); + } // if/else CacheValid + Volume->LastIOStatus = Status; if (EFI_ERROR(Status)) return FSW_IO_ERROR; return FSW_SUCCESS; } +#else +/** + * This version is the original, which does NOT implement a cache. It performs badly under + * VirtualBox, but I'm still using it for ext2fs because there seems to be a glitch in the + * ext2fs driver that causes a loop that repeatedly re-reads pairs of sectors, and the + * primitive cache in the preceding code just makes that worse. + */ +fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer) +{ + EFI_STATUS Status; + FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)vol->host_data; + +// FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_efi_read_block: %d (%d)\n"), phys_bno, vol->phys_blocksize)); + + // read from disk + Status = refit_call5_wrapper(Volume->DiskIo->ReadDisk, Volume->DiskIo, Volume->MediaId, + (UINT64)phys_bno * vol->phys_blocksize, + vol->phys_blocksize, + buffer); + Volume->LastIOStatus = Status; + if (EFI_ERROR(Status)) + return FSW_IO_ERROR; + return FSW_SUCCESS; +} +#endif /** * Map FSW status codes to EFI status codes. The FSW_IO_ERROR code is only produced @@ -584,7 +673,7 @@ EFI_STATUS EFIAPI fsw_efi_FileHandle_Delete(IN EFI_FILE *This) { EFI_STATUS Status; - Status = This->Close(This); + Status = refit_call1_wrapper(This->Close, This); if (Status == EFI_SUCCESS) { // this driver is read-only Status = EFI_WARN_DELETE_FAILURE; @@ -790,8 +879,7 @@ EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File, * to be a special value for the end of the file. */ -EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File, - IN UINT64 Position) +EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File, IN UINT64 Position) { if (Position == 0xFFFFFFFFFFFFFFFFULL) File->shand.pos = File->shand.dnode->size; @@ -833,14 +921,12 @@ EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File, lookup_path.data = FileName; // resolve the path (symlinks along the way are automatically resolved) - Status = fsw_efi_map_status(fsw_dnode_lookup_path(File->shand.dnode, &lookup_path, '\\', &dno), - Volume); + Status = fsw_efi_map_status(fsw_dnode_lookup_path(File->shand.dnode, &lookup_path, '\\', &dno), Volume); if (EFI_ERROR(Status)) return Status; // if the final node is a symlink, also resolve it - Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno), - Volume); + Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno), Volume); fsw_dnode_release(dno); if (EFI_ERROR(Status)) return Status; @@ -870,8 +956,7 @@ EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File, #endif // read the next entry - Status = fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno), - Volume); + Status = fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno), Volume); if (Status == EFI_NOT_FOUND) { // end of directory *BufferSize = 0; @@ -895,8 +980,7 @@ EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File, * position to zero. */ -EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File, - IN UINT64 Position) +EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File, IN UINT64 Position) { if (Position == 0) { File->shand.pos = 0;