pxe_utils.c 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516
  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 <env.h>
  9. #include <image.h>
  10. #include <log.h>
  11. #include <malloc.h>
  12. #include <mapmem.h>
  13. #include <lcd.h>
  14. #include <net.h>
  15. #include <fdt_support.h>
  16. #include <linux/libfdt.h>
  17. #include <linux/string.h>
  18. #include <linux/ctype.h>
  19. #include <errno.h>
  20. #include <linux/list.h>
  21. #include <splash.h>
  22. #include <asm/io.h>
  23. #include "menu.h"
  24. #include "cli.h"
  25. #include "pxe_utils.h"
  26. #define MAX_TFTP_PATH_LEN 512
  27. int pxe_get_file_size(ulong *sizep)
  28. {
  29. const char *val;
  30. val = from_env("filesize");
  31. if (!val)
  32. return -ENOENT;
  33. if (strict_strtoul(val, 16, sizep) < 0)
  34. return -EINVAL;
  35. return 0;
  36. }
  37. /**
  38. * format_mac_pxe() - obtain a MAC address in the PXE format
  39. *
  40. * This produces a MAC-address string in the format for the current ethernet
  41. * device:
  42. *
  43. * 01-aa-bb-cc-dd-ee-ff
  44. *
  45. * where aa-ff is the MAC address in hex
  46. *
  47. * @outbuf: Buffer to write string to
  48. * @outbuf_len: length of buffer
  49. * @return 1 if OK, -ENOSPC if buffer is too small, -ENOENT is there is no
  50. * current ethernet device
  51. */
  52. int format_mac_pxe(char *outbuf, size_t outbuf_len)
  53. {
  54. uchar ethaddr[6];
  55. if (outbuf_len < 21) {
  56. printf("outbuf is too small (%zd < 21)\n", outbuf_len);
  57. return -ENOSPC;
  58. }
  59. if (!eth_env_get_enetaddr_by_index("eth", eth_get_dev_index(), ethaddr))
  60. return -ENOENT;
  61. sprintf(outbuf, "01-%02x-%02x-%02x-%02x-%02x-%02x",
  62. ethaddr[0], ethaddr[1], ethaddr[2],
  63. ethaddr[3], ethaddr[4], ethaddr[5]);
  64. return 1;
  65. }
  66. /**
  67. * get_relfile() - read a file relative to the PXE file
  68. *
  69. * As in pxelinux, paths to files referenced from files we retrieve are
  70. * relative to the location of bootfile. get_relfile takes such a path and
  71. * joins it with the bootfile path to get the full path to the target file. If
  72. * the bootfile path is NULL, we use file_path as is.
  73. *
  74. * @ctx: PXE context
  75. * @file_path: File path to read (relative to the PXE file)
  76. * @file_addr: Address to load file to
  77. * @filesizep: If not NULL, returns the file size in bytes
  78. * Returns 1 for success, or < 0 on error
  79. */
  80. static int get_relfile(struct pxe_context *ctx, const char *file_path,
  81. unsigned long file_addr, ulong *filesizep)
  82. {
  83. size_t path_len;
  84. char relfile[MAX_TFTP_PATH_LEN + 1];
  85. char addr_buf[18];
  86. ulong size;
  87. int ret;
  88. if (file_path[0] == '/' && ctx->allow_abs_path)
  89. *relfile = '\0';
  90. else
  91. strncpy(relfile, ctx->bootdir, MAX_TFTP_PATH_LEN);
  92. path_len = strlen(file_path) + strlen(relfile);
  93. if (path_len > MAX_TFTP_PATH_LEN) {
  94. printf("Base path too long (%s%s)\n", relfile, file_path);
  95. return -ENAMETOOLONG;
  96. }
  97. strcat(relfile, file_path);
  98. printf("Retrieving file: %s\n", relfile);
  99. sprintf(addr_buf, "%lx", file_addr);
  100. ret = ctx->getfile(ctx, relfile, addr_buf, &size);
  101. if (ret < 0)
  102. return log_msg_ret("get", ret);
  103. if (filesizep)
  104. *filesizep = size;
  105. return 1;
  106. }
  107. /**
  108. * get_pxe_file() - read a file
  109. *
  110. * The file is read and nul-terminated
  111. *
  112. * @ctx: PXE context
  113. * @file_path: File path to read (relative to the PXE file)
  114. * @file_addr: Address to load file to
  115. * Returns 1 for success, or < 0 on error
  116. */
  117. int get_pxe_file(struct pxe_context *ctx, const char *file_path,
  118. ulong file_addr)
  119. {
  120. ulong size;
  121. int err;
  122. char *buf;
  123. err = get_relfile(ctx, file_path, file_addr, &size);
  124. if (err < 0)
  125. return err;
  126. buf = map_sysmem(file_addr + size, 1);
  127. *buf = '\0';
  128. unmap_sysmem(buf);
  129. return 1;
  130. }
  131. #define PXELINUX_DIR "pxelinux.cfg/"
  132. /**
  133. * get_pxelinux_path() - Get a file in the pxelinux.cfg/ directory
  134. *
  135. * @ctx: PXE context
  136. * @file: Filename to process (relative to pxelinux.cfg/)
  137. * Returns 1 for success, -ENAMETOOLONG if the resulting path is too long.
  138. * or other value < 0 on other error
  139. */
  140. int get_pxelinux_path(struct pxe_context *ctx, const char *file,
  141. unsigned long pxefile_addr_r)
  142. {
  143. size_t base_len = strlen(PXELINUX_DIR);
  144. char path[MAX_TFTP_PATH_LEN + 1];
  145. if (base_len + strlen(file) > MAX_TFTP_PATH_LEN) {
  146. printf("path (%s%s) too long, skipping\n",
  147. PXELINUX_DIR, file);
  148. return -ENAMETOOLONG;
  149. }
  150. sprintf(path, PXELINUX_DIR "%s", file);
  151. return get_pxe_file(ctx, path, pxefile_addr_r);
  152. }
  153. /**
  154. * get_relfile_envaddr() - read a file to an address in an env var
  155. *
  156. * Wrapper to make it easier to store the file at file_path in the location
  157. * specified by envaddr_name. file_path will be joined to the bootfile path,
  158. * if any is specified.
  159. *
  160. * @ctx: PXE context
  161. * @file_path: File path to read (relative to the PXE file)
  162. * @envaddr_name: Name of environment variable which contains the address to
  163. * load to
  164. * @filesizep: Returns the file size in bytes
  165. * Returns 1 on success, -ENOENT if @envaddr_name does not exist as an
  166. * environment variable, -EINVAL if its format is not valid hex, or other
  167. * value < 0 on other error
  168. */
  169. static int get_relfile_envaddr(struct pxe_context *ctx, const char *file_path,
  170. const char *envaddr_name, ulong *filesizep)
  171. {
  172. unsigned long file_addr;
  173. char *envaddr;
  174. envaddr = from_env(envaddr_name);
  175. if (!envaddr)
  176. return -ENOENT;
  177. if (strict_strtoul(envaddr, 16, &file_addr) < 0)
  178. return -EINVAL;
  179. return get_relfile(ctx, file_path, file_addr, filesizep);
  180. }
  181. /**
  182. * label_create() - crate a new PXE label
  183. *
  184. * Allocates memory for and initializes a pxe_label. This uses malloc, so the
  185. * result must be free()'d to reclaim the memory.
  186. *
  187. * Returns a pointer to the label, or NULL if out of memory
  188. */
  189. static struct pxe_label *label_create(void)
  190. {
  191. struct pxe_label *label;
  192. label = malloc(sizeof(struct pxe_label));
  193. if (!label)
  194. return NULL;
  195. memset(label, 0, sizeof(struct pxe_label));
  196. return label;
  197. }
  198. /**
  199. * label_destroy() - free the memory used by a pxe_label
  200. *
  201. * This frees @label itself as well as memory used by its name,
  202. * kernel, config, append, initrd, fdt, fdtdir and fdtoverlay members, if
  203. * they're non-NULL.
  204. *
  205. * So - be sure to only use dynamically allocated memory for the members of
  206. * the pxe_label struct, unless you want to clean it up first. These are
  207. * currently only created by the pxe file parsing code.
  208. *
  209. * @label: Label to free
  210. */
  211. static void label_destroy(struct pxe_label *label)
  212. {
  213. free(label->name);
  214. free(label->kernel);
  215. free(label->config);
  216. free(label->append);
  217. free(label->initrd);
  218. free(label->fdt);
  219. free(label->fdtdir);
  220. free(label->fdtoverlays);
  221. free(label);
  222. }
  223. /**
  224. * label_print() - Print a label and its string members if they're defined
  225. *
  226. * This is passed as a callback to the menu code for displaying each
  227. * menu entry.
  228. *
  229. * @data: Label to print (is cast to struct pxe_label *)
  230. */
  231. static void label_print(void *data)
  232. {
  233. struct pxe_label *label = data;
  234. const char *c = label->menu ? label->menu : label->name;
  235. printf("%s:\t%s\n", label->num, c);
  236. }
  237. /**
  238. * label_localboot() - Boot a label that specified 'localboot'
  239. *
  240. * This requires that the 'localcmd' environment variable is defined. Its
  241. * contents will be executed as U-Boot commands. If the label specified an
  242. * 'append' line, its contents will be used to overwrite the contents of the
  243. * 'bootargs' environment variable prior to running 'localcmd'.
  244. *
  245. * @label: Label to process
  246. * Returns 1 on success or < 0 on error
  247. */
  248. static int label_localboot(struct pxe_label *label)
  249. {
  250. char *localcmd;
  251. localcmd = from_env("localcmd");
  252. if (!localcmd)
  253. return -ENOENT;
  254. if (label->append) {
  255. char bootargs[CONFIG_SYS_CBSIZE];
  256. cli_simple_process_macros(label->append, bootargs,
  257. sizeof(bootargs));
  258. env_set("bootargs", bootargs);
  259. }
  260. debug("running: %s\n", localcmd);
  261. return run_command_list(localcmd, strlen(localcmd), 0);
  262. }
  263. /**
  264. * label_boot_fdtoverlay() - Loads fdt overlays specified in 'fdtoverlays'
  265. *
  266. * @ctx: PXE context
  267. * @label: Label to process
  268. */
  269. #ifdef CONFIG_OF_LIBFDT_OVERLAY
  270. static void label_boot_fdtoverlay(struct pxe_context *ctx,
  271. struct pxe_label *label)
  272. {
  273. char *fdtoverlay = label->fdtoverlays;
  274. struct fdt_header *working_fdt;
  275. char *fdtoverlay_addr_env;
  276. ulong fdtoverlay_addr;
  277. ulong fdt_addr;
  278. int err;
  279. /* Get the main fdt and map it */
  280. fdt_addr = hextoul(env_get("fdt_addr_r"), NULL);
  281. working_fdt = map_sysmem(fdt_addr, 0);
  282. err = fdt_check_header(working_fdt);
  283. if (err)
  284. return;
  285. /* Get the specific overlay loading address */
  286. fdtoverlay_addr_env = env_get("fdtoverlay_addr_r");
  287. if (!fdtoverlay_addr_env) {
  288. printf("Invalid fdtoverlay_addr_r for loading overlays\n");
  289. return;
  290. }
  291. fdtoverlay_addr = hextoul(fdtoverlay_addr_env, NULL);
  292. /* Cycle over the overlay files and apply them in order */
  293. do {
  294. struct fdt_header *blob;
  295. char *overlayfile;
  296. char *end;
  297. int len;
  298. /* Drop leading spaces */
  299. while (*fdtoverlay == ' ')
  300. ++fdtoverlay;
  301. /* Copy a single filename if multiple provided */
  302. end = strstr(fdtoverlay, " ");
  303. if (end) {
  304. len = (int)(end - fdtoverlay);
  305. overlayfile = malloc(len + 1);
  306. strncpy(overlayfile, fdtoverlay, len);
  307. overlayfile[len] = '\0';
  308. } else
  309. overlayfile = fdtoverlay;
  310. if (!strlen(overlayfile))
  311. goto skip_overlay;
  312. /* Load overlay file */
  313. err = get_relfile_envaddr(ctx, overlayfile, "fdtoverlay_addr_r",
  314. NULL);
  315. if (err < 0) {
  316. printf("Failed loading overlay %s\n", overlayfile);
  317. goto skip_overlay;
  318. }
  319. /* Resize main fdt */
  320. fdt_shrink_to_minimum(working_fdt, 8192);
  321. blob = map_sysmem(fdtoverlay_addr, 0);
  322. err = fdt_check_header(blob);
  323. if (err) {
  324. printf("Invalid overlay %s, skipping\n",
  325. overlayfile);
  326. goto skip_overlay;
  327. }
  328. err = fdt_overlay_apply_verbose(working_fdt, blob);
  329. if (err) {
  330. printf("Failed to apply overlay %s, skipping\n",
  331. overlayfile);
  332. goto skip_overlay;
  333. }
  334. skip_overlay:
  335. if (end)
  336. free(overlayfile);
  337. } while ((fdtoverlay = strstr(fdtoverlay, " ")));
  338. }
  339. #endif
  340. /**
  341. * label_boot() - Boot according to the contents of a pxe_label
  342. *
  343. * If we can't boot for any reason, we return. A successful boot never
  344. * returns.
  345. *
  346. * The kernel will be stored in the location given by the 'kernel_addr_r'
  347. * environment variable.
  348. *
  349. * If the label specifies an initrd file, it will be stored in the location
  350. * given by the 'ramdisk_addr_r' environment variable.
  351. *
  352. * If the label specifies an 'append' line, its contents will overwrite that
  353. * of the 'bootargs' environment variable.
  354. *
  355. * @ctx: PXE context
  356. * @label: Label to process
  357. * Returns does not return on success, otherwise returns 0 if a localboot
  358. * label was processed, or 1 on error
  359. */
  360. static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
  361. {
  362. char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL };
  363. char *zboot_argv[] = { "zboot", NULL, "0", NULL, NULL };
  364. char *kernel_addr = NULL;
  365. char *initrd_addr_str = NULL;
  366. char initrd_filesize[10];
  367. char initrd_str[28];
  368. char mac_str[29] = "";
  369. char ip_str[68] = "";
  370. char *fit_addr = NULL;
  371. int bootm_argc = 2;
  372. int zboot_argc = 3;
  373. int len = 0;
  374. ulong kernel_addr_r;
  375. void *buf;
  376. label_print(label);
  377. label->attempted = 1;
  378. if (label->localboot) {
  379. if (label->localboot_val >= 0)
  380. label_localboot(label);
  381. return 0;
  382. }
  383. if (!label->kernel) {
  384. printf("No kernel given, skipping %s\n",
  385. label->name);
  386. return 1;
  387. }
  388. if (label->initrd) {
  389. ulong size;
  390. if (get_relfile_envaddr(ctx, label->initrd, "ramdisk_addr_r",
  391. &size) < 0) {
  392. printf("Skipping %s for failure retrieving initrd\n",
  393. label->name);
  394. return 1;
  395. }
  396. initrd_addr_str = env_get("ramdisk_addr_r");
  397. strcpy(initrd_filesize, simple_xtoa(size));
  398. strncpy(initrd_str, initrd_addr_str, 18);
  399. strcat(initrd_str, ":");
  400. strncat(initrd_str, initrd_filesize, 9);
  401. }
  402. if (get_relfile_envaddr(ctx, label->kernel, "kernel_addr_r",
  403. NULL) < 0) {
  404. printf("Skipping %s for failure retrieving kernel\n",
  405. label->name);
  406. return 1;
  407. }
  408. if (label->ipappend & 0x1) {
  409. sprintf(ip_str, " ip=%s:%s:%s:%s",
  410. env_get("ipaddr"), env_get("serverip"),
  411. env_get("gatewayip"), env_get("netmask"));
  412. }
  413. if (IS_ENABLED(CONFIG_CMD_NET)) {
  414. if (label->ipappend & 0x2) {
  415. int err;
  416. strcpy(mac_str, " BOOTIF=");
  417. err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8);
  418. if (err < 0)
  419. mac_str[0] = '\0';
  420. }
  421. }
  422. if ((label->ipappend & 0x3) || label->append) {
  423. char bootargs[CONFIG_SYS_CBSIZE] = "";
  424. char finalbootargs[CONFIG_SYS_CBSIZE];
  425. if (strlen(label->append ?: "") +
  426. strlen(ip_str) + strlen(mac_str) + 1 > sizeof(bootargs)) {
  427. printf("bootarg overflow %zd+%zd+%zd+1 > %zd\n",
  428. strlen(label->append ?: ""),
  429. strlen(ip_str), strlen(mac_str),
  430. sizeof(bootargs));
  431. return 1;
  432. }
  433. if (label->append)
  434. strncpy(bootargs, label->append, sizeof(bootargs));
  435. strcat(bootargs, ip_str);
  436. strcat(bootargs, mac_str);
  437. cli_simple_process_macros(bootargs, finalbootargs,
  438. sizeof(finalbootargs));
  439. env_set("bootargs", finalbootargs);
  440. printf("append: %s\n", finalbootargs);
  441. }
  442. kernel_addr = env_get("kernel_addr_r");
  443. /* for FIT, append the configuration identifier */
  444. if (label->config) {
  445. int len = strlen(kernel_addr) + strlen(label->config) + 1;
  446. fit_addr = malloc(len);
  447. if (!fit_addr) {
  448. printf("malloc fail (FIT address)\n");
  449. return 1;
  450. }
  451. snprintf(fit_addr, len, "%s%s", kernel_addr, label->config);
  452. kernel_addr = fit_addr;
  453. }
  454. /*
  455. * fdt usage is optional:
  456. * It handles the following scenarios.
  457. *
  458. * Scenario 1: If fdt_addr_r specified and "fdt" or "fdtdir" label is
  459. * defined in pxe file, retrieve fdt blob from server. Pass fdt_addr_r to
  460. * bootm, and adjust argc appropriately.
  461. *
  462. * If retrieve fails and no exact fdt blob is specified in pxe file with
  463. * "fdt" label, try Scenario 2.
  464. *
  465. * Scenario 2: If there is an fdt_addr specified, pass it along to
  466. * bootm, and adjust argc appropriately.
  467. *
  468. * Scenario 3: fdt blob is not available.
  469. */
  470. bootm_argv[3] = env_get("fdt_addr_r");
  471. /* if fdt label is defined then get fdt from server */
  472. if (bootm_argv[3]) {
  473. char *fdtfile = NULL;
  474. char *fdtfilefree = NULL;
  475. if (label->fdt) {
  476. fdtfile = label->fdt;
  477. } else if (label->fdtdir) {
  478. char *f1, *f2, *f3, *f4, *slash;
  479. f1 = env_get("fdtfile");
  480. if (f1) {
  481. f2 = "";
  482. f3 = "";
  483. f4 = "";
  484. } else {
  485. /*
  486. * For complex cases where this code doesn't
  487. * generate the correct filename, the board
  488. * code should set $fdtfile during early boot,
  489. * or the boot scripts should set $fdtfile
  490. * before invoking "pxe" or "sysboot".
  491. */
  492. f1 = env_get("soc");
  493. f2 = "-";
  494. f3 = env_get("board");
  495. f4 = ".dtb";
  496. if (!f1) {
  497. f1 = "";
  498. f2 = "";
  499. }
  500. if (!f3) {
  501. f2 = "";
  502. f3 = "";
  503. }
  504. }
  505. len = strlen(label->fdtdir);
  506. if (!len)
  507. slash = "./";
  508. else if (label->fdtdir[len - 1] != '/')
  509. slash = "/";
  510. else
  511. slash = "";
  512. len = strlen(label->fdtdir) + strlen(slash) +
  513. strlen(f1) + strlen(f2) + strlen(f3) +
  514. strlen(f4) + 1;
  515. fdtfilefree = malloc(len);
  516. if (!fdtfilefree) {
  517. printf("malloc fail (FDT filename)\n");
  518. goto cleanup;
  519. }
  520. snprintf(fdtfilefree, len, "%s%s%s%s%s%s",
  521. label->fdtdir, slash, f1, f2, f3, f4);
  522. fdtfile = fdtfilefree;
  523. }
  524. if (fdtfile) {
  525. int err = get_relfile_envaddr(ctx, fdtfile,
  526. "fdt_addr_r", NULL);
  527. free(fdtfilefree);
  528. if (err < 0) {
  529. bootm_argv[3] = NULL;
  530. if (label->fdt) {
  531. printf("Skipping %s for failure retrieving FDT\n",
  532. label->name);
  533. goto cleanup;
  534. }
  535. }
  536. #ifdef CONFIG_OF_LIBFDT_OVERLAY
  537. if (label->fdtoverlays)
  538. label_boot_fdtoverlay(ctx, label);
  539. #endif
  540. } else {
  541. bootm_argv[3] = NULL;
  542. }
  543. }
  544. bootm_argv[1] = kernel_addr;
  545. zboot_argv[1] = kernel_addr;
  546. if (initrd_addr_str) {
  547. bootm_argv[2] = initrd_str;
  548. bootm_argc = 3;
  549. zboot_argv[3] = initrd_addr_str;
  550. zboot_argv[4] = initrd_filesize;
  551. zboot_argc = 5;
  552. }
  553. if (!bootm_argv[3])
  554. bootm_argv[3] = env_get("fdt_addr");
  555. if (bootm_argv[3]) {
  556. if (!bootm_argv[2])
  557. bootm_argv[2] = "-";
  558. bootm_argc = 4;
  559. }
  560. kernel_addr_r = genimg_get_kernel_addr(kernel_addr);
  561. buf = map_sysmem(kernel_addr_r, 0);
  562. /* Try bootm for legacy and FIT format image */
  563. if (genimg_get_format(buf) != IMAGE_FORMAT_INVALID)
  564. do_bootm(ctx->cmdtp, 0, bootm_argc, bootm_argv);
  565. /* Try booting an AArch64 Linux kernel image */
  566. else if (IS_ENABLED(CONFIG_CMD_BOOTI))
  567. do_booti(ctx->cmdtp, 0, bootm_argc, bootm_argv);
  568. /* Try booting a Image */
  569. else if (IS_ENABLED(CONFIG_CMD_BOOTZ))
  570. do_bootz(ctx->cmdtp, 0, bootm_argc, bootm_argv);
  571. /* Try booting an x86_64 Linux kernel image */
  572. else if (IS_ENABLED(CONFIG_CMD_ZBOOT))
  573. do_zboot_parent(ctx->cmdtp, 0, zboot_argc, zboot_argv, NULL);
  574. unmap_sysmem(buf);
  575. cleanup:
  576. free(fit_addr);
  577. return 1;
  578. }
  579. /** enum token_type - Tokens for the pxe file parser */
  580. enum token_type {
  581. T_EOL,
  582. T_STRING,
  583. T_EOF,
  584. T_MENU,
  585. T_TITLE,
  586. T_TIMEOUT,
  587. T_LABEL,
  588. T_KERNEL,
  589. T_LINUX,
  590. T_APPEND,
  591. T_INITRD,
  592. T_LOCALBOOT,
  593. T_DEFAULT,
  594. T_PROMPT,
  595. T_INCLUDE,
  596. T_FDT,
  597. T_FDTDIR,
  598. T_FDTOVERLAYS,
  599. T_ONTIMEOUT,
  600. T_IPAPPEND,
  601. T_BACKGROUND,
  602. T_INVALID
  603. };
  604. /** struct token - token - given by a value and a type */
  605. struct token {
  606. char *val;
  607. enum token_type type;
  608. };
  609. /* Keywords recognized */
  610. static const struct token keywords[] = {
  611. {"menu", T_MENU},
  612. {"title", T_TITLE},
  613. {"timeout", T_TIMEOUT},
  614. {"default", T_DEFAULT},
  615. {"prompt", T_PROMPT},
  616. {"label", T_LABEL},
  617. {"kernel", T_KERNEL},
  618. {"linux", T_LINUX},
  619. {"localboot", T_LOCALBOOT},
  620. {"append", T_APPEND},
  621. {"initrd", T_INITRD},
  622. {"include", T_INCLUDE},
  623. {"devicetree", T_FDT},
  624. {"fdt", T_FDT},
  625. {"devicetreedir", T_FDTDIR},
  626. {"fdtdir", T_FDTDIR},
  627. {"fdtoverlays", T_FDTOVERLAYS},
  628. {"ontimeout", T_ONTIMEOUT,},
  629. {"ipappend", T_IPAPPEND,},
  630. {"background", T_BACKGROUND,},
  631. {NULL, T_INVALID}
  632. };
  633. /**
  634. * enum lex_state - lexer state
  635. *
  636. * Since pxe(linux) files don't have a token to identify the start of a
  637. * literal, we have to keep track of when we're in a state where a literal is
  638. * expected vs when we're in a state a keyword is expected.
  639. */
  640. enum lex_state {
  641. L_NORMAL = 0,
  642. L_KEYWORD,
  643. L_SLITERAL
  644. };
  645. /**
  646. * get_string() - retrieves a string from *p and stores it as a token in *t.
  647. *
  648. * This is used for scanning both string literals and keywords.
  649. *
  650. * Characters from *p are copied into t-val until a character equal to
  651. * delim is found, or a NUL byte is reached. If delim has the special value of
  652. * ' ', any whitespace character will be used as a delimiter.
  653. *
  654. * If lower is unequal to 0, uppercase characters will be converted to
  655. * lowercase in the result. This is useful to make keywords case
  656. * insensitive.
  657. *
  658. * The location of *p is updated to point to the first character after the end
  659. * of the token - the ending delimiter.
  660. *
  661. * Memory for t->val is allocated using malloc and must be free()'d to reclaim
  662. * it.
  663. *
  664. * @p: Points to a pointer to the current position in the input being processed.
  665. * Updated to point at the first character after the current token
  666. * @t: Pointers to a token to fill in
  667. * @delim: Delimiter character to look for, either newline or space
  668. * @lower: true to convert the string to lower case when storing
  669. * Returns the new value of t->val, on success, NULL if out of memory
  670. */
  671. static char *get_string(char **p, struct token *t, char delim, int lower)
  672. {
  673. char *b, *e;
  674. size_t len, i;
  675. /*
  676. * b and e both start at the beginning of the input stream.
  677. *
  678. * e is incremented until we find the ending delimiter, or a NUL byte
  679. * is reached. Then, we take e - b to find the length of the token.
  680. */
  681. b = *p;
  682. e = *p;
  683. while (*e) {
  684. if ((delim == ' ' && isspace(*e)) || delim == *e)
  685. break;
  686. e++;
  687. }
  688. len = e - b;
  689. /*
  690. * Allocate memory to hold the string, and copy it in, converting
  691. * characters to lowercase if lower is != 0.
  692. */
  693. t->val = malloc(len + 1);
  694. if (!t->val)
  695. return NULL;
  696. for (i = 0; i < len; i++, b++) {
  697. if (lower)
  698. t->val[i] = tolower(*b);
  699. else
  700. t->val[i] = *b;
  701. }
  702. t->val[len] = '\0';
  703. /* Update *p so the caller knows where to continue scanning */
  704. *p = e;
  705. t->type = T_STRING;
  706. return t->val;
  707. }
  708. /**
  709. * get_keyword() - Populate a keyword token with a type and value
  710. *
  711. * Updates the ->type field based on the keyword string in @val
  712. * @t: Token to populate
  713. */
  714. static void get_keyword(struct token *t)
  715. {
  716. int i;
  717. for (i = 0; keywords[i].val; i++) {
  718. if (!strcmp(t->val, keywords[i].val)) {
  719. t->type = keywords[i].type;
  720. break;
  721. }
  722. }
  723. }
  724. /**
  725. * get_token() - Get the next token
  726. *
  727. * We have to keep track of which state we're in to know if we're looking to get
  728. * a string literal or a keyword.
  729. *
  730. * @p: Points to a pointer to the current position in the input being processed.
  731. * Updated to point at the first character after the current token
  732. */
  733. static void get_token(char **p, struct token *t, enum lex_state state)
  734. {
  735. char *c = *p;
  736. t->type = T_INVALID;
  737. /* eat non EOL whitespace */
  738. while (isblank(*c))
  739. c++;
  740. /*
  741. * eat comments. note that string literals can't begin with #, but
  742. * can contain a # after their first character.
  743. */
  744. if (*c == '#') {
  745. while (*c && *c != '\n')
  746. c++;
  747. }
  748. if (*c == '\n') {
  749. t->type = T_EOL;
  750. c++;
  751. } else if (*c == '\0') {
  752. t->type = T_EOF;
  753. c++;
  754. } else if (state == L_SLITERAL) {
  755. get_string(&c, t, '\n', 0);
  756. } else if (state == L_KEYWORD) {
  757. /*
  758. * when we expect a keyword, we first get the next string
  759. * token delimited by whitespace, and then check if it
  760. * matches a keyword in our keyword list. if it does, it's
  761. * converted to a keyword token of the appropriate type, and
  762. * if not, it remains a string token.
  763. */
  764. get_string(&c, t, ' ', 1);
  765. get_keyword(t);
  766. }
  767. *p = c;
  768. }
  769. /**
  770. * eol_or_eof() - Find end of line
  771. *
  772. * Increment *c until we get to the end of the current line, or EOF
  773. *
  774. * @c: Points to a pointer to the current position in the input being processed.
  775. * Updated to point at the first character after the current token
  776. */
  777. static void eol_or_eof(char **c)
  778. {
  779. while (**c && **c != '\n')
  780. (*c)++;
  781. }
  782. /*
  783. * All of these parse_* functions share some common behavior.
  784. *
  785. * They finish with *c pointing after the token they parse, and return 1 on
  786. * success, or < 0 on error.
  787. */
  788. /*
  789. * Parse a string literal and store a pointer it at *dst. String literals
  790. * terminate at the end of the line.
  791. */
  792. static int parse_sliteral(char **c, char **dst)
  793. {
  794. struct token t;
  795. char *s = *c;
  796. get_token(c, &t, L_SLITERAL);
  797. if (t.type != T_STRING) {
  798. printf("Expected string literal: %.*s\n", (int)(*c - s), s);
  799. return -EINVAL;
  800. }
  801. *dst = t.val;
  802. return 1;
  803. }
  804. /*
  805. * Parse a base 10 (unsigned) integer and store it at *dst.
  806. */
  807. static int parse_integer(char **c, int *dst)
  808. {
  809. struct token t;
  810. char *s = *c;
  811. get_token(c, &t, L_SLITERAL);
  812. if (t.type != T_STRING) {
  813. printf("Expected string: %.*s\n", (int)(*c - s), s);
  814. return -EINVAL;
  815. }
  816. *dst = simple_strtol(t.val, NULL, 10);
  817. free(t.val);
  818. return 1;
  819. }
  820. static int parse_pxefile_top(struct pxe_context *ctx, char *p, ulong base,
  821. struct pxe_menu *cfg, int nest_level);
  822. /*
  823. * Parse an include statement, and retrieve and parse the file it mentions.
  824. *
  825. * base should point to a location where it's safe to store the file, and
  826. * nest_level should indicate how many nested includes have occurred. For this
  827. * include, nest_level has already been incremented and doesn't need to be
  828. * incremented here.
  829. */
  830. static int handle_include(struct pxe_context *ctx, char **c, unsigned long base,
  831. struct pxe_menu *cfg, int nest_level)
  832. {
  833. char *include_path;
  834. char *s = *c;
  835. int err;
  836. char *buf;
  837. int ret;
  838. err = parse_sliteral(c, &include_path);
  839. if (err < 0) {
  840. printf("Expected include path: %.*s\n", (int)(*c - s), s);
  841. return err;
  842. }
  843. err = get_pxe_file(ctx, include_path, base);
  844. if (err < 0) {
  845. printf("Couldn't retrieve %s\n", include_path);
  846. return err;
  847. }
  848. buf = map_sysmem(base, 0);
  849. ret = parse_pxefile_top(ctx, buf, base, cfg, nest_level);
  850. unmap_sysmem(buf);
  851. return ret;
  852. }
  853. /*
  854. * Parse lines that begin with 'menu'.
  855. *
  856. * base and nest are provided to handle the 'menu include' case.
  857. *
  858. * base should point to a location where it's safe to store the included file.
  859. *
  860. * nest_level should be 1 when parsing the top level pxe file, 2 when parsing
  861. * a file it includes, 3 when parsing a file included by that file, and so on.
  862. */
  863. static int parse_menu(struct pxe_context *ctx, char **c, struct pxe_menu *cfg,
  864. unsigned long base, int nest_level)
  865. {
  866. struct token t;
  867. char *s = *c;
  868. int err = 0;
  869. get_token(c, &t, L_KEYWORD);
  870. switch (t.type) {
  871. case T_TITLE:
  872. err = parse_sliteral(c, &cfg->title);
  873. break;
  874. case T_INCLUDE:
  875. err = handle_include(ctx, c, base, cfg, nest_level + 1);
  876. break;
  877. case T_BACKGROUND:
  878. err = parse_sliteral(c, &cfg->bmp);
  879. break;
  880. default:
  881. printf("Ignoring malformed menu command: %.*s\n",
  882. (int)(*c - s), s);
  883. }
  884. if (err < 0)
  885. return err;
  886. eol_or_eof(c);
  887. return 1;
  888. }
  889. /*
  890. * Handles parsing a 'menu line' when we're parsing a label.
  891. */
  892. static int parse_label_menu(char **c, struct pxe_menu *cfg,
  893. struct pxe_label *label)
  894. {
  895. struct token t;
  896. char *s;
  897. s = *c;
  898. get_token(c, &t, L_KEYWORD);
  899. switch (t.type) {
  900. case T_DEFAULT:
  901. if (!cfg->default_label)
  902. cfg->default_label = strdup(label->name);
  903. if (!cfg->default_label)
  904. return -ENOMEM;
  905. break;
  906. case T_LABEL:
  907. parse_sliteral(c, &label->menu);
  908. break;
  909. default:
  910. printf("Ignoring malformed menu command: %.*s\n",
  911. (int)(*c - s), s);
  912. }
  913. eol_or_eof(c);
  914. return 0;
  915. }
  916. /*
  917. * Handles parsing a 'kernel' label.
  918. * expecting "filename" or "<fit_filename>#cfg"
  919. */
  920. static int parse_label_kernel(char **c, struct pxe_label *label)
  921. {
  922. char *s;
  923. int err;
  924. err = parse_sliteral(c, &label->kernel);
  925. if (err < 0)
  926. return err;
  927. s = strstr(label->kernel, "#");
  928. if (!s)
  929. return 1;
  930. label->config = malloc(strlen(s) + 1);
  931. if (!label->config)
  932. return -ENOMEM;
  933. strcpy(label->config, s);
  934. *s = 0;
  935. return 1;
  936. }
  937. /*
  938. * Parses a label and adds it to the list of labels for a menu.
  939. *
  940. * A label ends when we either get to the end of a file, or
  941. * get some input we otherwise don't have a handler defined
  942. * for.
  943. *
  944. */
  945. static int parse_label(char **c, struct pxe_menu *cfg)
  946. {
  947. struct token t;
  948. int len;
  949. char *s = *c;
  950. struct pxe_label *label;
  951. int err;
  952. label = label_create();
  953. if (!label)
  954. return -ENOMEM;
  955. err = parse_sliteral(c, &label->name);
  956. if (err < 0) {
  957. printf("Expected label name: %.*s\n", (int)(*c - s), s);
  958. label_destroy(label);
  959. return -EINVAL;
  960. }
  961. list_add_tail(&label->list, &cfg->labels);
  962. while (1) {
  963. s = *c;
  964. get_token(c, &t, L_KEYWORD);
  965. err = 0;
  966. switch (t.type) {
  967. case T_MENU:
  968. err = parse_label_menu(c, cfg, label);
  969. break;
  970. case T_KERNEL:
  971. case T_LINUX:
  972. err = parse_label_kernel(c, label);
  973. break;
  974. case T_APPEND:
  975. err = parse_sliteral(c, &label->append);
  976. if (label->initrd)
  977. break;
  978. s = strstr(label->append, "initrd=");
  979. if (!s)
  980. break;
  981. s += 7;
  982. len = (int)(strchr(s, ' ') - s);
  983. label->initrd = malloc(len + 1);
  984. strncpy(label->initrd, s, len);
  985. label->initrd[len] = '\0';
  986. break;
  987. case T_INITRD:
  988. if (!label->initrd)
  989. err = parse_sliteral(c, &label->initrd);
  990. break;
  991. case T_FDT:
  992. if (!label->fdt)
  993. err = parse_sliteral(c, &label->fdt);
  994. break;
  995. case T_FDTDIR:
  996. if (!label->fdtdir)
  997. err = parse_sliteral(c, &label->fdtdir);
  998. break;
  999. case T_FDTOVERLAYS:
  1000. if (!label->fdtoverlays)
  1001. err = parse_sliteral(c, &label->fdtoverlays);
  1002. break;
  1003. case T_LOCALBOOT:
  1004. label->localboot = 1;
  1005. err = parse_integer(c, &label->localboot_val);
  1006. break;
  1007. case T_IPAPPEND:
  1008. err = parse_integer(c, &label->ipappend);
  1009. break;
  1010. case T_EOL:
  1011. break;
  1012. default:
  1013. /*
  1014. * put the token back! we don't want it - it's the end
  1015. * of a label and whatever token this is, it's
  1016. * something for the menu level context to handle.
  1017. */
  1018. *c = s;
  1019. return 1;
  1020. }
  1021. if (err < 0)
  1022. return err;
  1023. }
  1024. }
  1025. /*
  1026. * This 16 comes from the limit pxelinux imposes on nested includes.
  1027. *
  1028. * There is no reason at all we couldn't do more, but some limit helps prevent
  1029. * infinite (until crash occurs) recursion if a file tries to include itself.
  1030. */
  1031. #define MAX_NEST_LEVEL 16
  1032. /*
  1033. * Entry point for parsing a menu file. nest_level indicates how many times
  1034. * we've nested in includes. It will be 1 for the top level menu file.
  1035. *
  1036. * Returns 1 on success, < 0 on error.
  1037. */
  1038. static int parse_pxefile_top(struct pxe_context *ctx, char *p, unsigned long base,
  1039. struct pxe_menu *cfg, int nest_level)
  1040. {
  1041. struct token t;
  1042. char *s, *b, *label_name;
  1043. int err;
  1044. b = p;
  1045. if (nest_level > MAX_NEST_LEVEL) {
  1046. printf("Maximum nesting (%d) exceeded\n", MAX_NEST_LEVEL);
  1047. return -EMLINK;
  1048. }
  1049. while (1) {
  1050. s = p;
  1051. get_token(&p, &t, L_KEYWORD);
  1052. err = 0;
  1053. switch (t.type) {
  1054. case T_MENU:
  1055. cfg->prompt = 1;
  1056. err = parse_menu(ctx, &p, cfg,
  1057. base + ALIGN(strlen(b) + 1, 4),
  1058. nest_level);
  1059. break;
  1060. case T_TIMEOUT:
  1061. err = parse_integer(&p, &cfg->timeout);
  1062. break;
  1063. case T_LABEL:
  1064. err = parse_label(&p, cfg);
  1065. break;
  1066. case T_DEFAULT:
  1067. case T_ONTIMEOUT:
  1068. err = parse_sliteral(&p, &label_name);
  1069. if (label_name) {
  1070. if (cfg->default_label)
  1071. free(cfg->default_label);
  1072. cfg->default_label = label_name;
  1073. }
  1074. break;
  1075. case T_INCLUDE:
  1076. err = handle_include(ctx, &p,
  1077. base + ALIGN(strlen(b), 4), cfg,
  1078. nest_level + 1);
  1079. break;
  1080. case T_PROMPT:
  1081. eol_or_eof(&p);
  1082. break;
  1083. case T_EOL:
  1084. break;
  1085. case T_EOF:
  1086. return 1;
  1087. default:
  1088. printf("Ignoring unknown command: %.*s\n",
  1089. (int)(p - s), s);
  1090. eol_or_eof(&p);
  1091. }
  1092. if (err < 0)
  1093. return err;
  1094. }
  1095. }
  1096. /*
  1097. */
  1098. void destroy_pxe_menu(struct pxe_menu *cfg)
  1099. {
  1100. struct list_head *pos, *n;
  1101. struct pxe_label *label;
  1102. free(cfg->title);
  1103. free(cfg->default_label);
  1104. list_for_each_safe(pos, n, &cfg->labels) {
  1105. label = list_entry(pos, struct pxe_label, list);
  1106. label_destroy(label);
  1107. }
  1108. free(cfg);
  1109. }
  1110. struct pxe_menu *parse_pxefile(struct pxe_context *ctx, unsigned long menucfg)
  1111. {
  1112. struct pxe_menu *cfg;
  1113. char *buf;
  1114. int r;
  1115. cfg = malloc(sizeof(struct pxe_menu));
  1116. if (!cfg)
  1117. return NULL;
  1118. memset(cfg, 0, sizeof(struct pxe_menu));
  1119. INIT_LIST_HEAD(&cfg->labels);
  1120. buf = map_sysmem(menucfg, 0);
  1121. r = parse_pxefile_top(ctx, buf, menucfg, cfg, 1);
  1122. unmap_sysmem(buf);
  1123. if (r < 0) {
  1124. destroy_pxe_menu(cfg);
  1125. return NULL;
  1126. }
  1127. return cfg;
  1128. }
  1129. /*
  1130. * Converts a pxe_menu struct into a menu struct for use with U-Boot's generic
  1131. * menu code.
  1132. */
  1133. static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)
  1134. {
  1135. struct pxe_label *label;
  1136. struct list_head *pos;
  1137. struct menu *m;
  1138. int err;
  1139. int i = 1;
  1140. char *default_num = NULL;
  1141. /*
  1142. * Create a menu and add items for all the labels.
  1143. */
  1144. m = menu_create(cfg->title, DIV_ROUND_UP(cfg->timeout, 10),
  1145. cfg->prompt, NULL, label_print, NULL, NULL);
  1146. if (!m)
  1147. return NULL;
  1148. list_for_each(pos, &cfg->labels) {
  1149. label = list_entry(pos, struct pxe_label, list);
  1150. sprintf(label->num, "%d", i++);
  1151. if (menu_item_add(m, label->num, label) != 1) {
  1152. menu_destroy(m);
  1153. return NULL;
  1154. }
  1155. if (cfg->default_label &&
  1156. (strcmp(label->name, cfg->default_label) == 0))
  1157. default_num = label->num;
  1158. }
  1159. /*
  1160. * After we've created items for each label in the menu, set the
  1161. * menu's default label if one was specified.
  1162. */
  1163. if (default_num) {
  1164. err = menu_default_set(m, default_num);
  1165. if (err != 1) {
  1166. if (err != -ENOENT) {
  1167. menu_destroy(m);
  1168. return NULL;
  1169. }
  1170. printf("Missing default: %s\n", cfg->default_label);
  1171. }
  1172. }
  1173. return m;
  1174. }
  1175. /*
  1176. * Try to boot any labels we have yet to attempt to boot.
  1177. */
  1178. static void boot_unattempted_labels(struct pxe_context *ctx,
  1179. struct pxe_menu *cfg)
  1180. {
  1181. struct list_head *pos;
  1182. struct pxe_label *label;
  1183. list_for_each(pos, &cfg->labels) {
  1184. label = list_entry(pos, struct pxe_label, list);
  1185. if (!label->attempted)
  1186. label_boot(ctx, label);
  1187. }
  1188. }
  1189. void handle_pxe_menu(struct pxe_context *ctx, struct pxe_menu *cfg)
  1190. {
  1191. void *choice;
  1192. struct menu *m;
  1193. int err;
  1194. if (IS_ENABLED(CONFIG_CMD_BMP)) {
  1195. /* display BMP if available */
  1196. if (cfg->bmp) {
  1197. if (get_relfile(ctx, cfg->bmp, image_load_addr, NULL)) {
  1198. if (CONFIG_IS_ENABLED(CMD_CLS))
  1199. run_command("cls", 0);
  1200. bmp_display(image_load_addr,
  1201. BMP_ALIGN_CENTER, BMP_ALIGN_CENTER);
  1202. } else {
  1203. printf("Skipping background bmp %s for failure\n",
  1204. cfg->bmp);
  1205. }
  1206. }
  1207. }
  1208. m = pxe_menu_to_menu(cfg);
  1209. if (!m)
  1210. return;
  1211. err = menu_get_choice(m, &choice);
  1212. menu_destroy(m);
  1213. /*
  1214. * err == 1 means we got a choice back from menu_get_choice.
  1215. *
  1216. * err == -ENOENT if the menu was setup to select the default but no
  1217. * default was set. in that case, we should continue trying to boot
  1218. * labels that haven't been attempted yet.
  1219. *
  1220. * otherwise, the user interrupted or there was some other error and
  1221. * we give up.
  1222. */
  1223. if (err == 1) {
  1224. err = label_boot(ctx, choice);
  1225. if (!err)
  1226. return;
  1227. } else if (err != -ENOENT) {
  1228. return;
  1229. }
  1230. boot_unattempted_labels(ctx, cfg);
  1231. }
  1232. int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl *cmdtp,
  1233. pxe_getfile_func getfile, void *userdata,
  1234. bool allow_abs_path, const char *bootfile)
  1235. {
  1236. const char *last_slash;
  1237. size_t path_len = 0;
  1238. memset(ctx, '\0', sizeof(*ctx));
  1239. ctx->cmdtp = cmdtp;
  1240. ctx->getfile = getfile;
  1241. ctx->userdata = userdata;
  1242. ctx->allow_abs_path = allow_abs_path;
  1243. /* figure out the boot directory, if there is one */
  1244. if (bootfile && strlen(bootfile) >= MAX_TFTP_PATH_LEN)
  1245. return -ENOSPC;
  1246. ctx->bootdir = strdup(bootfile ? bootfile : "");
  1247. if (!ctx->bootdir)
  1248. return -ENOMEM;
  1249. if (bootfile) {
  1250. last_slash = strrchr(bootfile, '/');
  1251. if (last_slash)
  1252. path_len = (last_slash - bootfile) + 1;
  1253. }
  1254. ctx->bootdir[path_len] = '\0';
  1255. return 0;
  1256. }
  1257. void pxe_destroy_ctx(struct pxe_context *ctx)
  1258. {
  1259. free(ctx->bootdir);
  1260. }
  1261. int pxe_process(struct pxe_context *ctx, ulong pxefile_addr_r, bool prompt)
  1262. {
  1263. struct pxe_menu *cfg;
  1264. cfg = parse_pxefile(ctx, pxefile_addr_r);
  1265. if (!cfg) {
  1266. printf("Error parsing config file\n");
  1267. return 1;
  1268. }
  1269. if (prompt)
  1270. cfg->prompt = 1;
  1271. handle_pxe_menu(ctx, cfg);
  1272. destroy_pxe_menu(cfg);
  1273. return 0;
  1274. }