VirtualBox

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

Last change on this file since 29921 was 29125, checked in by vboxsync, 15 years ago

export more EFI files to OSE

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