pxe.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2010-2011 Calxeda, Inc.
  4. * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
  5. */
  6. #include <common.h>
  7. #include <command.h>
  8. #include "pxe_utils.h"
  9. #ifdef CONFIG_CMD_NET
  10. const char *pxe_default_paths[] = {
  11. #ifdef CONFIG_SYS_SOC
  12. #ifdef CONFIG_SYS_BOARD
  13. "default-" CONFIG_SYS_ARCH "-" CONFIG_SYS_SOC "-" CONFIG_SYS_BOARD,
  14. #endif
  15. "default-" CONFIG_SYS_ARCH "-" CONFIG_SYS_SOC,
  16. #endif
  17. "default-" CONFIG_SYS_ARCH,
  18. "default",
  19. NULL
  20. };
  21. static int do_get_tftp(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
  22. {
  23. char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
  24. tftp_argv[1] = file_addr;
  25. tftp_argv[2] = (void *)file_path;
  26. if (do_tftpb(cmdtp, 0, 3, tftp_argv))
  27. return -ENOENT;
  28. return 1;
  29. }
  30. /*
  31. * Looks for a pxe file with a name based on the pxeuuid environment variable.
  32. *
  33. * Returns 1 on success or < 0 on error.
  34. */
  35. static int pxe_uuid_path(cmd_tbl_t *cmdtp, unsigned long pxefile_addr_r)
  36. {
  37. char *uuid_str;
  38. uuid_str = from_env("pxeuuid");
  39. if (!uuid_str)
  40. return -ENOENT;
  41. return get_pxelinux_path(cmdtp, uuid_str, pxefile_addr_r);
  42. }
  43. /*
  44. * Looks for a pxe file with a name based on the 'ethaddr' environment
  45. * variable.
  46. *
  47. * Returns 1 on success or < 0 on error.
  48. */
  49. static int pxe_mac_path(cmd_tbl_t *cmdtp, unsigned long pxefile_addr_r)
  50. {
  51. char mac_str[21];
  52. int err;
  53. err = format_mac_pxe(mac_str, sizeof(mac_str));
  54. if (err < 0)
  55. return err;
  56. return get_pxelinux_path(cmdtp, mac_str, pxefile_addr_r);
  57. }
  58. /*
  59. * Looks for pxe files with names based on our IP address. See pxelinux
  60. * documentation for details on what these file names look like. We match
  61. * that exactly.
  62. *
  63. * Returns 1 on success or < 0 on error.
  64. */
  65. static int pxe_ipaddr_paths(cmd_tbl_t *cmdtp, unsigned long pxefile_addr_r)
  66. {
  67. char ip_addr[9];
  68. int mask_pos, err;
  69. sprintf(ip_addr, "%08X", ntohl(net_ip.s_addr));
  70. for (mask_pos = 7; mask_pos >= 0; mask_pos--) {
  71. err = get_pxelinux_path(cmdtp, ip_addr, pxefile_addr_r);
  72. if (err > 0)
  73. return err;
  74. ip_addr[mask_pos] = '\0';
  75. }
  76. return -ENOENT;
  77. }
  78. /*
  79. * Entry point for the 'pxe get' command.
  80. * This Follows pxelinux's rules to download a config file from a tftp server.
  81. * The file is stored at the location given by the pxefile_addr_r environment
  82. * variable, which must be set.
  83. *
  84. * UUID comes from pxeuuid env variable, if defined
  85. * MAC addr comes from ethaddr env variable, if defined
  86. * IP
  87. *
  88. * see http://syslinux.zytor.com/wiki/index.php/PXELINUX
  89. *
  90. * Returns 0 on success or 1 on error.
  91. */
  92. static int
  93. do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  94. {
  95. char *pxefile_addr_str;
  96. unsigned long pxefile_addr_r;
  97. int err, i = 0;
  98. do_getfile = do_get_tftp;
  99. if (argc != 1)
  100. return CMD_RET_USAGE;
  101. pxefile_addr_str = from_env("pxefile_addr_r");
  102. if (!pxefile_addr_str)
  103. return 1;
  104. err = strict_strtoul(pxefile_addr_str, 16,
  105. (unsigned long *)&pxefile_addr_r);
  106. if (err < 0)
  107. return 1;
  108. /*
  109. * Keep trying paths until we successfully get a file we're looking
  110. * for.
  111. */
  112. if (pxe_uuid_path(cmdtp, pxefile_addr_r) > 0 ||
  113. pxe_mac_path(cmdtp, pxefile_addr_r) > 0 ||
  114. pxe_ipaddr_paths(cmdtp, pxefile_addr_r) > 0) {
  115. printf("Config file found\n");
  116. return 0;
  117. }
  118. while (pxe_default_paths[i]) {
  119. if (get_pxelinux_path(cmdtp, pxe_default_paths[i],
  120. pxefile_addr_r) > 0) {
  121. printf("Config file found\n");
  122. return 0;
  123. }
  124. i++;
  125. }
  126. printf("Config file not found\n");
  127. return 1;
  128. }
  129. /*
  130. * Boots a system using a pxe file
  131. *
  132. * Returns 0 on success, 1 on error.
  133. */
  134. static int
  135. do_pxe_boot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  136. {
  137. unsigned long pxefile_addr_r;
  138. struct pxe_menu *cfg;
  139. char *pxefile_addr_str;
  140. do_getfile = do_get_tftp;
  141. if (argc == 1) {
  142. pxefile_addr_str = from_env("pxefile_addr_r");
  143. if (!pxefile_addr_str)
  144. return 1;
  145. } else if (argc == 2) {
  146. pxefile_addr_str = argv[1];
  147. } else {
  148. return CMD_RET_USAGE;
  149. }
  150. if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) {
  151. printf("Invalid pxefile address: %s\n", pxefile_addr_str);
  152. return 1;
  153. }
  154. cfg = parse_pxefile(cmdtp, pxefile_addr_r);
  155. if (!cfg) {
  156. printf("Error parsing config file\n");
  157. return 1;
  158. }
  159. handle_pxe_menu(cmdtp, cfg);
  160. destroy_pxe_menu(cfg);
  161. copy_filename(net_boot_file_name, "", sizeof(net_boot_file_name));
  162. return 0;
  163. }
  164. static cmd_tbl_t cmd_pxe_sub[] = {
  165. U_BOOT_CMD_MKENT(get, 1, 1, do_pxe_get, "", ""),
  166. U_BOOT_CMD_MKENT(boot, 2, 1, do_pxe_boot, "", "")
  167. };
  168. static int do_pxe(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  169. {
  170. cmd_tbl_t *cp;
  171. if (argc < 2)
  172. return CMD_RET_USAGE;
  173. is_pxe = true;
  174. /* drop initial "pxe" arg */
  175. argc--;
  176. argv++;
  177. cp = find_cmd_tbl(argv[0], cmd_pxe_sub, ARRAY_SIZE(cmd_pxe_sub));
  178. if (cp)
  179. return cp->cmd(cmdtp, flag, argc, argv);
  180. return CMD_RET_USAGE;
  181. }
  182. U_BOOT_CMD(pxe, 3, 1, do_pxe,
  183. "commands to get and boot from pxe files",
  184. "get - try to retrieve a pxe file using tftp\n"
  185. "pxe boot [pxefile_addr_r] - boot from the pxe file at pxefile_addr_r\n"
  186. );
  187. #endif