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 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 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 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 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 ret = blk_dwrite(dev_desc, part.start, blknum, (void *)fileaddr); 132 if (ret != blknum) 133 printf("Failed(%d)\n", ret); 134 else 135 printf("OK\n"); 136 137 return 0; 138 } 139 140 U_BOOT_CMD( 141 tftpflash, 4, 0, do_tftpflash, 142 "flash image via network using TFTP protocol", 143 "[loadAddress] [[hostIPaddr:]bootfilename] [partition]" 144 ); 145 #endif 146 147 #ifdef CONFIG_CMD_TFTPPUT 148 static int do_tftpput(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 149 { 150 return netboot_common(TFTPPUT, cmdtp, argc, argv); 151 } 152 153 U_BOOT_CMD( 154 tftpput, 4, 1, do_tftpput, 155 "TFTP put command, for uploading files to a server", 156 "Address Size [[hostIPaddr:]filename]" 157 ); 158 #endif 159 160 #ifdef CONFIG_CMD_TFTPSRV 161 static int do_tftpsrv(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 162 { 163 return netboot_common(TFTPSRV, cmdtp, argc, argv); 164 } 165 166 U_BOOT_CMD( 167 tftpsrv, 2, 1, do_tftpsrv, 168 "act as a TFTP server and boot the first received file", 169 "[loadAddress]\n" 170 "Listen for an incoming TFTP transfer, receive a file and boot it.\n" 171 "The transfer is aborted if a transfer has not been started after\n" 172 "about 50 seconds or if Ctrl-C is pressed." 173 ); 174 #endif 175 176 #ifdef CONFIG_UDP_FUNCTION_FASTBOOT 177 int do_fastboot_udp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 178 { 179 return netboot_common(FASTBOOT, cmdtp, argc, argv); 180 } 181 #endif 182 183 #ifdef CONFIG_CMD_RARP 184 int do_rarpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 185 { 186 return netboot_common(RARP, cmdtp, argc, argv); 187 } 188 189 U_BOOT_CMD( 190 rarpboot, 3, 1, do_rarpb, 191 "boot image via network using RARP/TFTP protocol", 192 "[loadAddress] [[hostIPaddr:]bootfilename]" 193 ); 194 #endif 195 196 #if defined(CONFIG_CMD_DHCP) 197 static int do_dhcp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 198 { 199 return netboot_common(DHCP, cmdtp, argc, argv); 200 } 201 202 U_BOOT_CMD( 203 dhcp, 3, 1, do_dhcp, 204 "boot image via network using DHCP/TFTP protocol", 205 "[loadAddress] [[hostIPaddr:]bootfilename]" 206 ); 207 #endif 208 209 #if defined(CONFIG_CMD_NFS) 210 static int do_nfs(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 211 { 212 return netboot_common(NFS, cmdtp, argc, argv); 213 } 214 215 U_BOOT_CMD( 216 nfs, 3, 1, do_nfs, 217 "boot image via network using NFS protocol", 218 "[loadAddress] [[hostIPaddr:]bootfilename]" 219 ); 220 #endif 221 222 static void netboot_update_env(void) 223 { 224 char tmp[22]; 225 226 if (net_gateway.s_addr) { 227 ip_to_string(net_gateway, tmp); 228 env_set("gatewayip", tmp); 229 } 230 231 if (net_netmask.s_addr) { 232 ip_to_string(net_netmask, tmp); 233 env_set("netmask", tmp); 234 } 235 236 if (net_hostname[0]) 237 env_set("hostname", net_hostname); 238 239 if (net_root_path[0]) 240 env_set("rootpath", net_root_path); 241 242 if (net_ip.s_addr) { 243 ip_to_string(net_ip, tmp); 244 env_set("ipaddr", tmp); 245 } 246 #if !defined(CONFIG_BOOTP_SERVERIP) 247 /* 248 * Only attempt to change serverip if net/bootp.c:store_net_params() 249 * could have set it 250 */ 251 if (net_server_ip.s_addr) { 252 ip_to_string(net_server_ip, tmp); 253 env_set("serverip", tmp); 254 } 255 #endif 256 if (net_dns_server.s_addr) { 257 ip_to_string(net_dns_server, tmp); 258 env_set("dnsip", tmp); 259 } 260 #if defined(CONFIG_BOOTP_DNS2) 261 if (net_dns_server2.s_addr) { 262 ip_to_string(net_dns_server2, tmp); 263 env_set("dnsip2", tmp); 264 } 265 #endif 266 if (net_nis_domain[0]) 267 env_set("domain", net_nis_domain); 268 269 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET) 270 if (net_ntp_time_offset) { 271 sprintf(tmp, "%d", net_ntp_time_offset); 272 env_set("timeoffset", tmp); 273 } 274 #endif 275 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER) 276 if (net_ntp_server.s_addr) { 277 ip_to_string(net_ntp_server, tmp); 278 env_set("ntpserverip", tmp); 279 } 280 #endif 281 } 282 283 static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc, 284 char * const argv[]) 285 { 286 char *s; 287 char *end; 288 int rcode = 0; 289 int size; 290 ulong addr; 291 292 /* pre-set load_addr */ 293 s = env_get("loadaddr"); 294 if (s != NULL) 295 load_addr = simple_strtoul(s, NULL, 16); 296 297 switch (argc) { 298 case 1: 299 break; 300 301 case 2: /* 302 * Only one arg - accept two forms: 303 * Just load address, or just boot file name. The latter 304 * form must be written in a format which can not be 305 * mis-interpreted as a valid number. 306 */ 307 addr = simple_strtoul(argv[1], &end, 16); 308 if (end == (argv[1] + strlen(argv[1]))) 309 load_addr = addr; 310 else 311 copy_filename(net_boot_file_name, argv[1], 312 sizeof(net_boot_file_name)); 313 break; 314 315 case 3: 316 load_addr = simple_strtoul(argv[1], NULL, 16); 317 copy_filename(net_boot_file_name, argv[2], 318 sizeof(net_boot_file_name)); 319 320 break; 321 322 #ifdef CONFIG_CMD_TFTPPUT 323 case 4: 324 if (strict_strtoul(argv[1], 16, &save_addr) < 0 || 325 strict_strtoul(argv[2], 16, &save_size) < 0) { 326 printf("Invalid address/size\n"); 327 return CMD_RET_USAGE; 328 } 329 copy_filename(net_boot_file_name, argv[3], 330 sizeof(net_boot_file_name)); 331 break; 332 #endif 333 default: 334 bootstage_error(BOOTSTAGE_ID_NET_START); 335 return CMD_RET_USAGE; 336 } 337 bootstage_mark(BOOTSTAGE_ID_NET_START); 338 339 size = net_loop(proto); 340 if (size < 0) { 341 bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); 342 return CMD_RET_FAILURE; 343 } 344 bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK); 345 346 /* net_loop ok, update environment */ 347 netboot_update_env(); 348 349 /* done if no file was loaded (no errors though) */ 350 if (size == 0) { 351 bootstage_error(BOOTSTAGE_ID_NET_LOADED); 352 return CMD_RET_SUCCESS; 353 } 354 355 bootstage_mark(BOOTSTAGE_ID_NET_LOADED); 356 357 rcode = bootm_maybe_autostart(cmdtp, argv[0]); 358 359 if (rcode == CMD_RET_SUCCESS) 360 bootstage_mark(BOOTSTAGE_ID_NET_DONE); 361 else 362 bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR); 363 return rcode; 364 } 365 366 #if defined(CONFIG_CMD_PING) 367 static int do_ping(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 368 { 369 if (argc < 2) 370 return CMD_RET_USAGE; 371 372 net_ping_ip = string_to_ip(argv[1]); 373 if (net_ping_ip.s_addr == 0) 374 return CMD_RET_USAGE; 375 376 if (net_loop(PING) < 0) { 377 printf("ping failed; host %s is not alive\n", argv[1]); 378 return CMD_RET_FAILURE; 379 } 380 381 printf("host %s is alive\n", argv[1]); 382 383 return CMD_RET_SUCCESS; 384 } 385 386 U_BOOT_CMD( 387 ping, 2, 1, do_ping, 388 "send ICMP ECHO_REQUEST to network host", 389 "pingAddress" 390 ); 391 #endif 392 393 #if defined(CONFIG_CMD_CDP) 394 395 static void cdp_update_env(void) 396 { 397 char tmp[16]; 398 399 if (cdp_appliance_vlan != htons(-1)) { 400 printf("CDP offered appliance VLAN %d\n", 401 ntohs(cdp_appliance_vlan)); 402 vlan_to_string(cdp_appliance_vlan, tmp); 403 env_set("vlan", tmp); 404 net_our_vlan = cdp_appliance_vlan; 405 } 406 407 if (cdp_native_vlan != htons(-1)) { 408 printf("CDP offered native VLAN %d\n", ntohs(cdp_native_vlan)); 409 vlan_to_string(cdp_native_vlan, tmp); 410 env_set("nvlan", tmp); 411 net_native_vlan = cdp_native_vlan; 412 } 413 } 414 415 int do_cdp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 416 { 417 int r; 418 419 r = net_loop(CDP); 420 if (r < 0) { 421 printf("cdp failed; perhaps not a CISCO switch?\n"); 422 return CMD_RET_FAILURE; 423 } 424 425 cdp_update_env(); 426 427 return CMD_RET_SUCCESS; 428 } 429 430 U_BOOT_CMD( 431 cdp, 1, 1, do_cdp, 432 "Perform CDP network configuration", 433 "\n" 434 ); 435 #endif 436 437 #if defined(CONFIG_CMD_SNTP) 438 int do_sntp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 439 { 440 char *toff; 441 442 if (argc < 2) { 443 net_ntp_server = env_get_ip("ntpserverip"); 444 if (net_ntp_server.s_addr == 0) { 445 printf("ntpserverip not set\n"); 446 return CMD_RET_FAILURE; 447 } 448 } else { 449 net_ntp_server = string_to_ip(argv[1]); 450 if (net_ntp_server.s_addr == 0) { 451 printf("Bad NTP server IP address\n"); 452 return CMD_RET_FAILURE; 453 } 454 } 455 456 toff = env_get("timeoffset"); 457 if (toff == NULL) 458 net_ntp_time_offset = 0; 459 else 460 net_ntp_time_offset = simple_strtol(toff, NULL, 10); 461 462 if (net_loop(SNTP) < 0) { 463 printf("SNTP failed: host %pI4 not responding\n", 464 &net_ntp_server); 465 return CMD_RET_FAILURE; 466 } 467 468 return CMD_RET_SUCCESS; 469 } 470 471 U_BOOT_CMD( 472 sntp, 2, 1, do_sntp, 473 "synchronize RTC via network", 474 "[NTP server IP]\n" 475 ); 476 #endif 477 478 #if defined(CONFIG_CMD_DNS) 479 int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 480 { 481 if (argc == 1) 482 return CMD_RET_USAGE; 483 484 /* 485 * We should check for a valid hostname: 486 * - Each label must be between 1 and 63 characters long 487 * - the entire hostname has a maximum of 255 characters 488 * - only the ASCII letters 'a' through 'z' (case-insensitive), 489 * the digits '0' through '9', and the hyphen 490 * - cannot begin or end with a hyphen 491 * - no other symbols, punctuation characters, or blank spaces are 492 * permitted 493 * but hey - this is a minimalist implmentation, so only check length 494 * and let the name server deal with things. 495 */ 496 if (strlen(argv[1]) >= 255) { 497 printf("dns error: hostname too long\n"); 498 return CMD_RET_FAILURE; 499 } 500 501 net_dns_resolve = argv[1]; 502 503 if (argc == 3) 504 net_dns_env_var = argv[2]; 505 else 506 net_dns_env_var = NULL; 507 508 if (net_loop(DNS) < 0) { 509 printf("dns lookup of %s failed, check setup\n", argv[1]); 510 return CMD_RET_FAILURE; 511 } 512 513 return CMD_RET_SUCCESS; 514 } 515 516 U_BOOT_CMD( 517 dns, 3, 1, do_dns, 518 "lookup the IP of a hostname", 519 "hostname [envvar]" 520 ); 521 522 #endif /* CONFIG_CMD_DNS */ 523 524 #if defined(CONFIG_CMD_LINK_LOCAL) 525 static int do_link_local(cmd_tbl_t *cmdtp, int flag, int argc, 526 char * const argv[]) 527 { 528 char tmp[22]; 529 530 if (net_loop(LINKLOCAL) < 0) 531 return CMD_RET_FAILURE; 532 533 net_gateway.s_addr = 0; 534 ip_to_string(net_gateway, tmp); 535 env_set("gatewayip", tmp); 536 537 ip_to_string(net_netmask, tmp); 538 env_set("netmask", tmp); 539 540 ip_to_string(net_ip, tmp); 541 env_set("ipaddr", tmp); 542 env_set("llipaddr", tmp); /* store this for next time */ 543 544 return CMD_RET_SUCCESS; 545 } 546 547 U_BOOT_CMD( 548 linklocal, 1, 1, do_link_local, 549 "acquire a network IP address using the link-local protocol", 550 "" 551 ); 552 553 #endif /* CONFIG_CMD_LINK_LOCAL */ 554