From 6278ec1919fff83a4f0adde1e5d987852b154ebf Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 27 Nov 2020 11:20:51 +0100 Subject: [PATCH 01/46] test: add LOGL_FORCE_DEBUG flags support in log tests Add a check of the _log function with LOGL_FORCE_DEBUG flags, used to force the trace display. The trace should be displayed for all the level when flags have LOGL_FORCE_DEBUG bit is set, for any filter. Signed-off-by: Patrick Delaunay Reviewed-by: Sean Anderson Reviewed-by: Simon Glass --- test/log/log_test.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/test/log/log_test.c b/test/log/log_test.c index ea4fc6bc30..15874751f9 100644 --- a/test/log/log_test.c +++ b/test/log/log_test.c @@ -26,6 +26,11 @@ static int do_log_run(int cat, const char *file) _log(log_uc_cat(cat), i, file, 100 + i, "func", "_log %d\n", i); } + /* test with LOGL_COUNT flag */ + for (i = LOGL_FIRST; i < LOGL_COUNT; i++) { + _log(log_uc_cat(cat), i | LOGL_FORCE_DEBUG, file, 100 + i, + "func", "_log force %d\n", i); + } gd->log_fmt = log_get_default_format(); return 0; @@ -38,6 +43,7 @@ static int do_log_run(int cat, const char *file) #define EXPECT_LOG BIT(0) #define EXPECT_DIRECT BIT(1) #define EXPECT_EXTRA BIT(2) +#define EXPECT_FORCE BIT(3) static int do_check_log_entries(struct unit_test_state *uts, int flags, int min, int max) @@ -54,6 +60,11 @@ static int do_check_log_entries(struct unit_test_state *uts, int flags, int min, for (; i <= LOGL_MAX ; i++) ut_assert_nextline("func() _log %d", i); + for (i = LOGL_FIRST; i < LOGL_COUNT; i++) { + if (flags & EXPECT_FORCE) + ut_assert_nextline("func() _log force %d", i); + } + ut_assert_console_end(); return 0; } @@ -66,10 +77,10 @@ static int do_check_log_entries(struct unit_test_state *uts, int flags, int min, #define check_log_entries_flags(flags) \ check_log_entries_flags_levels(flags, LOGL_FIRST, _LOG_MAX_LEVEL) -#define check_log_entries() check_log_entries_flags(EXPECT_LOG | EXPECT_DIRECT) +#define check_log_entries() check_log_entries_flags(EXPECT_LOG | EXPECT_DIRECT | EXPECT_FORCE) #define check_log_entries_extra() \ - check_log_entries_flags(EXPECT_LOG | EXPECT_DIRECT | EXPECT_EXTRA) -#define check_log_entries_none() check_log_entries_flags(0) + check_log_entries_flags(EXPECT_LOG | EXPECT_DIRECT | EXPECT_EXTRA | EXPECT_FORCE) +#define check_log_entries_none() check_log_entries_flags(EXPECT_FORCE) /* Check a category filter using the first category */ int log_test_cat_allow(struct unit_test_state *uts) @@ -126,7 +137,7 @@ int log_test_file(struct unit_test_state *uts) ut_assertok(console_record_reset_enable()); log_run_file("file"); - check_log_entries_flags(EXPECT_DIRECT | EXPECT_EXTRA); + check_log_entries_flags(EXPECT_DIRECT | EXPECT_EXTRA | EXPECT_FORCE); ut_assertok(console_record_reset_enable()); log_run_file("file2"); @@ -147,7 +158,7 @@ int log_test_file_second(struct unit_test_state *uts) ut_assertok(console_record_reset_enable()); log_run_file("file2"); - check_log_entries_flags(EXPECT_DIRECT | EXPECT_EXTRA); + check_log_entries_flags(EXPECT_DIRECT | EXPECT_EXTRA | EXPECT_FORCE); ut_assertok(log_remove_filter("console", filt)); return 0; @@ -182,8 +193,8 @@ int log_test_level(struct unit_test_state *uts) ut_assertok(console_record_reset_enable()); log_run(); - check_log_entries_flags_levels(EXPECT_LOG | EXPECT_DIRECT, LOGL_FIRST, - LOGL_WARNING); + check_log_entries_flags_levels(EXPECT_LOG | EXPECT_DIRECT | EXPECT_FORCE, + LOGL_FIRST, LOGL_WARNING); ut_assertok(log_remove_filter("console", filt)); return 0; @@ -351,7 +362,7 @@ int log_test_level_deny(struct unit_test_state *uts) ut_assertok(console_record_reset_enable()); log_run(); - check_log_entries_flags_levels(EXPECT_LOG | EXPECT_DIRECT, + check_log_entries_flags_levels(EXPECT_LOG | EXPECT_DIRECT | EXPECT_FORCE, LOGL_WARNING + 1, _LOG_MAX_LEVEL); ut_assertok(log_remove_filter("console", filt1)); @@ -374,7 +385,7 @@ int log_test_min(struct unit_test_state *uts) ut_assertok(console_record_reset_enable()); log_run(); - check_log_entries_flags_levels(EXPECT_LOG | EXPECT_DIRECT, + check_log_entries_flags_levels(EXPECT_LOG | EXPECT_DIRECT | EXPECT_FORCE, LOGL_WARNING, LOGL_INFO - 1); ut_assertok(log_remove_filter("console", filt1)); From f0e90e0eadbed59f0afb0d281816873339fd51ee Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 27 Nov 2020 11:20:52 +0100 Subject: [PATCH 02/46] log: don't build the trace buffer when log is not ready Update _log function to drop any traces when log is yet initialized: vsnprintf is no more executed in this case. This patch allows to reduce the cost for the dropped early debug trace. Reviewed-by: Simon Glass Signed-off-by: Patrick Delaunay --- common/log.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/common/log.c b/common/log.c index ce39918e04..212789d6b3 100644 --- a/common/log.c +++ b/common/log.c @@ -228,6 +228,9 @@ int _log(enum log_category_t cat, enum log_level_t level, const char *file, struct log_rec rec; va_list args; + if (!gd) + return -ENOSYS; + /* Check for message continuation */ if (cat == LOGC_CONT) cat = gd->logc_prev; @@ -240,15 +243,15 @@ int _log(enum log_category_t cat, enum log_level_t level, const char *file, rec.file = file; rec.line = line; rec.func = func; + + if (!(gd->flags & GD_FLG_LOG_READY)) { + gd->log_drop_count++; + return -ENOSYS; + } va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); rec.msg = buf; - if (!gd || !(gd->flags & GD_FLG_LOG_READY)) { - if (gd) - gd->log_drop_count++; - return -ENOSYS; - } if (!log_dispatch(&rec)) { gd->logc_prev = cat; gd->logl_prev = level; From ce9af2a6b57b512853d6e6234616edc4265669de Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 27 Nov 2020 11:20:53 +0100 Subject: [PATCH 03/46] test: log: add test for dropped messages Add a new test to check the dropped messages when LOG is not ready with log_drop_count and the result of _log(). Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass --- test/log/log_test.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/test/log/log_test.c b/test/log/log_test.c index 15874751f9..6bafc1e315 100644 --- a/test/log/log_test.c +++ b/test/log/log_test.c @@ -15,30 +15,38 @@ DECLARE_GLOBAL_DATA_PTR; /* emit some sample log records in different ways, for testing */ -static int do_log_run(int cat, const char *file) +static int do_log_run(struct unit_test_state *uts, int cat, const char *file) { int i; + int ret, expected_ret; + + if (gd->flags & GD_FLG_LOG_READY) + expected_ret = 0; + else + expected_ret = -ENOSYS; gd->log_fmt = LOGF_TEST; debug("debug\n"); for (i = LOGL_FIRST; i < LOGL_COUNT; i++) { log(cat, i, "log %d\n", i); - _log(log_uc_cat(cat), i, file, 100 + i, "func", "_log %d\n", - i); + ret = _log(log_uc_cat(cat), i, file, 100 + i, + "func", "_log %d\n", i); + ut_asserteq(ret, expected_ret); } /* test with LOGL_COUNT flag */ for (i = LOGL_FIRST; i < LOGL_COUNT; i++) { - _log(log_uc_cat(cat), i | LOGL_FORCE_DEBUG, file, 100 + i, - "func", "_log force %d\n", i); + ret = _log(log_uc_cat(cat), i | LOGL_FORCE_DEBUG, file, 100 + i, + "func", "_log force %d\n", i); + ut_asserteq(ret, expected_ret); } gd->log_fmt = log_get_default_format(); return 0; } -#define log_run_cat(cat) do_log_run(cat, "file") -#define log_run_file(file) do_log_run(UCLASS_SPI, file) -#define log_run() do_log_run(UCLASS_SPI, "file") +#define log_run_cat(cat) do_log_run(uts, cat, "file") +#define log_run_file(file) do_log_run(uts, UCLASS_SPI, file) +#define log_run() do_log_run(uts, UCLASS_SPI, "file") #define EXPECT_LOG BIT(0) #define EXPECT_DIRECT BIT(1) @@ -393,3 +401,22 @@ int log_test_min(struct unit_test_state *uts) return 0; } LOG_TEST_FLAGS(log_test_min, UT_TESTF_CONSOLE_REC); + +/* Check dropped traces */ +int log_test_dropped(struct unit_test_state *uts) +{ + /* force LOG not ready */ + gd->flags &= ~(GD_FLG_LOG_READY); + gd->log_drop_count = 0; + + ut_assertok(console_record_reset_enable()); + log_run(); + + ut_asserteq(gd->log_drop_count, 3 * (LOGL_COUNT - LOGL_FIRST - 1)); + + gd->flags |= GD_FLG_LOG_READY; + gd->log_drop_count = 0; + + return 0; +} +LOG_TEST_FLAGS(log_test_dropped, UT_TESTF_CONSOLE_REC); From dd500134a4201f0edd8a8f6b9618ed7094b8d29e Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 27 Nov 2020 11:20:54 +0100 Subject: [PATCH 04/46] log: use console puts to output trace before LOG init Use the console puts functions to output the traces before the log initialization (when CONFIG_LOG is not activated). This patch allows to display the first U-Boot traces (with macro debug) when CONFIG_DEBUG_UART is activated and not only drop them. For example for traces in board_f.c requested by the macro debug, when LOG_DEBUG is defined and CONFIG_LOG is activated. Signed-off-by: Patrick Delaunay --- common/log.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/common/log.c b/common/log.c index 212789d6b3..a4ed7d79f8 100644 --- a/common/log.c +++ b/common/log.c @@ -246,6 +246,15 @@ int _log(enum log_category_t cat, enum log_level_t level, const char *file, if (!(gd->flags & GD_FLG_LOG_READY)) { gd->log_drop_count++; + + /* display dropped traces with console puts and DEBUG_UART */ + if (rec.level <= CONFIG_LOG_DEFAULT_LEVEL || rec.force_debug) { + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + puts(buf); + va_end(args); + } + return -ENOSYS; } va_start(args, fmt); From a4918b231065224092a34bf8cca5af704bb8373b Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 27 Nov 2020 11:20:55 +0100 Subject: [PATCH 05/46] test: add test for dropped trace before log_init Add test for dropped trace before log_init, displayed by debug uart. Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass --- arch/sandbox/cpu/start.c | 5 +++++ test/py/tests/test_log.py | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index 8322ed7a1f..2d18d9debc 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -486,6 +487,10 @@ int main(int argc, char *argv[]) */ gd->reloc_off = (ulong)gd->arch.text_base; + /* sandbox test: log functions called before log_init in board_init_f */ + log_info("sandbox: starting...\n"); + log_debug("debug: %s\n", __func__); + /* Do pre- and post-relocation init */ board_init_f(0); diff --git a/test/py/tests/test_log.py b/test/py/tests/test_log.py index 387b392ce9..f889120f2b 100644 --- a/test/py/tests/test_log.py +++ b/test/py/tests/test_log.py @@ -36,3 +36,14 @@ def test_log_format(u_boot_console): run_with_format('FLfm', 'file.c:123-func() msg') run_with_format('lm', 'NOTICE. msg') run_with_format('m', 'msg') + +@pytest.mark.buildconfigspec('debug_uart') +@pytest.mark.boardspec('sandbox') +def test_log_dropped(u_boot_console): + """Test dropped 'log' message when debug_uart is activated""" + + cons = u_boot_console + cons.restart_uboot() + output = cons.get_spawn_output().replace('\r', '') + assert 'sandbox: starting...' in output + assert (not 'debug: main' in output) From 93cdb52b2a06bf5fb2ea02db28a95b5524ab1e6e Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 27 Nov 2020 11:20:56 +0100 Subject: [PATCH 06/46] console: remove duplicated test on gd value Reorder test on gd value and remove the duplicated test (!gd) in putc and puts function. This patch is a preliminary step for rework of this function. Signed-off-by: Patrick Delaunay Reviewed-by: Sean Anderson Reviewed-by: Simon Glass --- common/console.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/common/console.c b/common/console.c index 3348436da6..70579af042 100644 --- a/common/console.c +++ b/common/console.c @@ -517,22 +517,22 @@ static inline void print_pre_console_buffer(int flushpoint) {} void putc(const char c) { + if (!gd) + return; #ifdef CONFIG_SANDBOX /* sandbox can send characters to stdout before it has a console */ - if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) { + if (!(gd->flags & GD_FLG_SERIAL_READY)) { os_putc(c); return; } #endif #ifdef CONFIG_DEBUG_UART /* if we don't have a console yet, use the debug UART */ - if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) { + if (!(gd->flags & GD_FLG_SERIAL_READY)) { printch(c); return; } #endif - if (!gd) - return; #ifdef CONFIG_CONSOLE_RECORD if ((gd->flags & GD_FLG_RECORD) && gd->console_out.start) membuff_putbyte((struct membuff *)&gd->console_out, c); @@ -565,15 +565,17 @@ void putc(const char c) void puts(const char *s) { + if (!gd) + return; #ifdef CONFIG_SANDBOX /* sandbox can send characters to stdout before it has a console */ - if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) { + if (!(gd->flags & GD_FLG_SERIAL_READY)) { os_puts(s); return; } #endif #ifdef CONFIG_DEBUG_UART - if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) { + if (!(gd->flags & GD_FLG_SERIAL_READY)) { while (*s) { int ch = *s++; @@ -582,8 +584,6 @@ void puts(const char *s) return; } #endif - if (!gd) - return; #ifdef CONFIG_CONSOLE_RECORD if ((gd->flags & GD_FLG_RECORD) && gd->console_out.start) membuff_put((struct membuff *)&gd->console_out, s, strlen(s)); From bf80edb91a9b7d61621c1413c15495348f8f0fcc Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 27 Nov 2020 11:20:57 +0100 Subject: [PATCH 07/46] console: allow to record console output before ready Allow to record the console output before before U-Boot has a console ready. This patch allows to test the console output in sandbox test based on console record. It is possible because GD_FLG_RECORD and GD_FLG_SERIAL_READY are 2 independent flags. Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass --- common/console.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/common/console.c b/common/console.c index 70579af042..c3d552bb3e 100644 --- a/common/console.c +++ b/common/console.c @@ -519,6 +519,10 @@ void putc(const char c) { if (!gd) return; +#ifdef CONFIG_CONSOLE_RECORD + if ((gd->flags & GD_FLG_RECORD) && gd->console_out.start) + membuff_putbyte((struct membuff *)&gd->console_out, c); +#endif #ifdef CONFIG_SANDBOX /* sandbox can send characters to stdout before it has a console */ if (!(gd->flags & GD_FLG_SERIAL_READY)) { @@ -533,10 +537,6 @@ void putc(const char c) return; } #endif -#ifdef CONFIG_CONSOLE_RECORD - if ((gd->flags & GD_FLG_RECORD) && gd->console_out.start) - membuff_putbyte((struct membuff *)&gd->console_out, c); -#endif #ifdef CONFIG_SILENT_CONSOLE if (gd->flags & GD_FLG_SILENT) { if (!(gd->flags & GD_FLG_DEVINIT)) @@ -567,6 +567,10 @@ void puts(const char *s) { if (!gd) return; +#ifdef CONFIG_CONSOLE_RECORD + if ((gd->flags & GD_FLG_RECORD) && gd->console_out.start) + membuff_put((struct membuff *)&gd->console_out, s, strlen(s)); +#endif #ifdef CONFIG_SANDBOX /* sandbox can send characters to stdout before it has a console */ if (!(gd->flags & GD_FLG_SERIAL_READY)) { @@ -584,10 +588,6 @@ void puts(const char *s) return; } #endif -#ifdef CONFIG_CONSOLE_RECORD - if ((gd->flags & GD_FLG_RECORD) && gd->console_out.start) - membuff_put((struct membuff *)&gd->console_out, s, strlen(s)); -#endif #ifdef CONFIG_SILENT_CONSOLE if (gd->flags & GD_FLG_SILENT) { if (!(gd->flags & GD_FLG_DEVINIT)) From 742346f6cc1d7053e95d26c82d235e00dd8c1e40 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 27 Nov 2020 11:20:58 +0100 Subject: [PATCH 08/46] test: log: add test for console output of dropped messages Add a new test to check the content of the dropped messages sent to console puts function. Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass --- test/log/log_test.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/log/log_test.c b/test/log/log_test.c index 6bafc1e315..82234a6994 100644 --- a/test/log/log_test.c +++ b/test/log/log_test.c @@ -52,6 +52,7 @@ static int do_log_run(struct unit_test_state *uts, int cat, const char *file) #define EXPECT_DIRECT BIT(1) #define EXPECT_EXTRA BIT(2) #define EXPECT_FORCE BIT(3) +#define EXPECT_DEBUG BIT(4) static int do_check_log_entries(struct unit_test_state *uts, int flags, int min, int max) @@ -63,6 +64,10 @@ static int do_check_log_entries(struct unit_test_state *uts, int flags, int min, ut_assert_nextline("do_log_run() log %d", i); if (flags & EXPECT_DIRECT) ut_assert_nextline("func() _log %d", i); + if (flags & EXPECT_DEBUG) { + ut_assert_nextline("log %d", i); + ut_assert_nextline("_log %d", i); + } } if (flags & EXPECT_EXTRA) for (; i <= LOGL_MAX ; i++) @@ -71,6 +76,8 @@ static int do_check_log_entries(struct unit_test_state *uts, int flags, int min, for (i = LOGL_FIRST; i < LOGL_COUNT; i++) { if (flags & EXPECT_FORCE) ut_assert_nextline("func() _log force %d", i); + if (flags & EXPECT_DEBUG) + ut_assert_nextline("_log force %d", i); } ut_assert_console_end(); @@ -413,6 +420,7 @@ int log_test_dropped(struct unit_test_state *uts) log_run(); ut_asserteq(gd->log_drop_count, 3 * (LOGL_COUNT - LOGL_FIRST - 1)); + check_log_entries_flags_levels(EXPECT_DEBUG, LOGL_FIRST, CONFIG_LOG_DEFAULT_LEVEL); gd->flags |= GD_FLG_LOG_READY; gd->log_drop_count = 0; From c698b998bb6003297f8ce20ba136348446e78278 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 27 Nov 2020 11:20:59 +0100 Subject: [PATCH 09/46] log: call vsnprintf only when it is needed to emit trace Reduce the log overhead when the traces are filtered, by moving the vsnprintf call from _log() to log_dispatch(). This patch avoids the printf treatment when LOG features is activated, but trace is filtered, for example when MAX_LOG_LEVEL=8 and LOG_DEFAULT_LEVEL=6. Reviewed-by: Simon Glass Signed-off-by: Patrick Delaunay --- common/log.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/common/log.c b/common/log.c index a4ed7d79f8..767f0febc5 100644 --- a/common/log.c +++ b/common/log.c @@ -198,9 +198,10 @@ static bool log_passes_filters(struct log_device *ldev, struct log_rec *rec) * @rec: log record to dispatch * Return: 0 msg sent, 1 msg not sent while already dispatching another msg */ -static int log_dispatch(struct log_rec *rec) +static int log_dispatch(struct log_rec *rec, const char *fmt, va_list args) { struct log_device *ldev; + char buf[CONFIG_SYS_CBSIZE]; /* * When a log driver writes messages (e.g. via the network stack) this @@ -214,8 +215,13 @@ static int log_dispatch(struct log_rec *rec) gd->processing_msg = true; list_for_each_entry(ldev, &gd->log_head, sibling_node) { if ((ldev->flags & LOGDF_ENABLE) && - log_passes_filters(ldev, rec)) + log_passes_filters(ldev, rec)) { + if (!rec->msg) { + vsnprintf(buf, sizeof(buf), fmt, args); + rec->msg = buf; + } ldev->drv->emit(ldev, rec); + } } gd->processing_msg = false; return 0; @@ -224,7 +230,6 @@ static int log_dispatch(struct log_rec *rec) int _log(enum log_category_t cat, enum log_level_t level, const char *file, int line, const char *func, const char *fmt, ...) { - char buf[CONFIG_SYS_CBSIZE]; struct log_rec rec; va_list args; @@ -243,12 +248,15 @@ int _log(enum log_category_t cat, enum log_level_t level, const char *file, rec.file = file; rec.line = line; rec.func = func; + rec.msg = NULL; if (!(gd->flags & GD_FLG_LOG_READY)) { gd->log_drop_count++; /* display dropped traces with console puts and DEBUG_UART */ if (rec.level <= CONFIG_LOG_DEFAULT_LEVEL || rec.force_debug) { + char buf[CONFIG_SYS_CBSIZE]; + va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); puts(buf); @@ -258,13 +266,11 @@ int _log(enum log_category_t cat, enum log_level_t level, const char *file, return -ENOSYS; } va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - rec.msg = buf; - if (!log_dispatch(&rec)) { + if (!log_dispatch(&rec, fmt, args)) { gd->logc_prev = cat; gd->logl_prev = level; } + va_end(args); return 0; } From 4e81920ba8f426d381583c9b2e576230a0757db5 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:03 +0200 Subject: [PATCH 10/46] common: Kconfig: Introduce CONFIG_CONSOLE_RECORD_INIT_F Currently, the following #ifdef construct is used to check whether to run console_record_init() during pre-relocation init: defined(CONFIG_CONSOLE_RECORD) && CONFIG_VAL(SYS_MALLOC_F_LEN) Introduce CONFIG_CONSOLE_RECORD_INIT_F Kconfig option to get rid of the complex ifdef check. Also, use IS_ENABLED() instead of #ifdef. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- common/Kconfig | 8 ++++++++ common/board_f.c | 7 +++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/common/Kconfig b/common/Kconfig index 2bce8c9ba1..d8982ba377 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -17,6 +17,14 @@ config CONSOLE_RECORD To enable console recording, call console_record_reset_enable() from your code. +config CONSOLE_RECORD_INIT_F + bool "Enable console recording during pre-relocation init" + depends on CONSOLE_RECORD && SYS_MALLOC_F + default y + help + This option enables console recording during pre-relocation init. + CONFIG_SYS_MALLOC_F must be enabled to use this feature. + config CONSOLE_RECORD_OUT_SIZE hex "Output buffer size" depends on CONSOLE_RECORD diff --git a/common/board_f.c b/common/board_f.c index 9f441c44f1..e5e69ff0fa 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -767,11 +767,10 @@ static int initf_bootstage(void) static int initf_console_record(void) { -#if defined(CONFIG_CONSOLE_RECORD) && CONFIG_VAL(SYS_MALLOC_F_LEN) - return console_record_init(); -#else + if (IS_ENABLED(CONFIG_CONSOLE_RECORD_INIT_F)) + return console_record_init(); + return 0; -#endif } static int initf_dm(void) From 8e8d45ee0209f5362b40218bcc5ae172b214042e Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:04 +0200 Subject: [PATCH 11/46] common: board_f: Drop initf_console_record wrapper Drop initf_console_record wrapper and call console_record_init directly. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- common/board_f.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/common/board_f.c b/common/board_f.c index e5e69ff0fa..552552e328 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -765,14 +765,6 @@ static int initf_bootstage(void) return 0; } -static int initf_console_record(void) -{ - if (IS_ENABLED(CONFIG_CONSOLE_RECORD_INIT_F)) - return console_record_init(); - - return 0; -} - static int initf_dm(void) { #if defined(CONFIG_DM) && CONFIG_VAL(SYS_MALLOC_F_LEN) @@ -829,7 +821,9 @@ static const init_fnc_t init_sequence_f[] = { bloblist_init, #endif setup_spl_handoff, - initf_console_record, +#if defined(CONFIG_CONSOLE_RECORD_INIT_F) + console_record_init, +#endif #if defined(CONFIG_HAVE_FSP) arch_fsp_init, #endif From 4b9a121fc6fa211a33b693851f55b60954635fce Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:05 +0200 Subject: [PATCH 12/46] common: board_f: Use IS_ENABLED(CONFIG_TIMER_EARLY) in initf_dm Use IS_ENABLED(CONFIG_TIMER_EARLY) instead of #ifdef in initf_dm. Also, move timer code to the main ifdef, so that ret is defined. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- common/board_f.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/common/board_f.c b/common/board_f.c index 552552e328..3c4437341a 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -775,11 +775,12 @@ static int initf_dm(void) bootstage_accum(BOOTSTAGE_ID_ACCUM_DM_F); if (ret) return ret; -#endif -#ifdef CONFIG_TIMER_EARLY - ret = dm_timer_init(); - if (ret) - return ret; + + if (IS_ENABLED(CONFIG_TIMER_EARLY)) { + ret = dm_timer_init(); + if (ret) + return ret; + } #endif return 0; From 36716686767dc3e31ad0076d3661d607d66f80c6 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:06 +0200 Subject: [PATCH 13/46] common: board_f: Move setup_machine code to setup_bdinfo setup_bdinfo is used to populate various bdinfo fields, so move setup_machine code there, as all it does is setting gd->bd->bi_arch_number. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- common/board_f.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/common/board_f.c b/common/board_f.c index 3c4437341a..fbf622e0f0 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -503,14 +503,6 @@ static int reserve_board(void) return 0; } -static int setup_machine(void) -{ -#ifdef CONFIG_MACH_TYPE - gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */ -#endif - return 0; -} - static int reserve_global_data(void) { gd->start_addr_sp = reserve_stack_aligned(sizeof(gd_t)); @@ -605,6 +597,10 @@ int setup_bdinfo(void) bd->bi_sramsize = CONFIG_SYS_SRAM_SIZE; /* size of SRAM */ } +#ifdef CONFIG_MACH_TYPE + bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */ +#endif + return arch_setup_bdinfo(); } @@ -916,7 +912,6 @@ static const init_fnc_t init_sequence_f[] = { reserve_uboot, reserve_malloc, reserve_board, - setup_machine, reserve_global_data, reserve_fdt, reserve_bootstage, From 19b18daa29b093d7d255190f75b2accac8f4057d Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:07 +0200 Subject: [PATCH 14/46] common: board_f: Use IS_ENABLED(CONFIG_OF_EMBED) in reserve_fdt, reloc_fdt Use IS_ENABLED(CONFIG_OF_EMBED) in instead of #ifdefs in reserve_fdt, reloc_fdt functions. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- common/board_f.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/common/board_f.c b/common/board_f.c index fbf622e0f0..ae3001bed1 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -514,21 +514,21 @@ static int reserve_global_data(void) static int reserve_fdt(void) { -#ifndef CONFIG_OF_EMBED - /* - * If the device tree is sitting immediately above our image then we - * must relocate it. If it is embedded in the data section, then it - * will be relocated with other data. - */ - if (gd->fdt_blob) { - gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob), 32); + if (!IS_ENABLED(CONFIG_OF_EMBED)) { + /* + * If the device tree is sitting immediately above our image + * then we must relocate it. If it is embedded in the data + * section, then it will be relocated with other data. + */ + if (gd->fdt_blob) { + gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob), 32); - gd->start_addr_sp = reserve_stack_aligned(gd->fdt_size); - gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size); - debug("Reserving %lu Bytes for FDT at: %08lx\n", - gd->fdt_size, gd->start_addr_sp); + gd->start_addr_sp = reserve_stack_aligned(gd->fdt_size); + gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size); + debug("Reserving %lu Bytes for FDT at: %08lx\n", + gd->fdt_size, gd->start_addr_sp); + } } -#endif return 0; } @@ -616,14 +616,15 @@ static int init_post(void) static int reloc_fdt(void) { -#ifndef CONFIG_OF_EMBED - if (gd->flags & GD_FLG_SKIP_RELOC) - return 0; - if (gd->new_fdt) { - memcpy(gd->new_fdt, gd->fdt_blob, fdt_totalsize(gd->fdt_blob)); - gd->fdt_blob = gd->new_fdt; + if (!IS_ENABLED(CONFIG_OF_EMBED)) { + if (gd->flags & GD_FLG_SKIP_RELOC) + return 0; + if (gd->new_fdt) { + memcpy(gd->new_fdt, gd->fdt_blob, + fdt_totalsize(gd->fdt_blob)); + gd->fdt_blob = gd->new_fdt; + } } -#endif return 0; } From 51c5a2c5e43e2c9c7ad6720c40aad8a55452f62c Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:08 +0200 Subject: [PATCH 15/46] common: board_r: Drop initr_console_record wrapper Drop initr_console_record wrapper and call console_record_init directly. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- common/board_r.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/common/board_r.c b/common/board_r.c index 29dd7d26d9..07c0ad363e 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -282,15 +282,6 @@ static int initr_malloc(void) return 0; } -static int initr_console_record(void) -{ -#if defined(CONFIG_CONSOLE_RECORD) - return console_record_init(); -#else - return 0; -#endif -} - #ifdef CONFIG_SYS_NONCACHED_MEMORY static int initr_noncached(void) { @@ -713,7 +704,9 @@ static init_fnc_t init_sequence_r[] = { initr_malloc, log_init, initr_bootstage, /* Needs malloc() but has its own timer */ - initr_console_record, +#if defined(CONFIG_CONSOLE_RECORD) + console_record_init, +#endif #ifdef CONFIG_SYS_NONCACHED_MEMORY initr_noncached, #endif From fb504b2c082c3ecd2ec7e550ae9504175c019b3a Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:09 +0200 Subject: [PATCH 16/46] common: board_r: Drop initr_secondary_cpu wrapper Add a return value to cpu_secondary_init_r and use it directly in the post-relocation init sequence, rather than using a wrapper stub. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- arch/powerpc/cpu/mpc85xx/cpu_init.c | 4 +++- common/board_r.c | 17 ++--------------- include/init.h | 14 ++++++++++++++ 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init.c b/arch/powerpc/cpu/mpc85xx/cpu_init.c index e0f0f7ecda..e920e01b25 100644 --- a/arch/powerpc/cpu/mpc85xx/cpu_init.c +++ b/arch/powerpc/cpu/mpc85xx/cpu_init.c @@ -1028,7 +1028,7 @@ void arch_preboot_os(void) mtmsr(msr); } -void cpu_secondary_init_r(void) +int cpu_secondary_init_r(void) { #ifdef CONFIG_QE #ifdef CONFIG_U_QE @@ -1040,6 +1040,8 @@ void cpu_secondary_init_r(void) qe_init(qe_base); qe_reset(); #endif + + return 0; } #ifdef CONFIG_BOARD_LATE_INIT diff --git a/common/board_r.c b/common/board_r.c index 07c0ad363e..a291543d74 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -91,21 +91,8 @@ __weak int board_flash_wp_on(void) return 0; } -__weak void cpu_secondary_init_r(void) +__weak int cpu_secondary_init_r(void) { -} - -static int initr_secondary_cpu(void) -{ - /* - * after non-volatile devices & environment is setup and cpu code have - * another round to deal with any initialization that might require - * full access to the environment or loading of some image (firmware) - * from a non-volatile device - */ - /* TODO: maybe define this for all archs? */ - cpu_secondary_init_r(); - return 0; } @@ -801,7 +788,7 @@ static init_fnc_t init_sequence_r[] = { initr_malloc_bootparams, #endif INIT_FUNC_WATCHDOG_RESET - initr_secondary_cpu, + cpu_secondary_init_r, #if defined(CONFIG_ID_EEPROM) || defined(CONFIG_SYS_I2C_MAC_OFFSET) mac_read_from_eeprom, #endif diff --git a/include/init.h b/include/init.h index 0f48ccb57a..7cdc47cff1 100644 --- a/include/init.h +++ b/include/init.h @@ -163,6 +163,20 @@ int arch_setup_bdinfo(void); */ int setup_bdinfo(void); +/** + * cpu_secondary_init_r() - CPU-specific secondary initialization + * + * After non-volatile devices, environment and cpu code are setup, have + * another round to deal with any initialization that might require + * full access to the environment or loading of some image (firmware) + * from a non-volatile device. + * + * It is called during the generic post-relocation init sequence. + * + * Return: 0 if OK + */ +int cpu_secondary_init_r(void); + /** * init_cache_f_r() - Turn on the cache in preparation for relocation * From 7addd3c6df61e10e74acf0859f65a82f28b771f5 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:10 +0200 Subject: [PATCH 17/46] common: board_r: Drop initr_post_backlog wrapper Add a return value to post_output_backlog and use it directly in the post-relocation init sequence, rather than using a wrapper stub. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- common/board_r.c | 10 +--------- include/post.h | 11 ++++++++++- post/post.c | 4 +++- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/common/board_r.c b/common/board_r.c index a291543d74..7a06627ba9 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -206,14 +206,6 @@ static int initr_addr_map(void) } #endif -#ifdef CONFIG_POST -static int initr_post_backlog(void) -{ - post_output_backlog(); - return 0; -} -#endif - #if defined(CONFIG_SYS_INIT_RAM_LOCK) && defined(CONFIG_E500) static int initr_unlock_ram_in_cache(void) { @@ -746,7 +738,7 @@ static init_fnc_t init_sequence_r[] = { #endif INIT_FUNC_WATCHDOG_RESET #ifdef CONFIG_POST - initr_post_backlog, + post_output_backlog, #endif INIT_FUNC_WATCHDOG_RESET #if defined(CONFIG_PCI) && defined(CONFIG_SYS_EARLY_PCI_INIT) diff --git a/include/post.h b/include/post.h index eb218acde5..5695e2b533 100644 --- a/include/post.h +++ b/include/post.h @@ -107,7 +107,6 @@ int post_init_f (void); void post_bootmode_init (void); int post_bootmode_get (unsigned int * last_test); void post_bootmode_clear (void); -void post_output_backlog ( void ); int post_run (char *name, int flags); int post_info (char *name); int post_log (char *format, ...); @@ -116,6 +115,16 @@ void post_reloc (void); #endif unsigned long post_time_ms (unsigned long base); +/** + * post_output_backlog() - Print POST results + * + * Print POST results during the generic board init sequence, after + * relocation. + * + * Return: 0 if OK + */ +int post_output_backlog(void); + extern struct post_test post_list[]; extern unsigned int post_list_size; extern int post_hotkeys_pressed(void); diff --git a/post/post.c b/post/post.c index 0f1fe8d905..7d6a647312 100644 --- a/post/post.c +++ b/post/post.c @@ -128,7 +128,7 @@ static void post_log_mark_succ(unsigned long testid) } /* ... and the messages are output once we are relocated */ -void post_output_backlog(void) +int post_output_backlog(void) { int j; @@ -143,6 +143,8 @@ void post_output_backlog(void) } } } + + return 0; } static void post_bootmode_test_on(unsigned int last_test) From c343e8c0bfe5be18d766c25d9d1de3d843793109 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:11 +0200 Subject: [PATCH 18/46] common: board_r: Drop initr_pci_ep wrapper Add a return value to pci_ep_init and use it directly in the post-relocation init sequence, rather than using a wrapper stub. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- common/board_r.c | 11 +---------- drivers/pci_endpoint/pci_ep-uclass.c | 4 +++- include/init.h | 10 +++++++++- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/common/board_r.c b/common/board_r.c index 7a06627ba9..d86ff0cb5e 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -214,15 +214,6 @@ static int initr_unlock_ram_in_cache(void) } #endif -#ifdef CONFIG_PCI_ENDPOINT -static int initr_pci_ep(void) -{ - pci_ep_init(); - - return 0; -} -#endif - #ifdef CONFIG_PCI static int initr_pci(void) { @@ -836,7 +827,7 @@ static init_fnc_t init_sequence_r[] = { initr_bbmii, #endif #ifdef CONFIG_PCI_ENDPOINT - initr_pci_ep, + pci_ep_init, #endif #ifdef CONFIG_CMD_NET INIT_FUNC_WATCHDOG_RESET diff --git a/drivers/pci_endpoint/pci_ep-uclass.c b/drivers/pci_endpoint/pci_ep-uclass.c index 38a5f08376..aa89701de8 100644 --- a/drivers/pci_endpoint/pci_ep-uclass.c +++ b/drivers/pci_endpoint/pci_ep-uclass.c @@ -210,7 +210,7 @@ UCLASS_DRIVER(pci_ep) = { .flags = DM_UC_FLAG_SEQ_ALIAS, }; -void pci_ep_init(void) +int pci_ep_init(void) { struct udevice *dev; @@ -219,4 +219,6 @@ void pci_ep_init(void) uclass_next_device_check(&dev)) { ; } + + return 0; } diff --git a/include/init.h b/include/init.h index 7cdc47cff1..c6c5f34b55 100644 --- a/include/init.h +++ b/include/init.h @@ -177,6 +177,15 @@ int setup_bdinfo(void); */ int cpu_secondary_init_r(void); +/** + * pci_ep_init() - Initialize pci endpoint devices + * + * It is called during the generic post-relocation init sequence. + * + * Return: 0 if OK + */ +int pci_ep_init(void); + /** * init_cache_f_r() - Turn on the cache in preparation for relocation * @@ -249,7 +258,6 @@ int set_cpu_clk_info(void); int update_flash_size(int flash_size); int arch_early_init_r(void); void pci_init(void); -void pci_ep_init(void); int misc_init_r(void); #if defined(CONFIG_VID) int init_func_vid(void); From b9f6d0f7db9ef57f77ec3bd23a50a160534efbd8 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:12 +0200 Subject: [PATCH 19/46] common: board_r: Drop initr_pci wrapper Add a return value to pci_init and use it directly in the post-relocation init sequence, rather than using a wrapper stub. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- common/board_r.c | 18 ++++-------------- drivers/pci/pci-uclass.c | 4 +++- drivers/pci/pci.c | 6 ++++-- include/init.h | 13 ++++++++++++- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/common/board_r.c b/common/board_r.c index d86ff0cb5e..414b6272c5 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -214,16 +214,6 @@ static int initr_unlock_ram_in_cache(void) } #endif -#ifdef CONFIG_PCI -static int initr_pci(void) -{ - if (IS_ENABLED(CONFIG_PCI_INIT_R)) - pci_init(); - - return 0; -} -#endif - static int initr_barrier(void) { #ifdef CONFIG_PPC @@ -732,12 +722,12 @@ static init_fnc_t init_sequence_r[] = { post_output_backlog, #endif INIT_FUNC_WATCHDOG_RESET -#if defined(CONFIG_PCI) && defined(CONFIG_SYS_EARLY_PCI_INIT) +#if defined(CONFIG_PCI_INIT_R) && defined(CONFIG_SYS_EARLY_PCI_INIT) /* * Do early PCI configuration _before_ the flash gets initialised, * because PCU resources are crucial for flash access on some boards. */ - initr_pci, + pci_init, #endif #ifdef CONFIG_ARCH_EARLY_INIT_R arch_early_init_r, @@ -776,11 +766,11 @@ static init_fnc_t init_sequence_r[] = { mac_read_from_eeprom, #endif INIT_FUNC_WATCHDOG_RESET -#if defined(CONFIG_PCI) && !defined(CONFIG_SYS_EARLY_PCI_INIT) +#if defined(CONFIG_PCI_INIT_R) && !defined(CONFIG_SYS_EARLY_PCI_INIT) /* * Do pci configuration */ - initr_pci, + pci_init, #endif stdio_add_devices, initr_jumptable, diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 4cdd06b125..ba65f47e80 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -1842,7 +1842,7 @@ U_BOOT_DRIVER(pci_generic_drv) = { .of_match = pci_generic_ids, }; -void pci_init(void) +int pci_init(void) { struct udevice *bus; @@ -1855,4 +1855,6 @@ void pci_init(void) uclass_next_device_check(&bus)) { ; } + + return 0; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 664e8379eb..a7453e5755 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -454,16 +454,18 @@ int pci_hose_scan(struct pci_controller *hose) return pci_hose_scan_bus(hose, hose->current_busno); } -void pci_init(void) +int pci_init(void) { hose_head = NULL; /* allow env to disable pci init/enum */ if (env_get("pcidisable") != NULL) - return; + return 0; /* now call board specific pci_init()... */ pci_init_board(); + + return 0; } /* Returns the address of the requested capability structure within the diff --git a/include/init.h b/include/init.h index c6c5f34b55..dded1cb871 100644 --- a/include/init.h +++ b/include/init.h @@ -186,6 +186,18 @@ int cpu_secondary_init_r(void); */ int pci_ep_init(void); +/** + * pci_init() - Enumerate pci devices + * + * It is called during the generic post-relocation init sequence to enumerate + * pci buses. This is needed, for instance, in the case of DM PCI-based + * Ethernet devices, which will not be detected without having the enumeration + * performed earlier. + * + * Return: 0 if OK + */ +int pci_init(void); + /** * init_cache_f_r() - Turn on the cache in preparation for relocation * @@ -257,7 +269,6 @@ int mac_read_from_eeprom(void); int set_cpu_clk_info(void); int update_flash_size(int flash_size); int arch_early_init_r(void); -void pci_init(void); int misc_init_r(void); #if defined(CONFIG_VID) int init_func_vid(void); From 42d0d4223f991062f10d8b09e9268ed4cbcf271e Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:13 +0200 Subject: [PATCH 20/46] common: board_r: Drop initr_noncached wrapper Add a return value to noncached_init and use it directly in the post-relocation init sequence, rather than using a wrapper stub. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- arch/arm/include/asm/system.h | 13 ++++++++++++- arch/arm/lib/cache.c | 4 +++- common/board_r.c | 10 +--------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index ce552944b7..5fe83699f4 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -628,7 +628,18 @@ void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size, enum dcache_option option); #ifdef CONFIG_SYS_NONCACHED_MEMORY -void noncached_init(void); +/** + * noncached_init() - Initialize non-cached memory region + * + * Initialize non-cached memory area. This memory region will be typically + * located right below the malloc() area and mapped uncached in the MMU. + * + * It is called during the generic post-relocation init sequence. + * + * Return: 0 if OK + */ +int noncached_init(void); + phys_addr_t noncached_alloc(size_t size, size_t align); #endif /* CONFIG_SYS_NONCACHED_MEMORY */ diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c index ee7d14b2d3..bdde9cdad5 100644 --- a/arch/arm/lib/cache.c +++ b/arch/arm/lib/cache.c @@ -86,7 +86,7 @@ void noncached_set_region(void) #endif } -void noncached_init(void) +int noncached_init(void) { phys_addr_t start, end; size_t size; @@ -103,6 +103,8 @@ void noncached_init(void) noncached_next = start; noncached_set_region(); + + return 0; } phys_addr_t noncached_alloc(size_t size, size_t align) diff --git a/common/board_r.c b/common/board_r.c index 414b6272c5..48e898b586 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -242,14 +242,6 @@ static int initr_malloc(void) return 0; } -#ifdef CONFIG_SYS_NONCACHED_MEMORY -static int initr_noncached(void) -{ - noncached_init(); - return 0; -} -#endif - static int initr_of_live(void) { if (CONFIG_IS_ENABLED(OF_LIVE)) { @@ -668,7 +660,7 @@ static init_fnc_t init_sequence_r[] = { console_record_init, #endif #ifdef CONFIG_SYS_NONCACHED_MEMORY - initr_noncached, + noncached_init, #endif initr_of_live, #ifdef CONFIG_DM From eb2825b79d1e029fa0b9e9ff35fe08c2eca8ca17 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:14 +0200 Subject: [PATCH 21/46] common: board_r: Drop initr_xen wrapper Add a return value to xen_init and use it directly in the post-relocation init sequence, rather than using a wrapper stub. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- common/board_r.c | 10 +--------- drivers/xen/hypervisor.c | 4 +++- include/xen.h | 2 +- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/common/board_r.c b/common/board_r.c index 48e898b586..a5cbbcc343 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -428,14 +428,6 @@ static int initr_mmc(void) } #endif -#ifdef CONFIG_XEN -static int initr_xen(void) -{ - xen_init(); - return 0; -} -#endif - #ifdef CONFIG_PVBLOCK static int initr_pvblock(void) { @@ -743,7 +735,7 @@ static init_fnc_t init_sequence_r[] = { initr_mmc, #endif #ifdef CONFIG_XEN - initr_xen, + xen_init, #endif #ifdef CONFIG_PVBLOCK initr_pvblock, diff --git a/drivers/xen/hypervisor.c b/drivers/xen/hypervisor.c index 178c206f5b..2560894832 100644 --- a/drivers/xen/hypervisor.c +++ b/drivers/xen/hypervisor.c @@ -232,7 +232,7 @@ void clear_evtchn(uint32_t port) synch_clear_bit(port, &s->evtchn_pending[0]); } -void xen_init(void) +int xen_init(void) { debug("%s\n", __func__); @@ -240,6 +240,8 @@ void xen_init(void) init_events(); init_xenbus(); init_gnttab(); + + return 0; } void xen_fini(void) diff --git a/include/xen.h b/include/xen.h index a952a2c84b..868132156e 100644 --- a/include/xen.h +++ b/include/xen.h @@ -11,7 +11,7 @@ * Map Xen memory pages, initialize event handler and xenbus, * setup the grant table. */ -void xen_init(void); +int xen_init(void); /** * xen_fini() - Board cleanup before Linux kernel start From 0154858039fd6d184528ed6a294153bd7f4cd3e0 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:15 +0200 Subject: [PATCH 22/46] common: board_r: Drop initr_jumptable wrapper Add a return value to jumptable_init and use it directly in the post-relocation init sequence, rather than using a wrapper stub. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- common/board_r.c | 8 +------- common/exports.c | 4 +++- include/exports.h | 10 ++++++++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/common/board_r.c b/common/board_r.c index a5cbbcc343..32ad40d372 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -490,12 +490,6 @@ static int initr_malloc_bootparams(void) } #endif -static int initr_jumptable(void) -{ - jumptable_init(); - return 0; -} - #if defined(CONFIG_API) static int initr_api(void) { @@ -757,7 +751,7 @@ static init_fnc_t init_sequence_r[] = { pci_init, #endif stdio_add_devices, - initr_jumptable, + jumptable_init, #ifdef CONFIG_API initr_api, #endif diff --git a/common/exports.c b/common/exports.c index 6253b55694..4578f07021 100644 --- a/common/exports.c +++ b/common/exports.c @@ -25,8 +25,10 @@ unsigned long get_version(void) # define miiphy_set_current_dev dummy #endif -void jumptable_init(void) +int jumptable_init(void) { gd->jt = malloc(sizeof(struct jt_funcs)); #include <_exports.h> + + return 0; } diff --git a/include/exports.h b/include/exports.h index b300554091..faf0f59244 100644 --- a/include/exports.h +++ b/include/exports.h @@ -15,8 +15,14 @@ struct cmd_tbl; struct spi_slave; -/* Set up the jump table for use by the API */ -void jumptable_init(void); +/** + * jumptable_init() - Set up the jump table for use by the API + * + * It is called during the generic post-relocation init sequence. + * + * Return: 0 if OK + */ +int jumptable_init(void); /* These are declarations of exported functions available in C code */ unsigned long get_version(void); From ce41e735231f350722221b10bb81408f88235d1d Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:16 +0200 Subject: [PATCH 23/46] common: board_r: Drop initr_api wrapper Add a return value to api_init and use it directly in the post-relocation init sequence, rather than using a wrapper stub. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- api/api.c | 6 ++++-- api/api_private.h | 2 +- common/board_r.c | 11 +---------- include/api.h | 10 +++++++++- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/api/api.c b/api/api.c index 493b77f809..89003c161c 100644 --- a/api/api.c +++ b/api/api.c @@ -642,7 +642,7 @@ int syscall(int call, int *retval, ...) return 1; } -void api_init(void) +int api_init(void) { struct api_signature *sig; @@ -679,7 +679,7 @@ void api_init(void) sig = malloc(sizeof(struct api_signature)); if (sig == NULL) { printf("API: could not allocate memory for the signature!\n"); - return; + return -ENOMEM; } env_set_hex("api_address", (unsigned long)sig); @@ -691,6 +691,8 @@ void api_init(void) sig->checksum = crc32(0, (unsigned char *)sig, sizeof(struct api_signature)); debugf("syscall entry: 0x%lX\n", (unsigned long)sig->syscall); + + return 0; } void platform_set_mr(struct sys_info *si, unsigned long start, unsigned long size, diff --git a/api/api_private.h b/api/api_private.h index 07fd50ad3a..bb23821c2c 100644 --- a/api/api_private.h +++ b/api/api_private.h @@ -8,7 +8,7 @@ #ifndef _API_PRIVATE_H_ #define _API_PRIVATE_H_ -void api_init(void); +int api_init(void); void platform_set_mr(struct sys_info *, unsigned long, unsigned long, int); int platform_sys_info(struct sys_info *); diff --git a/common/board_r.c b/common/board_r.c index 32ad40d372..500457b080 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -490,15 +490,6 @@ static int initr_malloc_bootparams(void) } #endif -#if defined(CONFIG_API) -static int initr_api(void) -{ - /* Initialize API */ - api_init(); - return 0; -} -#endif - #ifdef CONFIG_CMD_NET static int initr_ethaddr(void) { @@ -753,7 +744,7 @@ static init_fnc_t init_sequence_r[] = { stdio_add_devices, jumptable_init, #ifdef CONFIG_API - initr_api, + api_init, #endif console_init_r, /* fully init console as a device */ #ifdef CONFIG_DISPLAY_BOARDINFO_LATE diff --git a/include/api.h b/include/api.h index 84d81dc817..83412a7c87 100644 --- a/include/api.h +++ b/include/api.h @@ -7,6 +7,14 @@ #ifndef __API_H #define __API_H -void api_init(void); +/** + * api_init() - Initialize API for external applications + * + * Initialize API for external (standalone) applications running on top of + * U-Boot. It is called during the generic post-relocation init sequence. + * + * Return: 0 if OK + */ +int api_init(void); #endif From c65abc70fb7212301b70c6ab05ba2aa22c31c69e Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:17 +0200 Subject: [PATCH 24/46] common: board_r: Drop initr_bbmii wrapper Add a return value to bb_miiphy_init and use it directly in the post-relocation init sequence, rather than using a wrapper stub. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- common/board_r.c | 10 +--------- drivers/net/phy/miiphybb.c | 4 +++- include/miiphy.h | 10 +++++++++- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/common/board_r.c b/common/board_r.c index 500457b080..c083eb0a03 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -534,14 +534,6 @@ static int initr_scsi(void) } #endif -#ifdef CONFIG_BITBANGMII -static int initr_bbmii(void) -{ - bb_miiphy_init(); - return 0; -} -#endif - #ifdef CONFIG_CMD_NET static int initr_net(void) { @@ -783,7 +775,7 @@ static init_fnc_t init_sequence_r[] = { initr_scsi, #endif #ifdef CONFIG_BITBANGMII - initr_bbmii, + bb_miiphy_init, #endif #ifdef CONFIG_PCI_ENDPOINT pci_ep_init, diff --git a/drivers/net/phy/miiphybb.c b/drivers/net/phy/miiphybb.c index ba97a54c06..59a32c4913 100644 --- a/drivers/net/phy/miiphybb.c +++ b/drivers/net/phy/miiphybb.c @@ -105,7 +105,7 @@ int bb_miiphy_buses_num = sizeof(bb_miiphy_buses) / sizeof(bb_miiphy_buses[0]); #endif -void bb_miiphy_init(void) +int bb_miiphy_init(void) { int i; @@ -124,6 +124,8 @@ void bb_miiphy_init(void) bb_miiphy_buses[i].init(&bb_miiphy_buses[i]); } } + + return 0; } static inline struct bb_miiphy_bus *bb_miiphy_getbus(const char *devname) diff --git a/include/miiphy.h b/include/miiphy.h index 61c136b114..8b77bac01e 100644 --- a/include/miiphy.h +++ b/include/miiphy.h @@ -81,7 +81,15 @@ struct bb_miiphy_bus { extern struct bb_miiphy_bus bb_miiphy_buses[]; extern int bb_miiphy_buses_num; -void bb_miiphy_init(void); +/** + * bb_miiphy_init() - Initialize bit-banged MII bus driver + * + * It is called during the generic post-relocation init sequence. + * + * Return: 0 if OK + */ +int bb_miiphy_init(void); + int bb_miiphy_read(struct mii_dev *miidev, int addr, int devad, int reg); int bb_miiphy_write(struct mii_dev *miidev, int addr, int devad, int reg, u16 value); From 130845bac11ecd542587b2d2ce2b2fe87f112f1d Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:18 +0200 Subject: [PATCH 25/46] common: board_r: Drop arch-specific ifdefs around initr_trap In order to remove the arch-specific ifdefs around initr_trap, introduce arch_initr_trap weak initcall. Implementations for ppc/m68k/mips have been moved to arch//lib/traps.c Default implementation is a nop stub. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass Reviewed-by: Daniel Schwierzeck --- arch/m68k/lib/traps.c | 9 ++++++++- arch/mips/lib/traps.c | 9 ++++++++- arch/powerpc/lib/Makefile | 1 + arch/powerpc/lib/traps.c | 19 +++++++++++++++++++ common/board_r.c | 16 ++-------------- include/init.h | 10 +++++++++- 6 files changed, 47 insertions(+), 17 deletions(-) create mode 100644 arch/powerpc/lib/traps.c diff --git a/arch/m68k/lib/traps.c b/arch/m68k/lib/traps.c index c49141f376..0c2c1a9965 100644 --- a/arch/m68k/lib/traps.c +++ b/arch/m68k/lib/traps.c @@ -40,7 +40,7 @@ void exc_handler(struct pt_regs *fp) { for(;;); } -void trap_init(ulong value) { +static void trap_init(ulong value) { unsigned long *vec = (ulong *)value; int i; @@ -59,3 +59,10 @@ void trap_init(ulong value) { setvbr(value); /* set vector base register to new table */ } + +int arch_initr_trap(void) +{ + trap_init(CONFIG_SYS_SDRAM_BASE); + + return 0; +} diff --git a/arch/mips/lib/traps.c b/arch/mips/lib/traps.c index df8b63f383..540ea48e32 100644 --- a/arch/mips/lib/traps.c +++ b/arch/mips/lib/traps.c @@ -99,7 +99,7 @@ static void set_handler(unsigned long offset, void *addr, unsigned long size) flush_cache(ebase + offset, size); } -void trap_init(ulong reloc_addr) +static void trap_init(ulong reloc_addr) { unsigned long ebase = gd->irq_sp; @@ -131,3 +131,10 @@ void trap_restore(void) clear_c0_status(ST0_BEV); execution_hazard_barrier(); } + +int arch_initr_trap(void) +{ + trap_init(CONFIG_SYS_SDRAM_BASE); + + return 0; +} diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index f61809ab05..2782740bf5 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -40,6 +40,7 @@ obj-y += interrupts.o obj-$(CONFIG_CMD_KGDB) += kgdb.o obj-y += stack.o obj-y += time.o +obj-y += traps.o endif # not minimal ifdef CONFIG_SPL_BUILD diff --git a/arch/powerpc/lib/traps.c b/arch/powerpc/lib/traps.c new file mode 100644 index 0000000000..288e377632 --- /dev/null +++ b/arch/powerpc/lib/traps.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + */ + +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +void trap_init(unsigned long reloc_addr); + +int arch_initr_trap(void) +{ + trap_init(gd->relocaddr); + + return 0; +} diff --git a/common/board_r.c b/common/board_r.c index c083eb0a03..9fa4d4b42e 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -182,20 +182,10 @@ static int initr_reloc_global_data(void) return 0; } -#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_MIPS) -static int initr_trap(void) +__weak int arch_initr_trap(void) { - /* - * Setup trap handlers - */ -#if defined(CONFIG_PPC) - trap_init(gd->relocaddr); -#else - trap_init(CONFIG_SYS_SDRAM_BASE); -#endif return 0; } -#endif #ifdef CONFIG_ADDR_MAP static int initr_addr_map(void) @@ -669,9 +659,7 @@ static init_fnc_t init_sequence_r[] = { #ifdef CONFIG_NEEDS_MANUAL_RELOC initr_manual_reloc_cmdtable, #endif -#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_MIPS) - initr_trap, -#endif + arch_initr_trap, #ifdef CONFIG_ADDR_MAP initr_addr_map, #endif diff --git a/include/init.h b/include/init.h index dded1cb871..980be27993 100644 --- a/include/init.h +++ b/include/init.h @@ -300,7 +300,15 @@ int board_early_init_r(void); /* TODO(sjg@chromium.org): Drop this when DM_PCI migration is completed */ void pci_init_board(void); -void trap_init(unsigned long reloc_addr); +/** + * arch_initr_trap() - Init traps + * + * Arch specific routine for initializing traps. It is called during the + * generic board init sequence, after relocation. + * + * Return: 0 if OK + */ +int arch_initr_trap(void); /** * main_loop() - Enter the main loop of U-Boot From 2a7c9ab47970868ac29b197cfbbbd93440b8fa20 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:19 +0200 Subject: [PATCH 26/46] spl: Kconfig: Add SPL dependency to CONFIG_HANDOFF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CONFIG_HANDOFF is used in u-boot proper to locate handoff info from SPL during pre-relocation init (in setup_spl_handoff). Add explicit dependency on CONFIG_SPL, to fix the following build error when CONFIG_HANDOFF && !CONFIG_SPL: common/board_f.c: In function ‘setup_spl_handoff’: common/board_f.c:283:4: error: ‘gd_t {aka struct global_data}’ has no member named ‘spl_handoff’ gd->spl_handoff = bloblist_find(BLOBLISTT_SPL_HANDOFF, ^~ Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- common/spl/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 6b0186763b..7561335bfd 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -126,7 +126,7 @@ endmenu config HANDOFF bool "Pass hand-off information from SPL to U-Boot proper" - depends on BLOBLIST + depends on SPL && BLOBLIST help It is useful to be able to pass information from SPL to U-Boot proper to preserve state that is known in SPL and is needed in U-Boot. From 13e0f020f7710418c4f8ed231660f91cdd979254 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sat, 28 Nov 2020 10:43:20 +0200 Subject: [PATCH 27/46] global_data: Enable spl_handoff only if CONFIG_HANDOFF is set spl_handoff should only be enabled when CONFIG_HANDOFF is set. Drop the nested ifdefs and check for CONFIG_HANDOFF instead. Signed-off-by: Ovidiu Panait Reviewed-by: Simon Glass --- include/asm-generic/global_data.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index efa09a1943..19f70393b4 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -412,12 +412,12 @@ struct global_data { * @new_bloblist: relocated blob list information */ struct bloblist_hdr *new_bloblist; -# ifdef CONFIG_SPL +#endif +#if CONFIG_IS_ENABLED(HANDOFF) /** * @spl_handoff: SPL hand-off information */ struct spl_handoff *spl_handoff; -# endif #endif #if defined(CONFIG_TRANSLATION_OFFSET) /** From c04f856822aab04c3ccb05d741e83ce3b84913fd Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 18 Dec 2020 12:46:43 +0100 Subject: [PATCH 28/46] console: remove #ifdef CONFIG when it is possible Remove #ifdef or #ifndef for CONFIG when it is possible to simplify the console.c code and respect the U-Boot coding rules. Signed-off-by: Patrick Delaunay Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass --- common/console.c | 158 +++++++++++++++++++---------------------------- 1 file changed, 64 insertions(+), 94 deletions(-) diff --git a/common/console.c b/common/console.c index c3d552bb3e..d225fdd920 100644 --- a/common/console.c +++ b/common/console.c @@ -44,14 +44,15 @@ static int on_console(const char *name, const char *value, enum env_op op, case env_op_create: case env_op_overwrite: -#if CONFIG_IS_ENABLED(CONSOLE_MUX) - if (iomux_doenv(console, value)) - return 1; -#else - /* Try assigning specified device */ - if (console_assign(console, value) < 0) - return 1; -#endif + if (CONFIG_IS_ENABLED(CONSOLE_MUX)) { + if (iomux_doenv(console, value)) + return 1; + } else { + /* Try assigning specified device */ + if (console_assign(console, value) < 0) + return 1; + } + return 0; case env_op_delete: @@ -69,14 +70,13 @@ U_BOOT_ENV_CALLBACK(console, on_console); static int on_silent(const char *name, const char *value, enum env_op op, int flags) { -#if !CONFIG_IS_ENABLED(SILENT_CONSOLE_UPDATE_ON_SET) - if (flags & H_INTERACTIVE) - return 0; -#endif -#if !CONFIG_IS_ENABLED(SILENT_CONSOLE_UPDATE_ON_RELOC) - if ((flags & H_INTERACTIVE) == 0) - return 0; -#endif + if (!CONFIG_IS_ENABLED(SILENT_CONSOLE_UPDATE_ON_SET)) + if (flags & H_INTERACTIVE) + return 0; + + if (!CONFIG_IS_ENABLED(SILENT_CONSOLE_UPDATE_ON_RELOC)) + if ((flags & H_INTERACTIVE) == 0) + return 0; if (value != NULL) gd->flags |= GD_FLG_SILENT; @@ -159,14 +159,13 @@ static bool console_dev_is_serial(struct stdio_dev *sdev) { bool is_serial; -#ifdef CONFIG_DM_SERIAL - if (sdev->flags & DEV_FLAGS_DM) { + if (IS_ENABLED(CONFIG_DM_SERIAL) && (sdev->flags & DEV_FLAGS_DM)) { struct udevice *dev = sdev->priv; is_serial = device_get_uclass_id(dev) == UCLASS_SERIAL; - } else -#endif - is_serial = !strcmp(sdev->name, "serial"); + } else { + is_serial = !strcmp(sdev->name, "serial"); + } return is_serial; } @@ -350,13 +349,12 @@ int fgetc(int file) if (console_tstc(file)) return console_getc(file); #endif -#ifdef CONFIG_WATCHDOG /* * If the watchdog must be rate-limited then it should * already be handled in board-specific code. */ - udelay(1); -#endif + if (IS_ENABLED(CONFIG_WATCHDOG)) + udelay(1); } } @@ -406,10 +404,8 @@ int fprintf(int file, const char *fmt, ...) int getchar(void) { -#ifdef CONFIG_DISABLE_CONSOLE - if (gd->flags & GD_FLG_DISABLE_CONSOLE) + if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE)) return 0; -#endif if (!gd->have_console) return 0; @@ -434,10 +430,8 @@ int getchar(void) int tstc(void) { -#ifdef CONFIG_DISABLE_CONSOLE - if (gd->flags & GD_FLG_DISABLE_CONSOLE) + if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE)) return 0; -#endif if (!gd->have_console) return 0; @@ -485,10 +479,8 @@ static void print_pre_console_buffer(int flushpoint) char buf_out[CONFIG_PRE_CON_BUF_SZ + 1]; char *buf_in; -#ifdef CONFIG_SILENT_CONSOLE - if (gd->flags & GD_FLG_SILENT) + if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT)) return; -#endif buf_in = map_sysmem(CONFIG_PRE_CON_BUF_ADDR, CONFIG_PRE_CON_BUF_SZ); if (gd->precon_buf_idx > CONFIG_PRE_CON_BUF_SZ) @@ -523,32 +515,26 @@ void putc(const char c) if ((gd->flags & GD_FLG_RECORD) && gd->console_out.start) membuff_putbyte((struct membuff *)&gd->console_out, c); #endif -#ifdef CONFIG_SANDBOX /* sandbox can send characters to stdout before it has a console */ - if (!(gd->flags & GD_FLG_SERIAL_READY)) { + if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) { os_putc(c); return; } -#endif -#ifdef CONFIG_DEBUG_UART + /* if we don't have a console yet, use the debug UART */ - if (!(gd->flags & GD_FLG_SERIAL_READY)) { + if (IS_ENABLED(CONFIG_DEBUG_UART) && !(gd->flags & GD_FLG_SERIAL_READY)) { printch(c); return; } -#endif -#ifdef CONFIG_SILENT_CONSOLE - if (gd->flags & GD_FLG_SILENT) { + + if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT)) { if (!(gd->flags & GD_FLG_DEVINIT)) pre_console_putc(c); return; } -#endif -#ifdef CONFIG_DISABLE_CONSOLE - if (gd->flags & GD_FLG_DISABLE_CONSOLE) + if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE)) return; -#endif if (!gd->have_console) return pre_console_putc(c); @@ -571,15 +557,13 @@ void puts(const char *s) if ((gd->flags & GD_FLG_RECORD) && gd->console_out.start) membuff_put((struct membuff *)&gd->console_out, s, strlen(s)); #endif -#ifdef CONFIG_SANDBOX /* sandbox can send characters to stdout before it has a console */ - if (!(gd->flags & GD_FLG_SERIAL_READY)) { + if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) { os_puts(s); return; } -#endif -#ifdef CONFIG_DEBUG_UART - if (!(gd->flags & GD_FLG_SERIAL_READY)) { + + if (IS_ENABLED(CONFIG_DEBUG_UART) && !(gd->flags & GD_FLG_SERIAL_READY)) { while (*s) { int ch = *s++; @@ -587,19 +571,15 @@ void puts(const char *s) } return; } -#endif -#ifdef CONFIG_SILENT_CONSOLE - if (gd->flags & GD_FLG_SILENT) { + + if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT)) { if (!(gd->flags & GD_FLG_DEVINIT)) pre_console_puts(s); return; } -#endif -#ifdef CONFIG_DISABLE_CONSOLE - if (gd->flags & GD_FLG_DISABLE_CONSOLE) + if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE)) return; -#endif if (!gd->have_console) return pre_console_puts(s); @@ -772,19 +752,19 @@ int console_assign(int file, const char *devname) /* return true if the 'silent' flag is removed */ static bool console_update_silent(void) { -#ifdef CONFIG_SILENT_CONSOLE + unsigned long flags = gd->flags; + + if (!IS_ENABLED(CONFIG_SILENT_CONSOLE)) + return false; + if (env_get("silent")) { gd->flags |= GD_FLG_SILENT; - } else { - unsigned long flags = gd->flags; - - gd->flags &= ~GD_FLG_SILENT; - - return !!(flags & GD_FLG_SILENT); + return false; } -#endif - return false; + gd->flags &= ~GD_FLG_SILENT; + + return !!(flags & GD_FLG_SILENT); } int console_announce_r(void) @@ -843,12 +823,8 @@ int console_init_r(void) { char *stdinname, *stdoutname, *stderrname; struct stdio_dev *inputdev = NULL, *outputdev = NULL, *errdev = NULL; -#ifdef CONFIG_SYS_CONSOLE_ENV_OVERWRITE int i; -#endif /* CONFIG_SYS_CONSOLE_ENV_OVERWRITE */ -#if CONFIG_IS_ENABLED(CONSOLE_MUX) int iomux_err = 0; -#endif int flushpoint; /* update silent for env loaded from flash (initr_env) */ @@ -874,14 +850,14 @@ int console_init_r(void) inputdev = search_device(DEV_FLAGS_INPUT, stdinname); outputdev = search_device(DEV_FLAGS_OUTPUT, stdoutname); errdev = search_device(DEV_FLAGS_OUTPUT, stderrname); -#if CONFIG_IS_ENABLED(CONSOLE_MUX) - iomux_err = iomux_doenv(stdin, stdinname); - iomux_err += iomux_doenv(stdout, stdoutname); - iomux_err += iomux_doenv(stderr, stderrname); - if (!iomux_err) - /* Successful, so skip all the code below. */ - goto done; -#endif + if (CONFIG_IS_ENABLED(CONSOLE_MUX)) { + iomux_err = iomux_doenv(stdin, stdinname); + iomux_err += iomux_doenv(stdout, stdoutname); + iomux_err += iomux_doenv(stderr, stderrname); + if (!iomux_err) + /* Successful, so skip all the code below. */ + goto done; + } } /* if the devices are overwritten or not found, use default device */ if (inputdev == NULL) { @@ -907,25 +883,22 @@ int console_init_r(void) console_doenv(stdin, inputdev); } -#if CONFIG_IS_ENABLED(CONSOLE_MUX) done: -#endif -#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET - stdio_print_current_devices(); -#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */ + if (!IS_ENABLED(CONFIG_SYS_CONSOLE_INFO_QUIET)) + stdio_print_current_devices(); + #ifdef CONFIG_VIDCONSOLE_AS_LCD if (strstr(stdoutname, CONFIG_VIDCONSOLE_AS_NAME)) printf("Warning: Please change '%s' to 'vidconsole' in stdout/stderr environment vars\n", CONFIG_VIDCONSOLE_AS_NAME); #endif -#ifdef CONFIG_SYS_CONSOLE_ENV_OVERWRITE - /* set the environment variables (will overwrite previous env settings) */ - for (i = 0; i < MAX_FILES; i++) { - env_set(stdio_names[i], stdio_devices[i]->name); + if (IS_ENABLED(CONFIG_SYS_CONSOLE_ENV_OVERWRITE)) { + /* set the environment variables (will overwrite previous env settings) */ + for (i = 0; i < MAX_FILES; i++) + env_set(stdio_names[i], stdio_devices[i]->name); } -#endif /* CONFIG_SYS_CONSOLE_ENV_OVERWRITE */ gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */ @@ -956,18 +929,16 @@ int console_init_r(void) else flushpoint = PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL; -#ifdef CONFIG_SPLASH_SCREEN /* * suppress all output if splash screen is enabled and we have * a bmp to display. We redirect the output from frame buffer * console to serial console in this case or suppress it if * "silent" mode was requested. */ - if (env_get("splashimage") != NULL) { + if (IS_ENABLED(CONFIG_SPLASH_SCREEN) && env_get("splashimage")) { if (!(gd->flags & GD_FLG_SILENT)) outputdev = search_device (DEV_FLAGS_OUTPUT, "serial"); } -#endif /* Scan devices looking for input and output devices */ list_for_each(pos, list) { @@ -1001,9 +972,8 @@ int console_init_r(void) #endif } -#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET - stdio_print_current_devices(); -#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */ + if (!IS_ENABLED(CONFIG_SYS_CONSOLE_INFO_QUIET)) + stdio_print_current_devices(); /* Setting environment variables */ for (i = 0; i < MAX_FILES; i++) { From 45375adc97990ade77137c9922e673bb68e1a675 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 18 Dec 2020 12:46:44 +0100 Subject: [PATCH 29/46] console: add function console_devices_set Add a new function to access to console_devices only defined if CONFIG_IS_ENABLED(CONSOLE_MUX). This path allows to remove #if CONFIG_IS_ENABLED(CONSOLE_MUX) in console_getc function. Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass Signed-off-by: Patrick Delaunay --- common/console.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/common/console.c b/common/console.c index d225fdd920..036dd0358a 100644 --- a/common/console.c +++ b/common/console.c @@ -177,6 +177,11 @@ static struct stdio_dev *tstcdev; struct stdio_dev **console_devices[MAX_FILES]; int cd_count[MAX_FILES]; +static void __maybe_unused console_devices_set(int file, struct stdio_dev *dev) +{ + console_devices[file][0] = dev; +} + /* * This depends on tstc() always being called before getchar(). * This is guaranteed to be true because this routine is called @@ -275,6 +280,11 @@ static inline void console_doenv(int file, struct stdio_dev *dev) } #endif #else + +static void __maybe_unused console_devices_set(int file, struct stdio_dev *dev) +{ +} + static inline int console_getc(int file) { return stdio_devices[file]->getc(stdio_devices[file]); @@ -958,18 +968,14 @@ int console_init_r(void) if (outputdev != NULL) { console_setfile(stdout, outputdev); console_setfile(stderr, outputdev); -#if CONFIG_IS_ENABLED(CONSOLE_MUX) - console_devices[stdout][0] = outputdev; - console_devices[stderr][0] = outputdev; -#endif + console_devices_set(stdout, outputdev); + console_devices_set(stderr, outputdev); } /* Initializes input console */ if (inputdev != NULL) { console_setfile(stdin, inputdev); -#if CONFIG_IS_ENABLED(CONSOLE_MUX) - console_devices[stdin][0] = inputdev; -#endif + console_devices_set(stdin, inputdev); } if (!IS_ENABLED(CONFIG_SYS_CONSOLE_INFO_QUIET)) From 1e993710e8b99510a37f91fa97d9b783c6e5f32d Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 18 Dec 2020 12:46:45 +0100 Subject: [PATCH 30/46] console: remove #ifdef CONFIG_CONSOLE_RECORD Add helper functions to access to gd->console_out and gd->console_in with membuff API and replace the #ifdef CONFIG_CONSOLE_RECORD test by if (IS_ENABLED(CONFIG_CONSOLE_RECORD)) to respect the U-Boot coding rule. Signed-off-by: Patrick Delaunay Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass --- common/console.c | 95 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 22 deletions(-) diff --git a/common/console.c b/common/console.c index 036dd0358a..295c10f242 100644 --- a/common/console.c +++ b/common/console.c @@ -88,6 +88,64 @@ static int on_silent(const char *name, const char *value, enum env_op op, U_BOOT_ENV_CALLBACK(silent, on_silent); #endif +#ifdef CONFIG_CONSOLE_RECORD +/* helper function: access to gd->console_out and gd->console_in */ +static void console_record_putc(const char c) +{ + if (!(gd->flags & GD_FLG_RECORD)) + return; + if (gd->console_out.start) + membuff_putbyte((struct membuff *)&gd->console_out, c); +} + +static void console_record_puts(const char *s) +{ + if (!(gd->flags & GD_FLG_RECORD)) + return; + if (gd->console_out.start) + membuff_put((struct membuff *)&gd->console_out, s, strlen(s)); +} + +static int console_record_getc(void) +{ + if (!(gd->flags & GD_FLG_RECORD)) + return -1; + if (!gd->console_in.start) + return -1; + + return membuff_getbyte((struct membuff *)&gd->console_in); +} + +static int console_record_tstc(void) +{ + if (!(gd->flags & GD_FLG_RECORD)) + return 0; + if (gd->console_in.start) { + if (membuff_peekbyte((struct membuff *)&gd->console_in) != -1) + return 1; + } + return 0; +} +#else +static void console_record_putc(char c) +{ +} + +static void console_record_puts(const char *s) +{ +} + +static int console_record_getc(void) +{ + return -1; +} + +static int console_record_tstc(void) +{ + return 0; +} +#endif + #if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV) /* * if overwrite_console returns 1, the stdin, stderr and stdout @@ -414,21 +472,18 @@ int fprintf(int file, const char *fmt, ...) int getchar(void) { + int ch; + if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE)) return 0; if (!gd->have_console) return 0; -#ifdef CONFIG_CONSOLE_RECORD - if (gd->console_in.start) { - int ch; + ch = console_record_getc(); + if (ch != -1) + return ch; - ch = membuff_getbyte((struct membuff *)&gd->console_in); - if (ch != -1) - return 1; - } -#endif if (gd->flags & GD_FLG_DEVINIT) { /* Get from the standard input */ return fgetc(stdin); @@ -445,12 +500,10 @@ int tstc(void) if (!gd->have_console) return 0; -#ifdef CONFIG_CONSOLE_RECORD - if (gd->console_in.start) { - if (membuff_peekbyte((struct membuff *)&gd->console_in) != -1) - return 1; - } -#endif + + if (console_record_tstc()) + return 1; + if (gd->flags & GD_FLG_DEVINIT) { /* Test the standard input */ return ftstc(stdin); @@ -521,10 +574,9 @@ void putc(const char c) { if (!gd) return; -#ifdef CONFIG_CONSOLE_RECORD - if ((gd->flags & GD_FLG_RECORD) && gd->console_out.start) - membuff_putbyte((struct membuff *)&gd->console_out, c); -#endif + + console_record_putc(c); + /* sandbox can send characters to stdout before it has a console */ if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) { os_putc(c); @@ -563,10 +615,9 @@ void puts(const char *s) { if (!gd) return; -#ifdef CONFIG_CONSOLE_RECORD - if ((gd->flags & GD_FLG_RECORD) && gd->console_out.start) - membuff_put((struct membuff *)&gd->console_out, s, strlen(s)); -#endif + + console_record_puts(s); + /* sandbox can send characters to stdout before it has a console */ if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) { os_puts(s); From a17b38ce3902e46777322f6ec26e51b25415fa5b Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 18 Dec 2020 12:46:46 +0100 Subject: [PATCH 31/46] console: add console_has_tstc helper function for CONSOLE_MUX Add the helper function console_has_tstc() and replace the test #if CONFIG_IS_ENABLED(CONSOLE_MUX) to a simple 'if' test to respect the U-Boot coding rule. No functional change. Signed-off-by: Patrick Delaunay Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass --- common/console.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/common/console.c b/common/console.c index 295c10f242..e82b5d2075 100644 --- a/common/console.c +++ b/common/console.c @@ -231,6 +231,7 @@ static bool console_dev_is_serial(struct stdio_dev *sdev) #if CONFIG_IS_ENABLED(CONSOLE_MUX) /** Console I/O multiplexing *******************************************/ +/* tstcdev: save the last stdio device with pending characters, with tstc != 0 */ static struct stdio_dev *tstcdev; struct stdio_dev **console_devices[MAX_FILES]; int cd_count[MAX_FILES]; @@ -256,6 +257,12 @@ static int console_getc(int file) return ret; } +/* Upper layer may have already called tstc(): check the saved result */ +static bool console_has_tstc(void) +{ + return !!tstcdev; +} + static int console_tstc(int file) { int i, ret; @@ -348,6 +355,11 @@ static inline int console_getc(int file) return stdio_devices[file]->getc(stdio_devices[file]); } +static bool console_has_tstc(void) +{ + return false; +} + static inline int console_tstc(int file) { return stdio_devices[file]->tstc(stdio_devices[file]); @@ -405,18 +417,19 @@ int fgetc(int file) */ for (;;) { WATCHDOG_RESET(); -#if CONFIG_IS_ENABLED(CONSOLE_MUX) - /* - * Upper layer may have already called tstc() so - * check for that first. - */ - if (tstcdev != NULL) - return console_getc(file); - console_tstc(file); -#else - if (console_tstc(file)) - return console_getc(file); -#endif + if (CONFIG_IS_ENABLED(CONSOLE_MUX)) { + /* + * Upper layer may have already called tstc() so + * check for that first. + */ + if (console_has_tstc()) + return console_getc(file); + console_tstc(file); + } else { + if (console_tstc(file)) + return console_getc(file); + } + /* * If the watchdog must be rate-limited then it should * already be handled in board-specific code. From 41f668b97c7ac8d519f15961b67fc52817115701 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Dec 2020 14:30:00 +0200 Subject: [PATCH 32/46] console: Introduce console_start() and console_stop() In the future we would like to stop unused consoles and also add a reference counting to avoid imbalanced calls to ->start() and ->stop() in some cases. Signed-off-by: Andy Shevchenko Reviewed-by: Simon Glass --- common/console.c | 30 +++++++++++++++++++++++------- include/console.h | 3 +++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/common/console.c b/common/console.c index e82b5d2075..5b113da9d5 100644 --- a/common/console.c +++ b/common/console.c @@ -172,13 +172,9 @@ static int console_setfile(int file, struct stdio_dev * dev) case stdin: case stdout: case stderr: - /* Start new device */ - if (dev->start) { - error = dev->start(dev); - /* If it's not started dont use it */ - if (error < 0) - break; - } + error = console_start(file, dev); + if (error) + break; /* Assign the new device (leaving the existing one started) */ stdio_devices[file] = dev; @@ -389,6 +385,26 @@ static inline void console_doenv(int file, struct stdio_dev *dev) #endif #endif /* CONIFIG_IS_ENABLED(CONSOLE_MUX) */ +int console_start(int file, struct stdio_dev *sdev) +{ + int error; + + /* Start new device */ + if (sdev->start) { + error = sdev->start(sdev); + /* If it's not started don't use it */ + if (error < 0) + return error; + } + return 0; +} + +void console_stop(int file, struct stdio_dev *sdev) +{ + if (sdev->stop) + sdev->stop(sdev); +} + /** U-Boot INITIAL CONSOLE-NOT COMPATIBLE FUNCTIONS *************************/ int serial_printf(const char *fmt, ...) diff --git a/include/console.h b/include/console.h index 432f892b6c..58a4ec3f12 100644 --- a/include/console.h +++ b/include/console.h @@ -8,6 +8,7 @@ #define __CONSOLE_H #include +#include #include extern char console_buffer[]; @@ -15,6 +16,8 @@ extern char console_buffer[]; /* common/console.c */ int console_init_f(void); /* Before relocation; uses the serial stuff */ int console_init_r(void); /* After relocation; uses the console stuff */ +int console_start(int file, struct stdio_dev *sdev); /* Start a console device */ +void console_stop(int file, struct stdio_dev *sdev); /* Stop a console device */ int console_assign(int file, const char *devname); /* Assign the console */ int ctrlc(void); int had_ctrlc(void); /* have we had a Control-C since last clear? */ From 95aaf40254b44d614dc2eaca89b31f98598e4f27 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Dec 2020 14:30:01 +0200 Subject: [PATCH 33/46] console: Keep ->start() and ->stop() balanced There is no need to call ->start() for already started device. All the same, there is no need to call ->stop() for devices still in use. For now enforce this only for IOMUX case. Cc: Simon Glass Signed-off-by: Andy Shevchenko Reviewed-by: Simon Glass --- common/console.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/common/console.c b/common/console.c index 5b113da9d5..92e9bc0ec1 100644 --- a/common/console.c +++ b/common/console.c @@ -237,6 +237,32 @@ static void __maybe_unused console_devices_set(int file, struct stdio_dev *dev) console_devices[file][0] = dev; } +/** + * console_needs_start_stop() - check if we need to start or stop the STDIO device + * @file: STDIO file + * @sdev: STDIO device in question + * + * This function checks if we need to start or stop the stdio device used for + * a console. For IOMUX case it simply enforces one time start and one time + * stop of the device independently of how many STDIO files are using it. In + * other words, we start console once before first STDIO device wants it and + * stop after the last is gone. + */ +static bool console_needs_start_stop(int file, struct stdio_dev *sdev) +{ + int i, j; + + for (i = 0; i < ARRAY_SIZE(cd_count); i++) { + if (i == file) + continue; + + for (j = 0; j < cd_count[i]; j++) + if (console_devices[i][j] == sdev) + return false; + } + return true; +} + /* * This depends on tstc() always being called before getchar(). * This is guaranteed to be true because this routine is called @@ -346,6 +372,11 @@ static void __maybe_unused console_devices_set(int file, struct stdio_dev *dev) { } +static inline bool console_needs_start_stop(int file, struct stdio_dev *sdev) +{ + return true; +} + static inline int console_getc(int file) { return stdio_devices[file]->getc(stdio_devices[file]); @@ -389,6 +420,9 @@ int console_start(int file, struct stdio_dev *sdev) { int error; + if (!console_needs_start_stop(file, sdev)) + return 0; + /* Start new device */ if (sdev->start) { error = sdev->start(sdev); @@ -401,6 +435,9 @@ int console_start(int file, struct stdio_dev *sdev) void console_stop(int file, struct stdio_dev *sdev) { + if (!console_needs_start_stop(file, sdev)) + return; + if (sdev->stop) sdev->stop(sdev); } From e645b9bd8d07b87a59990fe0b542ce7bdc224b59 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Dec 2020 14:30:02 +0200 Subject: [PATCH 34/46] console: move search_device() from iomux.h to console.h search_device() is defined in console.c. Move its declaration to an appropriate header file. Signed-off-by: Andy Shevchenko Reviewed-by: Simon Glass --- include/console.h | 2 ++ include/iomux.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/console.h b/include/console.h index 58a4ec3f12..4e06b13736 100644 --- a/include/console.h +++ b/include/console.h @@ -25,6 +25,8 @@ void clear_ctrlc(void); /* clear the Control-C condition */ int disable_ctrlc(int); /* 1 to disable, 0 to enable Control-C detect */ int confirm_yesno(void); /* 1 if input is "y", "Y", "yes" or "YES" */ +struct stdio_dev *search_device(int flags, const char *name); + #ifdef CONFIG_CONSOLE_RECORD /** * console_record_init() - set up the console recording buffers diff --git a/include/iomux.h b/include/iomux.h index e6e1097db5..da7ff697d2 100644 --- a/include/iomux.h +++ b/include/iomux.h @@ -26,6 +26,5 @@ extern int cd_count[MAX_FILES]; int iomux_doenv(const int, const char *); void iomux_printdevs(const int); -struct stdio_dev *search_device(int, const char *); #endif /* _IO_MUX_H */ From 3232487daf7ca7c50ec7c964c66db56d591725a2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Dec 2020 14:30:03 +0200 Subject: [PATCH 35/46] console: rename search_device() to console_search_dev() Rename search_device() to console_search_dev() since it's in console.h. Suggested-by: Simon Glass Signed-off-by: Andy Shevchenko Reviewed-by: Simon Glass --- common/console.c | 18 +++++++++--------- common/iomux.c | 4 ++-- common/stdio.c | 4 ++-- include/console.h | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/common/console.c b/common/console.c index 92e9bc0ec1..b15f732ccb 100644 --- a/common/console.c +++ b/common/console.c @@ -832,7 +832,7 @@ void clear_ctrlc(void) /** U-Boot INIT FUNCTIONS *************************************************/ -struct stdio_dev *search_device(int flags, const char *name) +struct stdio_dev *console_search_dev(int flags, const char *name) { struct stdio_dev *dev; @@ -868,7 +868,7 @@ int console_assign(int file, const char *devname) /* Check for valid device name */ - dev = search_device(flag, devname); + dev = console_search_dev(flag, devname); if (dev) return console_setfile(file, dev); @@ -974,9 +974,9 @@ int console_init_r(void) stderrname = env_get("stderr"); if (OVERWRITE_CONSOLE == 0) { /* if not overwritten by config switch */ - inputdev = search_device(DEV_FLAGS_INPUT, stdinname); - outputdev = search_device(DEV_FLAGS_OUTPUT, stdoutname); - errdev = search_device(DEV_FLAGS_OUTPUT, stderrname); + inputdev = console_search_dev(DEV_FLAGS_INPUT, stdinname); + outputdev = console_search_dev(DEV_FLAGS_OUTPUT, stdoutname); + errdev = console_search_dev(DEV_FLAGS_OUTPUT, stderrname); if (CONFIG_IS_ENABLED(CONSOLE_MUX)) { iomux_err = iomux_doenv(stdin, stdinname); iomux_err += iomux_doenv(stdout, stdoutname); @@ -988,13 +988,13 @@ int console_init_r(void) } /* if the devices are overwritten or not found, use default device */ if (inputdev == NULL) { - inputdev = search_device(DEV_FLAGS_INPUT, "serial"); + inputdev = console_search_dev(DEV_FLAGS_INPUT, "serial"); } if (outputdev == NULL) { - outputdev = search_device(DEV_FLAGS_OUTPUT, "serial"); + outputdev = console_search_dev(DEV_FLAGS_OUTPUT, "serial"); } if (errdev == NULL) { - errdev = search_device(DEV_FLAGS_OUTPUT, "serial"); + errdev = console_search_dev(DEV_FLAGS_OUTPUT, "serial"); } /* Initializes output console first */ if (outputdev != NULL) { @@ -1064,7 +1064,7 @@ int console_init_r(void) */ if (IS_ENABLED(CONFIG_SPLASH_SCREEN) && env_get("splashimage")) { if (!(gd->flags & GD_FLG_SILENT)) - outputdev = search_device (DEV_FLAGS_OUTPUT, "serial"); + outputdev = console_search_dev (DEV_FLAGS_OUTPUT, "serial"); } /* Scan devices looking for input and output devices */ diff --git a/common/iomux.c b/common/iomux.c index 7cfd9f2e91..e1bd1b48cd 100644 --- a/common/iomux.c +++ b/common/iomux.c @@ -95,10 +95,10 @@ int iomux_doenv(const int console, const char *arg) for (j = 0; j < i; j++) { /* * Check whether the device exists and is valid. - * console_assign() also calls search_device(), + * console_assign() also calls console_search_dev(), * but I need the pointer to the device. */ - dev = search_device(io_flag, start[j]); + dev = console_search_dev(io_flag, start[j]); if (dev == NULL) continue; /* diff --git a/common/stdio.c b/common/stdio.c index a15f30804b..abf9b1e915 100644 --- a/common/stdio.c +++ b/common/stdio.c @@ -181,7 +181,7 @@ struct stdio_dev *stdio_get_by_name(const char *name) * 'stdout', which may include a list of devices separate by * commas. Obviously this is not going to work, so we ignore * that case. The call path in that case is - * console_init_r() -> search_device() -> stdio_get_by_name() + * console_init_r() -> console_search_dev() -> stdio_get_by_name() */ if (!strncmp(name, "vidconsole", 10) && !strchr(name, ',') && !stdio_probe_device(name, UCLASS_VIDEO, &sdev)) @@ -332,7 +332,7 @@ int stdio_add_devices(void) /* * If the console setting is not in environment variables then * console_init_r() will not be calling iomux_doenv() (which - * calls search_device()). So we will not dynamically add + * calls console_search_dev()). So we will not dynamically add * devices by calling stdio_probe_device(). * * So just probe all video devices now so that whichever one is diff --git a/include/console.h b/include/console.h index 4e06b13736..bb186e7be0 100644 --- a/include/console.h +++ b/include/console.h @@ -25,7 +25,7 @@ void clear_ctrlc(void); /* clear the Control-C condition */ int disable_ctrlc(int); /* 1 to disable, 0 to enable Control-C detect */ int confirm_yesno(void); /* 1 if input is "y", "Y", "yes" or "YES" */ -struct stdio_dev *search_device(int flags, const char *name); +struct stdio_dev *console_search_dev(int flags, const char *name); #ifdef CONFIG_CONSOLE_RECORD /** From ae69738d3b311d285db83fde37c0eaa2b7b6c2b4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Dec 2020 14:30:04 +0200 Subject: [PATCH 36/46] console: Provide a documentation for console_search_dev() Provide a documentation for console_search_dev(). Suggested-by: Simon Glass Signed-off-by: Andy Shevchenko --- include/console.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/console.h b/include/console.h index bb186e7be0..7e628c0cf8 100644 --- a/include/console.h +++ b/include/console.h @@ -25,6 +25,16 @@ void clear_ctrlc(void); /* clear the Control-C condition */ int disable_ctrlc(int); /* 1 to disable, 0 to enable Control-C detect */ int confirm_yesno(void); /* 1 if input is "y", "Y", "yes" or "YES" */ +/** + * console_search_dev() - search for stdio device with given flags and name + * @flags: device flags as per input/output/system + * @name: device name + * + * Iterates over registered STDIO devices and match them with given @flags + * and @name. + * + * @return pointer to the &struct stdio_dev if found, or NULL otherwise + */ struct stdio_dev *console_search_dev(int flags, const char *name); #ifdef CONFIG_CONSOLE_RECORD From 1f8e6985db8e1eb25a8644102216c9cd5174b7a3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Dec 2020 14:30:05 +0200 Subject: [PATCH 37/46] IOMUX: Preserve console list if realloc() fails It's realloc() 101 to avoid `foo = realloc(foo, ...);` call due to getting a memory leak. Actually it's not clear why realloc() has been used here. If we shrink the array, the memcpy() overwrites it anyway with the contents of a new array. If it becomes bigger, same story. Drop useless realloc() for good and thus preserve console list in case of failed allocation. Fixes: 16a28ef219c2 ("IOMUX: Add console multiplexing support.") Signed-off-by: Andy Shevchenko Reviewed-by: Simon Glass --- common/iomux.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/common/iomux.c b/common/iomux.c index e1bd1b48cd..7b7b063cfc 100644 --- a/common/iomux.c +++ b/common/iomux.c @@ -129,19 +129,10 @@ int iomux_doenv(const int console, const char *arg) return 1; } else { /* Works even if console_devices[console] is NULL. */ - console_devices[console] = - (struct stdio_dev **)realloc(console_devices[console], - cs_idx * sizeof(struct stdio_dev *)); - if (console_devices[console] == NULL) { - free(cons_set); - return 1; - } - memcpy(console_devices[console], cons_set, cs_idx * - sizeof(struct stdio_dev *)); - + free(console_devices[console]); + console_devices[console] = cons_set; cd_count[console] = cs_idx; } - free(cons_set); return 0; } #endif /* CONSOLE_MUX */ From c939e1ca5d952cad05f4aa14135cba2b1b1947e0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Dec 2020 14:30:06 +0200 Subject: [PATCH 38/46] IOMUX: Refactor iomux_doenv() in order to increase readability Refactor iomux_doenv() a bit in order to increase readability. There is no change in code generation on x86. Signed-off-by: Andy Shevchenko Reviewed-by: Simon Glass --- common/iomux.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/common/iomux.c b/common/iomux.c index 7b7b063cfc..7991235d11 100644 --- a/common/iomux.c +++ b/common/iomux.c @@ -45,15 +45,14 @@ int iomux_doenv(const int console, const char *arg) i = 0; temp = console_args; for (;;) { - temp = strchr(temp, ','); - if (temp != NULL) { - i++; - temp++; - continue; - } /* There's always one entry more than the number of commas. */ i++; - break; + + temp = strchr(temp, ','); + if (temp == NULL) + break; + + temp++; } start = (char **)malloc(i * sizeof(char *)); if (start == NULL) { From 420782c45b992c55201ee43426dcae2ffd9807a4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Dec 2020 14:30:07 +0200 Subject: [PATCH 39/46] IOMUX: Drop indentation level by removing redundant 'else' Obviously the following has unnecessary indentation level in 'else' branch. if (foo) { ... return; } else { ... } Drop indentation level by removing redundant 'else'. Signed-off-by: Andy Shevchenko Reviewed-by: Simon Glass --- common/iomux.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/common/iomux.c b/common/iomux.c index 7991235d11..126d92ce85 100644 --- a/common/iomux.c +++ b/common/iomux.c @@ -126,12 +126,12 @@ int iomux_doenv(const int console, const char *arg) if (cs_idx == 0) { free(cons_set); return 1; - } else { - /* Works even if console_devices[console] is NULL. */ - free(console_devices[console]); - console_devices[console] = cons_set; - cd_count[console] = cs_idx; } + + /* Works even if console_devices[console] is NULL. */ + free(console_devices[console]); + console_devices[console] = cons_set; + cd_count[console] = cs_idx; return 0; } #endif /* CONSOLE_MUX */ From 70c2525c0d3c5b459ba5a438b23056be648a5249 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Dec 2020 14:30:08 +0200 Subject: [PATCH 40/46] IOMUX: Stop dropped consoles When at some point environment shrinks we need to stop dropped devices. Signed-off-by: Andy Shevchenko Reviewed-by: Simon Glass --- common/iomux.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/common/iomux.c b/common/iomux.c index 126d92ce85..15bf533885 100644 --- a/common/iomux.c +++ b/common/iomux.c @@ -27,8 +27,8 @@ int iomux_doenv(const int console, const char *arg) { char *console_args, *temp, **start; int i, j, k, io_flag, cs_idx, repeat; + struct stdio_dev **cons_set, **old_set; struct stdio_dev *dev; - struct stdio_dev **cons_set; console_args = strdup(arg); if (console_args == NULL) @@ -128,10 +128,23 @@ int iomux_doenv(const int console, const char *arg) return 1; } - /* Works even if console_devices[console] is NULL. */ - free(console_devices[console]); + old_set = console_devices[console]; + repeat = cd_count[console]; + console_devices[console] = cons_set; cd_count[console] = cs_idx; + + /* Stop dropped consoles */ + for (i = 0; i < repeat; i++) { + for (j = 0; j < cs_idx; j++) { + if (old_set[i] == cons_set[j]) + break; + } + if (j == cs_idx) + console_stop(console, old_set[i]); + } + + free(old_set); return 0; } #endif /* CONSOLE_MUX */ From 92f1c89d0a90ee39fce53ca6054223bf6b422cfb Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 23 Dec 2020 13:55:10 +0100 Subject: [PATCH 41/46] disk: dos: rename write_mbr_partition to write_mbr_sector write_mbr_partition() function name is a bit misleading, so rename it to write_mbr_sector(). This is a preparation for adding code for writing a complete MBR partition layout. Signed-off-by: Marek Szyprowski --- disk/part_dos.c | 2 +- drivers/fastboot/fb_mmc.c | 2 +- include/part.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/disk/part_dos.c b/disk/part_dos.c index 04f53106f7..ef706fb59c 100644 --- a/disk/part_dos.c +++ b/disk/part_dos.c @@ -329,7 +329,7 @@ int is_valid_dos_buf(void *buf) return test_block_type(buf) == DOS_MBR ? 0 : -1; } -int write_mbr_partition(struct blk_desc *dev_desc, void *buf) +int write_mbr_sector(struct blk_desc *dev_desc, void *buf) { if (is_valid_dos_buf(buf)) return -1; diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c index ae8e8e512f..4e26cef941 100644 --- a/drivers/fastboot/fb_mmc.c +++ b/drivers/fastboot/fb_mmc.c @@ -508,7 +508,7 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer, fastboot_fail("invalid MBR partition", response); return; } - if (write_mbr_partition(dev_desc, download_buffer)) { + if (write_mbr_sector(dev_desc, download_buffer)) { printf("%s: writing MBR partition failed\n", __func__); fastboot_fail("writing MBR partition failed", response); diff --git a/include/part.h b/include/part.h index 55be724d20..67b8b2a5cc 100644 --- a/include/part.h +++ b/include/part.h @@ -465,14 +465,14 @@ int get_disk_guid(struct blk_desc *dev_desc, char *guid); int is_valid_dos_buf(void *buf); /** - * write_mbr_partition() - write DOS MBR + * write_mbr_sector() - write DOS MBR * * @param dev_desc - block device descriptor * @param buf - buffer which contains the MBR * * @return - '0' on success, otherwise error */ -int write_mbr_partition(struct blk_desc *dev_desc, void *buf); +int write_mbr_sector(struct blk_desc *dev_desc, void *buf); #endif From 80bd05f27fb4e26e765cfb5bde43166a48c218e1 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 23 Dec 2020 13:55:11 +0100 Subject: [PATCH 42/46] disk: dos: add some defines for the hardcoded numbers Add some handy defines for some hardcoded magic numbers related to extended partition handling. Signed-off-by: Marek Szyprowski --- disk/part_dos.c | 6 +++--- disk/part_dos.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/disk/part_dos.c b/disk/part_dos.c index ef706fb59c..20d35dc9cd 100644 --- a/disk/part_dos.c +++ b/disk/part_dos.c @@ -42,9 +42,9 @@ static inline unsigned int le32_to_int(unsigned char *le32) static inline int is_extended(int part_type) { - return (part_type == 0x5 || - part_type == 0xf || - part_type == 0x85); + return (part_type == DOS_PART_TYPE_EXTENDED || + part_type == DOS_PART_TYPE_EXTENDED_LBA || + part_type == DOS_PART_TYPE_EXTENDED_LINUX); } static int get_bootable(dos_partition_t *p) diff --git a/disk/part_dos.h b/disk/part_dos.h index 434b021ae8..dd909a9317 100644 --- a/disk/part_dos.h +++ b/disk/part_dos.h @@ -15,6 +15,9 @@ #define DOS_PBR_MEDIA_TYPE_OFFSET 0x15 #define DOS_MBR 0 #define DOS_PBR 1 +#define DOS_PART_TYPE_EXTENDED 0x05 +#define DOS_PART_TYPE_EXTENDED_LBA 0x0F +#define DOS_PART_TYPE_EXTENDED_LINUX 0x85 typedef struct dos_partition { unsigned char boot_ind; /* 0x80 - active */ From 97163dd1ac5bff3823106ee33c3f34177e3c82d7 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 23 Dec 2020 13:55:12 +0100 Subject: [PATCH 43/46] disk: dos: use generic macro for unaligned le32 access Use a generic helper for reading LE32 integers. Signed-off-by: Marek Szyprowski --- disk/part_dos.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/disk/part_dos.c b/disk/part_dos.c index 20d35dc9cd..3b79b9b1b8 100644 --- a/disk/part_dos.c +++ b/disk/part_dos.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "part_dos.h" #include @@ -29,17 +30,6 @@ * to use large numbers of partitions */ #define MAX_EXT_PARTS 256 -/* Convert char[4] in little endian format to the host format integer - */ -static inline unsigned int le32_to_int(unsigned char *le32) -{ - return ((le32[3] << 24) + - (le32[2] << 16) + - (le32[1] << 8) + - le32[0] - ); -} - static inline int is_extended(int part_type) { return (part_type == DOS_PART_TYPE_EXTENDED || @@ -61,8 +51,8 @@ static int get_bootable(dos_partition_t *p) static void print_one_part(dos_partition_t *p, lbaint_t ext_part_sector, int part_num, unsigned int disksig) { - lbaint_t lba_start = ext_part_sector + le32_to_int (p->start4); - lbaint_t lba_size = le32_to_int (p->size4); + lbaint_t lba_start = ext_part_sector + get_unaligned_le32(p->start4); + lbaint_t lba_size = get_unaligned_le32(p->size4); printf("%3d\t%-10" LBAFlength "u\t%-10" LBAFlength "u\t%08x-%02x\t%02x%s%s\n", @@ -171,7 +161,7 @@ static void print_partition_extended(struct blk_desc *dev_desc, } if (!ext_part_sector) - disksig = le32_to_int(&buffer[DOS_PART_DISKSIG_OFFSET]); + disksig = get_unaligned_le32(&buffer[DOS_PART_DISKSIG_OFFSET]); /* Print all primary/logical partitions */ pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET); @@ -198,7 +188,7 @@ static void print_partition_extended(struct blk_desc *dev_desc, for (i = 0; i < 4; i++, pt++) { if (is_extended (pt->sys_ind)) { lbaint_t lba_start - = le32_to_int (pt->start4) + relative; + = get_unaligned_le32 (pt->start4) + relative; print_partition_extended(dev_desc, lba_start, ext_part_sector == 0 ? lba_start : relative, @@ -244,7 +234,7 @@ static int part_get_info_extended(struct blk_desc *dev_desc, #if CONFIG_IS_ENABLED(PARTITION_UUIDS) if (!ext_part_sector) - disksig = le32_to_int(&buffer[DOS_PART_DISKSIG_OFFSET]); + disksig = get_unaligned_le32(&buffer[DOS_PART_DISKSIG_OFFSET]); #endif /* Print all primary/logical partitions */ @@ -260,8 +250,8 @@ static int part_get_info_extended(struct blk_desc *dev_desc, (ext_part_sector == 0 || is_extended(pt->sys_ind) == 0)) { info->blksz = DOS_PART_DEFAULT_SECTOR; info->start = (lbaint_t)(ext_part_sector + - le32_to_int(pt->start4)); - info->size = (lbaint_t)le32_to_int(pt->size4); + get_unaligned_le32(pt->start4)); + info->size = (lbaint_t)get_unaligned_le32(pt->size4); part_set_generic_name(dev_desc, part_num, (char *)info->name); /* sprintf(info->type, "%d, pt->sys_ind); */ @@ -286,7 +276,7 @@ static int part_get_info_extended(struct blk_desc *dev_desc, for (i = 0; i < 4; i++, pt++) { if (is_extended (pt->sys_ind)) { lbaint_t lba_start - = le32_to_int (pt->start4) + relative; + = get_unaligned_le32 (pt->start4) + relative; return part_get_info_extended(dev_desc, lba_start, ext_part_sector == 0 ? lba_start : relative, From cb571f91c642af68a807a2f24e6146e8b77f5f93 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 23 Dec 2020 13:55:13 +0100 Subject: [PATCH 44/46] disk: dos: make some functions static Make functions not used outside this file static. Signed-off-by: Marek Szyprowski [trini: Use __maybe_unused as there are cases they may not be used] Signed-off-by: Tom Rini --- disk/part_dos.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/disk/part_dos.c b/disk/part_dos.c index 3b79b9b1b8..c9c9c5fc28 100644 --- a/disk/part_dos.c +++ b/disk/part_dos.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "part_dos.h" #include @@ -302,13 +303,13 @@ static int part_get_info_extended(struct blk_desc *dev_desc, return -1; } -void part_print_dos(struct blk_desc *dev_desc) +static void __maybe_unused part_print_dos(struct blk_desc *dev_desc) { printf("Part\tStart Sector\tNum Sectors\tUUID\t\tType\n"); print_partition_extended(dev_desc, 0, 0, 1, 0); } -int part_get_info_dos(struct blk_desc *dev_desc, int part, +static int __maybe_unused part_get_info_dos(struct blk_desc *dev_desc, int part, struct disk_partition *info) { return part_get_info_extended(dev_desc, 0, 0, 1, part, info, 0); From 20bd5ac6e43124a7632a03cf8e47dba684fa2fc4 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 23 Dec 2020 13:55:14 +0100 Subject: [PATCH 45/46] disk: dos: add code for creating MBR partition layout Add a code for creating and writing MBR partition layout. The code generates similar layout of EBRs (Exteneded Block Records) and logical volumes as Linux's fdisk utility. Signed-off-by: Marek Szyprowski --- disk/part_dos.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++ disk/part_dos.h | 2 + include/part.h | 5 ++ 3 files changed, 174 insertions(+) diff --git a/disk/part_dos.c b/disk/part_dos.c index c9c9c5fc28..f431925745 100644 --- a/disk/part_dos.c +++ b/disk/part_dos.c @@ -320,6 +320,173 @@ int is_valid_dos_buf(void *buf) return test_block_type(buf) == DOS_MBR ? 0 : -1; } +#if CONFIG_IS_ENABLED(CMD_MBR) +static void lba_to_chs(lbaint_t lba, unsigned char *rc, unsigned char *rh, + unsigned char *rs) +{ + unsigned int c, h, s; + /* use fixed CHS geometry */ + unsigned int sectpertrack = 63; + unsigned int heads = 255; + + c = (lba + 1) / sectpertrack / heads; + h = (lba + 1) / sectpertrack - c * heads; + s = (lba + 1) - (c * heads + h) * sectpertrack; + + if (c > 1023) { + c = 1023; + h = 254; + s = 63; + } + + *rc = c & 0xff; + *rh = h; + *rs = s + ((c & 0x300) >> 2); +} + +static void mbr_fill_pt_entry(dos_partition_t *pt, lbaint_t start, + lbaint_t relative, lbaint_t size, uchar sys_ind, bool bootable) +{ + pt->boot_ind = bootable ? 0x80 : 0x00; + pt->sys_ind = sys_ind; + lba_to_chs(start, &pt->cyl, &pt->head, &pt->sector); + lba_to_chs(start + size - 1, &pt->end_cyl, &pt->end_head, &pt->end_sector); + put_unaligned_le32(relative, &pt->start4); + put_unaligned_le32(size, &pt->size4); +} + +int write_mbr_partitions(struct blk_desc *dev, + struct disk_partition *p, int count, unsigned int disksig) +{ + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev->blksz); + lbaint_t ext_part_start = 0, ext_part_size = 0, ext_part_sect = 0; + dos_partition_t *pt; + int i; + + memset(buffer, 0, dev->blksz); + buffer[DOS_PART_MAGIC_OFFSET] = 0x55; + buffer[DOS_PART_MAGIC_OFFSET + 1] = 0xaa; + put_unaligned_le32(disksig, &buffer[DOS_PART_DISKSIG_OFFSET]); + pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET); + + /* create all primary partitions */ + for (i = 0; i < 4 && i < count; i++, pt++) { + mbr_fill_pt_entry(pt, p[i].start, p[i].start, p[i].size, + p[i].sys_ind, p[i].bootable); + if (is_extended(p[i].sys_ind)) { + ext_part_start = p[i].start; + ext_part_size = p[i].size; + ext_part_sect = p[i].start; + } + } + + if (i < count && !ext_part_start) { + printf("%s: extended partition is needed for more than 4 partitions\n", + __func__); + return -1; + } + + /* write MBR */ + if (blk_dwrite(dev, 0, 1, buffer) != 1) { + printf("%s: failed writing 'MBR' (1 blks at 0x0)\n", + __func__); + return -1; + } + + /* create extended volumes */ + for (; i < count; i++) { + lbaint_t next_ebr = 0; + + memset(buffer, 0, dev->blksz); + buffer[DOS_PART_MAGIC_OFFSET] = 0x55; + buffer[DOS_PART_MAGIC_OFFSET + 1] = 0xaa; + pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET); + + mbr_fill_pt_entry(pt, p[i].start, p[i].start - ext_part_sect, + p[i].size, p[i].sys_ind, p[i].bootable); + + if (i + 1 < count) { + pt++; + next_ebr = p[i].start + p[i].size; + mbr_fill_pt_entry(pt, next_ebr, + next_ebr - ext_part_start, + p[i+1].start + p[i+1].size - next_ebr, + DOS_PART_TYPE_EXTENDED, 0); + } + + /* write EBR */ + if (blk_dwrite(dev, ext_part_sect, 1, buffer) != 1) { + printf("%s: failed writing 'EBR' (1 blks at 0x%lx)\n", + __func__, ext_part_sect); + return -1; + } + ext_part_sect = next_ebr; + } + + return 0; +} + +int layout_mbr_partitions(struct disk_partition *p, int count, + lbaint_t total_sectors) +{ + struct disk_partition *ext = NULL; + int i, j; + lbaint_t ext_vol_start; + + /* calculate primary partitions start and size if needed */ + if (!p[0].start) + p[0].start = DOS_PART_DEFAULT_GAP; + for (i = 0; i < 4 && i < count; i++) { + if (!p[i].start) + p[i].start = p[i - 1].start + p[i - 1].size; + if (!p[i].size) { + lbaint_t end = total_sectors; + lbaint_t allocated = 0; + + for (j = i + 1; j < 4 && j < count; j++) { + if (p[j].start) { + end = p[j].start; + break; + } + allocated += p[j].size; + } + p[i].size = end - allocated - p[i].start; + } + if (p[i].sys_ind == 0x05) + ext = &p[i]; + } + + if (i >= 4 && !ext) { + printf("%s: extended partition is needed for more than 4 partitions\n", + __func__); + return -1; + } + + /* calculate extended volumes start and size if needed */ + ext_vol_start = ext->start; + for (i = 4; i < count; i++) { + if (!p[i].start) + p[i].start = ext_vol_start + DOS_PART_DEFAULT_GAP; + if (!p[i].size) { + lbaint_t end = ext->start + ext->size; + lbaint_t allocated = 0; + + for (j = i + 1; j < count; j++) { + if (p[j].start) { + end = p[j].start - DOS_PART_DEFAULT_GAP; + break; + } + allocated += p[j].size + DOS_PART_DEFAULT_GAP; + } + p[i].size = end - allocated - p[i].start; + } + ext_vol_start = p[i].start + p[i].size; + } + + return 0; +} +#endif + int write_mbr_sector(struct blk_desc *dev_desc, void *buf) { if (is_valid_dos_buf(buf)) diff --git a/disk/part_dos.h b/disk/part_dos.h index dd909a9317..5055822422 100644 --- a/disk/part_dos.h +++ b/disk/part_dos.h @@ -19,6 +19,8 @@ #define DOS_PART_TYPE_EXTENDED_LBA 0x0F #define DOS_PART_TYPE_EXTENDED_LINUX 0x85 +#define DOS_PART_DEFAULT_GAP 2048 + typedef struct dos_partition { unsigned char boot_ind; /* 0x80 - active */ unsigned char head; /* starting head */ diff --git a/include/part.h b/include/part.h index 67b8b2a5cc..fac36364bd 100644 --- a/include/part.h +++ b/include/part.h @@ -474,6 +474,11 @@ int is_valid_dos_buf(void *buf); */ int write_mbr_sector(struct blk_desc *dev_desc, void *buf); +int write_mbr_partitions(struct blk_desc *dev, + struct disk_partition *p, int count, unsigned int disksig); +int layout_mbr_partitions(struct disk_partition *p, int count, + lbaint_t total_sectors); + #endif From 750c543ca74a80da4b67882deb967c80fe790c3f Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 23 Dec 2020 13:55:15 +0100 Subject: [PATCH 46/46] cmd: Add MBR partition layout control utility Add a 'mbr' command to let users create or verify MBR partition layout based on the provided text description. The partition layout is alternatively read from the 'mbr_parts' environment variable. This can be used in scripts to help system image flashing tools to ensure proper partition layout. The syntax of the text description of the partition list is similar to the one used by the 'gpt' command. Supported parameters are: name (currently ignored), start (partition start offset in bytes), size (in bytes or '-' to expand it to the whole free area), bootable (boolean flag) and id (MBR partition type). If one wants to create more than 4 partitions, an 'Extended' primary partition (with 0x05 ID) has to be explicitely provided as a one of the first 4 entries. Here is an example how to create a 6 partitions (3 on the 'extended volume'), some of the predefined sizes: > setenv mbr_parts 'name=boot,start=4M,size=128M,bootable,id=0x0e; name=rootfs,size=3072M,id=0x83; name=system-data,size=512M,id=0x83; name=[ext],size=-,id=0x05; name=user,size=-,id=0x83; name=modules,size=100M,id=0x83; name=ramdisk,size=8M,id=0x83' > mbr write mmc 0 Signed-off-by: Marek Szyprowski --- cmd/Kconfig | 8 ++ cmd/Makefile | 1 + cmd/mbr.c | 314 ++++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + doc/usage/mbr.rst | 94 +++++++++++++ 5 files changed, 418 insertions(+) create mode 100644 cmd/mbr.c create mode 100644 doc/usage/mbr.rst diff --git a/cmd/Kconfig b/cmd/Kconfig index da86a940ce..0107c0fa3e 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1034,6 +1034,14 @@ config CMD_LSBLK Print list of available block device drivers, and for each, the list of known block devices. +config CMD_MBR + bool "MBR (Master Boot Record) command" + select DOS_PARTITION + select HAVE_BLOCK_DEVICE + help + Enable the 'mbr' command to ready and write MBR (Master Boot Record) + style partition tables. + config CMD_MISC bool "misc" depends on MISC diff --git a/cmd/Makefile b/cmd/Makefile index 5b3400a840..87aa949e2f 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -178,6 +178,7 @@ obj-$(CONFIG_CMD_ZFS) += zfs.o obj-$(CONFIG_CMD_DFU) += dfu.o obj-$(CONFIG_CMD_GPT) += gpt.o +obj-$(CONFIG_CMD_MBR) += mbr.o obj-$(CONFIG_CMD_ETHSW) += ethsw.o obj-$(CONFIG_CMD_AXI) += axi.o obj-$(CONFIG_CMD_PVBLOCK) += pvblock.o diff --git a/cmd/mbr.c b/cmd/mbr.c new file mode 100644 index 0000000000..da2e3a4722 --- /dev/null +++ b/cmd/mbr.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * cmd_mbr.c -- MBR (Master Boot Record) handling command + * + * Copyright (C) 2020 Samsung Electronics + * author: Marek Szyprowski + * + * based on the gpt command. + */ + +#include +#include +#include +#include +#include + +/** + * extract_val() - Extract a value from the key=value pair list + * @str: pointer to string with key=values pairs + * @key: pointer to the key to search for + * + * The list of parameters is come separated, only a value for + * the given key is returend. + * + * Function allocates memory for the value, remember to free! + * + * Return: Pointer to allocated string with the value. + */ +static char *extract_val(const char *str, const char *key) +{ + char *v, *k; + char *s, *strcopy; + char *new = NULL; + + strcopy = strdup(str); + if (strcopy == NULL) + return NULL; + + s = strcopy; + while (s) { + v = strsep(&s, ","); + if (!v) + break; + k = strsep(&v, "="); + if (!k) + break; + if (strcmp(k, key) == 0) { + new = strdup(v); + break; + } + } + + free(strcopy); + + return new; +} + +/** + * found_key() - Search for a key without a value in the parameter list + * @str: pointer to string with key + * @key: pointer to the key to search for + * + * The list of parameters is come separated. + * + * Return: True if key has been found. + */ +static bool found_key(const char *str, const char *key) +{ + char *k; + char *s, *strcopy; + bool result = false; + + strcopy = strdup(str); + if (!strcopy) + return NULL; + + s = strcopy; + while (s) { + k = strsep(&s, ","); + if (!k) + break; + if (strcmp(k, key) == 0) { + result = true; + break; + } + } + + free(strcopy); + + return result; +} + +static int str_to_partitions(const char *str_part, int blksz, + unsigned long *disk_uuid, struct disk_partition **partitions, + int *parts_count) +{ + char *tok, *str, *s; + int i; + char *val, *p; + int p_count; + struct disk_partition *parts; + int errno = 0; + uint64_t size_ll, start_ll; + + if (str_part == NULL) + return -1; + + str = strdup(str_part); + if (str == NULL) + return -ENOMEM; + + /* extract disk guid */ + s = str; + val = extract_val(str, "uuid_disk"); + if (val) { + val = strsep(&val, ";"); + p = val; + *disk_uuid = ustrtoull(p, &p, 0); + free(val); + /* Move s to first partition */ + strsep(&s, ";"); + } + if (s == NULL) { + printf("Error: is the partitions string NULL-terminated?\n"); + return -EINVAL; + } + + /* remove the optional semicolon at the end of the string */ + i = strlen(s) - 1; + if (s[i] == ';') + s[i] = '\0'; + + /* calculate expected number of partitions */ + p_count = 1; + p = s; + while (*p) { + if (*p++ == ';') + p_count++; + } + + /* allocate memory for partitions */ + parts = calloc(sizeof(struct disk_partition), p_count); + if (parts == NULL) + return -ENOMEM; + + /* retrieve partitions data from string */ + for (i = 0; i < p_count; i++) { + tok = strsep(&s, ";"); + + if (tok == NULL) + break; + + /* size */ + val = extract_val(tok, "size"); + if (!val) { /* 'size' is mandatory */ + errno = -4; + goto err; + } + p = val; + if ((strcmp(p, "-") == 0)) { + /* auto extend the size */ + parts[i].size = 0; + } else { + size_ll = ustrtoull(p, &p, 0); + parts[i].size = size_ll / blksz; + } + free(val); + + /* start address */ + val = extract_val(tok, "start"); + if (val) { /* start address is optional */ + p = val; + start_ll = ustrtoull(p, &p, 0); + parts[i].start = start_ll / blksz; + free(val); + } + + /* system id */ + val = extract_val(tok, "id"); + if (!val) { /* '' is mandatory */ + errno = -4; + goto err; + } + p = val; + parts[i].sys_ind = ustrtoul(p, &p, 0); + free(val); + + /* bootable */ + if (found_key(tok, "bootable")) + parts[i].bootable = PART_BOOTABLE; + } + + *parts_count = p_count; + *partitions = parts; + free(str); + + return 0; +err: + free(str); + free(parts); + + return errno; +} + +static int do_write_mbr(struct blk_desc *dev, const char *str) +{ + unsigned long disk_uuid = 0; + struct disk_partition *partitions; + int blksz = dev->blksz; + int count; + + if (str_to_partitions(str, blksz, &disk_uuid, &partitions, &count)) { + printf("MBR: failed to setup partitions from \"%s\"\n", str); + return -1; + } + + if (layout_mbr_partitions(partitions, count, dev->lba)) { + printf("MBR: failed to layout partitions on the device\n"); + free(partitions); + return -1; + } + + if (write_mbr_partitions(dev, partitions, count, disk_uuid)) { + printf("MBR: failed to write partitions to the device\n"); + free(partitions); + return -1; + } + + return 0; +} + +static int do_verify_mbr(struct blk_desc *dev, const char *str) +{ + unsigned long disk_uuid = 0; + struct disk_partition *partitions; + int blksz = dev->blksz; + int count, i, ret = 1; + + if (str_to_partitions(str, blksz, &disk_uuid, &partitions, &count)) { + printf("MBR: failed to setup partitions from \"%s\"\n", str); + return -1; + } + + for (i = 0; i < count; i++) { + struct disk_partition p; + + if (part_get_info(dev, i+1, &p)) + goto fail; + + if ((partitions[i].size && p.size < partitions[i].size) || + (partitions[i].start && p.start < partitions[i].start) || + (p.sys_ind != partitions[i].sys_ind)) + goto fail; + } + ret = 0; +fail: + free(partitions); + return ret; +} + +static int do_mbr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + const char *parts = NULL; + int ret = CMD_RET_SUCCESS; + int dev = 0; + char *ep; + struct blk_desc *blk_dev_desc = NULL; + + if (argc != 4 && argc != 5) + return CMD_RET_USAGE; + + dev = (int)simple_strtoul(argv[3], &ep, 10); + if (!ep || ep[0] != '\0') { + printf("'%s' is not a number\n", argv[3]); + return CMD_RET_USAGE; + } + blk_dev_desc = blk_get_dev(argv[2], dev); + if (!blk_dev_desc) { + printf("%s: %s dev %d NOT available\n", + __func__, argv[2], dev); + return CMD_RET_FAILURE; + } + + if ((strcmp(argv[1], "write") == 0)) { + parts = (argc == 5) ? argv[4] : env_get("mbr_parts"); + printf("MBR: write "); + ret = do_write_mbr(blk_dev_desc, parts); + } else if ((strcmp(argv[1], "verify") == 0)) { + printf("MBR: verify "); + parts = (argc == 5) ? argv[4] : env_get("mbr_parts"); + ret = do_verify_mbr(blk_dev_desc, parts); + } else { + return CMD_RET_USAGE; + } + + if (ret) { + printf("error!\n"); + return CMD_RET_FAILURE; + } + + printf("success!\n"); + return CMD_RET_SUCCESS; +} + +U_BOOT_CMD(mbr, CONFIG_SYS_MAXARGS, 1, do_mbr, + "MBR (Master Boot Record)", + " \n" + " - MBR partition table restoration utility\n" + " Restore or check partition information on a device connected\n" + " to the given block interface\n" + " Example usage:\n" + " mbr write mmc 0 [\"${mbr_parts}\"]\n" + " mbr verify mmc 0 [\"${partitions}\"]\n" +); diff --git a/doc/usage/index.rst b/doc/usage/index.rst index fbb2c0481c..5869fba189 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -14,4 +14,5 @@ Shell commands bootefi bootmenu button + mbr pstore diff --git a/doc/usage/mbr.rst b/doc/usage/mbr.rst new file mode 100644 index 0000000000..bddf2f612a --- /dev/null +++ b/doc/usage/mbr.rst @@ -0,0 +1,94 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +mbr command +=========== + +Synopsis +-------- + +:: + + mbr verify [interface] [device no] [partition list] + mbr write [interface] [device no] [partition list] + +Description +----------- + +The mbr command lets users create or verify the MBR (Master Boot Record) +partition layout based on the provided text description. The partition +layout is alternatively read from the 'mbr_parts' environment variable. +This can be used in scripts to help system image flashing tools to ensure +proper partition layout. + +The syntax of the text description of the partition list is similar to +the one used by the 'gpt' command. + +Supported partition parameters are: + +* name (currently ignored) +* start (partition start offset in bytes) +* size (in bytes or '-' to expand it to the whole free area) +* bootable (boolean flag) +* id (MBR partition type) + +If one wants to create more than 4 partitions, an 'Extended' primary +partition (with 0x05 ID) has to be explicitly provided as a one of the +first 4 entries. + +Here is an example how to create a 6 partitions (3 on the 'extended +volume'), some of the predefined sizes: + +:: + + => setenv mbr_parts 'name=boot,start=4M,size=128M,bootable,id=0x0e; + name=rootfs,size=3072M,id=0x83; + name=system-data,size=512M,id=0x83; + name=[ext],size=-,id=0x05; + name=user,size=-,id=0x83; + name=modules,size=100M,id=0x83; + name=ramdisk,size=8M,id=0x83' + => mbr write mmc 0 + +To check if the layout on the MMC #0 storage device matches the provided +text description one has to issue following command (assuming that +mbr_parts environment variable is set): + +:: + + => mbr verify mmc 0 + +The verify sub-command is especially useful in the system update scripts: + +:: + + => if mbr verify mmc 0; then + echo MBR layout needs to be updated + ... + fi + +The 'mbr write' command returns 0 on success write or 1 on failure. + +The 'mbr verify' returns 0 if the layout matches the one on the storage +device or 1 if not. + +Configuration +------------- + +To use the mbr command you must specify CONFIG_CMD_MBR=y. + +Return value +------------ + +The variable *$?* takes the following values + ++---+------------------------------+ +| 0 | mbr write was succesful | ++---+------------------------------+ +| 1 | mbr write failed | ++---+------------------------------+ +| 0 | mbr verify was succesful | ++---+------------------------------+ +| 1 | mbr verify was not succesful | ++---+------------------------------+ +|-1 | invalid arguments | ++---+------------------------------+