diff options
Diffstat (limited to 'arch/s390/boot')
-rw-r--r-- | arch/s390/boot/als.c | 20 | ||||
-rw-r--r-- | arch/s390/boot/boot.h | 2 | ||||
-rw-r--r-- | arch/s390/boot/ipl_parm.c | 66 | ||||
-rw-r--r-- | arch/s390/boot/startup.c | 1 | ||||
-rw-r--r-- | arch/s390/boot/string.c | 1 |
5 files changed, 72 insertions, 18 deletions
diff --git a/arch/s390/boot/als.c b/arch/s390/boot/als.c index d592e0d90d9f..f902215e9cd9 100644 --- a/arch/s390/boot/als.c +++ b/arch/s390/boot/als.c @@ -7,6 +7,7 @@ #include <asm/facility.h> #include <asm/lowcore.h> #include <asm/sclp.h> +#include "boot.h" /* * The code within this file will be called very early. It may _not_ @@ -58,7 +59,7 @@ static void u16_to_decimal(char *str, u16 val) *str = '\0'; } -static void print_missing_facilities(void) +void print_missing_facilities(void) { static char als_str[80] = "Missing facilities: "; unsigned long val; @@ -90,7 +91,6 @@ static void print_missing_facilities(void) } strcat(als_str, "\n"); sclp_early_printk(als_str); - sclp_early_printk("See Principles of Operations for facility bits\n"); } static void facility_mismatch(void) @@ -98,6 +98,7 @@ static void facility_mismatch(void) sclp_early_printk("The Linux kernel requires more recent processor hardware\n"); print_machine_type(); print_missing_facilities(); + sclp_early_printk("See Principles of Operations for facility bits\n"); disabled_wait(0x8badcccc); } @@ -105,20 +106,7 @@ void verify_facilities(void) { int i; - for (i = 0; i < ARRAY_SIZE(S390_lowcore.stfle_fac_list); i++) - S390_lowcore.stfle_fac_list[i] = 0; - asm volatile( - " stfl 0(0)\n" - : "=m" (S390_lowcore.stfl_fac_list)); - S390_lowcore.stfle_fac_list[0] = (u64)S390_lowcore.stfl_fac_list << 32; - if (S390_lowcore.stfl_fac_list & 0x01000000) { - register unsigned long reg0 asm("0") = ARRAY_SIZE(als) - 1; - - asm volatile(".insn s,0xb2b00000,0(%1)" /* stfle */ - : "+d" (reg0) - : "a" (&S390_lowcore.stfle_fac_list) - : "memory", "cc"); - } + __stfle(S390_lowcore.stfle_fac_list, ARRAY_SIZE(S390_lowcore.stfle_fac_list)); for (i = 0; i < ARRAY_SIZE(als); i++) { if ((S390_lowcore.stfle_fac_list[i] & als[i]) != als[i]) facility_mismatch(); diff --git a/arch/s390/boot/boot.h b/arch/s390/boot/boot.h index fc41e2277ea8..82bc06346e05 100644 --- a/arch/s390/boot/boot.h +++ b/arch/s390/boot/boot.h @@ -6,6 +6,8 @@ void startup_kernel(void); void detect_memory(void); void store_ipl_parmblock(void); void setup_boot_command_line(void); +void parse_boot_command_line(void); void setup_memory_end(void); +void print_missing_facilities(void); #endif /* BOOT_BOOT_H */ diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c index 9dab596be98e..36beb56de021 100644 --- a/arch/s390/boot/ipl_parm.c +++ b/arch/s390/boot/ipl_parm.c @@ -1,10 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 +#include <linux/kernel.h> #include <linux/init.h> #include <linux/ctype.h> #include <asm/ebcdic.h> #include <asm/sclp.h> #include <asm/sections.h> #include <asm/boot_data.h> +#include <asm/facility.h> #include "boot.h" char __bootdata(early_command_line)[COMMAND_LINE_SIZE]; @@ -143,8 +145,66 @@ void setup_boot_command_line(void) append_ipl_block_parm(); } +static void modify_facility(unsigned long nr, bool clear) +{ + if (clear) + __clear_facility(nr, S390_lowcore.stfle_fac_list); + else + __set_facility(nr, S390_lowcore.stfle_fac_list); +} + +static void check_cleared_facilities(void) +{ + unsigned long als[] = { FACILITIES_ALS }; + int i; + + for (i = 0; i < ARRAY_SIZE(als); i++) { + if ((S390_lowcore.stfle_fac_list[i] & als[i]) != als[i]) { + sclp_early_printk("Warning: The Linux kernel requires facilities cleared via command line option\n"); + print_missing_facilities(); + break; + } + } +} + +static void modify_fac_list(char *str) +{ + unsigned long val, endval; + char *endp; + bool clear; + + while (*str) { + clear = false; + if (*str == '!') { + clear = true; + str++; + } + val = simple_strtoull(str, &endp, 0); + if (str == endp) + break; + str = endp; + if (*str == '-') { + str++; + endval = simple_strtoull(str, &endp, 0); + if (str == endp) + break; + str = endp; + while (val <= endval) { + modify_facility(val, clear); + val++; + } + } else { + modify_facility(val, clear); + } + if (*str != ',') + break; + str++; + } + check_cleared_facilities(); +} + static char command_line_buf[COMMAND_LINE_SIZE] __section(.data); -static void parse_mem_opt(void) +void parse_boot_command_line(void) { char *param, *val; bool enabled; @@ -165,12 +225,14 @@ static void parse_mem_opt(void) if (!rc && !enabled) noexec_disabled = 1; } + + if (!strcmp(param, "facilities")) + modify_fac_list(val); } } void setup_memory_end(void) { - parse_mem_opt(); #ifdef CONFIG_CRASH_DUMP if (!OLDMEM_BASE && early_ipl_block_valid && early_ipl_block.hdr.pbt == DIAG308_IPL_TYPE_FCP && diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c index 4d441317cdeb..bdfc5549a299 100644 --- a/arch/s390/boot/startup.c +++ b/arch/s390/boot/startup.c @@ -53,6 +53,7 @@ void startup_kernel(void) sclp_early_read_info(); store_ipl_parmblock(); setup_boot_command_line(); + parse_boot_command_line(); setup_memory_end(); detect_memory(); if (!IS_ENABLED(CONFIG_KERNEL_UNCOMPRESSED)) { diff --git a/arch/s390/boot/string.c b/arch/s390/boot/string.c index 25aca07898ba..b11e8108773a 100644 --- a/arch/s390/boot/string.c +++ b/arch/s390/boot/string.c @@ -2,6 +2,7 @@ #include <linux/ctype.h> #include <linux/kernel.h> #include <linux/errno.h> +#undef CONFIG_KASAN #include "../lib/string.c" int strncmp(const char *cs, const char *ct, size_t count) |