From d552a58d708020963f6973a8b3b690f19ac81c99 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 28 Apr 2021 13:30:56 +0200 Subject: s390/cpumf: remove counter transaction call backs The command 'perf stat -e cycles ...' triggers the following function sequence in the CPU Measurement Facility counter device driver: perf_pmu_event_init() __hw_perf_event_init() validate_ctr_auth() validate_ctr_version() During event creation, the counter number is checked in functions validate_ctr_auth() and validate_ctr_version() to verify it is a valid counter and supported by the hardware. If this is not the case, both functions return an error and the event is not created. System call perf_event_open() returns an error in this case. Later on the event is installed in the kernel event subsystem and the driver functions cpumf_pmu_add() and cpumf_pmu_commit_txn() are called to install the counter event by the hardware. Since both events have been verified at event creation, there is no need to re-evaluate the authorization state. This can not change since on * LPARs the authorization change requires a restart of the LPAR (and thus a reboot of the kernel) * DPMs can not take resources away, just add them. Also the sequence of CPU Measurement facility counter device driver calls is cpumf_pmu_start_txn cpumf_pmu_add cpumf_pmu_start cpumf_pmu_commit_txn for every single event. Which means the condition in cpumf_pmu_add() is never met and validate_ctr_auth() is never called. This leaves the counter device driver transaction functions with just one task: start_txn: Verify a transaction is not in flight and call perf_pmu_disable() cancel_txn, commit_txn: Verify a transaction is in flight and call perf_pmu_enable() The same functionality is provided by the default transaction handling functions in kernel/events/core.c. Use those by removing the counter device driver private call back functions. Suggested-by: Sumanth Korikkar Signed-off-by: Thomas Richter Reviewed-by: Sumanth Korikkar Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/cpu_mcf.h | 3 +- arch/s390/kernel/perf_cpum_cf.c | 84 ---------------------------------- arch/s390/kernel/perf_cpum_cf_common.c | 1 - 3 files changed, 1 insertion(+), 87 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/cpu_mcf.h b/arch/s390/include/asm/cpu_mcf.h index 3e4cbcb7c4cc..4dcefddb7751 100644 --- a/arch/s390/include/asm/cpu_mcf.h +++ b/arch/s390/include/asm/cpu_mcf.h @@ -92,9 +92,8 @@ struct cpu_cf_events { struct cpumf_ctr_info info; atomic_t ctr_set[CPUMF_CTR_SET_MAX]; atomic64_t alert; - u64 state, tx_state; + u64 state; unsigned int flags; - unsigned int txn_flags; }; DECLARE_PER_CPU(struct cpu_cf_events, cpu_cf_events); diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c index 31a605bcbc6e..91ee0f399aae 100644 --- a/arch/s390/kernel/perf_cpum_cf.c +++ b/arch/s390/kernel/perf_cpum_cf.c @@ -413,15 +413,6 @@ static int cpumf_pmu_add(struct perf_event *event, int flags) { struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); - /* Check authorization for the counter set to which this - * counter belongs. - * For group events transaction, the authorization check is - * done in cpumf_pmu_commit_txn(). - */ - if (!(cpuhw->txn_flags & PERF_PMU_TXN_ADD)) - if (validate_ctr_auth(&event->hw)) - return -ENOENT; - ctr_set_enable(&cpuhw->state, event->hw.config_base); event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED; @@ -449,78 +440,6 @@ static void cpumf_pmu_del(struct perf_event *event, int flags) ctr_set_disable(&cpuhw->state, event->hw.config_base); } -/* - * Start group events scheduling transaction. - * Set flags to perform a single test at commit time. - * - * We only support PERF_PMU_TXN_ADD transactions. Save the - * transaction flags but otherwise ignore non-PERF_PMU_TXN_ADD - * transactions. - */ -static void cpumf_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags) -{ - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); - - WARN_ON_ONCE(cpuhw->txn_flags); /* txn already in flight */ - - cpuhw->txn_flags = txn_flags; - if (txn_flags & ~PERF_PMU_TXN_ADD) - return; - - perf_pmu_disable(pmu); - cpuhw->tx_state = cpuhw->state; -} - -/* - * Stop and cancel a group events scheduling tranctions. - * Assumes cpumf_pmu_del() is called for each successful added - * cpumf_pmu_add() during the transaction. - */ -static void cpumf_pmu_cancel_txn(struct pmu *pmu) -{ - unsigned int txn_flags; - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); - - WARN_ON_ONCE(!cpuhw->txn_flags); /* no txn in flight */ - - txn_flags = cpuhw->txn_flags; - cpuhw->txn_flags = 0; - if (txn_flags & ~PERF_PMU_TXN_ADD) - return; - - WARN_ON(cpuhw->tx_state != cpuhw->state); - - perf_pmu_enable(pmu); -} - -/* - * Commit the group events scheduling transaction. On success, the - * transaction is closed. On error, the transaction is kept open - * until cpumf_pmu_cancel_txn() is called. - */ -static int cpumf_pmu_commit_txn(struct pmu *pmu) -{ - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); - u64 state; - - WARN_ON_ONCE(!cpuhw->txn_flags); /* no txn in flight */ - - if (cpuhw->txn_flags & ~PERF_PMU_TXN_ADD) { - cpuhw->txn_flags = 0; - return 0; - } - - /* check if the updated state can be scheduled */ - state = cpuhw->state & ~((1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1); - state >>= CPUMF_LCCTL_ENABLE_SHIFT; - if ((state & cpuhw->info.auth_ctl) != state) - return -ENOENT; - - cpuhw->txn_flags = 0; - perf_pmu_enable(pmu); - return 0; -} - /* Performance monitoring unit for s390x */ static struct pmu cpumf_pmu = { .task_ctx_nr = perf_sw_context, @@ -533,9 +452,6 @@ static struct pmu cpumf_pmu = { .start = cpumf_pmu_start, .stop = cpumf_pmu_stop, .read = cpumf_pmu_read, - .start_txn = cpumf_pmu_start_txn, - .commit_txn = cpumf_pmu_commit_txn, - .cancel_txn = cpumf_pmu_cancel_txn, }; static int __init cpumf_pmu_init(void) diff --git a/arch/s390/kernel/perf_cpum_cf_common.c b/arch/s390/kernel/perf_cpum_cf_common.c index 6d53215c8484..2300fbaac556 100644 --- a/arch/s390/kernel/perf_cpum_cf_common.c +++ b/arch/s390/kernel/perf_cpum_cf_common.c @@ -30,7 +30,6 @@ DEFINE_PER_CPU(struct cpu_cf_events, cpu_cf_events) = { .alert = ATOMIC64_INIT(0), .state = 0, .flags = 0, - .txn_flags = 0, }; /* Indicator whether the CPU-Measurement Counter Facility Support is ready */ static bool cpum_cf_initalized; -- cgit v1.2.3 From 15e5b53ff4c92c8ea79094871f91d077bfc60526 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Thu, 29 Apr 2021 15:04:30 +0200 Subject: s390/cpumf: remove WARN_ON_ONCE in counter start handler Remove some WARN_ON_ONCE() warnings when a counter is started. Each counter is installed function calls event_sched_in() --> cpumf_pmu_add(..., PERF_EF_START). This is done after the event has been created using perf_pmu_event_init() which verifies the counter is valid. Member hwc->config must be valid at this point. Function cpumf_pmu_start(..., PERF_EF_RELOAD) is called from function cpumf_pmu_add() for counter events. All other invocations of cpumf_pmu_start(..., PERF_EF_RELOAD) are from the performance subsystem for sampling events. Signed-off-by: Thomas Richter Acked-by: Sumanth Korikkar Signed-off-by: Vasily Gorbik --- arch/s390/kernel/perf_cpum_cf.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c index 91ee0f399aae..1b7a0525fbed 100644 --- a/arch/s390/kernel/perf_cpum_cf.c +++ b/arch/s390/kernel/perf_cpum_cf.c @@ -362,15 +362,9 @@ static void cpumf_pmu_start(struct perf_event *event, int flags) struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); struct hw_perf_event *hwc = &event->hw; - if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED))) + if (!(hwc->state & PERF_HES_STOPPED)) return; - if (WARN_ON_ONCE(hwc->config == -1)) - return; - - if (flags & PERF_EF_RELOAD) - WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE)); - hwc->state = 0; /* (Re-)enable and activate the counter set */ -- cgit v1.2.3 From d460bb6c6417588dd8b0907d34f69b237918812a Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Fri, 19 Feb 2021 12:00:52 +0100 Subject: s390: enable HAVE_IOREMAP_PROT In commit b02002cc4c0f ("s390/pci: Implement ioremap_wc/prot() with MIO") we implemented both ioremap_wc() and ioremap_prot() however until now we had not set HAVE_IOREMAP_PROT in Kconfig, do so now. This also requires implementing pte_pgprot() as this is used in the generic_access_phys() code enabled by CONFIG_HAVE_IOREMAP_PROT. As with ioremap_wc() we need to take the MMIO Write Back bit index into account. Moreover since the pgprot value returned from pte_pgprot() is to be used for mappings into kernel address space we must make sure that it uses appropriate kernel page table protection bits. In particular a pgprot value originally coming from userspace could have the _PAGE_PROTECT bit set to enable fault based dirty bit accounting which would then make the mapping inaccessible when used in kernel address space. Fixes: b02002cc4c0f ("s390/pci: Implement ioremap_wc/prot() with MIO") Reviewed-by: Gerald Schaefer Signed-off-by: Niklas Schnelle Signed-off-by: Vasily Gorbik --- arch/s390/Kconfig | 1 + arch/s390/include/asm/pgtable.h | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) (limited to 'arch/s390') diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index b4c7c34069f8..d6582f57e0a1 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -164,6 +164,7 @@ config S390 select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_GCC_PLUGINS select HAVE_GENERIC_VDSO + select HAVE_IOREMAP_PROT if PCI select HAVE_IRQ_EXIT_ON_IRQ_STACK select HAVE_KERNEL_BZIP2 select HAVE_KERNEL_GZIP diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 29c7ecd5ad1d..9512f6820ead 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -865,6 +865,25 @@ static inline int pte_unused(pte_t pte) return pte_val(pte) & _PAGE_UNUSED; } +/* + * Extract the pgprot value from the given pte while at the same time making it + * usable for kernel address space mappings where fault driven dirty and + * young/old accounting is not supported, i.e _PAGE_PROTECT and _PAGE_INVALID + * must not be set. + */ +static inline pgprot_t pte_pgprot(pte_t pte) +{ + unsigned long pte_flags = pte_val(pte) & _PAGE_CHG_MASK; + + if (pte_write(pte)) + pte_flags |= pgprot_val(PAGE_KERNEL); + else + pte_flags |= pgprot_val(PAGE_KERNEL_RO); + pte_flags |= pte_val(pte) & mio_wb_bit_mask; + + return __pgprot(pte_flags); +} + /* * pgd/pmd/pte modification functions */ -- cgit v1.2.3 From af9ad82290a58b3f1cc02d12459e3396eee04187 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Wed, 5 May 2021 22:01:09 +0200 Subject: s390/entry: use assignment to read intcode / asm to copy gprs arch/s390/kernel/syscall.c: In function __do_syscall: arch/s390/kernel/syscall.c:147:9: warning: memcpy reading 64 bytes from a region of size 0 [-Wstringop-overread] 147 | memcpy(®s->gprs[8], S390_lowcore.save_area_sync, 8 * sizeof(unsigned long)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ arch/s390/kernel/syscall.c:148:9: warning: memcpy reading 4 bytes from a region of size 0 [-Wstringop-overread] 148 | memcpy(®s->int_code, &S390_lowcore.svc_ilc, sizeof(regs->int_code)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Fix this by moving the gprs restore from C to assembly, and use a assignment for int_code instead of memcpy. Signed-off-by: Sven Schnelle Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/lowcore.h | 3 +-- arch/s390/kernel/asm-offsets.c | 2 -- arch/s390/kernel/entry.S | 1 + arch/s390/kernel/syscall.c | 5 +---- 4 files changed, 3 insertions(+), 8 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 22bceeeba4bc..484065b5fa7d 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -24,8 +24,7 @@ struct lowcore { __u32 ext_params; /* 0x0080 */ __u16 ext_cpu_addr; /* 0x0084 */ __u16 ext_int_code; /* 0x0086 */ - __u16 svc_ilc; /* 0x0088 */ - __u16 svc_code; /* 0x008a */ + __u32 svc_int_code; /* 0x0088 */ __u16 pgm_ilc; /* 0x008c */ __u16 pgm_code; /* 0x008e */ __u32 data_exc_code; /* 0x0090 */ diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 15e637728a4b..96270584ef69 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -58,8 +58,6 @@ int main(void) OFFSET(__LC_EXT_PARAMS, lowcore, ext_params); OFFSET(__LC_EXT_CPU_ADDR, lowcore, ext_cpu_addr); OFFSET(__LC_EXT_INT_CODE, lowcore, ext_int_code); - OFFSET(__LC_SVC_ILC, lowcore, svc_ilc); - OFFSET(__LC_SVC_INT_CODE, lowcore, svc_code); OFFSET(__LC_PGM_ILC, lowcore, pgm_ilc); OFFSET(__LC_PGM_INT_CODE, lowcore, pgm_code); OFFSET(__LC_DATA_EXC_CODE, lowcore, data_exc_code); diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 12de7a9c85b3..e7094ab8eb2c 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -276,6 +276,7 @@ ENTRY(system_call) xgr %r10,%r10 xgr %r11,%r11 la %r2,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs + mvc __PT_R8(64,%r2),__LC_SAVE_AREA_SYNC lgr %r3,%r14 brasl %r14,__do_syscall lctlg %c1,%c1,__LC_USER_ASCE diff --git a/arch/s390/kernel/syscall.c b/arch/s390/kernel/syscall.c index 4e5cc7d2364e..76f7916cc30f 100644 --- a/arch/s390/kernel/syscall.c +++ b/arch/s390/kernel/syscall.c @@ -144,11 +144,8 @@ void noinstr __do_syscall(struct pt_regs *regs, int per_trap) { add_random_kstack_offset(); enter_from_user_mode(regs); - - memcpy(®s->gprs[8], S390_lowcore.save_area_sync, 8 * sizeof(unsigned long)); - memcpy(®s->int_code, &S390_lowcore.svc_ilc, sizeof(regs->int_code)); regs->psw = S390_lowcore.svc_old_psw; - + regs->int_code = S390_lowcore.svc_int_code; update_timer_sys(); local_irq_enable(); -- cgit v1.2.3 From 17e89e1340a377b2f14a14d7050f609328592793 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Wed, 5 May 2021 22:01:10 +0200 Subject: s390/facilities: move stfl information from lowcore to global data With gcc-11, there are a lot of warnings because the facility functions are accessing lowcore through a null pointer. Fix this by moving the facility arrays away from lowcore. Signed-off-by: Sven Schnelle Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/boot/als.c | 6 +++--- arch/s390/boot/ipl_parm.c | 6 +++--- arch/s390/boot/startup.c | 3 +++ arch/s390/include/asm/facility.h | 13 +++++++++---- arch/s390/include/asm/lowcore.h | 7 +------ arch/s390/kernel/alternative.c | 3 +-- arch/s390/kernel/asm-offsets.c | 2 -- arch/s390/kernel/early.c | 6 ++---- arch/s390/kernel/nospec-branch.c | 14 +++++++------- arch/s390/kernel/nospec-sysfs.c | 2 +- arch/s390/kernel/processor.c | 4 +--- arch/s390/kernel/setup.c | 8 +++----- arch/s390/kernel/smp.c | 4 ---- arch/s390/kvm/kvm-s390.c | 12 ++++++------ 14 files changed, 40 insertions(+), 50 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/boot/als.c b/arch/s390/boot/als.c index ff6801d401c4..47c48fbfb563 100644 --- a/arch/s390/boot/als.c +++ b/arch/s390/boot/als.c @@ -68,7 +68,7 @@ void print_missing_facilities(void) first = 1; for (i = 0; i < ARRAY_SIZE(als); i++) { - val = ~S390_lowcore.stfle_fac_list[i] & als[i]; + val = ~stfle_fac_list[i] & als[i]; for (j = 0; j < BITS_PER_LONG; j++) { if (!(val & (1UL << (BITS_PER_LONG - 1 - j)))) continue; @@ -106,9 +106,9 @@ void verify_facilities(void) { int i; - __stfle(S390_lowcore.stfle_fac_list, ARRAY_SIZE(S390_lowcore.stfle_fac_list)); + __stfle(stfle_fac_list, ARRAY_SIZE(stfle_fac_list)); for (i = 0; i < ARRAY_SIZE(als); i++) { - if ((S390_lowcore.stfle_fac_list[i] & als[i]) != als[i]) + if ((stfle_fac_list[i] & als[i]) != als[i]) facility_mismatch(); } } diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c index d372a45fe10e..865c66cb9b79 100644 --- a/arch/s390/boot/ipl_parm.c +++ b/arch/s390/boot/ipl_parm.c @@ -180,9 +180,9 @@ void setup_boot_command_line(void) static void modify_facility(unsigned long nr, bool clear) { if (clear) - __clear_facility(nr, S390_lowcore.stfle_fac_list); + __clear_facility(nr, stfle_fac_list); else - __set_facility(nr, S390_lowcore.stfle_fac_list); + __set_facility(nr, stfle_fac_list); } static void check_cleared_facilities(void) @@ -191,7 +191,7 @@ static void check_cleared_facilities(void) int i; for (i = 0; i < ARRAY_SIZE(als); i++) { - if ((S390_lowcore.stfle_fac_list[i] & als[i]) != als[i]) { + if ((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; diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c index 05f8eefa3dcf..61a8ac4067e5 100644 --- a/arch/s390/boot/startup.c +++ b/arch/s390/boot/startup.c @@ -17,6 +17,9 @@ extern char __boot_data_preserved_start[], __boot_data_preserved_end[]; unsigned long __bootdata_preserved(__kaslr_offset); unsigned long __bootdata(ident_map_size); +u64 __bootdata_preserved(stfle_fac_list[16]); +u64 __bootdata_preserved(alt_stfle_fac_list[16]); + /* * Some code and data needs to stay below 2 GB, even when the kernel would be * relocated above 2 GB, because it has to use 31 bit addresses. diff --git a/arch/s390/include/asm/facility.h b/arch/s390/include/asm/facility.h index 91b5d714d28f..948e2616fe9c 100644 --- a/arch/s390/include/asm/facility.h +++ b/arch/s390/include/asm/facility.h @@ -13,7 +13,10 @@ #include #include -#define MAX_FACILITY_BIT (sizeof(((struct lowcore *)0)->stfle_fac_list) * 8) +#define MAX_FACILITY_BIT (sizeof(stfle_fac_list) * 8) + +extern u64 stfle_fac_list[16]; +extern u64 alt_stfle_fac_list[16]; static inline void __set_facility(unsigned long nr, void *facilities) { @@ -56,7 +59,7 @@ static inline int test_facility(unsigned long nr) if (__test_facility(nr, &facilities_als)) return 1; } - return __test_facility(nr, &S390_lowcore.stfle_fac_list); + return __test_facility(nr, &stfle_fac_list); } static inline unsigned long __stfle_asm(u64 *stfle_fac_list, int size) @@ -79,13 +82,15 @@ static inline unsigned long __stfle_asm(u64 *stfle_fac_list, int size) static inline void __stfle(u64 *stfle_fac_list, int size) { unsigned long nr; + u32 stfl_fac_list; asm volatile( " stfl 0(0)\n" : "=m" (S390_lowcore.stfl_fac_list)); + stfl_fac_list = S390_lowcore.stfl_fac_list; + memcpy(stfle_fac_list, &stfl_fac_list, 4); nr = 4; /* bytes stored by stfl */ - memcpy(stfle_fac_list, &S390_lowcore.stfl_fac_list, 4); - if (S390_lowcore.stfl_fac_list & 0x01000000) { + if (stfl_fac_list & 0x01000000) { /* More facility bits available with stfle */ nr = __stfle_asm(stfle_fac_list, size); nr = min_t(unsigned long, (nr + 1) * 8, size * 8); diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 484065b5fa7d..a6f0b8feb12e 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -153,12 +153,7 @@ struct lowcore { __u64 vmcore_info; /* 0x0e0c */ __u8 pad_0x0e14[0x0e18-0x0e14]; /* 0x0e14 */ __u64 os_info; /* 0x0e18 */ - __u8 pad_0x0e20[0x0f00-0x0e20]; /* 0x0e20 */ - - /* Extended facility list */ - __u64 stfle_fac_list[16]; /* 0x0f00 */ - __u64 alt_stfle_fac_list[16]; /* 0x0f80 */ - __u8 pad_0x1000[0x11b0-0x1000]; /* 0x1000 */ + __u8 pad_0x0e20[0x11b0-0x0e20]; /* 0x0e20 */ /* Pointer to the machine check extended save area */ __u64 mcesad; /* 0x11b0 */ diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c index 8e1f2aee85ef..c22ea1c3ef84 100644 --- a/arch/s390/kernel/alternative.c +++ b/arch/s390/kernel/alternative.c @@ -76,8 +76,7 @@ static void __init_or_module __apply_alternatives(struct alt_instr *start, instr = (u8 *)&a->instr_offset + a->instr_offset; replacement = (u8 *)&a->repl_offset + a->repl_offset; - if (!__test_facility(a->facility, - S390_lowcore.alt_stfle_fac_list)) + if (!__test_facility(a->facility, alt_stfle_fac_list)) continue; if (unlikely(a->instrlen % 2 || a->replacementlen % 2)) { diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 96270584ef69..b4ca7cc011cb 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -75,8 +75,6 @@ int main(void) OFFSET(__LC_SUBCHANNEL_NR, lowcore, subchannel_nr); OFFSET(__LC_IO_INT_PARM, lowcore, io_int_parm); OFFSET(__LC_IO_INT_WORD, lowcore, io_int_word); - OFFSET(__LC_STFL_FAC_LIST, lowcore, stfl_fac_list); - OFFSET(__LC_STFLE_FAC_LIST, lowcore, stfle_fac_list); OFFSET(__LC_MCCK_CODE, lowcore, mcck_interruption_code); OFFSET(__LC_EXT_DAMAGE_CODE, lowcore, external_damage_code); OFFSET(__LC_MCCK_FAIL_STOR_ADDR, lowcore, failing_storage_address); diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index a361d2e70025..c2cf79d353cf 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -180,11 +180,9 @@ static noinline __init void setup_lowcore_early(void) static noinline __init void setup_facility_list(void) { - memcpy(S390_lowcore.alt_stfle_fac_list, - S390_lowcore.stfle_fac_list, - sizeof(S390_lowcore.alt_stfle_fac_list)); + memcpy(alt_stfle_fac_list, stfle_fac_list, sizeof(alt_stfle_fac_list)); if (!IS_ENABLED(CONFIG_KERNEL_NOBP)) - __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + __clear_facility(82, alt_stfle_fac_list); } static __init void detect_diag9c(void) diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 29e511f5bf06..2c5c3756644b 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -17,11 +17,11 @@ static int __init nobp_setup_early(char *str) * The user explicitely requested nobp=1, enable it and * disable the expoline support. */ - __set_facility(82, S390_lowcore.alt_stfle_fac_list); + __set_facility(82, alt_stfle_fac_list); if (IS_ENABLED(CONFIG_EXPOLINE)) nospec_disable = 1; } else { - __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + __clear_facility(82, alt_stfle_fac_list); } return 0; } @@ -29,7 +29,7 @@ early_param("nobp", nobp_setup_early); static int __init nospec_setup_early(char *str) { - __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + __clear_facility(82, alt_stfle_fac_list); return 0; } early_param("nospec", nospec_setup_early); @@ -40,7 +40,7 @@ static int __init nospec_report(void) pr_info("Spectre V2 mitigation: etokens\n"); if (__is_defined(CC_USING_EXPOLINE) && !nospec_disable) pr_info("Spectre V2 mitigation: execute trampolines\n"); - if (__test_facility(82, S390_lowcore.alt_stfle_fac_list)) + if (__test_facility(82, alt_stfle_fac_list)) pr_info("Spectre V2 mitigation: limited branch prediction\n"); return 0; } @@ -66,14 +66,14 @@ void __init nospec_auto_detect(void) */ if (__is_defined(CC_USING_EXPOLINE)) nospec_disable = 1; - __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + __clear_facility(82, alt_stfle_fac_list); } else if (__is_defined(CC_USING_EXPOLINE)) { /* * The kernel has been compiled with expolines. * Keep expolines enabled and disable nobp. */ nospec_disable = 0; - __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + __clear_facility(82, alt_stfle_fac_list); } /* * If the kernel has not been compiled with expolines the @@ -86,7 +86,7 @@ static int __init spectre_v2_setup_early(char *str) { if (str && !strncmp(str, "on", 2)) { nospec_disable = 0; - __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + __clear_facility(82, alt_stfle_fac_list); } if (str && !strncmp(str, "off", 3)) nospec_disable = 1; diff --git a/arch/s390/kernel/nospec-sysfs.c b/arch/s390/kernel/nospec-sysfs.c index 48f472bf9290..b4b5c8c21166 100644 --- a/arch/s390/kernel/nospec-sysfs.c +++ b/arch/s390/kernel/nospec-sysfs.c @@ -17,7 +17,7 @@ ssize_t cpu_show_spectre_v2(struct device *dev, return sprintf(buf, "Mitigation: etokens\n"); if (__is_defined(CC_USING_EXPOLINE) && !nospec_disable) return sprintf(buf, "Mitigation: execute trampolines\n"); - if (__test_facility(82, S390_lowcore.alt_stfle_fac_list)) + if (__test_facility(82, alt_stfle_fac_list)) return sprintf(buf, "Mitigation: limited branch prediction\n"); return sprintf(buf, "Vulnerable\n"); } diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index c92d04f876cb..82df39b17bb5 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -103,11 +103,9 @@ EXPORT_SYMBOL(cpu_have_feature); static void show_facilities(struct seq_file *m) { unsigned int bit; - long *facilities; - facilities = (long *)&S390_lowcore.stfle_fac_list; seq_puts(m, "facilities :"); - for_each_set_bit_inv(bit, facilities, MAX_FACILITY_BIT) + for_each_set_bit_inv(bit, (long *)&stfle_fac_list, MAX_FACILITY_BIT) seq_printf(m, " %d", bit); seq_putc(m, '\n'); } diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 5aab59ad5688..59c21df9ea79 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -108,6 +108,9 @@ unsigned long __bootdata_preserved(__edma); unsigned long __bootdata_preserved(__kaslr_offset); unsigned int __bootdata_preserved(zlib_dfltcc_support); EXPORT_SYMBOL(zlib_dfltcc_support); +u64 __bootdata_preserved(stfle_fac_list[16]); +EXPORT_SYMBOL(stfle_fac_list); +u64 __bootdata_preserved(alt_stfle_fac_list[16]); unsigned long VMALLOC_START; EXPORT_SYMBOL(VMALLOC_START); @@ -413,11 +416,6 @@ static void __init setup_lowcore_dat_off(void) lc->lpp = LPP_MAGIC; lc->machine_flags = S390_lowcore.machine_flags; lc->preempt_count = S390_lowcore.preempt_count; - lc->stfl_fac_list = S390_lowcore.stfl_fac_list; - memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list, - sizeof(lc->stfle_fac_list)); - memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list, - sizeof(lc->alt_stfle_fac_list)); nmi_alloc_boot_cpu(lc); lc->sys_enter_timer = S390_lowcore.sys_enter_timer; lc->exit_timer = S390_lowcore.exit_timer; diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 2fec2b80d35d..4b439967ca5d 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -275,10 +275,6 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu) lc->cregs_save_area[1] = lc->kernel_asce; lc->cregs_save_area[7] = lc->user_asce; save_access_regs((unsigned int *) lc->access_regs_save_area); - memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list, - sizeof(lc->stfle_fac_list)); - memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list, - sizeof(lc->alt_stfle_fac_list)); arch_spin_lock_setup(cpu); } diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 1296fc10f80c..582e947675e6 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -214,7 +214,7 @@ static unsigned long kvm_s390_fac_size(void) BUILD_BUG_ON(SIZE_INTERNAL > S390_ARCH_FAC_MASK_SIZE_U64); BUILD_BUG_ON(SIZE_INTERNAL > S390_ARCH_FAC_LIST_SIZE_U64); BUILD_BUG_ON(SIZE_INTERNAL * sizeof(unsigned long) > - sizeof(S390_lowcore.stfle_fac_list)); + sizeof(stfle_fac_list)); return SIZE_INTERNAL; } @@ -1458,8 +1458,8 @@ static int kvm_s390_get_machine(struct kvm *kvm, struct kvm_device_attr *attr) mach->ibc = sclp.ibc; memcpy(&mach->fac_mask, kvm->arch.model.fac_mask, S390_ARCH_FAC_LIST_SIZE_BYTE); - memcpy((unsigned long *)&mach->fac_list, S390_lowcore.stfle_fac_list, - sizeof(S390_lowcore.stfle_fac_list)); + memcpy((unsigned long *)&mach->fac_list, stfle_fac_list, + sizeof(stfle_fac_list)); VM_EVENT(kvm, 3, "GET: host ibc: 0x%4.4x, host cpuid: 0x%16.16llx", kvm->arch.model.ibc, kvm->arch.model.cpuid); @@ -2683,10 +2683,10 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) kvm->arch.model.fac_list = kvm->arch.sie_page2->fac_list; for (i = 0; i < kvm_s390_fac_size(); i++) { - kvm->arch.model.fac_mask[i] = S390_lowcore.stfle_fac_list[i] & + kvm->arch.model.fac_mask[i] = stfle_fac_list[i] & (kvm_s390_fac_base[i] | kvm_s390_fac_ext[i]); - kvm->arch.model.fac_list[i] = S390_lowcore.stfle_fac_list[i] & + kvm->arch.model.fac_list[i] = stfle_fac_list[i] & kvm_s390_fac_base[i]; } kvm->arch.model.subfuncs = kvm_s390_available_subfunc; @@ -5055,7 +5055,7 @@ static int __init kvm_s390_init(void) for (i = 0; i < 16; i++) kvm_s390_fac_base[i] |= - S390_lowcore.stfle_fac_list[i] & nonhyp_mask(i); + stfle_fac_list[i] & nonhyp_mask(i); return kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); } -- cgit v1.2.3 From 6c6a07fc7c98f31fffb0a00d2d7a5344df8b4ba8 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Wed, 5 May 2021 22:01:11 +0200 Subject: s390/irq: add union/struct to access external interrupt parameters gcc-11 warns: arch/s390/kernel/irq.c: In function do_ext_irq: arch/s390/kernel/irq.c:175:9: warning: memcpy reading 4 bytes from a region of size 0 [-Wstringop-overread] 175 | memcpy(®s->int_code, &S390_lowcore.ext_cpu_addr, 4); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Fix this by adding a struct for int_code to struct lowcore. Signed-off-by: Sven Schnelle Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/lowcore.h | 9 +++++++-- arch/s390/kernel/irq.c | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index a6f0b8feb12e..d08813c7f462 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -22,8 +22,13 @@ struct lowcore { __u32 ipl_parmblock_ptr; /* 0x0014 */ __u8 pad_0x0018[0x0080-0x0018]; /* 0x0018 */ __u32 ext_params; /* 0x0080 */ - __u16 ext_cpu_addr; /* 0x0084 */ - __u16 ext_int_code; /* 0x0086 */ + union { + struct { + __u16 ext_cpu_addr; /* 0x0084 */ + __u16 ext_int_code; /* 0x0086 */ + } __packed; + __u32 ext_int_code_addr; + } __packed; __u32 svc_int_code; /* 0x0088 */ __u16 pgm_ilc; /* 0x008c */ __u16 pgm_code; /* 0x008e */ diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 714269e10eec..169258012530 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -172,7 +172,7 @@ void noinstr do_ext_irq(struct pt_regs *regs) if (user_mode(regs)) update_timer_sys(); - memcpy(®s->int_code, &S390_lowcore.ext_cpu_addr, 4); + regs->int_code = S390_lowcore.ext_int_code_addr; regs->int_parm = S390_lowcore.ext_params; regs->int_parm_long = S390_lowcore.ext_params2; -- cgit v1.2.3 From 755112b35cdd181dffd704b42ca6a788cc0e3326 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Wed, 5 May 2021 22:01:16 +0200 Subject: s390/traps: add struct to access transactional diagnostic block gcc-11 warns: arch/s390/kernel/traps.c: In function __do_pgm_check: arch/s390/kernel/traps.c:319:17: warning: memcpy reading 256 bytes from a region of size 0 [-Wstringop-overread] 319 | memcpy(¤t->thread.trap_tdb, &S390_lowcore.pgm_tdb, 256); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Fix this by adding a struct pgm_tdb to struct lowcore and copy that. Signed-off-by: Sven Schnelle Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/lowcore.h | 6 +++++- arch/s390/include/asm/processor.h | 2 +- arch/s390/kernel/ptrace.c | 4 +++- arch/s390/kernel/traps.c | 4 ++-- 4 files changed, 11 insertions(+), 5 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index d08813c7f462..3c85c60f56ac 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -17,6 +17,10 @@ #define LC_ORDER 1 #define LC_PAGES 2 +struct pgm_tdb { + u64 data[32]; +}; + struct lowcore { __u8 pad_0x0000[0x0014-0x0000]; /* 0x0000 */ __u32 ipl_parmblock_ptr; /* 0x0014 */ @@ -184,7 +188,7 @@ struct lowcore { __u8 pad_0x1400[0x1800-0x1400]; /* 0x1400 */ /* Transaction abort diagnostic block */ - __u8 pgm_tdb[256]; /* 0x1800 */ + struct pgm_tdb pgm_tdb; /* 0x1800 */ __u8 pad_0x1900[0x2000-0x1900]; /* 0x1900 */ } __packed __aligned(8192); diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 023a15dc25a3..6d3055f7329a 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -129,7 +129,7 @@ struct thread_struct { struct runtime_instr_cb *ri_cb; struct gs_cb *gs_cb; /* Current guarded storage cb */ struct gs_cb *gs_bc_cb; /* Broadcast guarded storage cb */ - unsigned char trap_tdb[256]; /* Transaction abort diagnose block */ + struct pgm_tdb trap_tdb; /* Transaction abort diagnose block */ /* * Warning: 'fpu' is dynamically-sized. It *MUST* be at * the end. diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 18b3416fd663..0ea3d02b378d 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -975,10 +975,12 @@ static int s390_tdb_get(struct task_struct *target, struct membuf to) { struct pt_regs *regs = task_pt_regs(target); + size_t size; if (!(regs->int_code & 0x200)) return -ENODATA; - return membuf_write(&to, target->thread.trap_tdb, 256); + size = sizeof(target->thread.trap_tdb.data); + return membuf_write(&to, target->thread.trap_tdb.data, size); } static int s390_tdb_set(struct task_struct *target, diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 8dd23c703718..019c5748b607 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -36,7 +36,7 @@ static inline void __user *get_trap_ip(struct pt_regs *regs) unsigned long address; if (regs->int_code & 0x200) - address = *(unsigned long *)(current->thread.trap_tdb + 24); + address = current->thread.trap_tdb.data[3]; else address = regs->psw.addr; return (void __user *) (address - (regs->int_code >> 16)); @@ -318,7 +318,7 @@ void noinstr __do_pgm_check(struct pt_regs *regs) if (S390_lowcore.pgm_code & 0x0200) { /* transaction abort */ - memcpy(¤t->thread.trap_tdb, &S390_lowcore.pgm_tdb, 256); + current->thread.trap_tdb = S390_lowcore.pgm_tdb; } if (S390_lowcore.pgm_code & PGM_INT_CODE_PER) { -- cgit v1.2.3 From b7d91d230a119fdcc334d10c9889ce9c5e15118b Mon Sep 17 00:00:00 2001 From: Valentin Vidic Date: Tue, 27 Apr 2021 21:40:10 +0200 Subject: s390/sclp_vt220: fix console name to match device Console name reported in /proc/consoles: ttyS1 -W- (EC p ) 4:65 does not match the char device name: crw--w---- 1 root root 4, 65 May 17 12:18 /dev/ttysclp0 so debian-installer inside a QEMU s390x instance gets confused and fails to start with the following error: steal-ctty: No such file or directory Signed-off-by: Valentin Vidic Link: https://lore.kernel.org/r/20210427194010.9330-1-vvidic@valentin-vidic.from.hr Signed-off-by: Christian Borntraeger Signed-off-by: Vasily Gorbik --- arch/s390/kernel/setup.c | 2 +- drivers/s390/char/sclp_vt220.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 59c21df9ea79..f069083a7517 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -168,7 +168,7 @@ static void __init set_preferred_console(void) else if (CONSOLE_IS_3270) add_preferred_console("tty3270", 0, NULL); else if (CONSOLE_IS_VT220) - add_preferred_console("ttyS", 1, NULL); + add_preferred_console("ttysclp", 0, NULL); else if (CONSOLE_IS_HVC) add_preferred_console("hvc", 0, NULL); } diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 7f4445b0f819..2f96c31e9b7b 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -35,8 +35,8 @@ #define SCLP_VT220_MINOR 65 #define SCLP_VT220_DRIVER_NAME "sclp_vt220" #define SCLP_VT220_DEVICE_NAME "ttysclp" -#define SCLP_VT220_CONSOLE_NAME "ttyS" -#define SCLP_VT220_CONSOLE_INDEX 1 /* console=ttyS1 */ +#define SCLP_VT220_CONSOLE_NAME "ttysclp" +#define SCLP_VT220_CONSOLE_INDEX 0 /* console=ttysclp0 */ /* Representation of a single write request */ struct sclp_vt220_request { -- cgit v1.2.3 From f73c632d387a5f1528cca6032c646489610bec13 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 7 May 2021 19:12:39 +0200 Subject: s390/ipl: make parameter area accessible via struct parmarea Since commit 9a965ea95135 ("s390/kexec_file: Simplify parmarea access") we have struct parmarea which describes the layout of the kernel parameter area. Make the kernel parameter area available as global variable parmarea of type struct parmarea, which allows to easily access its members. Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/boot/head.S | 3 +++ arch/s390/include/asm/setup.h | 2 ++ arch/s390/kernel/asm-offsets.c | 3 +++ 3 files changed, 8 insertions(+) (limited to 'arch/s390') diff --git a/arch/s390/boot/head.S b/arch/s390/boot/head.S index dacb7813f982..51693cfb65c2 100644 --- a/arch/s390/boot/head.S +++ b/arch/s390/boot/head.S @@ -401,6 +401,7 @@ SYM_CODE_END(startup_pgm_check_handler) # Must be keept in sync with struct parmarea in setup.h # .org PARMAREA +SYM_DATA_START(parmarea) .quad 0 # IPL_DEVICE .quad 0 # INITRD_START .quad 0 # INITRD_SIZE @@ -411,6 +412,8 @@ SYM_CODE_END(startup_pgm_check_handler) .org COMMAND_LINE .byte "root=/dev/ram0 ro" .byte 0 + .org PARMAREA+__PARMAREA_SIZE +SYM_DATA_END(parmarea) .org EARLY_SCCB_OFFSET .fill 4096 diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index 3e388fa208d4..29baab03f091 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -78,6 +78,8 @@ struct parmarea { char command_line[ARCH_COMMAND_LINE_SIZE]; /* 0x10480 */ }; +extern struct parmarea parmarea; + extern unsigned int zlib_dfltcc_support; #define ZLIB_DFLTCC_DISABLED 0 #define ZLIB_DFLTCC_FULL 1 diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index b4ca7cc011cb..f53605a3dfcd 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -15,6 +15,7 @@ #include #include #include +#include #include int main(void) @@ -155,5 +156,7 @@ int main(void) OFFSET(__KEXEC_SHA_REGION_START, kexec_sha_region, start); OFFSET(__KEXEC_SHA_REGION_LEN, kexec_sha_region, len); DEFINE(__KEXEC_SHA_REGION_SIZE, sizeof(struct kexec_sha_region)); + /* sizeof kernel parameter area */ + DEFINE(__PARMAREA_SIZE, sizeof(struct parmarea)); return 0; } -- cgit v1.2.3 From 27c1dac0b6d8c3b640e24a1b762c7244fbb116fd Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 7 May 2021 19:12:54 +0200 Subject: s390/boot: access kernel command line via parmarea Access the kernel command line via parmarea instead of using the COMMAND_LINE define. With this the following gcc11 warning is removed: arch/s390/boot/ipl_parm.c: In function ‘setup_boot_command_line’: arch/s390/boot/ipl_parm.c:168:50: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=] Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/boot/ipl_parm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c index 865c66cb9b79..3485a1d4e97b 100644 --- a/arch/s390/boot/ipl_parm.c +++ b/arch/s390/boot/ipl_parm.c @@ -165,12 +165,12 @@ static inline int has_ebcdic_char(const char *str) void setup_boot_command_line(void) { - COMMAND_LINE[ARCH_COMMAND_LINE_SIZE - 1] = 0; + parmarea.command_line[ARCH_COMMAND_LINE_SIZE - 1] = 0; /* convert arch command line to ascii if necessary */ - if (has_ebcdic_char(COMMAND_LINE)) - EBCASC(COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); + if (has_ebcdic_char(parmarea.command_line)) + EBCASC(parmarea.command_line, ARCH_COMMAND_LINE_SIZE); /* copy arch command line */ - strcpy(early_command_line, strim(COMMAND_LINE)); + strcpy(early_command_line, strim(parmarea.command_line)); /* append IPL PARM data to the boot command line */ if (!is_prot_virt_guest() && ipl_block_valid) -- cgit v1.2.3 From bdb8c9353ead1a4176e9ba034ea7ceb210c8a59c Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Thu, 6 May 2021 20:06:00 +0200 Subject: s390/mm: ensure switch_mm() is executed with interrupts disabled Architecture callback switch_mm() is allowed to be called with enabled interrupts. However, our implementation of switch_mm() does not expect that. Let's follow other architectures and make sure switch_mm() is always executed with interrupts disabled, regardless of what happens with the generic kernel code in the future. Signed-off-by: Alexander Gordeev Reviewed-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/mmu_context.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index e7cffc7b5c2f..c7937f369e62 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h @@ -70,8 +70,8 @@ static inline int init_new_context(struct task_struct *tsk, return 0; } -static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk) +static inline void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk) { int cpu = smp_processor_id(); @@ -85,6 +85,17 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, if (prev != next) cpumask_clear_cpu(cpu, &prev->context.cpu_attach_mask); } +#define switch_mm_irqs_off switch_mm_irqs_off + +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk) +{ + unsigned long flags; + + local_irq_save(flags); + switch_mm_irqs_off(prev, next, tsk); + local_irq_restore(flags); +} #define finish_arch_post_lock_switch finish_arch_post_lock_switch static inline void finish_arch_post_lock_switch(void) -- cgit v1.2.3 From 5789284710aa121416524acc54ac0d8c27c3c2ef Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Thu, 6 May 2021 16:26:52 +0200 Subject: s390/smp: reallocate IPL CPU lowcore The lowcore for IPL CPU is special. It is allocated early in the boot process using memblock and never freed since. The reason is pcpu_alloc_lowcore() and pcpu_free_lowcore() routines use page allocator which is not available when the IPL CPU is getting initialized. Similar problem is already addressed for stacks - once the virtual memory is available the early boot stacks get re- allocated. Doing the same for lowcore will allow freeing the IPL CPU lowcore and make no difference between the boot and secondary CPUs. Signed-off-by: Alexander Gordeev Reviewed-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/setup.c | 21 ------------------- arch/s390/kernel/smp.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 21 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index f069083a7517..146d01700a55 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -341,27 +341,6 @@ int __init arch_early_irq_init(void) return 0; } -static int __init stack_realloc(void) -{ - unsigned long old, new; - - old = S390_lowcore.async_stack - STACK_INIT_OFFSET; - new = stack_alloc(); - if (!new) - panic("Couldn't allocate async stack"); - WRITE_ONCE(S390_lowcore.async_stack, new + STACK_INIT_OFFSET); - free_pages(old, THREAD_SIZE_ORDER); - - old = S390_lowcore.mcck_stack - STACK_INIT_OFFSET; - new = stack_alloc(); - if (!new) - panic("Couldn't allocate machine check stack"); - WRITE_ONCE(S390_lowcore.mcck_stack, new + STACK_INIT_OFFSET); - memblock_free_late(old, THREAD_SIZE); - return 0; -} -early_initcall(stack_realloc); - void __init arch_call_rest_init(void) { unsigned long stack; diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 4b439967ca5d..1e1d61a4d294 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -1234,3 +1234,55 @@ out: return rc; } subsys_initcall(s390_smp_init); + +static __always_inline void set_new_lowcore(struct lowcore *lc) +{ + struct lowcore *old_lc = &S390_lowcore; + struct lowcore *new_lc = lc; + u32 pfx; + register struct lowcore *reg2 asm ("2") = new_lc; + register unsigned long reg3 asm ("3") = sizeof(*reg2); + register struct lowcore *reg4 asm ("4") = old_lc; + register unsigned long reg5 asm ("5") = sizeof(*reg4); + + asm volatile( + " st 2,%[pfx]\n" + " mvcl 2,4\n" + " spx %[pfx]\n" + : "+&d" (reg2), "+&d" (reg3), + "+&d" (reg4), "+&d" (reg5), [pfx] "=Q" (pfx) + : : "memory", "cc"); +} + +static int __init smp_reinit_ipl_cpu(void) +{ + unsigned long async_stack, nodat_stack, mcck_stack; + struct lowcore *lc, *lc_ipl; + unsigned long flags; + + lc_ipl = lowcore_ptr[0]; + lc = (struct lowcore *) __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER); + nodat_stack = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER); + async_stack = stack_alloc(); + mcck_stack = stack_alloc(); + if (!lc || !nodat_stack || !async_stack || !mcck_stack) + panic("Couldn't allocate memory"); + + local_irq_save(flags); + local_mcck_disable(); + set_new_lowcore(lc); + S390_lowcore.nodat_stack = nodat_stack + STACK_INIT_OFFSET; + S390_lowcore.async_stack = async_stack + STACK_INIT_OFFSET; + S390_lowcore.mcck_stack = mcck_stack + STACK_INIT_OFFSET; + lowcore_ptr[0] = lc; + pcpu_devices[0].lowcore = lc; + local_mcck_enable(); + local_irq_restore(flags); + + free_pages(lc_ipl->async_stack - STACK_INIT_OFFSET, THREAD_SIZE_ORDER); + memblock_free_late(lc_ipl->mcck_stack - STACK_INIT_OFFSET, THREAD_SIZE); + memblock_free_late((unsigned long) lc_ipl, sizeof(*lc_ipl)); + + return 0; +} +early_initcall(smp_reinit_ipl_cpu); -- cgit v1.2.3 From 587704efb3dea5685a2f571b75bd3dc47f73fec1 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Thu, 6 May 2021 16:26:53 +0200 Subject: s390/smp: do not preserve boot CPU lowcore on hotplug Once the kernel is running the boot CPU lowcore becomes freeable and does not differ from the secondary CPU ones in any way. Make use of it and do not preserve the boot CPU lowcore on unplugging. That allows returning unused memory when the boot CPU is offline and makes the code more clear. Signed-off-by: Alexander Gordeev Reviewed-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/smp.c | 47 ++++++++++++++++++----------------------------- 1 file changed, 18 insertions(+), 29 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 1e1d61a4d294..eaca08b1688f 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -194,20 +194,12 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu) unsigned long async_stack, nodat_stack, mcck_stack; struct lowcore *lc; - if (pcpu != &pcpu_devices[0]) { - pcpu->lowcore = (struct lowcore *) - __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER); - nodat_stack = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER); - if (!pcpu->lowcore || !nodat_stack) - goto out; - } else { - nodat_stack = pcpu->lowcore->nodat_stack - STACK_INIT_OFFSET; - } + lc = (struct lowcore *) __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER); + nodat_stack = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER); async_stack = stack_alloc(); mcck_stack = stack_alloc(); - if (!async_stack || !mcck_stack) - goto out_stack; - lc = pcpu->lowcore; + if (!lc || !nodat_stack || !async_stack || !mcck_stack) + goto out; memcpy(lc, &S390_lowcore, 512); memset((char *) lc + 512, 0, sizeof(*lc) - 512); lc->async_stack = async_stack + STACK_INIT_OFFSET; @@ -220,40 +212,37 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu) lc->return_lpswe = gen_lpswe(__LC_RETURN_PSW); lc->return_mcck_lpswe = gen_lpswe(__LC_RETURN_MCCK_PSW); if (nmi_alloc_per_cpu(lc)) - goto out_stack; + goto out; lowcore_ptr[cpu] = lc; + pcpu->lowcore = lc; pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, (u32)(unsigned long) lc); return 0; -out_stack: +out: stack_free(mcck_stack); stack_free(async_stack); -out: - if (pcpu != &pcpu_devices[0]) { - free_pages(nodat_stack, THREAD_SIZE_ORDER); - free_pages((unsigned long) pcpu->lowcore, LC_ORDER); - } + free_pages(nodat_stack, THREAD_SIZE_ORDER); + free_pages((unsigned long) lc, LC_ORDER); return -ENOMEM; } static void pcpu_free_lowcore(struct pcpu *pcpu) { - unsigned long async_stack, nodat_stack, mcck_stack, lowcore; - - nodat_stack = pcpu->lowcore->nodat_stack - STACK_INIT_OFFSET; - async_stack = pcpu->lowcore->async_stack - STACK_INIT_OFFSET; - mcck_stack = pcpu->lowcore->mcck_stack - STACK_INIT_OFFSET; - lowcore = (unsigned long) pcpu->lowcore; + unsigned long async_stack, nodat_stack, mcck_stack; + struct lowcore *lc; + lc = pcpu->lowcore; + nodat_stack = lc->nodat_stack - STACK_INIT_OFFSET; + async_stack = lc->async_stack - STACK_INIT_OFFSET; + mcck_stack = lc->mcck_stack - STACK_INIT_OFFSET; pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, 0); lowcore_ptr[pcpu - pcpu_devices] = NULL; - nmi_free_per_cpu(pcpu->lowcore); + pcpu->lowcore = NULL; + nmi_free_per_cpu(lc); stack_free(async_stack); stack_free(mcck_stack); - if (pcpu == &pcpu_devices[0]) - return; free_pages(nodat_stack, THREAD_SIZE_ORDER); - free_pages(lowcore, LC_ORDER); + free_pages((unsigned long) lc, LC_ORDER); } static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu) -- cgit v1.2.3 From d2e834c62d7fa467a534758f7994e981ce163c80 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Thu, 6 May 2021 16:26:54 +0200 Subject: s390/smp: remove redundant pcpu::lowcore member Per-CPU pointer to lowcore is stored in global lowcore_ptr[] array and duplicated in struct pcpu::lowcore member. This update removes the redundancy. Signed-off-by: Alexander Gordeev Reviewed-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/smp.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index eaca08b1688f..e137c840a4d3 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -74,7 +74,6 @@ enum { static DEFINE_PER_CPU(struct cpu *, cpu_device); struct pcpu { - struct lowcore *lowcore; /* lowcore page(s) for the cpu */ unsigned long ec_mask; /* bit mask for ec_xxx functions */ unsigned long ec_clk; /* sigp timestamp for ec_xxx */ signed char state; /* physical cpu state */ @@ -214,7 +213,6 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu) if (nmi_alloc_per_cpu(lc)) goto out; lowcore_ptr[cpu] = lc; - pcpu->lowcore = lc; pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, (u32)(unsigned long) lc); return 0; @@ -230,14 +228,15 @@ static void pcpu_free_lowcore(struct pcpu *pcpu) { unsigned long async_stack, nodat_stack, mcck_stack; struct lowcore *lc; + int cpu; - lc = pcpu->lowcore; + cpu = pcpu - pcpu_devices; + lc = lowcore_ptr[cpu]; nodat_stack = lc->nodat_stack - STACK_INIT_OFFSET; async_stack = lc->async_stack - STACK_INIT_OFFSET; mcck_stack = lc->mcck_stack - STACK_INIT_OFFSET; pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, 0); - lowcore_ptr[pcpu - pcpu_devices] = NULL; - pcpu->lowcore = NULL; + lowcore_ptr[cpu] = NULL; nmi_free_per_cpu(lc); stack_free(async_stack); stack_free(mcck_stack); @@ -247,7 +246,7 @@ static void pcpu_free_lowcore(struct pcpu *pcpu) static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu) { - struct lowcore *lc = pcpu->lowcore; + struct lowcore *lc = lowcore_ptr[cpu]; cpumask_set_cpu(cpu, &init_mm.context.cpu_attach_mask); cpumask_set_cpu(cpu, mm_cpumask(&init_mm)); @@ -269,8 +268,11 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu) static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk) { - struct lowcore *lc = pcpu->lowcore; + struct lowcore *lc; + int cpu; + cpu = pcpu - pcpu_devices; + lc = lowcore_ptr[cpu]; lc->kernel_stack = (unsigned long) task_stack_page(tsk) + THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs); lc->current_task = (unsigned long) tsk; @@ -286,8 +288,11 @@ static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk) static void pcpu_start_fn(struct pcpu *pcpu, void (*func)(void *), void *data) { - struct lowcore *lc = pcpu->lowcore; + struct lowcore *lc; + int cpu; + cpu = pcpu - pcpu_devices; + lc = lowcore_ptr[cpu]; lc->restart_stack = lc->nodat_stack; lc->restart_fn = (unsigned long) func; lc->restart_data = (unsigned long) data; @@ -372,7 +377,7 @@ void smp_call_online_cpu(void (*func)(void *), void *data) */ void smp_call_ipl_cpu(void (*func)(void *), void *data) { - struct lowcore *lc = pcpu_devices->lowcore; + struct lowcore *lc = lowcore_ptr[0]; if (pcpu_devices[0].address == stap()) lc = &S390_lowcore; @@ -585,18 +590,21 @@ EXPORT_SYMBOL(smp_ctl_clear_bit); int smp_store_status(int cpu) { - struct pcpu *pcpu = pcpu_devices + cpu; + struct lowcore *lc; + struct pcpu *pcpu; unsigned long pa; - pa = __pa(&pcpu->lowcore->floating_pt_save_area); + pcpu = pcpu_devices + cpu; + lc = lowcore_ptr[cpu]; + pa = __pa(&lc->floating_pt_save_area); if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_STATUS_AT_ADDRESS, pa) != SIGP_CC_ORDER_CODE_ACCEPTED) return -EIO; if (!MACHINE_HAS_VX && !MACHINE_HAS_GS) return 0; - pa = __pa(pcpu->lowcore->mcesad & MCESA_ORIGIN_MASK); + pa = __pa(lc->mcesad & MCESA_ORIGIN_MASK); if (MACHINE_HAS_GS) - pa |= pcpu->lowcore->mcesad & MCESA_LC_MASK; + pa |= lc->mcesad & MCESA_LC_MASK; if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS, pa) != SIGP_CC_ORDER_CODE_ACCEPTED) return -EIO; @@ -997,7 +1005,6 @@ void __init smp_prepare_boot_cpu(void) WARN_ON(!cpu_present(0) || !cpu_online(0)); pcpu->state = CPU_STATE_CONFIGURED; - pcpu->lowcore = (struct lowcore *)(unsigned long) store_prefix(); S390_lowcore.percpu_offset = __per_cpu_offset[0]; smp_cpu_set_polarization(0, POLARIZATION_UNKNOWN); } @@ -1264,7 +1271,6 @@ static int __init smp_reinit_ipl_cpu(void) S390_lowcore.async_stack = async_stack + STACK_INIT_OFFSET; S390_lowcore.mcck_stack = mcck_stack + STACK_INIT_OFFSET; lowcore_ptr[0] = lc; - pcpu_devices[0].lowcore = lc; local_mcck_enable(); local_irq_restore(flags); -- cgit v1.2.3 From 17c0b86e5fab71f6f1410ae31545b486e357dbe4 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 5 May 2021 10:28:21 +0200 Subject: s390/ccwgroup: use BUS_NOTIFY_UNBOUND_DRIVER to trigger ungrouping ccwgroup_notifier() currently listens for BUS_NOTIFY_UNBIND_DRIVER events, and triggers an ungrouping for the affected device. Looking at __device_release_driver(), we can wait for a little longer until the driver has been fully unbound and eg. bus->remove() has been called. So listen for BUS_NOTIFY_UNBOUND_DRIVER instead. Due to locking the current code should work just fine, but this clarifies our intent. Signed-off-by: Julian Wiedmann Reviewed-by: Vineeth Vijayan Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/ccwgroup.h | 3 +-- drivers/s390/cio/ccwgroup.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/ccwgroup.h b/arch/s390/include/asm/ccwgroup.h index ad3acb1e882b..20f169b6db4e 100644 --- a/arch/s390/include/asm/ccwgroup.h +++ b/arch/s390/include/asm/ccwgroup.h @@ -11,8 +11,7 @@ struct ccw_driver; * @count: number of attached slave devices * @dev: embedded device structure * @cdev: variable number of slave devices, allocated as needed - * @ungroup_work: work to be done when a ccwgroup notifier has action - * type %BUS_NOTIFY_UNBIND_DRIVER + * @ungroup_work: used to ungroup the ccwgroup device */ struct ccwgroup_device { enum { diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 7e5ceea62731..9748165e08e9 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -401,7 +401,7 @@ static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, { struct ccwgroup_device *gdev = to_ccwgroupdev(data); - if (action == BUS_NOTIFY_UNBIND_DRIVER) { + if (action == BUS_NOTIFY_UNBOUND_DRIVER) { get_device(&gdev->dev); schedule_work(&gdev->ungroup_work); } -- cgit v1.2.3 From 42e8d652438f5ddf04e5dac299cb5e623d113dc0 Mon Sep 17 00:00:00 2001 From: Fabrice Fontaine Date: Mon, 10 May 2021 07:31:33 +0200 Subject: s390: disable SSP when needed Though -nostdlib is passed in PURGATORY_LDFLAGS and -ffreestanding in KBUILD_CFLAGS_DECOMPRESSOR, -fno-stack-protector must also be passed to avoid linking errors related to undefined references to '__stack_chk_guard' and '__stack_chk_fail' if toolchain enforces -fstack-protector. Fixes - https://gitlab.com/kubu93/buildroot/-/jobs/1247043361 Signed-off-by: Fabrice Fontaine Signed-off-by: Vasily Gorbik Reviewed-by: Alexander Egorenkov Tested-by: Alexander Egorenkov Link: https://lore.kernel.org/r/20210510053133.1220167-1-fontaine.fabrice@gmail.com Signed-off-by: Vasily Gorbik --- arch/s390/Makefile | 1 + arch/s390/purgatory/Makefile | 1 + 2 files changed, 2 insertions(+) (limited to 'arch/s390') diff --git a/arch/s390/Makefile b/arch/s390/Makefile index e443ed9947bd..098abe3a56f3 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -28,6 +28,7 @@ KBUILD_CFLAGS_DECOMPRESSOR += -DDISABLE_BRANCH_PROFILING -D__NO_FORTIFY KBUILD_CFLAGS_DECOMPRESSOR += -fno-delete-null-pointer-checks -msoft-float -mbackchain KBUILD_CFLAGS_DECOMPRESSOR += -fno-asynchronous-unwind-tables KBUILD_CFLAGS_DECOMPRESSOR += -ffreestanding +KBUILD_CFLAGS_DECOMPRESSOR += -fno-stack-protector KBUILD_CFLAGS_DECOMPRESSOR += $(call cc-disable-warning, address-of-packed-member) KBUILD_CFLAGS_DECOMPRESSOR += $(if $(CONFIG_DEBUG_INFO),-g) KBUILD_CFLAGS_DECOMPRESSOR += $(if $(CONFIG_DEBUG_INFO_DWARF4), $(call cc-option, -gdwarf-4,)) diff --git a/arch/s390/purgatory/Makefile b/arch/s390/purgatory/Makefile index c57f8c40e992..21c4ebe29b9a 100644 --- a/arch/s390/purgatory/Makefile +++ b/arch/s390/purgatory/Makefile @@ -24,6 +24,7 @@ KBUILD_CFLAGS := -fno-strict-aliasing -Wall -Wstrict-prototypes KBUILD_CFLAGS += -Wno-pointer-sign -Wno-sign-compare KBUILD_CFLAGS += -fno-zero-initialized-in-bss -fno-builtin -ffreestanding KBUILD_CFLAGS += -c -MD -Os -m64 -msoft-float -fno-common +KBUILD_CFLAGS += -fno-stack-protector KBUILD_CFLAGS += $(CLANG_FLAGS) KBUILD_CFLAGS += $(call cc-option,-fno-PIE) KBUILD_AFLAGS := $(filter-out -DCC_USING_EXPOLINE,$(KBUILD_AFLAGS)) -- cgit v1.2.3 From 5d3516b3647621d5a1180672ea9e0817fb718ada Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 27 May 2021 17:24:20 -0700 Subject: s390: appldata depends on PROC_SYSCTL APPLDATA_BASE should depend on PROC_SYSCTL instead of PROC_FS. Building with PROC_FS but not PROC_SYSCTL causes a build error, since appldata_base.c uses data and APIs from fs/proc/proc_sysctl.c. arch/s390/appldata/appldata_base.o: in function `appldata_generic_handler': appldata_base.c:(.text+0x192): undefined reference to `sysctl_vals' Fixes: c185b783b099 ("[S390] Remove config options.") Signed-off-by: Randy Dunlap Cc: Heiko Carstens Cc: Vasily Gorbik Cc: Christian Borntraeger Cc: linux-s390@vger.kernel.org Signed-off-by: Vasily Gorbik Link: https://lore.kernel.org/r/20210528002420.17634-1-rdunlap@infradead.org Signed-off-by: Vasily Gorbik --- arch/s390/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/s390') diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index d6582f57e0a1..93488bbf491b 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -854,7 +854,7 @@ config CMM_IUCV config APPLDATA_BASE def_bool n prompt "Linux - VM Monitor Stream, base infrastructure" - depends on PROC_FS + depends on PROC_SYSCTL help This provides a kernel interface for creating and updating z/VM APPLDATA monitor records. The monitor records are updated at certain time -- cgit v1.2.3 From c63c473f18a7b72ba5cdc37b9a564dc2a4b625d5 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Mon, 10 May 2021 21:10:15 +0200 Subject: s390/cio: add tpi.h header file For future work we need the struct tpi_info declaration in asm/ptrace.h. Due to circular dependencies it cannot stay in asm/lowcore.h or asm/cio.h, which would be the preferred location. Therefore add it in its own header file. Also fix a typo in the length of a reserved field that did not have a functional effect beyond an incorrect field value in the s390_cio_tpi tracepoint. Fixes: 2ab59de7c5ce ("s390/cio: Consolidate inline assemblies and related data definitions") Signed-off-by: Sven Schnelle Acked-by: Peter Oberparleiter Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/cio.h | 1 + arch/s390/include/asm/tpi.h | 20 ++++++++++++++++++++ drivers/s390/cio/cio.h | 13 +------------ 3 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 arch/s390/include/asm/tpi.h (limited to 'arch/s390') diff --git a/arch/s390/include/asm/cio.h b/arch/s390/include/asm/cio.h index ac02df906cae..f58c92f28701 100644 --- a/arch/s390/include/asm/cio.h +++ b/arch/s390/include/asm/cio.h @@ -9,6 +9,7 @@ #include #include #include +#include #define LPM_ANYPATH 0xff #define __MAX_CSSID 0 diff --git a/arch/s390/include/asm/tpi.h b/arch/s390/include/asm/tpi.h new file mode 100644 index 000000000000..f88911180b02 --- /dev/null +++ b/arch/s390/include/asm/tpi.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _ASM_S390_TPI_H +#define _ASM_S390_TPI_H + +#include +#include + +/* I/O-Interruption Code as stored by TEST PENDING INTERRUPTION (TPI). */ +struct tpi_info { + struct subchannel_id schid; + u32 intparm; + u32 adapter_IO:1; + u32 directed_irq:1; + u32 isc:3; + u32 :12; + u32 type:3; + u32 :12; +} __packed __aligned(4); + +#endif /* _ASM_S390_TPI_H */ diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index dcdaba689b20..1cb9daf9c645 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "chsc.h" /* @@ -46,18 +47,6 @@ struct pmcw { /* ... in an operand exception. */ } __attribute__ ((packed)); -/* I/O-Interruption Code as stored by TEST PENDING INTERRUPTION (TPI). */ -struct tpi_info { - struct subchannel_id schid; - u32 intparm; - u32 adapter_IO:1; - u32 directed_irq:1; - u32 isc:3; - u32 :27; - u32 type:3; - u32 :12; -} __packed __aligned(4); - /* Target SCHIB configuration. */ struct schib_config { u64 mba; -- cgit v1.2.3 From 34bbeed07494cc0d64d0c7a953230883a4d78f6f Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Mon, 10 May 2021 21:10:16 +0200 Subject: s390: add struct tpi_info to struct pt_regs To avoid casting ptrace members, add a union containing both struct tpi_info and explicit int_code/int_parm members. Signed-off-by: Sven Schnelle Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/ptrace.h | 12 +++++++++--- arch/s390/include/asm/tpi.h | 4 ++++ arch/s390/include/uapi/asm/schid.h | 3 +++ drivers/s390/cio/airq.c | 2 +- drivers/s390/cio/cio.c | 2 +- 5 files changed, 18 insertions(+), 5 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index f828be78937f..c7850d649373 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h @@ -9,6 +9,7 @@ #include #include +#include #define PIF_SYSCALL 0 /* inside a system call */ #define PIF_SYSCALL_RESTART 1 /* restart the current system call */ @@ -86,9 +87,14 @@ struct pt_regs }; }; unsigned long orig_gpr2; - unsigned int int_code; - unsigned int int_parm; - unsigned long int_parm_long; + union { + struct { + unsigned int int_code; + unsigned int int_parm; + unsigned long int_parm_long; + }; + struct tpi_info tpi_info; + }; unsigned long flags; unsigned long cr1; }; diff --git a/arch/s390/include/asm/tpi.h b/arch/s390/include/asm/tpi.h index f88911180b02..1ac538b8cbf5 100644 --- a/arch/s390/include/asm/tpi.h +++ b/arch/s390/include/asm/tpi.h @@ -5,6 +5,8 @@ #include #include +#ifndef __ASSEMBLY__ + /* I/O-Interruption Code as stored by TEST PENDING INTERRUPTION (TPI). */ struct tpi_info { struct subchannel_id schid; @@ -17,4 +19,6 @@ struct tpi_info { u32 :12; } __packed __aligned(4); +#endif /* __ASSEMBLY__ */ + #endif /* _ASM_S390_TPI_H */ diff --git a/arch/s390/include/uapi/asm/schid.h b/arch/s390/include/uapi/asm/schid.h index 58fca6f48410..a3e1cf168553 100644 --- a/arch/s390/include/uapi/asm/schid.h +++ b/arch/s390/include/uapi/asm/schid.h @@ -4,6 +4,8 @@ #include +#ifndef __ASSEMBLY__ + struct subchannel_id { __u32 cssid : 8; __u32 : 4; @@ -13,5 +15,6 @@ struct subchannel_id { __u32 sch_no : 16; } __attribute__ ((packed, aligned(4))); +#endif /* __ASSEMBLY__ */ #endif /* _UAPIASM_SCHID_H */ diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index cb466ed7eb5e..e56535c99888 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -93,7 +93,7 @@ static irqreturn_t do_airq_interrupt(int irq, void *dummy) struct hlist_head *head; set_cpu_flag(CIF_NOHZ_DELAY); - tpi_info = (struct tpi_info *) &get_irq_regs()->int_code; + tpi_info = &get_irq_regs()->tpi_info; trace_s390_cio_adapter_int(tpi_info); head = &airq_lists[tpi_info->isc]; rcu_read_lock(); diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 6d716db2a46a..923f5ca4f5e6 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -536,7 +536,7 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy) struct irb *irb; set_cpu_flag(CIF_NOHZ_DELAY); - tpi_info = (struct tpi_info *) &get_irq_regs()->int_code; + tpi_info = &get_irq_regs()->tpi_info; trace_s390_cio_interrupt(tpi_info); irb = this_cpu_ptr(&cio_irb); sch = (struct subchannel *)(unsigned long) tpi_info->intparm; -- cgit v1.2.3 From 0a500447b847f87b06ae814253376d983ef98e04 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Mon, 10 May 2021 21:10:18 +0200 Subject: s390: use struct tpi_info in lowcore.h Signed-off-by: Sven Schnelle Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/lowcore.h | 13 +++++++++---- arch/s390/kernel/irq.c | 4 ++-- drivers/s390/cio/trace.h | 6 ++---- 3 files changed, 13 insertions(+), 10 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 3c85c60f56ac..adf7f473ad8f 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -48,10 +48,15 @@ struct lowcore { __u8 pad_0x00a4[0x00a8-0x00a4]; /* 0x00a4 */ __u64 trans_exc_code; /* 0x00a8 */ __u64 monitor_code; /* 0x00b0 */ - __u16 subchannel_id; /* 0x00b8 */ - __u16 subchannel_nr; /* 0x00ba */ - __u32 io_int_parm; /* 0x00bc */ - __u32 io_int_word; /* 0x00c0 */ + union { + struct { + __u16 subchannel_id; /* 0x00b8 */ + __u16 subchannel_nr; /* 0x00ba */ + __u32 io_int_parm; /* 0x00bc */ + __u32 io_int_word; /* 0x00c0 */ + }; + struct tpi_info tpi_info; /* 0x00b8 */ + }; __u8 pad_0x00c4[0x00c8-0x00c4]; /* 0x00c4 */ __u32 stfl_fac_list; /* 0x00c8 */ __u8 pad_0x00cc[0x00e8-0x00cc]; /* 0x00cc */ diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 169258012530..c0df4060d28d 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -146,8 +146,8 @@ void noinstr do_io_irq(struct pt_regs *regs) account_idle_time_irq(); do { - memcpy(®s->int_code, &S390_lowcore.subchannel_id, 12); - if (S390_lowcore.io_int_word & BIT(31)) + regs->tpi_info = S390_lowcore.tpi_info; + if (S390_lowcore.tpi_info.adapter_IO) do_irq_async(regs, THIN_INTERRUPT); else do_irq_async(regs, IO_INTERRUPT); diff --git a/drivers/s390/cio/trace.h b/drivers/s390/cio/trace.h index 4803139bce14..86993de25345 100644 --- a/drivers/s390/cio/trace.h +++ b/drivers/s390/cio/trace.h @@ -168,10 +168,8 @@ TRACE_EVENT(s390_cio_tpi, memset(&__entry->tpi_info, 0, sizeof(struct tpi_info)); else if (addr) __entry->tpi_info = *addr; - else { - memcpy(&__entry->tpi_info, &S390_lowcore.subchannel_id, - sizeof(struct tpi_info)); - } + else + __entry->tpi_info = S390_lowcore.tpi_info; __entry->cssid = __entry->tpi_info.schid.cssid; __entry->ssid = __entry->tpi_info.schid.ssid; __entry->schno = __entry->tpi_info.schid.sch_no; -- cgit v1.2.3 From 21aadf2eb055187ae8724997e6aca76e0d548447 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 1 Jun 2021 10:59:09 +0200 Subject: s390/lowcore: remove superfluous __packed annotations Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/lowcore.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index adf7f473ad8f..47bde5a20a41 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -30,9 +30,9 @@ struct lowcore { struct { __u16 ext_cpu_addr; /* 0x0084 */ __u16 ext_int_code; /* 0x0086 */ - } __packed; + }; __u32 ext_int_code_addr; - } __packed; + }; __u32 svc_int_code; /* 0x0088 */ __u16 pgm_ilc; /* 0x008c */ __u16 pgm_code; /* 0x008e */ -- cgit v1.2.3 From 20232b18e5345385851ae7e2b7ef9a7cf983333a Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 17 May 2021 08:18:13 +0200 Subject: s390/mcck: cleanup use of cleanup_sie_mcck cleanup_sie_mcck label is called from a single location only and thus does not need to be a subroutine. Move the labelled code to the caller - by doing that the SIE critical section checks appear next to each other and the SIE cleanup becomes bit more readable. Signed-off-by: Alexander Gordeev Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/entry.S | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index a070a5d10409..7cfa08b67cae 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -214,7 +214,7 @@ ENTRY(sie64a) # are some corner cases (e.g. runtime instrumentation) where ILC is unpredictable. # Other instructions between sie64a and .Lsie_done should not cause program # interrupts. So lets use 3 nops as a landing pad for all possible rewinds. -# See also .Lcleanup_sie_mcck/.Lcleanup_sie_int +# See also .Lcleanup_sie .Lrewind_pad6: nopr 7 .Lrewind_pad4: @@ -399,7 +399,7 @@ ENTRY(\name) lghi %r13,.Lsie_done - .Lsie_gmap clgr %r14,%r13 jhe 0f - brasl %r14,.Lcleanup_sie_int + brasl %r14,.Lcleanup_sie #endif 0: CHECK_STACK __LC_SAVE_AREA_ASYNC aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) @@ -547,7 +547,13 @@ ENTRY(mcck_int_handler) lghi %r13,.Lsie_done - .Lsie_gmap clgr %r14,%r13 jhe .Lmcck_stack - brasl %r14,.Lcleanup_sie_mcck + larl %r13,.Lsie_entry + slgr %r9,%r13 + lghi %r13,.Lsie_skip - .Lsie_entry + clgr %r9,%r13 + jhe 5f + oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST +5: brasl %r14,.Lcleanup_sie #endif j .Lmcck_stack .Lmcck_user: @@ -649,21 +655,13 @@ ENDPROC(stack_overflow) #endif #if IS_ENABLED(CONFIG_KVM) -.Lcleanup_sie_mcck: - larl %r13,.Lsie_entry - slgr %r9,%r13 - lghi %r13,.Lsie_skip - .Lsie_entry - clgr %r9,%r13 - jhe .Lcleanup_sie_int - oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST -.Lcleanup_sie_int: +.Lcleanup_sie: BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) lg %r9,__SF_SIE_CONTROL(%r15) # get control block pointer ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE lctlg %c1,%c1,__LC_KERNEL_ASCE larl %r9,sie_exit # skip forward to sie_exit BR_EX %r14,%r13 - #endif .section .rodata, "a" #define SYSCALL(esame,emu) .quad __s390x_ ## esame -- cgit v1.2.3 From 113af8e6f457bedc700bdcfc6848e3451394d74f Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Mon, 17 May 2021 23:46:44 -0500 Subject: s390/decompressor: replace use of perl with simple sed/tr Use simple sed/tr instead of perl to generate decompressor symbols file with the same result. Signed-off-by: Rob Landley Signed-off-by: Vasily Gorbik [gor: changed commit message] Link: https://lore.kernel.org/r/a48c51f8-5fe4-87e7-284e-c96e2381801a@landley.net Signed-off-by: Vasily Gorbik --- arch/s390/boot/compressed/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/s390') diff --git a/arch/s390/boot/compressed/Makefile b/arch/s390/boot/compressed/Makefile index de18dab518bb..e941b165bd4f 100644 --- a/arch/s390/boot/compressed/Makefile +++ b/arch/s390/boot/compressed/Makefile @@ -33,7 +33,7 @@ $(obj)/vmlinux.syms: $(obj)/vmlinux.lds $(objtree)/arch/s390/boot/startup.a $(OB quiet_cmd_dumpsyms = DUMPSYMS $< define cmd_dumpsyms - $(NM) -n -S --format=bsd "$<" | $(PERL) -ne '/(\w+)\s+(\w+)\s+[tT]\s+(\w+)/ and printf "%x %x %s\0",hex $$1,hex $$2,$$3' > "$@" + $(NM) -n -S --format=bsd "$<" | sed -nE 's/^0*([0-9a-fA-F]+) 0*([0-9a-fA-F]+) [tT] ([^ ]*)$$/\1 \2 \3/p' | tr '\n' '\0' > "$@" endef $(obj)/syms.bin: $(obj)/vmlinux.syms FORCE -- cgit v1.2.3 From b5415c8f9755069640aad184293198bcf794f66d Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 7 Jun 2021 12:01:49 +0200 Subject: s390/entry.S: factor out OUTSIDE macro Introduce OUTSIDE macro that checks whether an instruction address is inside or outside of a block of instructions. Signed-off-by: Alexander Gordeev Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/entry.S | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 7cfa08b67cae..187f704cc9e9 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -129,6 +129,27 @@ _LPP_OFFSET = __LC_LPP "jnz .+8; .long 0xb2e8d000", 82 .endm +#if IS_ENABLED(CONFIG_KVM) + /* + * The OUTSIDE macro jumps to the provided label in case the value + * in the provided register is outside of the provided range. The + * macro is useful for checking whether a PSW stored in a register + * pair points inside or outside of a block of instructions. + * @reg: register to check + * @start: start of the range + * @end: end of the range + * @outside_label: jump here if @reg is outside of [@start..@end) + */ + .macro OUTSIDE reg,start,end,outside_label + lgr %r14,\reg + larl %r13,\start + slgr %r14,%r13 + lghi %r13,\end - \start + clgr %r14,%r13 + jhe \outside_label + .endm +#endif + GEN_BR_THUNK %r14 GEN_BR_THUNK %r14,%r13 @@ -319,12 +340,7 @@ ENTRY(pgm_check_handler) .Lpgm_skip_asce: #if IS_ENABLED(CONFIG_KVM) # cleanup critical section for program checks in sie64a - lgr %r14,%r9 - larl %r13,.Lsie_gmap - slgr %r14,%r13 - lghi %r13,.Lsie_done - .Lsie_gmap - clgr %r14,%r13 - jhe 1f + OUTSIDE %r9,.Lsie_gmap,.Lsie_done,1f lg %r14,__SF_SIE_CONTROL(%r15) # get control block pointer ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE lctlg %c1,%c1,__LC_KERNEL_ASCE # load primary asce @@ -393,12 +409,7 @@ ENTRY(\name) tmhh %r8,0x0001 # interrupting from user ? jnz 1f #if IS_ENABLED(CONFIG_KVM) - lgr %r14,%r9 - larl %r13,.Lsie_gmap - slgr %r14,%r13 - lghi %r13,.Lsie_done - .Lsie_gmap - clgr %r14,%r13 - jhe 0f + OUTSIDE %r9,.Lsie_gmap,.Lsie_done,0f brasl %r14,.Lcleanup_sie #endif 0: CHECK_STACK __LC_SAVE_AREA_ASYNC @@ -541,17 +552,8 @@ ENTRY(mcck_int_handler) tmhh %r8,0x0001 # interrupting from user ? jnz .Lmcck_user #if IS_ENABLED(CONFIG_KVM) - lgr %r14,%r9 - larl %r13,.Lsie_gmap - slgr %r14,%r13 - lghi %r13,.Lsie_done - .Lsie_gmap - clgr %r14,%r13 - jhe .Lmcck_stack - larl %r13,.Lsie_entry - slgr %r9,%r13 - lghi %r13,.Lsie_skip - .Lsie_entry - clgr %r9,%r13 - jhe 5f + OUTSIDE %r9,.Lsie_gmap,.Lsie_done,.Lmcck_stack + OUTSIDE %r9,.Lsie_entry,.Lsie_skip,5f oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST 5: brasl %r14,.Lcleanup_sie #endif -- cgit v1.2.3 From 0c4f2623b95779fe8cfb277fa255e4b91c0f96f0 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Tue, 6 Oct 2020 22:12:39 +0200 Subject: s390: setup kernel memory layout early Currently there are two separate places where kernel memory layout has to be known and adjusted: 1. early kasan setup. 2. paging setup later. Those 2 places had to be kept in sync and adjusted to reflect peculiar technical details of one another. With additional factors which influence kernel memory layout like ultravisor secure storage limit, complexity of keeping two things in sync grew up even more. Besides that if we look forward towards creating identity mapping and enabling DAT before jumping into uncompressed kernel - that would also require full knowledge of and control over kernel memory layout. So, de-duplicate and move kernel memory layout setup logic into the decompressor. Reviewed-by: Alexander Gordeev Signed-off-by: Vasily Gorbik --- arch/s390/boot/boot.h | 1 + arch/s390/boot/ipl_parm.c | 8 ++-- arch/s390/boot/startup.c | 88 +++++++++++++++++++++++++++++++++++++++++ arch/s390/boot/uv.c | 25 ++++++++++++ arch/s390/include/asm/kasan.h | 1 - arch/s390/include/asm/pgtable.h | 13 +++--- arch/s390/include/asm/setup.h | 1 - arch/s390/kernel/setup.c | 50 ++--------------------- arch/s390/kernel/uv.c | 8 +--- arch/s390/mm/kasan_init.c | 35 +++------------- 10 files changed, 135 insertions(+), 95 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/boot/boot.h b/arch/s390/boot/boot.h index 8b50967f5804..ae04e1c93764 100644 --- a/arch/s390/boot/boot.h +++ b/arch/s390/boot/boot.h @@ -24,6 +24,7 @@ void __printf(1, 2) decompressor_printk(const char *fmt, ...); extern const char kernel_version[]; extern unsigned long memory_limit; +extern unsigned long vmalloc_size; extern int vmalloc_size_set; extern int kaslr_enabled; diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c index 3485a1d4e97b..bc1f973e656a 100644 --- a/arch/s390/boot/ipl_parm.c +++ b/arch/s390/boot/ipl_parm.c @@ -12,13 +12,13 @@ #include "boot.h" char __bootdata(early_command_line)[COMMAND_LINE_SIZE]; +int __bootdata(noexec_disabled); + +unsigned int __bootdata_preserved(zlib_dfltcc_support) = ZLIB_DFLTCC_FULL; struct ipl_parameter_block __bootdata_preserved(ipl_block); int __bootdata_preserved(ipl_block_valid); -unsigned int __bootdata_preserved(zlib_dfltcc_support) = ZLIB_DFLTCC_FULL; - -unsigned long __bootdata(vmalloc_size) = VMALLOC_DEFAULT_SIZE; -int __bootdata(noexec_disabled); +unsigned long vmalloc_size = VMALLOC_DEFAULT_SIZE; unsigned long memory_limit; int vmalloc_size_set; int kaslr_enabled; diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c index 61a8ac4067e5..bbe4df6c2f8b 100644 --- a/arch/s390/boot/startup.c +++ b/arch/s390/boot/startup.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,12 @@ extern char __boot_data_start[], __boot_data_end[]; extern char __boot_data_preserved_start[], __boot_data_preserved_end[]; unsigned long __bootdata_preserved(__kaslr_offset); +unsigned long __bootdata_preserved(VMALLOC_START); +unsigned long __bootdata_preserved(VMALLOC_END); +struct page *__bootdata_preserved(vmemmap); +unsigned long __bootdata_preserved(vmemmap_size); +unsigned long __bootdata_preserved(MODULES_VADDR); +unsigned long __bootdata_preserved(MODULES_END); unsigned long __bootdata(ident_map_size); u64 __bootdata_preserved(stfle_fac_list[16]); @@ -172,6 +179,86 @@ static void setup_ident_map_size(unsigned long max_physmem_end) #endif } +static void setup_kernel_memory_layout(void) +{ + bool vmalloc_size_verified = false; + unsigned long vmemmap_off; + unsigned long vspace_left; + unsigned long rte_size; + unsigned long pages; + unsigned long vmax; + + pages = ident_map_size / PAGE_SIZE; + /* vmemmap contains a multiple of PAGES_PER_SECTION struct pages */ + vmemmap_size = SECTION_ALIGN_UP(pages) * sizeof(struct page); + + /* choose kernel address space layout: 4 or 3 levels. */ + vmemmap_off = round_up(ident_map_size, _REGION3_SIZE); + if (IS_ENABLED(CONFIG_KASAN) || + vmalloc_size > _REGION2_SIZE || + vmemmap_off + vmemmap_size + vmalloc_size + MODULES_LEN > _REGION2_SIZE) + vmax = _REGION1_SIZE; + else + vmax = _REGION2_SIZE; + + /* keep vmemmap_off aligned to a top level region table entry */ + rte_size = vmax == _REGION1_SIZE ? _REGION2_SIZE : _REGION3_SIZE; + MODULES_END = vmax; + if (is_prot_virt_host()) { + /* + * forcing modules and vmalloc area under the ultravisor + * secure storage limit, so that any vmalloc allocation + * we do could be used to back secure guest storage. + */ + adjust_to_uv_max(&MODULES_END); + } + +#ifdef CONFIG_KASAN + if (MODULES_END < vmax) { + /* force vmalloc and modules below kasan shadow */ + MODULES_END = min(MODULES_END, KASAN_SHADOW_START); + } else { + /* + * leave vmalloc and modules above kasan shadow but make + * sure they don't overlap with it + */ + vmalloc_size = min(vmalloc_size, vmax - KASAN_SHADOW_END - MODULES_LEN); + vmalloc_size_verified = true; + vspace_left = KASAN_SHADOW_START; + } +#endif + MODULES_VADDR = MODULES_END - MODULES_LEN; + VMALLOC_END = MODULES_VADDR; + + if (vmalloc_size_verified) { + VMALLOC_START = VMALLOC_END - vmalloc_size; + } else { + vmemmap_off = round_up(ident_map_size, rte_size); + + if (vmemmap_off + vmemmap_size > VMALLOC_END || + vmalloc_size > VMALLOC_END - vmemmap_off - vmemmap_size) { + /* + * allow vmalloc area to occupy up to 1/2 of + * the rest virtual space left. + */ + vmalloc_size = min(vmalloc_size, VMALLOC_END / 2); + } + VMALLOC_START = VMALLOC_END - vmalloc_size; + vspace_left = VMALLOC_START; + } + + pages = vspace_left / (PAGE_SIZE + sizeof(struct page)); + pages = SECTION_ALIGN_UP(pages); + vmemmap_off = round_up(vspace_left - pages * sizeof(struct page), rte_size); + /* keep vmemmap left most starting from a fresh region table entry */ + vmemmap_off = min(vmemmap_off, round_up(ident_map_size, rte_size)); + /* take care that identity map is lower then vmemmap */ + ident_map_size = min(ident_map_size, vmemmap_off); + vmemmap_size = SECTION_ALIGN_UP(ident_map_size / PAGE_SIZE) * sizeof(struct page); + VMALLOC_START = max(vmemmap_off + vmemmap_size, VMALLOC_START); + vmemmap = (struct page *)vmemmap_off; +} + /* * This function clears the BSS section of the decompressed Linux kernel and NOT the decompressor's. */ @@ -211,6 +298,7 @@ void startup_kernel(void) parse_boot_command_line(); setup_ident_map_size(detect_memory()); setup_vmalloc_size(); + setup_kernel_memory_layout(); random_lma = __kaslr_offset = 0; if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && kaslr_enabled) { diff --git a/arch/s390/boot/uv.c b/arch/s390/boot/uv.c index 87641dd65ccf..82b99b916243 100644 --- a/arch/s390/boot/uv.c +++ b/arch/s390/boot/uv.c @@ -44,3 +44,28 @@ void uv_query_info(void) prot_virt_guest = 1; #endif } + +#if IS_ENABLED(CONFIG_KVM) +static bool has_uv_sec_stor_limit(void) +{ + /* + * keep these conditions in line with setup_uv() + */ + if (!is_prot_virt_host()) + return false; + + if (is_prot_virt_guest()) + return false; + + if (!test_facility(158)) + return false; + + return !!uv_info.max_sec_stor_addr; +} + +void adjust_to_uv_max(unsigned long *vmax) +{ + if (has_uv_sec_stor_limit()) + *vmax = min_t(unsigned long, *vmax, uv_info.max_sec_stor_addr); +} +#endif diff --git a/arch/s390/include/asm/kasan.h b/arch/s390/include/asm/kasan.h index 76f351bd6645..2768d5db181f 100644 --- a/arch/s390/include/asm/kasan.h +++ b/arch/s390/include/asm/kasan.h @@ -16,7 +16,6 @@ extern void kasan_early_init(void); extern void kasan_copy_shadow_mapping(void); extern void kasan_free_early_identity(void); -extern unsigned long kasan_vmax; /* * Estimate kasan memory requirements, which it will reserve diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 9512f6820ead..5677be473261 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -86,16 +87,16 @@ extern unsigned long zero_page_mask; * happen without trampolines and in addition the placement within a * 2GB frame is branch prediction unit friendly. */ -extern unsigned long VMALLOC_START; -extern unsigned long VMALLOC_END; +extern unsigned long __bootdata_preserved(VMALLOC_START); +extern unsigned long __bootdata_preserved(VMALLOC_END); #define VMALLOC_DEFAULT_SIZE ((512UL << 30) - MODULES_LEN) -extern struct page *vmemmap; -extern unsigned long vmemmap_size; +extern struct page *__bootdata_preserved(vmemmap); +extern unsigned long __bootdata_preserved(vmemmap_size); #define VMEM_MAX_PHYS ((unsigned long) vmemmap) -extern unsigned long MODULES_VADDR; -extern unsigned long MODULES_END; +extern unsigned long __bootdata_preserved(MODULES_VADDR); +extern unsigned long __bootdata_preserved(MODULES_END); #define MODULES_VADDR MODULES_VADDR #define MODULES_END MODULES_END #define MODULES_LEN (1UL << 31) diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index 29baab03f091..a8b75da3c1b8 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -89,7 +89,6 @@ extern unsigned int zlib_dfltcc_support; extern int noexec_disabled; extern unsigned long ident_map_size; -extern unsigned long vmalloc_size; /* The Write Back bit position in the physaddr is given by the SLPC PCI */ extern unsigned long mio_wb_bit_mask; diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 146d01700a55..9145ef983f38 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -96,7 +96,6 @@ unsigned long int_hwcap = 0; int __bootdata(noexec_disabled); unsigned long __bootdata(ident_map_size); -unsigned long __bootdata(vmalloc_size); struct mem_detect_info __bootdata(mem_detect); struct exception_table_entry *__bootdata_preserved(__start_dma_ex_table); @@ -545,53 +544,10 @@ static void __init setup_resources(void) #endif } -static void __init setup_ident_map_size(void) +static void __init setup_memory_end(void) { - unsigned long vmax, tmp; - - /* Choose kernel address space layout: 3 or 4 levels. */ - tmp = ident_map_size / PAGE_SIZE; - tmp = tmp * (sizeof(struct page) + PAGE_SIZE); - if (tmp + vmalloc_size + MODULES_LEN <= _REGION2_SIZE) - vmax = _REGION2_SIZE; /* 3-level kernel page table */ - else - vmax = _REGION1_SIZE; /* 4-level kernel page table */ - /* module area is at the end of the kernel address space. */ - MODULES_END = vmax; - if (is_prot_virt_host()) - adjust_to_uv_max(&MODULES_END); -#ifdef CONFIG_KASAN - vmax = _REGION1_SIZE; - MODULES_END = kasan_vmax; -#endif - MODULES_VADDR = MODULES_END - MODULES_LEN; - VMALLOC_END = MODULES_VADDR; - VMALLOC_START = VMALLOC_END - vmalloc_size; - - /* Split remaining virtual space between 1:1 mapping & vmemmap array */ - tmp = VMALLOC_START / (PAGE_SIZE + sizeof(struct page)); - /* vmemmap contains a multiple of PAGES_PER_SECTION struct pages */ - tmp = SECTION_ALIGN_UP(tmp); - tmp = VMALLOC_START - tmp * sizeof(struct page); - tmp &= ~((vmax >> 11) - 1); /* align to page table level */ - tmp = min(tmp, 1UL << MAX_PHYSMEM_BITS); - vmemmap = (struct page *) tmp; - - /* Take care that ident_map_size <= vmemmap */ - ident_map_size = min(ident_map_size, (unsigned long)vmemmap); -#ifdef CONFIG_KASAN - ident_map_size = min(ident_map_size, KASAN_SHADOW_START); -#endif - vmemmap_size = SECTION_ALIGN_UP(ident_map_size / PAGE_SIZE) * sizeof(struct page); -#ifdef CONFIG_KASAN - /* move vmemmap above kasan shadow only if stands in a way */ - if (KASAN_SHADOW_END > (unsigned long)vmemmap && - (unsigned long)vmemmap + vmemmap_size > KASAN_SHADOW_START) - vmemmap = max(vmemmap, (struct page *)KASAN_SHADOW_END); -#endif - max_pfn = max_low_pfn = PFN_DOWN(ident_map_size); memblock_remove(ident_map_size, ULONG_MAX); - + max_pfn = max_low_pfn = PFN_DOWN(ident_map_size); pr_notice("The maximum memory size is %luMB\n", ident_map_size >> 20); } @@ -1132,7 +1088,7 @@ void __init setup_arch(char **cmdline_p) remove_oldmem(); setup_uv(); - setup_ident_map_size(); + setup_memory_end(); setup_memory(); dma_contiguous_reserve(ident_map_size); vmcp_cma_reserve(); diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c index 370f664580af..6be2167943bb 100644 --- a/arch/s390/kernel/uv.c +++ b/arch/s390/kernel/uv.c @@ -52,7 +52,7 @@ void __init setup_uv(void) unsigned long uv_stor_base; /* - * keep these conditions in line with kasan init code has_uv_sec_stor_limit() + * keep these conditions in line with has_uv_sec_stor_limit() */ if (!is_prot_virt_host()) return; @@ -91,12 +91,6 @@ fail: prot_virt_host = 0; } -void adjust_to_uv_max(unsigned long *vmax) -{ - if (uv_info.max_sec_stor_addr) - *vmax = min_t(unsigned long, *vmax, uv_info.max_sec_stor_addr); -} - /* * Requests the Ultravisor to pin the page in the shared state. This will * cause an intercept when the guest attempts to unshare the pinned page. diff --git a/arch/s390/mm/kasan_init.c b/arch/s390/mm/kasan_init.c index db4d303aaaa9..a0fdc6dc5f9d 100644 --- a/arch/s390/mm/kasan_init.c +++ b/arch/s390/mm/kasan_init.c @@ -13,7 +13,6 @@ #include #include -unsigned long kasan_vmax; static unsigned long segment_pos __initdata; static unsigned long segment_low __initdata; static unsigned long pgalloc_pos __initdata; @@ -251,28 +250,9 @@ static void __init kasan_early_detect_facilities(void) } } -static bool __init has_uv_sec_stor_limit(void) -{ - /* - * keep these conditions in line with setup_uv() - */ - if (!is_prot_virt_host()) - return false; - - if (is_prot_virt_guest()) - return false; - - if (!test_facility(158)) - return false; - - return !!uv_info.max_sec_stor_addr; -} - void __init kasan_early_init(void) { - unsigned long untracked_mem_end; unsigned long shadow_alloc_size; - unsigned long vmax_unlimited; unsigned long initrd_end; unsigned long memsize; unsigned long pgt_prot = pgprot_val(PAGE_KERNEL_RO); @@ -306,9 +286,6 @@ void __init kasan_early_init(void) BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_START, P4D_SIZE)); BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_END, P4D_SIZE)); crst_table_init((unsigned long *)early_pg_dir, _REGION2_ENTRY_EMPTY); - untracked_mem_end = kasan_vmax = vmax_unlimited = _REGION1_SIZE; - if (has_uv_sec_stor_limit()) - kasan_vmax = min(vmax_unlimited, uv_info.max_sec_stor_addr); /* init kasan zero shadow */ crst_table_init((unsigned long *)kasan_early_shadow_p4d, @@ -375,18 +352,18 @@ void __init kasan_early_init(void) */ /* populate kasan shadow (for identity mapping and zero page mapping) */ kasan_early_pgtable_populate(__sha(0), __sha(memsize), POPULATE_MAP); - if (IS_ENABLED(CONFIG_MODULES)) - untracked_mem_end = kasan_vmax - MODULES_LEN; if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) { - untracked_mem_end = kasan_vmax - vmalloc_size - MODULES_LEN; /* shallowly populate kasan shadow for vmalloc and modules */ - kasan_early_pgtable_populate(__sha(untracked_mem_end), __sha(kasan_vmax), + kasan_early_pgtable_populate(__sha(VMALLOC_START), __sha(MODULES_END), POPULATE_SHALLOW); } /* populate kasan shadow for untracked memory */ - kasan_early_pgtable_populate(__sha(ident_map_size), __sha(untracked_mem_end), + kasan_early_pgtable_populate(__sha(ident_map_size), + IS_ENABLED(CONFIG_KASAN_VMALLOC) ? + __sha(VMALLOC_START) : + __sha(MODULES_VADDR), POPULATE_ZERO_SHADOW); - kasan_early_pgtable_populate(__sha(kasan_vmax), __sha(vmax_unlimited), + kasan_early_pgtable_populate(__sha(MODULES_END), __sha(_REGION1_SIZE), POPULATE_ZERO_SHADOW); /* memory allocated for identity mapping structs will be freed later */ pgalloc_freeable = pgalloc_pos; -- cgit v1.2.3 From 6a9100ad132c61e4ff345277862e3fecfb7cdf0e Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Thu, 8 Oct 2020 15:07:27 +0200 Subject: s390/setup: cleanup reserve/remove_oldmem Since OLDMEM_BASE/OLDMEM_SIZE is already taken into consideration and is reflected in ident_map_size. reserve/remove_oldmem() is no longer needed and could be removed. Reviewed-by: Alexander Gordeev Signed-off-by: Vasily Gorbik --- arch/s390/kernel/setup.c | 26 -------------------------- 1 file changed, 26 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 9145ef983f38..b58ee83f30e3 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -585,30 +585,6 @@ static void __init reserve_above_ident_map(void) memblock_reserve(ident_map_size, ULONG_MAX); } -/* - * Make sure that oldmem, where the dump is stored, is protected - */ -static void __init reserve_oldmem(void) -{ -#ifdef CONFIG_CRASH_DUMP - if (OLDMEM_BASE) - /* Forget all memory above the running kdump system */ - memblock_reserve(OLDMEM_SIZE, (phys_addr_t)ULONG_MAX); -#endif -} - -/* - * Make sure that oldmem, where the dump is stored, is protected - */ -static void __init remove_oldmem(void) -{ -#ifdef CONFIG_CRASH_DUMP - if (OLDMEM_BASE) - /* Forget all memory above the running kdump system */ - memblock_remove(OLDMEM_SIZE, (phys_addr_t)ULONG_MAX); -#endif -} - /* * Reserve memory for kdump kernel to be loaded with kexec */ @@ -1074,7 +1050,6 @@ void __init setup_arch(char **cmdline_p) /* Do some memory reservations *before* memory is added to memblock */ reserve_above_ident_map(); - reserve_oldmem(); reserve_kernel(); reserve_initrd(); reserve_certificate_list(); @@ -1085,7 +1060,6 @@ void __init setup_arch(char **cmdline_p) memblock_add_mem_detect_info(); free_mem_detect_info(); - remove_oldmem(); setup_uv(); setup_memory_end(); -- cgit v1.2.3 From d2beeb3bc74ec897ced7309c3a104fa4b3be0ac3 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Wed, 9 Jun 2021 14:05:56 +0200 Subject: s390/debug: Remove pointer obfuscation When read via debugfs, s390dbf debug-views print the kernel address of the call-site that created a trace entry. The kernel's %p pointer hashing feature obfuscates this address, and commit 860ec7c6e21c ("s390/debug: use pK for kernel pointers") made this obfuscation configurable via the kptr_restrict sysctl. Obfuscation of kernel address data printed via s390dbf debug-views does not add any additional protection since the associated debugfs files are only accessible to the root user that typically has enough other means to obtain kernel address data. Also trace payload data may contain binary representations of kernel addresses as part of logged data structues. Requiring such payload data to be obfuscated as well would be impractical and greatly diminish the use of s390dbf. Therefore completely remove pointer obfuscation from s390dbf debug-views. Reviewed-by: Steffen Maier Acked-by: Heiko Carstens Signed-off-by: Peter Oberparleiter Signed-off-by: Vasily Gorbik --- arch/s390/kernel/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index bb958d32bd81..09b6c6402f9b 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -1418,7 +1418,7 @@ int debug_dflt_header_fn(debug_info_t *id, struct debug_view *view, else except_str = "-"; caller = (unsigned long) entry->caller; - rc += sprintf(out_buf, "%02i %011ld:%06lu %1u %1s %04u %pK ", + rc += sprintf(out_buf, "%02i %011ld:%06lu %1u %1s %04u %px ", area, sec, usec, level, except_str, entry->cpu, (void *)caller); return rc; -- cgit v1.2.3 From 9c9a915afd90f7534c16a71d1cd44b58596fddf3 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 10 Jun 2021 17:50:25 +0200 Subject: s390/processor: always inline stap() and __load_psw_mask() s390 is the only architecture which makes use of the __no_kasan_or_inline attribute for two functions. Given that both stap() and __load_psw_mask() are very small functions they can and should be always inlined anyway. Therefore get rid of __no_kasan_or_inline and always inline these functions. Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/processor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 6d3055f7329a..ddc7858bbce4 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -207,7 +207,7 @@ static __always_inline unsigned long current_stack_pointer(void) return sp; } -static __no_kasan_or_inline unsigned short stap(void) +static __always_inline unsigned short stap(void) { unsigned short cpu_address; @@ -246,7 +246,7 @@ static inline void __load_psw(psw_t psw) * Set PSW mask to specified value, while leaving the * PSW addr pointing to the next instruction. */ -static __no_kasan_or_inline void __load_psw_mask(unsigned long mask) +static __always_inline void __load_psw_mask(unsigned long mask) { unsigned long addr; psw_t psw; -- cgit v1.2.3 From 4aca3ab45d725fe8c4d8be6b67c904c3c3cc6a1d Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 10 Jun 2021 17:58:00 +0200 Subject: s390/irqflags: always inline arch irqflags functions All s390 irqflags functions are very small and should be always inlined. Therefore mark them __always_inline. This also allows to get rid of the rather odd notrace attribute for these small functions, which was only added to prevent tracing iff any of these functions would not be inlined. Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/irqflags.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/irqflags.h b/arch/s390/include/asm/irqflags.h index 586df4c9e2f2..02427b205c11 100644 --- a/arch/s390/include/asm/irqflags.h +++ b/arch/s390/include/asm/irqflags.h @@ -32,45 +32,45 @@ }) /* set system mask. */ -static inline notrace void __arch_local_irq_ssm(unsigned long flags) +static __always_inline void __arch_local_irq_ssm(unsigned long flags) { asm volatile("ssm %0" : : "Q" (flags) : "memory"); } -static inline notrace unsigned long arch_local_save_flags(void) +static __always_inline unsigned long arch_local_save_flags(void) { return __arch_local_irq_stnsm(0xff); } -static inline notrace unsigned long arch_local_irq_save(void) +static __always_inline unsigned long arch_local_irq_save(void) { return __arch_local_irq_stnsm(0xfc); } -static inline notrace void arch_local_irq_disable(void) +static __always_inline void arch_local_irq_disable(void) { arch_local_irq_save(); } -static inline notrace void arch_local_irq_enable(void) +static __always_inline void arch_local_irq_enable(void) { __arch_local_irq_stosm(0x03); } /* This only restores external and I/O interrupt state */ -static inline notrace void arch_local_irq_restore(unsigned long flags) +static __always_inline void arch_local_irq_restore(unsigned long flags) { /* only disabled->disabled and disabled->enabled is valid */ if (flags & ARCH_IRQ_ENABLED) arch_local_irq_enable(); } -static inline notrace bool arch_irqs_disabled_flags(unsigned long flags) +static __always_inline bool arch_irqs_disabled_flags(unsigned long flags) { return !(flags & ARCH_IRQ_ENABLED); } -static inline notrace bool arch_irqs_disabled(void) +static __always_inline bool arch_irqs_disabled(void) { return arch_irqs_disabled_flags(arch_local_save_flags()); } -- cgit v1.2.3 From c4655a2098236d36c5b0678e56c9ea04308b45ed Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 9 Jun 2021 22:59:13 +0200 Subject: s390: introduce register pair union Introduce a register pair union, which is supposed to be used for inline assemblies where instructions require parameters in even/odd numbered register pairs. This is more or less the same register pair construct which was available for 31 bit builds which was removed with commit 5a79859ae0f3 ("s390: remove 31 bit support"). Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/types.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 arch/s390/include/asm/types.h (limited to 'arch/s390') diff --git a/arch/s390/include/asm/types.h b/arch/s390/include/asm/types.h new file mode 100644 index 000000000000..0b5d550a0478 --- /dev/null +++ b/arch/s390/include/asm/types.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef _ASM_S390_TYPES_H +#define _ASM_S390_TYPES_H + +#include + +#ifndef __ASSEMBLY__ + +union register_pair { + unsigned __int128 pair; + struct { + unsigned long even; + unsigned long odd; + }; +}; + +#endif /* __ASSEMBLY__ */ +#endif /* _ASM_S390_TYPES_H */ -- cgit v1.2.3 From 4f38c7aefed3c5c4e0d57837ad4c81cfad05df50 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 9 Jun 2021 22:59:13 +0200 Subject: s390/bitops: use register pair instead of register asm Get rid of register asm statement and use a register pair. This allows the compiler to allocate registers on its own. Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/bitops.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/bitops.h b/arch/s390/include/asm/bitops.h index 68da67d2c4c9..fd149480b6e2 100644 --- a/arch/s390/include/asm/bitops.h +++ b/arch/s390/include/asm/bitops.h @@ -299,13 +299,13 @@ static inline unsigned char __flogr(unsigned long word) } return bit; } else { - register unsigned long bit asm("4") = word; - register unsigned long out asm("5"); + union register_pair rp; + rp.even = word; asm volatile( - " flogr %[bit],%[bit]\n" - : [bit] "+d" (bit), [out] "=d" (out) : : "cc"); - return bit; + " flogr %[rp],%[rp]\n" + : [rp] "+d" (rp.pair) : : "cc"); + return rp.even; } } -- cgit v1.2.3 From ddd38fd261e7cd7772caea0128d0bee65bf1b159 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 9 Jun 2021 22:59:13 +0200 Subject: s390/smp: use register pair instead of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/smp.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index e137c840a4d3..c8493e7205ce 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -1233,21 +1233,21 @@ subsys_initcall(s390_smp_init); static __always_inline void set_new_lowcore(struct lowcore *lc) { - struct lowcore *old_lc = &S390_lowcore; - struct lowcore *new_lc = lc; + union register_pair dst, src; u32 pfx; - register struct lowcore *reg2 asm ("2") = new_lc; - register unsigned long reg3 asm ("3") = sizeof(*reg2); - register struct lowcore *reg4 asm ("4") = old_lc; - register unsigned long reg5 asm ("5") = sizeof(*reg4); + + src.even = (unsigned long) &S390_lowcore; + src.odd = sizeof(S390_lowcore); + dst.even = (unsigned long) lc; + dst.odd = sizeof(*lc); + pfx = (unsigned long) lc; asm volatile( - " st 2,%[pfx]\n" - " mvcl 2,4\n" + " mvcl %[dst],%[src]\n" " spx %[pfx]\n" - : "+&d" (reg2), "+&d" (reg3), - "+&d" (reg4), "+&d" (reg5), [pfx] "=Q" (pfx) - : : "memory", "cc"); + : [dst] "+&d" (dst.pair), [src] "+&d" (src.pair) + : [pfx] "Q" (pfx) + : "memory", "cc"); } static int __init smp_reinit_ipl_cpu(void) -- cgit v1.2.3 From 75c89a2bc6ef00fd3c38c69cba82a92d0535887a Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 9 Jun 2021 22:59:13 +0200 Subject: s390/page: use register pair instead of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/page.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h index cc98f9b78fd4..2d83e2cec43a 100644 --- a/arch/s390/include/asm/page.h +++ b/arch/s390/include/asm/page.h @@ -55,13 +55,16 @@ static inline void storage_key_init_range(unsigned long start, unsigned long end */ static inline void copy_page(void *to, void *from) { - register void *reg2 asm ("2") = to; - register unsigned long reg3 asm ("3") = 0x1000; - register void *reg4 asm ("4") = from; - register unsigned long reg5 asm ("5") = 0xb0001000; + union register_pair dst, src; + + dst.even = (unsigned long) to; + dst.odd = 0x1000; + src.even = (unsigned long) from; + src.odd = 0xb0001000; + asm volatile( - " mvcl 2,4" - : "+d" (reg2), "+d" (reg3), "+d" (reg4), "+d" (reg5) + " mvcl %[dst],%[src]" + : [dst] "+&d" (dst.pair), [src] "+&d" (src.pair) : : "memory", "cc"); } -- cgit v1.2.3 From 3c45a07bee619bb997b75b323f8d014e3efb36f8 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 9 Jun 2021 22:59:13 +0200 Subject: s390/diag: use register pair instead of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/diag.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/diag.c b/arch/s390/kernel/diag.c index b8b0cd7b008f..a3f47464c3f1 100644 --- a/arch/s390/kernel/diag.c +++ b/arch/s390/kernel/diag.c @@ -141,16 +141,15 @@ EXPORT_SYMBOL(diag14); static inline int __diag204(unsigned long *subcode, unsigned long size, void *addr) { - register unsigned long _subcode asm("0") = *subcode; - register unsigned long _size asm("1") = size; + union register_pair rp = { .even = *subcode, .odd = size }; asm volatile( - " diag %2,%0,0x204\n" + " diag %[addr],%[rp],0x204\n" "0: nopr %%r7\n" EX_TABLE(0b,0b) - : "+d" (_subcode), "+d" (_size) : "d" (addr) : "memory"); - *subcode = _subcode; - return _size; + : [rp] "+&d" (rp.pair) : [addr] "d" (addr) : "memory"); + *subcode = rp.even; + return rp.odd; } int diag204(unsigned long subcode, unsigned long size, void *addr) -- cgit v1.2.3 From a29a6b5a925b52fbec6b10edf8a7b713fda72bf1 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 9 Jun 2021 22:59:13 +0200 Subject: s390/checksum: use register pair instead of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/checksum.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/checksum.h b/arch/s390/include/asm/checksum.h index a8c02cfbc712..cdd19d326345 100644 --- a/arch/s390/include/asm/checksum.h +++ b/arch/s390/include/asm/checksum.h @@ -29,13 +29,15 @@ */ static inline __wsum csum_partial(const void *buff, int len, __wsum sum) { - register unsigned long reg2 asm("2") = (unsigned long) buff; - register unsigned long reg3 asm("3") = (unsigned long) len; + union register_pair rp = { + .even = (unsigned long) buff, + .odd = (unsigned long) len, + }; asm volatile( - "0: cksm %0,%1\n" /* do checksum on longs */ + "0: cksm %[sum],%[rp]\n" " jo 0b\n" - : "+d" (sum), "+d" (reg2), "+d" (reg3) : : "cc", "memory"); + : [sum] "+&d" (sum), [rp] "+&d" (rp.pair) : : "cc", "memory"); return sum; } -- cgit v1.2.3 From dda74578e7da917fdf2e16608c1f8ad2e87c451f Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 9 Jun 2021 22:59:13 +0200 Subject: s390/maccess: use register pair instead of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/mm/maccess.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c index 1d17413b319a..1f1f906344ff 100644 --- a/arch/s390/mm/maccess.c +++ b/arch/s390/mm/maccess.c @@ -79,22 +79,21 @@ notrace void *s390_kernel_write(void *dst, const void *src, size_t size) static int __no_sanitize_address __memcpy_real(void *dest, void *src, size_t count) { - register unsigned long _dest asm("2") = (unsigned long) dest; - register unsigned long _len1 asm("3") = (unsigned long) count; - register unsigned long _src asm("4") = (unsigned long) src; - register unsigned long _len2 asm("5") = (unsigned long) count; + union register_pair _dst, _src; int rc = -EFAULT; + _dst.even = (unsigned long) dest; + _dst.odd = (unsigned long) count; + _src.even = (unsigned long) src; + _src.odd = (unsigned long) count; asm volatile ( - "0: mvcle %1,%2,0x0\n" + "0: mvcle %[dst],%[src],0\n" "1: jo 0b\n" - " lhi %0,0x0\n" + " lhi %[rc],0\n" "2:\n" EX_TABLE(1b,2b) - : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1), - "+d" (_len2), "=m" (*((long *) dest)) - : "m" (*((long *) src)) - : "cc", "memory"); + : [rc] "+&d" (rc), [dst] "+&d" (_dst.pair), [src] "+&d" (_src.pair) + : : "cc", "memory"); return rc; } -- cgit v1.2.3 From 6a7b4e4ee1d9f7444dc7fe3ec1b3cf441a3ce9b4 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 9 Jun 2021 22:59:13 +0200 Subject: s390/sthyi: use register pair instead of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/sthyi.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/sthyi.c b/arch/s390/kernel/sthyi.c index 888cc2f166db..4d141e2c132e 100644 --- a/arch/s390/kernel/sthyi.c +++ b/arch/s390/kernel/sthyi.c @@ -395,19 +395,18 @@ out: static int sthyi(u64 vaddr, u64 *rc) { - register u64 code asm("0") = 0; - register u64 addr asm("2") = vaddr; - register u64 rcode asm("3"); + union register_pair r1 = { .even = 0, }; /* subcode */ + union register_pair r2 = { .even = vaddr, }; int cc; asm volatile( - ".insn rre,0xB2560000,%[code],%[addr]\n" + ".insn rre,0xB2560000,%[r1],%[r2]\n" "ipm %[cc]\n" "srl %[cc],28\n" - : [cc] "=d" (cc), "=d" (rcode) - : [code] "d" (code), [addr] "a" (addr) + : [cc] "=&d" (cc), [r2] "+&d" (r2.pair) + : [r1] "d" (r1.pair) : "memory", "cc"); - *rc = rcode; + *rc = r2.odd; return cc; } -- cgit v1.2.3 From 25130c1a9e99c7b10af6d542d62808476a0dff24 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 9 Jun 2021 22:59:13 +0200 Subject: s390/sigp: use register pair instead of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/sigp.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/sigp.h b/arch/s390/include/asm/sigp.h index 53ee795cd3d3..edee63da08e7 100644 --- a/arch/s390/include/asm/sigp.h +++ b/arch/s390/include/asm/sigp.h @@ -41,15 +41,17 @@ static inline int ____pcpu_sigp(u16 addr, u8 order, unsigned long parm, u32 *status) { - register unsigned long reg1 asm ("1") = parm; + union register_pair r1 = { .odd = parm, }; int cc; asm volatile( - " sigp %1,%2,0(%3)\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (cc), "+d" (reg1) : "d" (addr), "a" (order) : "cc"); - *status = reg1; + " sigp %[r1],%[addr],0(%[order])\n" + " ipm %[cc]\n" + " srl %[cc],28\n" + : [cc] "=&d" (cc), [r1] "+&d" (r1.pair) + : [addr] "d" (addr), [order] "a" (order) + : "cc"); + *status = r1.even; return cc; } -- cgit v1.2.3 From 0a9d947fbe3e89e44758e1b8bf0098e98b3ccd78 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 9 Jun 2021 22:59:13 +0200 Subject: s390/cpcmd: use register pair instead of register asm Remove register asm usage from diag8_noresponse() since it wasn't needed at all. There is no requirement for even/odd register pairs for diag 0x8. For diag_response() use register pairs to fulfill the rx+1 and ry+1 requirements as required if a response buffer is specified. Also change the inline asm to return the condition code of the diagnose instruction and do the conditional handling of response length calculation in C. Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/cpcmd.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index 2da027359798..54efc279f54e 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c @@ -26,33 +26,35 @@ static char cpcmd_buf[241]; static int diag8_noresponse(int cmdlen) { - register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf; - register unsigned long reg3 asm ("3") = cmdlen; - asm volatile( - " diag %1,%0,0x8\n" - : "+d" (reg3) : "d" (reg2) : "cc"); - return reg3; + " diag %[rx],%[ry],0x8\n" + : [ry] "+&d" (cmdlen) + : [rx] "d" ((addr_t) cpcmd_buf) + : "cc"); + return cmdlen; } static int diag8_response(int cmdlen, char *response, int *rlen) { - unsigned long _cmdlen = cmdlen | 0x40000000L; - unsigned long _rlen = *rlen; - register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf; - register unsigned long reg3 asm ("3") = (addr_t) response; - register unsigned long reg4 asm ("4") = _cmdlen; - register unsigned long reg5 asm ("5") = _rlen; + union register_pair rx, ry; + int cc; + rx.even = (addr_t) cpcmd_buf; + rx.odd = (addr_t) response; + ry.even = cmdlen | 0x40000000L; + ry.odd = *rlen; asm volatile( - " diag %2,%0,0x8\n" - " brc 8,1f\n" - " agr %1,%4\n" - "1:\n" - : "+d" (reg4), "+d" (reg5) - : "d" (reg2), "d" (reg3), "d" (*rlen) : "cc"); - *rlen = reg5; - return reg4; + " diag %[rx],%[ry],0x8\n" + " ipm %[cc]\n" + " srl %[cc],28\n" + : [cc] "=&d" (cc), [ry] "+&d" (ry.pair) + : [rx] "d" (rx.pair) + : "cc"); + if (cc) + *rlen += ry.odd; + else + *rlen = ry.odd; + return ry.even; } /* -- cgit v1.2.3 From 54f45214522ae74dc23ad262346ce1abbf96b1ed Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Wed, 16 Jun 2021 00:36:41 +0200 Subject: s390/decompressor: correct BOOT_HEAP_SIZE condition Currently BOOT_HEAP_SIZE is always defined as 0x400000 due to bogus condition. Use CONFIG_KERNEL_BZIP2 instead of CONFIG_HAVE_KERNEL_BZIP2 to correct that. BOOT_HEAP_SIZE of 0x10000 is still good enough for every decompressor algorithm but bzip2. Actual decompressor memory usage with allyesconfig is the following: gzip 0xbc28 bzip2 0x379518 xz 0x7410 lzma 0x3e6c lzo 0 lz4 0 Signed-off-by: Vasily Gorbik --- arch/s390/boot/compressed/decompressor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/s390') diff --git a/arch/s390/boot/compressed/decompressor.c b/arch/s390/boot/compressed/decompressor.c index 3061b11c4d27..cf2571050c68 100644 --- a/arch/s390/boot/compressed/decompressor.c +++ b/arch/s390/boot/compressed/decompressor.c @@ -28,7 +28,7 @@ extern char _end[]; extern unsigned char _compressed_start[]; extern unsigned char _compressed_end[]; -#ifdef CONFIG_HAVE_KERNEL_BZIP2 +#ifdef CONFIG_KERNEL_BZIP2 #define BOOT_HEAP_SIZE 0x400000 #else #define BOOT_HEAP_SIZE 0x10000 -- cgit v1.2.3 From 7b034d9c1b08b3d06ad712283c1115a7fe39e354 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Tue, 15 Jun 2021 12:41:50 +0100 Subject: s390/boot: add zstd support Enable ztsd support in s390/boot, to enable booting with zstd compressed kernel when configured with CONFIG_KERNEL_ZSTD=y. BOOT_HEAP_SIZE is defined to 0x30000 in this case. Actual decompressor memory usage with allyesconfig is currently 0x26150. BugLink: https://bugs.launchpad.net/bugs/1931725 Signed-off-by: Dimitri John Ledkov cc: Heiko Carstens cc: Vasily Gorbik cc: Christian Borntraeger cc: linux-s390@vger.kernel.org Link: https://lore.kernel.org/r/20210615114150.325080-1-dimitri.ledkov@canonical.com [gor: added BOOT_HEAP_SIZE for zstd] Signed-off-by: Vasily Gorbik --- arch/s390/Kconfig | 1 + arch/s390/boot/compressed/Makefile | 4 ++++ arch/s390/boot/compressed/decompressor.c | 6 ++++++ 3 files changed, 11 insertions(+) (limited to 'arch/s390') diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 93488bbf491b..e2ece2a74b24 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -173,6 +173,7 @@ config S390 select HAVE_KERNEL_LZO select HAVE_KERNEL_UNCOMPRESSED select HAVE_KERNEL_XZ + select HAVE_KERNEL_ZSTD select HAVE_KPROBES select HAVE_KPROBES_ON_FTRACE select HAVE_KRETPROBES diff --git a/arch/s390/boot/compressed/Makefile b/arch/s390/boot/compressed/Makefile index e941b165bd4f..660c799d875d 100644 --- a/arch/s390/boot/compressed/Makefile +++ b/arch/s390/boot/compressed/Makefile @@ -14,6 +14,7 @@ obj-y := $(if $(CONFIG_KERNEL_UNCOMPRESSED),,decompressor.o) info.o obj-all := $(obj-y) piggy.o syms.o targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 targets += vmlinux.bin.xz vmlinux.bin.lzma vmlinux.bin.lzo vmlinux.bin.lz4 +targets += vmlinux.bin.zst targets += info.bin syms.bin vmlinux.syms $(obj-all) KBUILD_AFLAGS := $(KBUILD_AFLAGS_DECOMPRESSOR) @@ -63,6 +64,7 @@ suffix-$(CONFIG_KERNEL_LZ4) := .lz4 suffix-$(CONFIG_KERNEL_LZMA) := .lzma suffix-$(CONFIG_KERNEL_LZO) := .lzo suffix-$(CONFIG_KERNEL_XZ) := .xz +suffix-$(CONFIG_KERNEL_ZSTD) := .zst $(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE $(call if_changed,gzip) @@ -76,6 +78,8 @@ $(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y) FORCE $(call if_changed,lzo) $(obj)/vmlinux.bin.xz: $(vmlinux.bin.all-y) FORCE $(call if_changed,xzkern) +$(obj)/vmlinux.bin.zst: $(vmlinux.bin.all-y) FORCE + $(call if_changed,zstd22) OBJCOPYFLAGS_piggy.o := -I binary -O elf64-s390 -B s390:64-bit --rename-section .data=.vmlinux.bin.compressed $(obj)/piggy.o: $(obj)/vmlinux.bin$(suffix-y) FORCE diff --git a/arch/s390/boot/compressed/decompressor.c b/arch/s390/boot/compressed/decompressor.c index cf2571050c68..37a4a8d33c6c 100644 --- a/arch/s390/boot/compressed/decompressor.c +++ b/arch/s390/boot/compressed/decompressor.c @@ -30,6 +30,8 @@ extern unsigned char _compressed_end[]; #ifdef CONFIG_KERNEL_BZIP2 #define BOOT_HEAP_SIZE 0x400000 +#elif CONFIG_KERNEL_ZSTD +#define BOOT_HEAP_SIZE 0x30000 #else #define BOOT_HEAP_SIZE 0x10000 #endif @@ -61,6 +63,10 @@ static unsigned long free_mem_end_ptr = (unsigned long) _end + BOOT_HEAP_SIZE; #include "../../../../lib/decompress_unxz.c" #endif +#ifdef CONFIG_KERNEL_ZSTD +#include "../../../../lib/decompress_unzstd.c" +#endif + #define decompress_offset ALIGN((unsigned long)_end + BOOT_HEAP_SIZE, PAGE_SIZE) unsigned long mem_safe_offset(void) -- cgit v1.2.3 From d66a4c7f760bb13222af9d69a6dca893130d193f Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Tue, 15 Jun 2021 17:08:23 +0200 Subject: s390/pci: use register pair instead of register asm Reviewed-by: Heiko Carstens Signed-off-by: Niklas Schnelle Signed-off-by: Vasily Gorbik --- arch/s390/pci/pci_insn.c | 55 +++++++++++++++++++++--------------------------- arch/s390/pci/pci_mmio.c | 24 +++++++++------------ 2 files changed, 34 insertions(+), 45 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/pci/pci_insn.c b/arch/s390/pci/pci_insn.c index 02f9505c99a8..2e43996159f0 100644 --- a/arch/s390/pci/pci_insn.c +++ b/arch/s390/pci/pci_insn.c @@ -63,16 +63,15 @@ u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status) /* Refresh PCI Translations */ static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status) { - register u64 __addr asm("2") = addr; - register u64 __range asm("3") = range; + union register_pair addr_range = {.even = addr, .odd = range}; u8 cc; asm volatile ( - " .insn rre,0xb9d30000,%[fn],%[addr]\n" + " .insn rre,0xb9d30000,%[fn],%[addr_range]\n" " ipm %[cc]\n" " srl %[cc],28\n" : [cc] "=d" (cc), [fn] "+d" (fn) - : [addr] "d" (__addr), "d" (__range) + : [addr_range] "d" (addr_range.pair) : "cc"); *status = fn >> 24 & 0xff; return cc; @@ -113,21 +112,19 @@ int __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib) /* PCI Load */ static inline int ____pcilg(u64 *data, u64 req, u64 offset, u8 *status) { - register u64 __req asm("2") = req; - register u64 __offset asm("3") = offset; + union register_pair req_off = {.even = req, .odd = offset}; int cc = -ENXIO; u64 __data; asm volatile ( - " .insn rre,0xb9d20000,%[data],%[req]\n" + " .insn rre,0xb9d20000,%[data],%[req_off]\n" "0: ipm %[cc]\n" " srl %[cc],28\n" "1:\n" EX_TABLE(0b, 1b) - : [cc] "+d" (cc), [data] "=d" (__data), [req] "+d" (__req) - : "d" (__offset) - : "cc"); - *status = __req >> 24 & 0xff; + : [cc] "+d" (cc), [data] "=d" (__data), + [req_off] "+&d" (req_off.pair) :: "cc"); + *status = req_off.even >> 24 & 0xff; *data = __data; return cc; } @@ -173,21 +170,19 @@ static inline int zpci_load_fh(u64 *data, const volatile void __iomem *addr, static inline int __pcilg_mio(u64 *data, u64 ioaddr, u64 len, u8 *status) { - register u64 addr asm("2") = ioaddr; - register u64 r3 asm("3") = len; + union register_pair ioaddr_len = {.even = ioaddr, .odd = len}; int cc = -ENXIO; u64 __data; asm volatile ( - " .insn rre,0xb9d60000,%[data],%[ioaddr]\n" + " .insn rre,0xb9d60000,%[data],%[ioaddr_len]\n" "0: ipm %[cc]\n" " srl %[cc],28\n" "1:\n" EX_TABLE(0b, 1b) - : [cc] "+d" (cc), [data] "=d" (__data), "+d" (r3) - : [ioaddr] "d" (addr) - : "cc"); - *status = r3 >> 24 & 0xff; + : [cc] "+d" (cc), [data] "=d" (__data), + [ioaddr_len] "+&d" (ioaddr_len.pair) :: "cc"); + *status = ioaddr_len.odd >> 24 & 0xff; *data = __data; return cc; } @@ -211,20 +206,19 @@ EXPORT_SYMBOL_GPL(zpci_load); /* PCI Store */ static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status) { - register u64 __req asm("2") = req; - register u64 __offset asm("3") = offset; + union register_pair req_off = {.even = req, .odd = offset}; int cc = -ENXIO; asm volatile ( - " .insn rre,0xb9d00000,%[data],%[req]\n" + " .insn rre,0xb9d00000,%[data],%[req_off]\n" "0: ipm %[cc]\n" " srl %[cc],28\n" "1:\n" EX_TABLE(0b, 1b) - : [cc] "+d" (cc), [req] "+d" (__req) - : "d" (__offset), [data] "d" (data) + : [cc] "+d" (cc), [req_off] "+&d" (req_off.pair) + : [data] "d" (data) : "cc"); - *status = __req >> 24 & 0xff; + *status = req_off.even >> 24 & 0xff; return cc; } @@ -257,20 +251,19 @@ static inline int zpci_store_fh(const volatile void __iomem *addr, u64 data, static inline int __pcistg_mio(u64 data, u64 ioaddr, u64 len, u8 *status) { - register u64 addr asm("2") = ioaddr; - register u64 r3 asm("3") = len; + union register_pair ioaddr_len = {.even = ioaddr, .odd = len}; int cc = -ENXIO; asm volatile ( - " .insn rre,0xb9d40000,%[data],%[ioaddr]\n" + " .insn rre,0xb9d40000,%[data],%[ioaddr_len]\n" "0: ipm %[cc]\n" " srl %[cc],28\n" "1:\n" EX_TABLE(0b, 1b) - : [cc] "+d" (cc), "+d" (r3) - : [data] "d" (data), [ioaddr] "d" (addr) - : "cc"); - *status = r3 >> 24 & 0xff; + : [cc] "+d" (cc), [ioaddr_len] "+&d" (ioaddr_len.pair) + : [data] "d" (data) + : "cc", "memory"); + *status = ioaddr_len.odd >> 24 & 0xff; return cc; } diff --git a/arch/s390/pci/pci_mmio.c b/arch/s390/pci/pci_mmio.c index 474617b88648..ae683aa623ac 100644 --- a/arch/s390/pci/pci_mmio.c +++ b/arch/s390/pci/pci_mmio.c @@ -49,8 +49,7 @@ static inline int __pcistg_mio_inuser( void __iomem *ioaddr, const void __user *src, u64 ulen, u8 *status) { - register u64 addr asm("2") = (u64 __force) ioaddr; - register u64 len asm("3") = ulen; + union register_pair ioaddr_len = {.even = (u64 __force)ioaddr, .odd = ulen}; int cc = -ENXIO; u64 val = 0; u64 cnt = ulen; @@ -68,7 +67,7 @@ static inline int __pcistg_mio_inuser( " aghi %[src],1\n" " ogr %[val],%[tmp]\n" " brctg %[cnt],0b\n" - "1: .insn rre,0xb9d40000,%[val],%[ioaddr]\n" + "1: .insn rre,0xb9d40000,%[val],%[ioaddr_len]\n" "2: ipm %[cc]\n" " srl %[cc],28\n" "3: sacf 768\n" @@ -76,10 +75,9 @@ static inline int __pcistg_mio_inuser( : [src] "+a" (src), [cnt] "+d" (cnt), [val] "+d" (val), [tmp] "=d" (tmp), - [len] "+d" (len), [cc] "+d" (cc), - [ioaddr] "+a" (addr) + [cc] "+d" (cc), [ioaddr_len] "+&d" (ioaddr_len.pair) :: "cc", "memory"); - *status = len >> 24 & 0xff; + *status = ioaddr_len.odd >> 24 & 0xff; /* did we read everything from user memory? */ if (!cc && cnt != 0) @@ -195,8 +193,7 @@ static inline int __pcilg_mio_inuser( void __user *dst, const void __iomem *ioaddr, u64 ulen, u8 *status) { - register u64 addr asm("2") = (u64 __force) ioaddr; - register u64 len asm("3") = ulen; + union register_pair ioaddr_len = {.even = (u64 __force)ioaddr, .odd = ulen}; u64 cnt = ulen; int shift = ulen * 8; int cc = -ENXIO; @@ -209,7 +206,7 @@ static inline int __pcilg_mio_inuser( */ asm volatile ( " sacf 256\n" - "0: .insn rre,0xb9d60000,%[val],%[ioaddr]\n" + "0: .insn rre,0xb9d60000,%[val],%[ioaddr_len]\n" "1: ipm %[cc]\n" " srl %[cc],28\n" " ltr %[cc],%[cc]\n" @@ -222,18 +219,17 @@ static inline int __pcilg_mio_inuser( "4: sacf 768\n" EX_TABLE(0b, 4b) EX_TABLE(1b, 4b) EX_TABLE(3b, 4b) : - [cc] "+d" (cc), [val] "=d" (val), [len] "+d" (len), + [ioaddr_len] "+&d" (ioaddr_len.pair), + [cc] "+d" (cc), [val] "=d" (val), [dst] "+a" (dst), [cnt] "+d" (cnt), [tmp] "=d" (tmp), [shift] "+d" (shift) - : - [ioaddr] "a" (addr) - : "cc", "memory"); + :: "cc", "memory"); /* did we write everything to the user space buffer? */ if (!cc && cnt != 0) cc = -EFAULT; - *status = len >> 24 & 0xff; + *status = ioaddr_len.odd >> 24 & 0xff; return cc; } -- cgit v1.2.3 From 88c2510cecb7e2b518e3c4fdf3cf0e13ebe9377c Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 14 Jun 2021 14:49:31 +0200 Subject: s390/ipl_parm: fix program check new psw handling The __diag308() inline asm temporarily changes the program check new psw to redirect a potential program check on the diag instruction. Restoring of the program check new psw is done in C code behind the inline asm. This can be problematic, especially if the function is inlined, since the compiler can reorder instructions in such a way that a different instruction, which may result in a program check, might be executed before the program check new psw has been restored. To avoid such a scenario move restoring into the inline asm. For consistency reasons move also saving of the original program check new psw into the inline asm. Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/boot/ipl_parm.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c index bc1f973e656a..6bf17c623770 100644 --- a/arch/s390/boot/ipl_parm.c +++ b/arch/s390/boot/ipl_parm.c @@ -28,22 +28,25 @@ static inline int __diag308(unsigned long subcode, void *addr) register unsigned long _addr asm("0") = (unsigned long)addr; register unsigned long _rc asm("1") = 0; unsigned long reg1, reg2; - psw_t old = S390_lowcore.program_new_psw; + psw_t old; asm volatile( + " mvc 0(16,%[psw_old]),0(%[psw_pgm])\n" " epsw %0,%1\n" - " st %0,%[psw_pgm]\n" - " st %1,%[psw_pgm]+4\n" + " st %0,0(%[psw_pgm])\n" + " st %1,4(%[psw_pgm])\n" " larl %0,1f\n" - " stg %0,%[psw_pgm]+8\n" + " stg %0,8(%[psw_pgm])\n" " diag %[addr],%[subcode],0x308\n" - "1: nopr %%r7\n" + "1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n" : "=&d" (reg1), "=&a" (reg2), - [psw_pgm] "=Q" (S390_lowcore.program_new_psw), + "+Q" (S390_lowcore.program_new_psw), + "=Q" (old), [addr] "+d" (_addr), "+d" (_rc) - : [subcode] "d" (subcode) + : [subcode] "d" (subcode), + [psw_old] "a" (&old), + [psw_pgm] "a" (&S390_lowcore.program_new_psw) : "cc", "memory"); - S390_lowcore.program_new_psw = old; return _rc; } -- cgit v1.2.3 From 9e2509265560a7b82cecfd39caae5cf7d62e59f3 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 14 Jun 2021 18:55:07 +0200 Subject: s390/ipl_parm: use register pair instead of register asm ...and slightly cleanup the inline asm. Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/boot/ipl_parm.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c index 6bf17c623770..0f84c072625e 100644 --- a/arch/s390/boot/ipl_parm.c +++ b/arch/s390/boot/ipl_parm.c @@ -25,29 +25,31 @@ int kaslr_enabled; static inline int __diag308(unsigned long subcode, void *addr) { - register unsigned long _addr asm("0") = (unsigned long)addr; - register unsigned long _rc asm("1") = 0; unsigned long reg1, reg2; + union register_pair r1; psw_t old; + r1.even = (unsigned long) addr; + r1.odd = 0; asm volatile( " mvc 0(16,%[psw_old]),0(%[psw_pgm])\n" - " epsw %0,%1\n" - " st %0,0(%[psw_pgm])\n" - " st %1,4(%[psw_pgm])\n" - " larl %0,1f\n" - " stg %0,8(%[psw_pgm])\n" - " diag %[addr],%[subcode],0x308\n" + " epsw %[reg1],%[reg2]\n" + " st %[reg1],0(%[psw_pgm])\n" + " st %[reg2],4(%[psw_pgm])\n" + " larl %[reg1],1f\n" + " stg %[reg1],8(%[psw_pgm])\n" + " diag %[r1],%[subcode],0x308\n" "1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n" - : "=&d" (reg1), "=&a" (reg2), + : [r1] "+&d" (r1.pair), + [reg1] "=&d" (reg1), + [reg2] "=&a" (reg2), "+Q" (S390_lowcore.program_new_psw), - "=Q" (old), - [addr] "+d" (_addr), "+d" (_rc) + "=Q" (old) : [subcode] "d" (subcode), [psw_old] "a" (&old), [psw_pgm] "a" (&S390_lowcore.program_new_psw) : "cc", "memory"); - return _rc; + return r1.odd; } void store_ipl_parmblock(void) -- cgit v1.2.3 From 53c1c2504b6b35871b20c832be96163c846f3517 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 14 Jun 2021 19:38:07 +0200 Subject: s390/pgtable: use register pair instead of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/pgtable.h | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 5677be473261..90e45ac5516f 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -558,27 +558,25 @@ static inline int mm_uses_skeys(struct mm_struct *mm) static inline void csp(unsigned int *ptr, unsigned int old, unsigned int new) { - register unsigned long reg2 asm("2") = old; - register unsigned long reg3 asm("3") = new; + union register_pair r1 = { .even = old, .odd = new, }; unsigned long address = (unsigned long)ptr | 1; asm volatile( - " csp %0,%3" - : "+d" (reg2), "+m" (*ptr) - : "d" (reg3), "d" (address) + " csp %[r1],%[address]" + : [r1] "+&d" (r1.pair), "+m" (*ptr) + : [address] "d" (address) : "cc"); } static inline void cspg(unsigned long *ptr, unsigned long old, unsigned long new) { - register unsigned long reg2 asm("2") = old; - register unsigned long reg3 asm("3") = new; + union register_pair r1 = { .even = old, .odd = new, }; unsigned long address = (unsigned long)ptr | 1; asm volatile( - " .insn rre,0xb98a0000,%0,%3" - : "+d" (reg2), "+m" (*ptr) - : "d" (reg3), "d" (address) + " .insn rre,0xb98a0000,%[r1],%[address]" + : [r1] "+&d" (r1.pair), "+m" (*ptr) + : [address] "d" (address) : "cc"); } @@ -592,14 +590,12 @@ static inline void crdte(unsigned long old, unsigned long new, unsigned long table, unsigned long dtt, unsigned long address, unsigned long asce) { - register unsigned long reg2 asm("2") = old; - register unsigned long reg3 asm("3") = new; - register unsigned long reg4 asm("4") = table | dtt; - register unsigned long reg5 asm("5") = address; + union register_pair r1 = { .even = old, .odd = new, }; + union register_pair r2 = { .even = table | dtt, .odd = address, }; - asm volatile(".insn rrf,0xb98f0000,%0,%2,%4,0" - : "+d" (reg2) - : "d" (reg3), "d" (reg4), "d" (reg5), "a" (asce) + asm volatile(".insn rrf,0xb98f0000,%[r1],%[r2],%[asce],0" + : [r1] "+&d" (r1.pair) + : [r2] "d" (r2.pair), [asce] "a" (asce) : "memory", "cc"); } -- cgit v1.2.3 From 5fe29839deb49ae5e9af32c1d344c867398b33eb Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 14 Jun 2021 19:54:42 +0200 Subject: s390/sysinfo: get rid of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/sysinfo.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c index 2ac3c9b56a13..ef3f2659876c 100644 --- a/arch/s390/kernel/sysinfo.c +++ b/arch/s390/kernel/sysinfo.c @@ -25,19 +25,22 @@ int topology_max_mnest; static inline int __stsi(void *sysinfo, int fc, int sel1, int sel2, int *lvl) { - register int r0 asm("0") = (fc << 28) | sel1; - register int r1 asm("1") = sel2; + int r0 = (fc << 28) | sel1; int rc = 0; asm volatile( - " stsi 0(%3)\n" + " lr 0,%[r0]\n" + " lr 1,%[r1]\n" + " stsi 0(%[sysinfo])\n" "0: jz 2f\n" - "1: lhi %1,%4\n" - "2:\n" + "1: lhi %[rc],%[retval]\n" + "2: lr %[r0],0\n" EX_TABLE(0b, 1b) - : "+d" (r0), "+d" (rc) - : "d" (r1), "a" (sysinfo), "K" (-EOPNOTSUPP) - : "cc", "memory"); + : [r0] "+d" (r0), [rc] "+d" (rc) + : [r1] "d" (sel2), + [sysinfo] "a" (sysinfo), + [retval] "K" (-EOPNOTSUPP) + : "cc", "0", "1", "memory"); *lvl = ((unsigned int) r0) >> 28; return rc; } -- cgit v1.2.3 From dbb8864b28d6323cb38e5ce332cc3bb7f46ed5d3 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 14 Jun 2021 21:07:37 +0200 Subject: s390/uaccess: get rid of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/uaccess.h | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h index 4756d2937e54..2316f2440881 100644 --- a/arch/s390/include/asm/uaccess.h +++ b/arch/s390/include/asm/uaccess.h @@ -49,52 +49,51 @@ int __get_user_bad(void) __attribute__((noreturn)); #ifdef CONFIG_HAVE_MARCH_Z10_FEATURES -#define __put_get_user_asm(to, from, size, spec) \ +#define __put_get_user_asm(to, from, size, insn) \ ({ \ - register unsigned long __reg0 asm("0") = spec; \ int __rc; \ \ asm volatile( \ - "0: mvcos %1,%3,%2\n" \ - "1: xr %0,%0\n" \ + insn " 0,%[spec]\n" \ + "0: mvcos %[_to],%[_from],%[_size]\n" \ + "1: xr %[rc],%[rc]\n" \ "2:\n" \ ".pushsection .fixup, \"ax\"\n" \ - "3: lhi %0,%5\n" \ + "3: lhi %[rc],%[retval]\n" \ " jg 2b\n" \ ".popsection\n" \ EX_TABLE(0b,3b) EX_TABLE(1b,3b) \ - : "=d" (__rc), "+Q" (*(to)) \ - : "d" (size), "Q" (*(from)), \ - "d" (__reg0), "K" (-EFAULT) \ - : "cc"); \ + : [rc] "=&d" (__rc), [_to] "+Q" (*(to)) \ + : [_size] "d" (size), [_from] "Q" (*(from)), \ + [retval] "K" (-EFAULT), [spec] "K" (0x81UL) \ + : "cc", "0"); \ __rc; \ }) static __always_inline int __put_user_fn(void *x, void __user *ptr, unsigned long size) { - unsigned long spec = 0x810000UL; int rc; switch (size) { case 1: rc = __put_get_user_asm((unsigned char __user *)ptr, (unsigned char *)x, - size, spec); + size, "llilh"); break; case 2: rc = __put_get_user_asm((unsigned short __user *)ptr, (unsigned short *)x, - size, spec); + size, "llilh"); break; case 4: rc = __put_get_user_asm((unsigned int __user *)ptr, (unsigned int *)x, - size, spec); + size, "llilh"); break; case 8: rc = __put_get_user_asm((unsigned long __user *)ptr, (unsigned long *)x, - size, spec); + size, "llilh"); break; default: __put_user_bad(); @@ -105,29 +104,28 @@ static __always_inline int __put_user_fn(void *x, void __user *ptr, unsigned lon static __always_inline int __get_user_fn(void *x, const void __user *ptr, unsigned long size) { - unsigned long spec = 0x81UL; int rc; switch (size) { case 1: rc = __put_get_user_asm((unsigned char *)x, (unsigned char __user *)ptr, - size, spec); + size, "lghi"); break; case 2: rc = __put_get_user_asm((unsigned short *)x, (unsigned short __user *)ptr, - size, spec); + size, "lghi"); break; case 4: rc = __put_get_user_asm((unsigned int *)x, (unsigned int __user *)ptr, - size, spec); + size, "lghi"); break; case 8: rc = __put_get_user_asm((unsigned long *)x, (unsigned long __user *)ptr, - size, spec); + size, "lghi"); break; default: __get_user_bad(); -- cgit v1.2.3 From d99aea73b4de2357095e1059637ef5427e9473e8 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 14 Jun 2021 21:30:44 +0200 Subject: s390/facility: get rid of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/facility.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/facility.h b/arch/s390/include/asm/facility.h index 948e2616fe9c..e3aa354ab9f4 100644 --- a/arch/s390/include/asm/facility.h +++ b/arch/s390/include/asm/facility.h @@ -64,13 +64,15 @@ static inline int test_facility(unsigned long nr) static inline unsigned long __stfle_asm(u64 *stfle_fac_list, int size) { - register unsigned long reg0 asm("0") = size - 1; + unsigned long reg0 = size - 1; asm volatile( - ".insn s,0xb2b00000,0(%1)" /* stfle */ - : "+d" (reg0) - : "a" (stfle_fac_list) - : "memory", "cc"); + " lgr 0,%[reg0]\n" + " .insn s,0xb2b00000,%[list]\n" /* stfle */ + " lgr %[reg0],0\n" + : [reg0] "+&d" (reg0), [list] "+Q" (*stfle_fac_list) + : + : "memory", "cc", "0"); return reg0; } -- cgit v1.2.3 From 86807f348f418a84970eebb8f9912a7eea16b497 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 14 Jun 2021 21:40:43 +0200 Subject: s390/mem_detect: fix diag260() program check new psw handling The __diag260() inline asm temporarily changes the program check new psw to redirect a potential program check on the diag instruction. Restoring of the program check new psw is done in C code behind the inline asm. This can be problematic, especially if the function is inlined, since the compiler can reorder instructions in such a way that a different instruction, which may result in a program check, might be executed before the program check new psw has been restored. To avoid such a scenario move restoring into the inline asm. For consistency reasons move also saving of the original program check new psw into the inline asm. Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/boot/mem_detect.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/boot/mem_detect.c b/arch/s390/boot/mem_detect.c index 40168e59abd3..3f093556dc3b 100644 --- a/arch/s390/boot/mem_detect.c +++ b/arch/s390/boot/mem_detect.c @@ -69,24 +69,27 @@ static int __diag260(unsigned long rx1, unsigned long rx2) register unsigned long _ry asm("4") = 0x10; /* storage configuration */ int rc = -1; /* fail */ unsigned long reg1, reg2; - psw_t old = S390_lowcore.program_new_psw; + psw_t old; asm volatile( + " mvc 0(16,%[psw_old]),0(%[psw_pgm])\n" " epsw %0,%1\n" - " st %0,%[psw_pgm]\n" - " st %1,%[psw_pgm]+4\n" + " st %0,0(%[psw_pgm])\n" + " st %1,4(%[psw_pgm])\n" " larl %0,1f\n" - " stg %0,%[psw_pgm]+8\n" + " stg %0,8(%[psw_pgm])\n" " diag %[rx],%[ry],0x260\n" " ipm %[rc]\n" " srl %[rc],28\n" - "1:\n" + "1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n" : "=&d" (reg1), "=&a" (reg2), - [psw_pgm] "=Q" (S390_lowcore.program_new_psw), + "+Q" (S390_lowcore.program_new_psw), + "=Q" (old), [rc] "+&d" (rc), [ry] "+d" (_ry) - : [rx] "d" (_rx1), "d" (_rx2) + : [rx] "d" (_rx1), "d" (_rx2), + [psw_old] "a" (&old), + [psw_pgm] "a" (&S390_lowcore.program_new_psw) : "cc", "memory"); - S390_lowcore.program_new_psw = old; return rc == 0 ? _ry : -1; } -- cgit v1.2.3 From 1b2f281f45afd5def728288df9732a74e8d12582 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 14 Jun 2021 21:57:58 +0200 Subject: s390/mem_detect: use register pair instead of register asm ...and slightly cleanup the inline asm. Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/boot/mem_detect.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/boot/mem_detect.c b/arch/s390/boot/mem_detect.c index 3f093556dc3b..2c5a9c61b101 100644 --- a/arch/s390/boot/mem_detect.c +++ b/arch/s390/boot/mem_detect.c @@ -64,33 +64,37 @@ void add_mem_detect_block(u64 start, u64 end) static int __diag260(unsigned long rx1, unsigned long rx2) { - register unsigned long _rx1 asm("2") = rx1; - register unsigned long _rx2 asm("3") = rx2; - register unsigned long _ry asm("4") = 0x10; /* storage configuration */ - int rc = -1; /* fail */ - unsigned long reg1, reg2; + unsigned long reg1, reg2, ry; + union register_pair rx; psw_t old; + int rc; + rx.even = rx1; + rx.odd = rx2; + ry = 0x10; /* storage configuration */ + rc = -1; /* fail */ asm volatile( " mvc 0(16,%[psw_old]),0(%[psw_pgm])\n" - " epsw %0,%1\n" - " st %0,0(%[psw_pgm])\n" - " st %1,4(%[psw_pgm])\n" - " larl %0,1f\n" - " stg %0,8(%[psw_pgm])\n" + " epsw %[reg1],%[reg2]\n" + " st %[reg1],0(%[psw_pgm])\n" + " st %[reg2],4(%[psw_pgm])\n" + " larl %[reg1],1f\n" + " stg %[reg1],8(%[psw_pgm])\n" " diag %[rx],%[ry],0x260\n" " ipm %[rc]\n" " srl %[rc],28\n" "1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n" - : "=&d" (reg1), "=&a" (reg2), + : [reg1] "=&d" (reg1), + [reg2] "=&a" (reg2), + [rc] "+&d" (rc), + [ry] "+&d" (ry), "+Q" (S390_lowcore.program_new_psw), - "=Q" (old), - [rc] "+&d" (rc), [ry] "+d" (_ry) - : [rx] "d" (_rx1), "d" (_rx2), + "=Q" (old) + : [rx] "d" (rx.pair), [psw_old] "a" (&old), [psw_pgm] "a" (&S390_lowcore.program_new_psw) : "cc", "memory"); - return rc == 0 ? _ry : -1; + return rc == 0 ? ry : -1; } static int diag260(void) -- cgit v1.2.3 From da9057576785aaab52e706e76c0475c85b77ec14 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 14 Jun 2021 22:09:20 +0200 Subject: s390/mem_detect: fix tprot() program check new psw handling The tprot() inline asm temporarily changes the program check new psw to redirect a potential program check on the diag instruction. Restoring of the program check new psw is done in C code behind the inline asm. This can be problematic, especially if the function is inlined, since the compiler can reorder instructions in such a way that a different instruction, which may result in a program check, might be executed before the program check new psw has been restored. To avoid such a scenario move restoring into the inline asm. For consistency reasons move also saving of the original program check new psw into the inline asm. Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/boot/mem_detect.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/boot/mem_detect.c b/arch/s390/boot/mem_detect.c index 2c5a9c61b101..4e17adbde495 100644 --- a/arch/s390/boot/mem_detect.c +++ b/arch/s390/boot/mem_detect.c @@ -118,24 +118,30 @@ static int diag260(void) static int tprot(unsigned long addr) { - unsigned long pgm_addr; + unsigned long reg1, reg2; int rc = -EFAULT; - psw_t old = S390_lowcore.program_new_psw; + psw_t old; - S390_lowcore.program_new_psw.mask = __extract_psw(); asm volatile( - " larl %[pgm_addr],1f\n" - " stg %[pgm_addr],%[psw_pgm_addr]\n" + " mvc 0(16,%[psw_old]),0(%[psw_pgm])\n" + " epsw %[reg1],%[reg2]\n" + " st %[reg1],0(%[psw_pgm])\n" + " st %[reg2],4(%[psw_pgm])\n" + " larl %[reg1],1f\n" + " stg %[reg1],8(%[psw_pgm])\n" " tprot 0(%[addr]),0\n" " ipm %[rc]\n" " srl %[rc],28\n" - "1:\n" - : [pgm_addr] "=&d"(pgm_addr), - [psw_pgm_addr] "=Q"(S390_lowcore.program_new_psw.addr), - [rc] "+&d"(rc) - : [addr] "a"(addr) + "1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n" + : [reg1] "=&d" (reg1), + [reg2] "=&a" (reg2), + [rc] "+&d" (rc), + "=Q" (S390_lowcore.program_new_psw.addr), + "=Q" (old) + : [psw_old] "a" (&old), + [psw_pgm] "a" (&S390_lowcore.program_new_psw), + [addr] "a" (addr) : "cc", "memory"); - S390_lowcore.program_new_psw = old; return rc; } -- cgit v1.2.3 From 5a4e0f58e2d959e2de0f0f1ddaa169e60711d2f0 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 14 Jun 2021 22:32:21 +0200 Subject: s390/ipl: use register pair instead of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/ipl.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index dba04fbc37a2..9ae33977e0b7 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -162,16 +162,18 @@ static bool reipl_ccw_clear; static inline int __diag308(unsigned long subcode, void *addr) { - register unsigned long _addr asm("0") = (unsigned long) addr; - register unsigned long _rc asm("1") = 0; + union register_pair r1; + r1.even = (unsigned long) addr; + r1.odd = 0; asm volatile( - " diag %0,%2,0x308\n" + " diag %[r1],%[subcode],0x308\n" "0: nopr %%r7\n" EX_TABLE(0b,0b) - : "+d" (_addr), "+d" (_rc) - : "d" (subcode) : "cc", "memory"); - return _rc; + : [r1] "+&d" (r1.pair) + : [subcode] "d" (subcode) + : "cc", "memory"); + return r1.odd; } int diag308(unsigned long subcode, void *addr) -- cgit v1.2.3 From c1e18c17bda68cdf2b58744b2864836de05dcf3a Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Thu, 10 Dec 2020 15:28:05 +0100 Subject: s390/pci: add zpci_set_irq()/zpci_clear_irq() Pull the directed vs floating IRQ check into common zpci_set_irq()/zpci_clear_irq() functions and expose them for the rest of the zPCI subsystem. Furthermore we add a zdev flag bit to easily check if IRQs are registered. This is needed for use in resetting a zPCI function. Reviewed-by: Matthew Rosato Signed-off-by: Niklas Schnelle Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/pci.h | 7 ++++++- arch/s390/pci/pci_irq.c | 46 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 42 insertions(+), 11 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 10b67f8aab99..5509b224c2ec 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -133,7 +133,8 @@ struct zpci_dev { u8 has_resources : 1; u8 is_physfn : 1; u8 util_str_avail : 1; - u8 reserved : 3; + u8 irqs_registered : 1; + u8 reserved : 2; unsigned int devfn; /* DEVFN part of the RID*/ struct mutex lock; @@ -271,9 +272,13 @@ struct zpci_dev *get_zdev_by_fid(u32); int zpci_dma_init(void); void zpci_dma_exit(void); +/* IRQ */ int __init zpci_irq_init(void); void __init zpci_irq_exit(void); +int zpci_set_irq(struct zpci_dev *zdev); +int zpci_clear_irq(struct zpci_dev *zdev); + /* FMB */ int zpci_fmb_enable_device(struct zpci_dev *); int zpci_fmb_disable_device(struct zpci_dev *); diff --git a/arch/s390/pci/pci_irq.c b/arch/s390/pci/pci_irq.c index 9dd5ad1b553d..9c7de9089939 100644 --- a/arch/s390/pci/pci_irq.c +++ b/arch/s390/pci/pci_irq.c @@ -35,7 +35,7 @@ static struct airq_iv *zpci_sbv; */ static struct airq_iv **zpci_ibv; -/* Modify PCI: Register adapter interruptions */ +/* Modify PCI: Register floating adapter interruptions */ static int zpci_set_airq(struct zpci_dev *zdev) { u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_REG_INT); @@ -53,7 +53,7 @@ static int zpci_set_airq(struct zpci_dev *zdev) return zpci_mod_fc(req, &fib, &status) ? -EIO : 0; } -/* Modify PCI: Unregister adapter interruptions */ +/* Modify PCI: Unregister floating adapter interruptions */ static int zpci_clear_airq(struct zpci_dev *zdev) { u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_DEREG_INT); @@ -98,6 +98,38 @@ static int zpci_clear_directed_irq(struct zpci_dev *zdev) return cc ? -EIO : 0; } +/* Register adapter interruptions */ +int zpci_set_irq(struct zpci_dev *zdev) +{ + int rc; + + if (irq_delivery == DIRECTED) + rc = zpci_set_directed_irq(zdev); + else + rc = zpci_set_airq(zdev); + + if (!rc) + zdev->irqs_registered = 1; + + return rc; +} + +/* Clear adapter interruptions */ +int zpci_clear_irq(struct zpci_dev *zdev) +{ + int rc; + + if (irq_delivery == DIRECTED) + rc = zpci_clear_directed_irq(zdev); + else + rc = zpci_clear_airq(zdev); + + if (!rc) + zdev->irqs_registered = 0; + + return rc; +} + static int zpci_set_irq_affinity(struct irq_data *data, const struct cpumask *dest, bool force) { @@ -311,10 +343,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) zdev->msi_first_bit = bit; zdev->msi_nr_irqs = msi_vecs; - if (irq_delivery == DIRECTED) - rc = zpci_set_directed_irq(zdev); - else - rc = zpci_set_airq(zdev); + rc = zpci_set_irq(zdev); if (rc) return rc; @@ -328,10 +357,7 @@ void arch_teardown_msi_irqs(struct pci_dev *pdev) int rc; /* Disable interrupts */ - if (irq_delivery == DIRECTED) - rc = zpci_clear_directed_irq(zdev); - else - rc = zpci_clear_airq(zdev); + rc = zpci_clear_irq(zdev); if (rc) return; -- cgit v1.2.3 From c74d3c182ab4a3db6c3c2a6c4b3c8b9a7f1feb1a Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 16 Jun 2021 13:18:23 -0700 Subject: s390/speculation: Use statically initialized const for instructions In preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid confusing the checks when using a static const source. Move the static const array into a variable so the compiler can perform appropriate bounds checking. Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20210616201823.1245603-1-keescook@chromium.org Signed-off-by: Vasily Gorbik --- arch/s390/kernel/nospec-branch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 2c5c3756644b..250e4dbf653c 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -99,6 +99,7 @@ early_param("spectre_v2", spectre_v2_setup_early); static void __init_or_module __nospec_revert(s32 *start, s32 *end) { enum { BRCL_EXPOLINE, BRASL_EXPOLINE } type; + static const u8 branch[] = { 0x47, 0x00, 0x07, 0x00 }; u8 *instr, *thunk, *br; u8 insnbuf[6]; s32 *epo; @@ -128,7 +129,7 @@ static void __init_or_module __nospec_revert(s32 *start, s32 *end) if ((br[0] & 0xbf) != 0x07 || (br[1] & 0xf0) != 0xf0) continue; - memcpy(insnbuf + 2, (char[]) { 0x47, 0x00, 0x07, 0x00 }, 4); + memcpy(insnbuf + 2, branch, sizeof(branch)); switch (type) { case BRCL_EXPOLINE: insnbuf[0] = br[0]; -- cgit v1.2.3 From cf1ffce243bc5a6f173621e5fa5afca67993e2c7 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 17 Jun 2021 10:26:57 +0200 Subject: s390/hypfs: use register pair instead of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/hypfs/hypfs_sprp.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/hypfs/hypfs_sprp.c b/arch/s390/hypfs/hypfs_sprp.c index 7d9fb496d155..f5f7e78ddc0c 100644 --- a/arch/s390/hypfs/hypfs_sprp.c +++ b/arch/s390/hypfs/hypfs_sprp.c @@ -25,14 +25,13 @@ static inline unsigned long __hypfs_sprp_diag304(void *data, unsigned long cmd) { - register unsigned long _data asm("2") = (unsigned long) data; - register unsigned long _rc asm("3"); - register unsigned long _cmd asm("4") = cmd; + union register_pair r1 = { .even = (unsigned long)data, }; - asm volatile("diag %1,%2,0x304\n" - : "=d" (_rc) : "d" (_data), "d" (_cmd) : "memory"); - - return _rc; + asm volatile("diag %[r1],%[r3],0x304\n" + : [r1] "+&d" (r1.pair) + : [r3] "d" (cmd) + : "memory"); + return r1.odd; } static unsigned long hypfs_sprp_diag304(void *data, unsigned long cmd) -- cgit v1.2.3 From fcc91d5d40475a5d0ea8f6b63f6fe8a693fc2142 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 17 Jun 2021 11:32:53 +0200 Subject: s390/timex: get rid of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/timex.h | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h index f6326c6d2abe..50d9b04ecbd1 100644 --- a/arch/s390/include/asm/timex.h +++ b/arch/s390/include/asm/timex.h @@ -75,9 +75,12 @@ static inline void set_clock_comparator(__u64 time) static inline void set_tod_programmable_field(u16 val) { - register unsigned long reg0 asm("0") = val; - - asm volatile("sckpf" : : "d" (reg0)); + asm volatile( + " lgr 0,%[val]\n" + " sckpf\n" + : + : [val] "d" ((unsigned long)val) + : "0"); } void clock_comparator_work(void); @@ -138,16 +141,19 @@ struct ptff_qui { #define ptff(ptff_block, len, func) \ ({ \ struct addrtype { char _[len]; }; \ - register unsigned int reg0 asm("0") = func; \ - register unsigned long reg1 asm("1") = (unsigned long) (ptff_block);\ + unsigned int reg0 = func; \ + unsigned long reg1 = (unsigned long)(ptff_block); \ int rc; \ \ asm volatile( \ - " .word 0x0104\n" \ - " ipm %0\n" \ - " srl %0,28\n" \ - : "=d" (rc), "+m" (*(struct addrtype *) reg1) \ - : "d" (reg0), "d" (reg1) : "cc"); \ + " lgr 0,%[reg0]\n" \ + " lgr 1,%[reg1]\n" \ + " .insn e,0x0104\n" \ + " ipm %[rc]\n" \ + " srl %[rc],28\n" \ + : [rc] "=&d" (rc), "+m" (*(struct addrtype *)reg1) \ + : [reg0] "d" (reg0), [reg1] "d" (reg1) \ + : "cc", "0", "1"); \ rc; \ }) -- cgit v1.2.3 From 7e86f967f4c98a6ad2a8c33c39f041e2955c05c8 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 17 Jun 2021 20:11:40 +0200 Subject: s390/lib,xor: get rid of register asm Looking at the generate code this was just a micro-optimization. However given that as many register asm constructs as possible will be removed from s390 code, remove this one as well. Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/lib/xor.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/lib/xor.c b/arch/s390/lib/xor.c index 29d9470dbceb..a963c3d8ad0d 100644 --- a/arch/s390/lib/xor.c +++ b/arch/s390/lib/xor.c @@ -91,9 +91,6 @@ static void xor_xc_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, static void xor_xc_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, unsigned long *p3, unsigned long *p4, unsigned long *p5) { - /* Get around a gcc oddity */ - register unsigned long *reg7 asm ("7") = p5; - asm volatile( " larl 1,2f\n" " aghi %0,-1\n" @@ -122,7 +119,7 @@ static void xor_xc_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, " xc 0(1,%1),0(%5)\n" "3:\n" : "+d" (bytes), "+a" (p1), "+a" (p2), "+a" (p3), "+a" (p4), - "+a" (reg7) + "+a" (p5) : : "0", "1", "cc", "memory"); } -- cgit v1.2.3 From 2bd67038f89e6400afcdbdc53ad1fde674a58195 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 17 Jun 2021 20:30:15 +0200 Subject: s390/mm,pages-states: get rid of register asm There is no reason to use fixed registers for the essa instruction. Therefore remove the register asm construct. Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/mm/page-states.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c index 7f0e154a470a..68b153083a92 100644 --- a/arch/s390/mm/page-states.c +++ b/arch/s390/mm/page-states.c @@ -31,17 +31,17 @@ __setup("cmma=", cmma); static inline int cmma_test_essa(void) { - register unsigned long tmp asm("0") = 0; - register int rc asm("1"); + unsigned long tmp = 0; + int rc = -EOPNOTSUPP; /* test ESSA_GET_STATE */ asm volatile( - " .insn rrf,0xb9ab0000,%1,%1,%2,0\n" - "0: la %0,0\n" + " .insn rrf,0xb9ab0000,%[tmp],%[tmp],%[cmd],0\n" + "0: la %[rc],0\n" "1:\n" EX_TABLE(0b,1b) - : "=&d" (rc), "+&d" (tmp) - : "i" (ESSA_GET_STATE), "0" (-EOPNOTSUPP)); + : [rc] "+&d" (rc), [tmp] "+&d" (tmp) + : [cmd] "i" (ESSA_GET_STATE)); return rc; } -- cgit v1.2.3 From 79ee201e26020cd950f7852a5ca12c395a3ee6e9 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 17 Jun 2021 21:18:14 +0200 Subject: s390/cmpxchg: use register pair instead of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/cmpxchg.h | 44 ++++++++++++++++++++++------------------- arch/s390/include/asm/percpu.h | 27 +++++++++++++------------ 2 files changed, 38 insertions(+), 33 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/cmpxchg.h b/arch/s390/include/asm/cmpxchg.h index 1960a7295ae5..84c3f0d576c5 100644 --- a/arch/s390/include/asm/cmpxchg.h +++ b/arch/s390/include/asm/cmpxchg.h @@ -169,32 +169,36 @@ static __always_inline unsigned long __cmpxchg(unsigned long address, #define system_has_cmpxchg_double() 1 -#define __cmpxchg_double(p1, p2, o1, o2, n1, n2) \ -({ \ - register __typeof__(*(p1)) __old1 asm("2") = (o1); \ - register __typeof__(*(p2)) __old2 asm("3") = (o2); \ - register __typeof__(*(p1)) __new1 asm("4") = (n1); \ - register __typeof__(*(p2)) __new2 asm("5") = (n2); \ - int cc; \ - asm volatile( \ - " cdsg %[old],%[new],%[ptr]\n" \ - " ipm %[cc]\n" \ - " srl %[cc],28" \ - : [cc] "=d" (cc), [old] "+d" (__old1), "+d" (__old2) \ - : [new] "d" (__new1), "d" (__new2), \ - [ptr] "Q" (*(p1)), "Q" (*(p2)) \ - : "memory", "cc"); \ - !cc; \ -}) +static __always_inline int __cmpxchg_double(unsigned long p1, unsigned long p2, + unsigned long o1, unsigned long o2, + unsigned long n1, unsigned long n2) +{ + union register_pair old = { .even = o1, .odd = o2, }; + union register_pair new = { .even = n1, .odd = n2, }; + int cc; + + asm volatile( + " cdsg %[old],%[new],%[ptr]\n" + " ipm %[cc]\n" + " srl %[cc],28\n" + : [cc] "=&d" (cc), [old] "+&d" (old.pair) + : [new] "d" (new.pair), + [ptr] "QS" (*(unsigned long *)p1), "Q" (*(unsigned long *)p2) + : "memory", "cc"); + return !cc; +} #define arch_cmpxchg_double(p1, p2, o1, o2, n1, n2) \ ({ \ - __typeof__(p1) __p1 = (p1); \ - __typeof__(p2) __p2 = (p2); \ + typeof(p1) __p1 = (p1); \ + typeof(p2) __p2 = (p2); \ + \ BUILD_BUG_ON(sizeof(*(p1)) != sizeof(long)); \ BUILD_BUG_ON(sizeof(*(p2)) != sizeof(long)); \ VM_BUG_ON((unsigned long)((__p1) + 1) != (unsigned long)(__p2));\ - __cmpxchg_double(__p1, __p2, o1, o2, n1, n2); \ + __cmpxchg_double((unsigned long)__p1, (unsigned long)__p2, \ + (unsigned long)(o1), (unsigned long)(o2), \ + (unsigned long)(n1), (unsigned long)(n2)); \ }) #endif /* __ASM_CMPXCHG_H */ diff --git a/arch/s390/include/asm/percpu.h b/arch/s390/include/asm/percpu.h index 918f0ba4f4d2..cb5fc0690435 100644 --- a/arch/s390/include/asm/percpu.h +++ b/arch/s390/include/asm/percpu.h @@ -164,19 +164,20 @@ #define this_cpu_xchg_4(pcp, nval) arch_this_cpu_xchg(pcp, nval) #define this_cpu_xchg_8(pcp, nval) arch_this_cpu_xchg(pcp, nval) -#define arch_this_cpu_cmpxchg_double(pcp1, pcp2, o1, o2, n1, n2) \ -({ \ - typeof(pcp1) o1__ = (o1), n1__ = (n1); \ - typeof(pcp2) o2__ = (o2), n2__ = (n2); \ - typeof(pcp1) *p1__; \ - typeof(pcp2) *p2__; \ - int ret__; \ - preempt_disable_notrace(); \ - p1__ = raw_cpu_ptr(&(pcp1)); \ - p2__ = raw_cpu_ptr(&(pcp2)); \ - ret__ = __cmpxchg_double(p1__, p2__, o1__, o2__, n1__, n2__); \ - preempt_enable_notrace(); \ - ret__; \ +#define arch_this_cpu_cmpxchg_double(pcp1, pcp2, o1, o2, n1, n2) \ +({ \ + typeof(pcp1) *p1__; \ + typeof(pcp2) *p2__; \ + int ret__; \ + \ + preempt_disable_notrace(); \ + p1__ = raw_cpu_ptr(&(pcp1)); \ + p2__ = raw_cpu_ptr(&(pcp2)); \ + ret__ = __cmpxchg_double((unsigned long)p1__, (unsigned long)p2__, \ + (unsigned long)(o1), (unsigned long)(o2), \ + (unsigned long)(n1), (unsigned long)(n2)); \ + preempt_enable_notrace(); \ + ret__; \ }) #define this_cpu_cmpxchg_double_8 arch_this_cpu_cmpxchg_double -- cgit v1.2.3 From 8f45db5555e38cf67cc38e485013e40e4a23c624 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 21 Jun 2021 11:30:30 +0200 Subject: s390/string: get rid of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/string.h | 59 +++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 24 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/string.h b/arch/s390/include/asm/string.h index 4c0690fc5167..4fd66c5e8934 100644 --- a/arch/s390/include/asm/string.h +++ b/arch/s390/include/asm/string.h @@ -107,16 +107,18 @@ static inline void *memset64(uint64_t *s, uint64_t v, size_t count) #ifdef __HAVE_ARCH_MEMCHR static inline void *memchr(const void * s, int c, size_t n) { - register int r0 asm("0") = (char) c; const void *ret = s + n; asm volatile( - "0: srst %0,%1\n" + " lgr 0,%[c]\n" + "0: srst %[ret],%[s]\n" " jo 0b\n" " jl 1f\n" - " la %0,0\n" + " la %[ret],0\n" "1:" - : "+a" (ret), "+&a" (s) : "d" (r0) : "cc", "memory"); + : [ret] "+&a" (ret), [s] "+&a" (s) + : [c] "d" (c) + : "cc", "memory", "0"); return (void *) ret; } #endif @@ -124,13 +126,15 @@ static inline void *memchr(const void * s, int c, size_t n) #ifdef __HAVE_ARCH_MEMSCAN static inline void *memscan(void *s, int c, size_t n) { - register int r0 asm("0") = (char) c; const void *ret = s + n; asm volatile( - "0: srst %0,%1\n" + " lgr 0,%[c]\n" + "0: srst %[ret],%[s]\n" " jo 0b\n" - : "+a" (ret), "+&a" (s) : "d" (r0) : "cc", "memory"); + : [ret] "+&a" (ret), [s] "+&a" (s) + : [c] "d" (c) + : "cc", "memory", "0"); return (void *) ret; } #endif @@ -138,17 +142,18 @@ static inline void *memscan(void *s, int c, size_t n) #ifdef __HAVE_ARCH_STRCAT static inline char *strcat(char *dst, const char *src) { - register int r0 asm("0") = 0; - unsigned long dummy; + unsigned long dummy = 0; char *ret = dst; asm volatile( - "0: srst %0,%1\n" + " lghi 0,0\n" + "0: srst %[dummy],%[dst]\n" " jo 0b\n" - "1: mvst %0,%2\n" + "1: mvst %[dummy],%[src]\n" " jo 1b" - : "=&a" (dummy), "+a" (dst), "+a" (src) - : "d" (r0), "0" (0) : "cc", "memory" ); + : [dummy] "+&a" (dummy), [dst] "+&a" (dst), [src] "+&a" (src) + : + : "cc", "memory", "0"); return ret; } #endif @@ -156,14 +161,15 @@ static inline char *strcat(char *dst, const char *src) #ifdef __HAVE_ARCH_STRCPY static inline char *strcpy(char *dst, const char *src) { - register int r0 asm("0") = 0; char *ret = dst; asm volatile( - "0: mvst %0,%1\n" + " lghi 0,0\n" + "0: mvst %[dst],%[src]\n" " jo 0b" - : "+&a" (dst), "+&a" (src) : "d" (r0) - : "cc", "memory"); + : [dst] "+&a" (dst), [src] "+&a" (src) + : + : "cc", "memory", "0"); return ret; } #endif @@ -171,28 +177,33 @@ static inline char *strcpy(char *dst, const char *src) #if defined(__HAVE_ARCH_STRLEN) || (defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__)) static inline size_t __no_sanitize_prefix_strfunc(strlen)(const char *s) { - register unsigned long r0 asm("0") = 0; + unsigned long end = 0; const char *tmp = s; asm volatile( - "0: srst %0,%1\n" + " lghi 0,0\n" + "0: srst %[end],%[tmp]\n" " jo 0b" - : "+d" (r0), "+a" (tmp) : : "cc", "memory"); - return r0 - (unsigned long) s; + : [end] "+&a" (end), [tmp] "+&a" (tmp) + : + : "cc", "memory", "0"); + return end - (unsigned long)s; } #endif #ifdef __HAVE_ARCH_STRNLEN static inline size_t strnlen(const char * s, size_t n) { - register int r0 asm("0") = 0; const char *tmp = s; const char *end = s + n; asm volatile( - "0: srst %0,%1\n" + " lghi 0,0\n" + "0: srst %[end],%[tmp]\n" " jo 0b" - : "+a" (end), "+a" (tmp) : "d" (r0) : "cc", "memory"); + : [end] "+&a" (end), [tmp] "+&a" (tmp) + : + : "cc", "memory", "0"); return end - s; } #endif -- cgit v1.2.3 From d1e18efa8fa960dc18bca493efaf6adaecb38c7d Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 21 Jun 2021 13:38:45 +0200 Subject: s390/lib,uaccess: get rid of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/lib/uaccess.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/lib/uaccess.c b/arch/s390/lib/uaccess.c index 2fece1fd210a..67606d932825 100644 --- a/arch/s390/lib/uaccess.c +++ b/arch/s390/lib/uaccess.c @@ -61,11 +61,11 @@ static inline int copy_with_mvcos(void) static inline unsigned long copy_from_user_mvcos(void *x, const void __user *ptr, unsigned long size) { - register unsigned long reg0 asm("0") = 0x81UL; unsigned long tmp1, tmp2; tmp1 = -4096UL; asm volatile( + " lghi 0,%[spec]\n" "0: .insn ss,0xc80000000000,0(%0,%2),0(%1),0\n" "6: jz 4f\n" "1: algr %0,%3\n" @@ -84,7 +84,8 @@ static inline unsigned long copy_from_user_mvcos(void *x, const void __user *ptr "5:\n" EX_TABLE(0b,2b) EX_TABLE(3b,5b) EX_TABLE(6b,2b) EX_TABLE(7b,5b) : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) - : "d" (reg0) : "cc", "memory"); + : [spec] "K" (0x81UL) + : "cc", "memory", "0"); return size; } @@ -133,11 +134,11 @@ EXPORT_SYMBOL(raw_copy_from_user); static inline unsigned long copy_to_user_mvcos(void __user *ptr, const void *x, unsigned long size) { - register unsigned long reg0 asm("0") = 0x810000UL; unsigned long tmp1, tmp2; tmp1 = -4096UL; asm volatile( + " llilh 0,%[spec]\n" "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n" "6: jz 4f\n" "1: algr %0,%3\n" @@ -156,7 +157,8 @@ static inline unsigned long copy_to_user_mvcos(void __user *ptr, const void *x, "5:\n" EX_TABLE(0b,2b) EX_TABLE(3b,5b) EX_TABLE(6b,2b) EX_TABLE(7b,5b) : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) - : "d" (reg0) : "cc", "memory"); + : [spec] "K" (0x81UL) + : "cc", "memory", "0"); return size; } @@ -205,12 +207,12 @@ EXPORT_SYMBOL(raw_copy_to_user); static inline unsigned long copy_in_user_mvcos(void __user *to, const void __user *from, unsigned long size) { - register unsigned long reg0 asm("0") = 0x810081UL; unsigned long tmp1, tmp2; tmp1 = -4096UL; /* FIXME: copy with reduced length. */ asm volatile( + " lgr 0,%[spec]\n" "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n" " jz 2f\n" "1: algr %0,%3\n" @@ -221,7 +223,8 @@ static inline unsigned long copy_in_user_mvcos(void __user *to, const void __use "3: \n" EX_TABLE(0b,3b) : "+a" (size), "+a" (to), "+a" (from), "+a" (tmp1), "=a" (tmp2) - : "d" (reg0) : "cc", "memory"); + : [spec] "d" (0x810081UL) + : "cc", "memory"); return size; } @@ -266,11 +269,11 @@ EXPORT_SYMBOL(raw_copy_in_user); static inline unsigned long clear_user_mvcos(void __user *to, unsigned long size) { - register unsigned long reg0 asm("0") = 0x810000UL; unsigned long tmp1, tmp2; tmp1 = -4096UL; asm volatile( + " llilh 0,%[spec]\n" "0: .insn ss,0xc80000000000,0(%0,%1),0(%4),0\n" " jz 4f\n" "1: algr %0,%2\n" @@ -288,7 +291,8 @@ static inline unsigned long clear_user_mvcos(void __user *to, unsigned long size "5:\n" EX_TABLE(0b,2b) EX_TABLE(3b,5b) : "+a" (size), "+a" (to), "+a" (tmp1), "=a" (tmp2) - : "a" (empty_zero_page), "d" (reg0) : "cc", "memory"); + : "a" (empty_zero_page), [spec] "K" (0x81UL) + : "cc", "memory", "0"); return size; } @@ -338,10 +342,10 @@ EXPORT_SYMBOL(__clear_user); static inline unsigned long strnlen_user_srst(const char __user *src, unsigned long size) { - register unsigned long reg0 asm("0") = 0; unsigned long tmp1, tmp2; asm volatile( + " lghi 0,0\n" " la %2,0(%1)\n" " la %3,0(%0,%1)\n" " slgr %0,%0\n" @@ -353,7 +357,8 @@ static inline unsigned long strnlen_user_srst(const char __user *src, "1: sacf 768\n" EX_TABLE(0b,1b) : "+a" (size), "+a" (src), "=a" (tmp1), "=a" (tmp2) - : "d" (reg0) : "cc", "memory"); + : + : "cc", "memory", "0"); return size; } -- cgit v1.2.3 From 8cf23c8e1fec64c8a1e748816f2f2926cacfb0fa Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 21 Jun 2021 14:56:46 +0200 Subject: s390/lib,string: get rid of register asm Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/lib/string.c | 131 ++++++++++++++++++++++++++++--------------------- 1 file changed, 75 insertions(+), 56 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/lib/string.c b/arch/s390/lib/string.c index 93b3209b94a2..ec5b76bde4d8 100644 --- a/arch/s390/lib/string.c +++ b/arch/s390/lib/string.c @@ -18,23 +18,30 @@ */ static inline char *__strend(const char *s) { - register unsigned long r0 asm("0") = 0; - - asm volatile ("0: srst %0,%1\n" - " jo 0b" - : "+d" (r0), "+a" (s) : : "cc", "memory"); - return (char *) r0; + unsigned long e = 0; + + asm volatile( + " lghi 0,0\n" + "0: srst %[e],%[s]\n" + " jo 0b\n" + : [e] "+&a" (e), [s] "+&a" (s) + : + : "cc", "memory", "0"); + return (char *)e; } static inline char *__strnend(const char *s, size_t n) { - register unsigned long r0 asm("0") = 0; const char *p = s + n; - asm volatile ("0: srst %0,%1\n" - " jo 0b" - : "+d" (p), "+a" (s) : "d" (r0) : "cc", "memory"); - return (char *) p; + asm volatile( + " lghi 0,0\n" + "0: srst %[p],%[s]\n" + " jo 0b\n" + : [p] "+&d" (p), [s] "+&a" (s) + : + : "cc", "memory", "0"); + return (char *)p; } /** @@ -76,13 +83,15 @@ EXPORT_SYMBOL(strnlen); #ifdef __HAVE_ARCH_STRCPY char *strcpy(char *dest, const char *src) { - register int r0 asm("0") = 0; char *ret = dest; - asm volatile ("0: mvst %0,%1\n" - " jo 0b" - : "+&a" (dest), "+&a" (src) : "d" (r0) - : "cc", "memory" ); + asm volatile( + " lghi 0,0\n" + "0: mvst %[dest],%[src]\n" + " jo 0b\n" + : [dest] "+&a" (dest), [src] "+&a" (src) + : + : "cc", "memory", "0"); return ret; } EXPORT_SYMBOL(strcpy); @@ -144,16 +153,18 @@ EXPORT_SYMBOL(strncpy); #ifdef __HAVE_ARCH_STRCAT char *strcat(char *dest, const char *src) { - register int r0 asm("0") = 0; - unsigned long dummy; + unsigned long dummy = 0; char *ret = dest; - asm volatile ("0: srst %0,%1\n" - " jo 0b\n" - "1: mvst %0,%2\n" - " jo 1b" - : "=&a" (dummy), "+a" (dest), "+a" (src) - : "d" (r0), "0" (0UL) : "cc", "memory" ); + asm volatile( + " lghi 0,0\n" + "0: srst %[dummy],%[dest]\n" + " jo 0b\n" + "1: mvst %[dummy],%[src]\n" + " jo 1b\n" + : [dummy] "=&a" (dummy), [dest] "+&a" (dest), [src] "+&a" (src) + : + : "cc", "memory", "0"); return ret; } EXPORT_SYMBOL(strcat); @@ -221,18 +232,20 @@ EXPORT_SYMBOL(strncat); #ifdef __HAVE_ARCH_STRCMP int strcmp(const char *s1, const char *s2) { - register int r0 asm("0") = 0; int ret = 0; - asm volatile ("0: clst %2,%3\n" - " jo 0b\n" - " je 1f\n" - " ic %0,0(%2)\n" - " ic %1,0(%3)\n" - " sr %0,%1\n" - "1:" - : "+d" (ret), "+d" (r0), "+a" (s1), "+a" (s2) - : : "cc", "memory"); + asm volatile( + " lghi 0,0\n" + "0: clst %[s1],%[s2]\n" + " jo 0b\n" + " je 1f\n" + " ic %[ret],0(%[s1])\n" + " ic 0,0(%[s2])\n" + " sr %[ret],0\n" + "1:" + : [ret] "+&d" (ret), [s1] "+&a" (s1), [s2] "+&a" (s2) + : + : "cc", "memory", "0"); return ret; } EXPORT_SYMBOL(strcmp); @@ -261,18 +274,18 @@ EXPORT_SYMBOL(strrchr); static inline int clcle(const char *s1, unsigned long l1, const char *s2, unsigned long l2) { - register unsigned long r2 asm("2") = (unsigned long) s1; - register unsigned long r3 asm("3") = (unsigned long) l1; - register unsigned long r4 asm("4") = (unsigned long) s2; - register unsigned long r5 asm("5") = (unsigned long) l2; + union register_pair r1 = { .even = (unsigned long)s1, .odd = l1, }; + union register_pair r3 = { .even = (unsigned long)s2, .odd = l2, }; int cc; - asm volatile ("0: clcle %1,%3,0\n" - " jo 0b\n" - " ipm %0\n" - " srl %0,28" - : "=&d" (cc), "+a" (r2), "+a" (r3), - "+a" (r4), "+a" (r5) : : "cc", "memory"); + asm volatile( + "0: clcle %[r1],%[r3],0\n" + " jo 0b\n" + " ipm %[cc]\n" + " srl %[cc],28\n" + : [cc] "=&d" (cc), [r1] "+&d" (r1.pair), [r3] "+&d" (r3.pair) + : + : "cc", "memory"); return cc; } @@ -315,15 +328,18 @@ EXPORT_SYMBOL(strstr); #ifdef __HAVE_ARCH_MEMCHR void *memchr(const void *s, int c, size_t n) { - register int r0 asm("0") = (char) c; const void *ret = s + n; - asm volatile ("0: srst %0,%1\n" - " jo 0b\n" - " jl 1f\n" - " la %0,0\n" - "1:" - : "+a" (ret), "+&a" (s) : "d" (r0) : "cc", "memory"); + asm volatile( + " lgr 0,%[c]\n" + "0: srst %[ret],%[s]\n" + " jo 0b\n" + " jl 1f\n" + " la %[ret],0\n" + "1:" + : [ret] "+&a" (ret), [s] "+&a" (s) + : [c] "d" (c) + : "cc", "memory", "0"); return (void *) ret; } EXPORT_SYMBOL(memchr); @@ -360,13 +376,16 @@ EXPORT_SYMBOL(memcmp); #ifdef __HAVE_ARCH_MEMSCAN void *memscan(void *s, int c, size_t n) { - register int r0 asm("0") = (char) c; const void *ret = s + n; - asm volatile ("0: srst %0,%1\n" - " jo 0b\n" - : "+a" (ret), "+&a" (s) : "d" (r0) : "cc", "memory"); - return (void *) ret; + asm volatile( + " lgr 0,%[c]\n" + "0: srst %[ret],%[s]\n" + " jo 0b\n" + : [ret] "+&a" (ret), [s] "+&a" (s) + : [c] "d" (c) + : "cc", "memory", "0"); + return (void *)ret; } EXPORT_SYMBOL(memscan); #endif -- cgit v1.2.3