[Concept,10/32] boot: pxe: Print 'say' message when label is booted

Message ID 20260109231151.4056804-11-sjg@u-boot.org
State New
Headers
Series boot: pxe: Refactor into separate load/setup phases |

Commit Message

Simon Glass Jan. 9, 2026, 11:11 p.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Per the syslinux specification, the 'say' directive should print its
message when the label is selected for booting, not during parsing.

Store the 'say' message in struct pxe_label so it can be printed at the
appropriate time. Print the message in label_boot() before displaying
the label information. Update the test to verify the say field instead
of expecting console output during parsing.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 boot/pxe_parse.c    |  6 ++++--
 boot/pxe_utils.c    |  5 +++--
 include/pxe_utils.h |  2 ++
 test/boot/pxe.c     | 42 +++++++++++++++++++-----------------------
 4 files changed, 28 insertions(+), 27 deletions(-)
  

Patch

diff --git a/boot/pxe_parse.c b/boot/pxe_parse.c
index 633b218a7cd..e3412166a63 100644
--- a/boot/pxe_parse.c
+++ b/boot/pxe_parse.c
@@ -121,6 +121,7 @@  void label_destroy(struct pxe_label *label)
 	free(label->fdt);
 	free(label->fdtdir);
 	free(label->fdtoverlays);
+	free(label->say);
 	free(label);
 }
 
@@ -553,8 +554,9 @@  static int parse_label(char **c, struct pxe_menu *cfg)
 			char *p = strchr(s, '\n');
 
 			if (p) {
-				printf("%.*s\n", (int)(p - *c) - 1, *c + 1);
-
+				label->say = strndup(*c + 1, p - *c - 1);
+				if (!label->say)
+					return -ENOMEM;
 				*c = p;
 			}
 			break;
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c
index 3c48b0ac51b..1516065a467 100644
--- a/boot/pxe_utils.c
+++ b/boot/pxe_utils.c
@@ -812,6 +812,9 @@  static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
 	char ip_str[68] = "";
 	int ret;
 
+	if (label->say)
+		printf("%s\n", label->say);
+
 	label_print(label);
 
 	label->attempted = 1;
@@ -897,8 +900,6 @@  static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
 	return 1;
 }
 
-/*
- */
 void destroy_pxe_menu(struct pxe_menu *cfg)
 {
 	struct list_head *pos, *n;
diff --git a/include/pxe_utils.h b/include/pxe_utils.h
index f910ea9d284..c0d2167cc25 100644
--- a/include/pxe_utils.h
+++ b/include/pxe_utils.h
@@ -39,6 +39,7 @@ 
  * @fdt: path to FDT to use
  * @fdtdir: path to FDT directory to use
  * @fdtoverlays: space-separated list of paths of FDT overlays to apply
+ * @say: message to print when this label is selected for booting
  * @ipappend: flags for appending IP address (0x1) and MAC address (0x3)
  * @attempted: 0 if we haven't tried to boot this label, 1 if we have
  * @localboot: 1 if this label specified 'localboot', 0 otherwise
@@ -58,6 +59,7 @@  struct pxe_label {
 	char *fdt;
 	char *fdtdir;
 	char *fdtoverlays;
+	char *say;
 	int ipappend;
 	int attempted;
 	int localboot;
diff --git a/test/boot/pxe.c b/test/boot/pxe.c
index af45c1fbffd..4ac0d6c6fa6 100644
--- a/test/boot/pxe.c
+++ b/test/boot/pxe.c
@@ -81,25 +81,20 @@  static int pxe_test_getfile(struct pxe_context *ctx, const char *file_path,
  *
  * This helper checks all the console output lines from loading and displaying
  * the PXE menu, including config file retrieval, include files, background
- * image attempt, and the menu itself.
+ * image attempt, and the menu itself. Note: 'say' messages are now printed
+ * when the label is booted, not during parsing.
  *
  * @uts: Unit test state
- * @say_msg: Expected 'say' message (shown before menu), or NULL if none
  * @error_msg: Expected error message after background image, or NULL if none
  * Return: 0 if OK, -ve on error
  */
-static int pxe_check_menu(struct unit_test_state *uts, const char *say_msg,
-			  const char *error_msg)
+static int pxe_check_menu(struct unit_test_state *uts, const char *error_msg)
 {
 	int i;
 
 	/* Config file retrieval */
 	ut_assert_nextline("Retrieving file: /extlinux/extlinux.conf");
 
-	/* Say message appears before includes are processed */
-	if (say_msg)
-		ut_assert_nextline(say_msg);
-
 	/* Include file retrievals */
 	ut_assert_nextline("Retrieving file: /extlinux/extra.conf");
 	for (i = 3; i <= 16; i++)
@@ -169,11 +164,7 @@  static int pxe_test_parse_norun(struct unit_test_state *uts)
 	cfg = parse_pxefile(&ctx, addr);
 	ut_assertnonnull(cfg);
 
-	/*
-	 * Verify 'say' keyword printed its message during parsing (quiet
-	 * suppresses file messages)
-	 */
-	ut_assert_nextline("Booting default Linux kernel");
+	/* Verify no console output during parsing (say is printed on boot) */
 	ut_assert_console_end();
 
 	/* Verify menu properties */
@@ -198,6 +189,7 @@  static int pxe_test_parse_norun(struct unit_test_state *uts)
 	ut_assertnull(label->fdtdir);
 	ut_asserteq_str("/dtb/overlay1.dtbo /dtb/overlay2.dtbo",
 			label->fdtoverlays);
+	ut_asserteq_str("Booting default Linux kernel", label->say);
 	ut_asserteq(0, label->ipappend);
 	ut_asserteq(0, label->attempted);
 	ut_asserteq(0, label->localboot);
@@ -217,6 +209,7 @@  static int pxe_test_parse_norun(struct unit_test_state *uts)
 	ut_assertnull(label->fdt);
 	ut_asserteq_str("/dtb/", label->fdtdir);
 	ut_assertnull(label->fdtoverlays);
+	ut_assertnull(label->say);
 	ut_asserteq(3, label->ipappend);
 	ut_asserteq(0, label->attempted);
 	ut_asserteq(0, label->localboot);
@@ -236,6 +229,7 @@  static int pxe_test_parse_norun(struct unit_test_state *uts)
 	ut_assertnull(label->fdt);
 	ut_assertnull(label->fdtdir);
 	ut_assertnull(label->fdtoverlays);
+	ut_assertnull(label->say);
 	ut_asserteq(0, label->ipappend);
 	ut_asserteq(0, label->attempted);
 	ut_asserteq(1, label->localboot);
@@ -255,6 +249,7 @@  static int pxe_test_parse_norun(struct unit_test_state *uts)
 	ut_assertnull(label->fdt);
 	ut_assertnull(label->fdtdir);
 	ut_assertnull(label->fdtoverlays);
+	ut_assertnull(label->say);
 	ut_asserteq(0, label->ipappend);
 	ut_asserteq(0, label->attempted);
 	ut_asserteq(0, label->localboot);
@@ -337,9 +332,9 @@  static int pxe_test_sysboot_norun(struct unit_test_state *uts)
 	ut_assertok(run_commandf("sysboot host 0:0 any %x %s",
 				 PXE_LOAD_ADDR, cfg_path));
 
-	/* Check menu output */
-	ut_assertok(pxe_check_menu(uts, "Booting default Linux kernel", NULL));
-	ut_assert_nextline("Enter choice: 1:\tBoot Linux");
+	/* Skip menu output and find the first label boot attempt */
+	ut_assert_skip_to_line("Enter choice: Booting default Linux kernel");
+	ut_assert_nextline("1:\tBoot Linux");
 
 	/* Verify files were loaded in order */
 	ut_assert_nextline("Retrieving file: /vmlinuz");
@@ -646,9 +641,8 @@  static int pxe_test_overlay_no_addr_norun(struct unit_test_state *uts)
 	cfg = parse_pxefile(&ctx, addr);
 	ut_assertnonnull(cfg);
 
-	/* Consume parsing output */
+	/* Consume parsing output (say message is printed on boot, not parsing) */
 	ut_assert_nextline("Retrieving file: %s", cfg_path);
-	ut_assert_nextline("Booting default Linux kernel");
 	ut_assert_nextline("Retrieving file: /extlinux/extra.conf");
 	for (i = 3; i <= 16; i++)
 		ut_assert_nextline("Retrieving file: /extlinux/nest%d.conf", i);
@@ -842,7 +836,7 @@  static int pxe_test_ipappend_norun(struct unit_test_state *uts)
 				 PXE_LOAD_ADDR, cfg_path));
 
 	/* Check menu output */
-	ut_assertok(pxe_check_menu(uts, "Booting default Linux kernel", NULL));
+	ut_assertok(pxe_check_menu(uts, NULL));
 	ut_assert_nextline("Enter choice: 2:\tRescue Mode");
 
 	/* Rescue label boot attempt */
@@ -962,7 +956,7 @@  static int pxe_test_label_override_norun(struct unit_test_state *uts)
 				 PXE_LOAD_ADDR, cfg_path));
 
 	/* Check menu output - say message is from default label */
-	ut_assertok(pxe_check_menu(uts, "Booting default Linux kernel", NULL));
+	ut_assertok(pxe_check_menu(uts, NULL));
 
 	/* Should boot 'local' label instead of default 'linux' */
 	ut_assert_nextline("Enter choice: 3:\tLocal Boot");
@@ -982,9 +976,11 @@  static int pxe_test_label_override_norun(struct unit_test_state *uts)
 				 PXE_LOAD_ADDR, cfg_path));
 
 	/* Check menu with error message before it */
-	ut_assertok(pxe_check_menu(uts, "Booting default Linux kernel",
-				   "Missing override pxe label: nonexistent"));
-	ut_assert_nextline("Enter choice: 1:\tBoot Linux");
+	ut_assertok(pxe_check_menu(uts, "Missing override pxe label: nonexistent"));
+
+	/* Say message is printed when label is selected (after "Enter choice:") */
+	ut_assert_nextline("Enter choice: Booting default Linux kernel");
+	ut_assert_nextline("1:\tBoot Linux");
 
 	/* Default label boot attempt - FDT/overlays loaded before append */
 	ut_assert_nextline("Retrieving file: /vmlinuz");