Skip to content

Commit

Permalink
Merge tag 's390-6.3-2' of git://git.kernel.org/pub/scm/linux/kernel/g…
Browse files Browse the repository at this point in the history
…it/s390/linux

Pull more s390 updates from Heiko Carstens:

 - Add empty command line parameter handling stubs to kernel for all
   command line parameters which are handled in the decompressor. This
   avoids invalid "Unknown kernel command line parameters" messages from
   the kernel, and also avoids that these will be incorrectly passed to
   user space. This caused already confusion, therefore add the empty
   stubs

 - Add missing phys_to_virt() handling to machine check handler

 - Introduce and use a union to be used for zcrypt inline assemblies.
   This makes sure that only a register wide member of the union is
   passed as input and output parameter to inline assemblies, while
   usual C code uses other members of the union to access bit fields of
   it

 - Add and use a READ_ONCE_ALIGNED_128() macro, which can be used to
   atomically read a 128-bit value from memory. This replaces the
   (mis-)use of the 128-bit cmpxchg operation to do the same in cpum_sf
   code. Currently gcc does not generate the used lpq instruction if
   __READ_ONCE() is used for aligned 128-bit accesses, therefore use
   this s390 specific helper

 - Simplify machine check handler code if a task needs to be killed
   because of e.g. register corruption due to a machine malfunction

 - Perform CPU reset to clear pending interrupts and TLB entries on an
   already stopped target CPU before delegating work to it

 - Generate arch/s390/boot/vmlinux.map link map for the decompressor,
   when CONFIG_VMLINUX_MAP is enabled for debugging purposes

 - Fix segment type handling for dcssblk devices. It incorrectly always
   returned type "READ/WRITE" even for read-only segements, which can
   result in a kernel panic if somebody tries to write to a read-only
   device

 - Sort config S390 select list again

 - Fix two kprobe reenter bugs revealed by a recently added kprobe kunit
   test

* tag 's390-6.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
  s390/kprobes: fix current_kprobe never cleared after kprobes reenter
  s390/kprobes: fix irq mask clobbering on kprobe reenter from post_handler
  s390/Kconfig: sort config S390 select list again
  s390/extmem: return correct segment type in __segment_load()
  s390/decompressor: add link map saving
  s390/smp: perform cpu reset before delegating work to target cpu
  s390/mcck: cleanup user process termination path
  s390/cpum_sf: use READ_ONCE_ALIGNED_128() instead of 128-bit cmpxchg
  s390/rwonce: add READ_ONCE_ALIGNED_128() macro
  s390/ap,zcrypt,vfio: introduce and use ap_queue_status_reg union
  s390/nmi: fix virtual-physical address confusion
  s390/setup: do not complain about parameters handled in decompressor
  • Loading branch information
Linus Torvalds committed Mar 3, 2023
2 parents bf1a1ba + cd57953 commit 0bdf4a8
Show file tree
Hide file tree
Showing 14 changed files with 131 additions and 102 deletions.
6 changes: 3 additions & 3 deletions arch/s390/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ config S390
select ARCH_WANTS_DYNAMIC_TASK_STRUCT
select ARCH_WANTS_NO_INSTR
select ARCH_WANT_DEFAULT_BPF_JIT
select ARCH_WANT_IPC_PARSE_VERSION
select ARCH_WANT_HUGETLB_PAGE_OPTIMIZE_VMEMMAP
select ARCH_WANT_IPC_PARSE_VERSION
select BUILDTIME_TABLE_SORT
select CLONE_BACKWARDS2
select DMA_OPS if PCI
Expand Down Expand Up @@ -187,7 +187,6 @@ config S390
select HAVE_KPROBES
select HAVE_KPROBES_ON_FTRACE
select HAVE_KRETPROBES
select HAVE_RETHOOK
select HAVE_KVM
select HAVE_LIVEPATCH
select HAVE_MEMBLOCK_PHYS_MAP
Expand All @@ -200,6 +199,7 @@ config S390
select HAVE_PERF_USER_STACK_DUMP
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_RELIABLE_STACKTRACE
select HAVE_RETHOOK
select HAVE_RSEQ
select HAVE_SAMPLE_FTRACE_DIRECT
select HAVE_SAMPLE_FTRACE_DIRECT_MULTI
Expand All @@ -210,9 +210,9 @@ config S390
select HAVE_VIRT_CPU_ACCOUNTING_IDLE
select IOMMU_HELPER if PCI
select IOMMU_SUPPORT if PCI
select MMU_GATHER_MERGE_VMAS
select MMU_GATHER_NO_GATHER
select MMU_GATHER_RCU_TABLE_FREE
select MMU_GATHER_MERGE_VMAS
select MODULES_USE_ELF_RELA
select NEED_DMA_MAP_STATE if PCI
select NEED_PER_CPU_EMBED_FIRST_CHUNK
Expand Down
4 changes: 3 additions & 1 deletion arch/s390/boot/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ targets += vmlinux.bin.zst info.bin syms.bin vmlinux.syms $(obj-all)
OBJECTS := $(addprefix $(obj)/,$(obj-y))
OBJECTS_ALL := $(addprefix $(obj)/,$(obj-all))

clean-files += vmlinux.map

quiet_cmd_section_cmp = SECTCMP $*
define cmd_section_cmp
s1=`$(OBJDUMP) -t -j "$*" "$<" | sort | \
Expand All @@ -71,7 +73,7 @@ $(obj)/bzImage: $(obj)/vmlinux $(obj)/section_cmp.boot.data $(obj)/section_cmp.b
$(obj)/section_cmp%: vmlinux $(obj)/vmlinux FORCE
$(call if_changed,section_cmp)

LDFLAGS_vmlinux := --oformat $(LD_BFD) -e startup --build-id=sha1 -T
LDFLAGS_vmlinux := --oformat $(LD_BFD) -e startup $(if $(CONFIG_VMLINUX_MAP),-Map=$(obj)/vmlinux.map) --build-id=sha1 -T
$(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS_ALL) FORCE
$(call if_changed,ld)

Expand Down
100 changes: 52 additions & 48 deletions arch/s390/include/asm/ap.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ struct ap_queue_status {
unsigned int _pad2 : 16;
};

/*
* AP queue status reg union to access the reg1
* register with the lower 32 bits comprising the
* ap queue status.
*/
union ap_queue_status_reg {
unsigned long value;
struct {
u32 _pad;
struct ap_queue_status status;
};
};

/**
* ap_intructions_available() - Test if AP instructions are available.
*
Expand Down Expand Up @@ -82,7 +95,7 @@ static inline bool ap_instructions_available(void)
*/
static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info)
{
struct ap_queue_status reg1;
union ap_queue_status_reg reg1;
unsigned long reg2;

asm volatile(
Expand All @@ -91,12 +104,12 @@ static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info)
" .insn rre,0xb2af0000,0,0\n" /* PQAP(TAPQ) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
" lgr %[reg2],2\n" /* gr2 into reg2 */
: [reg1] "=&d" (reg1), [reg2] "=&d" (reg2)
: [reg1] "=&d" (reg1.value), [reg2] "=&d" (reg2)
: [qid] "d" (qid)
: "cc", "0", "1", "2");
if (info)
*info = reg2;
return reg1;
return reg1.status;
}

/**
Expand Down Expand Up @@ -125,16 +138,16 @@ static inline struct ap_queue_status ap_test_queue(ap_qid_t qid,
static inline struct ap_queue_status ap_rapq(ap_qid_t qid)
{
unsigned long reg0 = qid | (1UL << 24); /* fc 1UL is RAPQ */
struct ap_queue_status reg1;
union ap_queue_status_reg reg1;

asm volatile(
" lgr 0,%[reg0]\n" /* qid arg into gr0 */
" .insn rre,0xb2af0000,0,0\n" /* PQAP(RAPQ) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
: [reg1] "=&d" (reg1)
: [reg1] "=&d" (reg1.value)
: [reg0] "d" (reg0)
: "cc", "0", "1");
return reg1;
return reg1.status;
}

/**
Expand All @@ -146,16 +159,16 @@ static inline struct ap_queue_status ap_rapq(ap_qid_t qid)
static inline struct ap_queue_status ap_zapq(ap_qid_t qid)
{
unsigned long reg0 = qid | (2UL << 24); /* fc 2UL is ZAPQ */
struct ap_queue_status reg1;
union ap_queue_status_reg reg1;

asm volatile(
" lgr 0,%[reg0]\n" /* qid arg into gr0 */
" .insn rre,0xb2af0000,0,0\n" /* PQAP(ZAPQ) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
: [reg1] "=&d" (reg1)
: [reg1] "=&d" (reg1.value)
: [reg0] "d" (reg0)
: "cc", "0", "1");
return reg1;
return reg1.status;
}

/**
Expand Down Expand Up @@ -209,18 +222,21 @@ static inline int ap_qci(struct ap_config_info *config)
* parameter to the PQAP(AQIC) instruction. For details please
* see the AR documentation.
*/
struct ap_qirq_ctrl {
unsigned int _res1 : 8;
unsigned int zone : 8; /* zone info */
unsigned int ir : 1; /* ir flag: enable (1) or disable (0) irq */
unsigned int _res2 : 4;
unsigned int gisc : 3; /* guest isc field */
unsigned int _res3 : 6;
unsigned int gf : 2; /* gisa format */
unsigned int _res4 : 1;
unsigned int gisa : 27; /* gisa origin */
unsigned int _res5 : 1;
unsigned int isc : 3; /* irq sub class */
union ap_qirq_ctrl {
unsigned long value;
struct {
unsigned int : 8;
unsigned int zone : 8; /* zone info */
unsigned int ir : 1; /* ir flag: enable (1) or disable (0) irq */
unsigned int : 4;
unsigned int gisc : 3; /* guest isc field */
unsigned int : 6;
unsigned int gf : 2; /* gisa format */
unsigned int : 1;
unsigned int gisa : 27; /* gisa origin */
unsigned int : 1;
unsigned int isc : 3; /* irq sub class */
};
};

/**
Expand All @@ -232,29 +248,22 @@ struct ap_qirq_ctrl {
* Returns AP queue status.
*/
static inline struct ap_queue_status ap_aqic(ap_qid_t qid,
struct ap_qirq_ctrl qirqctrl,
union ap_qirq_ctrl qirqctrl,
phys_addr_t pa_ind)
{
unsigned long reg0 = qid | (3UL << 24); /* fc 3UL is AQIC */
union {
unsigned long value;
struct ap_qirq_ctrl qirqctrl;
struct {
u32 _pad;
struct ap_queue_status status;
};
} reg1;
union ap_queue_status_reg reg1;
unsigned long reg2 = pa_ind;

reg1.qirqctrl = qirqctrl;
reg1.value = qirqctrl.value;

asm volatile(
" lgr 0,%[reg0]\n" /* qid param into gr0 */
" lgr 1,%[reg1]\n" /* irq ctrl into gr1 */
" lgr 2,%[reg2]\n" /* ni addr into gr2 */
" .insn rre,0xb2af0000,0,0\n" /* PQAP(AQIC) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
: [reg1] "+&d" (reg1)
: [reg1] "+&d" (reg1.value)
: [reg0] "d" (reg0), [reg2] "d" (reg2)
: "cc", "memory", "0", "1", "2");

Expand Down Expand Up @@ -291,13 +300,7 @@ static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit,
union ap_qact_ap_info *apinfo)
{
unsigned long reg0 = qid | (5UL << 24) | ((ifbit & 0x01) << 22);
union {
unsigned long value;
struct {
u32 _pad;
struct ap_queue_status status;
};
} reg1;
union ap_queue_status_reg reg1;
unsigned long reg2;

reg1.value = apinfo->val;
Expand All @@ -308,7 +311,7 @@ static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit,
" .insn rre,0xb2af0000,0,0\n" /* PQAP(QACT) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
" lgr %[reg2],2\n" /* qact out info into reg2 */
: [reg1] "+&d" (reg1), [reg2] "=&d" (reg2)
: [reg1] "+&d" (reg1.value), [reg2] "=&d" (reg2)
: [reg0] "d" (reg0)
: "cc", "0", "1", "2");
apinfo->val = reg2;
Expand All @@ -333,7 +336,7 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid,
{
unsigned long reg0 = qid | 0x40000000UL; /* 0x4... is last msg part */
union register_pair nqap_r1, nqap_r2;
struct ap_queue_status reg1;
union ap_queue_status_reg reg1;

nqap_r1.even = (unsigned int)(psmid >> 32);
nqap_r1.odd = psmid & 0xffffffff;
Expand All @@ -345,11 +348,11 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid,
"0: .insn rre,0xb2ad0000,%[nqap_r1],%[nqap_r2]\n"
" brc 2,0b\n" /* handle partial completion */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
: [reg0] "+&d" (reg0), [reg1] "=&d" (reg1),
: [reg0] "+&d" (reg0), [reg1] "=&d" (reg1.value),
[nqap_r2] "+&d" (nqap_r2.pair)
: [nqap_r1] "d" (nqap_r1.pair)
: "cc", "memory", "0", "1");
return reg1;
return reg1.status;
}

/**
Expand Down Expand Up @@ -389,7 +392,7 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid,
unsigned long *resgr0)
{
unsigned long reg0 = resgr0 && *resgr0 ? *resgr0 : qid | 0x80000000UL;
struct ap_queue_status reg1;
union ap_queue_status_reg reg1;
unsigned long reg2;
union register_pair rp1, rp2;

Expand All @@ -408,8 +411,9 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid,
"2: lgr %[reg0],0\n" /* gr0 (qid + info) into reg0 */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
" lgr %[reg2],2\n" /* gr2 (res length) into reg2 */
: [reg0] "+&d" (reg0), [reg1] "=&d" (reg1), [reg2] "=&d" (reg2),
[rp1] "+&d" (rp1.pair), [rp2] "+&d" (rp2.pair)
: [reg0] "+&d" (reg0), [reg1] "=&d" (reg1.value),
[reg2] "=&d" (reg2), [rp1] "+&d" (rp1.pair),
[rp2] "+&d" (rp2.pair)
:
: "cc", "memory", "0", "1", "2");

Expand All @@ -421,7 +425,7 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid,
* Signal the caller that this dqap is only partially received
* with a special status response code 0xFF and *resgr0 updated
*/
reg1.response_code = 0xFF;
reg1.status.response_code = 0xFF;
if (resgr0)
*resgr0 = reg0;
} else {
Expand All @@ -430,7 +434,7 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid,
*resgr0 = 0;
}

return reg1;
return reg1.status;
}

/*
Expand Down
5 changes: 2 additions & 3 deletions arch/s390/include/asm/nmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,8 @@ void nmi_alloc_mcesa_early(u64 *mcesad);
int nmi_alloc_mcesa(u64 *mcesad);
void nmi_free_mcesa(u64 *mcesad);

void s390_handle_mcck(struct pt_regs *regs);
void __s390_handle_mcck(void);
int s390_do_machine_check(struct pt_regs *regs);
void s390_handle_mcck(void);
void s390_do_machine_check(struct pt_regs *regs);

#endif /* __ASSEMBLY__ */
#endif /* _ASM_S390_NMI_H */
31 changes: 31 additions & 0 deletions arch/s390/include/asm/rwonce.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-2.0 */

#ifndef __ASM_S390_RWONCE_H
#define __ASM_S390_RWONCE_H

#include <linux/compiler_types.h>

/*
* Use READ_ONCE_ALIGNED_128() for 128-bit block concurrent (atomic) read
* accesses. Note that x must be 128-bit aligned, otherwise a specification
* exception is generated.
*/
#define READ_ONCE_ALIGNED_128(x) \
({ \
union { \
typeof(x) __x; \
__uint128_t val; \
} __u; \
\
BUILD_BUG_ON(sizeof(x) != 16); \
asm volatile( \
" lpq %[val],%[_x]\n" \
: [val] "=d" (__u.val) \
: [_x] "QS" (x) \
: "memory"); \
__u.__x; \
})

#include <asm-generic/rwonce.h>

#endif /* __ASM_S390_RWONCE_H */
17 changes: 17 additions & 0 deletions arch/s390/kernel/early.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,23 @@

int __bootdata(is_full_image);

#define decompressor_handled_param(param) \
static int __init ignore_decompressor_param_##param(char *s) \
{ \
return 0; \
} \
early_param(#param, ignore_decompressor_param_##param)

decompressor_handled_param(mem);
decompressor_handled_param(vmalloc);
decompressor_handled_param(dfltcc);
decompressor_handled_param(noexec);
decompressor_handled_param(facilities);
decompressor_handled_param(nokaslr);
#if IS_ENABLED(CONFIG_KVM)
decompressor_handled_param(prot_virt);
#endif

static void __init reset_tod_clock(void)
{
union tod_clock clk;
Expand Down
10 changes: 0 additions & 10 deletions arch/s390/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -562,16 +562,6 @@ ENTRY(mcck_int_handler)
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
lgr %r2,%r11 # pass pointer to pt_regs
brasl %r14,s390_do_machine_check
cghi %r2,0
je .Lmcck_return
lg %r1,__LC_KERNEL_STACK # switch to kernel stack
mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11)
xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1)
la %r11,STACK_FRAME_OVERHEAD(%r1)
lgr %r2,%r11
lgr %r15,%r1
brasl %r14,s390_handle_mcck
.Lmcck_return:
lctlg %c1,%c1,__PT_CR1(%r11)
lmg %r0,%r10,__PT_R0(%r11)
mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW
Expand Down
4 changes: 2 additions & 2 deletions arch/s390/kernel/kprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ static void pop_kprobe(struct kprobe_ctlblk *kcb)
{
__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
kcb->kprobe_status = kcb->prev_kprobe.status;
kcb->prev_kprobe.kp = NULL;
}
NOKPROBE_SYMBOL(pop_kprobe);

Expand Down Expand Up @@ -402,12 +403,11 @@ static int post_kprobe_handler(struct pt_regs *regs)
if (!p)
return 0;

resume_execution(p, regs);
if (kcb->kprobe_status != KPROBE_REENTER && p->post_handler) {
kcb->kprobe_status = KPROBE_HIT_SSDONE;
p->post_handler(p, regs, 0);
}

resume_execution(p, regs);
pop_kprobe(kcb);
preempt_enable_no_resched();

Expand Down
Loading

0 comments on commit 0bdf4a8

Please sign in to comment.