1 /*
2 * (C) Copyright 2000
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8 /*
9 * Boot support
10 */
11 #include <common.h>
12 #include <command.h>
13 #include <net.h>
14 #include <boot_rkimg.h>
15
16 static int netboot_common(enum proto_t, cmd_tbl_t *, int, char * const []);
17
do_bootp(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])18 static int do_bootp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
19 {
20 return netboot_common(BOOTP, cmdtp, argc, argv);
21 }
22
23 U_BOOT_CMD(
24 bootp, 3, 1, do_bootp,
25 "boot image via network using BOOTP/TFTP protocol",
26 "[loadAddress] [[hostIPaddr:]bootfilename]"
27 );
28
do_tftpb(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])29 int do_tftpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
30 {
31 int ret;
32
33 bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
34 ret = netboot_common(TFTPGET, cmdtp, argc, argv);
35 bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
36 return ret;
37 }
38
39 U_BOOT_CMD(
40 tftp, 3, 1, do_tftpb,
41 "download image via network using TFTP protocol",
42 "[loadAddress] [[hostIPaddr:]bootfilename]"
43 );
44
45 #ifdef CONFIG_CMD_TFTP_BOOTM
do_tftpbootm(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])46 int do_tftpbootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
47 {
48 char *tftp_argv[] = { "tftp", NULL, NULL };
49 char *bootm_argv[] = { "bootm", NULL };
50 char *fileaddr;
51 ulong filesize;
52
53 if (argc != 3)
54 return CMD_RET_USAGE;
55
56 /* tftp download */
57 tftp_argv[1] = argv[1];
58 tftp_argv[2] = argv[2];
59 if (do_tftpb(cmdtp, 0, 3, tftp_argv))
60 return -ENOENT;
61
62 fileaddr = env_get("fileaddr");
63 filesize = env_get_ulong("filesize", 16, 0);
64 if (!fileaddr || !filesize)
65 return -ENOENT;
66
67 /* bootm */
68 bootm_argv[1] = fileaddr;
69 printf("## TFTP bootm %s at %s size 0x%lx\n",
70 argv[2], fileaddr, filesize);
71
72 return do_bootm(NULL, 0, ARRAY_SIZE(bootm_argv), bootm_argv);
73 }
74
75 U_BOOT_CMD(
76 tftpbootm, 3, 1, do_tftpbootm,
77 "tftpbootm aosp/uImage/FIT image via network using TFTP protocol",
78 "[loadAddress] [[hostIPaddr:]bootfilename]"
79 );
80 #endif
81
82 #ifdef CONFIG_CMD_TFTP_FLASH
do_tftpflash(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])83 int do_tftpflash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
84 {
85 char *tftp_argv[] = { "tftp", NULL, NULL };
86 struct blk_desc *dev_desc;
87 disk_partition_t part;
88 ulong fileaddr;
89 ulong filesize;
90 char *part_name;
91 int ret, blknum;
92
93 if (argc != 4)
94 return CMD_RET_USAGE;
95
96 /* search partition */
97 dev_desc = rockchip_get_bootdev();
98 if (!dev_desc) {
99 printf("No boot device\n");
100 return -ENODEV;
101 }
102
103 part_name = argv[3];
104 ret = part_get_info_by_name(dev_desc, part_name, &part);
105 if (ret < 0) {
106 printf("No partition '%s'\n", part_name);
107 return -EINVAL;
108 }
109
110 /* tftp download */
111 tftp_argv[1] = argv[1];
112 tftp_argv[2] = argv[2];
113 if (do_tftpb(cmdtp, 0, ARRAY_SIZE(tftp_argv), tftp_argv))
114 return -ENOENT;
115
116 fileaddr = env_get_ulong("fileaddr", 16, 0);
117 filesize = env_get_ulong("filesize", 16, 0);
118 if (!fileaddr || !filesize)
119 return -ENOENT;
120
121 /* flash */
122 blknum = DIV_ROUND_UP(filesize, dev_desc->blksz);
123 if (blknum > part.size) {
124 printf("File size 0x%lx is too large to flash\n", filesize);
125 return -EINVAL;
126 }
127
128 printf("## TFTP flash %s to partititon '%s' size 0x%lx ... ",
129 argv[2], part_name, filesize);
130
131 if (dev_desc->if_type == IF_TYPE_MTD)
132 dev_desc->op_flag |= BLK_MTD_CONT_WRITE;
133 ret = blk_dwrite(dev_desc, part.start, blknum, (void *)fileaddr);
134 if (dev_desc->if_type == IF_TYPE_MTD)
135 dev_desc->op_flag &= ~(BLK_MTD_CONT_WRITE);
136 if (ret != blknum)
137 printf("Failed(%d)\n", ret);
138 else
139 printf("OK\n");
140
141 return 0;
142 }
143
144 U_BOOT_CMD(
145 tftpflash, 4, 0, do_tftpflash,
146 "flash image via network using TFTP protocol",
147 "[loadAddress] [[hostIPaddr:]bootfilename] [partition]"
148 );
149 #endif
150
151 #ifdef CONFIG_CMD_TFTPPUT
do_tftpput(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])152 static int do_tftpput(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
153 {
154 return netboot_common(TFTPPUT, cmdtp, argc, argv);
155 }
156
157 U_BOOT_CMD(
158 tftpput, 4, 1, do_tftpput,
159 "TFTP put command, for uploading files to a server",
160 "Address Size [[hostIPaddr:]filename]"
161 );
162 #endif
163
164 #ifdef CONFIG_CMD_TFTPSRV
do_tftpsrv(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])165 static int do_tftpsrv(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
166 {
167 return netboot_common(TFTPSRV, cmdtp, argc, argv);
168 }
169
170 U_BOOT_CMD(
171 tftpsrv, 2, 1, do_tftpsrv,
172 "act as a TFTP server and boot the first received file",
173 "[loadAddress]\n"
174 "Listen for an incoming TFTP transfer, receive a file and boot it.\n"
175 "The transfer is aborted if a transfer has not been started after\n"
176 "about 50 seconds or if Ctrl-C is pressed."
177 );
178 #endif
179
180 #ifdef CONFIG_UDP_FUNCTION_FASTBOOT
do_fastboot_udp(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])181 int do_fastboot_udp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
182 {
183 return netboot_common(FASTBOOT, cmdtp, argc, argv);
184 }
185 #endif
186
187 #ifdef CONFIG_CMD_RARP
do_rarpb(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])188 int do_rarpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
189 {
190 return netboot_common(RARP, cmdtp, argc, argv);
191 }
192
193 U_BOOT_CMD(
194 rarpboot, 3, 1, do_rarpb,
195 "boot image via network using RARP/TFTP protocol",
196 "[loadAddress] [[hostIPaddr:]bootfilename]"
197 );
198 #endif
199
200 #if defined(CONFIG_CMD_DHCP)
do_dhcp(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])201 static int do_dhcp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
202 {
203 return netboot_common(DHCP, cmdtp, argc, argv);
204 }
205
206 U_BOOT_CMD(
207 dhcp, 3, 1, do_dhcp,
208 "boot image via network using DHCP/TFTP protocol",
209 "[loadAddress] [[hostIPaddr:]bootfilename]"
210 );
211 #endif
212
213 #if defined(CONFIG_CMD_NFS)
do_nfs(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])214 static int do_nfs(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
215 {
216 return netboot_common(NFS, cmdtp, argc, argv);
217 }
218
219 U_BOOT_CMD(
220 nfs, 3, 1, do_nfs,
221 "boot image via network using NFS protocol",
222 "[loadAddress] [[hostIPaddr:]bootfilename]"
223 );
224 #endif
225
netboot_update_env(void)226 static void netboot_update_env(void)
227 {
228 char tmp[22];
229
230 if (net_gateway.s_addr) {
231 ip_to_string(net_gateway, tmp);
232 env_set("gatewayip", tmp);
233 }
234
235 if (net_netmask.s_addr) {
236 ip_to_string(net_netmask, tmp);
237 env_set("netmask", tmp);
238 }
239
240 if (net_hostname[0])
241 env_set("hostname", net_hostname);
242
243 if (net_root_path[0])
244 env_set("rootpath", net_root_path);
245
246 if (net_ip.s_addr) {
247 ip_to_string(net_ip, tmp);
248 env_set("ipaddr", tmp);
249 }
250 #if !defined(CONFIG_BOOTP_SERVERIP)
251 /*
252 * Only attempt to change serverip if net/bootp.c:store_net_params()
253 * could have set it
254 */
255 if (net_server_ip.s_addr) {
256 ip_to_string(net_server_ip, tmp);
257 env_set("serverip", tmp);
258 }
259 #endif
260 if (net_dns_server.s_addr) {
261 ip_to_string(net_dns_server, tmp);
262 env_set("dnsip", tmp);
263 }
264 #if defined(CONFIG_BOOTP_DNS2)
265 if (net_dns_server2.s_addr) {
266 ip_to_string(net_dns_server2, tmp);
267 env_set("dnsip2", tmp);
268 }
269 #endif
270 if (net_nis_domain[0])
271 env_set("domain", net_nis_domain);
272
273 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
274 if (net_ntp_time_offset) {
275 sprintf(tmp, "%d", net_ntp_time_offset);
276 env_set("timeoffset", tmp);
277 }
278 #endif
279 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
280 if (net_ntp_server.s_addr) {
281 ip_to_string(net_ntp_server, tmp);
282 env_set("ntpserverip", tmp);
283 }
284 #endif
285 }
286
netboot_common(enum proto_t proto,cmd_tbl_t * cmdtp,int argc,char * const argv[])287 static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,
288 char * const argv[])
289 {
290 char *s;
291 char *end;
292 int rcode = 0;
293 int size;
294 ulong addr;
295
296 /* pre-set load_addr */
297 s = env_get("loadaddr");
298 if (s != NULL)
299 load_addr = simple_strtoul(s, NULL, 16);
300
301 switch (argc) {
302 case 1:
303 break;
304
305 case 2: /*
306 * Only one arg - accept two forms:
307 * Just load address, or just boot file name. The latter
308 * form must be written in a format which can not be
309 * mis-interpreted as a valid number.
310 */
311 addr = simple_strtoul(argv[1], &end, 16);
312 if (end == (argv[1] + strlen(argv[1])))
313 load_addr = addr;
314 else
315 copy_filename(net_boot_file_name, argv[1],
316 sizeof(net_boot_file_name));
317 break;
318
319 case 3:
320 load_addr = simple_strtoul(argv[1], NULL, 16);
321 copy_filename(net_boot_file_name, argv[2],
322 sizeof(net_boot_file_name));
323
324 break;
325
326 #ifdef CONFIG_CMD_TFTPPUT
327 case 4:
328 if (strict_strtoul(argv[1], 16, &save_addr) < 0 ||
329 strict_strtoul(argv[2], 16, &save_size) < 0) {
330 printf("Invalid address/size\n");
331 return CMD_RET_USAGE;
332 }
333 copy_filename(net_boot_file_name, argv[3],
334 sizeof(net_boot_file_name));
335 break;
336 #endif
337 default:
338 bootstage_error(BOOTSTAGE_ID_NET_START);
339 return CMD_RET_USAGE;
340 }
341 bootstage_mark(BOOTSTAGE_ID_NET_START);
342
343 size = net_loop(proto);
344 if (size < 0) {
345 bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK);
346 return CMD_RET_FAILURE;
347 }
348 bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);
349
350 /* net_loop ok, update environment */
351 netboot_update_env();
352
353 /* done if no file was loaded (no errors though) */
354 if (size == 0) {
355 bootstage_error(BOOTSTAGE_ID_NET_LOADED);
356 return CMD_RET_SUCCESS;
357 }
358
359 bootstage_mark(BOOTSTAGE_ID_NET_LOADED);
360
361 rcode = bootm_maybe_autostart(cmdtp, argv[0]);
362
363 if (rcode == CMD_RET_SUCCESS)
364 bootstage_mark(BOOTSTAGE_ID_NET_DONE);
365 else
366 bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR);
367 return rcode;
368 }
369
370 #if defined(CONFIG_CMD_PING)
do_ping(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])371 static int do_ping(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
372 {
373 if (argc < 2)
374 return CMD_RET_USAGE;
375
376 net_ping_ip = string_to_ip(argv[1]);
377 if (net_ping_ip.s_addr == 0)
378 return CMD_RET_USAGE;
379
380 if (net_loop(PING) < 0) {
381 printf("ping failed; host %s is not alive\n", argv[1]);
382 return CMD_RET_FAILURE;
383 }
384
385 printf("host %s is alive\n", argv[1]);
386
387 return CMD_RET_SUCCESS;
388 }
389
390 U_BOOT_CMD(
391 ping, 2, 1, do_ping,
392 "send ICMP ECHO_REQUEST to network host",
393 "pingAddress"
394 );
395 #endif
396
397 #if defined(CONFIG_CMD_CDP)
398
cdp_update_env(void)399 static void cdp_update_env(void)
400 {
401 char tmp[16];
402
403 if (cdp_appliance_vlan != htons(-1)) {
404 printf("CDP offered appliance VLAN %d\n",
405 ntohs(cdp_appliance_vlan));
406 vlan_to_string(cdp_appliance_vlan, tmp);
407 env_set("vlan", tmp);
408 net_our_vlan = cdp_appliance_vlan;
409 }
410
411 if (cdp_native_vlan != htons(-1)) {
412 printf("CDP offered native VLAN %d\n", ntohs(cdp_native_vlan));
413 vlan_to_string(cdp_native_vlan, tmp);
414 env_set("nvlan", tmp);
415 net_native_vlan = cdp_native_vlan;
416 }
417 }
418
do_cdp(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])419 int do_cdp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
420 {
421 int r;
422
423 r = net_loop(CDP);
424 if (r < 0) {
425 printf("cdp failed; perhaps not a CISCO switch?\n");
426 return CMD_RET_FAILURE;
427 }
428
429 cdp_update_env();
430
431 return CMD_RET_SUCCESS;
432 }
433
434 U_BOOT_CMD(
435 cdp, 1, 1, do_cdp,
436 "Perform CDP network configuration",
437 "\n"
438 );
439 #endif
440
441 #if defined(CONFIG_CMD_SNTP)
do_sntp(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])442 int do_sntp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
443 {
444 char *toff;
445
446 if (argc < 2) {
447 net_ntp_server = env_get_ip("ntpserverip");
448 if (net_ntp_server.s_addr == 0) {
449 printf("ntpserverip not set\n");
450 return CMD_RET_FAILURE;
451 }
452 } else {
453 net_ntp_server = string_to_ip(argv[1]);
454 if (net_ntp_server.s_addr == 0) {
455 printf("Bad NTP server IP address\n");
456 return CMD_RET_FAILURE;
457 }
458 }
459
460 toff = env_get("timeoffset");
461 if (toff == NULL)
462 net_ntp_time_offset = 0;
463 else
464 net_ntp_time_offset = simple_strtol(toff, NULL, 10);
465
466 if (net_loop(SNTP) < 0) {
467 printf("SNTP failed: host %pI4 not responding\n",
468 &net_ntp_server);
469 return CMD_RET_FAILURE;
470 }
471
472 return CMD_RET_SUCCESS;
473 }
474
475 U_BOOT_CMD(
476 sntp, 2, 1, do_sntp,
477 "synchronize RTC via network",
478 "[NTP server IP]\n"
479 );
480 #endif
481
482 #if defined(CONFIG_CMD_DNS)
do_dns(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])483 int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
484 {
485 if (argc == 1)
486 return CMD_RET_USAGE;
487
488 /*
489 * We should check for a valid hostname:
490 * - Each label must be between 1 and 63 characters long
491 * - the entire hostname has a maximum of 255 characters
492 * - only the ASCII letters 'a' through 'z' (case-insensitive),
493 * the digits '0' through '9', and the hyphen
494 * - cannot begin or end with a hyphen
495 * - no other symbols, punctuation characters, or blank spaces are
496 * permitted
497 * but hey - this is a minimalist implmentation, so only check length
498 * and let the name server deal with things.
499 */
500 if (strlen(argv[1]) >= 255) {
501 printf("dns error: hostname too long\n");
502 return CMD_RET_FAILURE;
503 }
504
505 net_dns_resolve = argv[1];
506
507 if (argc == 3)
508 net_dns_env_var = argv[2];
509 else
510 net_dns_env_var = NULL;
511
512 if (net_loop(DNS) < 0) {
513 printf("dns lookup of %s failed, check setup\n", argv[1]);
514 return CMD_RET_FAILURE;
515 }
516
517 return CMD_RET_SUCCESS;
518 }
519
520 U_BOOT_CMD(
521 dns, 3, 1, do_dns,
522 "lookup the IP of a hostname",
523 "hostname [envvar]"
524 );
525
526 #endif /* CONFIG_CMD_DNS */
527
528 #if defined(CONFIG_CMD_LINK_LOCAL)
do_link_local(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])529 static int do_link_local(cmd_tbl_t *cmdtp, int flag, int argc,
530 char * const argv[])
531 {
532 char tmp[22];
533
534 if (net_loop(LINKLOCAL) < 0)
535 return CMD_RET_FAILURE;
536
537 net_gateway.s_addr = 0;
538 ip_to_string(net_gateway, tmp);
539 env_set("gatewayip", tmp);
540
541 ip_to_string(net_netmask, tmp);
542 env_set("netmask", tmp);
543
544 ip_to_string(net_ip, tmp);
545 env_set("ipaddr", tmp);
546 env_set("llipaddr", tmp); /* store this for next time */
547
548 return CMD_RET_SUCCESS;
549 }
550
551 U_BOOT_CMD(
552 linklocal, 1, 1, do_link_local,
553 "acquire a network IP address using the link-local protocol",
554 ""
555 );
556
557 #endif /* CONFIG_CMD_LINK_LOCAL */
558