pxe.c 5.2 KB

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