1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2010-2011 Calxeda, Inc.
4 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
14 #include "pxe_utils.h"
17 const char *pxe_default_paths
[] = {
19 #ifdef CONFIG_SYS_BOARD
20 "default-" CONFIG_SYS_ARCH
"-" CONFIG_SYS_SOC
"-" CONFIG_SYS_BOARD
,
22 "default-" CONFIG_SYS_ARCH
"-" CONFIG_SYS_SOC
,
24 "default-" CONFIG_SYS_ARCH
,
29 static int do_get_tftp(struct pxe_context
*ctx
, const char *file_path
,
30 char *file_addr
, ulong
*sizep
)
32 char *tftp_argv
[] = {"tftp", NULL
, NULL
, NULL
};
36 tftp_argv
[1] = file_addr
;
37 tftp_argv
[2] = (void *)file_path
;
39 tftp_argv
[3] = USE_IP6_CMD_PARAM
;
45 if (do_tftpb(ctx
->cmdtp
, 0, num_args
, tftp_argv
))
48 ret
= pxe_get_file_size(sizep
);
50 return log_msg_ret("tftp", ret
);
51 ctx
->pxe_file_size
= *sizep
;
57 * Looks for a pxe file with specified config file name,
58 * which is received from DHCPv4 option 209 or
61 * Returns 1 on success or < 0 on error.
63 static int pxe_dhcp_option_path(struct pxe_context
*ctx
, unsigned long pxefile_addr_r
)
65 int ret
= get_pxe_file(ctx
, pxelinux_configfile
, pxefile_addr_r
);
67 free(pxelinux_configfile
);
73 * Looks for a pxe file with a name based on the pxeuuid environment variable.
75 * Returns 1 on success or < 0 on error.
77 static int pxe_uuid_path(struct pxe_context
*ctx
, unsigned long pxefile_addr_r
)
81 uuid_str
= from_env("pxeuuid");
86 return get_pxelinux_path(ctx
, uuid_str
, pxefile_addr_r
);
90 * Looks for a pxe file with a name based on the 'ethaddr' environment
93 * Returns 1 on success or < 0 on error.
95 static int pxe_mac_path(struct pxe_context
*ctx
, unsigned long pxefile_addr_r
)
100 err
= format_mac_pxe(mac_str
, sizeof(mac_str
));
105 return get_pxelinux_path(ctx
, mac_str
, pxefile_addr_r
);
109 * Looks for pxe files with names based on our IP address. See pxelinux
110 * documentation for details on what these file names look like. We match
113 * Returns 1 on success or < 0 on error.
115 static int pxe_ipaddr_paths(struct pxe_context
*ctx
, unsigned long pxefile_addr_r
)
120 sprintf(ip_addr
, "%08X", ntohl(net_ip
.s_addr
));
122 for (mask_pos
= 7; mask_pos
>= 0; mask_pos
--) {
123 err
= get_pxelinux_path(ctx
, ip_addr
, pxefile_addr_r
);
128 ip_addr
[mask_pos
] = '\0';
134 int pxe_get(ulong pxefile_addr_r
, char **bootdirp
, ulong
*sizep
, bool use_ipv6
)
136 struct cmd_tbl cmdtp
[] = {}; /* dummy */
137 struct pxe_context ctx
;
140 if (pxe_setup_ctx(&ctx
, cmdtp
, do_get_tftp
, NULL
, false,
141 env_get("bootfile"), use_ipv6
, false))
144 if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION
) &&
145 pxelinux_configfile
&& !use_ipv6
) {
146 if (pxe_dhcp_option_path(&ctx
, pxefile_addr_r
) > 0)
152 if (IS_ENABLED(CONFIG_DHCP6_PXE_DHCP_OPTION
) &&
153 pxelinux_configfile
&& use_ipv6
) {
154 if (pxe_dhcp_option_path(&ctx
, pxefile_addr_r
) > 0)
161 * Keep trying paths until we successfully get a file we're looking
164 if (pxe_uuid_path(&ctx
, pxefile_addr_r
) > 0 ||
165 pxe_mac_path(&ctx
, pxefile_addr_r
) > 0 ||
166 pxe_ipaddr_paths(&ctx
, pxefile_addr_r
) > 0)
170 while (pxe_default_paths
[i
]) {
171 if (get_pxelinux_path(&ctx
, pxe_default_paths
[i
],
178 pxe_destroy_ctx(&ctx
);
182 *bootdirp
= env_get("bootfile");
185 * The PXE file size is returned but not the name. It is probably not
188 *sizep
= ctx
.pxe_file_size
;
189 pxe_destroy_ctx(&ctx
);
195 * Entry point for the 'pxe get' command.
196 * This Follows pxelinux's rules to download a config file from a tftp server.
197 * The file is stored at the location given by the pxefile_addr_r environment
198 * variable, which must be set.
200 * UUID comes from pxeuuid env variable, if defined
201 * MAC addr comes from ethaddr env variable, if defined
204 * see http://syslinux.zytor.com/wiki/index.php/PXELINUX
206 * Returns 0 on success or 1 on error.
209 do_pxe_get(struct cmd_tbl
*cmdtp
, int flag
, int argc
, char *const argv
[])
211 char *pxefile_addr_str
;
212 ulong pxefile_addr_r
;
216 bool use_ipv6
= false;
218 if (IS_ENABLED(CONFIG_IPV6
)) {
219 if (!strcmp(argv
[argc
- 1], USE_IP6_CMD_PARAM
))
222 if (!(argc
== 1 || (argc
== 2 && use_ipv6
)))
223 return CMD_RET_USAGE
;
226 return CMD_RET_USAGE
;
229 pxefile_addr_str
= from_env("pxefile_addr_r");
231 if (!pxefile_addr_str
)
234 ret
= strict_strtoul(pxefile_addr_str
, 16,
235 (unsigned long *)&pxefile_addr_r
);
239 ret
= pxe_get(pxefile_addr_r
, &fname
, &size
, use_ipv6
);
242 printf("Config file '%s' found\n", fname
);
245 printf("Out of memory\n");
246 return CMD_RET_FAILURE
;
248 printf("Config file not found\n");
249 return CMD_RET_FAILURE
;
256 * Boots a system using a pxe file
258 * Returns 0 on success, 1 on error.
261 do_pxe_boot(struct cmd_tbl
*cmdtp
, int flag
, int argc
, char *const argv
[])
263 unsigned long pxefile_addr_r
;
264 char *pxefile_addr_str
;
265 struct pxe_context ctx
;
267 bool use_ipv6
= false;
269 if (IS_ENABLED(CONFIG_IPV6
)) {
270 if (!strcmp(argv
[argc
- 1], USE_IP6_CMD_PARAM
))
274 if (argc
== 1 || (argc
== 2 && use_ipv6
)) {
275 pxefile_addr_str
= from_env("pxefile_addr_r");
276 if (!pxefile_addr_str
)
279 } else if (argc
== 2 || (argc
== 3 && use_ipv6
)) {
280 pxefile_addr_str
= argv
[1];
282 return CMD_RET_USAGE
;
285 if (strict_strtoul(pxefile_addr_str
, 16, &pxefile_addr_r
) < 0) {
286 printf("Invalid pxefile address: %s\n", pxefile_addr_str
);
290 if (pxe_setup_ctx(&ctx
, cmdtp
, do_get_tftp
, NULL
, false,
291 env_get("bootfile"), use_ipv6
, false)) {
292 printf("Out of memory\n");
293 return CMD_RET_FAILURE
;
295 ret
= pxe_process(&ctx
, pxefile_addr_r
, false);
296 pxe_destroy_ctx(&ctx
);
298 return CMD_RET_FAILURE
;
300 copy_filename(net_boot_file_name
, "", sizeof(net_boot_file_name
));
305 static struct cmd_tbl cmd_pxe_sub
[] = {
306 U_BOOT_CMD_MKENT(get
, 2, 1, do_pxe_get
, "", ""),
307 U_BOOT_CMD_MKENT(boot
, 3, 1, do_pxe_boot
, "", "")
310 static int do_pxe(struct cmd_tbl
*cmdtp
, int flag
, int argc
, char *const argv
[])
315 return CMD_RET_USAGE
;
317 /* drop initial "pxe" arg */
321 cp
= find_cmd_tbl(argv
[0], cmd_pxe_sub
, ARRAY_SIZE(cmd_pxe_sub
));
324 return cp
->cmd(cmdtp
, flag
, argc
, argv
);
326 return CMD_RET_USAGE
;
329 U_BOOT_CMD(pxe
, 4, 1, do_pxe
,
330 "get and boot from pxe files",
331 "get [" USE_IP6_CMD_PARAM
"] - try to retrieve a pxe file using tftp\n"
332 "pxe boot [pxefile_addr_r] [-ipv6] - boot from the pxe file at pxefile_addr_r\n"
335 #endif /* CONFIG_CMD_NET */