[48674] | 1 | /* $Id: fsw_efi.c 98103 2023-01-17 14:15:46Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * fsw_efi.c - EFI host environment code.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2010-2023 Oracle and/or its affiliates.
|
---|
[48674] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
[48674] | 11 | *
|
---|
[96407] | 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
[48674] | 25 | * The contents of this file may alternatively be used under the terms
|
---|
| 26 | * of the Common Development and Distribution License Version 1.0
|
---|
[96407] | 27 | * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
|
---|
| 28 | * in the VirtualBox distribution, in which case the provisions of the
|
---|
[48674] | 29 | * CDDL are applicable instead of those of the GPL.
|
---|
| 30 | *
|
---|
| 31 | * You may elect to license modified versions of this file under the
|
---|
| 32 | * terms and conditions of either the GPL or the CDDL or both.
|
---|
[96407] | 33 | *
|
---|
| 34 | * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
|
---|
[69498] | 35 | * ---------------------------------------------------------------------------
|
---|
[48674] | 36 | * This code is based on:
|
---|
| 37 | *
|
---|
| 38 | * Copyright (c) 2006 Christoph Pfisterer
|
---|
| 39 | *
|
---|
| 40 | * Redistribution and use in source and binary forms, with or without
|
---|
| 41 | * modification, are permitted provided that the following conditions are
|
---|
| 42 | * met:
|
---|
| 43 | *
|
---|
| 44 | * * Redistributions of source code must retain the above copyright
|
---|
| 45 | * notice, this list of conditions and the following disclaimer.
|
---|
| 46 | *
|
---|
| 47 | * * Redistributions in binary form must reproduce the above copyright
|
---|
| 48 | * notice, this list of conditions and the following disclaimer in the
|
---|
| 49 | * documentation and/or other materials provided with the
|
---|
| 50 | * distribution.
|
---|
| 51 | *
|
---|
| 52 | * * Neither the name of Christoph Pfisterer nor the names of the
|
---|
| 53 | * contributors may be used to endorse or promote products derived
|
---|
| 54 | * from this software without specific prior written permission.
|
---|
| 55 | *
|
---|
| 56 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
---|
| 57 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
---|
| 58 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
---|
| 59 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
---|
| 60 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
---|
| 61 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
---|
| 62 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
---|
| 63 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
---|
| 64 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
---|
| 65 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
---|
| 66 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
| 67 | */
|
---|
| 68 |
|
---|
| 69 | #include "fsw_efi.h"
|
---|
| 70 |
|
---|
| 71 | #define DEBUG_LEVEL 0
|
---|
| 72 |
|
---|
| 73 | #ifndef FSTYPE
|
---|
| 74 | #ifdef VBOX
|
---|
| 75 | #error FSTYPE must be defined!
|
---|
| 76 | #else
|
---|
| 77 | #define FSTYPE ext2
|
---|
| 78 | #endif
|
---|
| 79 | #endif
|
---|
| 80 |
|
---|
| 81 | /** Helper macro for stringification. */
|
---|
| 82 | #define FSW_EFI_STRINGIFY(x) L#x
|
---|
| 83 | /** Expands to the EFI driver name given the file system type name. */
|
---|
| 84 | #define FSW_EFI_DRIVER_NAME(t) L"Fsw " FSW_EFI_STRINGIFY(t) L" File System Driver"
|
---|
| 85 |
|
---|
| 86 |
|
---|
| 87 | // function prototypes
|
---|
| 88 |
|
---|
| 89 | EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
---|
| 90 | IN EFI_HANDLE ControllerHandle,
|
---|
| 91 | IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath);
|
---|
| 92 | EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
---|
| 93 | IN EFI_HANDLE ControllerHandle,
|
---|
| 94 | IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath);
|
---|
| 95 | EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
---|
| 96 | IN EFI_HANDLE ControllerHandle,
|
---|
| 97 | IN UINTN NumberOfChildren,
|
---|
| 98 | IN EFI_HANDLE *ChildHandleBuffer);
|
---|
| 99 |
|
---|
| 100 | EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
---|
| 101 | IN CHAR8 *Language,
|
---|
| 102 | OUT CHAR16 **DriverName);
|
---|
| 103 | EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
---|
| 104 | IN EFI_HANDLE ControllerHandle,
|
---|
| 105 | IN EFI_HANDLE ChildHandle OPTIONAL,
|
---|
| 106 | IN CHAR8 *Language,
|
---|
| 107 | OUT CHAR16 **ControllerName);
|
---|
| 108 |
|
---|
| 109 | void fsw_efi_change_blocksize(struct fsw_volume *vol,
|
---|
| 110 | fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
|
---|
| 111 | fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
|
---|
| 112 | fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer);
|
---|
| 113 |
|
---|
| 114 | EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume);
|
---|
| 115 |
|
---|
| 116 | EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
|
---|
| 117 | OUT EFI_FILE **Root);
|
---|
| 118 | EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno,
|
---|
| 119 | OUT EFI_FILE **NewFileHandle);
|
---|
| 120 |
|
---|
| 121 | EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File,
|
---|
| 122 | IN OUT UINTN *BufferSize,
|
---|
| 123 | OUT VOID *Buffer);
|
---|
| 124 | EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File,
|
---|
| 125 | OUT UINT64 *Position);
|
---|
| 126 | EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File,
|
---|
| 127 | IN UINT64 Position);
|
---|
| 128 |
|
---|
| 129 | EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
|
---|
| 130 | OUT EFI_FILE **NewHandle,
|
---|
| 131 | IN CHAR16 *FileName,
|
---|
| 132 | IN UINT64 OpenMode,
|
---|
| 133 | IN UINT64 Attributes);
|
---|
| 134 | EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
|
---|
| 135 | IN OUT UINTN *BufferSize,
|
---|
| 136 | OUT VOID *Buffer);
|
---|
| 137 | EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File,
|
---|
| 138 | IN UINT64 Position);
|
---|
| 139 |
|
---|
| 140 | EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File,
|
---|
| 141 | IN EFI_GUID *InformationType,
|
---|
| 142 | IN OUT UINTN *BufferSize,
|
---|
| 143 | OUT VOID *Buffer);
|
---|
| 144 | EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
|
---|
| 145 | IN struct fsw_dnode *dno,
|
---|
| 146 | IN OUT UINTN *BufferSize,
|
---|
| 147 | OUT VOID *Buffer);
|
---|
| 148 |
|
---|
[93492] | 149 | #if defined(VBOX) && (FSTYPE == hfs)
|
---|
[82508] | 150 | extern fsw_status_t fsw_hfs_get_blessed_file(void *vol, struct fsw_string *path);
|
---|
| 151 | #endif
|
---|
| 152 |
|
---|
[48674] | 153 | /**
|
---|
| 154 | * Interface structure for the EFI Driver Binding protocol.
|
---|
| 155 | */
|
---|
| 156 |
|
---|
| 157 | EFI_DRIVER_BINDING_PROTOCOL fsw_efi_DriverBinding_table = {
|
---|
| 158 | fsw_efi_DriverBinding_Supported,
|
---|
| 159 | fsw_efi_DriverBinding_Start,
|
---|
| 160 | fsw_efi_DriverBinding_Stop,
|
---|
| 161 | 0x10,
|
---|
| 162 | NULL,
|
---|
| 163 | NULL
|
---|
| 164 | };
|
---|
| 165 |
|
---|
| 166 | /**
|
---|
| 167 | * Interface structure for the EFI Component Name protocol.
|
---|
| 168 | */
|
---|
| 169 |
|
---|
| 170 | EFI_COMPONENT_NAME_PROTOCOL fsw_efi_ComponentName_table = {
|
---|
| 171 | fsw_efi_ComponentName_GetDriverName,
|
---|
| 172 | fsw_efi_ComponentName_GetControllerName,
|
---|
| 173 | "eng"
|
---|
| 174 | };
|
---|
| 175 |
|
---|
| 176 | /**
|
---|
| 177 | * Dispatch table for our FSW host driver.
|
---|
| 178 | */
|
---|
| 179 |
|
---|
| 180 | struct fsw_host_table fsw_efi_host_table = {
|
---|
| 181 | FSW_STRING_TYPE_UTF16,
|
---|
| 182 |
|
---|
| 183 | fsw_efi_change_blocksize,
|
---|
| 184 | fsw_efi_read_block
|
---|
| 185 | };
|
---|
| 186 |
|
---|
| 187 | extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE);
|
---|
| 188 |
|
---|
| 189 |
|
---|
| 190 |
|
---|
| 191 | /**
|
---|
| 192 | * Image entry point. Installs the Driver Binding and Component Name protocols
|
---|
| 193 | * on the image's handle. Actually mounting a file system is initiated through
|
---|
| 194 | * the Driver Binding protocol at the firmware's request.
|
---|
| 195 | */
|
---|
| 196 | EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE ImageHandle,
|
---|
| 197 | IN EFI_SYSTEM_TABLE *SystemTable)
|
---|
| 198 | {
|
---|
| 199 | EFI_STATUS Status;
|
---|
| 200 |
|
---|
| 201 | #ifndef VBOX
|
---|
| 202 | InitializeLib(ImageHandle, SystemTable);
|
---|
| 203 | #endif
|
---|
| 204 |
|
---|
| 205 | // complete Driver Binding protocol instance
|
---|
| 206 | fsw_efi_DriverBinding_table.ImageHandle = ImageHandle;
|
---|
| 207 | fsw_efi_DriverBinding_table.DriverBindingHandle = ImageHandle;
|
---|
| 208 | // install Driver Binding protocol
|
---|
| 209 | Status = BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.DriverBindingHandle,
|
---|
| 210 | &PROTO_NAME(DriverBindingProtocol),
|
---|
| 211 | EFI_NATIVE_INTERFACE,
|
---|
| 212 | &fsw_efi_DriverBinding_table);
|
---|
| 213 | if (EFI_ERROR (Status)) {
|
---|
| 214 | return Status;
|
---|
| 215 | }
|
---|
| 216 |
|
---|
| 217 | // install Component Name protocol
|
---|
| 218 | Status = BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.DriverBindingHandle,
|
---|
| 219 | &PROTO_NAME(ComponentNameProtocol),
|
---|
| 220 | EFI_NATIVE_INTERFACE,
|
---|
| 221 | &fsw_efi_ComponentName_table);
|
---|
| 222 | if (EFI_ERROR (Status)) {
|
---|
| 223 | return Status;
|
---|
| 224 | }
|
---|
| 225 |
|
---|
| 226 | return EFI_SUCCESS;
|
---|
| 227 | }
|
---|
| 228 |
|
---|
| 229 | /**
|
---|
| 230 | * Driver Binding EFI protocol, Supported function. This function is called by EFI
|
---|
| 231 | * to test if this driver can handle a certain device. Our implementation only checks
|
---|
| 232 | * if the device is a disk (i.e. that it supports the Block I/O and Disk I/O protocols)
|
---|
| 233 | * and implicitly checks if the disk is already in use by another driver.
|
---|
| 234 | */
|
---|
| 235 |
|
---|
| 236 | EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
---|
| 237 | IN EFI_HANDLE ControllerHandle,
|
---|
| 238 | IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath)
|
---|
| 239 | {
|
---|
| 240 | EFI_STATUS Status;
|
---|
| 241 | EFI_DISK_IO *DiskIo;
|
---|
| 242 |
|
---|
| 243 | // we check for both DiskIO and BlockIO protocols
|
---|
| 244 |
|
---|
| 245 | // first, open DiskIO
|
---|
| 246 | Status = BS->OpenProtocol(ControllerHandle,
|
---|
| 247 | &PROTO_NAME(DiskIoProtocol),
|
---|
| 248 | (VOID **) &DiskIo,
|
---|
| 249 | This->DriverBindingHandle,
|
---|
| 250 | ControllerHandle,
|
---|
| 251 | EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
---|
| 252 | if (EFI_ERROR(Status))
|
---|
| 253 | {
|
---|
| 254 | return Status;
|
---|
| 255 | }
|
---|
| 256 |
|
---|
| 257 | // we were just checking, close it again
|
---|
| 258 | BS->CloseProtocol(ControllerHandle,
|
---|
| 259 | &PROTO_NAME(DiskIoProtocol),
|
---|
| 260 | This->DriverBindingHandle,
|
---|
| 261 | ControllerHandle);
|
---|
| 262 |
|
---|
| 263 | // next, check BlockIO without actually opening it
|
---|
| 264 | Status = BS->OpenProtocol(ControllerHandle,
|
---|
| 265 | &PROTO_NAME(BlockIoProtocol),
|
---|
| 266 | NULL,
|
---|
| 267 | This->DriverBindingHandle,
|
---|
| 268 | ControllerHandle,
|
---|
| 269 | EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
|
---|
| 270 | return Status;
|
---|
| 271 | }
|
---|
| 272 |
|
---|
| 273 | static EFI_STATUS fsw_efi_ReMount(IN FSW_VOLUME_DATA *pVolume,
|
---|
| 274 | IN EFI_HANDLE ControllerHandle,
|
---|
| 275 | EFI_DISK_IO *pDiskIo,
|
---|
| 276 | EFI_BLOCK_IO *pBlockIo)
|
---|
| 277 | {
|
---|
| 278 | EFI_STATUS Status;
|
---|
| 279 | pVolume->Signature = FSW_VOLUME_DATA_SIGNATURE;
|
---|
| 280 | pVolume->Handle = ControllerHandle;
|
---|
| 281 | pVolume->DiskIo = pDiskIo;
|
---|
| 282 | pVolume->MediaId = pBlockIo->Media->MediaId;
|
---|
| 283 | pVolume->LastIOStatus = EFI_SUCCESS;
|
---|
| 284 |
|
---|
| 285 | // mount the filesystem
|
---|
| 286 | Status = fsw_efi_map_status(fsw_mount(pVolume, &fsw_efi_host_table,
|
---|
| 287 | &FSW_FSTYPE_TABLE_NAME(FSTYPE), &pVolume->vol),
|
---|
| 288 | pVolume);
|
---|
| 289 |
|
---|
| 290 | if (!EFI_ERROR(Status)) {
|
---|
| 291 | // register the SimpleFileSystem protocol
|
---|
| 292 | pVolume->FileSystem.Revision = EFI_FILE_IO_INTERFACE_REVISION;
|
---|
| 293 | pVolume->FileSystem.OpenVolume = fsw_efi_FileSystem_OpenVolume;
|
---|
| 294 | Status = BS->InstallMultipleProtocolInterfaces(&ControllerHandle,
|
---|
| 295 | &PROTO_NAME(SimpleFileSystemProtocol), &pVolume->FileSystem,
|
---|
| 296 | NULL);
|
---|
[58835] | 297 | #if DEBUG_LEVEL /* This error is always printed and destroys the boot logo. */
|
---|
[48674] | 298 | if (EFI_ERROR(Status))
|
---|
| 299 | Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned %x\n", Status);
|
---|
[58835] | 300 | #endif
|
---|
[48674] | 301 | }
|
---|
| 302 | return Status;
|
---|
| 303 | }
|
---|
| 304 |
|
---|
| 305 | /**
|
---|
| 306 | * Driver Binding EFI protocol, Start function. This function is called by EFI
|
---|
| 307 | * to start driving the given device. It is still possible at this point to
|
---|
| 308 | * return EFI_UNSUPPORTED, and in fact we will do so if the file system driver
|
---|
| 309 | * cannot find the superblock signature (or equivalent) that it expects.
|
---|
| 310 | *
|
---|
| 311 | * This function allocates memory for a per-volume structure, opens the
|
---|
| 312 | * required protocols (just Disk I/O in our case, Block I/O is only looked
|
---|
| 313 | * at to get the MediaId field), and lets the FSW core mount the file system.
|
---|
| 314 | * If successful, an EFI Simple File System protocol is exported on the
|
---|
| 315 | * device handle.
|
---|
| 316 | */
|
---|
| 317 |
|
---|
| 318 | EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
---|
| 319 | IN EFI_HANDLE ControllerHandle,
|
---|
| 320 | IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath)
|
---|
| 321 | {
|
---|
| 322 | EFI_STATUS Status;
|
---|
| 323 | EFI_BLOCK_IO *BlockIo;
|
---|
| 324 | EFI_DISK_IO *DiskIo;
|
---|
| 325 | FSW_VOLUME_DATA *Volume;
|
---|
| 326 |
|
---|
| 327 | // open consumed protocols
|
---|
| 328 | Status = BS->OpenProtocol(ControllerHandle,
|
---|
| 329 | &PROTO_NAME(BlockIoProtocol),
|
---|
| 330 | (VOID **) &BlockIo,
|
---|
| 331 | This->DriverBindingHandle,
|
---|
| 332 | ControllerHandle,
|
---|
| 333 | EFI_OPEN_PROTOCOL_GET_PROTOCOL); // NOTE: we only want to look at the MediaId
|
---|
| 334 | if (EFI_ERROR(Status)) {
|
---|
| 335 | return Status;
|
---|
| 336 | }
|
---|
| 337 |
|
---|
| 338 | Status = BS->OpenProtocol(ControllerHandle,
|
---|
| 339 | &PROTO_NAME(DiskIoProtocol),
|
---|
| 340 | (VOID **) &DiskIo,
|
---|
| 341 | This->DriverBindingHandle,
|
---|
| 342 | ControllerHandle,
|
---|
| 343 | EFI_OPEN_PROTOCOL_BY_DRIVER);
|
---|
| 344 | if (EFI_ERROR(Status)) {
|
---|
| 345 | return Status;
|
---|
| 346 | }
|
---|
| 347 |
|
---|
| 348 | // allocate volume structure
|
---|
| 349 | Volume = AllocateZeroPool(sizeof(FSW_VOLUME_DATA));
|
---|
| 350 | Status = fsw_efi_ReMount(Volume, ControllerHandle, DiskIo, BlockIo);
|
---|
| 351 |
|
---|
| 352 | // on errors, close the opened protocols
|
---|
| 353 | if (EFI_ERROR(Status)) {
|
---|
| 354 | if (Volume->vol != NULL)
|
---|
| 355 | fsw_unmount(Volume->vol);
|
---|
| 356 | FreePool(Volume);
|
---|
| 357 |
|
---|
| 358 | #if 0
|
---|
| 359 | if (Status == EFI_MEDIA_CHANGED)
|
---|
| 360 | Status = fsw_efi_ReMount(Volume, ControllerHandle, DiskIo, BlockIo);
|
---|
| 361 | else
|
---|
| 362 | #endif
|
---|
| 363 | BS->CloseProtocol(ControllerHandle,
|
---|
| 364 | &PROTO_NAME(DiskIoProtocol),
|
---|
| 365 | This->DriverBindingHandle,
|
---|
| 366 | ControllerHandle);
|
---|
| 367 | }
|
---|
| 368 |
|
---|
| 369 | return Status;
|
---|
| 370 | }
|
---|
| 371 |
|
---|
| 372 | /**
|
---|
| 373 | * Driver Binding EFI protocol, Stop function. This function is called by EFI
|
---|
| 374 | * to stop the driver on the given device. This translates to an unmount
|
---|
| 375 | * call for the FSW core.
|
---|
| 376 | *
|
---|
| 377 | * We assume that all file handles on the volume have been closed before
|
---|
| 378 | * the driver is stopped. At least with the EFI shell, that is actually the
|
---|
| 379 | * case; it closes all file handles between commands.
|
---|
| 380 | */
|
---|
| 381 |
|
---|
| 382 | EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
---|
| 383 | IN EFI_HANDLE ControllerHandle,
|
---|
| 384 | IN UINTN NumberOfChildren,
|
---|
| 385 | IN EFI_HANDLE *ChildHandleBuffer)
|
---|
| 386 | {
|
---|
| 387 | EFI_STATUS Status;
|
---|
| 388 | EFI_FILE_IO_INTERFACE *FileSystem;
|
---|
| 389 | FSW_VOLUME_DATA *Volume;
|
---|
| 390 |
|
---|
| 391 | #if DEBUG_LEVEL
|
---|
| 392 | Print(L"fsw_efi_DriverBinding_Stop\n");
|
---|
| 393 | #endif
|
---|
| 394 |
|
---|
| 395 | // get the installed SimpleFileSystem interface
|
---|
| 396 | Status = BS->OpenProtocol(ControllerHandle,
|
---|
| 397 | &PROTO_NAME(SimpleFileSystemProtocol),
|
---|
| 398 | (VOID **) &FileSystem,
|
---|
| 399 | This->DriverBindingHandle,
|
---|
| 400 | ControllerHandle,
|
---|
| 401 | EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
---|
| 402 | if (EFI_ERROR(Status))
|
---|
| 403 | return EFI_UNSUPPORTED;
|
---|
| 404 |
|
---|
| 405 | // get private data structure
|
---|
| 406 | Volume = FSW_VOLUME_FROM_FILE_SYSTEM(FileSystem);
|
---|
| 407 |
|
---|
| 408 | // uninstall Simple File System protocol
|
---|
| 409 | Status = BS->UninstallMultipleProtocolInterfaces(ControllerHandle,
|
---|
| 410 | &PROTO_NAME(SimpleFileSystemProtocol), &Volume->FileSystem,
|
---|
| 411 | NULL);
|
---|
| 412 | if (EFI_ERROR(Status)) {
|
---|
| 413 | Print(L"Fsw ERROR: UninstallMultipleProtocolInterfaces returned %x\n", Status);
|
---|
| 414 | return Status;
|
---|
| 415 | }
|
---|
| 416 | #if DEBUG_LEVEL
|
---|
| 417 | Print(L"fsw_efi_DriverBinding_Stop: protocol uninstalled successfully\n");
|
---|
| 418 | #endif
|
---|
| 419 |
|
---|
| 420 | // release private data structure
|
---|
| 421 | if (Volume->vol != NULL)
|
---|
| 422 | fsw_unmount(Volume->vol);
|
---|
| 423 | FreePool(Volume);
|
---|
| 424 |
|
---|
| 425 | // close the consumed protocols
|
---|
| 426 | Status = BS->CloseProtocol(ControllerHandle,
|
---|
| 427 | &PROTO_NAME(DiskIoProtocol),
|
---|
| 428 | This->DriverBindingHandle,
|
---|
| 429 | ControllerHandle);
|
---|
| 430 |
|
---|
| 431 | return Status;
|
---|
| 432 | }
|
---|
| 433 |
|
---|
| 434 | /**
|
---|
| 435 | * Component Name EFI protocol, GetDriverName function. Used by the EFI
|
---|
| 436 | * environment to inquire the name of this driver. The name returned is
|
---|
| 437 | * based on the file system type actually used in compilation.
|
---|
| 438 | */
|
---|
| 439 |
|
---|
| 440 | EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
---|
| 441 | IN CHAR8 *Language,
|
---|
| 442 | OUT CHAR16 **DriverName)
|
---|
| 443 | {
|
---|
| 444 | if (Language == NULL || DriverName == NULL)
|
---|
| 445 | return EFI_INVALID_PARAMETER;
|
---|
| 446 | #if 0
|
---|
| 447 |
|
---|
| 448 | if (Language[0] == 'e' && Language[1] == 'n' && Language[2] == 'g' && Language[3] == 0) {
|
---|
| 449 | *DriverName = FSW_EFI_DRIVER_NAME(FSTYPE);
|
---|
| 450 | return EFI_SUCCESS;
|
---|
| 451 | }
|
---|
| 452 | #endif
|
---|
| 453 | return EFI_UNSUPPORTED;
|
---|
| 454 | }
|
---|
| 455 |
|
---|
| 456 | /**
|
---|
| 457 | * Component Name EFI protocol, GetControllerName function. Not implemented
|
---|
| 458 | * because this is not a "bus" driver in the sense of the EFI Driver Model.
|
---|
| 459 | */
|
---|
| 460 |
|
---|
| 461 | EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
---|
| 462 | IN EFI_HANDLE ControllerHandle,
|
---|
| 463 | IN EFI_HANDLE ChildHandle OPTIONAL,
|
---|
| 464 | IN CHAR8 *Language,
|
---|
| 465 | OUT CHAR16 **ControllerName)
|
---|
| 466 | {
|
---|
| 467 | return EFI_UNSUPPORTED;
|
---|
| 468 | }
|
---|
| 469 |
|
---|
| 470 | /**
|
---|
| 471 | * FSW interface function for block size changes. This function is called by the FSW core
|
---|
| 472 | * when the file system driver changes the block sizes for the volume.
|
---|
| 473 | */
|
---|
| 474 |
|
---|
| 475 | void fsw_efi_change_blocksize(struct fsw_volume *vol,
|
---|
| 476 | fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
|
---|
| 477 | fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize)
|
---|
| 478 | {
|
---|
| 479 | // nothing to do
|
---|
| 480 | }
|
---|
| 481 |
|
---|
| 482 | /**
|
---|
| 483 | * FSW interface function to read data blocks. This function is called by the FSW core
|
---|
| 484 | * to read a block of data from the device. The buffer is allocated by the core code.
|
---|
| 485 | */
|
---|
| 486 |
|
---|
| 487 | fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer)
|
---|
| 488 | {
|
---|
| 489 | EFI_STATUS Status;
|
---|
| 490 | FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)vol->host_data;
|
---|
| 491 |
|
---|
| 492 | FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_efi_read_block: %d (%d)\n"), phys_bno, vol->phys_blocksize));
|
---|
| 493 |
|
---|
| 494 | // read from disk
|
---|
| 495 | Status = Volume->DiskIo->ReadDisk(Volume->DiskIo, Volume->MediaId,
|
---|
| 496 | (UINT64)phys_bno * vol->phys_blocksize,
|
---|
| 497 | vol->phys_blocksize,
|
---|
| 498 | buffer);
|
---|
| 499 | Volume->LastIOStatus = Status;
|
---|
| 500 | if (EFI_ERROR(Status))
|
---|
| 501 | return FSW_IO_ERROR;
|
---|
| 502 | return FSW_SUCCESS;
|
---|
| 503 | }
|
---|
| 504 |
|
---|
| 505 | /**
|
---|
| 506 | * Map FSW status codes to EFI status codes. The FSW_IO_ERROR code is only produced
|
---|
| 507 | * by fsw_efi_read_block, so we map it back to the EFI status code remembered from
|
---|
| 508 | * the last I/O operation.
|
---|
| 509 | */
|
---|
| 510 |
|
---|
| 511 | EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume)
|
---|
| 512 | {
|
---|
| 513 | switch (fsw_status) {
|
---|
| 514 | case FSW_SUCCESS:
|
---|
| 515 | return EFI_SUCCESS;
|
---|
| 516 | case FSW_OUT_OF_MEMORY:
|
---|
| 517 | return EFI_VOLUME_CORRUPTED;
|
---|
| 518 | case FSW_IO_ERROR:
|
---|
| 519 | return Volume->LastIOStatus;
|
---|
| 520 | case FSW_UNSUPPORTED:
|
---|
| 521 | return EFI_UNSUPPORTED;
|
---|
| 522 | case FSW_NOT_FOUND:
|
---|
| 523 | return EFI_NOT_FOUND;
|
---|
| 524 | case FSW_VOLUME_CORRUPTED:
|
---|
| 525 | return EFI_VOLUME_CORRUPTED;
|
---|
| 526 | default:
|
---|
| 527 | return EFI_DEVICE_ERROR;
|
---|
| 528 | }
|
---|
| 529 | }
|
---|
| 530 |
|
---|
| 531 | /**
|
---|
| 532 | * File System EFI protocol, OpenVolume function. Creates a file handle for
|
---|
| 533 | * the root directory and returns it. Note that this function may be called
|
---|
| 534 | * multiple times and returns a new file handle each time. Each returned
|
---|
| 535 | * handle is closed by the client using it.
|
---|
| 536 | */
|
---|
| 537 |
|
---|
| 538 | EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
|
---|
| 539 | OUT EFI_FILE **Root)
|
---|
| 540 | {
|
---|
| 541 | EFI_STATUS Status;
|
---|
| 542 | FSW_VOLUME_DATA *Volume = FSW_VOLUME_FROM_FILE_SYSTEM(This);
|
---|
| 543 |
|
---|
| 544 | #if DEBUG_LEVEL
|
---|
| 545 | Print(L"fsw_efi_FileSystem_OpenVolume\n");
|
---|
| 546 | #endif
|
---|
| 547 |
|
---|
| 548 | Status = fsw_efi_dnode_to_FileHandle(Volume->vol->root, Root);
|
---|
| 549 |
|
---|
| 550 | return Status;
|
---|
| 551 | }
|
---|
| 552 |
|
---|
| 553 | /**
|
---|
| 554 | * File Handle EFI protocol, Open function. Dispatches the call
|
---|
| 555 | * based on the kind of file handle.
|
---|
| 556 | */
|
---|
| 557 |
|
---|
| 558 | EFI_STATUS EFIAPI fsw_efi_FileHandle_Open(IN EFI_FILE *This,
|
---|
| 559 | OUT EFI_FILE **NewHandle,
|
---|
| 560 | IN CHAR16 *FileName,
|
---|
| 561 | IN UINT64 OpenMode,
|
---|
| 562 | IN UINT64 Attributes)
|
---|
| 563 | {
|
---|
| 564 | FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
|
---|
| 565 |
|
---|
| 566 | if (File->Type == FSW_EFI_FILE_TYPE_DIR)
|
---|
| 567 | return fsw_efi_dir_open(File, NewHandle, FileName, OpenMode, Attributes);
|
---|
| 568 | // not supported for regular files
|
---|
| 569 | return EFI_UNSUPPORTED;
|
---|
| 570 | }
|
---|
| 571 |
|
---|
| 572 | /**
|
---|
| 573 | * File Handle EFI protocol, Close function. Closes the FSW shandle
|
---|
| 574 | * and frees the memory used for the structure.
|
---|
| 575 | */
|
---|
| 576 |
|
---|
| 577 | EFI_STATUS EFIAPI fsw_efi_FileHandle_Close(IN EFI_FILE *This)
|
---|
| 578 | {
|
---|
| 579 | FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
|
---|
| 580 |
|
---|
| 581 | #if DEBUG_LEVEL
|
---|
| 582 | Print(L"fsw_efi_FileHandle_Close\n");
|
---|
| 583 | #endif
|
---|
| 584 |
|
---|
| 585 | fsw_shandle_close(&File->shand);
|
---|
| 586 | FreePool(File);
|
---|
| 587 |
|
---|
| 588 | return EFI_SUCCESS;
|
---|
| 589 | }
|
---|
| 590 |
|
---|
| 591 | /**
|
---|
| 592 | * File Handle EFI protocol, Delete function. Calls through to Close
|
---|
| 593 | * and returns a warning because this driver is read-only.
|
---|
| 594 | */
|
---|
| 595 |
|
---|
| 596 | EFI_STATUS EFIAPI fsw_efi_FileHandle_Delete(IN EFI_FILE *This)
|
---|
| 597 | {
|
---|
| 598 | EFI_STATUS Status;
|
---|
| 599 |
|
---|
| 600 | Status = This->Close(This);
|
---|
| 601 | if (Status == EFI_SUCCESS) {
|
---|
| 602 | // this driver is read-only
|
---|
| 603 | Status = EFI_WARN_DELETE_FAILURE;
|
---|
| 604 | }
|
---|
| 605 |
|
---|
| 606 | return Status;
|
---|
| 607 | }
|
---|
| 608 |
|
---|
| 609 | /**
|
---|
| 610 | * File Handle EFI protocol, Read function. Dispatches the call
|
---|
| 611 | * based on the kind of file handle.
|
---|
| 612 | */
|
---|
| 613 |
|
---|
| 614 | EFI_STATUS EFIAPI fsw_efi_FileHandle_Read(IN EFI_FILE *This,
|
---|
| 615 | IN OUT UINTN *BufferSize,
|
---|
| 616 | OUT VOID *Buffer)
|
---|
| 617 | {
|
---|
| 618 | FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
|
---|
| 619 |
|
---|
| 620 | if (File->Type == FSW_EFI_FILE_TYPE_FILE)
|
---|
| 621 | return fsw_efi_file_read(File, BufferSize, Buffer);
|
---|
| 622 | else if (File->Type == FSW_EFI_FILE_TYPE_DIR)
|
---|
| 623 | return fsw_efi_dir_read(File, BufferSize, Buffer);
|
---|
| 624 | return EFI_UNSUPPORTED;
|
---|
| 625 | }
|
---|
| 626 |
|
---|
| 627 | /**
|
---|
| 628 | * File Handle EFI protocol, Write function. Returns unsupported status
|
---|
| 629 | * because this driver is read-only.
|
---|
| 630 | */
|
---|
| 631 |
|
---|
| 632 | EFI_STATUS EFIAPI fsw_efi_FileHandle_Write(IN EFI_FILE *This,
|
---|
| 633 | IN OUT UINTN *BufferSize,
|
---|
| 634 | IN VOID *Buffer)
|
---|
| 635 | {
|
---|
| 636 | // this driver is read-only
|
---|
| 637 | return EFI_WRITE_PROTECTED;
|
---|
| 638 | }
|
---|
| 639 |
|
---|
| 640 | /**
|
---|
| 641 | * File Handle EFI protocol, GetPosition function. Dispatches the call
|
---|
| 642 | * based on the kind of file handle.
|
---|
| 643 | */
|
---|
| 644 |
|
---|
| 645 | EFI_STATUS EFIAPI fsw_efi_FileHandle_GetPosition(IN EFI_FILE *This,
|
---|
| 646 | OUT UINT64 *Position)
|
---|
| 647 | {
|
---|
| 648 | FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
|
---|
| 649 |
|
---|
| 650 | if (File->Type == FSW_EFI_FILE_TYPE_FILE)
|
---|
| 651 | return fsw_efi_file_getpos(File, Position);
|
---|
| 652 | // not defined for directories
|
---|
| 653 | return EFI_UNSUPPORTED;
|
---|
| 654 | }
|
---|
| 655 |
|
---|
| 656 | /**
|
---|
| 657 | * File Handle EFI protocol, SetPosition function. Dispatches the call
|
---|
| 658 | * based on the kind of file handle.
|
---|
| 659 | */
|
---|
| 660 |
|
---|
| 661 | EFI_STATUS EFIAPI fsw_efi_FileHandle_SetPosition(IN EFI_FILE *This,
|
---|
| 662 | IN UINT64 Position)
|
---|
| 663 | {
|
---|
| 664 | FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
|
---|
| 665 |
|
---|
| 666 | if (File->Type == FSW_EFI_FILE_TYPE_FILE)
|
---|
| 667 | return fsw_efi_file_setpos(File, Position);
|
---|
| 668 | else if (File->Type == FSW_EFI_FILE_TYPE_DIR)
|
---|
| 669 | return fsw_efi_dir_setpos(File, Position);
|
---|
| 670 | return EFI_UNSUPPORTED;
|
---|
| 671 | }
|
---|
| 672 |
|
---|
| 673 | /**
|
---|
| 674 | * File Handle EFI protocol, GetInfo function. Dispatches to the common
|
---|
| 675 | * function implementing this.
|
---|
| 676 | */
|
---|
| 677 |
|
---|
| 678 | EFI_STATUS EFIAPI fsw_efi_FileHandle_GetInfo(IN EFI_FILE *This,
|
---|
| 679 | IN EFI_GUID *InformationType,
|
---|
| 680 | IN OUT UINTN *BufferSize,
|
---|
| 681 | OUT VOID *Buffer)
|
---|
| 682 | {
|
---|
| 683 | FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
|
---|
| 684 |
|
---|
| 685 | return fsw_efi_dnode_getinfo(File, InformationType, BufferSize, Buffer);
|
---|
| 686 | }
|
---|
| 687 |
|
---|
| 688 | /**
|
---|
| 689 | * File Handle EFI protocol, SetInfo function. Returns unsupported status
|
---|
| 690 | * because this driver is read-only.
|
---|
| 691 | */
|
---|
| 692 |
|
---|
| 693 | EFI_STATUS EFIAPI fsw_efi_FileHandle_SetInfo(IN EFI_FILE *This,
|
---|
| 694 | IN EFI_GUID *InformationType,
|
---|
| 695 | IN UINTN BufferSize,
|
---|
| 696 | IN VOID *Buffer)
|
---|
| 697 | {
|
---|
| 698 | // this driver is read-only
|
---|
| 699 | return EFI_WRITE_PROTECTED;
|
---|
| 700 | }
|
---|
| 701 |
|
---|
| 702 | /**
|
---|
| 703 | * File Handle EFI protocol, Flush function. Returns unsupported status
|
---|
| 704 | * because this driver is read-only.
|
---|
| 705 | */
|
---|
| 706 |
|
---|
| 707 | EFI_STATUS EFIAPI fsw_efi_FileHandle_Flush(IN EFI_FILE *This)
|
---|
| 708 | {
|
---|
| 709 | // this driver is read-only
|
---|
| 710 | return EFI_WRITE_PROTECTED;
|
---|
| 711 | }
|
---|
| 712 |
|
---|
| 713 | /**
|
---|
| 714 | * Set up a file handle for a dnode. This function allocates a data structure
|
---|
| 715 | * for a file handle, opens a FSW shandle and populates the EFI_FILE structure
|
---|
| 716 | * with the interface functions.
|
---|
| 717 | */
|
---|
| 718 |
|
---|
| 719 | EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno,
|
---|
| 720 | OUT EFI_FILE **NewFileHandle)
|
---|
| 721 | {
|
---|
| 722 | EFI_STATUS Status;
|
---|
| 723 | FSW_FILE_DATA *File;
|
---|
| 724 |
|
---|
| 725 | // make sure the dnode has complete info
|
---|
| 726 | Status = fsw_efi_map_status(fsw_dnode_fill(dno), (FSW_VOLUME_DATA *)dno->vol->host_data);
|
---|
| 727 | if (EFI_ERROR(Status))
|
---|
| 728 | return Status;
|
---|
| 729 |
|
---|
| 730 | // check type
|
---|
| 731 | if (dno->type != FSW_DNODE_TYPE_FILE && dno->type != FSW_DNODE_TYPE_DIR)
|
---|
| 732 | return EFI_UNSUPPORTED;
|
---|
| 733 |
|
---|
| 734 | // allocate file structure
|
---|
| 735 | File = AllocateZeroPool(sizeof(FSW_FILE_DATA));
|
---|
| 736 | File->Signature = FSW_FILE_DATA_SIGNATURE;
|
---|
| 737 | if (dno->type == FSW_DNODE_TYPE_FILE)
|
---|
| 738 | File->Type = FSW_EFI_FILE_TYPE_FILE;
|
---|
| 739 | else if (dno->type == FSW_DNODE_TYPE_DIR)
|
---|
| 740 | File->Type = FSW_EFI_FILE_TYPE_DIR;
|
---|
| 741 |
|
---|
| 742 | // open shandle
|
---|
| 743 | Status = fsw_efi_map_status(fsw_shandle_open(dno, &File->shand),
|
---|
| 744 | (FSW_VOLUME_DATA *)dno->vol->host_data);
|
---|
| 745 | if (EFI_ERROR(Status)) {
|
---|
| 746 | FreePool(File);
|
---|
| 747 | return Status;
|
---|
| 748 | }
|
---|
| 749 |
|
---|
| 750 | // populate the file handle
|
---|
| 751 | File->FileHandle.Revision = EFI_FILE_HANDLE_REVISION;
|
---|
| 752 | File->FileHandle.Open = fsw_efi_FileHandle_Open;
|
---|
| 753 | File->FileHandle.Close = fsw_efi_FileHandle_Close;
|
---|
| 754 | File->FileHandle.Delete = fsw_efi_FileHandle_Delete;
|
---|
| 755 | File->FileHandle.Read = fsw_efi_FileHandle_Read;
|
---|
| 756 | File->FileHandle.Write = fsw_efi_FileHandle_Write;
|
---|
| 757 | File->FileHandle.GetPosition = fsw_efi_FileHandle_GetPosition;
|
---|
| 758 | File->FileHandle.SetPosition = fsw_efi_FileHandle_SetPosition;
|
---|
| 759 | File->FileHandle.GetInfo = fsw_efi_FileHandle_GetInfo;
|
---|
| 760 | File->FileHandle.SetInfo = fsw_efi_FileHandle_SetInfo;
|
---|
| 761 | File->FileHandle.Flush = fsw_efi_FileHandle_Flush;
|
---|
| 762 |
|
---|
| 763 | *NewFileHandle = &File->FileHandle;
|
---|
| 764 | return EFI_SUCCESS;
|
---|
| 765 | }
|
---|
| 766 |
|
---|
| 767 | /**
|
---|
| 768 | * Data read function for regular files. Calls through to fsw_shandle_read.
|
---|
| 769 | */
|
---|
| 770 |
|
---|
| 771 | EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File,
|
---|
| 772 | IN OUT UINTN *BufferSize,
|
---|
| 773 | OUT VOID *Buffer)
|
---|
| 774 | {
|
---|
| 775 | EFI_STATUS Status;
|
---|
| 776 | fsw_u32 buffer_size;
|
---|
| 777 |
|
---|
| 778 | #if DEBUG_LEVEL
|
---|
| 779 | Print(L"fsw_efi_file_read %d bytes\n", *BufferSize);
|
---|
| 780 | #endif
|
---|
| 781 |
|
---|
| 782 | buffer_size = (fsw_u32)*BufferSize;
|
---|
| 783 | if (buffer_size != *BufferSize)
|
---|
| 784 | buffer_size = ~(fsw_u32)0;
|
---|
| 785 | Status = fsw_efi_map_status(fsw_shandle_read(&File->shand, &buffer_size, Buffer),
|
---|
| 786 | (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data);
|
---|
| 787 | *BufferSize = buffer_size;
|
---|
| 788 |
|
---|
| 789 | return Status;
|
---|
| 790 | }
|
---|
| 791 |
|
---|
| 792 | /**
|
---|
| 793 | * Get file position for regular files.
|
---|
| 794 | */
|
---|
| 795 |
|
---|
| 796 | EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File,
|
---|
| 797 | OUT UINT64 *Position)
|
---|
| 798 | {
|
---|
| 799 | *Position = File->shand.pos;
|
---|
| 800 | return EFI_SUCCESS;
|
---|
| 801 | }
|
---|
| 802 |
|
---|
| 803 | /**
|
---|
| 804 | * Set file position for regular files. EFI specifies the all-ones value
|
---|
| 805 | * to be a special value for the end of the file.
|
---|
| 806 | */
|
---|
| 807 |
|
---|
| 808 | EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File,
|
---|
| 809 | IN UINT64 Position)
|
---|
| 810 | {
|
---|
| 811 | if (Position == 0xFFFFFFFFFFFFFFFFULL)
|
---|
| 812 | File->shand.pos = File->shand.dnode->size;
|
---|
| 813 | else
|
---|
| 814 | File->shand.pos = Position;
|
---|
| 815 | return EFI_SUCCESS;
|
---|
| 816 | }
|
---|
| 817 |
|
---|
| 818 | /**
|
---|
| 819 | * Open function used to open new file handles relative to a directory.
|
---|
| 820 | * In EFI, the "open file" function is implemented by directory file handles
|
---|
| 821 | * and is passed a relative or volume-absolute path to the file or directory
|
---|
| 822 | * to open. We use fsw_dnode_lookup_path to find the node plus an additional
|
---|
| 823 | * call to fsw_dnode_resolve because EFI has no concept of symbolic links.
|
---|
| 824 | */
|
---|
| 825 |
|
---|
| 826 | EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
|
---|
| 827 | OUT EFI_FILE **NewHandle,
|
---|
| 828 | IN CHAR16 *FileName,
|
---|
| 829 | IN UINT64 OpenMode,
|
---|
| 830 | IN UINT64 Attributes)
|
---|
| 831 | {
|
---|
| 832 | EFI_STATUS Status;
|
---|
| 833 | FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
|
---|
| 834 | struct fsw_dnode *dno;
|
---|
| 835 | struct fsw_dnode *target_dno;
|
---|
| 836 | struct fsw_string lookup_path;
|
---|
| 837 |
|
---|
| 838 | #if DEBUG_LEVEL
|
---|
| 839 | Print(L"fsw_efi_dir_open: '%s'\n", FileName);
|
---|
| 840 | #endif
|
---|
| 841 |
|
---|
| 842 | if (OpenMode != EFI_FILE_MODE_READ)
|
---|
| 843 | return EFI_WRITE_PROTECTED;
|
---|
| 844 |
|
---|
| 845 | lookup_path.type = FSW_STRING_TYPE_UTF16;
|
---|
| 846 | lookup_path.len = (int)StrLen(FileName);
|
---|
| 847 | lookup_path.size = lookup_path.len * sizeof(fsw_u16);
|
---|
| 848 | lookup_path.data = FileName;
|
---|
| 849 |
|
---|
| 850 | // resolve the path (symlinks along the way are automatically resolved)
|
---|
| 851 | Status = fsw_efi_map_status(fsw_dnode_lookup_path(File->shand.dnode, &lookup_path, '\\', &dno),
|
---|
| 852 | Volume);
|
---|
| 853 | if (EFI_ERROR(Status))
|
---|
| 854 | return Status;
|
---|
| 855 |
|
---|
| 856 | // if the final node is a symlink, also resolve it
|
---|
| 857 | Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno),
|
---|
| 858 | Volume);
|
---|
| 859 | fsw_dnode_release(dno);
|
---|
| 860 | if (EFI_ERROR(Status))
|
---|
| 861 | return Status;
|
---|
| 862 | dno = target_dno;
|
---|
| 863 |
|
---|
| 864 | // make a new EFI handle for the target dnode
|
---|
| 865 | Status = fsw_efi_dnode_to_FileHandle(dno, NewHandle);
|
---|
| 866 | fsw_dnode_release(dno);
|
---|
| 867 | return Status;
|
---|
| 868 | }
|
---|
| 869 |
|
---|
| 870 | /**
|
---|
| 871 | * Read function for directories. A file handle read on a directory retrieves
|
---|
| 872 | * the next directory entry.
|
---|
| 873 | */
|
---|
| 874 |
|
---|
| 875 | EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
|
---|
| 876 | IN OUT UINTN *BufferSize,
|
---|
| 877 | OUT VOID *Buffer)
|
---|
| 878 | {
|
---|
| 879 | EFI_STATUS Status;
|
---|
| 880 | FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
|
---|
| 881 | struct fsw_dnode *dno;
|
---|
| 882 |
|
---|
| 883 | #if DEBUG_LEVEL
|
---|
| 884 | Print(L"fsw_efi_dir_read...\n");
|
---|
| 885 | #endif
|
---|
| 886 |
|
---|
| 887 | // read the next entry
|
---|
| 888 | Status = fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno),
|
---|
| 889 | Volume);
|
---|
| 890 | if (Status == EFI_NOT_FOUND) {
|
---|
| 891 | // end of directory
|
---|
| 892 | *BufferSize = 0;
|
---|
| 893 | #if DEBUG_LEVEL
|
---|
| 894 | Print(L"...no more entries\n");
|
---|
| 895 | #endif
|
---|
| 896 | return EFI_SUCCESS;
|
---|
| 897 | }
|
---|
| 898 | if (EFI_ERROR(Status))
|
---|
| 899 | return Status;
|
---|
| 900 |
|
---|
| 901 | // get info into buffer
|
---|
| 902 | Status = fsw_efi_dnode_fill_FileInfo(Volume, dno, BufferSize, Buffer);
|
---|
| 903 | fsw_dnode_release(dno);
|
---|
| 904 | return Status;
|
---|
| 905 | }
|
---|
| 906 |
|
---|
| 907 | /**
|
---|
| 908 | * Set file position for directories. The only allowed set position operation
|
---|
| 909 | * for directories is to rewind the directory completely by setting the
|
---|
| 910 | * position to zero.
|
---|
| 911 | */
|
---|
| 912 |
|
---|
| 913 | EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File,
|
---|
| 914 | IN UINT64 Position)
|
---|
| 915 | {
|
---|
| 916 | if (Position == 0) {
|
---|
| 917 | File->shand.pos = 0;
|
---|
| 918 | return EFI_SUCCESS;
|
---|
| 919 | } else {
|
---|
| 920 | // directories can only rewind to the start
|
---|
| 921 | return EFI_UNSUPPORTED;
|
---|
| 922 | }
|
---|
| 923 | }
|
---|
| 924 |
|
---|
| 925 | /**
|
---|
| 926 | * Get file or volume information. This function implements the GetInfo call
|
---|
| 927 | * for all file handles. Control is dispatched according to the type of information
|
---|
| 928 | * requested by the caller.
|
---|
| 929 | */
|
---|
| 930 |
|
---|
| 931 | EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File,
|
---|
| 932 | IN EFI_GUID *InformationType,
|
---|
| 933 | IN OUT UINTN *BufferSize,
|
---|
| 934 | OUT VOID *Buffer)
|
---|
| 935 | {
|
---|
| 936 | EFI_STATUS Status;
|
---|
| 937 | FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
|
---|
| 938 | EFI_FILE_SYSTEM_INFO *FSInfo;
|
---|
| 939 | UINTN RequiredSize;
|
---|
| 940 | struct fsw_volume_stat vsb;
|
---|
| 941 |
|
---|
| 942 | if (CompareGuid(InformationType, &GUID_NAME(FileInfo))) {
|
---|
| 943 | #if DEBUG_LEVEL
|
---|
| 944 | Print(L"fsw_efi_dnode_getinfo: FILE_INFO\n");
|
---|
| 945 | #endif
|
---|
| 946 |
|
---|
| 947 | Status = fsw_efi_dnode_fill_FileInfo(Volume, File->shand.dnode, BufferSize, Buffer);
|
---|
| 948 |
|
---|
[82512] | 949 | } else if (CompareGuid(InformationType, &GUID_NAME(FileSystemInfo))) {
|
---|
[48674] | 950 | #if DEBUG_LEVEL
|
---|
| 951 | Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_INFO\n");
|
---|
| 952 | #endif
|
---|
| 953 |
|
---|
| 954 | // check buffer size
|
---|
| 955 | RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + fsw_efi_strsize(&Volume->vol->label);
|
---|
| 956 | if (*BufferSize < RequiredSize) {
|
---|
| 957 | *BufferSize = RequiredSize;
|
---|
| 958 | return EFI_BUFFER_TOO_SMALL;
|
---|
| 959 | }
|
---|
| 960 |
|
---|
| 961 | // fill structure
|
---|
| 962 | FSInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
|
---|
| 963 | FSInfo->Size = RequiredSize;
|
---|
| 964 | FSInfo->ReadOnly = TRUE;
|
---|
| 965 | FSInfo->BlockSize = Volume->vol->log_blocksize;
|
---|
| 966 | fsw_efi_strcpy(FSInfo->VolumeLabel, &Volume->vol->label);
|
---|
| 967 |
|
---|
| 968 | // get the missing info from the fs driver
|
---|
| 969 | ZeroMem(&vsb, sizeof(struct fsw_volume_stat));
|
---|
| 970 | Status = fsw_efi_map_status(fsw_volume_stat(Volume->vol, &vsb), Volume);
|
---|
| 971 | if (EFI_ERROR(Status))
|
---|
| 972 | return Status;
|
---|
| 973 | FSInfo->VolumeSize = vsb.total_bytes;
|
---|
| 974 | FSInfo->FreeSpace = vsb.free_bytes;
|
---|
| 975 |
|
---|
| 976 | // prepare for return
|
---|
| 977 | *BufferSize = RequiredSize;
|
---|
| 978 | Status = EFI_SUCCESS;
|
---|
| 979 |
|
---|
| 980 | } else if (CompareGuid(InformationType, &GUID_NAME(FileSystemVolumeLabelInfoId))) {
|
---|
| 981 | #if DEBUG_LEVEL
|
---|
| 982 | Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_VOLUME_LABEL\n");
|
---|
| 983 | #endif
|
---|
| 984 |
|
---|
| 985 | // check buffer size
|
---|
| 986 | RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + fsw_efi_strsize(&Volume->vol->label);
|
---|
| 987 | if (*BufferSize < RequiredSize) {
|
---|
| 988 | *BufferSize = RequiredSize;
|
---|
| 989 | return EFI_BUFFER_TOO_SMALL;
|
---|
| 990 | }
|
---|
| 991 |
|
---|
| 992 | // copy volume label
|
---|
| 993 | fsw_efi_strcpy(((EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *)Buffer)->VolumeLabel, &Volume->vol->label);
|
---|
| 994 |
|
---|
| 995 | // prepare for return
|
---|
| 996 | *BufferSize = RequiredSize;
|
---|
| 997 | Status = EFI_SUCCESS;
|
---|
| 998 |
|
---|
[93492] | 999 | #ifdef VBOX
|
---|
[82508] | 1000 | } else if (CompareGuid(InformationType, &gVBoxFsBlessedFileInfoGuid)) {
|
---|
| 1001 |
|
---|
[93492] | 1002 | # if FSTYPE == hfs
|
---|
[82508] | 1003 | struct fsw_string StrBlessedFile;
|
---|
| 1004 |
|
---|
| 1005 | fsw_status_t rc = fsw_hfs_get_blessed_file(Volume->vol, &StrBlessedFile);
|
---|
| 1006 | if (!rc)
|
---|
| 1007 | {
|
---|
| 1008 | // check buffer size
|
---|
| 1009 | RequiredSize = SIZE_OF_VBOX_FS_BLESSED_FILE + fsw_efi_strsize(&StrBlessedFile);
|
---|
| 1010 | if (*BufferSize < RequiredSize) {
|
---|
| 1011 | *BufferSize = RequiredSize;
|
---|
| 1012 | return EFI_BUFFER_TOO_SMALL;
|
---|
| 1013 | }
|
---|
| 1014 |
|
---|
| 1015 | // copy volume label
|
---|
| 1016 | fsw_efi_strcpy(((VBOX_FS_BLESSED_FILE *)Buffer)->BlessedFile, &StrBlessedFile);
|
---|
| 1017 |
|
---|
| 1018 | // prepare for return
|
---|
| 1019 | *BufferSize = RequiredSize;
|
---|
| 1020 | Status = EFI_SUCCESS;
|
---|
| 1021 | }
|
---|
| 1022 | else
|
---|
[93492] | 1023 | # endif
|
---|
[82508] | 1024 | Status = EFI_UNSUPPORTED;
|
---|
| 1025 | #endif
|
---|
| 1026 |
|
---|
[48674] | 1027 | } else {
|
---|
| 1028 | Status = EFI_UNSUPPORTED;
|
---|
| 1029 | }
|
---|
| 1030 |
|
---|
| 1031 | return Status;
|
---|
| 1032 | }
|
---|
| 1033 |
|
---|
| 1034 | /**
|
---|
| 1035 | * Time mapping callback for the fsw_dnode_stat call. This function converts
|
---|
| 1036 | * a Posix style timestamp into an EFI_TIME structure and writes it to the
|
---|
| 1037 | * appropriate member of the EFI_FILE_INFO structure that we're filling.
|
---|
| 1038 | */
|
---|
| 1039 |
|
---|
| 1040 | static void fsw_efi_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time)
|
---|
| 1041 | {
|
---|
| 1042 | EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
|
---|
| 1043 |
|
---|
| 1044 | if (which == FSW_DNODE_STAT_CTIME)
|
---|
| 1045 | fsw_efi_decode_time(&FileInfo->CreateTime, posix_time);
|
---|
| 1046 | else if (which == FSW_DNODE_STAT_MTIME)
|
---|
| 1047 | fsw_efi_decode_time(&FileInfo->ModificationTime, posix_time);
|
---|
| 1048 | else if (which == FSW_DNODE_STAT_ATIME)
|
---|
| 1049 | fsw_efi_decode_time(&FileInfo->LastAccessTime, posix_time);
|
---|
| 1050 | }
|
---|
| 1051 |
|
---|
| 1052 | /**
|
---|
| 1053 | * Mode mapping callback for the fsw_dnode_stat call. This function looks at
|
---|
| 1054 | * the Posix mode passed by the file system driver and makes appropriate
|
---|
| 1055 | * adjustments to the EFI_FILE_INFO structure that we're filling.
|
---|
| 1056 | */
|
---|
| 1057 |
|
---|
| 1058 | static void fsw_efi_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode)
|
---|
| 1059 | {
|
---|
| 1060 | EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
|
---|
| 1061 |
|
---|
| 1062 | if ((posix_mode & S_IWUSR) == 0)
|
---|
| 1063 | FileInfo->Attribute |= EFI_FILE_READ_ONLY;
|
---|
| 1064 | }
|
---|
| 1065 |
|
---|
| 1066 | /**
|
---|
| 1067 | * Common function to fill an EFI_FILE_INFO with information about a dnode.
|
---|
| 1068 | */
|
---|
| 1069 |
|
---|
| 1070 | EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
|
---|
| 1071 | IN struct fsw_dnode *dno,
|
---|
| 1072 | IN OUT UINTN *BufferSize,
|
---|
| 1073 | OUT VOID *Buffer)
|
---|
| 1074 | {
|
---|
| 1075 | EFI_STATUS Status;
|
---|
| 1076 | EFI_FILE_INFO *FileInfo;
|
---|
| 1077 | UINTN RequiredSize;
|
---|
[59146] | 1078 | struct fsw_dnode *target_dno;
|
---|
[48674] | 1079 | struct fsw_dnode_stat sb;
|
---|
| 1080 |
|
---|
| 1081 | // make sure the dnode has complete info
|
---|
| 1082 | Status = fsw_efi_map_status(fsw_dnode_fill(dno), Volume);
|
---|
| 1083 | if (EFI_ERROR(Status))
|
---|
| 1084 | return Status;
|
---|
| 1085 |
|
---|
[69429] | 1086 | /// @todo check/assert that the dno's name is in UTF16
|
---|
[48674] | 1087 |
|
---|
| 1088 | // check buffer size
|
---|
| 1089 | RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_efi_strsize(&dno->name);
|
---|
| 1090 | if (*BufferSize < RequiredSize) {
|
---|
[69429] | 1091 | /// @todo wind back the directory in this case
|
---|
[48674] | 1092 |
|
---|
| 1093 | #if DEBUG_LEVEL
|
---|
| 1094 | Print(L"...BUFFER TOO SMALL\n");
|
---|
| 1095 | #endif
|
---|
| 1096 | *BufferSize = RequiredSize;
|
---|
| 1097 | return EFI_BUFFER_TOO_SMALL;
|
---|
| 1098 | }
|
---|
| 1099 |
|
---|
| 1100 | // fill structure
|
---|
| 1101 | ZeroMem(Buffer, RequiredSize);
|
---|
| 1102 | FileInfo = (EFI_FILE_INFO *)Buffer;
|
---|
[59146] | 1103 |
|
---|
| 1104 | // must preserve the original file name
|
---|
| 1105 | fsw_efi_strcpy(FileInfo->FileName, &dno->name);
|
---|
| 1106 |
|
---|
| 1107 | // if the node is a symlink, also resolve it
|
---|
| 1108 | Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno), Volume);
|
---|
| 1109 | fsw_dnode_release(dno);
|
---|
| 1110 | if (EFI_ERROR(Status))
|
---|
| 1111 | return Status;
|
---|
| 1112 | dno = target_dno;
|
---|
| 1113 | // make sure the dnode has complete info again
|
---|
| 1114 | Status = fsw_efi_map_status(fsw_dnode_fill(dno), Volume);
|
---|
| 1115 | if (EFI_ERROR(Status))
|
---|
| 1116 | return Status;
|
---|
| 1117 |
|
---|
[48674] | 1118 | FileInfo->Size = RequiredSize;
|
---|
| 1119 | FileInfo->FileSize = dno->size;
|
---|
| 1120 | FileInfo->Attribute = 0;
|
---|
| 1121 | if (dno->type == FSW_DNODE_TYPE_DIR)
|
---|
| 1122 | FileInfo->Attribute |= EFI_FILE_DIRECTORY;
|
---|
| 1123 |
|
---|
| 1124 | // get the missing info from the fs driver
|
---|
| 1125 | ZeroMem(&sb, sizeof(struct fsw_dnode_stat));
|
---|
| 1126 | sb.store_time_posix = fsw_efi_store_time_posix;
|
---|
| 1127 | sb.store_attr_posix = fsw_efi_store_attr_posix;
|
---|
| 1128 | sb.host_data = FileInfo;
|
---|
| 1129 | Status = fsw_efi_map_status(fsw_dnode_stat(dno, &sb), Volume);
|
---|
| 1130 | if (EFI_ERROR(Status))
|
---|
| 1131 | return Status;
|
---|
| 1132 | FileInfo->PhysicalSize = sb.used_bytes;
|
---|
| 1133 |
|
---|
| 1134 | // prepare for return
|
---|
| 1135 | *BufferSize = RequiredSize;
|
---|
| 1136 | #if DEBUG_LEVEL
|
---|
| 1137 | Print(L"...returning '%s'\n", FileInfo->FileName);
|
---|
| 1138 | #endif
|
---|
| 1139 | return EFI_SUCCESS;
|
---|
| 1140 | }
|
---|
| 1141 |
|
---|
| 1142 | // EOF
|
---|