1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * 4 * ZFS filesystem porting to Uboot by 5 * Jorgen Lundman <lundman at lundman.net> 6 * 7 * zfsfs support 8 * made from existing GRUB Sources by Sun, GNU and others. 9 */ 10 11#include <common.h> 12#include <part.h> 13#include <config.h> 14#include <command.h> 15#include <env.h> 16#include <image.h> 17#include <linux/ctype.h> 18#include <asm/byteorder.h> 19#include <zfs_common.h> 20#include <linux/stat.h> 21#include <malloc.h> 22 23#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) 24#include <usb.h> 25#endif 26 27#if !CONFIG_IS_ENABLED(DOS_PARTITION) && !CONFIG_IS_ENABLED(EFI_PARTITION) 28#error DOS or EFI partition support must be selected 29#endif 30 31#define DOS_PART_MAGIC_OFFSET 0x1fe 32#define DOS_FS_TYPE_OFFSET 0x36 33#define DOS_FS32_TYPE_OFFSET 0x52 34 35static int do_zfs_load(struct cmd_tbl *cmdtp, int flag, int argc, 36 char *const argv[]) 37{ 38 char *filename = NULL; 39 int dev; 40 int part; 41 ulong addr = 0; 42 struct disk_partition info; 43 struct blk_desc *dev_desc; 44 unsigned long count; 45 const char *addr_str; 46 struct zfs_file zfile; 47 struct device_s vdev; 48 49 if (argc < 3) 50 return CMD_RET_USAGE; 51 52 count = 0; 53 addr = hextoul(argv[3], NULL); 54 filename = env_get("bootfile"); 55 switch (argc) { 56 case 3: 57 addr_str = env_get("loadaddr"); 58 if (addr_str != NULL) 59 addr = hextoul(addr_str, NULL); 60 else 61 addr = CONFIG_SYS_LOAD_ADDR; 62 63 break; 64 case 4: 65 break; 66 case 5: 67 filename = argv[4]; 68 break; 69 case 6: 70 filename = argv[4]; 71 count = hextoul(argv[5], NULL); 72 break; 73 74 default: 75 return cmd_usage(cmdtp); 76 } 77 78 if (!filename) { 79 puts("** No boot file defined **\n"); 80 return 1; 81 } 82 83 part = blk_get_device_part_str(argv[1], argv[2], &dev_desc, &info, 1); 84 if (part < 0) 85 return 1; 86 87 dev = dev_desc->devnum; 88 printf("Loading file \"%s\" from %s device %d%c%c\n", 89 filename, argv[1], dev, 90 part ? ':' : ' ', part ? part + '0' : ' '); 91 92 zfs_set_blk_dev(dev_desc, &info); 93 vdev.part_length = info.size; 94 95 memset(&zfile, 0, sizeof(zfile)); 96 zfile.device = &vdev; 97 if (zfs_open(&zfile, filename)) { 98 printf("** File not found %s **\n", filename); 99 return 1; 100 } 101 102 if ((count < zfile.size) && (count != 0)) 103 zfile.size = (uint64_t)count; 104 105 if (zfs_read(&zfile, (char *)addr, zfile.size) != zfile.size) { 106 printf("** Unable to read \"%s\" from %s %d:%d **\n", 107 filename, argv[1], dev, part); 108 zfs_close(&zfile); 109 return 1; 110 } 111 112 zfs_close(&zfile); 113 114 /* Loading ok, update default load address */ 115 image_load_addr = addr; 116 117 printf("%llu bytes read\n", zfile.size); 118 env_set_hex("filesize", zfile.size); 119 120 return 0; 121} 122 123 124int zfs_print(const char *entry, const struct zfs_dirhook_info *data) 125{ 126 printf("%s %s\n", 127 data->dir ? "<DIR> " : " ", 128 entry); 129 return 0; /* 0 continue, 1 stop */ 130} 131 132 133static int do_zfs_ls(struct cmd_tbl *cmdtp, int flag, int argc, 134 char *const argv[]) 135{ 136 const char *filename = "/"; 137 int part; 138 struct blk_desc *dev_desc; 139 struct disk_partition info; 140 struct device_s vdev; 141 142 if (argc < 2) 143 return cmd_usage(cmdtp); 144 145 if (argc == 4) 146 filename = argv[3]; 147 148 part = blk_get_device_part_str(argv[1], argv[2], &dev_desc, &info, 1); 149 if (part < 0) 150 return 1; 151 152 zfs_set_blk_dev(dev_desc, &info); 153 vdev.part_length = info.size; 154 155 zfs_ls(&vdev, filename, 156 zfs_print); 157 158 return 0; 159} 160 161 162U_BOOT_CMD(zfsls, 4, 1, do_zfs_ls, 163 "list files in a directory (default /)", 164 "<interface> <dev[:part]> [directory]\n" 165 " - list files from 'dev' on 'interface' in a '/DATASET/@/$dir/'"); 166 167U_BOOT_CMD(zfsload, 6, 0, do_zfs_load, 168 "load binary file from a ZFS filesystem", 169 "<interface> <dev[:part]> [addr] [filename] [bytes]\n" 170 " - load binary file '/DATASET/@/$dir/$file' from 'dev' on 'interface'\n" 171 " to address 'addr' from ZFS filesystem"); 172