1 1.6 christos /* $NetBSD: efifs.c,v 1.6 2014/03/25 18:35:33 christos Exp $ */ 2 1.1 cherry 3 1.1 cherry /*- 4 1.1 cherry * Copyright (c) 2001 Doug Rabson 5 1.1 cherry * All rights reserved. 6 1.1 cherry * 7 1.1 cherry * Redistribution and use in source and binary forms, with or without 8 1.1 cherry * modification, are permitted provided that the following conditions 9 1.1 cherry * are met: 10 1.1 cherry * 1. Redistributions of source code must retain the above copyright 11 1.1 cherry * notice, this list of conditions and the following disclaimer. 12 1.1 cherry * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cherry * notice, this list of conditions and the following disclaimer in the 14 1.1 cherry * documentation and/or other materials provided with the distribution. 15 1.1 cherry * 16 1.1 cherry * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.1 cherry * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 cherry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 cherry * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.1 cherry * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 cherry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 cherry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 cherry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 cherry * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 cherry * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 cherry * SUCH DAMAGE. 27 1.1 cherry * 28 1.2 cherry * $FreeBSD: src/sys/boot/efi/libefi/efifs.c,v 1.8 2003/08/02 08:22:03 marcel Exp $ 29 1.1 cherry */ 30 1.1 cherry 31 1.1 cherry #include <sys/time.h> 32 1.1 cherry #include <sys/dirent.h> 33 1.1 cherry #include <lib/libsa/stand.h> 34 1.4 kiyohara #include <lib/libsa/loadfile.h> 35 1.1 cherry #include <lib/libkern/libkern.h> 36 1.1 cherry 37 1.1 cherry #include <efi.h> 38 1.1 cherry #include <efilib.h> 39 1.1 cherry 40 1.1 cherry #include <bootstrap.h> 41 1.1 cherry 42 1.1 cherry #include "efiboot.h" 43 1.1 cherry 44 1.1 cherry /* Perform I/O in blocks of size EFI_BLOCK_SIZE. */ 45 1.1 cherry #define EFI_BLOCK_SIZE (1024 * 1024) 46 1.1 cherry 47 1.1 cherry 48 1.1 cherry int 49 1.1 cherry efifs_open(const char *upath, struct open_file *f) 50 1.1 cherry { 51 1.1 cherry struct efi_devdesc *dev = f->f_devdata; 52 1.1 cherry static EFI_GUID sfsid = SIMPLE_FILE_SYSTEM_PROTOCOL; 53 1.1 cherry EFI_FILE_IO_INTERFACE *sfs; 54 1.1 cherry EFI_FILE *root; 55 1.1 cherry EFI_FILE *file; 56 1.1 cherry EFI_STATUS status; 57 1.1 cherry CHAR16 *cp; 58 1.1 cherry CHAR16 *path; 59 1.1 cherry 60 1.1 cherry /* 61 1.1 cherry * We cannot blindly assume that f->f_devdata points to a 62 1.1 cherry * efi_devdesc structure. Before we dereference 'dev', make 63 1.1 cherry * sure that the underlying device is ours. 64 1.1 cherry */ 65 1.1 cherry if (f->f_dev != &devsw[0] || dev->d_handle == NULL) 66 1.1 cherry return ENOENT; 67 1.1 cherry 68 1.1 cherry status = BS->HandleProtocol(dev->d_handle, &sfsid, (VOID **)&sfs); 69 1.1 cherry if (EFI_ERROR(status)) 70 1.1 cherry return ENOENT; 71 1.1 cherry 72 1.1 cherry /* 73 1.1 cherry * Find the root directory. 74 1.1 cherry */ 75 1.1 cherry status = sfs->OpenVolume(sfs, &root); 76 1.1 cherry 77 1.1 cherry /* 78 1.1 cherry * Convert path to CHAR16, skipping leading separators. 79 1.1 cherry */ 80 1.1 cherry while (*upath == '/') 81 1.1 cherry upath++; 82 1.1 cherry if (!*upath) { 83 1.1 cherry /* Opening the root directory, */ 84 1.1 cherry f->f_fsdata = root; 85 1.1 cherry return 0; 86 1.1 cherry } 87 1.1 cherry cp = path = alloc((strlen(upath) + 1) * sizeof(CHAR16)); 88 1.1 cherry if (path == NULL) 89 1.1 cherry return ENOMEM; 90 1.1 cherry while (*upath) { 91 1.1 cherry if (*upath == '/') 92 1.1 cherry *cp = '\\'; 93 1.1 cherry else 94 1.1 cherry *cp = *upath; 95 1.1 cherry upath++; 96 1.1 cherry cp++; 97 1.1 cherry } 98 1.1 cherry *cp++ = 0; 99 1.1 cherry 100 1.1 cherry /* 101 1.1 cherry * Try to open it. 102 1.1 cherry */ 103 1.1 cherry status = root->Open(root, &file, path, EFI_FILE_MODE_READ, 0); 104 1.1 cherry free(path); 105 1.1 cherry if (EFI_ERROR(status)) { 106 1.1 cherry root->Close(root); 107 1.1 cherry return ENOENT; 108 1.1 cherry } 109 1.1 cherry 110 1.1 cherry root->Close(root); 111 1.1 cherry f->f_fsdata = file; 112 1.1 cherry return 0; 113 1.1 cherry } 114 1.1 cherry 115 1.1 cherry int 116 1.1 cherry efifs_close(struct open_file *f) 117 1.1 cherry { 118 1.1 cherry EFI_FILE *file = f->f_fsdata; 119 1.1 cherry 120 1.1 cherry file->Close(file); 121 1.1 cherry return 0; 122 1.1 cherry } 123 1.1 cherry 124 1.1 cherry int 125 1.1 cherry efifs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 126 1.1 cherry { 127 1.1 cherry EFI_FILE *file = f->f_fsdata; 128 1.1 cherry EFI_STATUS status; 129 1.1 cherry UINTN sz = size; 130 1.1 cherry char *bufp; 131 1.1 cherry 132 1.1 cherry bufp = buf; 133 1.1 cherry while (size > 0) { 134 1.1 cherry sz = size; 135 1.1 cherry if (sz > EFI_BLOCK_SIZE) 136 1.1 cherry sz = EFI_BLOCK_SIZE; 137 1.1 cherry status = file->Read(file, &sz, bufp); 138 1.1 cherry 139 1.1 cherry #if !defined(LIBSA_NO_TWIDDLE) 140 1.1 cherry twiddle(); 141 1.1 cherry #endif 142 1.1 cherry 143 1.1 cherry if (EFI_ERROR(status)) 144 1.1 cherry return EIO; 145 1.1 cherry if (sz == 0) 146 1.1 cherry break; 147 1.1 cherry size -= sz; 148 1.1 cherry bufp += sz; 149 1.1 cherry } 150 1.1 cherry if (resid) 151 1.1 cherry *resid = size; 152 1.1 cherry return 0; 153 1.1 cherry } 154 1.1 cherry 155 1.1 cherry int 156 1.1 cherry efifs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 157 1.1 cherry { 158 1.1 cherry EFI_FILE *file = f->f_fsdata; 159 1.1 cherry EFI_STATUS status; 160 1.1 cherry UINTN sz = size; 161 1.1 cherry char *bufp; 162 1.1 cherry 163 1.1 cherry bufp = buf; 164 1.1 cherry while (size > 0) { 165 1.1 cherry sz = size; 166 1.1 cherry if (sz > EFI_BLOCK_SIZE) 167 1.1 cherry sz = EFI_BLOCK_SIZE; 168 1.1 cherry status = file->Write(file, &sz, bufp); 169 1.1 cherry 170 1.1 cherry #if !defined(LIBSA_NO_TWIDDLE) 171 1.1 cherry twiddle(); 172 1.1 cherry #endif 173 1.1 cherry 174 1.1 cherry if (EFI_ERROR(status)) 175 1.1 cherry return EIO; 176 1.1 cherry if (sz == 0) 177 1.1 cherry break; 178 1.1 cherry size -= sz; 179 1.1 cherry bufp += sz; 180 1.1 cherry } 181 1.1 cherry if (resid) 182 1.1 cherry *resid = size; 183 1.1 cherry return 0; 184 1.1 cherry } 185 1.1 cherry 186 1.1 cherry off_t 187 1.1 cherry efifs_seek(struct open_file *f, off_t offset, int where) 188 1.1 cherry { 189 1.1 cherry EFI_FILE *file = f->f_fsdata; 190 1.1 cherry EFI_STATUS status; 191 1.1 cherry UINT64 base; 192 1.1 cherry UINTN sz; 193 1.1 cherry static EFI_GUID infoid = EFI_FILE_INFO_ID; 194 1.1 cherry EFI_FILE_INFO info; 195 1.1 cherry 196 1.1 cherry switch (where) { 197 1.1 cherry case SEEK_SET: 198 1.1 cherry base = 0; 199 1.1 cherry break; 200 1.1 cherry 201 1.1 cherry case SEEK_CUR: 202 1.1 cherry status = file->GetPosition(file, &base); 203 1.1 cherry if (EFI_ERROR(status)) 204 1.1 cherry return -1; 205 1.1 cherry break; 206 1.1 cherry 207 1.1 cherry case SEEK_END: 208 1.1 cherry sz = sizeof(info); 209 1.1 cherry status = file->GetInfo(file, &infoid, &sz, &info); 210 1.1 cherry if (EFI_ERROR(status)) 211 1.1 cherry return -1; 212 1.1 cherry base = info.FileSize; 213 1.1 cherry break; 214 1.1 cherry } 215 1.1 cherry 216 1.1 cherry status = file->SetPosition(file, base + offset); 217 1.1 cherry if (EFI_ERROR(status)) 218 1.1 cherry return -1; 219 1.1 cherry file->GetPosition(file, &base); 220 1.1 cherry 221 1.1 cherry return base; 222 1.1 cherry } 223 1.1 cherry 224 1.1 cherry int 225 1.1 cherry efifs_stat(struct open_file *f, struct stat *sb) 226 1.1 cherry { 227 1.1 cherry EFI_FILE *file = f->f_fsdata; 228 1.1 cherry EFI_STATUS status; 229 1.1 cherry char *buf; 230 1.1 cherry UINTN sz; 231 1.1 cherry static EFI_GUID infoid = EFI_FILE_INFO_ID; 232 1.1 cherry EFI_FILE_INFO *info; 233 1.1 cherry 234 1.3 cegger memset(sb, 0, sizeof(*sb)); 235 1.1 cherry 236 1.1 cherry buf = alloc(1024); 237 1.1 cherry sz = 1024; 238 1.1 cherry 239 1.1 cherry status = file->GetInfo(file, &infoid, &sz, buf); 240 1.1 cherry if (EFI_ERROR(status)) { 241 1.1 cherry free(buf); 242 1.1 cherry return -1; 243 1.1 cherry } 244 1.1 cherry 245 1.1 cherry info = (EFI_FILE_INFO *) buf; 246 1.1 cherry 247 1.1 cherry if (info->Attribute & EFI_FILE_READ_ONLY) 248 1.1 cherry sb->st_mode = S_IRUSR; 249 1.1 cherry else 250 1.1 cherry sb->st_mode = S_IRUSR | S_IWUSR; 251 1.1 cherry if (info->Attribute & EFI_FILE_DIRECTORY) 252 1.1 cherry sb->st_mode |= S_IFDIR; 253 1.1 cherry else 254 1.1 cherry sb->st_mode |= S_IFREG; 255 1.1 cherry sb->st_size = info->FileSize; 256 1.1 cherry 257 1.1 cherry free(buf); 258 1.1 cherry return 0; 259 1.1 cherry } 260 1.1 cherry 261 1.1 cherry int 262 1.1 cherry efifs_readdir(struct open_file *f, struct dirent *d) 263 1.1 cherry { 264 1.1 cherry EFI_FILE *file = f->f_fsdata; 265 1.1 cherry EFI_STATUS status; 266 1.1 cherry char *buf; 267 1.1 cherry UINTN sz; 268 1.1 cherry EFI_FILE_INFO *info; 269 1.1 cherry int i; 270 1.1 cherry 271 1.1 cherry buf = alloc(1024); 272 1.1 cherry sz = 1024; 273 1.1 cherry 274 1.1 cherry status = file->Read(file, &sz, buf); 275 1.1 cherry if (EFI_ERROR(status) || sz < offsetof(EFI_FILE_INFO, FileName)) 276 1.1 cherry return ENOENT; 277 1.1 cherry 278 1.1 cherry info = (EFI_FILE_INFO *) buf; 279 1.1 cherry 280 1.1 cherry d->d_fileno = 0; 281 1.1 cherry d->d_reclen = sizeof(*d); 282 1.1 cherry if (info->Attribute & EFI_FILE_DIRECTORY) 283 1.1 cherry d->d_type = DT_DIR; 284 1.1 cherry else 285 1.1 cherry d->d_type = DT_REG; 286 1.1 cherry d->d_namlen = ((info->Size - offsetof(EFI_FILE_INFO, FileName)) 287 1.1 cherry / sizeof(CHAR16)); 288 1.1 cherry for (i = 0; i < d->d_namlen; i++) 289 1.1 cherry d->d_name[i] = info->FileName[i]; 290 1.1 cherry d->d_name[i] = 0; 291 1.1 cherry 292 1.1 cherry free(buf); 293 1.1 cherry return 0; 294 1.1 cherry } 295 1.1 cherry 296 1.1 cherry static EFI_HANDLE *fs_handles; 297 1.1 cherry UINTN fs_handle_count; 298 1.1 cherry 299 1.1 cherry int 300 1.1 cherry efifs_get_unit(EFI_HANDLE h) 301 1.1 cherry { 302 1.1 cherry UINTN u; 303 1.1 cherry 304 1.1 cherry u = 0; 305 1.1 cherry while (u < fs_handle_count && fs_handles[u] != h) 306 1.1 cherry u++; 307 1.1 cherry return ((u < fs_handle_count) ? u : -1); 308 1.1 cherry } 309 1.1 cherry 310 1.1 cherry int 311 1.1 cherry efifs_dev_init(void) 312 1.1 cherry { 313 1.1 cherry EFI_STATUS status; 314 1.1 cherry UINTN sz; 315 1.1 cherry static EFI_GUID sfsid = SIMPLE_FILE_SYSTEM_PROTOCOL; 316 1.1 cherry 317 1.1 cherry sz = 0; 318 1.1 cherry status = BS->LocateHandle(ByProtocol, &sfsid, 0, &sz, 0); 319 1.1 cherry if (status != EFI_BUFFER_TOO_SMALL) 320 1.1 cherry return ENOENT; 321 1.1 cherry fs_handles = (EFI_HANDLE *) alloc(sz); 322 1.1 cherry status = BS->LocateHandle(ByProtocol, &sfsid, 0, 323 1.1 cherry &sz, fs_handles); 324 1.1 cherry if (EFI_ERROR(status)) { 325 1.1 cherry free(fs_handles); 326 1.1 cherry return ENOENT; 327 1.1 cherry } 328 1.1 cherry fs_handle_count = sz / sizeof(EFI_HANDLE); 329 1.1 cherry 330 1.1 cherry return 0; 331 1.1 cherry } 332 1.1 cherry 333 1.1 cherry /* 334 1.1 cherry * Print information about disks 335 1.1 cherry */ 336 1.1 cherry void 337 1.1 cherry efifs_dev_print(int verbose) 338 1.1 cherry { 339 1.1 cherry int i; 340 1.1 cherry char line[80]; 341 1.1 cherry 342 1.1 cherry for (i = 0; i < fs_handle_count; i++) { 343 1.6 christos snprintf(line, sizeof(line), " fs%d: EFI filesystem", i); 344 1.1 cherry pager_output(line); 345 1.1 cherry /* XXX more detail? */ 346 1.1 cherry pager_output("\n"); 347 1.1 cherry } 348 1.1 cherry } 349 1.1 cherry 350 1.1 cherry /* 351 1.1 cherry * Attempt to open the disk described by (dev) for use by (f). 352 1.1 cherry * 353 1.1 cherry * Note that the philosophy here is "give them exactly what 354 1.1 cherry * they ask for". This is necessary because being too "smart" 355 1.1 cherry * about what the user might want leads to complications. 356 1.1 cherry * (eg. given no slice or partition value, with a disk that is 357 1.1 cherry * sliced - are they after the first BSD slice, or the DOS 358 1.1 cherry * slice before it?) 359 1.1 cherry */ 360 1.1 cherry int 361 1.1 cherry efifs_dev_open(struct open_file *f, ...) 362 1.1 cherry { 363 1.1 cherry va_list args; 364 1.1 cherry struct efi_devdesc *dev; 365 1.1 cherry int unit; 366 1.1 cherry 367 1.1 cherry va_start(args, f); 368 1.1 cherry dev = va_arg(args, struct efi_devdesc*); 369 1.1 cherry va_end(args); 370 1.1 cherry 371 1.1 cherry unit = dev->d_kind.efidisk.unit; 372 1.1 cherry if (unit < 0 || unit >= fs_handle_count) { 373 1.1 cherry printf("attempt to open nonexistent EFI filesystem\n"); 374 1.1 cherry return(ENXIO); 375 1.1 cherry } 376 1.1 cherry 377 1.1 cherry dev->d_handle = fs_handles[unit]; 378 1.1 cherry 379 1.1 cherry return 0; 380 1.1 cherry } 381 1.1 cherry 382 1.1 cherry int 383 1.1 cherry efifs_dev_close(struct open_file *f) 384 1.1 cherry { 385 1.1 cherry 386 1.1 cherry return 0; 387 1.1 cherry } 388 1.1 cherry 389 1.1 cherry int 390 1.1 cherry efifs_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t size, void *buf, size_t *rsize) 391 1.1 cherry { 392 1.1 cherry return 0; 393 1.1 cherry } 394 1.1 cherry 395