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