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 //#include <EfiCommonLib.h>
55 //#include <EfiDriverLib.h>
61 #error FSTYPE must be defined!
69 // MESSAGE_LOG_PROTOCOL *Msg = NULL;
72 #define DBG(x...) AsciiPrint(x)
74 #define DBG(x...) BootLog(x)
80 /** Helper macro for stringification. */
81 #define FSW_EFI_STRINGIFY(x) #x
82 /** Expands to the EFI driver name given the file system type name. */
83 #define FSW_EFI_DRIVER_NAME(t) L"rEFInd 0.4.2 " FSW_EFI_STRINGIFY(t) L" File System Driver"
85 // function prototypes
87 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
88 IN EFI_HANDLE ControllerHandle
,
89 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
);
90 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
91 IN EFI_HANDLE ControllerHandle
,
92 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
);
93 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
94 IN EFI_HANDLE ControllerHandle
,
95 IN UINTN NumberOfChildren
,
96 IN EFI_HANDLE
*ChildHandleBuffer
);
98 EFI_STATUS EFIAPI
fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
100 OUT CHAR16
**DriverName
);
101 EFI_STATUS EFIAPI
fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
102 IN EFI_HANDLE ControllerHandle
,
103 IN EFI_HANDLE ChildHandle OPTIONAL
,
105 OUT CHAR16
**ControllerName
);
107 void fsw_efi_change_blocksize(struct fsw_volume
*vol
,
108 fsw_u32 old_phys_blocksize
, fsw_u32 old_log_blocksize
,
109 fsw_u32 new_phys_blocksize
, fsw_u32 new_log_blocksize
);
110 fsw_status_t
fsw_efi_read_block(struct fsw_volume
*vol
, fsw_u32 phys_bno
, void *buffer
);
112 EFI_STATUS
fsw_efi_map_status(fsw_status_t fsw_status
, FSW_VOLUME_DATA
*Volume
);
114 EFI_STATUS EFIAPI
fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE
*This
,
115 OUT EFI_FILE
**Root
);
116 EFI_STATUS
fsw_efi_dnode_to_FileHandle(IN
struct fsw_dnode
*dno
,
117 OUT EFI_FILE
**NewFileHandle
);
119 EFI_STATUS
fsw_efi_file_read(IN FSW_FILE_DATA
*File
,
120 IN OUT UINTN
*BufferSize
,
122 EFI_STATUS
fsw_efi_file_getpos(IN FSW_FILE_DATA
*File
,
123 OUT UINT64
*Position
);
124 EFI_STATUS
fsw_efi_file_setpos(IN FSW_FILE_DATA
*File
,
127 EFI_STATUS
fsw_efi_dir_open(IN FSW_FILE_DATA
*File
,
128 OUT EFI_FILE
**NewHandle
,
131 IN UINT64 Attributes
);
132 EFI_STATUS
fsw_efi_dir_read(IN FSW_FILE_DATA
*File
,
133 IN OUT UINTN
*BufferSize
,
135 EFI_STATUS
fsw_efi_dir_setpos(IN FSW_FILE_DATA
*File
,
138 EFI_STATUS
fsw_efi_dnode_getinfo(IN FSW_FILE_DATA
*File
,
139 IN EFI_GUID
*InformationType
,
140 IN OUT UINTN
*BufferSize
,
142 EFI_STATUS
fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA
*Volume
,
143 IN
struct fsw_dnode
*dno
,
144 IN OUT UINTN
*BufferSize
,
148 * Interface structure for the EFI Driver Binding protocol.
151 EFI_DRIVER_BINDING_PROTOCOL fsw_efi_DriverBinding_table
= {
152 fsw_efi_DriverBinding_Supported
,
153 fsw_efi_DriverBinding_Start
,
154 fsw_efi_DriverBinding_Stop
,
161 * Interface structure for the EFI Component Name protocol.
164 EFI_COMPONENT_NAME_PROTOCOL fsw_efi_ComponentName_table
= {
165 fsw_efi_ComponentName_GetDriverName
,
166 fsw_efi_ComponentName_GetControllerName
,
171 * Dispatch table for our FSW host driver.
174 struct fsw_host_table fsw_efi_host_table
= {
175 FSW_STRING_TYPE_UTF16
,
177 fsw_efi_change_blocksize
,
181 extern struct fsw_fstype_table
FSW_FSTYPE_TABLE_NAME(FSTYPE
);
183 //#include "OverrideFunctions-kabyl.edk2.c.include"
186 * Image entry point. Installs the Driver Binding and Component Name protocols
187 * on the image's handle. Actually mounting a file system is initiated through
188 * the Driver Binding protocol at the firmware's request.
190 EFI_STATUS EFIAPI
fsw_efi_main(IN EFI_HANDLE ImageHandle
,
191 IN EFI_SYSTEM_TABLE
*SystemTable
)
196 InitializeLib(ImageHandle
, SystemTable
);
199 // complete Driver Binding protocol instance
200 fsw_efi_DriverBinding_table
.ImageHandle
= ImageHandle
;
201 fsw_efi_DriverBinding_table
.DriverBindingHandle
= ImageHandle
;
202 // install Driver Binding protocol
203 Status
= BS
->InstallProtocolInterface(&fsw_efi_DriverBinding_table
.DriverBindingHandle
,
204 &PROTO_NAME(DriverBindingProtocol
),
205 EFI_NATIVE_INTERFACE
,
206 &fsw_efi_DriverBinding_table
);
207 if (EFI_ERROR (Status
)) {
211 // install Component Name protocol
212 Status
= BS
->InstallProtocolInterface(&fsw_efi_DriverBinding_table
.DriverBindingHandle
,
213 &PROTO_NAME(ComponentNameProtocol
),
214 EFI_NATIVE_INTERFACE
,
215 &fsw_efi_ComponentName_table
);
216 if (EFI_ERROR (Status
)) {
220 // OverrideFunctions();
223 // Status = BS->LocateProtocol(&gMsgLogProtocolGuid, NULL, (VOID **) &Msg);
224 // if (!EFI_ERROR(Status) && (Msg != NULL)) {
225 // msgCursor = Msg->Cursor;
226 // BootLog("MsgLog installed into VBoxFs\n");
233 * Driver Binding EFI protocol, Supported function. This function is called by EFI
234 * to test if this driver can handle a certain device. Our implementation only checks
235 * if the device is a disk (i.e. that it supports the Block I/O and Disk I/O protocols)
236 * and implicitly checks if the disk is already in use by another driver.
239 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
240 IN EFI_HANDLE ControllerHandle
,
241 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
)
246 // we check for both DiskIO and BlockIO protocols
248 // first, open DiskIO
249 Status
= BS
->OpenProtocol(ControllerHandle
,
250 &PROTO_NAME(DiskIoProtocol
),
252 This
->DriverBindingHandle
,
254 EFI_OPEN_PROTOCOL_BY_DRIVER
);
255 if (EFI_ERROR(Status
))
258 // we were just checking, close it again
259 BS
->CloseProtocol(ControllerHandle
,
260 &PROTO_NAME(DiskIoProtocol
),
261 This
->DriverBindingHandle
,
264 // next, check BlockIO without actually opening it
265 Status
= BS
->OpenProtocol(ControllerHandle
,
266 &PROTO_NAME(BlockIoProtocol
),
268 This
->DriverBindingHandle
,
270 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
275 * Driver Binding EFI protocol, Start function. This function is called by EFI
276 * to start driving the given device. It is still possible at this point to
277 * return EFI_UNSUPPORTED, and in fact we will do so if the file system driver
278 * cannot find the superblock signature (or equivalent) that it expects.
280 * This function allocates memory for a per-volume structure, opens the
281 * required protocols (just Disk I/O in our case, Block I/O is only looked
282 * at to get the MediaId field), and lets the FSW core mount the file system.
283 * If successful, an EFI Simple File System protocol is exported on the
287 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
288 IN EFI_HANDLE ControllerHandle
,
289 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
)
292 EFI_BLOCK_IO
*BlockIo
;
294 FSW_VOLUME_DATA
*Volume
;
297 Print(L
"fsw_efi_DriverBinding_Start\n");
300 // open consumed protocols
301 Status
= BS
->OpenProtocol(ControllerHandle
,
302 &PROTO_NAME(BlockIoProtocol
),
304 This
->DriverBindingHandle
,
306 EFI_OPEN_PROTOCOL_GET_PROTOCOL
); // NOTE: we only want to look at the MediaId
307 if (EFI_ERROR(Status
)) {
308 // Print(L"Fsw ERROR: OpenProtocol(BlockIo) returned %x\n", Status);
312 Status
= BS
->OpenProtocol(ControllerHandle
,
313 &PROTO_NAME(DiskIoProtocol
),
315 This
->DriverBindingHandle
,
317 EFI_OPEN_PROTOCOL_BY_DRIVER
);
318 if (EFI_ERROR(Status
)) {
319 Print(L
"Fsw ERROR: OpenProtocol(DiskIo) returned %r\n", Status
);
323 // allocate volume structure
324 Volume
= AllocateZeroPool(sizeof(FSW_VOLUME_DATA
));
325 Volume
->Signature
= FSW_VOLUME_DATA_SIGNATURE
;
326 Volume
->Handle
= ControllerHandle
;
327 Volume
->DiskIo
= DiskIo
;
328 Volume
->MediaId
= BlockIo
->Media
->MediaId
;
329 Volume
->LastIOStatus
= EFI_SUCCESS
;
331 // mount the filesystem
332 Status
= fsw_efi_map_status(fsw_mount(Volume
, &fsw_efi_host_table
,
333 &FSW_FSTYPE_TABLE_NAME(FSTYPE
), &Volume
->vol
),
336 if (!EFI_ERROR(Status
)) {
337 // register the SimpleFileSystem protocol
338 Volume
->FileSystem
.Revision
= EFI_FILE_IO_INTERFACE_REVISION
;
339 Volume
->FileSystem
.OpenVolume
= fsw_efi_FileSystem_OpenVolume
;
340 Status
= BS
->InstallMultipleProtocolInterfaces(&ControllerHandle
,
341 &PROTO_NAME(SimpleFileSystemProtocol
),
344 if (EFI_ERROR(Status
)) {
345 // Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned %x\n", Status);
349 // on errors, close the opened protocols
350 if (EFI_ERROR(Status
)) {
351 if (Volume
->vol
!= NULL
)
352 fsw_unmount(Volume
->vol
);
355 BS
->CloseProtocol(ControllerHandle
,
356 &PROTO_NAME(DiskIoProtocol
),
357 This
->DriverBindingHandle
,
365 * Driver Binding EFI protocol, Stop function. This function is called by EFI
366 * to stop the driver on the given device. This translates to an unmount
367 * call for the FSW core.
369 * We assume that all file handles on the volume have been closed before
370 * the driver is stopped. At least with the EFI shell, that is actually the
371 * case; it closes all file handles between commands.
374 EFI_STATUS EFIAPI
fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
375 IN EFI_HANDLE ControllerHandle
,
376 IN UINTN NumberOfChildren
,
377 IN EFI_HANDLE
*ChildHandleBuffer
)
380 EFI_FILE_IO_INTERFACE
*FileSystem
;
381 FSW_VOLUME_DATA
*Volume
;
384 Print(L
"fsw_efi_DriverBinding_Stop\n");
387 // get the installed SimpleFileSystem interface
388 Status
= BS
->OpenProtocol(ControllerHandle
,
389 &PROTO_NAME(SimpleFileSystemProtocol
),
390 (VOID
**) &FileSystem
,
391 This
->DriverBindingHandle
,
393 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
394 if (EFI_ERROR(Status
))
395 return EFI_UNSUPPORTED
;
397 // get private data structure
398 Volume
= FSW_VOLUME_FROM_FILE_SYSTEM(FileSystem
);
400 // uninstall Simple File System protocol
401 Status
= BS
->UninstallMultipleProtocolInterfaces(ControllerHandle
,
402 &PROTO_NAME(SimpleFileSystemProtocol
), &Volume
->FileSystem
,
404 if (EFI_ERROR(Status
)) {
405 // Print(L"Fsw ERROR: UninstallMultipleProtocolInterfaces returned %x\n", Status);
409 Print(L
"fsw_efi_DriverBinding_Stop: protocol uninstalled successfully\n");
412 // release private data structure
413 if (Volume
->vol
!= NULL
)
414 fsw_unmount(Volume
->vol
);
417 // close the consumed protocols
418 Status
= BS
->CloseProtocol(ControllerHandle
,
419 &PROTO_NAME(DiskIoProtocol
),
420 This
->DriverBindingHandle
,
427 * Component Name EFI protocol, GetDriverName function. Used by the EFI
428 * environment to inquire the name of this driver. The name returned is
429 * based on the file system type actually used in compilation.
432 EFI_STATUS EFIAPI
fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
434 OUT CHAR16
**DriverName
)
436 if (Language
== NULL
|| DriverName
== NULL
)
437 return EFI_INVALID_PARAMETER
;
439 if (Language
[0] == 'e' && Language
[1] == 'n' && Language
[2] == 'g' && Language
[3] == 0) {
440 *DriverName
= FSW_EFI_DRIVER_NAME(FSTYPE
);
443 return EFI_UNSUPPORTED
;
447 * Component Name EFI protocol, GetControllerName function. Not implemented
448 * because this is not a "bus" driver in the sense of the EFI Driver Model.
451 EFI_STATUS EFIAPI
fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
452 IN EFI_HANDLE ControllerHandle
,
453 IN EFI_HANDLE ChildHandle OPTIONAL
,
455 OUT CHAR16
**ControllerName
)
457 return EFI_UNSUPPORTED
;
461 * FSW interface function for block size changes. This function is called by the FSW core
462 * when the file system driver changes the block sizes for the volume.
465 void fsw_efi_change_blocksize(struct fsw_volume
*vol
,
466 fsw_u32 old_phys_blocksize
, fsw_u32 old_log_blocksize
,
467 fsw_u32 new_phys_blocksize
, fsw_u32 new_log_blocksize
)
473 * FSW interface function to read data blocks. This function is called by the FSW core
474 * to read a block of data from the device. The buffer is allocated by the core code.
477 fsw_status_t
fsw_efi_read_block(struct fsw_volume
*vol
, fsw_u32 phys_bno
, void *buffer
)
480 FSW_VOLUME_DATA
*Volume
= (FSW_VOLUME_DATA
*)vol
->host_data
;
482 // FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_efi_read_block: %d (%d)\n"), phys_bno, vol->phys_blocksize));
485 Status
= Volume
->DiskIo
->ReadDisk(Volume
->DiskIo
, Volume
->MediaId
,
486 (UINT64
)phys_bno
* vol
->phys_blocksize
,
489 Volume
->LastIOStatus
= Status
;
490 if (EFI_ERROR(Status
))
496 * Map FSW status codes to EFI status codes. The FSW_IO_ERROR code is only produced
497 * by fsw_efi_read_block, so we map it back to the EFI status code remembered from
498 * the last I/O operation.
501 EFI_STATUS
fsw_efi_map_status(fsw_status_t fsw_status
, FSW_VOLUME_DATA
*Volume
)
503 switch (fsw_status
) {
506 case FSW_OUT_OF_MEMORY
:
507 return EFI_VOLUME_CORRUPTED
;
509 return Volume
->LastIOStatus
;
510 case FSW_UNSUPPORTED
:
511 return EFI_UNSUPPORTED
;
513 return EFI_NOT_FOUND
;
514 case FSW_VOLUME_CORRUPTED
:
515 return EFI_VOLUME_CORRUPTED
;
517 return EFI_DEVICE_ERROR
;
522 * File System EFI protocol, OpenVolume function. Creates a file handle for
523 * the root directory and returns it. Note that this function may be called
524 * multiple times and returns a new file handle each time. Each returned
525 * handle is closed by the client using it.
528 EFI_STATUS EFIAPI
fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE
*This
,
532 FSW_VOLUME_DATA
*Volume
= FSW_VOLUME_FROM_FILE_SYSTEM(This
);
535 Print(L
"fsw_efi_FileSystem_OpenVolume\n");
538 Status
= fsw_efi_dnode_to_FileHandle(Volume
->vol
->root
, Root
);
544 * File Handle EFI protocol, Open function. Dispatches the call
545 * based on the kind of file handle.
548 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Open(IN EFI_FILE
*This
,
549 OUT EFI_FILE
**NewHandle
,
552 IN UINT64 Attributes
)
554 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
556 if (File
->Type
== FSW_EFI_FILE_TYPE_DIR
)
557 return fsw_efi_dir_open(File
, NewHandle
, FileName
, OpenMode
, Attributes
);
558 // not supported for regular files
559 return EFI_UNSUPPORTED
;
563 * File Handle EFI protocol, Close function. Closes the FSW shandle
564 * and frees the memory used for the structure.
567 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Close(IN EFI_FILE
*This
)
569 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
572 Print(L
"fsw_efi_FileHandle_Close\n");
575 fsw_shandle_close(&File
->shand
);
582 * File Handle EFI protocol, Delete function. Calls through to Close
583 * and returns a warning because this driver is read-only.
586 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Delete(IN EFI_FILE
*This
)
590 Status
= This
->Close(This
);
591 if (Status
== EFI_SUCCESS
) {
592 // this driver is read-only
593 Status
= EFI_WARN_DELETE_FAILURE
;
600 * File Handle EFI protocol, Read function. Dispatches the call
601 * based on the kind of file handle.
604 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Read(IN EFI_FILE
*This
,
605 IN OUT UINTN
*BufferSize
,
608 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
610 if (File
->Type
== FSW_EFI_FILE_TYPE_FILE
)
611 return fsw_efi_file_read(File
, BufferSize
, Buffer
);
612 else if (File
->Type
== FSW_EFI_FILE_TYPE_DIR
)
613 return fsw_efi_dir_read(File
, BufferSize
, Buffer
);
614 return EFI_UNSUPPORTED
;
618 * File Handle EFI protocol, Write function. Returns unsupported status
619 * because this driver is read-only.
622 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Write(IN EFI_FILE
*This
,
623 IN OUT UINTN
*BufferSize
,
626 // this driver is read-only
627 return EFI_WRITE_PROTECTED
;
631 * File Handle EFI protocol, GetPosition function. Dispatches the call
632 * based on the kind of file handle.
635 EFI_STATUS EFIAPI
fsw_efi_FileHandle_GetPosition(IN EFI_FILE
*This
,
636 OUT UINT64
*Position
)
638 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
640 if (File
->Type
== FSW_EFI_FILE_TYPE_FILE
)
641 return fsw_efi_file_getpos(File
, Position
);
642 // not defined for directories
643 return EFI_UNSUPPORTED
;
647 * File Handle EFI protocol, SetPosition function. Dispatches the call
648 * based on the kind of file handle.
651 EFI_STATUS EFIAPI
fsw_efi_FileHandle_SetPosition(IN EFI_FILE
*This
,
654 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
656 if (File
->Type
== FSW_EFI_FILE_TYPE_FILE
)
657 return fsw_efi_file_setpos(File
, Position
);
658 else if (File
->Type
== FSW_EFI_FILE_TYPE_DIR
)
659 return fsw_efi_dir_setpos(File
, Position
);
660 return EFI_UNSUPPORTED
;
664 * File Handle EFI protocol, GetInfo function. Dispatches to the common
665 * function implementing this.
668 EFI_STATUS EFIAPI
fsw_efi_FileHandle_GetInfo(IN EFI_FILE
*This
,
669 IN EFI_GUID
*InformationType
,
670 IN OUT UINTN
*BufferSize
,
673 FSW_FILE_DATA
*File
= FSW_FILE_FROM_FILE_HANDLE(This
);
675 return fsw_efi_dnode_getinfo(File
, InformationType
, BufferSize
, Buffer
);
679 * File Handle EFI protocol, SetInfo function. Returns unsupported status
680 * because this driver is read-only.
683 EFI_STATUS EFIAPI
fsw_efi_FileHandle_SetInfo(IN EFI_FILE
*This
,
684 IN EFI_GUID
*InformationType
,
688 // this driver is read-only
689 return EFI_WRITE_PROTECTED
;
693 * File Handle EFI protocol, Flush function. Returns unsupported status
694 * because this driver is read-only.
697 EFI_STATUS EFIAPI
fsw_efi_FileHandle_Flush(IN EFI_FILE
*This
)
699 // this driver is read-only
700 return EFI_WRITE_PROTECTED
;
704 * Set up a file handle for a dnode. This function allocates a data structure
705 * for a file handle, opens a FSW shandle and populates the EFI_FILE structure
706 * with the interface functions.
709 EFI_STATUS
fsw_efi_dnode_to_FileHandle(IN
struct fsw_dnode
*dno
,
710 OUT EFI_FILE
**NewFileHandle
)
715 // make sure the dnode has complete info
716 Status
= fsw_efi_map_status(fsw_dnode_fill(dno
), (FSW_VOLUME_DATA
*)dno
->vol
->host_data
);
717 if (EFI_ERROR(Status
))
721 if (dno
->type
!= FSW_DNODE_TYPE_FILE
&& dno
->type
!= FSW_DNODE_TYPE_DIR
)
722 return EFI_UNSUPPORTED
;
724 // allocate file structure
725 File
= AllocateZeroPool(sizeof(FSW_FILE_DATA
));
726 File
->Signature
= FSW_FILE_DATA_SIGNATURE
;
727 if (dno
->type
== FSW_DNODE_TYPE_FILE
)
728 File
->Type
= FSW_EFI_FILE_TYPE_FILE
;
729 else if (dno
->type
== FSW_DNODE_TYPE_DIR
)
730 File
->Type
= FSW_EFI_FILE_TYPE_DIR
;
733 Status
= fsw_efi_map_status(fsw_shandle_open(dno
, &File
->shand
),
734 (FSW_VOLUME_DATA
*)dno
->vol
->host_data
);
735 if (EFI_ERROR(Status
)) {
740 // populate the file handle
741 File
->FileHandle
.Revision
= EFI_FILE_HANDLE_REVISION
;
742 File
->FileHandle
.Open
= fsw_efi_FileHandle_Open
;
743 File
->FileHandle
.Close
= fsw_efi_FileHandle_Close
;
744 File
->FileHandle
.Delete
= fsw_efi_FileHandle_Delete
;
745 File
->FileHandle
.Read
= fsw_efi_FileHandle_Read
;
746 File
->FileHandle
.Write
= fsw_efi_FileHandle_Write
;
747 File
->FileHandle
.GetPosition
= fsw_efi_FileHandle_GetPosition
;
748 File
->FileHandle
.SetPosition
= fsw_efi_FileHandle_SetPosition
;
749 File
->FileHandle
.GetInfo
= fsw_efi_FileHandle_GetInfo
;
750 File
->FileHandle
.SetInfo
= fsw_efi_FileHandle_SetInfo
;
751 File
->FileHandle
.Flush
= fsw_efi_FileHandle_Flush
;
753 *NewFileHandle
= &File
->FileHandle
;
758 * Data read function for regular files. Calls through to fsw_shandle_read.
761 EFI_STATUS
fsw_efi_file_read(IN FSW_FILE_DATA
*File
,
762 IN OUT UINTN
*BufferSize
,
769 Print(L
"fsw_efi_file_read %d bytes\n", *BufferSize
);
772 buffer_size
= (fsw_u32
)*BufferSize
;
773 Status
= fsw_efi_map_status(fsw_shandle_read(&File
->shand
, &buffer_size
, Buffer
),
774 (FSW_VOLUME_DATA
*)File
->shand
.dnode
->vol
->host_data
);
775 *BufferSize
= buffer_size
;
781 * Get file position for regular files.
784 EFI_STATUS
fsw_efi_file_getpos(IN FSW_FILE_DATA
*File
,
785 OUT UINT64
*Position
)
787 *Position
= File
->shand
.pos
;
792 * Set file position for regular files. EFI specifies the all-ones value
793 * to be a special value for the end of the file.
796 EFI_STATUS
fsw_efi_file_setpos(IN FSW_FILE_DATA
*File
,
799 if (Position
== 0xFFFFFFFFFFFFFFFFULL
)
800 File
->shand
.pos
= File
->shand
.dnode
->size
;
802 File
->shand
.pos
= Position
;
807 * Open function used to open new file handles relative to a directory.
808 * In EFI, the "open file" function is implemented by directory file handles
809 * and is passed a relative or volume-absolute path to the file or directory
810 * to open. We use fsw_dnode_lookup_path to find the node plus an additional
811 * call to fsw_dnode_resolve because EFI has no concept of symbolic links.
814 EFI_STATUS
fsw_efi_dir_open(IN FSW_FILE_DATA
*File
,
815 OUT EFI_FILE
**NewHandle
,
818 IN UINT64 Attributes
)
821 FSW_VOLUME_DATA
*Volume
= (FSW_VOLUME_DATA
*)File
->shand
.dnode
->vol
->host_data
;
822 struct fsw_dnode
*dno
;
823 struct fsw_dnode
*target_dno
;
824 struct fsw_string lookup_path
;
827 Print(L
"fsw_efi_dir_open: '%s'\n", FileName
);
830 if (OpenMode
!= EFI_FILE_MODE_READ
)
831 return EFI_WRITE_PROTECTED
;
833 lookup_path
.type
= FSW_STRING_TYPE_UTF16
;
834 lookup_path
.len
= (int)StrLen(FileName
);
835 lookup_path
.size
= lookup_path
.len
* sizeof(fsw_u16
);
836 lookup_path
.data
= FileName
;
838 // resolve the path (symlinks along the way are automatically resolved)
839 Status
= fsw_efi_map_status(fsw_dnode_lookup_path(File
->shand
.dnode
, &lookup_path
, '\\', &dno
),
841 if (EFI_ERROR(Status
))
844 // if the final node is a symlink, also resolve it
845 Status
= fsw_efi_map_status(fsw_dnode_resolve(dno
, &target_dno
),
847 fsw_dnode_release(dno
);
848 if (EFI_ERROR(Status
))
852 // make a new EFI handle for the target dnode
853 Status
= fsw_efi_dnode_to_FileHandle(dno
, NewHandle
);
854 fsw_dnode_release(dno
);
859 * Read function for directories. A file handle read on a directory retrieves
860 * the next directory entry.
863 EFI_STATUS
fsw_efi_dir_read(IN FSW_FILE_DATA
*File
,
864 IN OUT UINTN
*BufferSize
,
868 FSW_VOLUME_DATA
*Volume
= (FSW_VOLUME_DATA
*)File
->shand
.dnode
->vol
->host_data
;
869 struct fsw_dnode
*dno
;
872 Print(L
"fsw_efi_dir_read...\n");
875 // read the next entry
876 Status
= fsw_efi_map_status(fsw_dnode_dir_read(&File
->shand
, &dno
),
878 if (Status
== EFI_NOT_FOUND
) {
882 Print(L
"...no more entries\n");
886 if (EFI_ERROR(Status
))
889 // get info into buffer
890 Status
= fsw_efi_dnode_fill_FileInfo(Volume
, dno
, BufferSize
, Buffer
);
891 fsw_dnode_release(dno
);
896 * Set file position for directories. The only allowed set position operation
897 * for directories is to rewind the directory completely by setting the
901 EFI_STATUS
fsw_efi_dir_setpos(IN FSW_FILE_DATA
*File
,
908 // directories can only rewind to the start
909 return EFI_UNSUPPORTED
;
914 * Get file or volume information. This function implements the GetInfo call
915 * for all file handles. Control is dispatched according to the type of information
916 * requested by the caller.
919 EFI_STATUS
fsw_efi_dnode_getinfo(IN FSW_FILE_DATA
*File
,
920 IN EFI_GUID
*InformationType
,
921 IN OUT UINTN
*BufferSize
,
925 FSW_VOLUME_DATA
*Volume
= (FSW_VOLUME_DATA
*)File
->shand
.dnode
->vol
->host_data
;
926 EFI_FILE_SYSTEM_INFO
*FSInfo
;
928 struct fsw_volume_stat vsb
;
931 if (CompareGuid(InformationType
, &gEfiFileInfoGuid
)) {
933 Print(L
"fsw_efi_dnode_getinfo: FILE_INFO\n");
936 Status
= fsw_efi_dnode_fill_FileInfo(Volume
, File
->shand
.dnode
, BufferSize
, Buffer
);
938 } else if (CompareGuid(InformationType
, &gEfiFileSystemInfoGuid
)) {
940 Print(L
"fsw_efi_dnode_getinfo: FILE_SYSTEM_INFO\n");
944 RequiredSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ fsw_efi_strsize(&Volume
->vol
->label
);
945 if (*BufferSize
< RequiredSize
) {
946 *BufferSize
= RequiredSize
;
947 return EFI_BUFFER_TOO_SMALL
;
951 FSInfo
= (EFI_FILE_SYSTEM_INFO
*)Buffer
;
952 FSInfo
->Size
= RequiredSize
;
953 FSInfo
->ReadOnly
= TRUE
;
954 FSInfo
->BlockSize
= Volume
->vol
->log_blocksize
;
955 fsw_efi_strcpy(FSInfo
->VolumeLabel
, &Volume
->vol
->label
);
957 // get the missing info from the fs driver
958 ZeroMem(&vsb
, sizeof(struct fsw_volume_stat
));
959 Status
= fsw_efi_map_status(fsw_volume_stat(Volume
->vol
, &vsb
), Volume
);
960 if (EFI_ERROR(Status
))
962 FSInfo
->VolumeSize
= vsb
.total_bytes
;
963 FSInfo
->FreeSpace
= vsb
.free_bytes
;
965 // prepare for return
966 *BufferSize
= RequiredSize
;
967 Status
= EFI_SUCCESS
;
969 } else if (CompareGuid(InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
971 Print(L
"fsw_efi_dnode_getinfo: FILE_SYSTEM_VOLUME_LABEL\n");
975 RequiredSize
= SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO
+ fsw_efi_strsize(&Volume
->vol
->label
);
976 if (*BufferSize
< RequiredSize
) {
977 *BufferSize
= RequiredSize
;
978 return EFI_BUFFER_TOO_SMALL
;
982 fsw_efi_strcpy(((EFI_FILE_SYSTEM_VOLUME_LABEL_INFO
*)Buffer
)->VolumeLabel
, &Volume
->vol
->label
);
984 // prepare for return
985 *BufferSize
= RequiredSize
;
986 Status
= EFI_SUCCESS
;
989 Status
= EFI_UNSUPPORTED
;
996 * Time mapping callback for the fsw_dnode_stat call. This function converts
997 * a Posix style timestamp into an EFI_TIME structure and writes it to the
998 * appropriate member of the EFI_FILE_INFO structure that we're filling.
1001 static void fsw_efi_store_time_posix(struct fsw_dnode_stat
*sb
, int which
, fsw_u32 posix_time
)
1003 EFI_FILE_INFO
*FileInfo
= (EFI_FILE_INFO
*)sb
->host_data
;
1005 if (which
== FSW_DNODE_STAT_CTIME
)
1006 fsw_efi_decode_time(&FileInfo
->CreateTime
, posix_time
);
1007 else if (which
== FSW_DNODE_STAT_MTIME
)
1008 fsw_efi_decode_time(&FileInfo
->ModificationTime
, posix_time
);
1009 else if (which
== FSW_DNODE_STAT_ATIME
)
1010 fsw_efi_decode_time(&FileInfo
->LastAccessTime
, posix_time
);
1014 * Mode mapping callback for the fsw_dnode_stat call. This function looks at
1015 * the Posix mode passed by the file system driver and makes appropriate
1016 * adjustments to the EFI_FILE_INFO structure that we're filling.
1019 static void fsw_efi_store_attr_posix(struct fsw_dnode_stat
*sb
, fsw_u16 posix_mode
)
1021 EFI_FILE_INFO
*FileInfo
= (EFI_FILE_INFO
*)sb
->host_data
;
1023 if ((posix_mode
& S_IWUSR
) == 0)
1024 FileInfo
->Attribute
|= EFI_FILE_READ_ONLY
;
1028 * Common function to fill an EFI_FILE_INFO with information about a dnode.
1031 EFI_STATUS
fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA
*Volume
,
1032 IN
struct fsw_dnode
*dno
,
1033 IN OUT UINTN
*BufferSize
,
1037 EFI_FILE_INFO
*FileInfo
;
1039 struct fsw_dnode_stat sb
;
1041 // make sure the dnode has complete info
1042 Status
= fsw_efi_map_status(fsw_dnode_fill(dno
), Volume
);
1043 if (EFI_ERROR(Status
))
1046 // TODO: check/assert that the dno's name is in UTF16
1048 // check buffer size
1049 RequiredSize
= SIZE_OF_EFI_FILE_INFO
+ fsw_efi_strsize(&dno
->name
);
1050 if (*BufferSize
< RequiredSize
) {
1051 // TODO: wind back the directory in this case
1054 Print(L
"...BUFFER TOO SMALL\n");
1056 *BufferSize
= RequiredSize
;
1057 return EFI_BUFFER_TOO_SMALL
;
1061 ZeroMem(Buffer
, RequiredSize
);
1062 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
1063 FileInfo
->Size
= RequiredSize
;
1064 FileInfo
->FileSize
= dno
->size
;
1065 FileInfo
->Attribute
= 0;
1066 if (dno
->type
== FSW_DNODE_TYPE_DIR
)
1067 FileInfo
->Attribute
|= EFI_FILE_DIRECTORY
;
1068 fsw_efi_strcpy(FileInfo
->FileName
, &dno
->name
);
1070 // get the missing info from the fs driver
1071 ZeroMem(&sb
, sizeof(struct fsw_dnode_stat
));
1072 sb
.store_time_posix
= fsw_efi_store_time_posix
;
1073 sb
.store_attr_posix
= fsw_efi_store_attr_posix
;
1074 sb
.host_data
= FileInfo
;
1075 Status
= fsw_efi_map_status(fsw_dnode_stat(dno
, &sb
), Volume
);
1076 if (EFI_ERROR(Status
))
1078 FileInfo
->PhysicalSize
= sb
.used_bytes
;
1080 // prepare for return
1081 *BufferSize
= RequiredSize
;
1083 Print(L
"...returning '%s'\n", FileInfo
->FileName
);