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 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 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 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 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 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) 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) 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 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 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) 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 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 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) 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) 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) 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