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