]> code.delx.au - refind/blob - filesystems/fsw_efi.c
0.4.4 release
[refind] / filesystems / fsw_efi.c
1 /* $Id: fsw_efi.c 29125 2010-05-06 09:43:05Z vboxsync $ */
2 /** @file
3 * fsw_efi.c - EFI host environment code.
4 */
5
6 /*
7 * Copyright (C) 2010 Oracle Corporation
8 *
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.
16 */
17
18 /*-
19 * This code is based on:
20 *
21 * Copyright (c) 2006 Christoph Pfisterer
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions are
25 * met:
26 *
27 * * Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 *
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
33 * distribution.
34 *
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.
38 *
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.
50 */
51
52 #include "fsw_efi.h"
53 #include "fsw_core.h"
54 //#include <EfiCommonLib.h>
55 //#include <EfiDriverLib.h>
56
57 #define DEBUG_LEVEL 0
58
59 #ifndef FSTYPE
60 #ifdef VBOX
61 #error FSTYPE must be defined!
62 #else
63 #define FSTYPE ext2
64 #endif
65 #endif
66
67 #define DEBUG_VBFS 1
68 // CHAR8 *msgCursor;
69 // MESSAGE_LOG_PROTOCOL *Msg = NULL;
70
71 #if DEBUG_VBFS==2
72 #define DBG(x...) AsciiPrint(x)
73 #elif DEBUG_VBFS==1
74 #define DBG(x...) BootLog(x)
75 #else
76 #define DBG(x...)
77 #endif
78
79
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.4 " FSW_EFI_STRINGIFY(t) L" File System Driver"
84
85 // function prototypes
86
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);
97
98 EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
99 IN CHAR8 *Language,
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,
104 IN CHAR8 *Language,
105 OUT CHAR16 **ControllerName);
106
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);
111
112 EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume);
113
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);
118
119 EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File,
120 IN OUT UINTN *BufferSize,
121 OUT VOID *Buffer);
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,
125 IN UINT64 Position);
126
127 EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
128 OUT EFI_FILE **NewHandle,
129 IN CHAR16 *FileName,
130 IN UINT64 OpenMode,
131 IN UINT64 Attributes);
132 EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
133 IN OUT UINTN *BufferSize,
134 OUT VOID *Buffer);
135 EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File,
136 IN UINT64 Position);
137
138 EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File,
139 IN EFI_GUID *InformationType,
140 IN OUT UINTN *BufferSize,
141 OUT VOID *Buffer);
142 EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
143 IN struct fsw_dnode *dno,
144 IN OUT UINTN *BufferSize,
145 OUT VOID *Buffer);
146
147 /**
148 * Interface structure for the EFI Driver Binding protocol.
149 */
150
151 EFI_DRIVER_BINDING_PROTOCOL fsw_efi_DriverBinding_table = {
152 fsw_efi_DriverBinding_Supported,
153 fsw_efi_DriverBinding_Start,
154 fsw_efi_DriverBinding_Stop,
155 0x10,
156 NULL,
157 NULL
158 };
159
160 /**
161 * Interface structure for the EFI Component Name protocol.
162 */
163
164 EFI_COMPONENT_NAME_PROTOCOL fsw_efi_ComponentName_table = {
165 fsw_efi_ComponentName_GetDriverName,
166 fsw_efi_ComponentName_GetControllerName,
167 "eng"
168 };
169
170 /**
171 * Dispatch table for our FSW host driver.
172 */
173
174 struct fsw_host_table fsw_efi_host_table = {
175 FSW_STRING_TYPE_UTF16,
176
177 fsw_efi_change_blocksize,
178 fsw_efi_read_block
179 };
180
181 extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE);
182
183 //#include "OverrideFunctions-kabyl.edk2.c.include"
184
185 /**
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.
189 */
190 EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE ImageHandle,
191 IN EFI_SYSTEM_TABLE *SystemTable)
192 {
193 EFI_STATUS Status;
194
195 #ifndef VBOX
196 InitializeLib(ImageHandle, SystemTable);
197 #endif
198
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)) {
208 return Status;
209 }
210
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)) {
217 return Status;
218 }
219
220 // OverrideFunctions();
221 // Msg = NULL;
222 // msgCursor = NULL;
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");
227 // }
228
229 return EFI_SUCCESS;
230 }
231
232 /**
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.
237 */
238
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)
242 {
243 EFI_STATUS Status;
244 EFI_DISK_IO *DiskIo;
245
246 // we check for both DiskIO and BlockIO protocols
247
248 // first, open DiskIO
249 Status = BS->OpenProtocol(ControllerHandle,
250 &PROTO_NAME(DiskIoProtocol),
251 (VOID **) &DiskIo,
252 This->DriverBindingHandle,
253 ControllerHandle,
254 EFI_OPEN_PROTOCOL_BY_DRIVER);
255 if (EFI_ERROR(Status))
256 return Status;
257
258 // we were just checking, close it again
259 BS->CloseProtocol(ControllerHandle,
260 &PROTO_NAME(DiskIoProtocol),
261 This->DriverBindingHandle,
262 ControllerHandle);
263
264 // next, check BlockIO without actually opening it
265 Status = BS->OpenProtocol(ControllerHandle,
266 &PROTO_NAME(BlockIoProtocol),
267 NULL,
268 This->DriverBindingHandle,
269 ControllerHandle,
270 EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
271 return Status;
272 }
273
274 /**
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.
279 *
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
284 * device handle.
285 */
286
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)
290 {
291 EFI_STATUS Status;
292 EFI_BLOCK_IO *BlockIo;
293 EFI_DISK_IO *DiskIo;
294 FSW_VOLUME_DATA *Volume;
295
296 #if DEBUG_LEVEL
297 Print(L"fsw_efi_DriverBinding_Start\n");
298 #endif
299
300 // open consumed protocols
301 Status = BS->OpenProtocol(ControllerHandle,
302 &PROTO_NAME(BlockIoProtocol),
303 (VOID **) &BlockIo,
304 This->DriverBindingHandle,
305 ControllerHandle,
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);
309 return Status;
310 }
311
312 Status = BS->OpenProtocol(ControllerHandle,
313 &PROTO_NAME(DiskIoProtocol),
314 (VOID **) &DiskIo,
315 This->DriverBindingHandle,
316 ControllerHandle,
317 EFI_OPEN_PROTOCOL_BY_DRIVER);
318 if (EFI_ERROR(Status)) {
319 Print(L"Fsw ERROR: OpenProtocol(DiskIo) returned %r\n", Status);
320 return Status;
321 }
322
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;
330
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),
334 Volume);
335
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),
342 &Volume->FileSystem,
343 NULL);
344 if (EFI_ERROR(Status)) {
345 // Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned %x\n", Status);
346 }
347 }
348
349 // on errors, close the opened protocols
350 if (EFI_ERROR(Status)) {
351 if (Volume->vol != NULL)
352 fsw_unmount(Volume->vol);
353 FreePool(Volume);
354
355 BS->CloseProtocol(ControllerHandle,
356 &PROTO_NAME(DiskIoProtocol),
357 This->DriverBindingHandle,
358 ControllerHandle);
359 }
360
361 return Status;
362 }
363
364 /**
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.
368 *
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.
372 */
373
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)
378 {
379 EFI_STATUS Status;
380 EFI_FILE_IO_INTERFACE *FileSystem;
381 FSW_VOLUME_DATA *Volume;
382
383 #if DEBUG_LEVEL
384 Print(L"fsw_efi_DriverBinding_Stop\n");
385 #endif
386
387 // get the installed SimpleFileSystem interface
388 Status = BS->OpenProtocol(ControllerHandle,
389 &PROTO_NAME(SimpleFileSystemProtocol),
390 (VOID **) &FileSystem,
391 This->DriverBindingHandle,
392 ControllerHandle,
393 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
394 if (EFI_ERROR(Status))
395 return EFI_UNSUPPORTED;
396
397 // get private data structure
398 Volume = FSW_VOLUME_FROM_FILE_SYSTEM(FileSystem);
399
400 // uninstall Simple File System protocol
401 Status = BS->UninstallMultipleProtocolInterfaces(ControllerHandle,
402 &PROTO_NAME(SimpleFileSystemProtocol), &Volume->FileSystem,
403 NULL);
404 if (EFI_ERROR(Status)) {
405 // Print(L"Fsw ERROR: UninstallMultipleProtocolInterfaces returned %x\n", Status);
406 return Status;
407 }
408 #if DEBUG_LEVEL
409 Print(L"fsw_efi_DriverBinding_Stop: protocol uninstalled successfully\n");
410 #endif
411
412 // release private data structure
413 if (Volume->vol != NULL)
414 fsw_unmount(Volume->vol);
415 FreePool(Volume);
416
417 // close the consumed protocols
418 Status = BS->CloseProtocol(ControllerHandle,
419 &PROTO_NAME(DiskIoProtocol),
420 This->DriverBindingHandle,
421 ControllerHandle);
422
423 return Status;
424 }
425
426 /**
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.
430 */
431
432 EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
433 IN CHAR8 *Language,
434 OUT CHAR16 **DriverName)
435 {
436 if (Language == NULL || DriverName == NULL)
437 return EFI_INVALID_PARAMETER;
438
439 if (Language[0] == 'e' && Language[1] == 'n' && Language[2] == 'g' && Language[3] == 0) {
440 *DriverName = FSW_EFI_DRIVER_NAME(FSTYPE);
441 return EFI_SUCCESS;
442 }
443 return EFI_UNSUPPORTED;
444 }
445
446 /**
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.
449 */
450
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,
454 IN CHAR8 *Language,
455 OUT CHAR16 **ControllerName)
456 {
457 return EFI_UNSUPPORTED;
458 }
459
460 /**
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.
463 */
464
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)
468 {
469 // nothing to do
470 }
471
472 /**
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.
475 */
476
477 fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer)
478 {
479 EFI_STATUS Status;
480 FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)vol->host_data;
481
482 // FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_efi_read_block: %d (%d)\n"), phys_bno, vol->phys_blocksize));
483
484 // read from disk
485 Status = Volume->DiskIo->ReadDisk(Volume->DiskIo, Volume->MediaId,
486 (UINT64)phys_bno * vol->phys_blocksize,
487 vol->phys_blocksize,
488 buffer);
489 Volume->LastIOStatus = Status;
490 if (EFI_ERROR(Status))
491 return FSW_IO_ERROR;
492 return FSW_SUCCESS;
493 }
494
495 /**
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.
499 */
500
501 EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume)
502 {
503 switch (fsw_status) {
504 case FSW_SUCCESS:
505 return EFI_SUCCESS;
506 case FSW_OUT_OF_MEMORY:
507 return EFI_VOLUME_CORRUPTED;
508 case FSW_IO_ERROR:
509 return Volume->LastIOStatus;
510 case FSW_UNSUPPORTED:
511 return EFI_UNSUPPORTED;
512 case FSW_NOT_FOUND:
513 return EFI_NOT_FOUND;
514 case FSW_VOLUME_CORRUPTED:
515 return EFI_VOLUME_CORRUPTED;
516 default:
517 return EFI_DEVICE_ERROR;
518 }
519 }
520
521 /**
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.
526 */
527
528 EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
529 OUT EFI_FILE **Root)
530 {
531 EFI_STATUS Status;
532 FSW_VOLUME_DATA *Volume = FSW_VOLUME_FROM_FILE_SYSTEM(This);
533
534 #if DEBUG_LEVEL
535 Print(L"fsw_efi_FileSystem_OpenVolume\n");
536 #endif
537
538 Status = fsw_efi_dnode_to_FileHandle(Volume->vol->root, Root);
539
540 return Status;
541 }
542
543 /**
544 * File Handle EFI protocol, Open function. Dispatches the call
545 * based on the kind of file handle.
546 */
547
548 EFI_STATUS EFIAPI fsw_efi_FileHandle_Open(IN EFI_FILE *This,
549 OUT EFI_FILE **NewHandle,
550 IN CHAR16 *FileName,
551 IN UINT64 OpenMode,
552 IN UINT64 Attributes)
553 {
554 FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
555
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;
560 }
561
562 /**
563 * File Handle EFI protocol, Close function. Closes the FSW shandle
564 * and frees the memory used for the structure.
565 */
566
567 EFI_STATUS EFIAPI fsw_efi_FileHandle_Close(IN EFI_FILE *This)
568 {
569 FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
570
571 #if DEBUG_LEVEL
572 Print(L"fsw_efi_FileHandle_Close\n");
573 #endif
574
575 fsw_shandle_close(&File->shand);
576 FreePool(File);
577
578 return EFI_SUCCESS;
579 }
580
581 /**
582 * File Handle EFI protocol, Delete function. Calls through to Close
583 * and returns a warning because this driver is read-only.
584 */
585
586 EFI_STATUS EFIAPI fsw_efi_FileHandle_Delete(IN EFI_FILE *This)
587 {
588 EFI_STATUS Status;
589
590 Status = This->Close(This);
591 if (Status == EFI_SUCCESS) {
592 // this driver is read-only
593 Status = EFI_WARN_DELETE_FAILURE;
594 }
595
596 return Status;
597 }
598
599 /**
600 * File Handle EFI protocol, Read function. Dispatches the call
601 * based on the kind of file handle.
602 */
603
604 EFI_STATUS EFIAPI fsw_efi_FileHandle_Read(IN EFI_FILE *This,
605 IN OUT UINTN *BufferSize,
606 OUT VOID *Buffer)
607 {
608 FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
609
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;
615 }
616
617 /**
618 * File Handle EFI protocol, Write function. Returns unsupported status
619 * because this driver is read-only.
620 */
621
622 EFI_STATUS EFIAPI fsw_efi_FileHandle_Write(IN EFI_FILE *This,
623 IN OUT UINTN *BufferSize,
624 IN VOID *Buffer)
625 {
626 // this driver is read-only
627 return EFI_WRITE_PROTECTED;
628 }
629
630 /**
631 * File Handle EFI protocol, GetPosition function. Dispatches the call
632 * based on the kind of file handle.
633 */
634
635 EFI_STATUS EFIAPI fsw_efi_FileHandle_GetPosition(IN EFI_FILE *This,
636 OUT UINT64 *Position)
637 {
638 FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
639
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;
644 }
645
646 /**
647 * File Handle EFI protocol, SetPosition function. Dispatches the call
648 * based on the kind of file handle.
649 */
650
651 EFI_STATUS EFIAPI fsw_efi_FileHandle_SetPosition(IN EFI_FILE *This,
652 IN UINT64 Position)
653 {
654 FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
655
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;
661 }
662
663 /**
664 * File Handle EFI protocol, GetInfo function. Dispatches to the common
665 * function implementing this.
666 */
667
668 EFI_STATUS EFIAPI fsw_efi_FileHandle_GetInfo(IN EFI_FILE *This,
669 IN EFI_GUID *InformationType,
670 IN OUT UINTN *BufferSize,
671 OUT VOID *Buffer)
672 {
673 FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
674
675 return fsw_efi_dnode_getinfo(File, InformationType, BufferSize, Buffer);
676 }
677
678 /**
679 * File Handle EFI protocol, SetInfo function. Returns unsupported status
680 * because this driver is read-only.
681 */
682
683 EFI_STATUS EFIAPI fsw_efi_FileHandle_SetInfo(IN EFI_FILE *This,
684 IN EFI_GUID *InformationType,
685 IN UINTN BufferSize,
686 IN VOID *Buffer)
687 {
688 // this driver is read-only
689 return EFI_WRITE_PROTECTED;
690 }
691
692 /**
693 * File Handle EFI protocol, Flush function. Returns unsupported status
694 * because this driver is read-only.
695 */
696
697 EFI_STATUS EFIAPI fsw_efi_FileHandle_Flush(IN EFI_FILE *This)
698 {
699 // this driver is read-only
700 return EFI_WRITE_PROTECTED;
701 }
702
703 /**
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.
707 */
708
709 EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno,
710 OUT EFI_FILE **NewFileHandle)
711 {
712 EFI_STATUS Status;
713 FSW_FILE_DATA *File;
714
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))
718 return Status;
719
720 // check type
721 if (dno->type != FSW_DNODE_TYPE_FILE && dno->type != FSW_DNODE_TYPE_DIR)
722 return EFI_UNSUPPORTED;
723
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;
731
732 // open shandle
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)) {
736 FreePool(File);
737 return Status;
738 }
739
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;
752
753 *NewFileHandle = &File->FileHandle;
754 return EFI_SUCCESS;
755 }
756
757 /**
758 * Data read function for regular files. Calls through to fsw_shandle_read.
759 */
760
761 EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File,
762 IN OUT UINTN *BufferSize,
763 OUT VOID *Buffer)
764 {
765 EFI_STATUS Status;
766 fsw_u32 buffer_size;
767
768 #if DEBUG_LEVEL
769 Print(L"fsw_efi_file_read %d bytes\n", *BufferSize);
770 #endif
771
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;
776
777 return Status;
778 }
779
780 /**
781 * Get file position for regular files.
782 */
783
784 EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File,
785 OUT UINT64 *Position)
786 {
787 *Position = File->shand.pos;
788 return EFI_SUCCESS;
789 }
790
791 /**
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.
794 */
795
796 EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File,
797 IN UINT64 Position)
798 {
799 if (Position == 0xFFFFFFFFFFFFFFFFULL)
800 File->shand.pos = File->shand.dnode->size;
801 else
802 File->shand.pos = Position;
803 return EFI_SUCCESS;
804 }
805
806 /**
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.
812 */
813
814 EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
815 OUT EFI_FILE **NewHandle,
816 IN CHAR16 *FileName,
817 IN UINT64 OpenMode,
818 IN UINT64 Attributes)
819 {
820 EFI_STATUS Status;
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;
825
826 #if DEBUG_LEVEL
827 Print(L"fsw_efi_dir_open: '%s'\n", FileName);
828 #endif
829
830 if (OpenMode != EFI_FILE_MODE_READ)
831 return EFI_WRITE_PROTECTED;
832
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;
837
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),
840 Volume);
841 if (EFI_ERROR(Status))
842 return Status;
843
844 // if the final node is a symlink, also resolve it
845 Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno),
846 Volume);
847 fsw_dnode_release(dno);
848 if (EFI_ERROR(Status))
849 return Status;
850 dno = target_dno;
851
852 // make a new EFI handle for the target dnode
853 Status = fsw_efi_dnode_to_FileHandle(dno, NewHandle);
854 fsw_dnode_release(dno);
855 return Status;
856 }
857
858 /**
859 * Read function for directories. A file handle read on a directory retrieves
860 * the next directory entry.
861 */
862
863 EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
864 IN OUT UINTN *BufferSize,
865 OUT VOID *Buffer)
866 {
867 EFI_STATUS Status;
868 FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
869 struct fsw_dnode *dno;
870
871 #if DEBUG_LEVEL
872 Print(L"fsw_efi_dir_read...\n");
873 #endif
874
875 // read the next entry
876 Status = fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno),
877 Volume);
878 if (Status == EFI_NOT_FOUND) {
879 // end of directory
880 *BufferSize = 0;
881 #if DEBUG_LEVEL
882 Print(L"...no more entries\n");
883 #endif
884 return EFI_SUCCESS;
885 }
886 if (EFI_ERROR(Status))
887 return Status;
888
889 // get info into buffer
890 Status = fsw_efi_dnode_fill_FileInfo(Volume, dno, BufferSize, Buffer);
891 fsw_dnode_release(dno);
892 return Status;
893 }
894
895 /**
896 * Set file position for directories. The only allowed set position operation
897 * for directories is to rewind the directory completely by setting the
898 * position to zero.
899 */
900
901 EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File,
902 IN UINT64 Position)
903 {
904 if (Position == 0) {
905 File->shand.pos = 0;
906 return EFI_SUCCESS;
907 } else {
908 // directories can only rewind to the start
909 return EFI_UNSUPPORTED;
910 }
911 }
912
913 /**
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.
917 */
918
919 EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File,
920 IN EFI_GUID *InformationType,
921 IN OUT UINTN *BufferSize,
922 OUT VOID *Buffer)
923 {
924 EFI_STATUS Status;
925 FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
926 EFI_FILE_SYSTEM_INFO *FSInfo;
927 UINTN RequiredSize;
928 struct fsw_volume_stat vsb;
929
930
931 if (CompareGuid(InformationType, &gEfiFileInfoGuid)) {
932 #if DEBUG_LEVEL
933 Print(L"fsw_efi_dnode_getinfo: FILE_INFO\n");
934 #endif
935
936 Status = fsw_efi_dnode_fill_FileInfo(Volume, File->shand.dnode, BufferSize, Buffer);
937
938 } else if (CompareGuid(InformationType, &gEfiFileSystemInfoGuid)) {
939 #if DEBUG_LEVEL
940 Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_INFO\n");
941 #endif
942
943 // check buffer size
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;
948 }
949
950 // fill structure
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);
956
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))
961 return Status;
962 FSInfo->VolumeSize = vsb.total_bytes;
963 FSInfo->FreeSpace = vsb.free_bytes;
964
965 // prepare for return
966 *BufferSize = RequiredSize;
967 Status = EFI_SUCCESS;
968
969 } else if (CompareGuid(InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
970 #if DEBUG_LEVEL
971 Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_VOLUME_LABEL\n");
972 #endif
973
974 // check buffer size
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;
979 }
980
981 // copy volume label
982 fsw_efi_strcpy(((EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *)Buffer)->VolumeLabel, &Volume->vol->label);
983
984 // prepare for return
985 *BufferSize = RequiredSize;
986 Status = EFI_SUCCESS;
987
988 } else {
989 Status = EFI_UNSUPPORTED;
990 }
991
992 return Status;
993 }
994
995 /**
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.
999 */
1000
1001 static void fsw_efi_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time)
1002 {
1003 EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
1004
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);
1011 }
1012
1013 /**
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.
1017 */
1018
1019 static void fsw_efi_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode)
1020 {
1021 EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
1022
1023 if ((posix_mode & S_IWUSR) == 0)
1024 FileInfo->Attribute |= EFI_FILE_READ_ONLY;
1025 }
1026
1027 /**
1028 * Common function to fill an EFI_FILE_INFO with information about a dnode.
1029 */
1030
1031 EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
1032 IN struct fsw_dnode *dno,
1033 IN OUT UINTN *BufferSize,
1034 OUT VOID *Buffer)
1035 {
1036 EFI_STATUS Status;
1037 EFI_FILE_INFO *FileInfo;
1038 UINTN RequiredSize;
1039 struct fsw_dnode_stat sb;
1040
1041 // make sure the dnode has complete info
1042 Status = fsw_efi_map_status(fsw_dnode_fill(dno), Volume);
1043 if (EFI_ERROR(Status))
1044 return Status;
1045
1046 // TODO: check/assert that the dno's name is in UTF16
1047
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
1052
1053 #if DEBUG_LEVEL
1054 Print(L"...BUFFER TOO SMALL\n");
1055 #endif
1056 *BufferSize = RequiredSize;
1057 return EFI_BUFFER_TOO_SMALL;
1058 }
1059
1060 // fill structure
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);
1069
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))
1077 return Status;
1078 FileInfo->PhysicalSize = sb.used_bytes;
1079
1080 // prepare for return
1081 *BufferSize = RequiredSize;
1082 #if DEBUG_LEVEL
1083 Print(L"...returning '%s'\n", FileInfo->FileName);
1084 #endif
1085 return EFI_SUCCESS;
1086 }
1087
1088 // EOF