1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (c) 2012, Google Inc. 4 */ 5 6#include <common.h> 7#include <command.h> 8#include <dm.h> 9#include <fs.h> 10#include <part.h> 11#include <sandbox_host.h> 12#include <dm/device_compat.h> 13#include <dm/device-internal.h> 14#include <dm/uclass-internal.h> 15#include <linux/errno.h> 16#include <linux/log2.h> 17 18static int do_host_load(struct cmd_tbl *cmdtp, int flag, int argc, 19 char *const argv[]) 20{ 21 return do_load(cmdtp, flag, argc, argv, FS_TYPE_SANDBOX); 22} 23 24static int do_host_ls(struct cmd_tbl *cmdtp, int flag, int argc, 25 char *const argv[]) 26{ 27 return do_ls(cmdtp, flag, argc, argv, FS_TYPE_SANDBOX); 28} 29 30static int do_host_size(struct cmd_tbl *cmdtp, int flag, int argc, 31 char *const argv[]) 32{ 33 return do_size(cmdtp, flag, argc, argv, FS_TYPE_SANDBOX); 34} 35 36static int do_host_save(struct cmd_tbl *cmdtp, int flag, int argc, 37 char *const argv[]) 38{ 39 return do_save(cmdtp, flag, argc, argv, FS_TYPE_SANDBOX); 40} 41 42static int do_host_bind(struct cmd_tbl *cmdtp, int flag, int argc, 43 char *const argv[]) 44{ 45 bool removable = false; 46 struct udevice *dev; 47 const char *label; 48 char *file; 49 unsigned long blksz = DEFAULT_BLKSZ; 50 int ret; 51 52 /* Skip 'bind' */ 53 argc--; 54 argv++; 55 if (argc < 2) 56 return CMD_RET_USAGE; 57 58 if (!strcmp(argv[0], "-r")) { 59 removable = true; 60 argc--; 61 argv++; 62 } 63 64 if (argc < 2 || argc > 3) 65 return CMD_RET_USAGE; 66 label = argv[0]; 67 file = argv[1]; 68 if (argc > 2) { 69 blksz = dectoul(argv[2], NULL); 70 if (blksz < DEFAULT_BLKSZ || !is_power_of_2(blksz)) { 71 printf("blksz must be >= 512 and power of 2\n"); 72 return CMD_RET_FAILURE; 73 } 74 } 75 76 ret = host_create_attach_file(label, file, removable, blksz, &dev); 77 if (ret) { 78 printf("Cannot create device / bind file\n"); 79 return CMD_RET_FAILURE; 80 } 81 82 return 0; 83} 84 85/** 86 * parse_host_label() - Parse a device label or sequence number 87 * 88 * This shows an error if it returns NULL 89 * 90 * @label: String containing the label or sequence number 91 * Returns: Associated device, or NULL if not found 92 */ 93static struct udevice *parse_host_label(const char *label) 94{ 95 struct udevice *dev; 96 97 dev = host_find_by_label(label); 98 if (!dev) { 99 int devnum; 100 char *ep; 101 102 devnum = hextoul(label, &ep); 103 if (*ep || 104 uclass_find_device_by_seq(UCLASS_HOST, devnum, &dev)) { 105 printf("No such device '%s'\n", label); 106 return NULL; 107 } 108 } 109 110 return dev; 111} 112 113static int do_host_unbind(struct cmd_tbl *cmdtp, int flag, int argc, 114 char *const argv[]) 115{ 116 struct udevice *dev; 117 const char *label; 118 int ret; 119 120 if (argc < 2) 121 return CMD_RET_USAGE; 122 123 label = argv[1]; 124 dev = parse_host_label(label); 125 if (!dev) 126 return CMD_RET_FAILURE; 127 128 ret = host_detach_file(dev); 129 if (ret) { 130 printf("Cannot detach file (err=%d)\n", ret); 131 return CMD_RET_FAILURE; 132 } 133 134 ret = device_unbind(dev); 135 if (ret) { 136 printf("Cannot attach file\n"); 137 ret = device_unbind(dev); 138 if (ret) 139 printf("Cannot unbind device '%s'\n", dev->name); 140 return CMD_RET_FAILURE; 141 } 142 143 return 0; 144} 145 146static void show_host_dev(struct udevice *dev) 147{ 148 struct host_sb_plat *plat = dev_get_plat(dev); 149 struct blk_desc *desc; 150 struct udevice *blk; 151 int ret; 152 153 printf("%3d ", dev_seq(dev)); 154 if (!plat->fd) { 155 printf("Not bound to a backing file\n"); 156 return; 157 } 158 ret = blk_get_from_parent(dev, &blk); 159 if (ret) /* cannot happen */ 160 return; 161 162 desc = dev_get_uclass_plat(blk); 163 printf("%12lu %6lu %-15s %s\n", (unsigned long)desc->lba, desc->blksz, 164 plat->label, plat->filename); 165} 166 167static int do_host_info(struct cmd_tbl *cmdtp, int flag, int argc, 168 char *const argv[]) 169{ 170 struct udevice *dev; 171 172 if (argc < 1) 173 return CMD_RET_USAGE; 174 175 dev = NULL; 176 if (argc >= 2) { 177 dev = parse_host_label(argv[1]); 178 if (!dev) 179 return CMD_RET_FAILURE; 180 } 181 182 printf("%3s %12s %6s %-15s %s\n", 183 "dev", "blocks", "blksz", "label", "path"); 184 if (dev) { 185 show_host_dev(dev); 186 } else { 187 struct uclass *uc; 188 189 uclass_id_foreach_dev(UCLASS_HOST, dev, uc) 190 show_host_dev(dev); 191 } 192 193 return 0; 194} 195 196static int do_host_dev(struct cmd_tbl *cmdtp, int flag, int argc, 197 char *const argv[]) 198{ 199 struct udevice *dev; 200 const char *label; 201 202 if (argc < 1 || argc > 3) 203 return CMD_RET_USAGE; 204 205 if (argc == 1) { 206 struct host_sb_plat *plat; 207 208 dev = host_get_cur_dev(); 209 if (!dev) { 210 printf("No current host device\n"); 211 return CMD_RET_FAILURE; 212 } 213 plat = dev_get_plat(dev); 214 printf("Current host device: %d: %s\n", dev_seq(dev), 215 plat->label); 216 return 0; 217 } 218 219 label = argv[1]; 220 dev = parse_host_label(argv[1]); 221 if (!dev) 222 return CMD_RET_FAILURE; 223 224 host_set_cur_dev(dev); 225 226 return 0; 227} 228 229static struct cmd_tbl cmd_host_sub[] = { 230 U_BOOT_CMD_MKENT(load, 7, 0, do_host_load, "", ""), 231 U_BOOT_CMD_MKENT(ls, 3, 0, do_host_ls, "", ""), 232 U_BOOT_CMD_MKENT(save, 6, 0, do_host_save, "", ""), 233 U_BOOT_CMD_MKENT(size, 3, 0, do_host_size, "", ""), 234 U_BOOT_CMD_MKENT(bind, 4, 0, do_host_bind, "", ""), 235 U_BOOT_CMD_MKENT(unbind, 4, 0, do_host_unbind, "", ""), 236 U_BOOT_CMD_MKENT(info, 3, 0, do_host_info, "", ""), 237 U_BOOT_CMD_MKENT(dev, 0, 1, do_host_dev, "", ""), 238}; 239 240static int do_host(struct cmd_tbl *cmdtp, int flag, int argc, 241 char *const argv[]) 242{ 243 struct cmd_tbl *c; 244 245 /* Skip past 'host' */ 246 argc--; 247 argv++; 248 249 c = find_cmd_tbl(argv[0], cmd_host_sub, ARRAY_SIZE(cmd_host_sub)); 250 251 if (c) 252 return c->cmd(cmdtp, flag, argc, argv); 253 else 254 return CMD_RET_USAGE; 255} 256 257U_BOOT_CMD( 258 host, 8, 1, do_host, 259 "Miscellaneous host commands", 260 "load hostfs - <addr> <filename> [<bytes> <offset>] - " 261 "load a file from host\n" 262 "host ls hostfs - <filename> - list files on host\n" 263 "host save hostfs - <addr> <filename> <bytes> [<offset>] - " 264 "save a file to host\n" 265 "host size hostfs - <filename> - determine size of file on host\n" 266 "host bind [-r] <label> <filename> [<blksz>] - bind \"host\" device to file,\n" 267 " and optionally set the device's logical block size\n" 268 " -r = mark as removable\n" 269 "host unbind <label> - unbind file from \"host\" device\n" 270 "host info [<label>] - show device binding & info\n" 271 "host dev [<label>] - set or retrieve the current host device\n" 272 "host commands use the \"hostfs\" device. The \"host\" device is used\n" 273 "with standard IO commands such as fatls or ext2load" 274); 275