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