Felix Held has submitted this change. ( https://review.coreboot.org/c/coreboot/+/75510?usp=email )
Change subject: drivers/ocp/vpd: Overwrite Linux payload's kernel command via VPD ......................................................................
drivers/ocp/vpd: Overwrite Linux payload's kernel command via VPD
Add a new Kconfig LINUXPAYLOAD_CMDLINE_VPD_OVERWRITE that can overwrite Linux payload's kernel command line from VPD. Currently only overwrite Linux kernel command line 'loglevel' via VPD key 'kernel_log_level'.
TESTED=On OCP Delta Lake, with kernel_log_level set to 0, warm reboot time can see about 10 seconds improvement comparing to kernel log level 7.
Change-Id: Idf06c7ab9958c940fc3b23d560bb9dade991a6da Signed-off-by: Johnny Lin johnny_lin@wiwynn.com Reviewed-on: https://review.coreboot.org/c/coreboot/+/75510 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: David Hendricks david.hendricks@gmail.com --- M src/drivers/ocp/include/vpd.h M src/drivers/ocp/vpd/Kconfig M src/drivers/ocp/vpd/Makefile.inc A src/drivers/ocp/vpd/vpd_cmdline.c 4 files changed, 69 insertions(+), 0 deletions(-)
Approvals: build bot (Jenkins): Verified David Hendricks: Looks good to me, approved
diff --git a/src/drivers/ocp/include/vpd.h b/src/drivers/ocp/include/vpd.h index 33fece5..60299e3 100644 --- a/src/drivers/ocp/include/vpd.h +++ b/src/drivers/ocp/include/vpd.h @@ -77,6 +77,9 @@ /* Socket 1 core disable bitmask */ #define CORE_DIS_BITMSK1 "core_disable_bitmask1"
+/* Linux payload kernel log level */ +#define KERNEL_LOG_LEVEL "kernel_log_level" + /* Get VPD key with provided fallback value and min/max ranges */ int get_int_from_vpd_range(const char *const key, const int fallback, const int min, const int max); diff --git a/src/drivers/ocp/vpd/Kconfig b/src/drivers/ocp/vpd/Kconfig index ebecbe6..12ee185 100644 --- a/src/drivers/ocp/vpd/Kconfig +++ b/src/drivers/ocp/vpd/Kconfig @@ -4,3 +4,12 @@ depends on VPD help It implements functions that get common VPD variables for OCP projects. + +config LINUXPAYLOAD_CMDLINE_VPD_OVERWRITE + bool + default n + depends on VPD + help + Overwrite Linux payload's kernel command line by using VPD. Currently only + overwrite the value of kernel command line 'loglevel'. The Linux kernel command + line data is detected in the last segment loaded in memory and overwritten. diff --git a/src/drivers/ocp/vpd/Makefile.inc b/src/drivers/ocp/vpd/Makefile.inc index 8db5afa..b40534a 100644 --- a/src/drivers/ocp/vpd/Makefile.inc +++ b/src/drivers/ocp/vpd/Makefile.inc @@ -1,5 +1,6 @@ romstage-$(CONFIG_OCP_VPD) += vpd_util.c ramstage-$(CONFIG_OCP_VPD) += vpd_util.c +ramstage-$(CONFIG_LINUXPAYLOAD_CMDLINE_VPD_OVERWRITE) += vpd_cmdline.c ifeq ($(CONFIG_VPD),y) all-$(CONFIG_CONSOLE_OVERRIDE_LOGLEVEL) += loglevel_vpd.c endif diff --git a/src/drivers/ocp/vpd/vpd_cmdline.c b/src/drivers/ocp/vpd/vpd_cmdline.c new file mode 100644 index 0000000..44e166c --- /dev/null +++ b/src/drivers/ocp/vpd/vpd_cmdline.c @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <console/console.h> +#include <drivers/vpd/vpd.h> +#include <drivers/ocp/include/vpd.h> +#include <string.h> +#include <program_loading.h> + +#define CMDLINE_LOGLVL_STR "loglevel=" + +static void overwrite_kernel_loglevel(uintptr_t start) +{ + int val; + if (!vpd_get_int(KERNEL_LOG_LEVEL, VPD_RW_THEN_RO, &val)) { + printk(BIOS_DEBUG, "%s: not able to get VPD %s\n", __func__, KERNEL_LOG_LEVEL); + return; + } + + printk(BIOS_DEBUG, "%s: VPD %s, got %d\n", __func__, KERNEL_LOG_LEVEL, val); + if (val < 0 || val > 7) { + printk(BIOS_INFO, "Invalid VPD for Linux kernel log level\n"); + return; + } + + int loglevel; + char *loc = strstr((const char *)start, CMDLINE_LOGLVL_STR); + if (!loc) { + printk(BIOS_INFO, "%s is not found from LINUX_COMMAND_LINE\n", + CMDLINE_LOGLVL_STR); + return; + } + + char *loc_bkup; + loc += strlen(CMDLINE_LOGLVL_STR); + loc_bkup = loc; + loglevel = skip_atoi(&loc); + printk(BIOS_DEBUG, "Original kernel log level is %d\n", loglevel); + /* Unlikely but don't overwrite with such an unexpected case. */ + if (loglevel < 0 || loglevel > 7) { + printk(BIOS_DEBUG, "Invalid kernel log level, must be from 0 to 7.\n"); + return; + } + + char c = '0' + val; + printk(BIOS_INFO, "Overwrite kernel log level with %c from VPD.\n", c); + memcpy(loc_bkup, &c, 1); +} + +void platform_segment_loaded(uintptr_t start, size_t size, int flags) +{ + /* CONFIG_LINUX_COMMAND_LINE is in the final segment. */ + if (flags != SEG_FINAL) + return; + + overwrite_kernel_loglevel(start); +}