2 * Copyright (c) 2001 Doug Rabson
3 * Copyright (c) 2006 Marcel Moolenaar
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
36 #include <bootstrap.h>
42 /* Perform I/O in blocks of size EFI_BLOCK_SIZE. */
43 #define EFI_BLOCK_SIZE (1024 * 1024)
47 char bytes[sizeof(EFI_FILE_INFO) + 508];
50 static EFI_GUID sfs_guid = SIMPLE_FILE_SYSTEM_PROTOCOL;
51 static EFI_GUID fs_guid = EFI_FILE_SYSTEM_INFO_ID;
52 static EFI_GUID fi_guid = EFI_FILE_INFO_ID;
55 efifs_open(const char *upath, struct open_file *f)
57 struct devdesc *dev = f->f_devdata;
58 EFI_FILE_IO_INTERFACE *fsif;
59 EFI_FILE *file, *root;
64 if (f->f_dev != &efifs_dev || dev->d_unit < 0)
67 h = efi_find_handle(f->f_dev, dev->d_unit);
71 status = BS->HandleProtocol(h, &sfs_guid, (VOID **)&fsif);
72 if (EFI_ERROR(status))
73 return (efi_status_to_errno(status));
75 /* Get the root directory. */
76 status = fsif->OpenVolume(fsif, &root);
77 if (EFI_ERROR(status))
78 return (efi_status_to_errno(status));
83 /* Special case: opening the root directory. */
89 path = malloc((strlen(upath) + 1) * sizeof(CHAR16));
96 while (*upath != '\0') {
99 while (upath[1] == '/')
109 status = root->Open(root, &file, path,
110 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
111 if (status == EFI_ACCESS_DENIED || status == EFI_WRITE_PROTECTED)
112 status = root->Open(root, &file, path, EFI_FILE_MODE_READ, 0);
115 if (EFI_ERROR(status))
116 return (efi_status_to_errno(status));
123 efifs_close(struct open_file *f)
125 EFI_FILE *file = f->f_fsdata;
136 efifs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
138 EFI_FILE *file = f->f_fsdata;
149 if (sz > EFI_BLOCK_SIZE)
151 status = file->Read(file, &sz, bufp);
152 if (EFI_ERROR(status))
153 return (efi_status_to_errno(status));
165 efifs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
167 EFI_FILE *file = f->f_fsdata;
178 if (sz > EFI_BLOCK_SIZE)
180 status = file->Write(file, &sz, bufp);
181 if (EFI_ERROR(status))
182 return (efi_status_to_errno(status));
194 efifs_seek(struct open_file *f, off_t offset, int where)
196 EFI_FILE *file = f->f_fsdata;
208 status = file->SetPosition(file, ~0ULL);
209 if (EFI_ERROR(status))
214 status = file->GetPosition(file, &base);
215 if (EFI_ERROR(status))
217 offset = (off_t)(base + offset);
226 status = file->SetPosition(file, (UINT64)offset);
227 return (EFI_ERROR(status) ? -1 : offset);
231 efifs_stat(struct open_file *f, struct stat *sb)
233 EFI_FILE *file = f->f_fsdata;
241 bzero(sb, sizeof(*sb));
244 status = file->GetInfo(file, &fi_guid, &sz, &fi);
245 if (EFI_ERROR(status))
246 return (efi_status_to_errno(status));
248 sb->st_mode = S_IRUSR | S_IRGRP | S_IROTH;
249 if ((fi.info.Attribute & EFI_FILE_READ_ONLY) == 0)
250 sb->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
251 if (fi.info.Attribute & EFI_FILE_DIRECTORY)
252 sb->st_mode |= S_IFDIR;
254 sb->st_mode |= S_IFREG;
256 sb->st_atime = efi_time(&fi.info.LastAccessTime);
257 sb->st_mtime = efi_time(&fi.info.ModificationTime);
258 sb->st_ctime = efi_time(&fi.info.CreateTime);
259 sb->st_size = fi.info.FileSize;
260 sb->st_blocks = fi.info.PhysicalSize / S_BLKSIZE;
261 sb->st_blksize = S_BLKSIZE;
262 sb->st_birthtime = sb->st_ctime;
267 efifs_readdir(struct open_file *f, struct dirent *d)
269 EFI_FILE *file = f->f_fsdata;
279 status = file->Read(file, &sz, &fi);
280 if (EFI_ERROR(status))
281 return (efi_status_to_errno(status));
286 d->d_reclen = sizeof(*d);
287 if (fi.info.Attribute & EFI_FILE_DIRECTORY)
291 for (i = 0; fi.info.FileName[i] != 0; i++)
292 d->d_name[i] = fi.info.FileName[i];
298 struct fs_ops efifs_fsops = {
300 .fo_open = efifs_open,
301 .fo_close = efifs_close,
302 .fo_read = efifs_read,
303 .fo_write = efifs_write,
304 .fo_seek = efifs_seek,
305 .fo_stat = efifs_stat,
306 .fo_readdir = efifs_readdir
318 status = BS->LocateHandle(ByProtocol, &sfs_guid, 0, &sz, 0);
319 if (status == EFI_BUFFER_TOO_SMALL) {
320 handles = (EFI_HANDLE *)malloc(sz);
321 status = BS->LocateHandle(ByProtocol, &sfs_guid, 0, &sz,
323 if (EFI_ERROR(status))
326 if (EFI_ERROR(status))
327 return (efi_status_to_errno(status));
328 err = efi_register_handles(&efifs_dev, handles,
329 sz / sizeof(EFI_HANDLE));
335 * Print information about disks
338 efifs_dev_print(int verbose)
341 EFI_FILE_SYSTEM_INFO info;
345 EFI_FILE_IO_INTERFACE *fsif;
352 for (unit = 0, h = efi_find_handle(&efifs_dev, 0);
353 h != NULL; h = efi_find_handle(&efifs_dev, ++unit)) {
354 sprintf(line, " %s%d: ", efifs_dev.dv_name, unit);
357 status = BS->HandleProtocol(h, &sfs_guid, (VOID **)&fsif);
358 if (EFI_ERROR(status))
361 status = fsif->OpenVolume(fsif, &volume);
362 if (EFI_ERROR(status))
366 status = volume->GetInfo(volume, &fs_guid, &sz, &fi);
367 volume->Close(volume);
368 if (EFI_ERROR(status))
371 if (fi.info.ReadOnly)
372 pager_output("[RO] ");
375 for (i = 0; fi.info.VolumeLabel[i] != 0; i++)
376 fi.buffer[i] = fi.info.VolumeLabel[i];
378 if (fi.buffer[0] != 0)
379 pager_output(fi.buffer);
381 pager_output("EFI filesystem");
386 sprintf(line, "[--] error %d: unable to obtain information\n",
387 efi_status_to_errno(status));
393 * Attempt to open the disk described by (dev) for use by (f).
395 * Note that the philosophy here is "give them exactly what
396 * they ask for". This is necessary because being too "smart"
397 * about what the user might want leads to complications.
398 * (eg. given no slice or partition value, with a disk that is
399 * sliced - are they after the first BSD slice, or the DOS
403 efifs_dev_open(struct open_file *f, ...)
409 dev = va_arg(args, struct devdesc*);
418 efifs_dev_close(struct open_file *f)
425 efifs_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize)
431 struct devsw efifs_dev = {
433 .dv_type = DEVT_DISK,
434 .dv_init = efifs_dev_init,
435 .dv_strategy = efifs_dev_strategy,
436 .dv_open = efifs_dev_open,
437 .dv_close = efifs_dev_close,
439 .dv_print = efifs_dev_print,