VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_efi.c@ 46284

Last change on this file since 46284 was 44529, checked in by vboxsync, 12 years ago

header (C) fixes

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette