Commit 9ae24d5a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 's390-5.18-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull more s390 updates from Vasily Gorbik:

 - Add kretprobes framepointer verification and return address recovery
   in stacktrace.

 - Support control domain masks on custom zcrypt devices and filter
   admin requests.

 - Cleanup timer API usage.

 - Rework absolute lowcore access helpers.

 - Other various small improvements and fixes.

* tag 's390-5.18-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (26 commits)
  s390/alternatives: avoid using jgnop mnemonic
  s390/pci: rename get_zdev_by_bus() to zdev_from_bus()
  s390/pci: improve zpci_dev reference counting
  s390/smp: use physical address for SIGP_SET_PREFIX command
  s390: cleanup timer API use
  s390/zcrypt: fix using the correct variable for sizeof()
  s390/vfio-ap: fix kernel doc and signature of group notifier functions
  s390/maccess: rework absolute lowcore accessors
  s390/smp: cleanup control register update routines
  s390/smp: cleanup target CPU callback starting
  s390/test_unwind: verify __kretprobe_trampoline is replaced
  s390/unwind: avoid duplicated unwinding entries for kretprobes
  s390/unwind: recover kretprobe modified return address in stacktrace
  s390/kprobes: enable kretprobes framepointer verification
  s390/test_unwind: extend kretprobe test
  s390/ap: adjust whitespace
  s390/ap: use insn format for new instructions
  s390/alternatives: use insn format for new instructions
  s390/alternatives: use instructions instead of byte patterns
  s390/traps: improve panic message for translation-specification exception
  ...
parents ba2d6201 faf79934
...@@ -58,6 +58,7 @@ config S390 ...@@ -58,6 +58,7 @@ config S390
select ALTERNATE_USER_ADDRESS_SPACE select ALTERNATE_USER_ADDRESS_SPACE
select ARCH_32BIT_USTAT_F_TINODE select ARCH_32BIT_USTAT_F_TINODE
select ARCH_BINFMT_ELF_STATE select ARCH_BINFMT_ELF_STATE
select ARCH_CORRECT_STACKTRACE_ON_KRETPROBE
select ARCH_ENABLE_MEMORY_HOTPLUG if SPARSEMEM select ARCH_ENABLE_MEMORY_HOTPLUG if SPARSEMEM
select ARCH_ENABLE_MEMORY_HOTREMOVE select ARCH_ENABLE_MEMORY_HOTREMOVE
select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2 select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
......
...@@ -37,9 +37,15 @@ ...@@ -37,9 +37,15 @@
* a 2-byte nop if the size of the area is not divisible by 6. * a 2-byte nop if the size of the area is not divisible by 6.
*/ */
.macro alt_pad_fill bytes .macro alt_pad_fill bytes
.fill ( \bytes ) / 6, 6, 0xc0040000 .rept ( \bytes ) / 6
.fill ( \bytes ) % 6 / 4, 4, 0x47000000 brcl 0,0
.fill ( \bytes ) % 6 % 4 / 2, 2, 0x0700 .endr
.rept ( \bytes ) % 6 / 4
nop
.endr
.rept ( \bytes ) % 6 % 4 / 2
nopr
.endr
.endm .endm
/* /*
......
...@@ -71,11 +71,18 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end); ...@@ -71,11 +71,18 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
".if " oldinstr_pad_len(num) " > 6\n" \ ".if " oldinstr_pad_len(num) " > 6\n" \
"\tjg " e_oldinstr_pad_end "f\n" \ "\tjg " e_oldinstr_pad_end "f\n" \
"6620:\n" \ "6620:\n" \
"\t.fill (" oldinstr_pad_len(num) " - (6620b-662b)) / 2, 2, 0x0700\n" \ "\t.rept (" oldinstr_pad_len(num) " - (6620b-662b)) / 2\n" \
"\tnopr\n" \
".else\n" \ ".else\n" \
"\t.fill " oldinstr_pad_len(num) " / 6, 6, 0xc0040000\n" \ "\t.rept " oldinstr_pad_len(num) " / 6\n" \
"\t.fill " oldinstr_pad_len(num) " %% 6 / 4, 4, 0x47000000\n" \ "\t.brcl 0,0\n" \
"\t.fill " oldinstr_pad_len(num) " %% 6 %% 4 / 2, 2, 0x0700\n" \ "\t.endr\n" \
"\t.rept " oldinstr_pad_len(num) " %% 6 / 4\n" \
"\tnop\n" \
"\t.endr\n" \
"\t.rept " oldinstr_pad_len(num) " %% 6 %% 4 / 2\n" \
"\tnopr\n" \
".endr\n" \
".endif\n" ".endif\n"
#define OLDINSTR(oldinstr, num) \ #define OLDINSTR(oldinstr, num) \
......
...@@ -60,11 +60,11 @@ static inline bool ap_instructions_available(void) ...@@ -60,11 +60,11 @@ static inline bool ap_instructions_available(void)
unsigned long reg1 = 0; unsigned long reg1 = 0;
asm volatile( asm volatile(
" lgr 0,%[reg0]\n" /* qid into gr0 */ " lgr 0,%[reg0]\n" /* qid into gr0 */
" lghi 1,0\n" /* 0 into gr1 */ " lghi 1,0\n" /* 0 into gr1 */
" lghi 2,0\n" /* 0 into gr2 */ " lghi 2,0\n" /* 0 into gr2 */
" .long 0xb2af0000\n" /* PQAP(TAPQ) */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(TAPQ) */
"0: la %[reg1],1\n" /* 1 into reg1 */ "0: la %[reg1],1\n" /* 1 into reg1 */
"1:\n" "1:\n"
EX_TABLE(0b, 1b) EX_TABLE(0b, 1b)
: [reg1] "+&d" (reg1) : [reg1] "+&d" (reg1)
...@@ -86,11 +86,11 @@ static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info) ...@@ -86,11 +86,11 @@ static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info)
unsigned long reg2; unsigned long reg2;
asm volatile( asm volatile(
" lgr 0,%[qid]\n" /* qid into gr0 */ " lgr 0,%[qid]\n" /* qid into gr0 */
" lghi 2,0\n" /* 0 into gr2 */ " lghi 2,0\n" /* 0 into gr2 */
" .long 0xb2af0000\n" /* PQAP(TAPQ) */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(TAPQ) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */ " lgr %[reg1],1\n" /* gr1 (status) into reg1 */
" lgr %[reg2],2\n" /* gr2 into reg2 */ " lgr %[reg2],2\n" /* gr2 into reg2 */
: [reg1] "=&d" (reg1), [reg2] "=&d" (reg2) : [reg1] "=&d" (reg1), [reg2] "=&d" (reg2)
: [qid] "d" (qid) : [qid] "d" (qid)
: "cc", "0", "1", "2"); : "cc", "0", "1", "2");
...@@ -128,9 +128,9 @@ static inline struct ap_queue_status ap_rapq(ap_qid_t qid) ...@@ -128,9 +128,9 @@ static inline struct ap_queue_status ap_rapq(ap_qid_t qid)
struct ap_queue_status reg1; struct ap_queue_status reg1;
asm volatile( asm volatile(
" lgr 0,%[reg0]\n" /* qid arg into gr0 */ " lgr 0,%[reg0]\n" /* qid arg into gr0 */
" .long 0xb2af0000\n" /* PQAP(RAPQ) */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(RAPQ) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */ " lgr %[reg1],1\n" /* gr1 (status) into reg1 */
: [reg1] "=&d" (reg1) : [reg1] "=&d" (reg1)
: [reg0] "d" (reg0) : [reg0] "d" (reg0)
: "cc", "0", "1"); : "cc", "0", "1");
...@@ -149,9 +149,9 @@ static inline struct ap_queue_status ap_zapq(ap_qid_t qid) ...@@ -149,9 +149,9 @@ static inline struct ap_queue_status ap_zapq(ap_qid_t qid)
struct ap_queue_status reg1; struct ap_queue_status reg1;
asm volatile( asm volatile(
" lgr 0,%[reg0]\n" /* qid arg into gr0 */ " lgr 0,%[reg0]\n" /* qid arg into gr0 */
" .long 0xb2af0000\n" /* PQAP(ZAPQ) */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(ZAPQ) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */ " lgr %[reg1],1\n" /* gr1 (status) into reg1 */
: [reg1] "=&d" (reg1) : [reg1] "=&d" (reg1)
: [reg0] "d" (reg0) : [reg0] "d" (reg0)
: "cc", "0", "1"); : "cc", "0", "1");
...@@ -190,10 +190,10 @@ static inline int ap_qci(struct ap_config_info *config) ...@@ -190,10 +190,10 @@ static inline int ap_qci(struct ap_config_info *config)
struct ap_config_info *reg2 = config; struct ap_config_info *reg2 = config;
asm volatile( asm volatile(
" lgr 0,%[reg0]\n" /* QCI fc into gr0 */ " lgr 0,%[reg0]\n" /* QCI fc into gr0 */
" lgr 2,%[reg2]\n" /* ptr to config into gr2 */ " lgr 2,%[reg2]\n" /* ptr to config into gr2 */
" .long 0xb2af0000\n" /* PQAP(QCI) */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(QCI) */
"0: la %[reg1],0\n" /* good case, QCI fc available */ "0: la %[reg1],0\n" /* good case, QCI fc available */
"1:\n" "1:\n"
EX_TABLE(0b, 1b) EX_TABLE(0b, 1b)
: [reg1] "+&d" (reg1) : [reg1] "+&d" (reg1)
...@@ -246,11 +246,11 @@ static inline struct ap_queue_status ap_aqic(ap_qid_t qid, ...@@ -246,11 +246,11 @@ static inline struct ap_queue_status ap_aqic(ap_qid_t qid,
reg1.qirqctrl = qirqctrl; reg1.qirqctrl = qirqctrl;
asm volatile( asm volatile(
" lgr 0,%[reg0]\n" /* qid param into gr0 */ " lgr 0,%[reg0]\n" /* qid param into gr0 */
" lgr 1,%[reg1]\n" /* irq ctrl into gr1 */ " lgr 1,%[reg1]\n" /* irq ctrl into gr1 */
" lgr 2,%[reg2]\n" /* ni addr into gr2 */ " lgr 2,%[reg2]\n" /* ni addr into gr2 */
" .long 0xb2af0000\n" /* PQAP(AQIC) */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(AQIC) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */ " lgr %[reg1],1\n" /* gr1 (status) into reg1 */
: [reg1] "+&d" (reg1) : [reg1] "+&d" (reg1)
: [reg0] "d" (reg0), [reg2] "d" (reg2) : [reg0] "d" (reg0), [reg2] "d" (reg2)
: "cc", "0", "1", "2"); : "cc", "0", "1", "2");
...@@ -297,11 +297,11 @@ static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit, ...@@ -297,11 +297,11 @@ static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit,
reg1.value = apinfo->val; reg1.value = apinfo->val;
asm volatile( asm volatile(
" lgr 0,%[reg0]\n" /* qid param into gr0 */ " lgr 0,%[reg0]\n" /* qid param into gr0 */
" lgr 1,%[reg1]\n" /* qact in info into gr1 */ " lgr 1,%[reg1]\n" /* qact in info into gr1 */
" .long 0xb2af0000\n" /* PQAP(QACT) */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(QACT) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */ " lgr %[reg1],1\n" /* gr1 (status) into reg1 */
" lgr %[reg2],2\n" /* qact out info into reg2 */ " lgr %[reg2],2\n" /* qact out info into reg2 */
: [reg1] "+&d" (reg1), [reg2] "=&d" (reg2) : [reg1] "+&d" (reg1), [reg2] "=&d" (reg2)
: [reg0] "d" (reg0) : [reg0] "d" (reg0)
: "cc", "0", "1", "2"); : "cc", "0", "1", "2");
......
...@@ -74,8 +74,17 @@ static __always_inline void __ctl_clear_bit(unsigned int cr, unsigned int bit) ...@@ -74,8 +74,17 @@ static __always_inline void __ctl_clear_bit(unsigned int cr, unsigned int bit)
__ctl_load(reg, cr, cr); __ctl_load(reg, cr, cr);
} }
void smp_ctl_set_bit(int cr, int bit); void smp_ctl_set_clear_bit(int cr, int bit, bool set);
void smp_ctl_clear_bit(int cr, int bit);
static inline void ctl_set_bit(int cr, int bit)
{
smp_ctl_set_clear_bit(cr, bit, true);
}
static inline void ctl_clear_bit(int cr, int bit)
{
smp_ctl_set_clear_bit(cr, bit, false);
}
union ctlreg0 { union ctlreg0 {
unsigned long val; unsigned long val;
...@@ -130,8 +139,5 @@ union ctlreg15 { ...@@ -130,8 +139,5 @@ union ctlreg15 {
}; };
}; };
#define ctl_set_bit(cr, bit) smp_ctl_set_bit(cr, bit)
#define ctl_clear_bit(cr, bit) smp_ctl_clear_bit(cr, bit)
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#endif /* __ASM_CTL_REG_H */ #endif /* __ASM_CTL_REG_H */
...@@ -319,11 +319,18 @@ extern void (*s390_base_pgm_handler_fn)(struct pt_regs *regs); ...@@ -319,11 +319,18 @@ extern void (*s390_base_pgm_handler_fn)(struct pt_regs *regs);
extern int memcpy_real(void *, unsigned long, size_t); extern int memcpy_real(void *, unsigned long, size_t);
extern void memcpy_absolute(void *, void *, size_t); extern void memcpy_absolute(void *, void *, size_t);
#define mem_assign_absolute(dest, val) do { \ #define put_abs_lowcore(member, x) do { \
__typeof__(dest) __tmp = (val); \ unsigned long __abs_address = offsetof(struct lowcore, member); \
\ __typeof__(((struct lowcore *)0)->member) __tmp = (x); \
BUILD_BUG_ON(sizeof(__tmp) != sizeof(val)); \ \
memcpy_absolute(&(dest), &__tmp, sizeof(__tmp)); \ memcpy_absolute(__va(__abs_address), &__tmp, sizeof(__tmp)); \
} while (0)
#define get_abs_lowcore(x, member) do { \
unsigned long __abs_address = offsetof(struct lowcore, member); \
__typeof__(((struct lowcore *)0)->member) *__ptr = &(x); \
\
memcpy_absolute(__ptr, __va(__abs_address), sizeof(*__ptr)); \
} while (0) } while (0)
extern int s390_isolate_bp(void); extern int s390_isolate_bp(void);
......
...@@ -78,7 +78,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lp) ...@@ -78,7 +78,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lp)
{ {
typecheck(int, lp->lock); typecheck(int, lp->lock);
asm_inline volatile( asm_inline volatile(
ALTERNATIVE("", ".long 0xb2fa0070", 49) /* NIAI 7 */ ALTERNATIVE("", ".insn rre,0xb2fa0000,7,0", 49) /* NIAI 7 */
" sth %1,%0\n" " sth %1,%0\n"
: "=R" (((unsigned short *) &lp->lock)[1]) : "=R" (((unsigned short *) &lp->lock)[1])
: "d" (0) : "cc", "memory"); : "d" (0) : "cc", "memory");
......
...@@ -162,4 +162,4 @@ ...@@ -162,4 +162,4 @@
__diag_pop(); \ __diag_pop(); \
static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
#endif /* _ASM_X86_SYSCALL_WRAPPER_H */ #endif /* _ASM_S390_SYSCALL_WRAPPER_H */
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <linux/kprobes.h>
#include <linux/llist.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/stacktrace.h> #include <asm/stacktrace.h>
...@@ -36,10 +38,21 @@ struct unwind_state { ...@@ -36,10 +38,21 @@ struct unwind_state {
struct pt_regs *regs; struct pt_regs *regs;
unsigned long sp, ip; unsigned long sp, ip;
int graph_idx; int graph_idx;
struct llist_node *kr_cur;
bool reliable; bool reliable;
bool error; bool error;
}; };
/* Recover the return address modified by kretprobe and ftrace_graph. */
static inline unsigned long unwind_recover_ret_addr(struct unwind_state *state,
unsigned long ip)
{
ip = ftrace_graph_ret_addr(state->task, &state->graph_idx, ip, NULL);
if (is_kretprobe_trampoline(ip))
ip = kretprobe_find_ret_addr(state->task, (void *)state->sp, &state->kr_cur);
return ip;
}
void __unwind_start(struct unwind_state *state, struct task_struct *task, void __unwind_start(struct unwind_state *state, struct task_struct *task,
struct pt_regs *regs, unsigned long first_frame); struct pt_regs *regs, unsigned long first_frame);
bool unwind_next_frame(struct unwind_state *state); bool unwind_next_frame(struct unwind_state *state);
......
...@@ -121,22 +121,22 @@ _LPP_OFFSET = __LC_LPP ...@@ -121,22 +121,22 @@ _LPP_OFFSET = __LC_LPP
.endm .endm
.macro BPOFF .macro BPOFF
ALTERNATIVE "", ".long 0xb2e8c000", 82 ALTERNATIVE "", ".insn rrf,0xb2e80000,0,0,12,0", 82
.endm .endm
.macro BPON .macro BPON
ALTERNATIVE "", ".long 0xb2e8d000", 82 ALTERNATIVE "", ".insn rrf,0xb2e80000,0,0,13,0", 82
.endm .endm
.macro BPENTER tif_ptr,tif_mask .macro BPENTER tif_ptr,tif_mask
ALTERNATIVE "TSTMSK \tif_ptr,\tif_mask; jz .+8; .long 0xb2e8d000", \ ALTERNATIVE "TSTMSK \tif_ptr,\tif_mask; jz .+8; .insn rrf,0xb2e80000,0,0,13,0", \
"", 82 "", 82
.endm .endm
.macro BPEXIT tif_ptr,tif_mask .macro BPEXIT tif_ptr,tif_mask
TSTMSK \tif_ptr,\tif_mask TSTMSK \tif_ptr,\tif_mask
ALTERNATIVE "jz .+8; .long 0xb2e8c000", \ ALTERNATIVE "jz .+8; .insn rrf,0xb2e80000,0,0,12,0", \
"jnz .+8; .long 0xb2e8d000", 82 "jnz .+8; .insn rrf,0xb2e80000,0,0,13,0", 82
.endm .endm
/* /*
......
...@@ -1646,8 +1646,8 @@ static void dump_reipl_run(struct shutdown_trigger *trigger) ...@@ -1646,8 +1646,8 @@ static void dump_reipl_run(struct shutdown_trigger *trigger)
csum = (__force unsigned int) csum = (__force unsigned int)
csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0); csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0);
mem_assign_absolute(S390_lowcore.ipib, ipib); put_abs_lowcore(ipib, ipib);
mem_assign_absolute(S390_lowcore.ipib_checksum, csum); put_abs_lowcore(ipib_checksum, csum);
dump_run(trigger); dump_run(trigger);
} }
......
...@@ -284,11 +284,11 @@ NOKPROBE_SYMBOL(pop_kprobe); ...@@ -284,11 +284,11 @@ NOKPROBE_SYMBOL(pop_kprobe);
void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs)
{ {
ri->ret_addr = (kprobe_opcode_t *) regs->gprs[14]; ri->ret_addr = (kprobe_opcode_t *)regs->gprs[14];
ri->fp = NULL; ri->fp = (void *)regs->gprs[15];
/* Replace the return addr with trampoline addr */ /* Replace the return addr with trampoline addr */
regs->gprs[14] = (unsigned long) &__kretprobe_trampoline; regs->gprs[14] = (unsigned long)&__kretprobe_trampoline;
} }
NOKPROBE_SYMBOL(arch_prepare_kretprobe); NOKPROBE_SYMBOL(arch_prepare_kretprobe);
...@@ -385,7 +385,7 @@ NOKPROBE_SYMBOL(arch_kretprobe_fixup_return); ...@@ -385,7 +385,7 @@ NOKPROBE_SYMBOL(arch_kretprobe_fixup_return);
*/ */
void trampoline_probe_handler(struct pt_regs *regs) void trampoline_probe_handler(struct pt_regs *regs)
{ {
kretprobe_trampoline_handler(regs, NULL); kretprobe_trampoline_handler(regs, (void *)regs->gprs[15]);
} }
NOKPROBE_SYMBOL(trampoline_probe_handler); NOKPROBE_SYMBOL(trampoline_probe_handler);
......
...@@ -226,7 +226,7 @@ void arch_crash_save_vmcoreinfo(void) ...@@ -226,7 +226,7 @@ void arch_crash_save_vmcoreinfo(void)
vmcoreinfo_append_str("SAMODE31=%lx\n", __samode31); vmcoreinfo_append_str("SAMODE31=%lx\n", __samode31);
vmcoreinfo_append_str("EAMODE31=%lx\n", __eamode31); vmcoreinfo_append_str("EAMODE31=%lx\n", __eamode31);
vmcoreinfo_append_str("KERNELOFFSET=%lx\n", kaslr_offset()); vmcoreinfo_append_str("KERNELOFFSET=%lx\n", kaslr_offset());
mem_assign_absolute(S390_lowcore.vmcore_info, paddr_vmcoreinfo_note()); put_abs_lowcore(vmcore_info, paddr_vmcoreinfo_note());
} }
void machine_shutdown(void) void machine_shutdown(void)
......
...@@ -63,7 +63,7 @@ void __init os_info_init(void) ...@@ -63,7 +63,7 @@ void __init os_info_init(void)
os_info.version_minor = OS_INFO_VERSION_MINOR; os_info.version_minor = OS_INFO_VERSION_MINOR;
os_info.magic = OS_INFO_MAGIC; os_info.magic = OS_INFO_MAGIC;
os_info.csum = os_info_csum(&os_info); os_info.csum = os_info_csum(&os_info);
mem_assign_absolute(S390_lowcore.os_info, __pa(ptr)); put_abs_lowcore(os_info, __pa(ptr));
} }
#ifdef CONFIG_CRASH_DUMP #ifdef CONFIG_CRASH_DUMP
......
...@@ -481,11 +481,11 @@ static void __init setup_lowcore_dat_off(void) ...@@ -481,11 +481,11 @@ static void __init setup_lowcore_dat_off(void)
lc->mcck_stack = mcck_stack + STACK_INIT_OFFSET; lc->mcck_stack = mcck_stack + STACK_INIT_OFFSET;
/* Setup absolute zero lowcore */ /* Setup absolute zero lowcore */
mem_assign_absolute(S390_lowcore.restart_stack, lc->restart_stack); put_abs_lowcore(restart_stack, lc->restart_stack);
mem_assign_absolute(S390_lowcore.restart_fn, lc->restart_fn); put_abs_lowcore(restart_fn, lc->restart_fn);
mem_assign_absolute(S390_lowcore.restart_data, lc->restart_data); put_abs_lowcore(restart_data, lc->restart_data);
mem_assign_absolute(S390_lowcore.restart_source, lc->restart_source); put_abs_lowcore(restart_source, lc->restart_source);
mem_assign_absolute(S390_lowcore.restart_psw, lc->restart_psw); put_abs_lowcore(restart_psw, lc->restart_psw);
lc->spinlock_lockval = arch_spin_lockval(0); lc->spinlock_lockval = arch_spin_lockval(0);
lc->spinlock_index = 0; lc->spinlock_index = 0;
...@@ -501,6 +501,7 @@ static void __init setup_lowcore_dat_off(void) ...@@ -501,6 +501,7 @@ static void __init setup_lowcore_dat_off(void)
static void __init setup_lowcore_dat_on(void) static void __init setup_lowcore_dat_on(void)
{ {
struct lowcore *lc = lowcore_ptr[0]; struct lowcore *lc = lowcore_ptr[0];
int cr;
__ctl_clear_bit(0, 28); __ctl_clear_bit(0, 28);
S390_lowcore.external_new_psw.mask |= PSW_MASK_DAT; S390_lowcore.external_new_psw.mask |= PSW_MASK_DAT;
...@@ -509,10 +510,10 @@ static void __init setup_lowcore_dat_on(void) ...@@ -509,10 +510,10 @@ static void __init setup_lowcore_dat_on(void)
S390_lowcore.io_new_psw.mask |= PSW_MASK_DAT; S390_lowcore.io_new_psw.mask |= PSW_MASK_DAT;
__ctl_store(S390_lowcore.cregs_save_area, 0, 15); __ctl_store(S390_lowcore.cregs_save_area, 0, 15);
__ctl_set_bit(0, 28); __ctl_set_bit(0, 28);
mem_assign_absolute(S390_lowcore.restart_flags, RESTART_FLAG_CTLREGS); put_abs_lowcore(restart_flags, RESTART_FLAG_CTLREGS);
mem_assign_absolute(S390_lowcore.program_new_psw, lc->program_new_psw); put_abs_lowcore(program_new_psw, lc->program_new_psw);
memcpy_absolute(&S390_lowcore.cregs_save_area, lc->cregs_save_area, for (cr = 0; cr < ARRAY_SIZE(lc->cregs_save_area); cr++)
sizeof(S390_lowcore.cregs_save_area)); put_abs_lowcore(cregs_save_area[cr], lc->cregs_save_area[cr]);
} }
static struct resource code_resource = { static struct resource code_resource = {
......
...@@ -213,7 +213,7 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu) ...@@ -213,7 +213,7 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
if (nmi_alloc_mcesa(&lc->mcesad)) if (nmi_alloc_mcesa(&lc->mcesad))
goto out; goto out;
lowcore_ptr[cpu] = lc; lowcore_ptr[cpu] = lc;
pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, (u32)(unsigned long) lc); pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, __pa(lc));
return 0; return 0;
out: out:
...@@ -326,10 +326,17 @@ static void pcpu_delegate(struct pcpu *pcpu, ...@@ -326,10 +326,17 @@ static void pcpu_delegate(struct pcpu *pcpu,
/* Stop target cpu (if func returns this stops the current cpu). */ /* Stop target cpu (if func returns this stops the current cpu). */
pcpu_sigp_retry(pcpu, SIGP_STOP, 0); pcpu_sigp_retry(pcpu, SIGP_STOP, 0);
/* Restart func on the target cpu and stop the current cpu. */ /* Restart func on the target cpu and stop the current cpu. */
mem_assign_absolute(lc->restart_stack, stack); if (lc) {
mem_assign_absolute(lc->restart_fn, (unsigned long) func); lc->restart_stack = stack;
mem_assign_absolute(lc->restart_data, (unsigned long) data); lc->restart_fn = (unsigned long)func;
mem_assign_absolute(lc->restart_source, source_cpu); lc->restart_data = (unsigned long)data;
lc->restart_source = source_cpu;
} else {
put_abs_lowcore(restart_stack, stack);
put_abs_lowcore(restart_fn, (unsigned long)func);
put_abs_lowcore(restart_data, (unsigned long)data);
put_abs_lowcore(restart_source, source_cpu);
}
__bpon(); __bpon();
asm volatile( asm volatile(
"0: sigp 0,%0,%2 # sigp restart to target cpu\n" "0: sigp 0,%0,%2 # sigp restart to target cpu\n"
...@@ -570,39 +577,27 @@ static void smp_ctl_bit_callback(void *info) ...@@ -570,39 +577,27 @@ static void smp_ctl_bit_callback(void *info)
} }
static DEFINE_SPINLOCK(ctl_lock); static DEFINE_SPINLOCK(ctl_lock);
static unsigned long ctlreg;
/* void smp_ctl_set_clear_bit(int cr, int bit, bool set)
* Set a bit in a control register of all cpus
*/
void smp_ctl_set_bit(int cr, int bit)
{ {
struct ec_creg_mask_parms parms = { 1UL << bit, -1UL, cr }; struct ec_creg_mask_parms parms = { .cr = cr, };
u64 ctlreg;
spin_lock(&ctl_lock);
memcpy_absolute(&ctlreg, &S390_lowcore.cregs_save_area[cr], sizeof(ctlreg));
__set_bit(bit, &ctlreg);
memcpy_absolute(&S390_lowcore.cregs_save_area[cr], &ctlreg, sizeof(ctlreg));
spin_unlock(&ctl_lock);
on_each_cpu(smp_ctl_bit_callback, &parms, 1);
}
EXPORT_SYMBOL(smp_ctl_set_bit);
/*
* Clear a bit in a control register of all cpus
*/
void smp_ctl_clear_bit(int cr, int bit)
{
struct ec_creg_mask_parms parms = { 0, ~(1UL << bit), cr };
if (set) {
parms.orval = 1UL << bit;
parms.andval = -1UL;
} else {
parms.orval = 0;
parms.andval = ~(1UL << bit);
}
spin_lock(&ctl_lock); spin_lock(&ctl_lock);
memcpy_absolute(&ctlreg, &S390_lowcore.cregs_save_area[cr], sizeof(ctlreg)); get_abs_lowcore(ctlreg, cregs_save_area[cr]);
__clear_bit(bit, &ctlreg); ctlreg = (ctlreg & parms.andval) | parms.orval;
memcpy_absolute(&S390_lowcore.cregs_save_area[cr], &ctlreg, sizeof(ctlreg)); put_abs_lowcore(cregs_save_area[cr], ctlreg);
spin_unlock(&ctl_lock); spin_unlock(&ctl_lock);
on_each_cpu(smp_ctl_bit_callback, &parms, 1); on_each_cpu(smp_ctl_bit_callback, &parms, 1);
} }
EXPORT_SYMBOL(smp_ctl_clear_bit); EXPORT_SYMBOL(smp_ctl_set_clear_bit);
#ifdef CONFIG_CRASH_DUMP #ifdef CONFIG_CRASH_DUMP
......
...@@ -141,10 +141,10 @@ static inline void do_fp_trap(struct pt_regs *regs, __u32 fpc) ...@@ -141,10 +141,10 @@ static inline void do_fp_trap(struct pt_regs *regs, __u32 fpc)
do_trap(regs, SIGFPE, si_code, "floating point exception"); do_trap(regs, SIGFPE, si_code, "floating point exception");
} }
static void translation_exception(struct pt_regs *regs) static void translation_specification_exception(struct pt_regs *regs)
{ {
/* May never happen. */ /* May never happen. */
panic("Translation exception"); panic("Translation-Specification Exception");
} }
static void illegal_op(struct pt_regs *regs) static void illegal_op(struct pt_regs *regs)
...@@ -368,7 +368,7 @@ static void (*pgm_check_table[128])(struct pt_regs *regs) = { ...@@ -368,7 +368,7 @@ static void (*pgm_check_table[128])(struct pt_regs *regs) = {
[0x0f] = hfp_divide_exception, [0x0f] = hfp_divide_exception,
[0x10] = do_dat_exception, [0x10] = do_dat_exception,
[0x11] = do_dat_exception, [0x11] = do_dat_exception,
[0x12] = translation_exception, [0x12] = translation_specification_exception,
[0x13] = special_op_exception, [0x13] = special_op_exception,
[0x14] = default_trap_handler, [0x14] = default_trap_handler,
[0x15] = operand_exception, [0x15] = operand_exception,
......
...@@ -64,8 +64,8 @@ bool unwind_next_frame(struct unwind_state *state) ...@@ -64,8 +64,8 @@ bool unwind_next_frame(struct unwind_state *state)
ip = READ_ONCE_NOCHECK(sf->gprs[8]); ip = READ_ONCE_NOCHECK(sf->gprs[8]);
reliable = false; reliable = false;
regs = NULL; regs = NULL;
if (!__kernel_text_address(ip)) { /* skip bogus %r14 or if is the same as regs->psw.addr */
/* skip bogus %r14 */ if (!__kernel_text_address(ip) || state->ip == unwind_recover_ret_addr(state, ip)) {
state->regs = NULL; state->regs = NULL;
return unwind_next_frame(state); return unwind_next_frame(state);
} }
...@@ -103,13 +103,11 @@ bool unwind_next_frame(struct unwind_state *state) ...@@ -103,13 +103,11 @@ bool unwind_next_frame(struct unwind_state *state)
if (sp & 0x7) if (sp & 0x7)
goto out_err; goto out_err;
ip = ftrace_graph_ret_addr(state->task, &state->graph_idx, ip, (void *) sp);
/* Update unwind state */ /* Update unwind state */
state->sp = sp; state->sp = sp;
state->ip = ip;
state->regs = regs; state->regs = regs;
state->reliable = reliable; state->reliable = reliable;
state->ip = unwind_recover_ret_addr(state, ip);
return true; return true;
out_err: out_err:
...@@ -161,12 +159,10 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task, ...@@ -161,12 +159,10 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task,
ip = READ_ONCE_NOCHECK(sf->gprs[8]); ip = READ_ONCE_NOCHECK(sf->gprs[8]);
} }
ip = ftrace_graph_ret_addr(state->task, &state->graph_idx, ip, NULL);
/* Update unwind state */ /* Update unwind state */
state->sp = sp; state->sp = sp;
state->ip = ip;
state->reliable = true; state->reliable = true;
state->ip = unwind_recover_ret_addr(state, ip);
if (!first_frame) if (!first_frame)
return; return;
......
...@@ -75,7 +75,7 @@ static inline int arch_load_niai4(int *lock) ...@@ -75,7 +75,7 @@ static inline int arch_load_niai4(int *lock)
int owner; int owner;
asm_inline volatile( asm_inline volatile(
ALTERNATIVE("", ".long 0xb2fa0040", 49) /* NIAI 4 */ ALTERNATIVE("", ".insn rre,0xb2fa0000,4,0", 49) /* NIAI 4 */
" l %0,%1\n" " l %0,%1\n"
: "=d" (owner) : "Q" (*lock) : "memory"); : "=d" (owner) : "Q" (*lock) : "memory");
return owner; return owner;
...@@ -86,7 +86,7 @@ static inline int arch_cmpxchg_niai8(int *lock, int old, int new) ...@@ -86,7 +86,7 @@ static inline int arch_cmpxchg_niai8(int *lock, int old, int new)
int expected = old; int expected = old;
asm_inline volatile( asm_inline volatile(
ALTERNATIVE("", ".long 0xb2fa0080", 49) /* NIAI 8 */ ALTERNATIVE("", ".insn rre,0xb2fa0000,8,0", 49) /* NIAI 8 */
" cs %0,%3,%1\n" " cs %0,%3,%1\n"
: "=d" (old), "=Q" (*lock) : "=d" (old), "=Q" (*lock)
: "0" (old), "d" (new), "Q" (*lock) : "0" (old), "d" (new), "Q" (*lock)
......
...@@ -47,7 +47,7 @@ static void print_backtrace(char *bt) ...@@ -47,7 +47,7 @@ static void print_backtrace(char *bt)
static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs, static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs,
unsigned long sp) unsigned long sp)
{ {
int frame_count, prev_is_func2, seen_func2_func1; int frame_count, prev_is_func2, seen_func2_func1, seen_kretprobe_trampoline;
const int max_frames = 128; const int max_frames = 128;
struct unwind_state state; struct unwind_state state;
size_t bt_pos = 0; size_t bt_pos = 0;
...@@ -63,6 +63,7 @@ static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs, ...@@ -63,6 +63,7 @@ static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs,
frame_count = 0; frame_count = 0;
prev_is_func2 = 0; prev_is_func2 = 0;
seen_func2_func1 = 0; seen_func2_func1 = 0;
seen_kretprobe_trampoline = 0;
unwind_for_each_frame(&state, task, regs, sp) { unwind_for_each_frame(&state, task, regs, sp) {
unsigned long addr = unwind_get_return_address(&state); unsigned long addr = unwind_get_return_address(&state);
char sym[KSYM_SYMBOL_LEN]; char sym[KSYM_SYMBOL_LEN];
...@@ -88,6 +89,8 @@ static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs, ...@@ -88,6 +89,8 @@ static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs,
if (prev_is_func2 && str_has_prefix(sym, "unwindme_func1")) if (prev_is_func2 && str_has_prefix(sym, "unwindme_func1"))
seen_func2_func1 = 1; seen_func2_func1 = 1;
prev_is_func2 = str_has_prefix(sym, "unwindme_func2"); prev_is_func2 = str_has_prefix(sym, "unwindme_func2");
if (str_has_prefix(sym, "__kretprobe_trampoline+0x0/"))
seen_kretprobe_trampoline = 1;
} }
/* Check the results. */ /* Check the results. */
...@@ -103,6 +106,10 @@ static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs, ...@@ -103,6 +106,10 @@ static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs,
kunit_err(current_test, "Maximum number of frames exceeded\n"); kunit_err(current_test, "Maximum number of frames exceeded\n");
ret = -EINVAL; ret = -EINVAL;
} }
if (seen_kretprobe_trampoline) {
kunit_err(current_test, "__kretprobe_trampoline+0x0 in unwinding results\n");
ret = -EINVAL;
}
if (ret || force_bt) if (ret || force_bt)
print_backtrace(bt); print_backtrace(bt);
kfree(bt); kfree(bt);
...@@ -132,36 +139,50 @@ static struct unwindme *unwindme; ...@@ -132,36 +139,50 @@ static struct unwindme *unwindme;
#define UWM_PGM 0x40 /* Unwind from program check handler */ #define UWM_PGM 0x40 /* Unwind from program check handler */
#define UWM_KPROBE_ON_FTRACE 0x80 /* Unwind from kprobe handler called via ftrace. */ #define UWM_KPROBE_ON_FTRACE 0x80 /* Unwind from kprobe handler called via ftrace. */
#define UWM_FTRACE 0x100 /* Unwind from ftrace handler. */ #define UWM_FTRACE 0x100 /* Unwind from ftrace handler. */
#define UWM_KRETPROBE 0x200 /* Unwind kretprobe handlers. */ #define UWM_KRETPROBE 0x200 /* Unwind through kretprobed function. */
#define UWM_KRETPROBE_HANDLER 0x400 /* Unwind from kretprobe handler. */
static __always_inline unsigned long get_psw_addr(void) static __always_inline struct pt_regs fake_pt_regs(void)
{ {
unsigned long psw_addr; struct pt_regs regs;
memset(&regs, 0, sizeof(regs));
regs.gprs[15] = current_stack_pointer();
asm volatile( asm volatile(
"basr %[psw_addr],0\n" "basr %[psw_addr],0\n"
: [psw_addr] "=d" (psw_addr)); : [psw_addr] "=d" (regs.psw.addr));
return psw_addr; return regs;
} }
static int kretprobe_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs) static int kretprobe_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{ {
struct unwindme *u = unwindme; struct unwindme *u = unwindme;
if (!(u->flags & UWM_KRETPROBE_HANDLER))
return 0;
u->ret = test_unwind(NULL, (u->flags & UWM_REGS) ? regs : NULL, u->ret = test_unwind(NULL, (u->flags & UWM_REGS) ? regs : NULL,
(u->flags & UWM_SP) ? u->sp : 0); (u->flags & UWM_SP) ? u->sp : 0);
return 0; return 0;
} }
static noinline notrace void test_unwind_kretprobed_func(void) static noinline notrace int test_unwind_kretprobed_func(struct unwindme *u)
{ {
asm volatile(" nop\n"); struct pt_regs regs;
if (!(u->flags & UWM_KRETPROBE))
return 0;
regs = fake_pt_regs();
return test_unwind(NULL, (u->flags & UWM_REGS) ? &regs : NULL,
(u->flags & UWM_SP) ? u->sp : 0);
} }
static noinline void test_unwind_kretprobed_func_caller(void) static noinline int test_unwind_kretprobed_func_caller(struct unwindme *u)
{ {
test_unwind_kretprobed_func(); return test_unwind_kretprobed_func(u);
} }
static int test_unwind_kretprobe(struct unwindme *u) static int test_unwind_kretprobe(struct unwindme *u)
...@@ -187,10 +208,12 @@ static int test_unwind_kretprobe(struct unwindme *u) ...@@ -187,10 +208,12 @@ static int test_unwind_kretprobe(struct unwindme *u)
return -EINVAL; return -EINVAL;
} }
test_unwind_kretprobed_func_caller(); ret = test_unwind_kretprobed_func_caller(u);
unregister_kretprobe(&my_kretprobe); unregister_kretprobe(&my_kretprobe);
unwindme = NULL; unwindme = NULL;
return u->ret; if (u->flags & UWM_KRETPROBE_HANDLER)
ret = u->ret;
return ret;
} }
static int kprobe_pre_handler(struct kprobe *p, struct pt_regs *regs) static int kprobe_pre_handler(struct kprobe *p, struct pt_regs *regs)
...@@ -304,16 +327,13 @@ static noinline int unwindme_func4(struct unwindme *u) ...@@ -304,16 +327,13 @@ static noinline int unwindme_func4(struct unwindme *u)
return 0; return 0;
} else if (u->flags & (UWM_PGM | UWM_KPROBE_ON_FTRACE)) { } else if (u->flags & (UWM_PGM | UWM_KPROBE_ON_FTRACE)) {
return test_unwind_kprobe(u); return test_unwind_kprobe(u);
} else if (u->flags & (UWM_KRETPROBE)) { } else if (u->flags & (UWM_KRETPROBE | UWM_KRETPROBE_HANDLER)) {
return test_unwind_kretprobe(u); return test_unwind_kretprobe(u);
} else if (u->flags & UWM_FTRACE) { } else if (u->flags & UWM_FTRACE) {
return test_unwind_ftrace(u); return test_unwind_ftrace(u);
} else { } else {
struct pt_regs regs; struct pt_regs regs = fake_pt_regs();
memset(&regs, 0, sizeof(regs));
regs.psw.addr = get_psw_addr();
regs.gprs[15] = current_stack_pointer();
return test_unwind(NULL, return test_unwind(NULL,
(u->flags & UWM_REGS) ? &regs : NULL, (u->flags & UWM_REGS) ? &regs : NULL,
(u->flags & UWM_SP) ? u->sp : 0); (u->flags & UWM_SP) ? u->sp : 0);
...@@ -452,6 +472,10 @@ static const struct test_params param_list[] = { ...@@ -452,6 +472,10 @@ static const struct test_params param_list[] = {
TEST_WITH_FLAGS(UWM_KRETPROBE | UWM_SP), TEST_WITH_FLAGS(UWM_KRETPROBE | UWM_SP),
TEST_WITH_FLAGS(UWM_KRETPROBE | UWM_REGS), TEST_WITH_FLAGS(UWM_KRETPROBE | UWM_REGS),
TEST_WITH_FLAGS(UWM_KRETPROBE | UWM_SP | UWM_REGS), TEST_WITH_FLAGS(UWM_KRETPROBE | UWM_SP | UWM_REGS),
TEST_WITH_FLAGS(UWM_KRETPROBE_HANDLER),
TEST_WITH_FLAGS(UWM_KRETPROBE_HANDLER | UWM_SP),
TEST_WITH_FLAGS(UWM_KRETPROBE_HANDLER | UWM_REGS),
TEST_WITH_FLAGS(UWM_KRETPROBE_HANDLER | UWM_SP | UWM_REGS),
}; };
/* /*
......
...@@ -69,6 +69,7 @@ struct zpci_dev *get_zdev_by_fid(u32 fid) ...@@ -69,6 +69,7 @@ struct zpci_dev *get_zdev_by_fid(u32 fid)
list_for_each_entry(tmp, &zpci_list, entry) { list_for_each_entry(tmp, &zpci_list, entry) {
if (tmp->fid == fid) { if (tmp->fid == fid) {
zdev = tmp; zdev = tmp;
zpci_zdev_get(zdev);
break; break;
} }
} }
...@@ -399,7 +400,7 @@ EXPORT_SYMBOL(pci_iounmap); ...@@ -399,7 +400,7 @@ EXPORT_SYMBOL(pci_iounmap);
static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, static int pci_read(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 *val) int size, u32 *val)
{ {
struct zpci_dev *zdev = get_zdev_by_bus(bus, devfn); struct zpci_dev *zdev = zdev_from_bus(bus, devfn);
return (zdev) ? zpci_cfg_load(zdev, where, val, size) : -ENODEV; return (zdev) ? zpci_cfg_load(zdev, where, val, size) : -ENODEV;
} }
...@@ -407,7 +408,7 @@ static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, ...@@ -407,7 +408,7 @@ static int pci_read(struct pci_bus *bus, unsigned int devfn, int where,
static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, static int pci_write(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 val) int size, u32 val)
{ {
struct zpci_dev *zdev = get_zdev_by_bus(bus, devfn); struct zpci_dev *zdev = zdev_from_bus(bus, devfn);
return (zdev) ? zpci_cfg_store(zdev, where, val, size) : -ENODEV; return (zdev) ? zpci_cfg_store(zdev, where, val, size) : -ENODEV;
} }
......
...@@ -19,7 +19,8 @@ void zpci_bus_remove_device(struct zpci_dev *zdev, bool set_error); ...@@ -19,7 +19,8 @@ void zpci_bus_remove_device(struct zpci_dev *zdev, bool set_error);
void zpci_release_device(struct kref *kref); void zpci_release_device(struct kref *kref);
static inline void zpci_zdev_put(struct zpci_dev *zdev) static inline void zpci_zdev_put(struct zpci_dev *zdev)
{ {
kref_put(&zdev->kref, zpci_release_device); if (zdev)
kref_put(&zdev->kref, zpci_release_device);
} }
static inline void zpci_zdev_get(struct zpci_dev *zdev) static inline void zpci_zdev_get(struct zpci_dev *zdev)
...@@ -32,8 +33,8 @@ void zpci_free_domain(int domain); ...@@ -32,8 +33,8 @@ void zpci_free_domain(int domain);
int zpci_setup_bus_resources(struct zpci_dev *zdev, int zpci_setup_bus_resources(struct zpci_dev *zdev,
struct list_head *resources); struct list_head *resources);
static inline struct zpci_dev *get_zdev_by_bus(struct pci_bus *bus, static inline struct zpci_dev *zdev_from_bus(struct pci_bus *bus,
unsigned int devfn) unsigned int devfn)
{ {
struct zpci_bus *zbus = bus->sysdata; struct zpci_bus *zbus = bus->sysdata;
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include <asm/clp.h> #include <asm/clp.h>
#include <uapi/asm/clp.h> #include <uapi/asm/clp.h>
#include "pci_bus.h"
bool zpci_unique_uid; bool zpci_unique_uid;
void update_uid_checking(bool new) void update_uid_checking(bool new)
...@@ -404,8 +406,11 @@ static void __clp_add(struct clp_fh_list_entry *entry, void *data) ...@@ -404,8 +406,11 @@ static void __clp_add(struct clp_fh_list_entry *entry, void *data)
return; return;
zdev = get_zdev_by_fid(entry->fid); zdev = get_zdev_by_fid(entry->fid);
if (!zdev) if (zdev) {
zpci_create_device(entry->fid, entry->fh, entry->config_state); zpci_zdev_put(zdev);
return;
}
zpci_create_device(entry->fid, entry->fh, entry->config_state);
} }
int clp_scan_pci_devices(void) int clp_scan_pci_devices(void)
......
...@@ -269,7 +269,7 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf) ...@@ -269,7 +269,7 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid); pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid);
if (!pdev) if (!pdev)
return; goto no_pdev;
switch (ccdf->pec) { switch (ccdf->pec) {
case 0x003a: /* Service Action or Error Recovery Successful */ case 0x003a: /* Service Action or Error Recovery Successful */
...@@ -286,6 +286,8 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf) ...@@ -286,6 +286,8 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
break; break;
} }
pci_dev_put(pdev); pci_dev_put(pdev);
no_pdev:
zpci_zdev_put(zdev);
} }
void zpci_event_error(void *data) void zpci_event_error(void *data)
...@@ -314,6 +316,7 @@ static void zpci_event_hard_deconfigured(struct zpci_dev *zdev, u32 fh) ...@@ -314,6 +316,7 @@ static void zpci_event_hard_deconfigured(struct zpci_dev *zdev, u32 fh)
static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
{ {
struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
bool existing_zdev = !!zdev;
enum zpci_state state; enum zpci_state state;
zpci_dbg(3, "avl fid:%x, fh:%x, pec:%x\n", zpci_dbg(3, "avl fid:%x, fh:%x, pec:%x\n",
...@@ -378,6 +381,8 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) ...@@ -378,6 +381,8 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
default: default:
break; break;
} }
if (existing_zdev)
zpci_zdev_put(zdev);
} }
void zpci_event_availability(void *data) void zpci_event_availability(void *data)
......
...@@ -745,9 +745,7 @@ sclp_sync_wait(void) ...@@ -745,9 +745,7 @@ sclp_sync_wait(void)
/* Loop until driver state indicates finished request */ /* Loop until driver state indicates finished request */
while (sclp_running_state != sclp_running_state_idle) { while (sclp_running_state != sclp_running_state_idle) {
/* Check for expired request timer */ /* Check for expired request timer */
if (timer_pending(&sclp_request_timer) && if (get_tod_clock_fast() > timeout && del_timer(&sclp_request_timer))
get_tod_clock_fast() > timeout &&
del_timer(&sclp_request_timer))
sclp_request_timer.function(&sclp_request_timer); sclp_request_timer.function(&sclp_request_timer);
cpu_relax(); cpu_relax();
} }
......
...@@ -109,8 +109,7 @@ static void sclp_console_sync_queue(void) ...@@ -109,8 +109,7 @@ static void sclp_console_sync_queue(void)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&sclp_con_lock, flags); spin_lock_irqsave(&sclp_con_lock, flags);
if (timer_pending(&sclp_con_timer)) del_timer(&sclp_con_timer);
del_timer(&sclp_con_timer);
while (sclp_con_queue_running) { while (sclp_con_queue_running) {
spin_unlock_irqrestore(&sclp_con_lock, flags); spin_unlock_irqrestore(&sclp_con_lock, flags);
sclp_sync_wait(); sclp_sync_wait();
......
...@@ -231,8 +231,7 @@ sclp_vt220_emit_current(void) ...@@ -231,8 +231,7 @@ sclp_vt220_emit_current(void)
list_add_tail(&sclp_vt220_current_request->list, list_add_tail(&sclp_vt220_current_request->list,
&sclp_vt220_outqueue); &sclp_vt220_outqueue);
sclp_vt220_current_request = NULL; sclp_vt220_current_request = NULL;
if (timer_pending(&sclp_vt220_timer)) del_timer(&sclp_vt220_timer);
del_timer(&sclp_vt220_timer);
} }
sclp_vt220_flush_later = 0; sclp_vt220_flush_later = 0;
} }
...@@ -776,8 +775,7 @@ static void __sclp_vt220_flush_buffer(void) ...@@ -776,8 +775,7 @@ static void __sclp_vt220_flush_buffer(void)
sclp_vt220_emit_current(); sclp_vt220_emit_current();
spin_lock_irqsave(&sclp_vt220_lock, flags); spin_lock_irqsave(&sclp_vt220_lock, flags);
if (timer_pending(&sclp_vt220_timer)) del_timer(&sclp_vt220_timer);
del_timer(&sclp_vt220_timer);
while (sclp_vt220_queue_running) { while (sclp_vt220_queue_running) {
spin_unlock_irqrestore(&sclp_vt220_lock, flags); spin_unlock_irqrestore(&sclp_vt220_lock, flags);
sclp_sync_wait(); sclp_sync_wait();
......
...@@ -354,10 +354,10 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, ...@@ -354,10 +354,10 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
if (( if ((
sense[0] == SENSE_DATA_CHECK || sense[0] == SENSE_DATA_CHECK ||
sense[0] == SENSE_EQUIPMENT_CHECK || sense[0] == SENSE_EQUIPMENT_CHECK ||
sense[0] == SENSE_EQUIPMENT_CHECK + SENSE_DEFERRED_UNIT_CHECK sense[0] == (SENSE_EQUIPMENT_CHECK | SENSE_DEFERRED_UNIT_CHECK)
) && ( ) && (
sense[1] == SENSE_DRIVE_ONLINE || sense[1] == SENSE_DRIVE_ONLINE ||
sense[1] == SENSE_BEGINNING_OF_TAPE + SENSE_WRITE_MODE sense[1] == (SENSE_BEGINNING_OF_TAPE | SENSE_WRITE_MODE)
)) { )) {
switch (request->op) { switch (request->op) {
/* /*
......
...@@ -113,16 +113,10 @@ ccw_device_timeout(struct timer_list *t) ...@@ -113,16 +113,10 @@ ccw_device_timeout(struct timer_list *t)
void void
ccw_device_set_timeout(struct ccw_device *cdev, int expires) ccw_device_set_timeout(struct ccw_device *cdev, int expires)
{ {
if (expires == 0) { if (expires == 0)
del_timer(&cdev->private->timer); del_timer(&cdev->private->timer);
return; else
} mod_timer(&cdev->private->timer, jiffies + expires);
if (timer_pending(&cdev->private->timer)) {
if (mod_timer(&cdev->private->timer, jiffies + expires))
return;
}
cdev->private->timer.expires = jiffies + expires;
add_timer(&cdev->private->timer);
} }
int int
......
...@@ -112,16 +112,10 @@ static void eadm_subchannel_set_timeout(struct subchannel *sch, int expires) ...@@ -112,16 +112,10 @@ static void eadm_subchannel_set_timeout(struct subchannel *sch, int expires)
{ {
struct eadm_private *private = get_eadm_private(sch); struct eadm_private *private = get_eadm_private(sch);
if (expires == 0) { if (expires == 0)
del_timer(&private->timer); del_timer(&private->timer);
return; else
} mod_timer(&private->timer, jiffies + expires);
if (timer_pending(&private->timer)) {
if (mod_timer(&private->timer, jiffies + expires))
return;
}
private->timer.expires = jiffies + expires;
add_timer(&private->timer);
} }
static void eadm_subchannel_irq(struct subchannel *sch) static void eadm_subchannel_irq(struct subchannel *sch)
......
...@@ -315,6 +315,7 @@ struct ap_perms { ...@@ -315,6 +315,7 @@ struct ap_perms {
unsigned long ioctlm[BITS_TO_LONGS(AP_IOCTLS)]; unsigned long ioctlm[BITS_TO_LONGS(AP_IOCTLS)];
unsigned long apm[BITS_TO_LONGS(AP_DEVICES)]; unsigned long apm[BITS_TO_LONGS(AP_DEVICES)];
unsigned long aqm[BITS_TO_LONGS(AP_DOMAINS)]; unsigned long aqm[BITS_TO_LONGS(AP_DOMAINS)];
unsigned long adm[BITS_TO_LONGS(AP_DOMAINS)];
}; };
extern struct ap_perms ap_perms; extern struct ap_perms ap_perms;
extern struct mutex ap_perms_mutex; extern struct mutex ap_perms_mutex;
......
...@@ -155,7 +155,7 @@ static int pkey_skey2pkey(const u8 *key, struct pkey_protkey *pkey) ...@@ -155,7 +155,7 @@ static int pkey_skey2pkey(const u8 *key, struct pkey_protkey *pkey)
/* /*
* The cca_xxx2protkey call may fail when a card has been * The cca_xxx2protkey call may fail when a card has been
* addressed where the master key was changed after last fetch * addressed where the master key was changed after last fetch
* of the mkvp into the cache. Try 3 times: First witout verify * of the mkvp into the cache. Try 3 times: First without verify
* then with verify and last round with verify and old master * then with verify and last round with verify and old master
* key verification pattern match not ignored. * key verification pattern match not ignored.
*/ */
......
...@@ -1189,13 +1189,6 @@ static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { ...@@ -1189,13 +1189,6 @@ static const struct attribute_group *vfio_ap_mdev_attr_groups[] = {
* @matrix_mdev: a mediated matrix device * @matrix_mdev: a mediated matrix device
* @kvm: reference to KVM instance * @kvm: reference to KVM instance
* *
* Note: The matrix_dev->lock must be taken prior to calling
* this function; however, the lock will be temporarily released while the
* guest's AP configuration is set to avoid a potential lockdep splat.
* The kvm->lock is taken to set the guest's AP configuration which, under
* certain circumstances, will result in a circular lock dependency if this is
* done under the @matrix_mdev->lock.
*
* Return: 0 if no other mediated matrix device has a reference to @kvm; * Return: 0 if no other mediated matrix device has a reference to @kvm;
* otherwise, returns an -EPERM. * otherwise, returns an -EPERM.
*/ */
...@@ -1269,18 +1262,11 @@ static int vfio_ap_mdev_iommu_notifier(struct notifier_block *nb, ...@@ -1269,18 +1262,11 @@ static int vfio_ap_mdev_iommu_notifier(struct notifier_block *nb,
* by @matrix_mdev. * by @matrix_mdev.
* *
* @matrix_mdev: a matrix mediated device * @matrix_mdev: a matrix mediated device
* @kvm: the pointer to the kvm structure being unset.
*
* Note: The matrix_dev->lock must be taken prior to calling
* this function; however, the lock will be temporarily released while the
* guest's AP configuration is cleared to avoid a potential lockdep splat.
* The kvm->lock is taken to clear the guest's AP configuration which, under
* certain circumstances, will result in a circular lock dependency if this is
* done under the @matrix_mdev->lock.
*/ */
static void vfio_ap_mdev_unset_kvm(struct ap_matrix_mdev *matrix_mdev, static void vfio_ap_mdev_unset_kvm(struct ap_matrix_mdev *matrix_mdev)
struct kvm *kvm)
{ {
struct kvm *kvm = matrix_mdev->kvm;
if (kvm && kvm->arch.crypto.crycbd) { if (kvm && kvm->arch.crypto.crycbd) {
down_write(&kvm->arch.crypto.pqap_hook_rwsem); down_write(&kvm->arch.crypto.pqap_hook_rwsem);
kvm->arch.crypto.pqap_hook = NULL; kvm->arch.crypto.pqap_hook = NULL;
...@@ -1311,7 +1297,7 @@ static int vfio_ap_mdev_group_notifier(struct notifier_block *nb, ...@@ -1311,7 +1297,7 @@ static int vfio_ap_mdev_group_notifier(struct notifier_block *nb,
matrix_mdev = container_of(nb, struct ap_matrix_mdev, group_notifier); matrix_mdev = container_of(nb, struct ap_matrix_mdev, group_notifier);
if (!data) if (!data)
vfio_ap_mdev_unset_kvm(matrix_mdev, matrix_mdev->kvm); vfio_ap_mdev_unset_kvm(matrix_mdev);
else if (vfio_ap_mdev_set_kvm(matrix_mdev, data)) else if (vfio_ap_mdev_set_kvm(matrix_mdev, data))
notify_rc = NOTIFY_DONE; notify_rc = NOTIFY_DONE;
...@@ -1448,7 +1434,7 @@ static void vfio_ap_mdev_close_device(struct vfio_device *vdev) ...@@ -1448,7 +1434,7 @@ static void vfio_ap_mdev_close_device(struct vfio_device *vdev)
&matrix_mdev->iommu_notifier); &matrix_mdev->iommu_notifier);
vfio_unregister_notifier(vdev->dev, VFIO_GROUP_NOTIFY, vfio_unregister_notifier(vdev->dev, VFIO_GROUP_NOTIFY,
&matrix_mdev->group_notifier); &matrix_mdev->group_notifier);
vfio_ap_mdev_unset_kvm(matrix_mdev, matrix_mdev->kvm); vfio_ap_mdev_unset_kvm(matrix_mdev);
} }
static int vfio_ap_mdev_get_device_info(unsigned long arg) static int vfio_ap_mdev_get_device_info(unsigned long arg)
......
...@@ -285,10 +285,53 @@ static ssize_t aqmask_store(struct device *dev, ...@@ -285,10 +285,53 @@ static ssize_t aqmask_store(struct device *dev,
static DEVICE_ATTR_RW(aqmask); static DEVICE_ATTR_RW(aqmask);
static ssize_t admask_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int i, rc;
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
if (mutex_lock_interruptible(&ap_perms_mutex))
return -ERESTARTSYS;
buf[0] = '0';
buf[1] = 'x';
for (i = 0; i < sizeof(zcdndev->perms.adm) / sizeof(long); i++)
snprintf(buf + 2 + 2 * i * sizeof(long),
PAGE_SIZE - 2 - 2 * i * sizeof(long),
"%016lx", zcdndev->perms.adm[i]);
buf[2 + 2 * i * sizeof(long)] = '\n';
buf[2 + 2 * i * sizeof(long) + 1] = '\0';
rc = 2 + 2 * i * sizeof(long) + 1;
mutex_unlock(&ap_perms_mutex);
return rc;
}
static ssize_t admask_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int rc;
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
rc = ap_parse_mask_str(buf, zcdndev->perms.adm,
AP_DOMAINS, &ap_perms_mutex);
if (rc)
return rc;
return count;
}
static DEVICE_ATTR_RW(admask);
static struct attribute *zcdn_dev_attrs[] = { static struct attribute *zcdn_dev_attrs[] = {
&dev_attr_ioctlmask.attr, &dev_attr_ioctlmask.attr,
&dev_attr_apmask.attr, &dev_attr_apmask.attr,
&dev_attr_aqmask.attr, &dev_attr_aqmask.attr,
&dev_attr_admask.attr,
NULL NULL
}; };
...@@ -880,11 +923,22 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, ...@@ -880,11 +923,22 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
if (rc) if (rc)
goto out; goto out;
tdom = *domain;
if (perms != &ap_perms && tdom < AP_DOMAINS) {
if (ap_msg.flags & AP_MSG_FLAG_ADMIN) {
if (!test_bit_inv(tdom, perms->adm)) {
rc = -ENODEV;
goto out;
}
} else if ((ap_msg.flags & AP_MSG_FLAG_USAGE) == 0) {
rc = -EOPNOTSUPP;
goto out;
}
}
/* /*
* If a valid target domain is set and this domain is NOT a usage * If a valid target domain is set and this domain is NOT a usage
* domain but a control only domain, autoselect target domain. * domain but a control only domain, autoselect target domain.
*/ */
tdom = *domain;
if (tdom < AP_DOMAINS && if (tdom < AP_DOMAINS &&
!ap_test_config_usage_domain(tdom) && !ap_test_config_usage_domain(tdom) &&
ap_test_config_ctrl_domain(tdom)) ap_test_config_ctrl_domain(tdom))
...@@ -1062,6 +1116,18 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms, ...@@ -1062,6 +1116,18 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
if (rc) if (rc)
goto out_free; goto out_free;
if (perms != &ap_perms && domain < AUTOSEL_DOM) {
if (ap_msg.flags & AP_MSG_FLAG_ADMIN) {
if (!test_bit_inv(domain, perms->adm)) {
rc = -ENODEV;
goto out_free;
}
} else if ((ap_msg.flags & AP_MSG_FLAG_USAGE) == 0) {
rc = -EOPNOTSUPP;
goto out_free;
}
}
pref_zc = NULL; pref_zc = NULL;
pref_zq = NULL; pref_zq = NULL;
spin_lock(&zcrypt_list_lock); spin_lock(&zcrypt_list_lock);
......
...@@ -90,7 +90,7 @@ static ssize_t online_store(struct device *dev, ...@@ -90,7 +90,7 @@ static ssize_t online_store(struct device *dev,
list_for_each_entry(zq, &zc->zqueues, list) list_for_each_entry(zq, &zc->zqueues, list)
maxzqs++; maxzqs++;
if (maxzqs > 0) if (maxzqs > 0)
zq_uelist = kcalloc(maxzqs + 1, sizeof(zq), GFP_ATOMIC); zq_uelist = kcalloc(maxzqs + 1, sizeof(*zq_uelist), GFP_ATOMIC);
list_for_each_entry(zq, &zc->zqueues, list) list_for_each_entry(zq, &zc->zqueues, list)
if (zcrypt_queue_force_online(zq, online)) if (zcrypt_queue_force_online(zq, online))
if (zq_uelist) { if (zq_uelist) {
......
...@@ -1109,7 +1109,7 @@ static int ep11_wrapkey(u16 card, u16 domain, ...@@ -1109,7 +1109,7 @@ static int ep11_wrapkey(u16 card, u16 domain,
if (kb->head.type == TOKTYPE_NON_CCA && if (kb->head.type == TOKTYPE_NON_CCA &&
kb->head.version == TOKVER_EP11_AES) { kb->head.version == TOKVER_EP11_AES) {
has_header = true; has_header = true;
keysize = kb->head.len < keysize ? kb->head.len : keysize; keysize = min_t(size_t, kb->head.len, keysize);
} }
/* request cprb and payload */ /* request cprb and payload */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment