blob: a6ea2c07cdd06de193eb8f3edb1bcc0e4f4a6a10 [file] [log] [blame]
Jorgen Lundman4d3c95f2012-07-19 20:48:25 +00001/*
2 *
3 * ZFS filesystem porting to Uboot by
4 * Jorgen Lundman <lundman at lundman.net>
5 *
6 * zfsfs support
7 * made from existing GRUB Sources by Sun, GNU and others.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22 * MA 02111-1307 USA
23 *
24 */
25
26#include <common.h>
27#include <part.h>
28#include <config.h>
29#include <command.h>
30#include <image.h>
31#include <linux/ctype.h>
32#include <asm/byteorder.h>
33#include <zfs_common.h>
34#include <linux/stat.h>
35#include <malloc.h>
36
37#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
38#include <usb.h>
39#endif
40
41#if !defined(CONFIG_DOS_PARTITION) && !defined(CONFIG_EFI_PARTITION)
42#error DOS or EFI partition support must be selected
43#endif
44
45#define DOS_PART_MAGIC_OFFSET 0x1fe
46#define DOS_FS_TYPE_OFFSET 0x36
47#define DOS_FS32_TYPE_OFFSET 0x52
48
49static int do_zfs_load(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
50{
51 char *filename = NULL;
52 char *ep;
53 int dev;
54 unsigned long part = 1;
55 ulong addr = 0;
56 ulong part_length;
57 disk_partition_t info;
58 char buf[12];
59 unsigned long count;
60 const char *addr_str;
61 struct zfs_file zfile;
62 struct device_s vdev;
63
64 if (argc < 3)
65 return CMD_RET_USAGE;
66
67 count = 0;
68 addr = simple_strtoul(argv[3], NULL, 16);
69 filename = getenv("bootfile");
70 switch (argc) {
71 case 3:
72 addr_str = getenv("loadaddr");
73 if (addr_str != NULL)
74 addr = simple_strtoul(addr_str, NULL, 16);
75 else
76 addr = CONFIG_SYS_LOAD_ADDR;
77
78 break;
79 case 4:
80 break;
81 case 5:
82 filename = argv[4];
83 break;
84 case 6:
85 filename = argv[4];
86 count = simple_strtoul(argv[5], NULL, 16);
87 break;
88
89 default:
90 return cmd_usage(cmdtp);
91 }
92
93 if (!filename) {
94 puts("** No boot file defined **\n");
95 return 1;
96 }
97
98 dev = (int)simple_strtoul(argv[2], &ep, 16);
99 zfs_dev_desc = get_dev(argv[1], dev);
100 if (zfs_dev_desc == NULL) {
101 printf("** Block device %s %d not supported\n", argv[1], dev);
102 return 1;
103 }
104
105 if (*ep) {
106 if (*ep != ':') {
107 puts("** Invalid boot device, use `dev[:part]' **\n");
108 return 1;
109 }
110 part = simple_strtoul(++ep, NULL, 16);
111 }
112
113 if (part != 0) {
114 if (get_partition_info(zfs_dev_desc, part, &info)) {
115 printf("** Bad partition %lu **\n", part);
116 return 1;
117 }
118
119 if (strncmp((char *)info.type, BOOT_PART_TYPE,
120 strlen(BOOT_PART_TYPE)) != 0) {
121 printf("** Invalid partition type \"%s\" (expect \"" BOOT_PART_TYPE "\")\n",
122 info.type);
123 return 1;
124 }
125 printf("Loading file \"%s\" "
126 "from %s device %d:%lu %s\n",
127 filename, argv[1], dev, part, info.name);
128 } else {
129 printf("Loading file \"%s\" from %s device %d\n",
130 filename, argv[1], dev);
131 }
132
133 part_length = zfs_set_blk_dev(zfs_dev_desc, part);
134 if (part_length == 0) {
135 printf("**Bad partition - %s %d:%lu **\n", argv[1], dev, part);
136 return 1;
137 }
138
139 vdev.part_length = part_length;
140
141 memset(&zfile, 0, sizeof(zfile));
142 zfile.device = &vdev;
143 if (zfs_open(&zfile, filename)) {
144 printf("** File not found %s\n", filename);
145 return 1;
146 }
147
148 if ((count < zfile.size) && (count != 0))
149 zfile.size = (uint64_t)count;
150
151 if (zfs_read(&zfile, (char *)addr, zfile.size) != zfile.size) {
152 printf("** Unable to read \"%s\" from %s %d:%lu **\n",
153 filename, argv[1], dev, part);
154 zfs_close(&zfile);
155 return 1;
156 }
157
158 zfs_close(&zfile);
159
160 /* Loading ok, update default load address */
161 load_addr = addr;
162
163 printf("%llu bytes read\n", zfile.size);
164 sprintf(buf, "%llX", zfile.size);
165 setenv("filesize", buf);
166
167 return 0;
168}
169
170
171int zfs_print(const char *entry, const struct zfs_dirhook_info *data)
172{
173 printf("%s %s\n",
174 data->dir ? "<DIR> " : " ",
175 entry);
176 return 0; /* 0 continue, 1 stop */
177}
178
179
180
181static int do_zfs_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
182{
183 const char *filename = "/";
184 int dev;
185 unsigned long part = 1;
186 char *ep;
187 int part_length;
188 struct device_s vdev;
189
190 if (argc < 3)
191 return cmd_usage(cmdtp);
192
193 dev = (int)simple_strtoul(argv[2], &ep, 16);
194 zfs_dev_desc = get_dev(argv[1], dev);
195
196 if (zfs_dev_desc == NULL) {
197 printf("\n** Block device %s %d not supported\n", argv[1], dev);
198 return 1;
199 }
200
201 if (*ep) {
202 if (*ep != ':') {
203 puts("\n** Invalid boot device, use `dev[:part]' **\n");
204 return 1;
205 }
206 part = simple_strtoul(++ep, NULL, 16);
207 }
208
209 if (argc == 4)
210 filename = argv[3];
211
212 part_length = zfs_set_blk_dev(zfs_dev_desc, part);
213 if (part_length == 0) {
214 printf("** Bad partition - %s %d:%lu **\n", argv[1], dev, part);
215 return 1;
216 }
217
218 vdev.part_length = part_length;
219
220 zfs_ls(&vdev, filename,
221 zfs_print);
222
223 return 0;
224}
225
226
227U_BOOT_CMD(zfsls, 4, 1, do_zfs_ls,
228 "list files in a directory (default /)",
229 "<interface> <dev[:part]> [directory]\n"
230 " - list files from 'dev' on 'interface' in a '/DATASET/@/$dir/'");
231
232U_BOOT_CMD(zfsload, 6, 0, do_zfs_load,
233 "load binary file from a ZFS filesystem",
234 "<interface> <dev[:part]> [addr] [filename] [bytes]\n"
235 " - load binary file '/DATASET/@/$dir/$file' from 'dev' on 'interface'\n"
236 " to address 'addr' from ZFS filesystem");