From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933516AbbLVWw4 (ORCPT ); Tue, 22 Dec 2015 17:52:56 -0500 Received: from mga14.intel.com ([192.55.52.115]:21157 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933281AbbLVWwp (ORCPT ); Tue, 22 Dec 2015 17:52:45 -0500 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.20,466,1444719600"; d="scan'208";a="846739817" Subject: [PATCH 5/5] x86: test early command-line code To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, Dave Hansen , dave.hansen@linux.intel.com, bp@suse.de, hpa@zytor.com, fenghua.yu@intel.com, yu-cheng.yu@intel.com From: Dave Hansen Date: Tue, 22 Dec 2015 14:52:44 -0800 References: <20151222225237.08CDE5F1@viggo.jf.intel.com> In-Reply-To: <20151222225237.08CDE5F1@viggo.jf.intel.com> Message-Id: <20151222225244.C64747AF@viggo.jf.intel.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Dave Hansen Here are some simple tests for the early command-line code. It had way more bugs than it should have, so let's make sure they never pop up again. Note, there are a few failures in here now. We will fix those up in the next few patches. This is complete overkill for this code, but I had to do it to convince myself that I wasn't making it any worse. Signed-off-by: Dave Hansen Cc: Borislav Petkov Cc: H. Peter Anvin Cc: linux-kernel@vger.kernel.org Cc: fenghua.yu@intel.com Cc: yu-cheng.yu@intel.com --- b/arch/x86/Kconfig.debug | 7 ++ b/arch/x86/kernel/check.c | 1 b/arch/x86/kernel/setup.c | 9 +++ b/arch/x86/lib/cmdline.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 138 insertions(+), 1 deletion(-) diff -puN arch/x86/Kconfig.debug~x86-early-command-line-test arch/x86/Kconfig.debug --- a/arch/x86/Kconfig.debug~x86-early-command-line-test 2015-12-22 11:57:01.229266152 -0800 +++ b/arch/x86/Kconfig.debug 2015-12-22 11:57:01.238266557 -0800 @@ -400,4 +400,11 @@ config PUNIT_ATOM_DEBUG The current power state can be read from /sys/kernel/debug/punit_atom/dev_power_state +config X86_TEST_EARLY_CMDLINE + bool "Early command line runtime tests" + ---help--- + This creates some test command-lines and tries to parse + a bunch of options from them. The overhead is small both + at boot and increased text/data sizes. + endmenu diff -puN arch/x86/kernel/check.c~x86-early-command-line-test arch/x86/kernel/check.c --- a/arch/x86/kernel/check.c~x86-early-command-line-test 2015-12-22 11:57:01.230266197 -0800 +++ b/arch/x86/kernel/check.c 2015-12-22 11:57:01.239266602 -0800 @@ -164,4 +164,3 @@ static int start_periodic_check_for_corr return 0; } device_initcall(start_periodic_check_for_corruption); - diff -puN arch/x86/lib/cmdline.c~x86-early-command-line-test arch/x86/lib/cmdline.c --- a/arch/x86/lib/cmdline.c~x86-early-command-line-test 2015-12-22 11:57:01.232266287 -0800 +++ b/arch/x86/lib/cmdline.c 2015-12-22 11:57:01.239266602 -0800 @@ -4,6 +4,7 @@ * * Misc librarized functions for cmdline poking. */ +#include #include #include #include @@ -108,3 +109,124 @@ int cmdline_find_option_bool(const char return __cmdline_find_option_bool(cmdline, COMMAND_LINE_SIZE, option); } + +#ifdef CONFIG_X86_TEST_EARLY_CMDLINE + +static int __cmdtest(char *cmdline, int str_size, char *option, + int expected_result, int do_shrink) +{ + int ret; + int null_terminate; + /* Results are 1-based, so bias back down by 1 */ + int option_end = expected_result + strlen(option) - 1; + int shrink_max = 0; + + if (cmdline && do_shrink) + shrink_max = strlen(cmdline); + /* + * The option was not found. If it was not found in the + * *full* command-line, it should never be found in any + * *part* of the command-line. + */ + for (null_terminate = 0; null_terminate <= 1; null_terminate++) { + int shrink_by; + for (shrink_by = 0; shrink_by < shrink_max; shrink_by++) { + int str_size_tst = str_size - shrink_by; + char tmp = cmdline[str_size_tst]; + + /* + * Do not run tests that would truncate + * over the expected option + */ + if (str_size_tst <= option_end) + continue; + + if (null_terminate) + cmdline[str_size_tst] = '\0'; + ret = __cmdline_find_option_bool(cmdline, str_size_tst, + option); + if (null_terminate) + cmdline[str_size_tst] = tmp; + + if (ret == expected_result) + continue; + pr_err("failed cmdline test ('%s', %d, '%s') == %d " + "nulld: %d got: %d\n", + cmdline, str_size_tst, option, + expected_result, null_terminate, + ret); + return 1; + } + } + return 0; +} + +#define cmdtest(cmdline, option, result) \ + WARN_ON(__cmdtest(cmdline, sizeof(cmdline), option, result, 1)) + +#define cmdtest_noshrink(cmdline, option, result) \ + WARN_ON(__cmdtest(cmdline, sizeof(cmdline), option, result, 0)) + +char cmdline1[] = "CALL me Ishmael "; +char cmdline2[] = "Whenever I find myself growing grim about the mouth "; +char cmdline3[] = "grow growing "; +int test_early_cmdline(void) +{ + /* NULL command-line: */ + WARN_ON(__cmdline_find_option_bool(NULL, 22, "Ishmael") != -1); + /* zero-length command-line: */ + cmdtest("", "Ishmael", 0); + + /* Find words at each of 3 positions: start, middle, end */ + cmdtest(cmdline1, "CALL", 1); + cmdtest(cmdline1, "me", 6); + cmdtest(cmdline1, "Ishmael", 9); + + /* + * Fail to find strings that all occur in the cmdline, + * but not as full words + */ + /* + * If "option" is _present_ in "cmdline" as the start of a + * word, like cmdline="foo bar" and we pass in option="b", + * when we shrink cmdline to "foo b", it will match. So, + * skip shrink tests for those. + */ + cmdtest_noshrink(cmdline1, "m", 0); + cmdtest(cmdline1, "e", 0); + cmdtest(cmdline1, "C", 0); + cmdtest(cmdline1, "l", 0); + cmdtest_noshrink(cmdline1, "Ishmae", 0); + cmdtest(cmdline1, "mael", 0); + /* + * Look for strings that do not occur, but match until + * close to the end of cmdline + */ + cmdtest_noshrink(cmdline1, "Ishmae", 0); + cmdtest(cmdline1, "Ishmaels", 0); + cmdtest(cmdline1, "maels", 0); + + /* + * Look for full words that do not occur in a different + * cmdline + */ + cmdtest(cmdline2, "CALL", 0); + cmdtest(cmdline2, "me", 0); + cmdtest(cmdline2, "Ishmael", 0); + /* + * Look for full words which do occur in cmdline2 + */ + cmdtest(cmdline2, "Whenever", 1); + cmdtest(cmdline2, "growing", 24); + cmdtest(cmdline2, "grim", 32); + cmdtest(cmdline2, "mouth", 47); + + /* + * Catch the bug where if we match a partial word and + * then have a space, we do not match the _next_ word. + */ + cmdtest(cmdline3, "grow", 1); + cmdtest(cmdline3, "growing", 6); + return 0; +} +#endif /* CONFIG_X86_TEST_EARLY_CMDLINE */ diff -puN arch/x86/kernel/setup.c~x86-early-command-line-test arch/x86/kernel/setup.c --- a/arch/x86/kernel/setup.c~x86-early-command-line-test 2015-12-22 11:57:01.233266332 -0800 +++ b/arch/x86/kernel/setup.c 2015-12-22 11:57:01.239266602 -0800 @@ -1282,3 +1282,12 @@ static int __init register_kernel_offset return 0; } __initcall(register_kernel_offset_dumper); + +/* + * This code is in lib/ and we do not link initcalls from there. + * Stash it here instead. + */ +#ifdef CONFIG_X86_TEST_EARLY_CMDLINE +int test_early_cmdline(void); +late_initcall(test_early_cmdline); +#endif /* CONFIG_X86_TEST_EARLY_CMDLINE */ _