1 /* $NetBSD: efifs.c,v 1.3 2009/03/18 16:00:12 cegger Exp $ */
4 * Copyright (c) 2001 Doug Rabson
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * $FreeBSD: src/sys/boot/efi/libefi/efifs.c,v 1.8 2003/08/02 08:22:03 marcel Exp $
32 #include <sys/dirent.h>
33 #include <lib/libsa/stand.h>
34 #include <lib/libsa/loadfile.h>
35 #include <lib/libkern/libkern.h>
36 #include <machine/stdarg.h>
41 #include <bootstrap.h>
45 /* Perform I/O in blocks of size EFI_BLOCK_SIZE. */
46 #define EFI_BLOCK_SIZE (1024 * 1024)
50 efifs_open(const char *upath
, struct open_file
*f
)
52 struct efi_devdesc
*dev
= f
->f_devdata
;
53 static EFI_GUID sfsid
= SIMPLE_FILE_SYSTEM_PROTOCOL
;
54 EFI_FILE_IO_INTERFACE
*sfs
;
62 * We cannot blindly assume that f->f_devdata points to a
63 * efi_devdesc structure. Before we dereference 'dev', make
64 * sure that the underlying device is ours.
66 if (f
->f_dev
!= &devsw
[0] || dev
->d_handle
== NULL
)
69 status
= BS
->HandleProtocol(dev
->d_handle
, &sfsid
, (VOID
**)&sfs
);
70 if (EFI_ERROR(status
))
74 * Find the root directory.
76 status
= sfs
->OpenVolume(sfs
, &root
);
79 * Convert path to CHAR16, skipping leading separators.
84 /* Opening the root directory, */
88 cp
= path
= alloc((strlen(upath
) + 1) * sizeof(CHAR16
));
104 status
= root
->Open(root
, &file
, path
, EFI_FILE_MODE_READ
, 0);
106 if (EFI_ERROR(status
)) {
117 efifs_close(struct open_file
*f
)
119 EFI_FILE
*file
= f
->f_fsdata
;
126 efifs_read(struct open_file
*f
, void *buf
, size_t size
, size_t *resid
)
128 EFI_FILE
*file
= f
->f_fsdata
;
136 if (sz
> EFI_BLOCK_SIZE
)
138 status
= file
->Read(file
, &sz
, bufp
);
140 #if !defined(LIBSA_NO_TWIDDLE)
144 if (EFI_ERROR(status
))
157 efifs_write(struct open_file
*f
, void *buf
, size_t size
, size_t *resid
)
159 EFI_FILE
*file
= f
->f_fsdata
;
167 if (sz
> EFI_BLOCK_SIZE
)
169 status
= file
->Write(file
, &sz
, bufp
);
171 #if !defined(LIBSA_NO_TWIDDLE)
175 if (EFI_ERROR(status
))
188 efifs_seek(struct open_file
*f
, off_t offset
, int where
)
190 EFI_FILE
*file
= f
->f_fsdata
;
194 static EFI_GUID infoid
= EFI_FILE_INFO_ID
;
203 status
= file
->GetPosition(file
, &base
);
204 if (EFI_ERROR(status
))
210 status
= file
->GetInfo(file
, &infoid
, &sz
, &info
);
211 if (EFI_ERROR(status
))
213 base
= info
.FileSize
;
217 status
= file
->SetPosition(file
, base
+ offset
);
218 if (EFI_ERROR(status
))
220 file
->GetPosition(file
, &base
);
226 efifs_stat(struct open_file
*f
, struct stat
*sb
)
228 EFI_FILE
*file
= f
->f_fsdata
;
232 static EFI_GUID infoid
= EFI_FILE_INFO_ID
;
235 memset(sb
, 0, sizeof(*sb
));
240 status
= file
->GetInfo(file
, &infoid
, &sz
, buf
);
241 if (EFI_ERROR(status
)) {
246 info
= (EFI_FILE_INFO
*) buf
;
248 if (info
->Attribute
& EFI_FILE_READ_ONLY
)
249 sb
->st_mode
= S_IRUSR
;
251 sb
->st_mode
= S_IRUSR
| S_IWUSR
;
252 if (info
->Attribute
& EFI_FILE_DIRECTORY
)
253 sb
->st_mode
|= S_IFDIR
;
255 sb
->st_mode
|= S_IFREG
;
256 sb
->st_size
= info
->FileSize
;
263 efifs_readdir(struct open_file
*f
, struct dirent
*d
)
265 EFI_FILE
*file
= f
->f_fsdata
;
275 status
= file
->Read(file
, &sz
, buf
);
276 if (EFI_ERROR(status
) || sz
< offsetof(EFI_FILE_INFO
, FileName
))
279 info
= (EFI_FILE_INFO
*) buf
;
282 d
->d_reclen
= sizeof(*d
);
283 if (info
->Attribute
& EFI_FILE_DIRECTORY
)
287 d
->d_namlen
= ((info
->Size
- offsetof(EFI_FILE_INFO
, FileName
))
289 for (i
= 0; i
< d
->d_namlen
; i
++)
290 d
->d_name
[i
] = info
->FileName
[i
];
297 static EFI_HANDLE
*fs_handles
;
298 UINTN fs_handle_count
;
301 efifs_get_unit(EFI_HANDLE h
)
306 while (u
< fs_handle_count
&& fs_handles
[u
] != h
)
308 return ((u
< fs_handle_count
) ? u
: -1);
316 static EFI_GUID sfsid
= SIMPLE_FILE_SYSTEM_PROTOCOL
;
319 status
= BS
->LocateHandle(ByProtocol
, &sfsid
, 0, &sz
, 0);
320 if (status
!= EFI_BUFFER_TOO_SMALL
)
322 fs_handles
= (EFI_HANDLE
*) alloc(sz
);
323 status
= BS
->LocateHandle(ByProtocol
, &sfsid
, 0,
325 if (EFI_ERROR(status
)) {
329 fs_handle_count
= sz
/ sizeof(EFI_HANDLE
);
335 * Print information about disks
338 efifs_dev_print(int verbose
)
343 for (i
= 0; i
< fs_handle_count
; i
++) {
344 sprintf(line
, " fs%d: EFI filesystem", i
);
346 /* XXX more detail? */
352 * Attempt to open the disk described by (dev) for use by (f).
354 * Note that the philosophy here is "give them exactly what
355 * they ask for". This is necessary because being too "smart"
356 * about what the user might want leads to complications.
357 * (eg. given no slice or partition value, with a disk that is
358 * sliced - are they after the first BSD slice, or the DOS
362 efifs_dev_open(struct open_file
*f
, ...)
365 struct efi_devdesc
*dev
;
369 dev
= va_arg(args
, struct efi_devdesc
*);
372 unit
= dev
->d_kind
.efidisk
.unit
;
373 if (unit
< 0 || unit
>= fs_handle_count
) {
374 printf("attempt to open nonexistent EFI filesystem\n");
378 dev
->d_handle
= fs_handles
[unit
];
384 efifs_dev_close(struct open_file
*f
)
391 efifs_dev_strategy(void *devdata
, int rw
, daddr_t dblk
, size_t size
, void *buf
, size_t *rsize
)