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),