From 121ab8e2013f448419ec5192e73b9036a922b692 Mon Sep 17 00:00:00 2001 From: Subrata Banik Date: Wed, 5 Feb 2025 09:32:28 +0000 Subject: [PATCH] lib: Refactor ux_locales_get_text API This patch refactors the `ux_locales_get_text` API to handle fallback text (English) internally, rather than relying on the caller. It introduces message IDs for lookups, enabling the API to locate both the UX locale name and fallback text based on the ID. With this patch, `ux_locales_get_text` API locates UX locales message based on message ID. `ux_locales_get_text` retrieves fallback text message depending upon the message ID if UX locales is not available. This centralizes fallback handling and simplifies adding future messages without per-SoC duplication. BUG=b:339673254 TEST=Built and booted google/brox. Verified eSOL display. Change-Id: I4952802396265b9ee8d164d6e43a7f2b3599d6c0 Signed-off-by: Subrata Banik Reviewed-on: https://review.coreboot.org/c/coreboot/+/86283 Tested-by: build bot (Jenkins) Reviewed-by: Karthik Ramasubramanian Reviewed-by: Julius Werner --- src/include/ux_locales.h | 9 +- src/lib/ux_locales.c | 37 ++++++-- src/soc/intel/alderlake/romstage/ux.c | 10 +- .../intel/meteorlake/romstage/fsp_params.c | 9 +- tests/lib/ux_locales-test.c | 95 +++++++++---------- 5 files changed, 85 insertions(+), 75 deletions(-) diff --git a/src/include/ux_locales.h b/src/include/ux_locales.h index 1affd925d1..e8710839b0 100644 --- a/src/include/ux_locales.h +++ b/src/include/ux_locales.h @@ -5,14 +5,19 @@ #include +enum ux_locale_msg { + UX_LOCALE_MSG_MEMORY_TRAINING, + UX_LOCALE_MSG_NUM, +}; + /* Unmap the preram_locales if it has been mapped. No-op otherwise. */ void ux_locales_unmap(void); /* - * Get the localized text for a given string name. + * Get the localized text for a given message ID as per `enum ux_locale_msg`. * This function will try to read the language ID from vboot API, and search the * corresponding translation from CBFS preram_locales. */ -const char *ux_locales_get_text(const char *name); +const char *ux_locales_get_text(enum ux_locale_msg msg_id); #endif // _UX_LOCALES_H_ diff --git a/src/lib/ux_locales.c b/src/lib/ux_locales.c index b389548955..b9f153772e 100644 --- a/src/lib/ux_locales.c +++ b/src/lib/ux_locales.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include +#include #include #include #include @@ -20,6 +21,18 @@ #define DELIM_STR 0x00 #define DELIM_NAME 0x01 +/* Mapping of different default UX local message based on message ID */ +static const struct { + const char *ux_locale_name; + const char *ux_locale_fallback_text; +} ux_locale_msg_list[] = { + [UX_LOCALE_MSG_MEMORY_TRAINING] = { + "memory_training_desc", + "Your device is finishing an update. This may take 1-2 minutes.\n" + "Please do not turn off your device." + }, +}; + /* * Devices which support early vga have the capability to show localized text in * Code Page 437 encoding. (see src/drivers/pc80/vga/vga_font_8x16.c) @@ -113,18 +126,28 @@ static size_t search_for_id(const char *data, size_t offset, size_t size, return search_for(data, offset, size, int_to_str, DELIM_STR); } -const char *ux_locales_get_text(const char *name) +const char *ux_locales_get_text(enum ux_locale_msg msg_id) { const char *data; size_t size, offset, name_offset, next_name_offset, next; uint32_t lang_id = 0; /* default language English (0) */ unsigned char version; + const char *name; + const char *fallback_text; + + if (msg_id >= UX_LOCALE_MSG_NUM) { + printk(BIOS_ERR, "%s: Unknown message id = %d.\n", __func__, msg_id); + return "Trying to display an unknown message?"; + } + + name = ux_locale_msg_list[msg_id].ux_locale_name; + fallback_text = ux_locale_msg_list[msg_id].ux_locale_fallback_text; data = locales_get_map(&size, false); if (!data || size == 0) { printk(BIOS_ERR, "%s: %s not found.\n", __func__, PRERAM_LOCALES_NAME); - return NULL; + return fallback_text; } if (CONFIG(VBOOT)) { @@ -146,14 +169,14 @@ const char *ux_locales_get_text(const char *name) if (version != PRERAM_LOCALES_VERSION_BYTE) { printk(BIOS_ERR, "%s: The version %u is not the expected one %u\n", __func__, version, PRERAM_LOCALES_VERSION_BYTE); - return NULL; + return fallback_text; } /* Search for name. Skip the version byte. */ offset = search_for_name(data, 1, size, name); if (offset >= size) { printk(BIOS_ERR, "%s: Name %s not found.\n", __func__, name); - return NULL; + return fallback_text; } name_offset = offset; @@ -171,21 +194,21 @@ const char *ux_locales_get_text(const char *name) offset = search_for_id(data, name_offset, next_name_offset, 0); if (offset >= next_name_offset) { printk(BIOS_ERR, "%s: Neither %d nor 0 found.\n", __func__, lang_id); - return NULL; + return fallback_text; } } /* Move to the corresponding localized_string. */ offset = move_next(data, offset, next_name_offset, DELIM_STR); if (offset >= next_name_offset) - return NULL; + return fallback_text; /* Validity check that the returned string must be NULL terminated. */ next = move_next(data, offset, next_name_offset, DELIM_STR) - 1; if (next >= next_name_offset || data[next] != '\0') { printk(BIOS_ERR, "%s: %s is not NULL terminated.\n", __func__, PRERAM_LOCALES_NAME); - return NULL; + return fallback_text; } return data + offset; diff --git a/src/soc/intel/alderlake/romstage/ux.c b/src/soc/intel/alderlake/romstage/ux.c index 0fb73c188d..d0961c51ec 100644 --- a/src/soc/intel/alderlake/romstage/ux.c +++ b/src/soc/intel/alderlake/romstage/ux.c @@ -8,8 +8,6 @@ #include "ux.h" -#define UX_MEMORY_TRAINING_DESC "memory_training_desc" - bool ux_inform_user_of_update_operation(const char *name) { timestamp_add_now(TS_ESOL_START); @@ -22,12 +20,8 @@ bool ux_inform_user_of_update_operation(const char *name) printk(BIOS_INFO, "Informing user on-display of %s.\n", name); - const char *text = ux_locales_get_text(UX_MEMORY_TRAINING_DESC); - /* No localized text found; fallback to built-in English. */ - if (!text) - text = "Your device is finishing an update. " - "This may take 1-2 minutes.\n" - "Please do not turn off your device."; + const char *text = ux_locales_get_text(UX_LOCALE_MSG_MEMORY_TRAINING); + vga_write_text(VGA_TEXT_CENTER, VGA_TEXT_HORIZONTAL_MIDDLE, (const unsigned char *)text); ux_locales_unmap(); diff --git a/src/soc/intel/meteorlake/romstage/fsp_params.c b/src/soc/intel/meteorlake/romstage/fsp_params.c index 82706ed3bf..dd9d2b54c6 100644 --- a/src/soc/intel/meteorlake/romstage/fsp_params.c +++ b/src/soc/intel/meteorlake/romstage/fsp_params.c @@ -436,8 +436,6 @@ static void soc_memory_init_params(FSP_M_CONFIG *m_cfg, fill_fspm_params[i](m_cfg, config); } -#define UX_MEMORY_TRAINING_DESC "memory_training_desc" - #define VGA_INIT_CONTROL_ENABLE BIT(0) /* Tear down legacy VGA mode before exiting FSP-M. */ #define VGA_INIT_CONTROL_TEAR_DOWN BIT(1) @@ -465,12 +463,7 @@ static void fill_fspm_sign_of_life(FSP_M_CONFIG *m_cfg, if (!vga_init_control) return; - const char *text = ux_locales_get_text(UX_MEMORY_TRAINING_DESC); - /* No localized text found; fallback to built-in English. */ - if (!text) - text = "Your device is finishing an update. " - "This may take 1-2 minutes.\n" - "Please do not turn off your device."; + const char *text = ux_locales_get_text(UX_LOCALE_MSG_MEMORY_TRAINING); vbt = cbfs_map("vbt.bin", &vbt_size); if (!vbt) { diff --git a/tests/lib/ux_locales-test.c b/tests/lib/ux_locales-test.c index 5fe18e773c..63f2f56318 100644 --- a/tests/lib/ux_locales-test.c +++ b/tests/lib/ux_locales-test.c @@ -7,22 +7,14 @@ #include #include -#define DATA_DEFAULT \ - ( \ - "\x01" /* Version. */ \ - "name_1\x00" /* name_1, langs = [0, 2, 30]. */ \ - "0\x00translation_1_0\x00" \ - "2\x00translation_1_2\x00" \ - "30\x00translation_1_30\x00" \ - "\x01" \ - "name_15\x00" /* name_15, langs = [4, 25, 60]. */ \ - "4\x00translation_15_4\x00" \ - "25\x00translation_15_25\x00" \ - "60\x00translation_15_60\x00" \ - "\x01" \ - "name_20\x00" /* name_20, langs = [8]. */ \ - "8\x00translation_20_8\x00" \ - "\x01" \ +#define DATA_DEFAULT \ + ( \ + "\x01" /* Version. */ \ + "memory_training_desc\x00" /* memory_training_desc, langs = [0, 2, 30]. */ \ + "0\x00memory_training_desc_0\x00" \ + "2\x00memory_training_desc_2\x00" \ + "30\x00memory_training_desc_30\x00" \ + "\x01" \ ) const unsigned char data_default[] = DATA_DEFAULT; @@ -73,7 +65,7 @@ struct vb2_context *vboot_get_context(void) /* Test states for test_ux_locales_get_text with valid CBFS data. */ struct ux_locales_test_state { - const char *name; + enum ux_locale_msg msg_id; uint32_t lang_id; const char *expect; }; @@ -116,9 +108,12 @@ static void test_ux_locales_get_text(void **state) struct ux_locales_test_state *s = *state; const char *ret; - will_return(_cbfs_alloc, true); - will_return(vb2api_get_locale_id, s->lang_id); - ret = ux_locales_get_text(s->name); + if (s->msg_id < UX_LOCALE_MSG_NUM) { + will_return(_cbfs_alloc, true); + will_return(vb2api_get_locale_id, s->lang_id); + } + + ret = ux_locales_get_text(s->msg_id); if (s->expect) { assert_non_null(ret); assert_string_equal(ret, s->expect); @@ -131,14 +126,18 @@ static void test_ux_locales_bad_cbfs(void **state) { will_return(_cbfs_alloc, false); will_return_maybe(vb2api_get_locale_id, 0); - assert_null(ux_locales_get_text("name_1")); + assert_string_equal(ux_locales_get_text(UX_LOCALE_MSG_MEMORY_TRAINING), + "Your device is finishing an update. This may take 1-2 minutes.\n" + "Please do not turn off your device."); } static void test_ux_locales_bad_version(void **state) { will_return(_cbfs_alloc, true); will_return(vb2api_get_locale_id, 0); - assert_null(ux_locales_get_text("name_1")); + assert_string_equal(ux_locales_get_text(UX_LOCALE_MSG_MEMORY_TRAINING), + "Your device is finishing an update. This may take 1-2 minutes.\n" + "Please do not turn off your device."); } static void test_ux_locales_two_calls(void **state) @@ -148,26 +147,26 @@ static void test_ux_locales_two_calls(void **state) /* We do not need to ensure that we cached the cbfs region. */ will_return_always(_cbfs_alloc, true); - /* Call #1: read (15, 60). */ - will_return(vb2api_get_locale_id, 60); - ret = ux_locales_get_text("name_15"); + /* Call #1: read (1, 30). */ + will_return(vb2api_get_locale_id, 30); + ret = ux_locales_get_text(UX_LOCALE_MSG_MEMORY_TRAINING); assert_non_null(ret); - assert_string_equal(ret, "translation_15_60"); + assert_string_equal(ret, "memory_training_desc_30"); /* Call #2: read (1, 0). */ will_return(vb2api_get_locale_id, 0); - ret = ux_locales_get_text("name_1"); + ret = ux_locales_get_text(UX_LOCALE_MSG_MEMORY_TRAINING); assert_non_null(ret); - assert_string_equal(ret, "translation_1_0"); + assert_string_equal(ret, "memory_training_desc_0"); } static void test_ux_locales_null_terminated(void **state) { will_return_always(_cbfs_alloc, true); - will_return_always(vb2api_get_locale_id, 8); + will_return_always(vb2api_get_locale_id, 30); /* Verify the access to the very last text. */ - assert_non_null(ux_locales_get_text("name_20")); + assert_non_null(ux_locales_get_text(UX_LOCALE_MSG_MEMORY_TRAINING)); /* Modify the last 2 bytes from "\x00\x01" to "XX" and unmap, */ data.raw[data.size - 1] = 'X'; @@ -175,24 +174,27 @@ static void test_ux_locales_null_terminated(void **state) ux_locales_unmap(); /* The last few characters are now changed so that the data is not NULL terminated. - This will prevent us from accessing the last text. */ - assert_null(ux_locales_get_text("name_20")); + This will prevent us from accessing the last text therefore, make use of fallback + text message */ + assert_string_equal(ux_locales_get_text(UX_LOCALE_MSG_MEMORY_TRAINING), + "Your device is finishing an update. This may take 1-2 minutes.\n" + "Please do not turn off your device."); } /* - * This macro helps test ux_locales_get_text with `_name` and `_lang_id`. + * This macro helps test ux_locales_get_text with `_msg_id` and `_lang_id`. * If `_expect` is NULL, then the function should not find anything. * Otherwise, the function should find the corresponding expect value. */ -#define UX_LOCALES_GET_TEXT_TEST(_name, _lang_id, _expect) \ +#define UX_LOCALES_GET_TEXT_TEST(_msg_id, _lang_id, _expect) \ ((struct CMUnitTest) { \ - .name = "test_ux_locales_get_text(name=" _name ", lang_id=" #_lang_id \ + .name = "test_ux_locales_get_text(msg_id=" #_msg_id ", lang_id=" #_lang_id \ ", expect=" #_expect ")", \ .test_func = test_ux_locales_get_text, \ .setup_func = setup_default, \ .teardown_func = teardown_unmap, \ .initial_state = &(struct ux_locales_test_state) { \ - .name = _name, \ + .msg_id = _msg_id, \ .lang_id = _lang_id, \ .expect = _expect, \ }, \ @@ -202,21 +204,14 @@ int main(void) { const struct CMUnitTest tests[] = { /* Get text successfully. */ - UX_LOCALES_GET_TEXT_TEST("name_1", 0, "translation_1_0"), - /* Get text with name and id both in the middle. */ - UX_LOCALES_GET_TEXT_TEST("name_15", 25, "translation_15_25"), - /* Ensure we check the whole string of 'name'. - ('name_2' is the prefix of 'name_20') */ - UX_LOCALES_GET_TEXT_TEST("name_2", 3, NULL), - /* Ensure we check the whole string of 'lang_id'. - (id:'2' is the prefix of id:'25' in 'name_15') */ - UX_LOCALES_GET_TEXT_TEST("name_15", 2, NULL), - /* Ensure we will fallback to 0. */ - UX_LOCALES_GET_TEXT_TEST("name_1", 7, "translation_1_0"), - /* Do not search for locale id with unmatched name. */ - UX_LOCALES_GET_TEXT_TEST("name_15", 8, NULL), + UX_LOCALES_GET_TEXT_TEST(UX_LOCALE_MSG_MEMORY_TRAINING, 0, "memory_training_desc_0"), + UX_LOCALES_GET_TEXT_TEST(UX_LOCALE_MSG_MEMORY_TRAINING, 2, "memory_training_desc_2"), + /* Check the whole string of lang_id. */ + UX_LOCALES_GET_TEXT_TEST(UX_LOCALE_MSG_MEMORY_TRAINING, 3, "memory_training_desc_0"), /* Validity check of lang_id > 100. We will fallback to 0. */ - UX_LOCALES_GET_TEXT_TEST("name_1", 100, "translation_1_0"), + UX_LOCALES_GET_TEXT_TEST(UX_LOCALE_MSG_MEMORY_TRAINING, 100, "memory_training_desc_0"), + /* Ensure we show fallback message if `msg_id >= UX_LOCALE_MSG_NUM` */ + UX_LOCALES_GET_TEXT_TEST(UX_LOCALE_MSG_NUM, 0, "Trying to display an unknown message?"), /* cbfs not found. */ cmocka_unit_test_setup_teardown(test_ux_locales_bad_cbfs, setup_default, teardown_unmap),