1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * EFI utils 4 * 5 * Copyright (c) 2017 Rob Clark 6 */ 7 8 #include <common.h> 9 #include <charset.h> 10 #include <efi_loader.h> 11 #include <malloc.h> 12 #include <mapmem.h> 13 #include <fs.h> 14 15 /* GUID for file system information */ 16 const efi_guid_t efi_file_system_info_guid = EFI_FILE_SYSTEM_INFO_GUID; 17 18 struct file_system { 19 struct efi_simple_file_system_protocol base; 20 struct efi_device_path *dp; 21 struct blk_desc *desc; 22 int part; 23 }; 24 #define to_fs(x) container_of(x, struct file_system, base) 25 26 struct file_handle { 27 struct efi_file_handle base; 28 struct file_system *fs; 29 loff_t offset; /* current file position/cursor */ 30 int isdir; 31 32 /* for reading a directory: */ 33 struct fs_dir_stream *dirs; 34 struct fs_dirent *dent; 35 36 char path[0]; 37 }; 38 #define to_fh(x) container_of(x, struct file_handle, base) 39 40 static const struct efi_file_handle efi_file_handle_protocol; 41 42 static char *basename(struct file_handle *fh) 43 { 44 char *s = strrchr(fh->path, '/'); 45 if (s) 46 return s + 1; 47 return fh->path; 48 } 49 50 static int set_blk_dev(struct file_handle *fh) 51 { 52 return fs_set_blk_dev_with_part(fh->fs->desc, fh->fs->part); 53 } 54 55 static int is_dir(struct file_handle *fh) 56 { 57 struct fs_dir_stream *dirs; 58 59 set_blk_dev(fh); 60 dirs = fs_opendir(fh->path); 61 if (!dirs) 62 return 0; 63 64 fs_closedir(dirs); 65 66 return 1; 67 } 68 69 /* 70 * Normalize a path which may include either back or fwd slashes, 71 * double slashes, . or .. entries in the path, etc. 72 */ 73 static int sanitize_path(char *path) 74 { 75 char *p; 76 77 /* backslash to slash: */ 78 p = path; 79 while ((p = strchr(p, '\\'))) 80 *p++ = '/'; 81 82 /* handle double-slashes: */ 83 p = path; 84 while ((p = strstr(p, "//"))) { 85 char *src = p + 1; 86 memmove(p, src, strlen(src) + 1); 87 } 88 89 /* handle extra /.'s */ 90 p = path; 91 while ((p = strstr(p, "/."))) { 92 /* 93 * You'd be tempted to do this *after* handling ".."s 94 * below to avoid having to check if "/." is start of 95 * a "/..", but that won't have the correct results.. 96 * for example, "/foo/./../bar" would get resolved to 97 * "/foo/bar" if you did these two passes in the other 98 * order 99 */ 100 if (p[2] == '.') { 101 p += 2; 102 continue; 103 } 104 char *src = p + 2; 105 memmove(p, src, strlen(src) + 1); 106 } 107 108 /* handle extra /..'s: */ 109 p = path; 110 while ((p = strstr(p, "/.."))) { 111 char *src = p + 3; 112 113 p--; 114 115 /* find beginning of previous path entry: */ 116 while (true) { 117 if (p < path) 118 return -1; 119 if (*p == '/') 120 break; 121 p--; 122 } 123 124 memmove(p, src, strlen(src) + 1); 125 } 126 127 return 0; 128 } 129 130 /** 131 * file_open() - open a file handle 132 * 133 * @fs: file system 134 * @parent: directory relative to which the file is to be opened 135 * @file_name: path of the file to be opened. '\', '.', or '..' may 136 * be used as modifiers. A leading backslash indicates an 137 * absolute path. 138 * @mode: bit mask indicating the access mode (read, write, 139 * create) 140 * @attributes: attributes for newly created file 141 * Returns: handle to the opened file or NULL 142 */ 143 static struct efi_file_handle *file_open(struct file_system *fs, 144 struct file_handle *parent, s16 *file_name, u64 mode, 145 u64 attributes) 146 { 147 struct file_handle *fh; 148 char f0[MAX_UTF8_PER_UTF16] = {0}; 149 int plen = 0; 150 int flen = 0; 151 152 if (file_name) { 153 utf16_to_utf8((u8 *)f0, (u16 *)file_name, 1); 154 flen = u16_strlen((u16 *)file_name); 155 } 156 157 /* we could have a parent, but also an absolute path: */ 158 if (f0[0] == '\\') { 159 plen = 0; 160 } else if (parent) { 161 plen = strlen(parent->path) + 1; 162 } 163 164 /* +2 is for null and '/' */ 165 fh = calloc(1, sizeof(*fh) + plen + (flen * MAX_UTF8_PER_UTF16) + 2); 166 167 fh->base = efi_file_handle_protocol; 168 fh->fs = fs; 169 170 if (parent) { 171 char *p = fh->path; 172 173 if (plen > 0) { 174 strcpy(p, parent->path); 175 p += plen - 1; 176 *p++ = '/'; 177 } 178 179 utf16_to_utf8((u8 *)p, (u16 *)file_name, flen); 180 181 if (sanitize_path(fh->path)) 182 goto error; 183 184 /* check if file exists: */ 185 if (set_blk_dev(fh)) 186 goto error; 187 188 if ((mode & EFI_FILE_MODE_CREATE) && 189 (attributes & EFI_FILE_DIRECTORY)) { 190 if (fs_mkdir(fh->path)) 191 goto error; 192 } else if (!((mode & EFI_FILE_MODE_CREATE) || 193 fs_exists(fh->path))) 194 goto error; 195 196 /* figure out if file is a directory: */ 197 fh->isdir = is_dir(fh); 198 } else { 199 fh->isdir = 1; 200 strcpy(fh->path, ""); 201 } 202 203 return &fh->base; 204 205 error: 206 free(fh); 207 return NULL; 208 } 209 210 static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file, 211 struct efi_file_handle **new_handle, 212 s16 *file_name, u64 open_mode, u64 attributes) 213 { 214 struct file_handle *fh = to_fh(file); 215 efi_status_t ret; 216 217 EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", file, new_handle, file_name, 218 open_mode, attributes); 219 220 /* Check parameters */ 221 if (!file || !new_handle || !file_name) { 222 ret = EFI_INVALID_PARAMETER; 223 goto out; 224 } 225 if (open_mode != EFI_FILE_MODE_READ && 226 open_mode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE) && 227 open_mode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | 228 EFI_FILE_MODE_CREATE)) { 229 ret = EFI_INVALID_PARAMETER; 230 goto out; 231 } 232 /* 233 * The UEFI spec requires that attributes are only set in create mode. 234 * The SCT does not care about this and sets EFI_FILE_DIRECTORY in 235 * read mode. EDK2 does not check that attributes are zero if not in 236 * create mode. 237 * 238 * So here we only check attributes in create mode and do not check 239 * that they are zero otherwise. 240 */ 241 if ((open_mode & EFI_FILE_MODE_CREATE) && 242 (attributes & (EFI_FILE_READ_ONLY | ~EFI_FILE_VALID_ATTR))) { 243 ret = EFI_INVALID_PARAMETER; 244 goto out; 245 } 246 247 /* Open file */ 248 *new_handle = file_open(fh->fs, fh, file_name, open_mode, attributes); 249 if (*new_handle) 250 ret = EFI_SUCCESS; 251 else 252 ret = EFI_NOT_FOUND; 253 out: 254 return EFI_EXIT(ret); 255 } 256 257 static efi_status_t file_close(struct file_handle *fh) 258 { 259 fs_closedir(fh->dirs); 260 free(fh); 261 return EFI_SUCCESS; 262 } 263 264 static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file) 265 { 266 struct file_handle *fh = to_fh(file); 267 EFI_ENTRY("%p", file); 268 return EFI_EXIT(file_close(fh)); 269 } 270 271 static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file) 272 { 273 struct file_handle *fh = to_fh(file); 274 efi_status_t ret = EFI_SUCCESS; 275 276 EFI_ENTRY("%p", file); 277 278 if (set_blk_dev(fh)) { 279 ret = EFI_DEVICE_ERROR; 280 goto error; 281 } 282 283 if (fs_unlink(fh->path)) 284 ret = EFI_DEVICE_ERROR; 285 file_close(fh); 286 287 error: 288 return EFI_EXIT(ret); 289 } 290 291 static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size, 292 void *buffer) 293 { 294 loff_t actread; 295 296 if (fs_read(fh->path, map_to_sysmem(buffer), fh->offset, 297 *buffer_size, &actread)) 298 return EFI_DEVICE_ERROR; 299 300 *buffer_size = actread; 301 fh->offset += actread; 302 303 return EFI_SUCCESS; 304 } 305 306 static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size, 307 void *buffer) 308 { 309 struct efi_file_info *info = buffer; 310 struct fs_dirent *dent; 311 unsigned int required_size; 312 313 if (!fh->dirs) { 314 assert(fh->offset == 0); 315 fh->dirs = fs_opendir(fh->path); 316 if (!fh->dirs) 317 return EFI_DEVICE_ERROR; 318 } 319 320 /* 321 * So this is a bit awkward. Since fs layer is stateful and we 322 * can't rewind an entry, in the EFI_BUFFER_TOO_SMALL case below 323 * we might have to return without consuming the dent.. so we 324 * have to stash it for next call. 325 */ 326 if (fh->dent) { 327 dent = fh->dent; 328 fh->dent = NULL; 329 } else { 330 dent = fs_readdir(fh->dirs); 331 } 332 333 334 if (!dent) { 335 /* no more files in directory: */ 336 /* workaround shim.efi bug/quirk.. as find_boot_csv() 337 * loops through directory contents, it initially calls 338 * read w/ zero length buffer to find out how much mem 339 * to allocate for the EFI_FILE_INFO, then allocates, 340 * and then calls a 2nd time. If we return size of 341 * zero the first time, it happily passes that to 342 * AllocateZeroPool(), and when that returns NULL it 343 * thinks it is EFI_OUT_OF_RESOURCES. So on first 344 * call return a non-zero size: 345 */ 346 if (*buffer_size == 0) 347 *buffer_size = sizeof(*info); 348 else 349 *buffer_size = 0; 350 return EFI_SUCCESS; 351 } 352 353 /* check buffer size: */ 354 required_size = sizeof(*info) + 2 * (strlen(dent->name) + 1); 355 if (*buffer_size < required_size) { 356 *buffer_size = required_size; 357 fh->dent = dent; 358 return EFI_BUFFER_TOO_SMALL; 359 } 360 361 *buffer_size = required_size; 362 memset(info, 0, required_size); 363 364 info->size = required_size; 365 info->file_size = dent->size; 366 info->physical_size = dent->size; 367 368 if (dent->type == FS_DT_DIR) 369 info->attribute |= EFI_FILE_DIRECTORY; 370 371 ascii2unicode((u16 *)info->file_name, dent->name); 372 373 fh->offset++; 374 375 return EFI_SUCCESS; 376 } 377 378 static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file, 379 efi_uintn_t *buffer_size, void *buffer) 380 { 381 struct file_handle *fh = to_fh(file); 382 efi_status_t ret = EFI_SUCCESS; 383 u64 bs; 384 385 EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer); 386 387 if (!buffer_size || !buffer) { 388 ret = EFI_INVALID_PARAMETER; 389 goto error; 390 } 391 392 if (set_blk_dev(fh)) { 393 ret = EFI_DEVICE_ERROR; 394 goto error; 395 } 396 397 bs = *buffer_size; 398 if (fh->isdir) 399 ret = dir_read(fh, &bs, buffer); 400 else 401 ret = file_read(fh, &bs, buffer); 402 if (bs <= SIZE_MAX) 403 *buffer_size = bs; 404 else 405 *buffer_size = SIZE_MAX; 406 407 error: 408 return EFI_EXIT(ret); 409 } 410 411 static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file, 412 efi_uintn_t *buffer_size, 413 void *buffer) 414 { 415 struct file_handle *fh = to_fh(file); 416 efi_status_t ret = EFI_SUCCESS; 417 loff_t actwrite; 418 419 EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer); 420 421 if (set_blk_dev(fh)) { 422 ret = EFI_DEVICE_ERROR; 423 goto error; 424 } 425 426 if (fs_write(fh->path, map_to_sysmem(buffer), fh->offset, *buffer_size, 427 &actwrite)) { 428 ret = EFI_DEVICE_ERROR; 429 goto error; 430 } 431 432 *buffer_size = actwrite; 433 fh->offset += actwrite; 434 435 error: 436 return EFI_EXIT(ret); 437 } 438 439 static efi_status_t EFIAPI efi_file_getpos(struct efi_file_handle *file, 440 efi_uintn_t *pos) 441 { 442 struct file_handle *fh = to_fh(file); 443 444 EFI_ENTRY("%p, %p", file, pos); 445 446 if (fh->offset <= SIZE_MAX) { 447 *pos = fh->offset; 448 return EFI_EXIT(EFI_SUCCESS); 449 } else { 450 return EFI_EXIT(EFI_DEVICE_ERROR); 451 } 452 } 453 454 static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file, 455 efi_uintn_t pos) 456 { 457 struct file_handle *fh = to_fh(file); 458 efi_status_t ret = EFI_SUCCESS; 459 460 EFI_ENTRY("%p, %zu", file, pos); 461 462 if (fh->isdir) { 463 if (pos != 0) { 464 ret = EFI_UNSUPPORTED; 465 goto error; 466 } 467 fs_closedir(fh->dirs); 468 fh->dirs = NULL; 469 } 470 471 if (pos == ~0ULL) { 472 loff_t file_size; 473 474 if (set_blk_dev(fh)) { 475 ret = EFI_DEVICE_ERROR; 476 goto error; 477 } 478 479 if (fs_size(fh->path, &file_size)) { 480 ret = EFI_DEVICE_ERROR; 481 goto error; 482 } 483 484 pos = file_size; 485 } 486 487 fh->offset = pos; 488 489 error: 490 return EFI_EXIT(ret); 491 } 492 493 static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file, 494 const efi_guid_t *info_type, 495 efi_uintn_t *buffer_size, 496 void *buffer) 497 { 498 struct file_handle *fh = to_fh(file); 499 efi_status_t ret = EFI_SUCCESS; 500 501 EFI_ENTRY("%p, %pUl, %p, %p", file, info_type, buffer_size, buffer); 502 503 if (!guidcmp(info_type, &efi_file_info_guid)) { 504 struct efi_file_info *info = buffer; 505 char *filename = basename(fh); 506 unsigned int required_size; 507 loff_t file_size; 508 509 /* check buffer size: */ 510 required_size = sizeof(*info) + 2 * (strlen(filename) + 1); 511 if (*buffer_size < required_size) { 512 *buffer_size = required_size; 513 ret = EFI_BUFFER_TOO_SMALL; 514 goto error; 515 } 516 517 if (set_blk_dev(fh)) { 518 ret = EFI_DEVICE_ERROR; 519 goto error; 520 } 521 522 if (fs_size(fh->path, &file_size)) { 523 ret = EFI_DEVICE_ERROR; 524 goto error; 525 } 526 527 memset(info, 0, required_size); 528 529 info->size = required_size; 530 info->file_size = file_size; 531 info->physical_size = file_size; 532 533 if (fh->isdir) 534 info->attribute |= EFI_FILE_DIRECTORY; 535 536 ascii2unicode((u16 *)info->file_name, filename); 537 } else if (!guidcmp(info_type, &efi_file_system_info_guid)) { 538 struct efi_file_system_info *info = buffer; 539 disk_partition_t part; 540 efi_uintn_t required_size; 541 int r; 542 543 if (fh->fs->part >= 1) 544 r = part_get_info(fh->fs->desc, fh->fs->part, &part); 545 else 546 r = part_get_info_whole_disk(fh->fs->desc, &part); 547 if (r < 0) { 548 ret = EFI_DEVICE_ERROR; 549 goto error; 550 } 551 required_size = sizeof(info) + 2 * 552 (strlen((const char *)part.name) + 1); 553 if (*buffer_size < required_size) { 554 *buffer_size = required_size; 555 ret = EFI_BUFFER_TOO_SMALL; 556 goto error; 557 } 558 559 memset(info, 0, required_size); 560 561 info->size = required_size; 562 info->read_only = true; 563 info->volume_size = part.size * part.blksz; 564 info->free_space = 0; 565 info->block_size = part.blksz; 566 /* 567 * TODO: The volume label is not available in U-Boot. 568 * Use the partition name as substitute. 569 */ 570 ascii2unicode((u16 *)info->volume_label, 571 (const char *)part.name); 572 } else { 573 ret = EFI_UNSUPPORTED; 574 } 575 576 error: 577 return EFI_EXIT(ret); 578 } 579 580 static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file, 581 const efi_guid_t *info_type, 582 efi_uintn_t buffer_size, 583 void *buffer) 584 { 585 EFI_ENTRY("%p, %p, %zu, %p", file, info_type, buffer_size, buffer); 586 587 return EFI_EXIT(EFI_UNSUPPORTED); 588 } 589 590 static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file) 591 { 592 EFI_ENTRY("%p", file); 593 return EFI_EXIT(EFI_SUCCESS); 594 } 595 596 static const struct efi_file_handle efi_file_handle_protocol = { 597 .rev = EFI_FILE_PROTOCOL_REVISION, 598 .open = efi_file_open, 599 .close = efi_file_close, 600 .delete = efi_file_delete, 601 .read = efi_file_read, 602 .write = efi_file_write, 603 .getpos = efi_file_getpos, 604 .setpos = efi_file_setpos, 605 .getinfo = efi_file_getinfo, 606 .setinfo = efi_file_setinfo, 607 .flush = efi_file_flush, 608 }; 609 610 struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp) 611 { 612 struct efi_simple_file_system_protocol *v; 613 struct efi_file_handle *f; 614 efi_status_t ret; 615 616 v = efi_fs_from_path(fp); 617 if (!v) 618 return NULL; 619 620 EFI_CALL(ret = v->open_volume(v, &f)); 621 if (ret != EFI_SUCCESS) 622 return NULL; 623 624 /* skip over device-path nodes before the file path: */ 625 while (fp && !EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) 626 fp = efi_dp_next(fp); 627 628 while (fp) { 629 struct efi_device_path_file_path *fdp = 630 container_of(fp, struct efi_device_path_file_path, dp); 631 struct efi_file_handle *f2; 632 633 if (!EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) { 634 printf("bad file path!\n"); 635 f->close(f); 636 return NULL; 637 } 638 639 EFI_CALL(ret = f->open(f, &f2, (s16 *)fdp->str, 640 EFI_FILE_MODE_READ, 0)); 641 if (ret != EFI_SUCCESS) 642 return NULL; 643 644 fp = efi_dp_next(fp); 645 646 EFI_CALL(f->close(f)); 647 f = f2; 648 } 649 650 return f; 651 } 652 653 static efi_status_t EFIAPI 654 efi_open_volume(struct efi_simple_file_system_protocol *this, 655 struct efi_file_handle **root) 656 { 657 struct file_system *fs = to_fs(this); 658 659 EFI_ENTRY("%p, %p", this, root); 660 661 *root = file_open(fs, NULL, NULL, 0, 0); 662 663 return EFI_EXIT(EFI_SUCCESS); 664 } 665 666 struct efi_simple_file_system_protocol * 667 efi_simple_file_system(struct blk_desc *desc, int part, 668 struct efi_device_path *dp) 669 { 670 struct file_system *fs; 671 672 fs = calloc(1, sizeof(*fs)); 673 fs->base.rev = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION; 674 fs->base.open_volume = efi_open_volume; 675 fs->desc = desc; 676 fs->part = part; 677 fs->dp = dp; 678 679 return &fs->base; 680 } 681