pxe_utils.c 36 KB

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