Merge tag 'efi-2025-07-rc3-2' of https://source.denx.de/u-boot/custodians/u-boot-efi

Pull request efi-2025-07-rc3-2

Documentation:

* Add test/py/requirements.txt to documentation
* Use globing for selecting pytest files

UEFI:

* Provide a function to disable ANSI output during tests

Other:

* test: allow multiple config options in buildconfigspec
* test: allow testing with NET_LWIP=y
diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml
index 9c13651..15520c4 100644
--- a/.azure-pipelines.yml
+++ b/.azure-pipelines.yml
@@ -92,7 +92,7 @@
           set -e
           python3 -m venv /tmp/venvhtml
           . /tmp/venvhtml/bin/activate
-          pip install -r doc/sphinx/requirements.txt pytest
+          pip install -r doc/sphinx/requirements.txt -r test/py/requirements.txt
           make htmldocs KDOC_WERROR=1
           make infodocs
 
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7aadd5d..49f3c58 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -164,7 +164,7 @@
   script:
     - python3 -m venv /tmp/venvhtml
     - . /tmp/venvhtml/bin/activate
-    - pip install -r doc/sphinx/requirements.txt pytest
+    - pip install -r doc/sphinx/requirements.txt -r test/py/requirements.txt
     - make htmldocs KDOC_WERROR=1
     - make infodocs
 
diff --git a/.readthedocs.yml b/.readthedocs.yml
index 16418f2..9b6d251 100644
--- a/.readthedocs.yml
+++ b/.readthedocs.yml
@@ -22,3 +22,4 @@
 python:
   install:
     - requirements: doc/sphinx/requirements.txt
+    - requirements: test/py/requirements.txt
diff --git a/doc/develop/pytest/index.rst b/doc/develop/pytest/index.rst
index 0a7c1b2..dce8a96 100644
--- a/doc/develop/pytest/index.rst
+++ b/doc/develop/pytest/index.rst
@@ -16,12 +16,6 @@
 
 .. toctree::
    :maxdepth: 1
+   :glob:
 
-   test_000_version
-   test_bind
-   test_bootmenu
-   test_bootstage
-   test_button
-   test_efi_loader
-   test_net
-   test_net_boot
+   test_*
diff --git a/doc/develop/pytest/usage.rst b/doc/develop/pytest/usage.rst
index 49d269d..779b2db 100644
--- a/doc/develop/pytest/usage.rst
+++ b/doc/develop/pytest/usage.rst
@@ -522,3 +522,27 @@
 Build configuration values (from `.config`) may be accessed via the dictionary
 `ubman.config.buildconfig`, with keys equal to the Kconfig variable
 names.
+
+A required configuration setting can be defined via a buildconfigspec()
+annotation. The name of the configuration option is specified in lower case. The
+following annotation for a test requires CONFIG_EFI_LOADER=y:
+
+.. code-block:: python
+
+    @pytest.mark.buildconfigspec('efi_loader')
+
+Sometimes multiple configuration option supply the same functionality. If
+multiple arguments are passed to buildconfigspec(), only one of the
+configuration options needs to be set. The following annotation requires that
+either of CONFIG_NET or CONFIG_NET_LWIP is set:
+
+.. code-block:: python
+
+    @pytest.mark.buildconfigspec('net', 'net lwip')
+
+The notbuildconfigspec() annotation can be used to require a configuration
+option not to be set. The following annotation requires CONFIG_RISCV=n:
+
+.. code-block:: python
+
+    @pytest.mark.notbuildconfigspec('riscv')
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 84e8cfe..8f9f2bc 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -588,8 +588,27 @@
 efi_status_t efi_bootmgr_run(void *fdt);
 /* search the boot option index in BootOrder */
 bool efi_search_bootorder(u16 *bootorder, efi_uintn_t num, u32 target, u32 *index);
-/* Set up console modes */
+
+/**
+ * efi_setup_console_size() - update the mode table.
+ *
+ * By default the only mode available is 80x25. If the console has at least 50
+ * lines, enable mode 80x50. If we can query the console size and it is neither
+ * 80x25 nor 80x50, set it as an additional mode.
+ */
 void efi_setup_console_size(void);
+
+/**
+ * efi_console_set_ansi() - Set whether ANSI escape-characters should be emitted
+ *
+ * These characters mess up tests which use ut_assert_nextline(). Call this
+ * function to tell efi_loader not to emit these characters when starting up the
+ * terminal
+ *
+ * @allow_ansi: Allow emitting ANSI escape-characters
+ */
+void efi_console_set_ansi(bool allow_ansi);
+
 /* Set up load options from environment variable */
 efi_status_t efi_env_set_load_options(efi_handle_t handle, const char *env_var,
 				      u16 **load_options);
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 9d9f786..e310f2f 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -30,6 +30,17 @@
 
 __maybe_unused static struct efi_object uart_obj;
 
+/*
+ * suppress emission of ANSI escape-characters for use by unit tests. Leave it
+ * as 0 for the default behaviour
+ */
+static bool no_ansi;
+
+void efi_console_set_ansi(bool allow_ansi)
+{
+	no_ansi = !allow_ansi;
+}
+
 static struct cout_mode efi_cout_modes[] = {
 	/* EFI Mode 0 is 80x25 and always present */
 	{
@@ -348,13 +359,6 @@
 	return 0;
 }
 
-/**
- * efi_setup_console_size() - update the mode table.
- *
- * By default the only mode available is 80x25. If the console has at least 50
- * lines, enable mode 80x50. If we can query the console size and it is neither
- * 80x25 nor 80x50, set it as an additional mode.
- */
 void efi_setup_console_size(void)
 {
 	int rows = 25, cols = 80;
@@ -362,8 +366,12 @@
 
 	if (IS_ENABLED(CONFIG_VIDEO))
 		ret = query_vidconsole(&rows, &cols);
-	if (ret)
-		ret = query_console_serial(&rows, &cols);
+	if (ret) {
+		if (no_ansi)
+			ret = 0;
+		else
+			ret = query_console_serial(&rows, &cols);
+	}
 	if (ret)
 		return;
 
diff --git a/test/py/conftest.py b/test/py/conftest.py
index 5aea856..6c3ac67 100644
--- a/test/py/conftest.py
+++ b/test/py/conftest.py
@@ -711,9 +711,13 @@
     """
 
     for options in item.iter_markers('buildconfigspec'):
-        option = options.args[0]
-        if not ubconfig.buildconfig.get('config_' + option.lower(), None):
-            pytest.skip('.config feature "%s" not enabled' % option.lower())
+        nomatch = True
+        for arg in options.args:
+            if ubconfig.buildconfig.get('config_' + arg.lower(), None):
+                nomatch = False
+        if nomatch:
+            argsString = ', '.join(options.args)
+            pytest.skip(f'.config features "{argsString}" not enabled')
     for options in item.iter_markers('notbuildconfigspec'):
         option = options.args[0]
         if ubconfig.buildconfig.get('config_' + option.lower(), None):
diff --git a/test/py/tests/test_efi_loader.py b/test/py/tests/test_efi_loader.py
index 91f151d..dc58c0d 100644
--- a/test/py/tests/test_efi_loader.py
+++ b/test/py/tests/test_efi_loader.py
@@ -98,7 +98,7 @@
     global net_set_up
     net_set_up = True
 
-@pytest.mark.buildconfigspec('net')
+@pytest.mark.buildconfigspec('net', 'net_lwip')
 def test_efi_setup_static(ubman):
     """Set up the network using a static IP configuration.
 
diff --git a/test/py/tests/test_fpga.py b/test/py/tests/test_fpga.py
index 74cd42b..299a865 100644
--- a/test/py/tests/test_fpga.py
+++ b/test/py/tests/test_fpga.py
@@ -506,7 +506,7 @@
 @pytest.mark.buildconfigspec('cmd_fpga_load_secure')
 @pytest.mark.buildconfigspec('cmd_net')
 @pytest.mark.buildconfigspec('cmd_dhcp')
-@pytest.mark.buildconfigspec('net')
+@pytest.mark.buildconfigspec('net', 'net_lwip')
 def test_fpga_secure_bit_auth(ubman):
 
     test_net.test_net_dhcp(ubman)
@@ -534,7 +534,7 @@
 @pytest.mark.buildconfigspec('cmd_fpga_load_secure')
 @pytest.mark.buildconfigspec('cmd_net')
 @pytest.mark.buildconfigspec('cmd_dhcp')
-@pytest.mark.buildconfigspec('net')
+@pytest.mark.buildconfigspec('net', 'net_lwip')
 def test_fpga_secure_bit_img_auth_kup(ubman):
 
     test_net.test_net_dhcp(ubman)
diff --git a/test/py/tests/test_net.py b/test/py/tests/test_net.py
index 27cdd73..6ef02e5 100644
--- a/test/py/tests/test_net.py
+++ b/test/py/tests/test_net.py
@@ -201,7 +201,7 @@
     global net6_set_up
     net6_set_up = True
 
-@pytest.mark.buildconfigspec('net')
+@pytest.mark.buildconfigspec('net', 'net_lwip')
 def test_net_setup_static(ubman):
     """Set up a static IP configuration.