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, s16 *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, (u16 *)file_name, 1); 161 flen = u16_strlen((u16 *)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, (u16 *)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 /* figure out if file is a directory: */ 204 fh->isdir = is_dir(fh); 205 } else { 206 fh->isdir = 1; 207 strcpy(fh->path, ""); 208 } 209 210 return &fh->base; 211 212 error: 213 free(fh); 214 return NULL; 215 } 216 217 static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file, 218 struct efi_file_handle **new_handle, 219 s16 *file_name, u64 open_mode, u64 attributes) 220 { 221 struct file_handle *fh = to_fh(file); 222 efi_status_t ret; 223 224 EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", file, new_handle, file_name, 225 open_mode, attributes); 226 227 /* Check parameters */ 228 if (!file || !new_handle || !file_name) { 229 ret = EFI_INVALID_PARAMETER; 230 goto out; 231 } 232 if (open_mode != EFI_FILE_MODE_READ && 233 open_mode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE) && 234 open_mode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | 235 EFI_FILE_MODE_CREATE)) { 236 ret = EFI_INVALID_PARAMETER; 237 goto out; 238 } 239 /* 240 * The UEFI spec requires that attributes are only set in create mode. 241 * The SCT does not care about this and sets EFI_FILE_DIRECTORY in 242 * read mode. EDK2 does not check that attributes are zero if not in 243 * create mode. 244 * 245 * So here we only check attributes in create mode and do not check 246 * that they are zero otherwise. 247 */ 248 if ((open_mode & EFI_FILE_MODE_CREATE) && 249 (attributes & (EFI_FILE_READ_ONLY | ~EFI_FILE_VALID_ATTR))) { 250 ret = EFI_INVALID_PARAMETER; 251 goto out; 252 } 253 254 /* Open file */ 255 *new_handle = file_open(fh->fs, fh, file_name, open_mode, attributes); 256 if (*new_handle) 257 ret = EFI_SUCCESS; 258 else 259 ret = EFI_NOT_FOUND; 260 out: 261 return EFI_EXIT(ret); 262 } 263 264 static efi_status_t file_close(struct file_handle *fh) 265 { 266 fs_closedir(fh->dirs); 267 free(fh); 268 return EFI_SUCCESS; 269 } 270 271 static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file) 272 { 273 struct file_handle *fh = to_fh(file); 274 EFI_ENTRY("%p", file); 275 return EFI_EXIT(file_close(fh)); 276 } 277 278 static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file) 279 { 280 struct file_handle *fh = to_fh(file); 281 efi_status_t ret = EFI_SUCCESS; 282 283 EFI_ENTRY("%p", file); 284 285 if (set_blk_dev(fh)) { 286 ret = EFI_DEVICE_ERROR; 287 goto error; 288 } 289 290 if (fs_unlink(fh->path)) 291 ret = EFI_DEVICE_ERROR; 292 file_close(fh); 293 294 error: 295 return EFI_EXIT(ret); 296 } 297 298 static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size, 299 void *buffer) 300 { 301 loff_t actread; 302 303 if (fs_read(fh->path, map_to_sysmem(buffer), fh->offset, 304 *buffer_size, &actread)) 305 return EFI_DEVICE_ERROR; 306 307 *buffer_size = actread; 308 fh->offset += actread; 309 310 return EFI_SUCCESS; 311 } 312 313 static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size, 314 void *buffer) 315 { 316 struct efi_file_info *info = buffer; 317 struct fs_dirent *dent; 318 unsigned int required_size; 319 320 if (!fh->dirs) { 321 assert(fh->offset == 0); 322 fh->dirs = fs_opendir(fh->path); 323 if (!fh->dirs) 324 return EFI_DEVICE_ERROR; 325 } 326 327 /* 328 * So this is a bit awkward. Since fs layer is stateful and we 329 * can't rewind an entry, in the EFI_BUFFER_TOO_SMALL case below 330 * we might have to return without consuming the dent.. so we 331 * have to stash it for next call. 332 */ 333 if (fh->dent) { 334 dent = fh->dent; 335 fh->dent = NULL; 336 } else { 337 dent = fs_readdir(fh->dirs); 338 } 339 340 341 if (!dent) { 342 /* no more files in directory: */ 343 /* workaround shim.efi bug/quirk.. as find_boot_csv() 344 * loops through directory contents, it initially calls 345 * read w/ zero length buffer to find out how much mem 346 * to allocate for the EFI_FILE_INFO, then allocates, 347 * and then calls a 2nd time. If we return size of 348 * zero the first time, it happily passes that to 349 * AllocateZeroPool(), and when that returns NULL it 350 * thinks it is EFI_OUT_OF_RESOURCES. So on first 351 * call return a non-zero size: 352 */ 353 if (*buffer_size == 0) 354 *buffer_size = sizeof(*info); 355 else 356 *buffer_size = 0; 357 return EFI_SUCCESS; 358 } 359 360 /* check buffer size: */ 361 required_size = sizeof(*info) + 2 * (strlen(dent->name) + 1); 362 if (*buffer_size < required_size) { 363 *buffer_size = required_size; 364 fh->dent = dent; 365 return EFI_BUFFER_TOO_SMALL; 366 } 367 368 *buffer_size = required_size; 369 memset(info, 0, required_size); 370 371 info->size = required_size; 372 info->file_size = dent->size; 373 info->physical_size = dent->size; 374 375 if (dent->type == FS_DT_DIR) 376 info->attribute |= EFI_FILE_DIRECTORY; 377 378 ascii2unicode((u16 *)info->file_name, dent->name); 379 380 fh->offset++; 381 382 return EFI_SUCCESS; 383 } 384 385 static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file, 386 efi_uintn_t *buffer_size, void *buffer) 387 { 388 struct file_handle *fh = to_fh(file); 389 efi_status_t ret = EFI_SUCCESS; 390 u64 bs; 391 392 EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer); 393 394 if (!buffer_size || !buffer) { 395 ret = EFI_INVALID_PARAMETER; 396 goto error; 397 } 398 399 if (set_blk_dev(fh)) { 400 ret = EFI_DEVICE_ERROR; 401 goto error; 402 } 403 404 bs = *buffer_size; 405 if (fh->isdir) 406 ret = dir_read(fh, &bs, buffer); 407 else 408 ret = file_read(fh, &bs, buffer); 409 if (bs <= SIZE_MAX) 410 *buffer_size = bs; 411 else 412 *buffer_size = SIZE_MAX; 413 414 error: 415 return EFI_EXIT(ret); 416 } 417 418 static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file, 419 efi_uintn_t *buffer_size, 420 void *buffer) 421 { 422 struct file_handle *fh = to_fh(file); 423 efi_status_t ret = EFI_SUCCESS; 424 loff_t actwrite; 425 426 EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer); 427 428 if (set_blk_dev(fh)) { 429 ret = EFI_DEVICE_ERROR; 430 goto error; 431 } 432 433 if (fs_write(fh->path, map_to_sysmem(buffer), fh->offset, *buffer_size, 434 &actwrite)) { 435 ret = EFI_DEVICE_ERROR; 436 goto error; 437 } 438 439 *buffer_size = actwrite; 440 fh->offset += actwrite; 441 442 error: 443 return EFI_EXIT(ret); 444 } 445 446 /** 447 * efi_file_getpos() - get current position in file 448 * 449 * This function implements the GetPosition service of the EFI file protocol. 450 * See the UEFI spec for details. 451 * 452 * @file: file handle 453 * @pos: pointer to file position 454 * Return: status code 455 */ 456 static efi_status_t EFIAPI efi_file_getpos(struct efi_file_handle *file, 457 u64 *pos) 458 { 459 efi_status_t ret = EFI_SUCCESS; 460 struct file_handle *fh = to_fh(file); 461 462 EFI_ENTRY("%p, %p", file, pos); 463 464 if (fh->isdir) { 465 ret = EFI_UNSUPPORTED; 466 goto out; 467 } 468 469 *pos = fh->offset; 470 out: 471 return EFI_EXIT(ret); 472 } 473 474 /** 475 * efi_file_setpos() - set current position in file 476 * 477 * This function implements the SetPosition service of the EFI file protocol. 478 * See the UEFI spec for details. 479 * 480 * @file: file handle 481 * @pos: new file position 482 * Return: status code 483 */ 484 static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file, 485 u64 pos) 486 { 487 struct file_handle *fh = to_fh(file); 488 efi_status_t ret = EFI_SUCCESS; 489 490 EFI_ENTRY("%p, %llu", file, pos); 491 492 if (fh->isdir) { 493 if (pos != 0) { 494 ret = EFI_UNSUPPORTED; 495 goto error; 496 } 497 fs_closedir(fh->dirs); 498 fh->dirs = NULL; 499 } 500 501 if (pos == ~0ULL) { 502 loff_t file_size; 503 504 if (set_blk_dev(fh)) { 505 ret = EFI_DEVICE_ERROR; 506 goto error; 507 } 508 509 if (fs_size(fh->path, &file_size)) { 510 ret = EFI_DEVICE_ERROR; 511 goto error; 512 } 513 514 pos = file_size; 515 } 516 517 fh->offset = pos; 518 519 error: 520 return EFI_EXIT(ret); 521 } 522 523 static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file, 524 const efi_guid_t *info_type, 525 efi_uintn_t *buffer_size, 526 void *buffer) 527 { 528 struct file_handle *fh = to_fh(file); 529 efi_status_t ret = EFI_SUCCESS; 530 531 EFI_ENTRY("%p, %pUl, %p, %p", file, info_type, buffer_size, buffer); 532 533 if (!guidcmp(info_type, &efi_file_info_guid)) { 534 struct efi_file_info *info = buffer; 535 char *filename = basename(fh); 536 unsigned int required_size; 537 loff_t file_size; 538 539 /* check buffer size: */ 540 required_size = sizeof(*info) + 2 * (strlen(filename) + 1); 541 if (*buffer_size < required_size) { 542 *buffer_size = required_size; 543 ret = EFI_BUFFER_TOO_SMALL; 544 goto error; 545 } 546 547 if (set_blk_dev(fh)) { 548 ret = EFI_DEVICE_ERROR; 549 goto error; 550 } 551 552 if (fs_size(fh->path, &file_size)) { 553 ret = EFI_DEVICE_ERROR; 554 goto error; 555 } 556 557 memset(info, 0, required_size); 558 559 info->size = required_size; 560 info->file_size = file_size; 561 info->physical_size = file_size; 562 563 if (fh->isdir) 564 info->attribute |= EFI_FILE_DIRECTORY; 565 566 ascii2unicode((u16 *)info->file_name, filename); 567 } else if (!guidcmp(info_type, &efi_file_system_info_guid)) { 568 struct efi_file_system_info *info = buffer; 569 disk_partition_t part; 570 efi_uintn_t required_size; 571 int r; 572 573 if (fh->fs->part >= 1) 574 r = part_get_info(fh->fs->desc, fh->fs->part, &part); 575 else 576 r = part_get_info_whole_disk(fh->fs->desc, &part); 577 if (r < 0) { 578 ret = EFI_DEVICE_ERROR; 579 goto error; 580 } 581 required_size = sizeof(info) + 2 * 582 (strlen((const char *)part.name) + 1); 583 if (*buffer_size < required_size) { 584 *buffer_size = required_size; 585 ret = EFI_BUFFER_TOO_SMALL; 586 goto error; 587 } 588 589 memset(info, 0, required_size); 590 591 info->size = required_size; 592 info->read_only = true; 593 info->volume_size = part.size * part.blksz; 594 info->free_space = 0; 595 info->block_size = part.blksz; 596 /* 597 * TODO: The volume label is not available in U-Boot. 598 * Use the partition name as substitute. 599 */ 600 ascii2unicode((u16 *)info->volume_label, 601 (const char *)part.name); 602 } else { 603 ret = EFI_UNSUPPORTED; 604 } 605 606 error: 607 return EFI_EXIT(ret); 608 } 609 610 static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file, 611 const efi_guid_t *info_type, 612 efi_uintn_t buffer_size, 613 void *buffer) 614 { 615 EFI_ENTRY("%p, %p, %zu, %p", file, info_type, buffer_size, buffer); 616 617 return EFI_EXIT(EFI_UNSUPPORTED); 618 } 619 620 static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file) 621 { 622 EFI_ENTRY("%p", file); 623 return EFI_EXIT(EFI_SUCCESS); 624 } 625 626 static const struct efi_file_handle efi_file_handle_protocol = { 627 .rev = EFI_FILE_PROTOCOL_REVISION, 628 .open = efi_file_open, 629 .close = efi_file_close, 630 .delete = efi_file_delete, 631 .read = efi_file_read, 632 .write = efi_file_write, 633 .getpos = efi_file_getpos, 634 .setpos = efi_file_setpos, 635 .getinfo = efi_file_getinfo, 636 .setinfo = efi_file_setinfo, 637 .flush = efi_file_flush, 638 }; 639 640 struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp) 641 { 642 struct efi_simple_file_system_protocol *v; 643 struct efi_file_handle *f; 644 efi_status_t ret; 645 646 v = efi_fs_from_path(fp); 647 if (!v) 648 return NULL; 649 650 EFI_CALL(ret = v->open_volume(v, &f)); 651 if (ret != EFI_SUCCESS) 652 return NULL; 653 654 /* skip over device-path nodes before the file path: */ 655 while (fp && !EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) 656 fp = efi_dp_next(fp); 657 658 while (fp) { 659 struct efi_device_path_file_path *fdp = 660 container_of(fp, struct efi_device_path_file_path, dp); 661 struct efi_file_handle *f2; 662 663 if (!EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) { 664 printf("bad file path!\n"); 665 f->close(f); 666 return NULL; 667 } 668 669 EFI_CALL(ret = f->open(f, &f2, (s16 *)fdp->str, 670 EFI_FILE_MODE_READ, 0)); 671 if (ret != EFI_SUCCESS) 672 return NULL; 673 674 fp = efi_dp_next(fp); 675 676 EFI_CALL(f->close(f)); 677 f = f2; 678 } 679 680 return f; 681 } 682 683 static efi_status_t EFIAPI 684 efi_open_volume(struct efi_simple_file_system_protocol *this, 685 struct efi_file_handle **root) 686 { 687 struct file_system *fs = to_fs(this); 688 689 EFI_ENTRY("%p, %p", this, root); 690 691 *root = file_open(fs, NULL, NULL, 0, 0); 692 693 return EFI_EXIT(EFI_SUCCESS); 694 } 695 696 struct efi_simple_file_system_protocol * 697 efi_simple_file_system(struct blk_desc *desc, int part, 698 struct efi_device_path *dp) 699 { 700 struct file_system *fs; 701 702 fs = calloc(1, sizeof(*fs)); 703 fs->base.rev = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION; 704 fs->base.open_volume = efi_open_volume; 705 fs->desc = desc; 706 fs->part = part; 707 fs->dp = dp; 708 709 return &fs->base; 710 } 711