12e192b24SSimon Glass /* 22e192b24SSimon Glass * 32e192b24SSimon Glass * ZFS filesystem porting to Uboot by 42e192b24SSimon Glass * Jorgen Lundman <lundman at lundman.net> 52e192b24SSimon Glass * 62e192b24SSimon Glass * zfsfs support 72e192b24SSimon Glass * made from existing GRUB Sources by Sun, GNU and others. 82e192b24SSimon Glass * 92e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 102e192b24SSimon Glass */ 112e192b24SSimon Glass 122e192b24SSimon Glass #include <common.h> 132e192b24SSimon Glass #include <part.h> 142e192b24SSimon Glass #include <config.h> 152e192b24SSimon Glass #include <command.h> 162e192b24SSimon Glass #include <image.h> 172e192b24SSimon Glass #include <linux/ctype.h> 182e192b24SSimon Glass #include <asm/byteorder.h> 192e192b24SSimon Glass #include <zfs_common.h> 202e192b24SSimon Glass #include <linux/stat.h> 212e192b24SSimon Glass #include <malloc.h> 222e192b24SSimon Glass 232e192b24SSimon Glass #if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) 242e192b24SSimon Glass #include <usb.h> 252e192b24SSimon Glass #endif 262e192b24SSimon Glass 272e192b24SSimon Glass #if !defined(CONFIG_DOS_PARTITION) && !defined(CONFIG_EFI_PARTITION) 282e192b24SSimon Glass #error DOS or EFI partition support must be selected 292e192b24SSimon Glass #endif 302e192b24SSimon Glass 312e192b24SSimon Glass #define DOS_PART_MAGIC_OFFSET 0x1fe 322e192b24SSimon Glass #define DOS_FS_TYPE_OFFSET 0x36 332e192b24SSimon Glass #define DOS_FS32_TYPE_OFFSET 0x52 342e192b24SSimon Glass 352e192b24SSimon Glass static int do_zfs_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 362e192b24SSimon Glass { 372e192b24SSimon Glass char *filename = NULL; 382e192b24SSimon Glass int dev; 392e192b24SSimon Glass int part; 402e192b24SSimon Glass ulong addr = 0; 412e192b24SSimon Glass disk_partition_t info; 42*4101f687SSimon Glass struct blk_desc *dev_desc; 432e192b24SSimon Glass char buf[12]; 442e192b24SSimon Glass unsigned long count; 452e192b24SSimon Glass const char *addr_str; 462e192b24SSimon Glass struct zfs_file zfile; 472e192b24SSimon Glass struct device_s vdev; 482e192b24SSimon Glass 492e192b24SSimon Glass if (argc < 3) 502e192b24SSimon Glass return CMD_RET_USAGE; 512e192b24SSimon Glass 522e192b24SSimon Glass count = 0; 532e192b24SSimon Glass addr = simple_strtoul(argv[3], NULL, 16); 542e192b24SSimon Glass filename = getenv("bootfile"); 552e192b24SSimon Glass switch (argc) { 562e192b24SSimon Glass case 3: 572e192b24SSimon Glass addr_str = getenv("loadaddr"); 582e192b24SSimon Glass if (addr_str != NULL) 592e192b24SSimon Glass addr = simple_strtoul(addr_str, NULL, 16); 602e192b24SSimon Glass else 612e192b24SSimon Glass addr = CONFIG_SYS_LOAD_ADDR; 622e192b24SSimon Glass 632e192b24SSimon Glass break; 642e192b24SSimon Glass case 4: 652e192b24SSimon Glass break; 662e192b24SSimon Glass case 5: 672e192b24SSimon Glass filename = argv[4]; 682e192b24SSimon Glass break; 692e192b24SSimon Glass case 6: 702e192b24SSimon Glass filename = argv[4]; 712e192b24SSimon Glass count = simple_strtoul(argv[5], NULL, 16); 722e192b24SSimon Glass break; 732e192b24SSimon Glass 742e192b24SSimon Glass default: 752e192b24SSimon Glass return cmd_usage(cmdtp); 762e192b24SSimon Glass } 772e192b24SSimon Glass 782e192b24SSimon Glass if (!filename) { 792e192b24SSimon Glass puts("** No boot file defined **\n"); 802e192b24SSimon Glass return 1; 812e192b24SSimon Glass } 822e192b24SSimon Glass 832e192b24SSimon Glass part = get_device_and_partition(argv[1], argv[2], &dev_desc, &info, 1); 842e192b24SSimon Glass if (part < 0) 852e192b24SSimon Glass return 1; 862e192b24SSimon Glass 872e192b24SSimon Glass dev = dev_desc->dev; 882e192b24SSimon Glass printf("Loading file \"%s\" from %s device %d%c%c\n", 892e192b24SSimon Glass filename, argv[1], dev, 902e192b24SSimon Glass part ? ':' : ' ', part ? part + '0' : ' '); 912e192b24SSimon Glass 922e192b24SSimon Glass zfs_set_blk_dev(dev_desc, &info); 932e192b24SSimon Glass vdev.part_length = info.size; 942e192b24SSimon Glass 952e192b24SSimon Glass memset(&zfile, 0, sizeof(zfile)); 962e192b24SSimon Glass zfile.device = &vdev; 972e192b24SSimon Glass if (zfs_open(&zfile, filename)) { 982e192b24SSimon Glass printf("** File not found %s **\n", filename); 992e192b24SSimon Glass return 1; 1002e192b24SSimon Glass } 1012e192b24SSimon Glass 1022e192b24SSimon Glass if ((count < zfile.size) && (count != 0)) 1032e192b24SSimon Glass zfile.size = (uint64_t)count; 1042e192b24SSimon Glass 1052e192b24SSimon Glass if (zfs_read(&zfile, (char *)addr, zfile.size) != zfile.size) { 1062e192b24SSimon Glass printf("** Unable to read \"%s\" from %s %d:%d **\n", 1072e192b24SSimon Glass filename, argv[1], dev, part); 1082e192b24SSimon Glass zfs_close(&zfile); 1092e192b24SSimon Glass return 1; 1102e192b24SSimon Glass } 1112e192b24SSimon Glass 1122e192b24SSimon Glass zfs_close(&zfile); 1132e192b24SSimon Glass 1142e192b24SSimon Glass /* Loading ok, update default load address */ 1152e192b24SSimon Glass load_addr = addr; 1162e192b24SSimon Glass 1172e192b24SSimon Glass printf("%llu bytes read\n", zfile.size); 1182e192b24SSimon Glass setenv_hex("filesize", zfile.size); 1192e192b24SSimon Glass 1202e192b24SSimon Glass return 0; 1212e192b24SSimon Glass } 1222e192b24SSimon Glass 1232e192b24SSimon Glass 1242e192b24SSimon Glass int zfs_print(const char *entry, const struct zfs_dirhook_info *data) 1252e192b24SSimon Glass { 1262e192b24SSimon Glass printf("%s %s\n", 1272e192b24SSimon Glass data->dir ? "<DIR> " : " ", 1282e192b24SSimon Glass entry); 1292e192b24SSimon Glass return 0; /* 0 continue, 1 stop */ 1302e192b24SSimon Glass } 1312e192b24SSimon Glass 1322e192b24SSimon Glass 1332e192b24SSimon Glass 1342e192b24SSimon Glass static int do_zfs_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 1352e192b24SSimon Glass { 1362e192b24SSimon Glass const char *filename = "/"; 1372e192b24SSimon Glass int part; 138*4101f687SSimon Glass struct blk_desc *dev_desc; 1392e192b24SSimon Glass disk_partition_t info; 1402e192b24SSimon Glass struct device_s vdev; 1412e192b24SSimon Glass 1422e192b24SSimon Glass if (argc < 2) 1432e192b24SSimon Glass return cmd_usage(cmdtp); 1442e192b24SSimon Glass 1452e192b24SSimon Glass if (argc == 4) 1462e192b24SSimon Glass filename = argv[3]; 1472e192b24SSimon Glass 1482e192b24SSimon Glass part = get_device_and_partition(argv[1], argv[2], &dev_desc, &info, 1); 1492e192b24SSimon Glass if (part < 0) 1502e192b24SSimon Glass return 1; 1512e192b24SSimon Glass 1522e192b24SSimon Glass zfs_set_blk_dev(dev_desc, &info); 1532e192b24SSimon Glass vdev.part_length = info.size; 1542e192b24SSimon Glass 1552e192b24SSimon Glass zfs_ls(&vdev, filename, 1562e192b24SSimon Glass zfs_print); 1572e192b24SSimon Glass 1582e192b24SSimon Glass return 0; 1592e192b24SSimon Glass } 1602e192b24SSimon Glass 1612e192b24SSimon Glass 1622e192b24SSimon Glass U_BOOT_CMD(zfsls, 4, 1, do_zfs_ls, 1632e192b24SSimon Glass "list files in a directory (default /)", 1642e192b24SSimon Glass "<interface> <dev[:part]> [directory]\n" 1652e192b24SSimon Glass " - list files from 'dev' on 'interface' in a '/DATASET/@/$dir/'"); 1662e192b24SSimon Glass 1672e192b24SSimon Glass U_BOOT_CMD(zfsload, 6, 0, do_zfs_load, 1682e192b24SSimon Glass "load binary file from a ZFS filesystem", 1692e192b24SSimon Glass "<interface> <dev[:part]> [addr] [filename] [bytes]\n" 1702e192b24SSimon Glass " - load binary file '/DATASET/@/$dir/$file' from 'dev' on 'interface'\n" 1712e192b24SSimon Glass " to address 'addr' from ZFS filesystem"); 172