s390 updates for the 5.16 merge window

- Add support for ftrace with direct call and ftrace direct call samples.
 
 - Add support for kernel command lines longer than current 896 bytes and
   make its length configurable.
 
 - Add support for BEAR enhancement facility to improve last breaking
   event instruction tracking.
 
 - Add kprobes sanity checks and testcases to prevent kprobe in the mid
   of an instruction.
 
 - Allow concurrent access to /dev/hwc for the CPUMF users.
 
 - Various ftrace / jump label improvements.
 
 - Convert unwinder tests to KUnit.
 
 - Add s390_iommu_aperture kernel parameter to tweak the limits on
   concurrently usable DMA mappings.
 
 - Add ap.useirq AP module option which can be used to disable interrupt
   use.
 
 - Add add_disk() error handling support to block device drivers.
 
 - Drop arch specific and use generic implementation of strlcpy and strrchr.
 
 - Several __pa/__va usages fixes.
 
 - Various cio, crypto, pci, kernel doc and other small fixes and
   improvements all over the code.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEE3QHqV+H2a8xAv27vjYWKoQLXFBgFAmGFW6EACgkQjYWKoQLX
 FBg20Qf/UbohgnKnE6vxbbH3sNTlI2dk3Cw4z3IobcsZgqXAu6AFLgLQGLk/X07F
 DIyUdrgSgCzLIEKLqrLrFXIOMIK44zAGaurIltNt7IrnWWlA+/YVD+YeL2gHwccq
 wT7KXRcrVMZQ1z18djJQ45DpPUC8ErBdL6+P+ftHck90YGFZsfMA5S7jf8X1h08U
 IlqdPTmY8t4unKHWVpHbxx9b+xrUuV6KTEXADsllpMV2jQoTLdDECd3vmefYR6tR
 3lssgop1m/RzH5OCqvia5Sy2D5fOQObNWDMakwOkVMxOD43lmGCTHstzS2Uo2OFE
 QcY79lfZ5NrzKnenUdE5Fd0XJ9kSwQ==
 =k0Ab
 -----END PGP SIGNATURE-----

Merge tag 's390-5.16-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull s390 updates from Vasily Gorbik:

 - Add support for ftrace with direct call and ftrace direct call
   samples.

 - Add support for kernel command lines longer than current 896 bytes
   and make its length configurable.

 - Add support for BEAR enhancement facility to improve last breaking
   event instruction tracking.

 - Add kprobes sanity checks and testcases to prevent kprobe in the mid
   of an instruction.

 - Allow concurrent access to /dev/hwc for the CPUMF users.

 - Various ftrace / jump label improvements.

 - Convert unwinder tests to KUnit.

 - Add s390_iommu_aperture kernel parameter to tweak the limits on
   concurrently usable DMA mappings.

 - Add ap.useirq AP module option which can be used to disable interrupt
   use.

 - Add add_disk() error handling support to block device drivers.

 - Drop arch specific and use generic implementation of strlcpy and
   strrchr.

 - Several __pa/__va usages fixes.

 - Various cio, crypto, pci, kernel doc and other small fixes and
   improvements all over the code.

[ Merge fixup as per https://lore.kernel.org/all/YXAqZ%2FEszRisunQw@osiris/ ]

* tag 's390-5.16-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (63 commits)
  s390: make command line configurable
  s390: support command lines longer than 896 bytes
  s390/kexec_file: move kernel image size check
  s390/pci: add s390_iommu_aperture kernel parameter
  s390/spinlock: remove incorrect kernel doc indicator
  s390/string: use generic strlcpy
  s390/string: use generic strrchr
  s390/ap: function rework based on compiler warning
  s390/cio: make ccw_device_dma_* more robust
  s390/vfio-ap: s390/crypto: fix all kernel-doc warnings
  s390/hmcdrv: fix kernel doc comments
  s390/ap: new module option ap.useirq
  s390/cpumf: Allow multiple processes to access /dev/hwc
  s390/bitops: return true/false (not 1/0) from bool functions
  s390: add support for BEAR enhancement facility
  s390: introduce nospec_uses_trampoline()
  s390: rename last_break to pgm_last_break
  s390/ptrace: add last_break member to pt_regs
  s390/sclp: sort out physical vs virtual pointers usage
  s390/setup: convert start and end initrd pointers to virtual
  ...
This commit is contained in:
Linus Torvalds 2021-11-06 14:48:06 -07:00
commit 0b707e572a
97 changed files with 1288 additions and 658 deletions

View File

@ -4992,6 +4992,18 @@
an IOTLB flush. Default is lazy flushing before reuse,
which is faster.
s390_iommu_aperture= [KNL,S390]
Specifies the size of the per device DMA address space
accessible through the DMA and IOMMU APIs as a decimal
factor of the size of main memory.
The default is 1 meaning that one can concurrently use
as many DMA addresses as physical memory is installed,
if supported by hardware, and thus map all of memory
once. With a value of 2 one can map all of memory twice
and so on. As a special case a factor of 0 imposes no
restrictions other than those given by hardware at the
cost of significant additional memory use for tables.
sa1100ir [NET]
See drivers/net/irda/sa1100_ir.c.

View File

@ -153,12 +153,15 @@ config S390
select HAVE_DEBUG_KMEMLEAK
select HAVE_DMA_CONTIGUOUS
select HAVE_DYNAMIC_FTRACE
select HAVE_DYNAMIC_FTRACE_WITH_ARGS
select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
select HAVE_DYNAMIC_FTRACE_WITH_REGS
select HAVE_EBPF_JIT if PACK_STACK && HAVE_MARCH_Z196_FEATURES
select HAVE_EFFICIENT_UNALIGNED_ACCESS
select HAVE_FAST_GUP
select HAVE_FENTRY
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_FUNCTION_ARG_ACCESS_API
select HAVE_FUNCTION_ERROR_INJECTION
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_FUNCTION_TRACER
@ -190,6 +193,7 @@ config S390
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_RELIABLE_STACKTRACE
select HAVE_RSEQ
select HAVE_SAMPLE_FTRACE_DIRECT
select HAVE_SOFTIRQ_ON_OWN_STACK
select HAVE_SYSCALL_TRACEPOINTS
select HAVE_VIRT_CPU_ACCOUNTING
@ -434,6 +438,14 @@ endchoice
config 64BIT
def_bool y
config COMMAND_LINE_SIZE
int "Maximum size of kernel command line"
default 4096
range 896 1048576
help
This allows you to specify the maximum length of the kernel command
line.
config COMPAT
def_bool y
prompt "Kernel support for 31 bit emulation"
@ -938,6 +950,8 @@ menu "Selftests"
config S390_UNWIND_SELFTEST
def_tristate n
depends on KUNIT
default KUNIT_ALL_TESTS
prompt "Test unwind functions"
help
This option enables s390 specific stack unwinder testing kernel
@ -946,4 +960,16 @@ config S390_UNWIND_SELFTEST
Say N if you are unsure.
config S390_KPROBES_SANITY_TEST
def_tristate n
prompt "Enable s390 specific kprobes tests"
depends on KPROBES
depends on KUNIT
help
This option enables an s390 specific kprobes test module. This option
is not useful for distributions or general kernels, but only for kernel
developers working on architecture code.
Say N if you are unsure.
endmenu

View File

@ -24,6 +24,7 @@ struct vmlinux_info {
unsigned long dynsym_start;
unsigned long rela_dyn_start;
unsigned long rela_dyn_end;
unsigned long amode31_size;
};
/* Symbols defined by linker scripts */

View File

@ -184,35 +184,23 @@ iplstart:
bas %r14,.Lloader # load parameter file
ltr %r2,%r2 # got anything ?
bz .Lnopf
chi %r2,895
bnh .Lnotrunc
la %r2,895
l %r3,MAX_COMMAND_LINE_SIZE+ARCH_OFFSET-PARMAREA(%r12)
ahi %r3,-1
clr %r2,%r3
bl .Lnotrunc
lr %r2,%r3
.Lnotrunc:
l %r4,.Linitrd
clc 0(3,%r4),.L_hdr # if it is HDRx
bz .Lagain1 # skip dataset header
clc 0(3,%r4),.L_eof # if it is EOFx
bz .Lagain1 # skip dateset trailer
la %r5,0(%r4,%r2)
lr %r3,%r2
la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
mvc 0(256,%r3),0(%r4)
mvc 256(256,%r3),256(%r4)
mvc 512(256,%r3),512(%r4)
mvc 768(122,%r3),768(%r4)
slr %r0,%r0
b .Lcntlp
.Ldelspc:
ic %r0,0(%r2,%r3)
chi %r0,0x20 # is it a space ?
be .Lcntlp
ahi %r2,1
b .Leolp
.Lcntlp:
brct %r2,.Ldelspc
.Leolp:
slr %r0,%r0
stc %r0,0(%r2,%r3) # terminate buffer
lr %r5,%r2
la %r6,COMMAND_LINE-PARMAREA(%r12)
lr %r7,%r2
ahi %r7,1
mvcl %r6,%r4
.Lnopf:
#
@ -317,6 +305,7 @@ SYM_CODE_START_LOCAL(startup_normal)
xc 0x300(256),0x300
xc 0xe00(256),0xe00
xc 0xf00(256),0xf00
lctlg %c0,%c15,.Lctl-.LPG0(%r13) # load control registers
stcke __LC_BOOT_CLOCK
mvc __LC_LAST_UPDATE_CLOCK(8),__LC_BOOT_CLOCK+1
spt 6f-.LPG0(%r13)
@ -335,6 +324,22 @@ SYM_CODE_END(startup_normal)
.quad 0x0000000180000000,startup_pgm_check_handler
.Lio_new_psw:
.quad 0x0002000180000000,0x1f0 # disabled wait
.Lctl: .quad 0x04040000 # cr0: AFP registers & secondary space
.quad 0 # cr1: primary space segment table
.quad 0 # cr2: dispatchable unit control table
.quad 0 # cr3: instruction authorization
.quad 0xffff # cr4: instruction authorization
.quad 0 # cr5: primary-aste origin
.quad 0 # cr6: I/O interrupts
.quad 0 # cr7: secondary space segment table
.quad 0x0000000000008000 # cr8: access registers translation
.quad 0 # cr9: tracing off
.quad 0 # cr10: tracing off
.quad 0 # cr11: tracing off
.quad 0 # cr12: tracing off
.quad 0 # cr13: home space segment table
.quad 0xc0000000 # cr14: machine check handling off
.quad 0 # cr15: linkage stack operations
#include "head_kdump.S"
@ -377,11 +382,10 @@ SYM_DATA_START(parmarea)
.quad 0 # OLDMEM_BASE
.quad 0 # OLDMEM_SIZE
.quad kernel_version # points to kernel version string
.quad COMMAND_LINE_SIZE
.org COMMAND_LINE
.byte "root=/dev/ram0 ro"
.byte 0
.org PARMAREA+__PARMAREA_SIZE
SYM_DATA_END(parmarea)
.org HEAD_END

View File

@ -170,10 +170,10 @@ static inline int has_ebcdic_char(const char *str)
void setup_boot_command_line(void)
{
parmarea.command_line[ARCH_COMMAND_LINE_SIZE - 1] = 0;
parmarea.command_line[COMMAND_LINE_SIZE - 1] = 0;
/* convert arch command line to ascii if necessary */
if (has_ebcdic_char(parmarea.command_line))
EBCASC(parmarea.command_line, ARCH_COMMAND_LINE_SIZE);
EBCASC(parmarea.command_line, COMMAND_LINE_SIZE);
/* copy arch command line */
strcpy(early_command_line, strim(parmarea.command_line));

View File

@ -175,6 +175,6 @@ void print_pgm_check_info(void)
gpregs[12], gpregs[13], gpregs[14], gpregs[15]);
print_stacktrace();
decompressor_printk("Last Breaking-Event-Address:\n");
decompressor_printk(" [<%016lx>] %pS\n", (unsigned long)S390_lowcore.breaking_event_addr,
(void *)S390_lowcore.breaking_event_addr);
decompressor_printk(" [<%016lx>] %pS\n", (unsigned long)S390_lowcore.pgm_last_break,
(void *)S390_lowcore.pgm_last_break);
}

View File

@ -15,6 +15,7 @@
#include "uv.h"
unsigned long __bootdata_preserved(__kaslr_offset);
unsigned long __bootdata(__amode31_base);
unsigned long __bootdata_preserved(VMALLOC_START);
unsigned long __bootdata_preserved(VMALLOC_END);
struct page *__bootdata_preserved(vmemmap);
@ -259,6 +260,12 @@ static void offset_vmlinux_info(unsigned long offset)
vmlinux.dynsym_start += offset;
}
static unsigned long reserve_amode31(unsigned long safe_addr)
{
__amode31_base = PAGE_ALIGN(safe_addr);
return safe_addr + vmlinux.amode31_size;
}
void startup_kernel(void)
{
unsigned long random_lma;
@ -273,6 +280,7 @@ void startup_kernel(void)
setup_lpp();
store_ipl_parmblock();
safe_addr = mem_safe_offset();
safe_addr = reserve_amode31(safe_addr);
safe_addr = read_ipl_report(safe_addr);
uv_query_info();
rescue_initrd(safe_addr);

View File

@ -61,7 +61,8 @@ CONFIG_PROTECTED_VIRTUALIZATION_GUEST=y
CONFIG_CMM=m
CONFIG_APPLDATA_BASE=y
CONFIG_KVM=m
CONFIG_S390_UNWIND_SELFTEST=y
CONFIG_S390_UNWIND_SELFTEST=m
CONFIG_S390_KPROBES_SANITY_TEST=m
CONFIG_KPROBES=y
CONFIG_JUMP_LABEL=y
CONFIG_STATIC_KEYS_SELFTEST=y
@ -776,7 +777,6 @@ CONFIG_CRC8=m
CONFIG_RANDOM32_SELFTEST=y
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=0
CONFIG_DMA_API_DEBUG=y
CONFIG_PRINTK_TIME=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_INFO=y
@ -839,8 +839,13 @@ CONFIG_BPF_KPROBE_OVERRIDE=y
CONFIG_HIST_TRIGGERS=y
CONFIG_FTRACE_STARTUP_TEST=y
# CONFIG_EVENT_TRACE_STARTUP_TEST is not set
CONFIG_SAMPLES=y
CONFIG_SAMPLE_TRACE_PRINTK=m
CONFIG_SAMPLE_FTRACE_DIRECT=m
CONFIG_DEBUG_ENTRY=y
CONFIG_CIO_INJECT=y
CONFIG_KUNIT=m
CONFIG_KUNIT_DEBUGFS=y
CONFIG_NOTIFIER_ERROR_INJECTION=m
CONFIG_NETDEV_NOTIFIER_ERROR_INJECT=m
CONFIG_FAULT_INJECTION=y

View File

@ -60,6 +60,7 @@ CONFIG_CMM=m
CONFIG_APPLDATA_BASE=y
CONFIG_KVM=m
CONFIG_S390_UNWIND_SELFTEST=m
CONFIG_S390_KPROBES_SANITY_TEST=m
CONFIG_KPROBES=y
CONFIG_JUMP_LABEL=y
# CONFIG_GCC_PLUGINS is not set
@ -788,6 +789,11 @@ CONFIG_FTRACE_SYSCALLS=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_BPF_KPROBE_OVERRIDE=y
CONFIG_HIST_TRIGGERS=y
CONFIG_SAMPLES=y
CONFIG_SAMPLE_TRACE_PRINTK=m
CONFIG_SAMPLE_FTRACE_DIRECT=m
CONFIG_KUNIT=m
CONFIG_KUNIT_DEBUGFS=y
CONFIG_LKDTM=m
CONFIG_PERCPU_TEST=m
CONFIG_ATOMIC64_SELFTEST=y

View File

@ -16,20 +16,24 @@
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
/* Fast-BCR without checkpoint synchronization */
#define __ASM_BARRIER "bcr 14,0\n"
#define __ASM_BCR_SERIALIZE "bcr 14,0\n"
#else
#define __ASM_BARRIER "bcr 15,0\n"
#define __ASM_BCR_SERIALIZE "bcr 15,0\n"
#endif
#define mb() do { asm volatile(__ASM_BARRIER : : : "memory"); } while (0)
static __always_inline void bcr_serialize(void)
{
asm volatile(__ASM_BCR_SERIALIZE : : : "memory");
}
#define rmb() barrier()
#define wmb() barrier()
#define dma_rmb() mb()
#define dma_wmb() mb()
#define __smp_mb() mb()
#define __smp_rmb() rmb()
#define __smp_wmb() wmb()
#define mb() bcr_serialize()
#define rmb() barrier()
#define wmb() barrier()
#define dma_rmb() mb()
#define dma_wmb() mb()
#define __smp_mb() mb()
#define __smp_rmb() rmb()
#define __smp_wmb() wmb()
#define __smp_store_release(p, v) \
do { \

View File

@ -188,7 +188,7 @@ static inline bool arch_test_and_set_bit_lock(unsigned long nr,
volatile unsigned long *ptr)
{
if (arch_test_bit(nr, ptr))
return 1;
return true;
return arch_test_and_set_bit(nr, ptr);
}

View File

@ -12,6 +12,7 @@
#ifndef __ASSEMBLY__
#include <linux/types.h>
#include <linux/jump_label.h>
struct cpuid
{
@ -21,5 +22,7 @@ struct cpuid
unsigned int unused : 16;
} __attribute__ ((packed, aligned(8)));
DECLARE_STATIC_KEY_FALSE(cpu_has_bear);
#endif /* __ASSEMBLY__ */
#endif /* _ASM_S390_CPU_H */

View File

@ -462,7 +462,7 @@ arch_initcall(VNAME(var, reg))
*
* @var: Name of debug_info_t variable
* @name: Name of debug log (e.g. used for debugfs entry)
* @pages_per_area: Number of pages per area
* @pages: Number of pages per area
* @nr_areas: Number of debug areas
* @buf_size: Size of data area in each debug entry
* @view: Pointer to debug view struct

View File

@ -17,7 +17,6 @@
void ftrace_caller(void);
extern char ftrace_graph_caller_end;
extern void *ftrace_func;
struct dyn_arch_ftrace { };
@ -42,6 +41,35 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr)
return addr;
}
struct ftrace_regs {
struct pt_regs regs;
};
static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs)
{
return &fregs->regs;
}
static __always_inline void ftrace_instruction_pointer_set(struct ftrace_regs *fregs,
unsigned long ip)
{
struct pt_regs *regs = arch_ftrace_get_regs(fregs);
regs->psw.addr = ip;
}
/*
* When an ftrace registered caller is tracing a function that is
* also set by a register_ftrace_direct() call, it needs to be
* differentiated in the ftrace_caller trampoline. To do this,
* place the direct caller in the ORIG_GPR2 part of pt_regs. This
* tells the ftrace_caller that there's a direct caller.
*/
static inline void arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr)
{
regs->orig_gpr2 = addr;
}
/*
* Even though the system call numbers are identical for s390/s390x a
* different system call table is used for compat tasks. This may lead
@ -68,4 +96,32 @@ static inline bool arch_syscall_match_sym_name(const char *sym,
}
#endif /* __ASSEMBLY__ */
#ifdef CONFIG_FUNCTION_TRACER
#define FTRACE_NOP_INSN .word 0xc004, 0x0000, 0x0000 /* brcl 0,0 */
#ifndef CC_USING_HOTPATCH
#define FTRACE_GEN_MCOUNT_RECORD(name) \
.section __mcount_loc, "a", @progbits; \
.quad name; \
.previous;
#else /* !CC_USING_HOTPATCH */
#define FTRACE_GEN_MCOUNT_RECORD(name)
#endif /* !CC_USING_HOTPATCH */
#define FTRACE_GEN_NOP_ASM(name) \
FTRACE_GEN_MCOUNT_RECORD(name) \
FTRACE_NOP_INSN
#else /* CONFIG_FUNCTION_TRACER */
#define FTRACE_GEN_NOP_ASM(name)
#endif /* CONFIG_FUNCTION_TRACER */
#endif /* _ASM_S390_FTRACE_H */

View File

@ -2,6 +2,8 @@
#ifndef _ASM_S390_JUMP_LABEL_H
#define _ASM_S390_JUMP_LABEL_H
#define HAVE_JUMP_LABEL_BATCH
#ifndef __ASSEMBLY__
#include <linux/types.h>

View File

@ -16,9 +16,7 @@
static inline void klp_arch_set_pc(struct ftrace_regs *fregs, unsigned long ip)
{
struct pt_regs *regs = ftrace_get_regs(fregs);
regs->psw.addr = ip;
ftrace_instruction_pointer_set(fregs, ip);
}
#endif

View File

@ -65,7 +65,7 @@ struct lowcore {
__u32 external_damage_code; /* 0x00f4 */
__u64 failing_storage_address; /* 0x00f8 */
__u8 pad_0x0100[0x0110-0x0100]; /* 0x0100 */
__u64 breaking_event_addr; /* 0x0110 */
__u64 pgm_last_break; /* 0x0110 */
__u8 pad_0x0118[0x0120-0x0118]; /* 0x0118 */
psw_t restart_old_psw; /* 0x0120 */
psw_t external_old_psw; /* 0x0130 */
@ -93,9 +93,10 @@ struct lowcore {
psw_t return_psw; /* 0x0290 */
psw_t return_mcck_psw; /* 0x02a0 */
__u64 last_break; /* 0x02b0 */
/* CPU accounting and timing values. */
__u64 sys_enter_timer; /* 0x02b0 */
__u8 pad_0x02b8[0x02c0-0x02b8]; /* 0x02b8 */
__u64 sys_enter_timer; /* 0x02b8 */
__u64 mcck_enter_timer; /* 0x02c0 */
__u64 exit_timer; /* 0x02c8 */
__u64 user_timer; /* 0x02d0 */
@ -188,7 +189,7 @@ struct lowcore {
__u32 tod_progreg_save_area; /* 0x1324 */
__u32 cpu_timer_save_area[2]; /* 0x1328 */
__u32 clock_comp_save_area[2]; /* 0x1330 */
__u8 pad_0x1338[0x1340-0x1338]; /* 0x1338 */
__u64 last_break_save_area; /* 0x1338 */
__u32 access_regs_save_area[16]; /* 0x1340 */
__u64 cregs_save_area[16]; /* 0x1380 */
__u8 pad_0x1400[0x1800-0x1400]; /* 0x1400 */

View File

@ -12,6 +12,11 @@ void nospec_init_branches(void);
void nospec_auto_detect(void);
void nospec_revert(s32 *start, s32 *end);
static inline bool nospec_uses_trampoline(void)
{
return __is_defined(CC_USING_EXPOLINE) && !nospec_disable;
}
#endif /* __ASSEMBLY__ */
#endif /* _ASM_S390_EXPOLINE_H */

View File

@ -583,11 +583,11 @@ static inline void cspg(unsigned long *ptr, unsigned long old, unsigned long new
#define CRDTE_DTT_REGION1 0x1cUL
static inline void crdte(unsigned long old, unsigned long new,
unsigned long table, unsigned long dtt,
unsigned long *table, unsigned long dtt,
unsigned long address, unsigned long asce)
{
union register_pair r1 = { .even = old, .odd = new, };
union register_pair r2 = { .even = table | dtt, .odd = address, };
union register_pair r2 = { .even = __pa(table) | dtt, .odd = address, };
asm volatile(".insn rrf,0xb98f0000,%[r1],%[r2],%[asce],0"
: [r1] "+&d" (r1.pair)
@ -1001,7 +1001,7 @@ static __always_inline void __ptep_ipte(unsigned long address, pte_t *ptep,
unsigned long opt, unsigned long asce,
int local)
{
unsigned long pto = (unsigned long) ptep;
unsigned long pto = __pa(ptep);
if (__builtin_constant_p(opt) && opt == 0) {
/* Invalidation + TLB flush for the pte */
@ -1023,7 +1023,7 @@ static __always_inline void __ptep_ipte(unsigned long address, pte_t *ptep,
static __always_inline void __ptep_ipte_range(unsigned long address, int nr,
pte_t *ptep, int local)
{
unsigned long pto = (unsigned long) ptep;
unsigned long pto = __pa(ptep);
/* Invalidate a range of ptes + TLB flush of the ptes */
do {
@ -1487,7 +1487,7 @@ static __always_inline void __pmdp_idte(unsigned long addr, pmd_t *pmdp,
{
unsigned long sto;
sto = (unsigned long) pmdp - pmd_index(addr) * sizeof(pmd_t);
sto = __pa(pmdp) - pmd_index(addr) * sizeof(pmd_t);
if (__builtin_constant_p(opt) && opt == 0) {
/* flush without guest asce */
asm volatile(
@ -1513,7 +1513,7 @@ static __always_inline void __pudp_idte(unsigned long addr, pud_t *pudp,
{
unsigned long r3o;
r3o = (unsigned long) pudp - pud_index(addr) * sizeof(pud_t);
r3o = __pa(pudp) - pud_index(addr) * sizeof(pud_t);
r3o |= _ASCE_TYPE_REGION3;
if (__builtin_constant_p(opt) && opt == 0) {
/* flush without guest asce */

View File

@ -76,8 +76,7 @@ enum {
* The pt_regs struct defines the way the registers are stored on
* the stack during a system call.
*/
struct pt_regs
{
struct pt_regs {
union {
user_pt_regs user_regs;
struct {
@ -97,6 +96,7 @@ struct pt_regs
};
unsigned long flags;
unsigned long cr1;
unsigned long last_break;
};
/*
@ -197,6 +197,25 @@ const char *regs_query_register_name(unsigned int offset);
unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset);
unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n);
/**
* regs_get_kernel_argument() - get Nth function argument in kernel
* @regs: pt_regs of that context
* @n: function argument number (start from 0)
*
* regs_get_kernel_argument() returns @n th argument of the function call.
*/
static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
unsigned int n)
{
unsigned int argoffset = STACK_FRAME_OVERHEAD / sizeof(long);
#define NR_REG_ARGUMENTS 5
if (n < NR_REG_ARGUMENTS)
return regs_get_register(regs, 2 + n);
n -= NR_REG_ARGUMENTS;
return regs_get_kernel_stack_nth(regs, argoffset + n);
}
static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
{
return regs->gprs[15];

View File

@ -117,6 +117,7 @@ struct zpci_report_error_header {
extern char *sclp_early_sccb;
void sclp_early_adjust_va(void);
void sclp_early_set_buffer(void *sccb);
int sclp_early_read_info(void);
int sclp_early_read_storage_info(void);

View File

@ -11,8 +11,8 @@
#include <linux/build_bug.h>
#define PARMAREA 0x10400
#define HEAD_END 0x11000
#define COMMAND_LINE_SIZE CONFIG_COMMAND_LINE_SIZE
/*
* Machine features detected in early.c
*/
@ -43,6 +43,8 @@
#define STARTUP_NORMAL_OFFSET 0x10000
#define STARTUP_KDUMP_OFFSET 0x10010
#define LEGACY_COMMAND_LINE_SIZE 896
#ifndef __ASSEMBLY__
#include <asm/lowcore.h>
@ -55,8 +57,9 @@ struct parmarea {
unsigned long oldmem_base; /* 0x10418 */
unsigned long oldmem_size; /* 0x10420 */
unsigned long kernel_version; /* 0x10428 */
char pad1[0x10480 - 0x10430]; /* 0x10430 - 0x10480 */
char command_line[ARCH_COMMAND_LINE_SIZE]; /* 0x10480 */
unsigned long max_command_line_size; /* 0x10430 */
char pad1[0x10480-0x10438]; /* 0x10438 - 0x10480 */
char command_line[COMMAND_LINE_SIZE]; /* 0x10480 */
};
extern struct parmarea parmarea;

View File

@ -31,22 +31,18 @@ void *memmove(void *dest, const void *src, size_t n);
#define __HAVE_ARCH_STRCMP /* arch function */
#define __HAVE_ARCH_STRCPY /* inline & arch function */
#define __HAVE_ARCH_STRLCAT /* arch function */
#define __HAVE_ARCH_STRLCPY /* arch function */
#define __HAVE_ARCH_STRLEN /* inline & arch function */
#define __HAVE_ARCH_STRNCAT /* arch function */
#define __HAVE_ARCH_STRNCPY /* arch function */
#define __HAVE_ARCH_STRNLEN /* inline & arch function */
#define __HAVE_ARCH_STRRCHR /* arch function */
#define __HAVE_ARCH_STRSTR /* arch function */
/* Prototypes for non-inlined arch strings functions. */
int memcmp(const void *s1, const void *s2, size_t n);
int strcmp(const char *s1, const char *s2);
size_t strlcat(char *dest, const char *src, size_t n);
size_t strlcpy(char *dest, const char *src, size_t size);
char *strncat(char *dest, const char *src, size_t n);
char *strncpy(char *dest, const char *src, size_t n);
char *strrchr(const char *s, int c);
char *strstr(const char *s1, const char *s2);
#endif /* !CONFIG_KASAN */

View File

@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_TEXT_PATCHING_H
#define _ASM_S390_TEXT_PATCHING_H
#include <asm/barrier.h>
static __always_inline void sync_core(void)
{
bcr_serialize();
}
void text_poke_sync(void);
void text_poke_sync_lock(void);
#endif /* _ASM_S390_TEXT_PATCHING_H */

View File

@ -1,14 +1 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* S390 version
* Copyright IBM Corp. 1999, 2010
*/
#ifndef _UAPI_ASM_S390_SETUP_H
#define _UAPI_ASM_S390_SETUP_H
#define COMMAND_LINE_SIZE 4096
#define ARCH_COMMAND_LINE_SIZE 896
#endif /* _UAPI_ASM_S390_SETUP_H */

View File

@ -1,5 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/module.h>
#include <linux/cpu.h>
#include <linux/smp.h>
#include <asm/text-patching.h>
#include <asm/alternative.h>
#include <asm/facility.h>
#include <asm/nospec-branch.h>
@ -110,3 +113,20 @@ void __init apply_alternative_instructions(void)
{
apply_alternatives(__alt_instructions, __alt_instructions_end);
}
static void do_sync_core(void *info)
{
sync_core();
}
void text_poke_sync(void)
{
on_each_cpu(do_sync_core, NULL, 1);
}
void text_poke_sync_lock(void)
{
cpus_read_lock();
text_poke_sync();
cpus_read_unlock();
}

View File

@ -35,6 +35,7 @@ int main(void)
OFFSET(__PT_ORIG_GPR2, pt_regs, orig_gpr2);
OFFSET(__PT_FLAGS, pt_regs, flags);
OFFSET(__PT_CR1, pt_regs, cr1);
OFFSET(__PT_LAST_BREAK, pt_regs, last_break);
DEFINE(__PT_SIZE, sizeof(struct pt_regs));
BLANK();
/* stack_frame offsets */
@ -45,6 +46,7 @@ int main(void)
OFFSET(__SF_SIE_SAVEAREA, stack_frame, empty1[2]);
OFFSET(__SF_SIE_REASON, stack_frame, empty1[3]);
OFFSET(__SF_SIE_FLAGS, stack_frame, empty1[4]);
DEFINE(STACK_FRAME_OVERHEAD, sizeof(struct stack_frame));
BLANK();
/* idle data offsets */
OFFSET(__CLOCK_IDLE_ENTER, s390_idle_data, clock_idle_enter);
@ -77,7 +79,7 @@ int main(void)
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);
OFFSET(__LC_LAST_BREAK, lowcore, breaking_event_addr);
OFFSET(__LC_PGM_LAST_BREAK, lowcore, pgm_last_break);
OFFSET(__LC_RETURN_LPSWE, lowcore, return_lpswe);
OFFSET(__LC_RETURN_MCCK_LPSWE, lowcore, return_mcck_lpswe);
OFFSET(__LC_RST_OLD_PSW, lowcore, restart_old_psw);
@ -126,6 +128,7 @@ int main(void)
OFFSET(__LC_PREEMPT_COUNT, lowcore, preempt_count);
OFFSET(__LC_GMAP, lowcore, gmap);
OFFSET(__LC_BR_R1, lowcore, br_r1_trampoline);
OFFSET(__LC_LAST_BREAK, lowcore, last_break);
/* software defined ABI-relevant lowcore locations 0xe00 - 0xe20 */
OFFSET(__LC_DUMP_REIPL, lowcore, ipib);
/* hardware defined lowcore locations 0x1000 - 0x18ff */
@ -139,6 +142,7 @@ int main(void)
OFFSET(__LC_TOD_PROGREG_SAVE_AREA, lowcore, tod_progreg_save_area);
OFFSET(__LC_CPU_TIMER_SAVE_AREA, lowcore, cpu_timer_save_area);
OFFSET(__LC_CLOCK_COMP_SAVE_AREA, lowcore, clock_comp_save_area);
OFFSET(__LC_LAST_BREAK_SAVE_AREA, lowcore, last_break_save_area);
OFFSET(__LC_AREGS_SAVE_AREA, lowcore, access_regs_save_area);
OFFSET(__LC_CREGS_SAVE_AREA, lowcore, cregs_save_area);
OFFSET(__LC_PGM_TDB, lowcore, pgm_tdb);
@ -160,5 +164,6 @@ int main(void)
DEFINE(OLDMEM_BASE, PARMAREA + offsetof(struct parmarea, oldmem_base));
DEFINE(OLDMEM_SIZE, PARMAREA + offsetof(struct parmarea, oldmem_size));
DEFINE(COMMAND_LINE, PARMAREA + offsetof(struct parmarea, command_line));
DEFINE(MAX_COMMAND_LINE_SIZE, PARMAREA + offsetof(struct parmarea, max_command_line_size));
return 0;
}

View File

@ -29,7 +29,7 @@ static int diag8_noresponse(int cmdlen)
asm volatile(
" diag %[rx],%[ry],0x8\n"
: [ry] "+&d" (cmdlen)
: [rx] "d" ((addr_t) cpcmd_buf)
: [rx] "d" (__pa(cpcmd_buf))
: "cc");
return cmdlen;
}
@ -39,8 +39,8 @@ static int diag8_response(int cmdlen, char *response, int *rlen)
union register_pair rx, ry;
int cc;
rx.even = (addr_t) cpcmd_buf;
rx.odd = (addr_t) response;
rx.even = __pa(cpcmd_buf);
rx.odd = __pa(response);
ry.even = cmdlen | 0x40000000L;
ry.odd = *rlen;
asm volatile(

View File

@ -152,7 +152,7 @@ void show_stack(struct task_struct *task, unsigned long *stack,
static void show_last_breaking_event(struct pt_regs *regs)
{
printk("Last Breaking-Event-Address:\n");
printk(" [<%016lx>] %pSR\n", regs->args[0], (void *)regs->args[0]);
printk(" [<%016lx>] %pSR\n", regs->last_break, (void *)regs->last_break);
}
void show_registers(struct pt_regs *regs)

View File

@ -280,7 +280,7 @@ char __bootdata(early_command_line)[COMMAND_LINE_SIZE];
static void __init setup_boot_command_line(void)
{
/* copy arch command line */
strlcpy(boot_command_line, early_command_line, ARCH_COMMAND_LINE_SIZE);
strlcpy(boot_command_line, early_command_line, COMMAND_LINE_SIZE);
}
static void __init check_image_bootable(void)
@ -296,6 +296,7 @@ static void __init check_image_bootable(void)
void __init startup_init(void)
{
sclp_early_adjust_va();
reset_tod_clock();
check_image_bootable();
time_early_init();

View File

@ -52,6 +52,22 @@ STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE
_LPP_OFFSET = __LC_LPP
.macro STBEAR address
ALTERNATIVE "", ".insn s,0xb2010000,\address", 193
.endm
.macro LBEAR address
ALTERNATIVE "", ".insn s,0xb2000000,\address", 193
.endm
.macro LPSWEY address,lpswe
ALTERNATIVE "b \lpswe", ".insn siy,0xeb0000000071,\address,0", 193
.endm
.macro MBEAR reg
ALTERNATIVE "", __stringify(mvc __PT_LAST_BREAK(8,\reg),__LC_LAST_BREAK), 193
.endm
.macro CHECK_STACK savearea
#ifdef CONFIG_CHECK_STACK
tml %r15,STACK_SIZE - CONFIG_STACK_GUARD
@ -302,6 +318,7 @@ ENTRY(system_call)
BPOFF
lghi %r14,0
.Lsysc_per:
STBEAR __LC_LAST_BREAK
lctlg %c1,%c1,__LC_KERNEL_ASCE
lg %r12,__LC_CURRENT
lg %r15,__LC_KERNEL_STACK
@ -321,14 +338,16 @@ ENTRY(system_call)
xgr %r11,%r11
la %r2,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs
mvc __PT_R8(64,%r2),__LC_SAVE_AREA_SYNC
MBEAR %r2
lgr %r3,%r14
brasl %r14,__do_syscall
lctlg %c1,%c1,__LC_USER_ASCE
mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15)
BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP
LBEAR STACK_FRAME_OVERHEAD+__PT_LAST_BREAK(%r15)
lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15)
stpt __LC_EXIT_TIMER
b __LC_RETURN_LPSWE
LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE
ENDPROC(system_call)
#
@ -340,9 +359,10 @@ ENTRY(ret_from_fork)
lctlg %c1,%c1,__LC_USER_ASCE
mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15)
BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP
LBEAR STACK_FRAME_OVERHEAD+__PT_LAST_BREAK(%r15)
lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15)
stpt __LC_EXIT_TIMER
b __LC_RETURN_LPSWE
LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE
ENDPROC(ret_from_fork)
/*
@ -382,6 +402,7 @@ ENTRY(pgm_check_handler)
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
stmg %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
mvc __PT_LAST_BREAK(8,%r11),__LC_PGM_LAST_BREAK
stmg %r8,%r9,__PT_PSW(%r11)
# clear user controlled registers to prevent speculative use
@ -401,8 +422,9 @@ ENTRY(pgm_check_handler)
stpt __LC_EXIT_TIMER
.Lpgm_exit_kernel:
mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15)
LBEAR STACK_FRAME_OVERHEAD+__PT_LAST_BREAK(%r15)
lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15)
b __LC_RETURN_LPSWE
LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE
#
# single stepped system call
@ -412,7 +434,8 @@ ENTRY(pgm_check_handler)
larl %r14,.Lsysc_per
stg %r14,__LC_RETURN_PSW+8
lghi %r14,1
lpswe __LC_RETURN_PSW # branch to .Lsysc_per
LBEAR __LC_PGM_LAST_BREAK
LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE # branch to .Lsysc_per
ENDPROC(pgm_check_handler)
/*
@ -422,6 +445,7 @@ ENDPROC(pgm_check_handler)
ENTRY(\name)
STCK __LC_INT_CLOCK
stpt __LC_SYS_ENTER_TIMER
STBEAR __LC_LAST_BREAK
BPOFF
stmg %r8,%r15,__LC_SAVE_AREA_ASYNC
lg %r12,__LC_CURRENT
@ -453,6 +477,7 @@ ENTRY(\name)
xgr %r10,%r10
xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
MBEAR %r11
stmg %r8,%r9,__PT_PSW(%r11)
tm %r8,0x0001 # coming from user space?
jno 1f
@ -465,8 +490,9 @@ ENTRY(\name)
lctlg %c1,%c1,__LC_USER_ASCE
BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP
stpt __LC_EXIT_TIMER
2: lmg %r0,%r15,__PT_R0(%r11)
b __LC_RETURN_LPSWE
2: LBEAR __PT_LAST_BREAK(%r11)
lmg %r0,%r15,__PT_R0(%r11)
LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE
ENDPROC(\name)
.endm
@ -505,6 +531,7 @@ ENTRY(mcck_int_handler)
BPOFF
la %r1,4095 # validate r1
spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # validate cpu timer
LBEAR __LC_LAST_BREAK_SAVE_AREA-4095(%r1) # validate bear
lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# validate gprs
lg %r12,__LC_CURRENT
lmg %r8,%r9,__LC_MCK_OLD_PSW
@ -591,8 +618,10 @@ ENTRY(mcck_int_handler)
jno 0f
BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP
stpt __LC_EXIT_TIMER
0: lmg %r11,%r15,__PT_R11(%r11)
b __LC_RETURN_MCCK_LPSWE
0: ALTERNATIVE "", __stringify(lghi %r12,__LC_LAST_BREAK_SAVE_AREA),193
LBEAR 0(%r12)
lmg %r11,%r15,__PT_R11(%r11)
LPSWEY __LC_RETURN_MCCK_PSW,__LC_RETURN_MCCK_LPSWE
.Lmcck_panic:
/*

View File

@ -70,5 +70,6 @@ extern struct exception_table_entry _stop_amode31_ex_table[];
#define __amode31_data __section(".amode31.data")
#define __amode31_ref __section(".amode31.refs")
extern long _start_amode31_refs[], _end_amode31_refs[];
extern unsigned long __amode31_base;
#endif /* _ENTRY_H */

View File

@ -17,6 +17,7 @@
#include <linux/kprobes.h>
#include <trace/syscall.h>
#include <asm/asm-offsets.h>
#include <asm/text-patching.h>
#include <asm/cacheflush.h>
#include <asm/ftrace.lds.h>
#include <asm/nospec-branch.h>
@ -80,17 +81,6 @@ asm(
#ifdef CONFIG_MODULES
static char *ftrace_plt;
asm(
" .data\n"
"ftrace_plt_template:\n"
" basr %r1,%r0\n"
" lg %r1,0f-.(%r1)\n"
" br %r1\n"
"0: .quad ftrace_caller\n"
"ftrace_plt_template_end:\n"
" .previous\n"
);
#endif /* CONFIG_MODULES */
static const char *ftrace_shared_hotpatch_trampoline(const char **end)
@ -116,7 +106,7 @@ static const char *ftrace_shared_hotpatch_trampoline(const char **end)
bool ftrace_need_init_nop(void)
{
return ftrace_shared_hotpatch_trampoline(NULL);
return true;
}
int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
@ -175,28 +165,6 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
return 0;
}
static void ftrace_generate_nop_insn(struct ftrace_insn *insn)
{
/* brcl 0,0 */
insn->opc = 0xc004;
insn->disp = 0;
}
static void ftrace_generate_call_insn(struct ftrace_insn *insn,
unsigned long ip)
{
unsigned long target;
/* brasl r0,ftrace_caller */
target = FTRACE_ADDR;
#ifdef CONFIG_MODULES
if (is_module_addr((void *)ip))
target = (unsigned long)ftrace_plt;
#endif /* CONFIG_MODULES */
insn->opc = 0xc005;
insn->disp = (target - ip) / 2;
}
static void brcl_disable(void *brcl)
{
u8 op = 0x04; /* set mask field to zero */
@ -207,23 +175,7 @@ static void brcl_disable(void *brcl)
int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
unsigned long addr)
{
struct ftrace_insn orig, new, old;
if (ftrace_shared_hotpatch_trampoline(NULL)) {
brcl_disable((void *)rec->ip);
return 0;
}
if (copy_from_kernel_nofault(&old, (void *) rec->ip, sizeof(old)))
return -EFAULT;
/* Replace ftrace call with a nop. */
ftrace_generate_call_insn(&orig, rec->ip);
ftrace_generate_nop_insn(&new);
/* Verify that the to be replaced code matches what we expect. */
if (memcmp(&orig, &old, sizeof(old)))
return -EINVAL;
s390_kernel_write((void *) rec->ip, &new, sizeof(new));
brcl_disable((void *)rec->ip);
return 0;
}
@ -236,23 +188,7 @@ static void brcl_enable(void *brcl)
int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
{
struct ftrace_insn orig, new, old;
if (ftrace_shared_hotpatch_trampoline(NULL)) {
brcl_enable((void *)rec->ip);
return 0;
}
if (copy_from_kernel_nofault(&old, (void *) rec->ip, sizeof(old)))
return -EFAULT;
/* Replace nop with an ftrace call. */
ftrace_generate_nop_insn(&orig);
ftrace_generate_call_insn(&new, rec->ip);
/* Verify that the to be replaced code matches what we expect. */
if (memcmp(&orig, &old, sizeof(old)))
return -EINVAL;
s390_kernel_write((void *) rec->ip, &new, sizeof(new));
brcl_enable((void *)rec->ip);
return 0;
}
@ -264,22 +200,16 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
void arch_ftrace_update_code(int command)
{
if (ftrace_shared_hotpatch_trampoline(NULL))
ftrace_modify_all_code(command);
else
ftrace_run_stop_machine(command);
}
static void __ftrace_sync(void *dummy)
{
ftrace_modify_all_code(command);
}
int ftrace_arch_code_modify_post_process(void)
{
if (ftrace_shared_hotpatch_trampoline(NULL)) {
/* Send SIGP to the other CPUs, so they see the new code. */
smp_call_function(__ftrace_sync, NULL, 1);
}
/*
* Flush any pre-fetched instructions on all
* CPUs to make the new code visible.
*/
text_poke_sync_lock();
return 0;
}
@ -294,10 +224,6 @@ static int __init ftrace_plt_init(void)
panic("cannot allocate ftrace plt\n");
start = ftrace_shared_hotpatch_trampoline(&end);
if (!start) {
start = ftrace_plt_template;
end = ftrace_plt_template_end;
}
memcpy(ftrace_plt, start, end - start);
set_memory_ro((unsigned long)ftrace_plt, 1);
return 0;
@ -337,12 +263,14 @@ NOKPROBE_SYMBOL(prepare_ftrace_return);
int ftrace_enable_ftrace_graph_caller(void)
{
brcl_disable(ftrace_graph_caller);
text_poke_sync_lock();
return 0;
}
int ftrace_disable_ftrace_graph_caller(void)
{
brcl_enable(ftrace_graph_caller);
text_poke_sync_lock();
return 0;
}

View File

@ -20,8 +20,6 @@ __HEAD
ENTRY(startup_continue)
larl %r1,tod_clock_base
mvc 0(16,%r1),__LC_BOOT_CLOCK
larl %r13,.LPG1 # get base
lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
#
# Setup stack
#
@ -42,19 +40,3 @@ ENTRY(startup_continue)
.align 16
.LPG1:
.Ldw: .quad 0x0002000180000000,0x0000000000000000
.Lctl: .quad 0x04040000 # cr0: AFP registers & secondary space
.quad 0 # cr1: primary space segment table
.quad 0 # cr2: dispatchable unit control table
.quad 0 # cr3: instruction authorization
.quad 0xffff # cr4: instruction authorization
.quad 0 # cr5: primary-aste origin
.quad 0 # cr6: I/O interrupts
.quad 0 # cr7: secondary space segment table
.quad 0x0000000000008000 # cr8: access registers translation
.quad 0 # cr9: tracing off
.quad 0 # cr10: tracing off
.quad 0 # cr11: tracing off
.quad 0 # cr12: tracing off
.quad 0 # cr13: home space segment table
.quad 0xc0000000 # cr14: machine check handling off
.quad 0 # cr15: linkage stack operations

View File

@ -140,8 +140,11 @@ void noinstr do_io_irq(struct pt_regs *regs)
irq_enter();
if (user_mode(regs))
if (user_mode(regs)) {
update_timer_sys();
if (static_branch_likely(&cpu_has_bear))
current->thread.last_break = regs->last_break;
}
from_idle = !user_mode(regs) && regs->psw.addr == (unsigned long)psw_idle_exit;
if (from_idle)
@ -171,8 +174,11 @@ void noinstr do_ext_irq(struct pt_regs *regs)
irq_enter();
if (user_mode(regs))
if (user_mode(regs)) {
update_timer_sys();
if (static_branch_likely(&cpu_has_bear))
current->thread.last_break = regs->last_break;
}
regs->int_code = S390_lowcore.ext_int_code_addr;
regs->int_parm = S390_lowcore.ext_params;

View File

@ -6,8 +6,9 @@
* Author(s): Jan Glauber <jang@linux.vnet.ibm.com>
*/
#include <linux/uaccess.h>
#include <linux/stop_machine.h>
#include <linux/jump_label.h>
#include <linux/module.h>
#include <asm/text-patching.h>
#include <asm/ipl.h>
struct insn {
@ -48,9 +49,9 @@ static struct insn orignop = {
.offset = JUMP_LABEL_NOP_OFFSET >> 1,
};
static void __jump_label_transform(struct jump_entry *entry,
enum jump_label_type type,
int init)
static void jump_label_transform(struct jump_entry *entry,
enum jump_label_type type,
int init)
{
void *code = (void *)jump_entry_code(entry);
struct insn old, new;
@ -72,19 +73,28 @@ static void __jump_label_transform(struct jump_entry *entry,
s390_kernel_write(code, &new, sizeof(new));
}
static void __jump_label_sync(void *dummy)
{
}
void arch_jump_label_transform(struct jump_entry *entry,
enum jump_label_type type)
{
__jump_label_transform(entry, type, 0);
smp_call_function(__jump_label_sync, NULL, 1);
jump_label_transform(entry, type, 0);
text_poke_sync();
}
void arch_jump_label_transform_static(struct jump_entry *entry,
enum jump_label_type type)
bool arch_jump_label_transform_queue(struct jump_entry *entry,
enum jump_label_type type)
{
__jump_label_transform(entry, type, 1);
jump_label_transform(entry, type, 0);
return true;
}
void arch_jump_label_transform_apply(void)
{
text_poke_sync();
}
void __init_or_module arch_jump_label_transform_static(struct jump_entry *entry,
enum jump_label_type type)
{
jump_label_transform(entry, type, 1);
text_poke_sync();
}

View File

@ -122,9 +122,55 @@ static void s390_free_insn_slot(struct kprobe *p)
}
NOKPROBE_SYMBOL(s390_free_insn_slot);
/* Check if paddr is at an instruction boundary */
static bool can_probe(unsigned long paddr)
{
unsigned long addr, offset = 0;
kprobe_opcode_t insn;
struct kprobe *kp;
if (paddr & 0x01)
return false;
if (!kallsyms_lookup_size_offset(paddr, NULL, &offset))
return false;
/* Decode instructions */
addr = paddr - offset;
while (addr < paddr) {
if (copy_from_kernel_nofault(&insn, (void *)addr, sizeof(insn)))
return false;
if (insn >> 8 == 0) {
if (insn != BREAKPOINT_INSTRUCTION) {
/*
* Note that QEMU inserts opcode 0x0000 to implement
* software breakpoints for guests. Since the size of
* the original instruction is unknown, stop following
* instructions and prevent setting a kprobe.
*/
return false;
}
/*
* Check if the instruction has been modified by another
* kprobe, in which case the original instruction is
* decoded.
*/
kp = get_kprobe((void *)addr);
if (!kp) {
/* not a kprobe */
return false;
}
insn = kp->opcode;
}
addr += insn_length(insn >> 8);
}
return addr == paddr;
}
int arch_prepare_kprobe(struct kprobe *p)
{
if ((unsigned long) p->addr & 0x01)
if (!can_probe((unsigned long)p->addr))
return -EINVAL;
/* Make sure the probe isn't going on a difficult instruction */
if (probe_is_prohibited_opcode(p->addr))

View File

@ -216,7 +216,9 @@ void *kexec_file_add_components(struct kimage *image,
int (*add_kernel)(struct kimage *image,
struct s390_load_data *data))
{
unsigned long max_command_line_size = LEGACY_COMMAND_LINE_SIZE;
struct s390_load_data data = {0};
unsigned long minsize;
int ret;
data.report = ipl_report_init(&ipl_block);
@ -227,10 +229,23 @@ void *kexec_file_add_components(struct kimage *image,
if (ret)
goto out;
if (image->cmdline_buf_len >= ARCH_COMMAND_LINE_SIZE) {
ret = -EINVAL;
ret = -EINVAL;
minsize = PARMAREA + offsetof(struct parmarea, command_line);
if (image->kernel_buf_len < minsize)
goto out;
}
if (data.parm->max_command_line_size)
max_command_line_size = data.parm->max_command_line_size;
if (minsize + max_command_line_size < minsize)
goto out;
if (image->kernel_buf_len < minsize + max_command_line_size)
goto out;
if (image->cmdline_buf_len >= max_command_line_size)
goto out;
memcpy(data.parm->command_line, image->cmdline_buf,
image->cmdline_buf_len);
@ -307,17 +322,3 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
}
return 0;
}
int arch_kexec_kernel_image_probe(struct kimage *image, void *buf,
unsigned long buf_len)
{
/* A kernel must be at least large enough to contain head.S. During
* load memory in head.S will be accessed, e.g. to register the next
* command line. If the next kernel were smaller the current kernel
* will panic at load.
*/
if (buf_len < HEAD_END)
return -ENOEXEC;
return kexec_image_probe_default(image, buf, buf_len);
}

View File

@ -22,10 +22,11 @@ ENTRY(ftrace_stub)
BR_EX %r14
ENDPROC(ftrace_stub)
#define STACK_FRAME_SIZE (STACK_FRAME_OVERHEAD + __PT_SIZE)
#define STACK_PTREGS (STACK_FRAME_OVERHEAD)
#define STACK_PTREGS_GPRS (STACK_PTREGS + __PT_GPRS)
#define STACK_PTREGS_PSW (STACK_PTREGS + __PT_PSW)
#define STACK_FRAME_SIZE (STACK_FRAME_OVERHEAD + __PT_SIZE)
#define STACK_PTREGS (STACK_FRAME_OVERHEAD)
#define STACK_PTREGS_GPRS (STACK_PTREGS + __PT_GPRS)
#define STACK_PTREGS_PSW (STACK_PTREGS + __PT_PSW)
#define STACK_PTREGS_ORIG_GPR2 (STACK_PTREGS + __PT_ORIG_GPR2)
#ifdef __PACK_STACK
/* allocate just enough for r14, r15 and backchain */
#define TRACED_FUNC_FRAME_SIZE 24
@ -33,13 +34,15 @@ ENDPROC(ftrace_stub)
#define TRACED_FUNC_FRAME_SIZE STACK_FRAME_OVERHEAD
#endif
ENTRY(ftrace_caller)
.globl ftrace_regs_caller
.set ftrace_regs_caller,ftrace_caller
.macro ftrace_regs_entry, allregs=0
stg %r14,(__SF_GPRS+8*8)(%r15) # save traced function caller
.if \allregs == 1
lghi %r14,0 # save condition code
ipm %r14 # don't put any instructions
sllg %r14,%r14,16 # clobbering CC before this point
.endif
lgr %r1,%r15
# allocate stack frame for ftrace_caller to contain traced function
aghi %r15,-TRACED_FUNC_FRAME_SIZE
@ -49,13 +52,31 @@ ENTRY(ftrace_caller)
# allocate pt_regs and stack frame for ftrace_trace_function
aghi %r15,-STACK_FRAME_SIZE
stg %r1,(STACK_PTREGS_GPRS+15*8)(%r15)
xc STACK_PTREGS_ORIG_GPR2(8,%r15),STACK_PTREGS_ORIG_GPR2(%r15)
.if \allregs == 1
stg %r14,(STACK_PTREGS_PSW)(%r15)
lg %r14,(__SF_GPRS+8*8)(%r1) # restore original return address
stosm (STACK_PTREGS_PSW)(%r15),0
.endif
lg %r14,(__SF_GPRS+8*8)(%r1) # restore original return address
aghi %r1,-TRACED_FUNC_FRAME_SIZE
stg %r1,__SF_BACKCHAIN(%r15)
stg %r0,(STACK_PTREGS_PSW+8)(%r15)
stmg %r2,%r14,(STACK_PTREGS_GPRS+2*8)(%r15)
.endm
SYM_CODE_START(ftrace_regs_caller)
ftrace_regs_entry 1
j ftrace_common
SYM_CODE_END(ftrace_regs_caller)
SYM_CODE_START(ftrace_caller)
ftrace_regs_entry 0
j ftrace_common
SYM_CODE_END(ftrace_caller)
SYM_CODE_START(ftrace_common)
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
aghik %r2,%r0,-MCOUNT_INSN_SIZE
lgrl %r4,function_trace_op
@ -74,24 +95,31 @@ ENTRY(ftrace_caller)
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
# The j instruction gets runtime patched to a nop instruction.
# See ftrace_enable_ftrace_graph_caller.
.globl ftrace_graph_caller
ftrace_graph_caller:
j ftrace_graph_caller_end
SYM_INNER_LABEL(ftrace_graph_caller, SYM_L_GLOBAL)
j .Lftrace_graph_caller_end
lmg %r2,%r3,(STACK_PTREGS_GPRS+14*8)(%r15)
lg %r4,(STACK_PTREGS_PSW+8)(%r15)
brasl %r14,prepare_ftrace_return
stg %r2,(STACK_PTREGS_GPRS+14*8)(%r15)
ftrace_graph_caller_end:
.globl ftrace_graph_caller_end
.Lftrace_graph_caller_end:
#endif
lg %r1,(STACK_PTREGS_PSW+8)(%r15)
lmg %r2,%r15,(STACK_PTREGS_GPRS+2*8)(%r15)
lg %r0,(STACK_PTREGS_PSW+8)(%r15)
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
ltg %r1,STACK_PTREGS_ORIG_GPR2(%r15)
locgrz %r1,%r0
#else
lg %r1,STACK_PTREGS_ORIG_GPR2(%r15)
ltgr %r1,%r1
jnz 0f
lgr %r1,%r0
#endif
0: lmg %r2,%r15,(STACK_PTREGS_GPRS+2*8)(%r15)
BR_EX %r1
ENDPROC(ftrace_caller)
SYM_CODE_END(ftrace_common)
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
ENTRY(return_to_handler)
SYM_FUNC_START(return_to_handler)
stmg %r2,%r5,32(%r15)
lgr %r1,%r15
aghi %r15,-STACK_FRAME_OVERHEAD
@ -101,6 +129,6 @@ ENTRY(return_to_handler)
lgr %r14,%r2
lmg %r2,%r5,32(%r15)
BR_EX %r14
ENDPROC(return_to_handler)
SYM_FUNC_END(return_to_handler)
#endif

View File

@ -38,7 +38,7 @@ static int __init nospec_report(void)
{
if (test_facility(156))
pr_info("Spectre V2 mitigation: etokens\n");
if (__is_defined(CC_USING_EXPOLINE) && !nospec_disable)
if (nospec_uses_trampoline())
pr_info("Spectre V2 mitigation: execute trampolines\n");
if (__test_facility(82, alt_stfle_fac_list))
pr_info("Spectre V2 mitigation: limited branch prediction\n");

View File

@ -15,7 +15,7 @@ ssize_t cpu_show_spectre_v2(struct device *dev,
{
if (test_facility(156))
return sprintf(buf, "Mitigation: etokens\n");
if (__is_defined(CC_USING_EXPOLINE) && !nospec_disable)
if (nospec_uses_trampoline())
return sprintf(buf, "Mitigation: execute trampolines\n");
if (__test_facility(82, alt_stfle_fac_list))
return sprintf(buf, "Mitigation: limited branch prediction\n");

View File

@ -773,22 +773,46 @@ static int __init cpumf_pmu_init(void)
* counter set via normal file operations.
*/
static atomic_t cfset_opencnt = ATOMIC_INIT(0); /* Excl. access */
static atomic_t cfset_opencnt = ATOMIC_INIT(0); /* Access count */
static DEFINE_MUTEX(cfset_ctrset_mutex);/* Synchronize access to hardware */
struct cfset_call_on_cpu_parm { /* Parm struct for smp_call_on_cpu */
unsigned int sets; /* Counter set bit mask */
atomic_t cpus_ack; /* # CPUs successfully executed func */
};
static struct cfset_request { /* CPUs and counter set bit mask */
static struct cfset_session { /* CPUs and counter set bit mask */
struct list_head head; /* Head of list of active processes */
} cfset_session = {
.head = LIST_HEAD_INIT(cfset_session.head)
};
struct cfset_request { /* CPUs and counter set bit mask */
unsigned long ctrset; /* Bit mask of counter set to read */
cpumask_t mask; /* CPU mask to read from */
} cfset_request;
struct list_head node; /* Chain to cfset_session.head */
};
static void cfset_ctrset_clear(void)
static void cfset_session_init(void)
{
cpumask_clear(&cfset_request.mask);
cfset_request.ctrset = 0;
INIT_LIST_HEAD(&cfset_session.head);
}
/* Remove current request from global bookkeeping. Maintain a counter set bit
* mask on a per CPU basis.
* Done in process context under mutex protection.
*/
static void cfset_session_del(struct cfset_request *p)
{
list_del(&p->node);
}
/* Add current request to global bookkeeping. Maintain a counter set bit mask
* on a per CPU basis.
* Done in process context under mutex protection.
*/
static void cfset_session_add(struct cfset_request *p)
{
list_add(&p->node, &cfset_session.head);
}
/* The /dev/hwctr device access uses PMU_F_IN_USE to mark the device access
@ -827,15 +851,23 @@ static void cfset_ioctl_off(void *parm)
struct cfset_call_on_cpu_parm *p = parm;
int rc;
cpuhw->dev_state = 0;
/* Check if any counter set used by /dev/hwc */
for (rc = CPUMF_CTR_SET_BASIC; rc < CPUMF_CTR_SET_MAX; ++rc)
if ((p->sets & cpumf_ctr_ctl[rc]))
atomic_dec(&cpuhw->ctr_set[rc]);
rc = lcctl(cpuhw->state); /* Keep perf_event_open counter sets */
if ((p->sets & cpumf_ctr_ctl[rc])) {
if (!atomic_dec_return(&cpuhw->ctr_set[rc])) {
ctr_set_disable(&cpuhw->dev_state,
cpumf_ctr_ctl[rc]);
ctr_set_stop(&cpuhw->dev_state,
cpumf_ctr_ctl[rc]);
}
}
/* Keep perf_event_open counter sets */
rc = lcctl(cpuhw->dev_state | cpuhw->state);
if (rc)
pr_err("Counter set stop %#llx of /dev/%s failed rc=%i\n",
cpuhw->state, S390_HWCTR_DEVICE, rc);
cpuhw->flags &= ~PMU_F_IN_USE;
if (!cpuhw->dev_state)
cpuhw->flags &= ~PMU_F_IN_USE;
debug_sprintf_event(cf_dbg, 4, "%s rc %d state %#llx dev_state %#llx\n",
__func__, rc, cpuhw->state, cpuhw->dev_state);
}
@ -870,11 +902,26 @@ static void cfset_release_cpu(void *p)
debug_sprintf_event(cf_dbg, 4, "%s state %#llx dev_state %#llx\n",
__func__, cpuhw->state, cpuhw->dev_state);
cpuhw->dev_state = 0;
rc = lcctl(cpuhw->state); /* Keep perf_event_open counter sets */
if (rc)
pr_err("Counter set release %#llx of /dev/%s failed rc=%i\n",
cpuhw->state, S390_HWCTR_DEVICE, rc);
cpuhw->dev_state = 0;
}
/* This modifies the process CPU mask to adopt it to the currently online
* CPUs. Offline CPUs can not be addresses. This call terminates the access
* and is usually followed by close() or a new iotcl(..., START, ...) which
* creates a new request structure.
*/
static void cfset_all_stop(struct cfset_request *req)
{
struct cfset_call_on_cpu_parm p = {
.sets = req->ctrset,
};
cpumask_and(&req->mask, &req->mask, cpu_online_mask);
on_each_cpu_mask(&req->mask, cfset_ioctl_off, &p, 1);
}
/* Release function is also called when application gets terminated without
@ -882,10 +929,19 @@ static void cfset_release_cpu(void *p)
*/
static int cfset_release(struct inode *inode, struct file *file)
{
on_each_cpu(cfset_release_cpu, NULL, 1);
mutex_lock(&cfset_ctrset_mutex);
/* Open followed by close/exit has no private_data */
if (file->private_data) {
cfset_all_stop(file->private_data);
cfset_session_del(file->private_data);
kfree(file->private_data);
file->private_data = NULL;
}
if (!atomic_dec_return(&cfset_opencnt))
on_each_cpu(cfset_release_cpu, NULL, 1);
mutex_unlock(&cfset_ctrset_mutex);
hw_perf_event_destroy(NULL);
cfset_ctrset_clear();
atomic_set(&cfset_opencnt, 0);
return 0;
}
@ -893,9 +949,10 @@ static int cfset_open(struct inode *inode, struct file *file)
{
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
/* Only one user space program can open /dev/hwctr */
if (atomic_xchg(&cfset_opencnt, 1))
return -EBUSY;
mutex_lock(&cfset_ctrset_mutex);
if (atomic_inc_return(&cfset_opencnt) == 1)
cfset_session_init();
mutex_unlock(&cfset_ctrset_mutex);
cpumf_hw_inuse();
file->private_data = NULL;
@ -903,25 +960,10 @@ static int cfset_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
}
static int cfset_all_stop(void)
static int cfset_all_start(struct cfset_request *req)
{
struct cfset_call_on_cpu_parm p = {
.sets = cfset_request.ctrset,
};
cpumask_var_t mask;
if (!alloc_cpumask_var(&mask, GFP_KERNEL))
return -ENOMEM;
cpumask_and(mask, &cfset_request.mask, cpu_online_mask);
on_each_cpu_mask(mask, cfset_ioctl_off, &p, 1);
free_cpumask_var(mask);
return 0;
}
static int cfset_all_start(void)
{
struct cfset_call_on_cpu_parm p = {
.sets = cfset_request.ctrset,
.sets = req->ctrset,
.cpus_ack = ATOMIC_INIT(0),
};
cpumask_var_t mask;
@ -929,7 +971,7 @@ static int cfset_all_start(void)
if (!alloc_cpumask_var(&mask, GFP_KERNEL))
return -ENOMEM;
cpumask_and(mask, &cfset_request.mask, cpu_online_mask);
cpumask_and(mask, &req->mask, cpu_online_mask);
on_each_cpu_mask(mask, cfset_ioctl_on, &p, 1);
if (atomic_read(&p.cpus_ack) != cpumask_weight(mask)) {
on_each_cpu_mask(mask, cfset_ioctl_off, &p, 1);
@ -1045,7 +1087,7 @@ static void cfset_cpu_read(void *parm)
cpuhw->sets, cpuhw->used);
}
static int cfset_all_read(unsigned long arg)
static int cfset_all_read(unsigned long arg, struct cfset_request *req)
{
struct cfset_call_on_cpu_parm p;
cpumask_var_t mask;
@ -1054,46 +1096,53 @@ static int cfset_all_read(unsigned long arg)
if (!alloc_cpumask_var(&mask, GFP_KERNEL))
return -ENOMEM;
p.sets = cfset_request.ctrset;
cpumask_and(mask, &cfset_request.mask, cpu_online_mask);
p.sets = req->ctrset;
cpumask_and(mask, &req->mask, cpu_online_mask);
on_each_cpu_mask(mask, cfset_cpu_read, &p, 1);
rc = cfset_all_copy(arg, mask);
free_cpumask_var(mask);
return rc;
}
static long cfset_ioctl_read(unsigned long arg)
static long cfset_ioctl_read(unsigned long arg, struct cfset_request *req)
{
struct s390_ctrset_read read;
int ret = 0;
int ret = -ENODATA;
if (copy_from_user(&read, (char __user *)arg, sizeof(read)))
return -EFAULT;
ret = cfset_all_read(arg);
return ret;
}
static long cfset_ioctl_stop(void)
{
int ret = ENXIO;
if (cfset_request.ctrset) {
ret = cfset_all_stop();
cfset_ctrset_clear();
if (req && req->ctrset) {
if (copy_from_user(&read, (char __user *)arg, sizeof(read)))
return -EFAULT;
ret = cfset_all_read(arg, req);
}
return ret;
}
static long cfset_ioctl_start(unsigned long arg)
static long cfset_ioctl_stop(struct file *file)
{
struct cfset_request *req = file->private_data;
int ret = -ENXIO;
if (req) {
cfset_all_stop(req);
cfset_session_del(req);
kfree(req);
file->private_data = NULL;
ret = 0;
}
return ret;
}
static long cfset_ioctl_start(unsigned long arg, struct file *file)
{
struct s390_ctrset_start __user *ustart;
struct s390_ctrset_start start;
struct cfset_request *preq;
void __user *umask;
unsigned int len;
int ret = 0;
size_t need;
if (cfset_request.ctrset)
if (file->private_data)
return -EBUSY;
ustart = (struct s390_ctrset_start __user *)arg;
if (copy_from_user(&start, ustart, sizeof(start)))
@ -1108,25 +1157,36 @@ static long cfset_ioctl_start(unsigned long arg)
return -EINVAL; /* Invalid counter set */
if (!start.counter_sets)
return -EINVAL; /* No counter set at all? */
cpumask_clear(&cfset_request.mask);
preq = kzalloc(sizeof(*preq), GFP_KERNEL);
if (!preq)
return -ENOMEM;
cpumask_clear(&preq->mask);
len = min_t(u64, start.cpumask_len, cpumask_size());
umask = (void __user *)start.cpumask;
if (copy_from_user(&cfset_request.mask, umask, len))
if (copy_from_user(&preq->mask, umask, len)) {
kfree(preq);
return -EFAULT;
if (cpumask_empty(&cfset_request.mask))
}
if (cpumask_empty(&preq->mask)) {
kfree(preq);
return -EINVAL;
}
need = cfset_needspace(start.counter_sets);
if (put_user(need, &ustart->data_bytes))
ret = -EFAULT;
if (ret)
goto out;
cfset_request.ctrset = start.counter_sets;
ret = cfset_all_start();
out:
if (ret)
cfset_ctrset_clear();
debug_sprintf_event(cf_dbg, 4, "%s sets %#lx need %ld ret %d\n",
__func__, cfset_request.ctrset, need, ret);
if (put_user(need, &ustart->data_bytes)) {
kfree(preq);
return -EFAULT;
}
preq->ctrset = start.counter_sets;
ret = cfset_all_start(preq);
if (!ret) {
cfset_session_add(preq);
file->private_data = preq;
debug_sprintf_event(cf_dbg, 4, "%s set %#lx need %ld ret %d\n",
__func__, preq->ctrset, need, ret);
} else {
kfree(preq);
}
return ret;
}
@ -1136,7 +1196,7 @@ out:
* counter set keeps running until explicitly stopped. Returns the number
* of bytes needed to store the counter values. If another S390_HWCTR_START
* ioctl subcommand is called without a previous S390_HWCTR_STOP stop
* command, -EBUSY is returned.
* command on the same file descriptor, -EBUSY is returned.
* S390_HWCTR_READ: Read the counter set values from specified CPU list given
* with the S390_HWCTR_START command.
* S390_HWCTR_STOP: Stops the counter sets on the CPU list given with the
@ -1150,13 +1210,13 @@ static long cfset_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
mutex_lock(&cfset_ctrset_mutex);
switch (cmd) {
case S390_HWCTR_START:
ret = cfset_ioctl_start(arg);
ret = cfset_ioctl_start(arg, file);
break;
case S390_HWCTR_STOP:
ret = cfset_ioctl_stop();
ret = cfset_ioctl_stop(file);
break;
case S390_HWCTR_READ:
ret = cfset_ioctl_read(arg);
ret = cfset_ioctl_read(arg, file->private_data);
break;
default:
ret = -ENOTTY;
@ -1182,29 +1242,41 @@ static struct miscdevice cfset_dev = {
.fops = &cfset_fops,
};
/* Hotplug add of a CPU. Scan through all active processes and add
* that CPU to the list of CPUs supplied with ioctl(..., START, ...).
*/
int cfset_online_cpu(unsigned int cpu)
{
struct cfset_call_on_cpu_parm p;
struct cfset_request *rp;
mutex_lock(&cfset_ctrset_mutex);
if (cfset_request.ctrset) {
p.sets = cfset_request.ctrset;
cfset_ioctl_on(&p);
cpumask_set_cpu(cpu, &cfset_request.mask);
if (!list_empty(&cfset_session.head)) {
list_for_each_entry(rp, &cfset_session.head, node) {
p.sets = rp->ctrset;
cfset_ioctl_on(&p);
cpumask_set_cpu(cpu, &rp->mask);
}
}
mutex_unlock(&cfset_ctrset_mutex);
return 0;
}
/* Hotplug remove of a CPU. Scan through all active processes and clear
* that CPU from the list of CPUs supplied with ioctl(..., START, ...).
*/
int cfset_offline_cpu(unsigned int cpu)
{
struct cfset_call_on_cpu_parm p;
struct cfset_request *rp;
mutex_lock(&cfset_ctrset_mutex);
if (cfset_request.ctrset) {
p.sets = cfset_request.ctrset;
cfset_ioctl_off(&p);
cpumask_clear_cpu(cpu, &cfset_request.mask);
if (!list_empty(&cfset_session.head)) {
list_for_each_entry(rp, &cfset_session.head, node) {
p.sets = rp->ctrset;
cfset_ioctl_off(&p);
cpumask_clear_cpu(cpu, &rp->mask);
}
}
mutex_unlock(&cfset_ctrset_mutex);
return 0;

View File

@ -141,7 +141,7 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
frame->childregs.gprs[10] = arg;
frame->childregs.gprs[11] = (unsigned long)do_exit;
frame->childregs.orig_gpr2 = -1;
frame->childregs.last_break = 1;
return 0;
}
frame->childregs = *current_pt_regs();

View File

@ -95,10 +95,10 @@ EXPORT_SYMBOL(console_irq);
* relocated above 2 GB, because it has to use 31 bit addresses.
* Such code and data is part of the .amode31 section.
*/
unsigned long __amode31_ref __samode31 = __pa(&_samode31);
unsigned long __amode31_ref __eamode31 = __pa(&_eamode31);
unsigned long __amode31_ref __stext_amode31 = __pa(&_stext_amode31);
unsigned long __amode31_ref __etext_amode31 = __pa(&_etext_amode31);
unsigned long __amode31_ref __samode31 = (unsigned long)&_samode31;
unsigned long __amode31_ref __eamode31 = (unsigned long)&_eamode31;
unsigned long __amode31_ref __stext_amode31 = (unsigned long)&_stext_amode31;
unsigned long __amode31_ref __etext_amode31 = (unsigned long)&_etext_amode31;
struct exception_table_entry __amode31_ref *__start_amode31_ex_table = _start_amode31_ex_table;
struct exception_table_entry __amode31_ref *__stop_amode31_ex_table = _stop_amode31_ex_table;
@ -149,6 +149,7 @@ struct mem_detect_info __bootdata(mem_detect);
struct initrd_data __bootdata(initrd_data);
unsigned long __bootdata_preserved(__kaslr_offset);
unsigned long __bootdata(__amode31_base);
unsigned int __bootdata_preserved(zlib_dfltcc_support);
EXPORT_SYMBOL(zlib_dfltcc_support);
u64 __bootdata_preserved(stfle_fac_list[16]);
@ -173,6 +174,8 @@ unsigned long MODULES_END;
struct lowcore *lowcore_ptr[NR_CPUS];
EXPORT_SYMBOL(lowcore_ptr);
DEFINE_STATIC_KEY_FALSE(cpu_has_bear);
/*
* The Write Back bit position in the physaddr is given by the SLPC PCI.
* Leaving the mask zero always uses write through which is safe
@ -719,7 +722,7 @@ static void __init reserve_initrd(void)
#ifdef CONFIG_BLK_DEV_INITRD
if (!initrd_data.start || !initrd_data.size)
return;
initrd_start = initrd_data.start;
initrd_start = (unsigned long)__va(initrd_data.start);
initrd_end = initrd_start + initrd_data.size;
memblock_reserve(initrd_data.start, initrd_data.size);
#endif
@ -805,12 +808,10 @@ static void __init check_initrd(void)
*/
static void __init reserve_kernel(void)
{
unsigned long start_pfn = PFN_UP(__pa(_end));
memblock_reserve(0, STARTUP_NORMAL_OFFSET);
memblock_reserve((unsigned long)sclp_early_sccb, EXT_SCCB_READ_SCP);
memblock_reserve((unsigned long)_stext, PFN_PHYS(start_pfn)
- (unsigned long)_stext);
memblock_reserve(__amode31_base, __eamode31 - __samode31);
memblock_reserve(__pa(sclp_early_sccb), EXT_SCCB_READ_SCP);
memblock_reserve(__pa(_stext), _end - _stext);
}
static void __init setup_memory(void)
@ -832,20 +833,14 @@ static void __init setup_memory(void)
static void __init relocate_amode31_section(void)
{
unsigned long amode31_addr, amode31_size;
long amode31_offset;
unsigned long amode31_size = __eamode31 - __samode31;
long amode31_offset = __amode31_base - __samode31;
long *ptr;
/* Allocate a new AMODE31 capable memory region */
amode31_size = __eamode31 - __samode31;
pr_info("Relocating AMODE31 section of size 0x%08lx\n", amode31_size);
amode31_addr = (unsigned long)memblock_alloc_low(amode31_size, PAGE_SIZE);
if (!amode31_addr)
panic("Failed to allocate memory for AMODE31 section\n");
amode31_offset = amode31_addr - __samode31;
/* Move original AMODE31 section to the new one */
memmove((void *)amode31_addr, (void *)__samode31, amode31_size);
memmove((void *)__amode31_base, (void *)__samode31, amode31_size);
/* Zero out the old AMODE31 section to catch invalid accesses within it */
memset((void *)__samode31, 0, amode31_size);
@ -884,14 +879,12 @@ static void __init setup_randomness(void)
{
struct sysinfo_3_2_2 *vmms;
vmms = (struct sysinfo_3_2_2 *) memblock_phys_alloc(PAGE_SIZE,
PAGE_SIZE);
vmms = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
if (!vmms)
panic("Failed to allocate memory for sysinfo structure\n");
if (stsi(vmms, 3, 2, 2) == 0 && vmms->count)
add_device_randomness(&vmms->vm, sizeof(vmms->vm[0]) * vmms->count);
memblock_phys_free((unsigned long)vmms, PAGE_SIZE);
memblock_free(vmms, PAGE_SIZE);
}
/*
@ -1048,6 +1041,9 @@ void __init setup_arch(char **cmdline_p)
smp_detect_cpus();
topology_init_early();
if (test_facility(193))
static_branch_enable(&cpu_has_bear);
/*
* Create kernel page tables and switch to virtual addressing.
*/

View File

@ -154,6 +154,8 @@ void noinstr __do_syscall(struct pt_regs *regs, int per_trap)
regs->psw = S390_lowcore.svc_old_psw;
regs->int_code = S390_lowcore.svc_int_code;
update_timer_sys();
if (static_branch_likely(&cpu_has_bear))
current->thread.last_break = regs->last_break;
local_irq_enable();
regs->orig_gpr2 = regs->gprs[2];

View File

@ -300,7 +300,6 @@ static void (*pgm_check_table[128])(struct pt_regs *regs);
void noinstr __do_pgm_check(struct pt_regs *regs)
{
unsigned long last_break = S390_lowcore.breaking_event_addr;
unsigned int trapnr;
irqentry_state_t state;
@ -311,10 +310,11 @@ void noinstr __do_pgm_check(struct pt_regs *regs)
if (user_mode(regs)) {
update_timer_sys();
if (last_break < 4096)
last_break = 1;
current->thread.last_break = last_break;
regs->args[0] = last_break;
if (!static_branch_likely(&cpu_has_bear)) {
if (regs->last_break < 4096)
regs->last_break = 1;
}
current->thread.last_break = regs->last_break;
}
if (S390_lowcore.pgm_code & 0x0200) {

View File

@ -212,6 +212,7 @@ SECTIONS
QUAD(__dynsym_start) /* dynsym_start */
QUAD(__rela_dyn_start) /* rela_dyn_start */
QUAD(__rela_dyn_end) /* rela_dyn_end */
QUAD(_eamode31 - _samode31) /* amode31_size */
} :NONE
/* Debugging sections. */

View File

@ -960,7 +960,7 @@ static int __must_check __deliver_prog(struct kvm_vcpu *vcpu)
/* bit 1+2 of the target are the ilc, so we can directly use ilen */
rc |= put_guest_lc(vcpu, ilen, (u16 *) __LC_PGM_ILC);
rc |= put_guest_lc(vcpu, vcpu->arch.sie_block->gbea,
(u64 *) __LC_LAST_BREAK);
(u64 *) __LC_PGM_LAST_BREAK);
rc |= put_guest_lc(vcpu, pgm_info.code,
(u16 *)__LC_PGM_INT_CODE);
rc |= write_guest_lc(vcpu, __LC_PGM_OLD_PSW,

View File

@ -7,6 +7,8 @@ lib-y += delay.o string.o uaccess.o find.o spinlock.o
obj-y += mem.o xor.o
lib-$(CONFIG_KPROBES) += probes.o
lib-$(CONFIG_UPROBES) += probes.o
obj-$(CONFIG_S390_KPROBES_SANITY_TEST) += test_kprobes_s390.o
test_kprobes_s390-objs += test_kprobes_asm.o test_kprobes.o
# Instrumenting memory accesses to __user data (in different address space)
# produce false positives

View File

@ -26,7 +26,7 @@ static int __init spin_retry_init(void)
}
early_initcall(spin_retry_init);
/**
/*
* spin_retry= parameter
*/
static int __init spin_retry_setup(char *str)

View File

@ -100,32 +100,6 @@ char *strcpy(char *dest, const char *src)
EXPORT_SYMBOL(strcpy);
#endif
/**
* strlcpy - Copy a %NUL terminated string into a sized buffer
* @dest: Where to copy the string to
* @src: Where to copy the string from
* @size: size of destination buffer
*
* Compatible with *BSD: the result is always a valid
* NUL-terminated string that fits in the buffer (unless,
* of course, the buffer size is zero). It does not pad
* out the result like strncpy() does.
*/
#ifdef __HAVE_ARCH_STRLCPY
size_t strlcpy(char *dest, const char *src, size_t size)
{
size_t ret = __strend(src) - src;
if (size) {
size_t len = (ret >= size) ? size-1 : ret;
dest[len] = '\0';
memcpy(dest, src, len);
}
return ret;
}
EXPORT_SYMBOL(strlcpy);
#endif
/**
* strncpy - Copy a length-limited, %NUL-terminated string
* @dest: Where to copy the string to
@ -254,25 +228,6 @@ int strcmp(const char *s1, const char *s2)
EXPORT_SYMBOL(strcmp);
#endif
/**
* strrchr - Find the last occurrence of a character in a string
* @s: The string to be searched
* @c: The character to search for
*/
#ifdef __HAVE_ARCH_STRRCHR
char *strrchr(const char *s, int c)
{
ssize_t len = __strend(s) - s;
do {
if (s[len] == (char)c)
return (char *)s + len;
} while (--len >= 0);
return NULL;
}
EXPORT_SYMBOL(strrchr);
#endif
static inline int clcle(const char *s1, unsigned long l1,
const char *s2, unsigned long l2)
{

View File

@ -0,0 +1,75 @@
// SPDX-License-Identifier: GPL-2.0+
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/random.h>
#include <kunit/test.h>
#include "test_kprobes.h"
static struct kprobe kp;
static void setup_kprobe(struct kunit *test, struct kprobe *kp,
const char *symbol, int offset)
{
kp->offset = offset;
kp->addr = NULL;
kp->symbol_name = symbol;
}
static void test_kprobe_offset(struct kunit *test, struct kprobe *kp,
const char *target, int offset)
{
int ret;
setup_kprobe(test, kp, target, 0);
ret = register_kprobe(kp);
if (!ret)
unregister_kprobe(kp);
KUNIT_EXPECT_EQ(test, 0, ret);
setup_kprobe(test, kp, target, offset);
ret = register_kprobe(kp);
KUNIT_EXPECT_EQ(test, -EINVAL, ret);
if (!ret)
unregister_kprobe(kp);
}
static void test_kprobe_odd(struct kunit *test)
{
test_kprobe_offset(test, &kp, "kprobes_target_odd",
kprobes_target_odd_offs);
}
static void test_kprobe_in_insn4(struct kunit *test)
{
test_kprobe_offset(test, &kp, "kprobes_target_in_insn4",
kprobes_target_in_insn4_offs);
}
static void test_kprobe_in_insn6_lo(struct kunit *test)
{
test_kprobe_offset(test, &kp, "kprobes_target_in_insn6_lo",
kprobes_target_in_insn6_lo_offs);
}
static void test_kprobe_in_insn6_hi(struct kunit *test)
{
test_kprobe_offset(test, &kp, "kprobes_target_in_insn6_hi",
kprobes_target_in_insn6_hi_offs);
}
static struct kunit_case kprobes_testcases[] = {
KUNIT_CASE(test_kprobe_odd),
KUNIT_CASE(test_kprobe_in_insn4),
KUNIT_CASE(test_kprobe_in_insn6_lo),
KUNIT_CASE(test_kprobe_in_insn6_hi),
{}
};
static struct kunit_suite kprobes_test_suite = {
.name = "kprobes_test_s390",
.test_cases = kprobes_testcases,
};
kunit_test_suites(&kprobes_test_suite);
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef TEST_KPROBES_H
#define TEST_KPROBES_H
extern unsigned long kprobes_target_odd_offs;
extern unsigned long kprobes_target_in_insn4_offs;
extern unsigned long kprobes_target_in_insn6_lo_offs;
extern unsigned long kprobes_target_in_insn6_hi_offs;
#endif

View File

@ -0,0 +1,45 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#include <linux/linkage.h>
#include <asm/ftrace.h>
#define KPROBES_TARGET_START(name) \
SYM_FUNC_START(name); \
FTRACE_GEN_NOP_ASM(name)
#define KPROBES_TARGET_END(name) \
SYM_FUNC_END(name); \
SYM_DATA(name##_offs, .quad 1b - name)
KPROBES_TARGET_START(kprobes_target_in_insn4)
.word 0x4700 // bc 0,0
1: .word 0x0000
br %r14
KPROBES_TARGET_END(kprobes_target_in_insn4)
KPROBES_TARGET_START(kprobes_target_in_insn6_lo)
.word 0xe310 // ly 1,0
1: .word 0x0000
.word 0x0058
br %r14
KPROBES_TARGET_END(kprobes_target_in_insn6_lo)
KPROBES_TARGET_START(kprobes_target_in_insn6_hi)
.word 0xe310 // ly 1,0
.word 0x0000
1: .word 0x0058
br %r14
KPROBES_TARGET_END(kprobes_target_in_insn6_hi)
KPROBES_TARGET_START(kprobes_target_bp)
nop
.word 0x0000
nop
1: br %r14
KPROBES_TARGET_END(kprobes_target_bp)
KPROBES_TARGET_START(kprobes_target_odd)
.byte 0x07
1: .byte 0x07
br %r14
KPROBES_TARGET_END(kprobes_target_odd)

View File

@ -3,7 +3,7 @@
* Test module for unwind_for_each_frame
*/
#define pr_fmt(fmt) "test_unwind: " fmt
#include <kunit/test.h>
#include <asm/unwind.h>
#include <linux/completion.h>
#include <linux/kallsyms.h>
@ -16,6 +16,8 @@
#include <linux/wait.h>
#include <asm/irq.h>
struct kunit *current_test;
#define BT_BUF_SIZE (PAGE_SIZE * 4)
/*
@ -29,7 +31,7 @@ static void print_backtrace(char *bt)
p = strsep(&bt, "\n");
if (!p)
break;
pr_err("%s\n", p);
kunit_err(current_test, "%s\n", p);
}
}
@ -49,7 +51,7 @@ static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs,
bt = kmalloc(BT_BUF_SIZE, GFP_ATOMIC);
if (!bt) {
pr_err("failed to allocate backtrace buffer\n");
kunit_err(current_test, "failed to allocate backtrace buffer\n");
return -ENOMEM;
}
/* Unwind. */
@ -63,7 +65,7 @@ static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs,
if (frame_count++ == max_frames)
break;
if (state.reliable && !addr) {
pr_err("unwind state reliable but addr is 0\n");
kunit_err(current_test, "unwind state reliable but addr is 0\n");
ret = -EINVAL;
break;
}
@ -75,7 +77,7 @@ static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs,
stack_type_name(state.stack_info.type),
(void *)state.sp, (void *)state.ip);
if (bt_pos >= BT_BUF_SIZE)
pr_err("backtrace buffer is too small\n");
kunit_err(current_test, "backtrace buffer is too small\n");
}
frame_count += 1;
if (prev_is_func2 && str_has_prefix(sym, "unwindme_func1"))
@ -85,15 +87,15 @@ static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs,
/* Check the results. */
if (unwind_error(&state)) {
pr_err("unwind error\n");
kunit_err(current_test, "unwind error\n");
ret = -EINVAL;
}
if (!seen_func2_func1) {
pr_err("unwindme_func2 and unwindme_func1 not found\n");
kunit_err(current_test, "unwindme_func2 and unwindme_func1 not found\n");
ret = -EINVAL;
}
if (frame_count == max_frames) {
pr_err("Maximum number of frames exceeded\n");
kunit_err(current_test, "Maximum number of frames exceeded\n");
ret = -EINVAL;
}
if (ret)
@ -166,7 +168,7 @@ static noinline int unwindme_func4(struct unwindme *u)
kp.pre_handler = pgm_pre_handler;
ret = register_kprobe(&kp);
if (ret < 0) {
pr_err("register_kprobe failed %d\n", ret);
kunit_err(current_test, "register_kprobe failed %d\n", ret);
return -EINVAL;
}
@ -252,7 +254,7 @@ static int test_unwind_irq(struct unwindme *u)
}
/* Spawns a task and passes it to test_unwind(). */
static int test_unwind_task(struct unwindme *u)
static int test_unwind_task(struct kunit *test, struct unwindme *u)
{
struct task_struct *task;
int ret;
@ -267,7 +269,7 @@ static int test_unwind_task(struct unwindme *u)
*/
task = kthread_run(unwindme_func1, u, "%s", __func__);
if (IS_ERR(task)) {
pr_err("kthread_run() failed\n");
kunit_err(test, "kthread_run() failed\n");
return PTR_ERR(task);
}
/*
@ -282,77 +284,98 @@ static int test_unwind_task(struct unwindme *u)
return ret;
}
static int test_unwind_flags(int flags)
struct test_params {
int flags;
char *name;
};
/*
* Create required parameter list for tests
*/
static const struct test_params param_list[] = {
{.flags = UWM_DEFAULT, .name = "UWM_DEFAULT"},
{.flags = UWM_SP, .name = "UWM_SP"},
{.flags = UWM_REGS, .name = "UWM_REGS"},
{.flags = UWM_SWITCH_STACK,
.name = "UWM_SWITCH_STACK"},
{.flags = UWM_SP | UWM_REGS,
.name = "UWM_SP | UWM_REGS"},
{.flags = UWM_CALLER | UWM_SP,
.name = "WM_CALLER | UWM_SP"},
{.flags = UWM_CALLER | UWM_SP | UWM_REGS,
.name = "UWM_CALLER | UWM_SP | UWM_REGS"},
{.flags = UWM_CALLER | UWM_SP | UWM_REGS | UWM_SWITCH_STACK,
.name = "UWM_CALLER | UWM_SP | UWM_REGS | UWM_SWITCH_STACK"},
{.flags = UWM_THREAD, .name = "UWM_THREAD"},
{.flags = UWM_THREAD | UWM_SP,
.name = "UWM_THREAD | UWM_SP"},
{.flags = UWM_THREAD | UWM_CALLER | UWM_SP,
.name = "UWM_THREAD | UWM_CALLER | UWM_SP"},
{.flags = UWM_IRQ, .name = "UWM_IRQ"},
{.flags = UWM_IRQ | UWM_SWITCH_STACK,
.name = "UWM_IRQ | UWM_SWITCH_STACK"},
{.flags = UWM_IRQ | UWM_SP,
.name = "UWM_IRQ | UWM_SP"},
{.flags = UWM_IRQ | UWM_REGS,
.name = "UWM_IRQ | UWM_REGS"},
{.flags = UWM_IRQ | UWM_SP | UWM_REGS,
.name = "UWM_IRQ | UWM_SP | UWM_REGS"},
{.flags = UWM_IRQ | UWM_CALLER | UWM_SP,
.name = "UWM_IRQ | UWM_CALLER | UWM_SP"},
{.flags = UWM_IRQ | UWM_CALLER | UWM_SP | UWM_REGS,
.name = "UWM_IRQ | UWM_CALLER | UWM_SP | UWM_REGS"},
{.flags = UWM_IRQ | UWM_CALLER | UWM_SP | UWM_REGS | UWM_SWITCH_STACK,
.name = "UWM_IRQ | UWM_CALLER | UWM_SP | UWM_REGS | UWM_SWITCH_STACK"},
#ifdef CONFIG_KPROBES
{.flags = UWM_PGM, .name = "UWM_PGM"},
{.flags = UWM_PGM | UWM_SP,
.name = "UWM_PGM | UWM_SP"},
{.flags = UWM_PGM | UWM_REGS,
.name = "UWM_PGM | UWM_REGS"},
{.flags = UWM_PGM | UWM_SP | UWM_REGS,
.name = "UWM_PGM | UWM_SP | UWM_REGS"},
#endif
};
/*
* Parameter description generator: required for KUNIT_ARRAY_PARAM()
*/
static void get_desc(const struct test_params *params, char *desc)
{
strscpy(desc, params->name, KUNIT_PARAM_DESC_SIZE);
}
/*
* Create test_unwind_gen_params
*/
KUNIT_ARRAY_PARAM(test_unwind, param_list, get_desc);
static void test_unwind_flags(struct kunit *test)
{
struct unwindme u;
const struct test_params *params;
u.flags = flags;
current_test = test;
params = (const struct test_params *)test->param_value;
u.flags = params->flags;
if (u.flags & UWM_THREAD)
return test_unwind_task(&u);
KUNIT_EXPECT_EQ(test, 0, test_unwind_task(test, &u));
else if (u.flags & UWM_IRQ)
return test_unwind_irq(&u);
KUNIT_EXPECT_EQ(test, 0, test_unwind_irq(&u));
else
return unwindme_func1(&u);
KUNIT_EXPECT_EQ(test, 0, unwindme_func1(&u));
}
static int test_unwind_init(void)
{
int failed = 0;
int total = 0;
static struct kunit_case unwind_test_cases[] = {
KUNIT_CASE_PARAM(test_unwind_flags, test_unwind_gen_params),
{}
};
#define TEST(flags) \
do { \
pr_info("[ RUN ] " #flags "\n"); \
total++; \
if (!test_unwind_flags((flags))) { \
pr_info("[ OK ] " #flags "\n"); \
} else { \
pr_err("[ FAILED ] " #flags "\n"); \
failed++; \
} \
} while (0)
static struct kunit_suite test_unwind_suite = {
.name = "test_unwind",
.test_cases = unwind_test_cases,
};
pr_info("running stack unwinder tests");
TEST(UWM_DEFAULT);
TEST(UWM_SP);
TEST(UWM_REGS);
TEST(UWM_SWITCH_STACK);
TEST(UWM_SP | UWM_REGS);
TEST(UWM_CALLER | UWM_SP);
TEST(UWM_CALLER | UWM_SP | UWM_REGS);
TEST(UWM_CALLER | UWM_SP | UWM_REGS | UWM_SWITCH_STACK);
TEST(UWM_THREAD);
TEST(UWM_THREAD | UWM_SP);
TEST(UWM_THREAD | UWM_CALLER | UWM_SP);
TEST(UWM_IRQ);
TEST(UWM_IRQ | UWM_SWITCH_STACK);
TEST(UWM_IRQ | UWM_SP);
TEST(UWM_IRQ | UWM_REGS);
TEST(UWM_IRQ | UWM_SP | UWM_REGS);
TEST(UWM_IRQ | UWM_CALLER | UWM_SP);
TEST(UWM_IRQ | UWM_CALLER | UWM_SP | UWM_REGS);
TEST(UWM_IRQ | UWM_CALLER | UWM_SP | UWM_REGS | UWM_SWITCH_STACK);
#ifdef CONFIG_KPROBES
TEST(UWM_PGM);
TEST(UWM_PGM | UWM_SP);
TEST(UWM_PGM | UWM_REGS);
TEST(UWM_PGM | UWM_SP | UWM_REGS);
#endif
#undef TEST
if (failed) {
pr_err("%d of %d stack unwinder tests failed", failed, total);
WARN(1, "%d of %d stack unwinder tests failed", failed, total);
} else {
pr_info("all %d stack unwinder tests passed", total);
}
kunit_test_suites(&test_unwind_suite);
return failed ? -EINVAL : 0;
}
static void test_unwind_exit(void)
{
}
module_init(test_unwind_init);
module_exit(test_unwind_exit);
MODULE_LICENSE("GPL");

View File

@ -14,8 +14,8 @@
#include <linux/moduleparam.h>
#include <linux/gfp.h>
#include <linux/sched.h>
#include <linux/string_helpers.h>
#include <linux/sysctl.h>
#include <linux/ctype.h>
#include <linux/swap.h>
#include <linux/kthread.h>
#include <linux/oom.h>
@ -394,13 +394,10 @@ static int __init cmm_init(void)
goto out_sysctl;
#ifdef CONFIG_CMM_IUCV
/* convert sender to uppercase characters */
if (sender) {
int len = strlen(sender);
while (len--)
sender[len] = toupper(sender[len]);
} else {
if (sender)
string_upper(sender, sender);
else
sender = cmm_default_sender;
}
rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
if (rc < 0)

View File

@ -8,6 +8,7 @@
#include <linux/kasan.h>
#include <asm/ptdump.h>
#include <asm/kasan.h>
#include <asm/nospec-branch.h>
#include <asm/sections.h>
static unsigned long max_addr;
@ -116,8 +117,13 @@ static void note_prot_wx(struct pg_state *st, unsigned long addr)
return;
if (st->current_prot & _PAGE_NOEXEC)
return;
/* The first lowcore page is currently still W+X. */
if (addr == PAGE_SIZE)
/*
* The first lowcore page is W+X if spectre mitigations are using
* trampolines or the BEAR enhancements facility is not installed,
* in which case we have two lpswe instructions in lowcore that need
* to be executable.
*/
if (addr == PAGE_SIZE && (nospec_uses_trampoline() || !static_key_enabled(&cpu_has_bear)))
return;
WARN_ONCE(1, "s390/mm: Found insecure W+X mapping at address %pS\n",
(void *)st->start_address);
@ -203,7 +209,9 @@ void ptdump_check_wx(void)
if (st.wx_pages)
pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found\n", st.wx_pages);
else
pr_info("Checked W+X mappings: passed, no unexpected W+X pages found\n");
pr_info("Checked W+X mappings: passed, no %sW+X pages found\n",
(nospec_uses_trampoline() || !static_key_enabled(&cpu_has_bear)) ?
"unexpected " : "");
}
#endif /* CONFIG_DEBUG_WX */

View File

@ -57,7 +57,7 @@ void arch_report_meminfo(struct seq_file *m)
static void pgt_set(unsigned long *old, unsigned long new, unsigned long addr,
unsigned long dtt)
{
unsigned long table, mask;
unsigned long *table, mask;
mask = 0;
if (MACHINE_HAS_EDAT2) {
@ -72,7 +72,7 @@ static void pgt_set(unsigned long *old, unsigned long new, unsigned long addr,
mask = ~(PTRS_PER_PTE * sizeof(pte_t) - 1);
break;
}
table = (unsigned long)old & mask;
table = (unsigned long *)((unsigned long)old & mask);
crdte(*old, new, table, dtt, addr, S390_lowcore.kernel_asce);
} else if (MACHINE_HAS_IDTE) {
cspg(old, *old, new);

View File

@ -13,6 +13,7 @@
#include <linux/hugetlb.h>
#include <linux/slab.h>
#include <asm/cacheflush.h>
#include <asm/nospec-branch.h>
#include <asm/pgalloc.h>
#include <asm/setup.h>
#include <asm/tlbflush.h>
@ -584,8 +585,13 @@ void __init vmem_map_init(void)
__set_memory(__stext_amode31, (__etext_amode31 - __stext_amode31) >> PAGE_SHIFT,
SET_MEMORY_RO | SET_MEMORY_X);
/* we need lowcore executable for our LPSWE instructions */
set_memory_x(0, 1);
if (nospec_uses_trampoline() || !static_key_enabled(&cpu_has_bear)) {
/*
* Lowcore must be executable for LPSWE
* and expoline trampoline branch instructions.
*/
set_memory_x(0, 1);
}
pr_info("Write protected kernel read-only data: %luk\n",
(unsigned long)(__end_rodata - _stext) >> 10);

View File

@ -567,7 +567,7 @@ static void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth)
EMIT4(0xb9040000, REG_2, BPF_REG_0);
/* Restore registers */
save_restore_regs(jit, REGS_RESTORE, stack_depth);
if (__is_defined(CC_USING_EXPOLINE) && !nospec_disable) {
if (nospec_uses_trampoline()) {
jit->r14_thunk_ip = jit->prg;
/* Generate __s390_indirect_jump_r14 thunk */
if (test_facility(35)) {
@ -585,7 +585,7 @@ static void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth)
/* br %r14 */
_EMIT2(0x07fe);
if (__is_defined(CC_USING_EXPOLINE) && !nospec_disable &&
if ((nospec_uses_trampoline()) &&
(is_first_pass(jit) || (jit->seen & SEEN_FUNC))) {
jit->r1_thunk_ip = jit->prg;
/* Generate __s390_indirect_jump_r1 thunk */
@ -1332,7 +1332,7 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
jit->seen |= SEEN_FUNC;
/* lgrl %w1,func */
EMIT6_PCREL_RILB(0xc4080000, REG_W1, _EMIT_CONST_U64(func));
if (__is_defined(CC_USING_EXPOLINE) && !nospec_disable) {
if (nospec_uses_trampoline()) {
/* brasl %r14,__s390_indirect_jump_r1 */
EMIT6_PCREL_RILB(0xc0050000, REG_14, jit->r1_thunk_ip);
} else {

View File

@ -18,6 +18,8 @@
static struct kmem_cache *dma_region_table_cache;
static struct kmem_cache *dma_page_table_cache;
static int s390_iommu_strict;
static u64 s390_iommu_aperture;
static u32 s390_iommu_aperture_factor = 1;
static int zpci_refresh_global(struct zpci_dev *zdev)
{
@ -565,15 +567,19 @@ int zpci_dma_init_device(struct zpci_dev *zdev)
/*
* Restrict the iommu bitmap size to the minimum of the following:
* - main memory size
* - s390_iommu_aperture which defaults to high_memory
* - 3-level pagetable address limit minus start_dma offset
* - DMA address range allowed by the hardware (clp query pci fn)
*
* Also set zdev->end_dma to the actual end address of the usable
* range, instead of the theoretical maximum as reported by hardware.
*
* This limits the number of concurrently usable DMA mappings since
* for each DMA mapped memory address we need a DMA address including
* extra DMA addresses for multiple mappings of the same memory address.
*/
zdev->start_dma = PAGE_ALIGN(zdev->start_dma);
zdev->iommu_size = min3((u64) high_memory,
zdev->iommu_size = min3(s390_iommu_aperture,
ZPCI_TABLE_SIZE_RT - zdev->start_dma,
zdev->end_dma - zdev->start_dma + 1);
zdev->end_dma = zdev->start_dma + zdev->iommu_size - 1;
@ -660,6 +666,12 @@ static int __init dma_alloc_cpu_table_caches(void)
int __init zpci_dma_init(void)
{
s390_iommu_aperture = (u64)high_memory;
if (!s390_iommu_aperture_factor)
s390_iommu_aperture = ULONG_MAX;
else
s390_iommu_aperture *= s390_iommu_aperture_factor;
return dma_alloc_cpu_table_caches();
}
@ -692,3 +704,12 @@ static int __init s390_iommu_setup(char *str)
}
__setup("s390_iommu=", s390_iommu_setup);
static int __init s390_iommu_aperture_setup(char *str)
{
if (kstrtou32(str, 10, &s390_iommu_aperture_factor))
s390_iommu_aperture_factor = 1;
return 1;
}
__setup("s390_iommu_aperture=", s390_iommu_aperture_setup);

View File

@ -52,6 +52,8 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
struct pci_dev *pdev = NULL;
zpci_dbg(3, "err fid:%x, fh:%x, pec:%x\n",
ccdf->fid, ccdf->fh, ccdf->pec);
zpci_err("error CCDF:\n");
zpci_err_hex(ccdf, sizeof(*ccdf));
@ -96,6 +98,8 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
enum zpci_state state;
zpci_dbg(3, "avl fid:%x, fh:%x, pec:%x\n",
ccdf->fid, ccdf->fh, ccdf->pec);
zpci_err("avail CCDF:\n");
zpci_err_hex(ccdf, sizeof(*ccdf));

View File

@ -90,6 +90,14 @@ static ssize_t recover_store(struct device *dev, struct device_attribute *attr,
if (zdev_enabled(zdev)) {
ret = zpci_disable_device(zdev);
/*
* Due to a z/VM vs LPAR inconsistency in the error
* state the FH may indicate an enabled device but
* disable says the device is already disabled don't
* treat it as an error here.
*/
if (ret == -EINVAL)
ret = 0;
if (ret)
goto out;
}

View File

@ -192,6 +192,8 @@ config X86
select HAVE_DYNAMIC_FTRACE_WITH_REGS
select HAVE_DYNAMIC_FTRACE_WITH_ARGS if X86_64
select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
select HAVE_SAMPLE_FTRACE_DIRECT if X86_64
select HAVE_SAMPLE_FTRACE_MULTI_DIRECT if X86_64
select HAVE_EBPF_JIT
select HAVE_EFFICIENT_UNALIGNED_ACCESS
select HAVE_EISA

View File

@ -34,7 +34,7 @@ int dasd_gendisk_alloc(struct dasd_block *block)
{
struct gendisk *gdp;
struct dasd_device *base;
int len;
int len, rc;
/* Make sure the minor for this device exists. */
base = block->base;
@ -80,7 +80,13 @@ int dasd_gendisk_alloc(struct dasd_block *block)
dasd_add_link_to_gendisk(gdp, base);
block->gdp = gdp;
set_capacity(block->gdp, 0);
device_add_disk(&base->cdev->dev, block->gdp, NULL);
rc = device_add_disk(&base->cdev->dev, block->gdp, NULL);
if (rc) {
dasd_gendisk_free(block);
return rc;
}
return 0;
}

View File

@ -696,7 +696,9 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
}
get_device(&dev_info->dev);
device_add_disk(&dev_info->dev, dev_info->gd, NULL);
rc = device_add_disk(&dev_info->dev, dev_info->gd, NULL);
if (rc)
goto out_dax;
switch (dev_info->segment_type) {
case SEG_TYPE_SR:
@ -712,6 +714,10 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
rc = count;
goto out;
out_dax:
put_device(&dev_info->dev);
kill_dax(dev_info->dax_dev);
put_dax(dev_info->dax_dev);
put_dev:
list_del(&dev_info->lh);
blk_cleanup_disk(dev_info->gd);

View File

@ -495,9 +495,14 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev)
/* 512 byte sectors */
set_capacity(bdev->gendisk, scmdev->size >> 9);
device_add_disk(&scmdev->dev, bdev->gendisk, NULL);
ret = device_add_disk(&scmdev->dev, bdev->gendisk, NULL);
if (ret)
goto out_cleanup_disk;
return 0;
out_cleanup_disk:
blk_cleanup_disk(bdev->gendisk);
out_tag:
blk_mq_free_tag_set(&bdev->tag_set);
out:

View File

@ -163,7 +163,7 @@ static inline void sclp_trace_req(int prio, char *id, struct sclp_req *req,
summary.timeout = (u16)req->queue_timeout;
summary.start_count = (u16)req->start_count;
sclp_trace(prio, id, (u32)(addr_t)sccb, summary.b, err);
sclp_trace(prio, id, __pa(sccb), summary.b, err);
}
static inline void sclp_trace_register(int prio, char *id, u32 a, u64 b,
@ -502,7 +502,7 @@ sclp_add_request(struct sclp_req *req)
}
/* RQAD: Request was added (a=sccb, b=caller) */
sclp_trace(2, "RQAD", (u32)(addr_t)req->sccb, _RET_IP_, false);
sclp_trace(2, "RQAD", __pa(req->sccb), _RET_IP_, false);
req->status = SCLP_REQ_QUEUED;
req->start_count = 0;
@ -617,15 +617,15 @@ __sclp_find_req(u32 sccb)
list_for_each(l, &sclp_req_queue) {
req = list_entry(l, struct sclp_req, list);
if (sccb == (u32) (addr_t) req->sccb)
return req;
if (sccb == __pa(req->sccb))
return req;
}
return NULL;
}
static bool ok_response(u32 sccb_int, sclp_cmdw_t cmd)
{
struct sccb_header *sccb = (struct sccb_header *)(addr_t)sccb_int;
struct sccb_header *sccb = (struct sccb_header *)__va(sccb_int);
struct evbuf_header *evbuf;
u16 response;
@ -664,7 +664,7 @@ static void sclp_interrupt_handler(struct ext_code ext_code,
/* INT: Interrupt received (a=intparm, b=cmd) */
sclp_trace_sccb(0, "INT", param32, active_cmd, active_cmd,
(struct sccb_header *)(addr_t)finished_sccb,
(struct sccb_header *)__va(finished_sccb),
!ok_response(finished_sccb, active_cmd));
if (finished_sccb) {
@ -1110,7 +1110,7 @@ static void sclp_check_handler(struct ext_code ext_code,
/* Is this the interrupt we are waiting for? */
if (finished_sccb == 0)
return;
if (finished_sccb != (u32) (addr_t) sclp_init_sccb)
if (finished_sccb != __pa(sclp_init_sccb))
panic("sclp: unsolicited interrupt for buffer at 0x%x\n",
finished_sccb);
spin_lock(&sclp_lock);

View File

@ -333,7 +333,7 @@ static inline int sclp_service_call(sclp_cmdw_t command, void *sccb)
"2:\n"
EX_TABLE(0b, 2b)
EX_TABLE(1b, 2b)
: "+&d" (cc) : "d" (command), "a" ((unsigned long)sccb)
: "+&d" (cc) : "d" (command), "a" (__pa(sccb))
: "cc", "memory");
if (cc == 4)
return -EINVAL;

View File

@ -155,6 +155,11 @@ static void __init sclp_early_console_detect(struct init_sccb *sccb)
sclp.has_linemode = 1;
}
void __init sclp_early_adjust_va(void)
{
sclp_early_sccb = __va((unsigned long)sclp_early_sccb);
}
void __init sclp_early_detect(void)
{
void *sccb = sclp_early_sccb;

View File

@ -31,6 +31,8 @@ static u64 sclp_ftp_length;
/**
* sclp_ftp_txcb() - Diagnostic Test FTP services SCLP command callback
* @req: sclp request
* @data: pointer to struct completion
*/
static void sclp_ftp_txcb(struct sclp_req *req, void *data)
{
@ -45,6 +47,7 @@ static void sclp_ftp_txcb(struct sclp_req *req, void *data)
/**
* sclp_ftp_rxcb() - Diagnostic Test FTP services receiver event callback
* @evbuf: pointer to Diagnostic Test (ET7) event buffer
*/
static void sclp_ftp_rxcb(struct evbuf_header *evbuf)
{

View File

@ -122,6 +122,7 @@ static void sclp_sd_listener_remove(struct sclp_sd_listener *listener)
/**
* sclp_sd_listener_init() - Initialize a Store Data response listener
* @listener: Response listener to initialize
* @id: Event ID to listen for
*
* Initialize a listener for asynchronous Store Data responses. This listener
@ -193,7 +194,7 @@ static int sclp_sd_sync(unsigned long page, u8 eq, u8 di, u64 sat, u64 sa,
struct sclp_sd_evbuf *evbuf;
int rc;
sclp_sd_listener_init(&listener, (u32) (addr_t) sccb);
sclp_sd_listener_init(&listener, __pa(sccb));
sclp_sd_listener_add(&listener);
/* Prepare SCCB */
@ -403,6 +404,7 @@ static int sclp_sd_file_update(struct sclp_sd_file *sd_file)
/**
* sclp_sd_file_update_async() - Wrapper for asynchronous update call
* @data: Object to update
* @cookie: Unused
*/
static void sclp_sd_file_update_async(void *data, async_cookie_t cookie)
{
@ -414,6 +416,9 @@ static void sclp_sd_file_update_async(void *data, async_cookie_t cookie)
/**
* reload_store() - Store function for "reload" sysfs attribute
* @kobj: Kobject of sclp_sd_file object
* @attr: Reload attribute
* @buf: Data written to sysfs attribute
* @count: Count of bytes written
*
* Initiate a reload of the data associated with an sclp_sd_file object.
*/
@ -441,8 +446,10 @@ static struct kobj_type sclp_sd_file_ktype = {
};
/**
* data_read() - Read function for "read" sysfs attribute
* data_read() - Read function for "data" sysfs attribute
* @file: Open file pointer
* @kobj: Kobject of sclp_sd_file object
* @attr: Data attribute
* @buffer: Target buffer
* @off: Requested file offset
* @size: Requested number of bytes

View File

@ -768,6 +768,8 @@ out_driver:
}
__initcall(sclp_vt220_tty_init);
#ifdef CONFIG_SCLP_VT220_CONSOLE
static void __sclp_vt220_flush_buffer(void)
{
unsigned long flags;
@ -784,8 +786,6 @@ static void __sclp_vt220_flush_buffer(void)
spin_unlock_irqrestore(&sclp_vt220_lock, flags);
}
#ifdef CONFIG_SCLP_VT220_CONSOLE
static void
sclp_vt220_con_write(struct console *con, const char *buf, unsigned int count)
{

View File

@ -792,10 +792,13 @@ static int __unset_online(struct device *dev, void *data)
{
struct idset *set = data;
struct subchannel *sch = to_subchannel(dev);
struct ccw_device *cdev = sch_get_cdev(sch);
struct ccw_device *cdev;
if (cdev && cdev->online)
idset_sch_del(set, sch->schid);
if (sch->st == SUBCHANNEL_TYPE_IO) {
cdev = sch_get_cdev(sch);
if (cdev && cdev->online)
idset_sch_del(set, sch->schid);
}
return 0;
}

View File

@ -1322,6 +1322,7 @@ static int purge_fn(struct device *dev, void *data)
{
struct ccw_device *cdev = to_ccwdev(dev);
struct ccw_dev_id *id = &cdev->private->dev_id;
struct subchannel *sch = to_subchannel(cdev->dev.parent);
spin_lock_irq(cdev->ccwlock);
if (is_blacklisted(id->ssid, id->devno) &&
@ -1330,6 +1331,7 @@ static int purge_fn(struct device *dev, void *data)
CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", id->ssid,
id->devno);
ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
css_sched_sch_todo(sch, SCH_TODO_UNREG);
atomic_set(&cdev->private->onoff, 0);
}
spin_unlock_irq(cdev->ccwlock);

View File

@ -825,13 +825,23 @@ EXPORT_SYMBOL_GPL(ccw_device_get_chid);
*/
void *ccw_device_dma_zalloc(struct ccw_device *cdev, size_t size)
{
return cio_gp_dma_zalloc(cdev->private->dma_pool, &cdev->dev, size);
void *addr;
if (!get_device(&cdev->dev))
return NULL;
addr = cio_gp_dma_zalloc(cdev->private->dma_pool, &cdev->dev, size);
if (IS_ERR_OR_NULL(addr))
put_device(&cdev->dev);
return addr;
}
EXPORT_SYMBOL(ccw_device_dma_zalloc);
void ccw_device_dma_free(struct ccw_device *cdev, void *cpu_addr, size_t size)
{
if (!cpu_addr)
return;
cio_gp_dma_free(cdev->private->dma_pool, cpu_addr, size);
put_device(&cdev->dev);
}
EXPORT_SYMBOL(ccw_device_dma_free);

View File

@ -61,6 +61,10 @@ static char *aqm_str;
module_param_named(aqmask, aqm_str, charp, 0440);
MODULE_PARM_DESC(aqmask, "AP bus domain mask.");
static int ap_useirq = 1;
module_param_named(useirq, ap_useirq, int, 0440);
MODULE_PARM_DESC(useirq, "Use interrupt if available, default is 1 (on).");
atomic_t ap_max_msg_size = ATOMIC_INIT(AP_DEFAULT_MAX_MSG_SIZE);
EXPORT_SYMBOL(ap_max_msg_size);
@ -725,7 +729,7 @@ static void ap_check_bindings_complete(void)
if (bound == apqns) {
if (!completion_done(&ap_init_apqn_bindings_complete)) {
complete_all(&ap_init_apqn_bindings_complete);
AP_DBF(DBF_INFO, "%s complete\n", __func__);
AP_DBF_INFO("%s complete\n", __func__);
}
ap_send_bindings_complete_uevent();
}
@ -786,9 +790,12 @@ static int __ap_revise_reserved(struct device *dev, void *dummy)
drvres = to_ap_drv(dev->driver)->flags
& AP_DRIVER_FLAG_DEFAULT;
if (!!devres != !!drvres) {
AP_DBF_DBG("reprobing queue=%02x.%04x\n",
card, queue);
AP_DBF_DBG("%s reprobing queue=%02x.%04x\n",
__func__, card, queue);
rc = device_reprobe(dev);
if (rc)
AP_DBF_WARN("%s reprobing queue=%02x.%04x failed\n",
__func__, card, queue);
}
}
@ -1118,7 +1125,8 @@ static ssize_t ap_domain_store(struct bus_type *bus,
ap_domain_index = domain;
spin_unlock_bh(&ap_domain_lock);
AP_DBF_INFO("stored new default domain=%d\n", domain);
AP_DBF_INFO("%s stored new default domain=%d\n",
__func__, domain);
return count;
}
@ -1433,8 +1441,9 @@ static int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func)
/* < CEX2A is not supported */
if (rawtype < AP_DEVICE_TYPE_CEX2A) {
AP_DBF_WARN("get_comp_type queue=%02x.%04x unsupported type %d\n",
AP_QID_CARD(qid), AP_QID_QUEUE(qid), rawtype);
AP_DBF_WARN("%s queue=%02x.%04x unsupported type %d\n",
__func__, AP_QID_CARD(qid),
AP_QID_QUEUE(qid), rawtype);
return 0;
}
/* up to CEX7 known and fully supported */
@ -1458,11 +1467,12 @@ static int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func)
comp_type = apinfo.cat;
}
if (!comp_type)
AP_DBF_WARN("get_comp_type queue=%02x.%04x unable to map type %d\n",
AP_QID_CARD(qid), AP_QID_QUEUE(qid), rawtype);
AP_DBF_WARN("%s queue=%02x.%04x unable to map type %d\n",
__func__, AP_QID_CARD(qid),
AP_QID_QUEUE(qid), rawtype);
else if (comp_type != rawtype)
AP_DBF_INFO("get_comp_type queue=%02x.%04x map type %d to %d\n",
AP_QID_CARD(qid), AP_QID_QUEUE(qid),
AP_DBF_INFO("%s queue=%02x.%04x map type %d to %d\n",
__func__, AP_QID_CARD(qid), AP_QID_QUEUE(qid),
rawtype, comp_type);
return comp_type;
}
@ -1535,7 +1545,7 @@ static inline void ap_scan_domains(struct ap_card *ac)
aq = dev ? to_ap_queue(dev) : NULL;
if (!ap_test_config_usage_domain(dom)) {
if (dev) {
AP_DBF_INFO("%s(%d,%d) not in config any more, rm queue device\n",
AP_DBF_INFO("%s(%d,%d) not in config anymore, rm queue dev\n",
__func__, ac->id, dom);
device_unregister(dev);
put_device(dev);
@ -1545,9 +1555,8 @@ static inline void ap_scan_domains(struct ap_card *ac)
/* domain is valid, get info from this APQN */
if (!ap_queue_info(qid, &type, &func, &depth, &ml, &decfg)) {
if (aq) {
AP_DBF_INFO(
"%s(%d,%d) ap_queue_info() not successful, rm queue device\n",
__func__, ac->id, dom);
AP_DBF_INFO("%s(%d,%d) queue_info() failed, rm queue dev\n",
__func__, ac->id, dom);
device_unregister(dev);
put_device(dev);
}
@ -1577,10 +1586,10 @@ static inline void ap_scan_domains(struct ap_card *ac)
/* get it and thus adjust reference counter */
get_device(dev);
if (decfg)
AP_DBF_INFO("%s(%d,%d) new (decfg) queue device created\n",
AP_DBF_INFO("%s(%d,%d) new (decfg) queue dev created\n",
__func__, ac->id, dom);
else
AP_DBF_INFO("%s(%d,%d) new queue device created\n",
AP_DBF_INFO("%s(%d,%d) new queue dev created\n",
__func__, ac->id, dom);
goto put_dev_and_continue;
}
@ -1594,7 +1603,7 @@ static inline void ap_scan_domains(struct ap_card *ac)
aq->last_err_rc = AP_RESPONSE_DECONFIGURED;
}
spin_unlock_bh(&aq->lock);
AP_DBF_INFO("%s(%d,%d) queue device config off\n",
AP_DBF_INFO("%s(%d,%d) queue dev config off\n",
__func__, ac->id, dom);
ap_send_config_uevent(&aq->ap_dev, aq->config);
/* 'receive' pending messages with -EAGAIN */
@ -1609,7 +1618,7 @@ static inline void ap_scan_domains(struct ap_card *ac)
aq->sm_state = AP_SM_STATE_RESET_START;
}
spin_unlock_bh(&aq->lock);
AP_DBF_INFO("%s(%d,%d) queue device config on\n",
AP_DBF_INFO("%s(%d,%d) queue dev config on\n",
__func__, ac->id, dom);
ap_send_config_uevent(&aq->ap_dev, aq->config);
goto put_dev_and_continue;
@ -1621,7 +1630,7 @@ static inline void ap_scan_domains(struct ap_card *ac)
ap_flush_queue(aq);
/* re-init (with reset) the queue device */
ap_queue_init_state(aq);
AP_DBF_INFO("%s(%d,%d) queue device reinit enforced\n",
AP_DBF_INFO("%s(%d,%d) queue dev reinit enforced\n",
__func__, ac->id, dom);
goto put_dev_and_continue;
}
@ -1653,7 +1662,7 @@ static inline void ap_scan_adapter(int ap)
/* Adapter not in configuration ? */
if (!ap_test_config_card_id(ap)) {
if (ac) {
AP_DBF_INFO("%s(%d) ap not in config any more, rm card and queue devices\n",
AP_DBF_INFO("%s(%d) ap not in config any more, rm card and queue devs\n",
__func__, ap);
ap_scan_rm_card_dev_and_queue_devs(ac);
put_device(dev);
@ -1678,9 +1687,8 @@ static inline void ap_scan_adapter(int ap)
if (dom > ap_max_domain_id) {
/* Could not find a valid APQN for this adapter */
if (ac) {
AP_DBF_INFO(
"%s(%d) no type info (no APQN found), rm card and queue devices\n",
__func__, ap);
AP_DBF_INFO("%s(%d) no type info (no APQN found), rm card and queue devs\n",
__func__, ap);
ap_scan_rm_card_dev_and_queue_devs(ac);
put_device(dev);
} else {
@ -1692,7 +1700,7 @@ static inline void ap_scan_adapter(int ap)
if (!type) {
/* No apdater type info available, an unusable adapter */
if (ac) {
AP_DBF_INFO("%s(%d) no valid type (0) info, rm card and queue devices\n",
AP_DBF_INFO("%s(%d) no valid type (0) info, rm card and queue devs\n",
__func__, ap);
ap_scan_rm_card_dev_and_queue_devs(ac);
put_device(dev);
@ -1706,13 +1714,13 @@ static inline void ap_scan_adapter(int ap)
if (ac) {
/* Check APQN against existing card device for changes */
if (ac->raw_hwtype != type) {
AP_DBF_INFO("%s(%d) hwtype %d changed, rm card and queue devices\n",
AP_DBF_INFO("%s(%d) hwtype %d changed, rm card and queue devs\n",
__func__, ap, type);
ap_scan_rm_card_dev_and_queue_devs(ac);
put_device(dev);
ac = NULL;
} else if (ac->functions != func) {
AP_DBF_INFO("%s(%d) functions 0x%08x changed, rm card and queue devices\n",
AP_DBF_INFO("%s(%d) functions 0x%08x changed, rm card and queue devs\n",
__func__, ap, type);
ap_scan_rm_card_dev_and_queue_devs(ac);
put_device(dev);
@ -1720,13 +1728,13 @@ static inline void ap_scan_adapter(int ap)
} else {
if (decfg && ac->config) {
ac->config = false;
AP_DBF_INFO("%s(%d) card device config off\n",
AP_DBF_INFO("%s(%d) card dev config off\n",
__func__, ap);
ap_send_config_uevent(&ac->ap_dev, ac->config);
}
if (!decfg && !ac->config) {
ac->config = true;
AP_DBF_INFO("%s(%d) card device config on\n",
AP_DBF_INFO("%s(%d) card dev config on\n",
__func__, ap);
ap_send_config_uevent(&ac->ap_dev, ac->config);
}
@ -1756,7 +1764,8 @@ static inline void ap_scan_adapter(int ap)
if (ac->maxmsgsize > atomic_read(&ap_max_msg_size)) {
atomic_set(&ap_max_msg_size, ac->maxmsgsize);
AP_DBF_INFO("%s(%d) ap_max_msg_size update to %d byte\n",
__func__, ap, atomic_read(&ap_max_msg_size));
__func__, ap,
atomic_read(&ap_max_msg_size));
}
/* Register the new card device with AP bus */
rc = device_register(dev);
@ -1769,10 +1778,10 @@ static inline void ap_scan_adapter(int ap)
/* get it and thus adjust reference counter */
get_device(dev);
if (decfg)
AP_DBF_INFO("%s(%d) new (decfg) card device type=%d func=0x%08x created\n",
AP_DBF_INFO("%s(%d) new (decfg) card dev type=%d func=0x%08x created\n",
__func__, ap, type, func);
else
AP_DBF_INFO("%s(%d) new card device type=%d func=0x%08x created\n",
AP_DBF_INFO("%s(%d) new card dev type=%d func=0x%08x created\n",
__func__, ap, type, func);
}
@ -1810,12 +1819,12 @@ static void ap_scan_bus(struct work_struct *unused)
if (dev)
put_device(dev);
else
AP_DBF_INFO("no queue device with default domain %d available\n",
ap_domain_index);
AP_DBF_INFO("%s no queue device with default domain %d available\n",
__func__, ap_domain_index);
}
if (atomic64_inc_return(&ap_scan_bus_count) == 1) {
AP_DBF(DBF_DEBUG, "%s init scan complete\n", __func__);
AP_DBF_DBG("%s init scan complete\n", __func__);
ap_send_init_scan_done_uevent();
ap_check_bindings_complete();
}
@ -1830,7 +1839,7 @@ static void ap_config_timeout(struct timer_list *unused)
static int __init ap_debug_init(void)
{
ap_dbf_info = debug_register("ap", 1, 1,
ap_dbf_info = debug_register("ap", 2, 1,
DBF_MAX_SPRINTF_ARGS * sizeof(long));
debug_register_view(ap_dbf_info, &debug_sprintf_view);
debug_set_level(ap_dbf_info, DBF_ERR);
@ -1897,7 +1906,7 @@ static int __init ap_module_init(void)
}
/* enable interrupts if available */
if (ap_interrupts_available()) {
if (ap_interrupts_available() && ap_useirq) {
rc = register_adapter_interrupt(&ap_airq);
ap_irq_flag = (rc == 0);
}

View File

@ -16,7 +16,7 @@
#define RC2ERR(rc) ((rc) ? DBF_ERR : DBF_INFO)
#define RC2WARN(rc) ((rc) ? DBF_WARN : DBF_INFO)
#define DBF_MAX_SPRINTF_ARGS 5
#define DBF_MAX_SPRINTF_ARGS 6
#define AP_DBF(...) \
debug_sprintf_event(ap_dbf_info, ##__VA_ARGS__)

View File

@ -157,6 +157,8 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq)
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
aq->queue_count = max_t(int, 0, aq->queue_count - 1);
if (!status.queue_empty && !aq->queue_count)
aq->queue_count++;
if (aq->queue_count > 0)
mod_timer(&aq->timeout,
jiffies + aq->request_timeout);
@ -246,6 +248,7 @@ static enum ap_sm_wait ap_sm_write(struct ap_queue *aq)
if (aq->requestq_count <= 0)
return AP_SM_WAIT_NONE;
/* Start the next request on the queue. */
ap_msg = list_entry(aq->requestq.next, struct ap_message, list);
#ifdef CONFIG_ZCRYPT_DEBUG
@ -279,7 +282,7 @@ static enum ap_sm_wait ap_sm_write(struct ap_queue *aq)
aq->sm_state = AP_SM_STATE_RESET_WAIT;
return AP_SM_WAIT_TIMEOUT;
case AP_RESPONSE_INVALID_DOMAIN:
AP_DBF(DBF_WARN, "AP_RESPONSE_INVALID_DOMAIN on NQAP\n");
AP_DBF_WARN("%s RESPONSE_INVALID_DOMAIN on NQAP\n", __func__);
fallthrough;
case AP_RESPONSE_MESSAGE_TOO_BIG:
case AP_RESPONSE_REQ_FAC_NOT_INST:
@ -571,8 +574,8 @@ static ssize_t reset_store(struct device *dev,
ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL));
spin_unlock_bh(&aq->lock);
AP_DBF(DBF_INFO, "reset queue=%02x.%04x triggered by user\n",
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
AP_DBF_INFO("%s reset queue=%02x.%04x triggered by user\n",
__func__, AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
return count;
}

View File

@ -42,10 +42,13 @@ static struct ap_device_id ap_queue_ids[] = {
MODULE_DEVICE_TABLE(vfio_ap, ap_queue_ids);
/**
* vfio_ap_queue_dev_probe:
* vfio_ap_queue_dev_probe: Allocate a vfio_ap_queue structure and associate it
* with the device as driver_data.
*
* Allocate a vfio_ap_queue structure and associate it
* with the device as driver_data.
* @apdev: the AP device being probed
*
* Return: returns 0 if the probe succeeded; otherwise, returns -ENOMEM if
* storage could not be allocated for a vfio_ap_queue object.
*/
static int vfio_ap_queue_dev_probe(struct ap_device *apdev)
{
@ -61,10 +64,11 @@ static int vfio_ap_queue_dev_probe(struct ap_device *apdev)
}
/**
* vfio_ap_queue_dev_remove:
* vfio_ap_queue_dev_remove: Free the associated vfio_ap_queue structure.
*
* Takes the matrix lock to avoid actions on this device while removing
* Free the associated vfio_ap_queue structure
* @apdev: the AP device being removed
*
* Takes the matrix lock to avoid actions on this device while doing the remove.
*/
static void vfio_ap_queue_dev_remove(struct ap_device *apdev)
{

View File

@ -187,6 +187,8 @@ end_free:
* vfio_ap_irq_enable - Enable Interruption for a APQN
*
* @q: the vfio_ap_queue holding AQIC parameters
* @isc: the guest ISC to register with the GIB interface
* @nib: the notification indicator byte to pin.
*
* Pin the NIB saved in *q
* Register the guest ISC to GIB interface and retrieve the
@ -738,7 +740,6 @@ vfio_ap_mdev_verify_queues_reserved_for_apqi(struct ap_matrix_mdev *matrix_mdev,
* assign_domain_store - parses the APQI from @buf and sets the
* corresponding bit in the mediated matrix device's AQM
*
*
* @dev: the matrix device
* @attr: the mediated matrix device's assign_domain attribute
* @buf: a buffer containing the AP queue index (APQI) of the domain to
@ -866,7 +867,6 @@ static DEVICE_ATTR_WO(unassign_domain);
* assign_control_domain_store - parses the domain ID from @buf and sets
* the corresponding bit in the mediated matrix device's ADM
*
*
* @dev: the matrix device
* @attr: the mediated matrix device's assign_control_domain attribute
* @buf: a buffer containing the domain ID to be assigned
@ -1142,6 +1142,7 @@ static int vfio_ap_mdev_iommu_notifier(struct notifier_block *nb,
* by @matrix_mdev.
*
* @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

View File

@ -26,16 +26,18 @@
#define VFIO_AP_DRV_NAME "vfio_ap"
/**
* ap_matrix_dev - the AP matrix device structure
* struct ap_matrix_dev - Contains the data for the matrix device.
*
* @device: generic device structure associated with the AP matrix device
* @available_instances: number of mediated matrix devices that can be created
* @info: the struct containing the output from the PQAP(QCI) instruction
* mdev_list: the list of mediated matrix devices created
* lock: mutex for locking the AP matrix device. This lock will be
* @mdev_list: the list of mediated matrix devices created
* @lock: mutex for locking the AP matrix device. This lock will be
* taken every time we fiddle with state managed by the vfio_ap
* driver, be it using @mdev_list or writing the state of a
* single ap_matrix_mdev device. It's quite coarse but we don't
* expect much contention.
* @vfio_ap_drv: the vfio_ap device driver
*/
struct ap_matrix_dev {
struct device device;
@ -49,17 +51,19 @@ struct ap_matrix_dev {
extern struct ap_matrix_dev *matrix_dev;
/**
* The AP matrix is comprised of three bit masks identifying the adapters,
* queues (domains) and control domains that belong to an AP matrix. The bits i
* each mask, from least significant to most significant bit, correspond to IDs
* 0 to 255. When a bit is set, the corresponding ID belongs to the matrix.
* struct ap_matrix - matrix of adapters, domains and control domains
*
* @apm_max: max adapter number in @apm
* @apm identifies the AP adapters in the matrix
* @apm: identifies the AP adapters in the matrix
* @aqm_max: max domain number in @aqm
* @aqm identifies the AP queues (domains) in the matrix
* @aqm: identifies the AP queues (domains) in the matrix
* @adm_max: max domain number in @adm
* @adm identifies the AP control domains in the matrix
* @adm: identifies the AP control domains in the matrix
*
* The AP matrix is comprised of three bit masks identifying the adapters,
* queues (domains) and control domains that belong to an AP matrix. The bits in
* each mask, from left to right, correspond to IDs 0 to 255. When a bit is set
* the corresponding ID belongs to the matrix.
*/
struct ap_matrix {
unsigned long apm_max;
@ -71,13 +75,20 @@ struct ap_matrix {
};
/**
* struct ap_matrix_mdev - the mediated matrix device structure
* @list: allows the ap_matrix_mdev struct to be added to a list
* struct ap_matrix_mdev - Contains the data associated with a matrix mediated
* device.
* @vdev: the vfio device
* @node: allows the ap_matrix_mdev struct to be added to a list
* @matrix: the adapters, usage domains and control domains assigned to the
* mediated matrix device.
* @group_notifier: notifier block used for specifying callback function for
* handling the VFIO_GROUP_NOTIFY_SET_KVM event
* @iommu_notifier: notifier block used for specifying callback function for
* handling the VFIO_IOMMU_NOTIFY_DMA_UNMAP even
* @kvm: the struct holding guest's state
* @pqap_hook: the function pointer to the interception handler for the
* PQAP(AQIC) instruction.
* @mdev: the mediated device
*/
struct ap_matrix_mdev {
struct vfio_device vdev;
@ -90,6 +101,14 @@ struct ap_matrix_mdev {
struct mdev_device *mdev;
};
/**
* struct vfio_ap_queue - contains the data associated with a queue bound to the
* vfio_ap device driver
* @matrix_mdev: the matrix mediated device
* @saved_pfn: the guest PFN pinned for the guest
* @apqn: the APQN of the AP queue device
* @saved_isc: the guest ISC registered with the GIB interface
*/
struct vfio_ap_queue {
struct ap_matrix_mdev *matrix_mdev;
unsigned long saved_pfn;

View File

@ -82,8 +82,8 @@ static inline int zcrypt_process_rescan(void)
atomic_set(&zcrypt_rescan_req, 0);
atomic_inc(&zcrypt_rescan_count);
ap_bus_force_rescan();
ZCRYPT_DBF(DBF_INFO, "rescan count=%07d\n",
atomic_inc_return(&zcrypt_rescan_count));
ZCRYPT_DBF_INFO("%s rescan count=%07d\n", __func__,
atomic_inc_return(&zcrypt_rescan_count));
return 1;
}
return 0;
@ -341,8 +341,8 @@ static void zcdn_device_release(struct device *dev)
{
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
ZCRYPT_DBF(DBF_INFO, "releasing zcdn device %d:%d\n",
MAJOR(dev->devt), MINOR(dev->devt));
ZCRYPT_DBF_INFO("%s releasing zcdn device %d:%d\n",
__func__, MAJOR(dev->devt), MINOR(dev->devt));
kfree(zcdndev);
}
@ -407,8 +407,8 @@ static int zcdn_create(const char *name)
goto unlockout;
}
ZCRYPT_DBF(DBF_INFO, "created zcdn device %d:%d\n",
MAJOR(devt), MINOR(devt));
ZCRYPT_DBF_INFO("%s created zcdn device %d:%d\n",
__func__, MAJOR(devt), MINOR(devt));
unlockout:
mutex_unlock(&ap_perms_mutex);
@ -550,9 +550,8 @@ static inline int zcrypt_check_ioctl(struct ap_perms *perms,
}
if (rc)
ZCRYPT_DBF(DBF_WARN,
"ioctl check failed: ioctlnr=0x%04x rc=%d\n",
ioctlnr, rc);
ZCRYPT_DBF_WARN("%s ioctl check failed: ioctlnr=0x%04x rc=%d\n",
__func__, ioctlnr, rc);
return rc;
}
@ -1446,7 +1445,7 @@ static int icarsamodexpo_ioctl(struct ap_perms *perms, unsigned long arg)
if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
rc = -EIO;
if (rc) {
ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSAMODEXPO rc=%d\n", rc);
ZCRYPT_DBF_DBG("ioctl ICARSAMODEXPO rc=%d\n", rc);
return rc;
}
return put_user(mex.outputdatalength, &umex->outputdatalength);
@ -1491,7 +1490,7 @@ static int icarsacrt_ioctl(struct ap_perms *perms, unsigned long arg)
if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
rc = -EIO;
if (rc) {
ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSACRT rc=%d\n", rc);
ZCRYPT_DBF_DBG("ioctl ICARSACRT rc=%d\n", rc);
return rc;
}
return put_user(crt.outputdatalength, &ucrt->outputdatalength);
@ -1509,12 +1508,12 @@ static int zsecsendcprb_ioctl(struct ap_perms *perms, unsigned long arg)
return -EFAULT;
#ifdef CONFIG_ZCRYPT_DEBUG
if (xcRB.status & (1U << 31)) {
if ((xcRB.status & 0x8000FFFF) == 0x80004649 /* 'FI' */) {
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
tr.fi.cmd = (u16)(xcRB.status >> 16);
}
xcRB.status &= 0x0000FFFF;
xcRB.status = 0;
#endif
do {
@ -1536,8 +1535,8 @@ static int zsecsendcprb_ioctl(struct ap_perms *perms, unsigned long arg)
if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
rc = -EIO;
if (rc)
ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDCPRB rc=%d status=0x%x\n",
rc, xcRB.status);
ZCRYPT_DBF_DBG("ioctl ZSENDCPRB rc=%d status=0x%x\n",
rc, xcRB.status);
if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB)))
return -EFAULT;
return rc;
@ -1582,7 +1581,7 @@ static int zsendep11cprb_ioctl(struct ap_perms *perms, unsigned long arg)
if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
rc = -EIO;
if (rc)
ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDEP11CPRB rc=%d\n", rc);
ZCRYPT_DBF_DBG("ioctl ZSENDEP11CPRB rc=%d\n", rc);
if (copy_to_user(uxcrb, &xcrb, sizeof(xcrb)))
return -EFAULT;
return rc;
@ -1709,7 +1708,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
}
/* unknown ioctl number */
default:
ZCRYPT_DBF(DBF_DEBUG, "unknown ioctl 0x%08x\n", cmd);
ZCRYPT_DBF_DBG("unknown ioctl 0x%08x\n", cmd);
return -ENOIOCTLCMD;
}
}
@ -2048,16 +2047,14 @@ int zcrypt_wait_api_operational(void)
break;
case -ETIME:
/* timeout */
ZCRYPT_DBF(DBF_WARN,
"%s ap_wait_init_apqn_bindings_complete() returned with ETIME\n",
__func__);
ZCRYPT_DBF_WARN("%s ap_wait_init_apqn_bindings_complete()=ETIME\n",
__func__);
zcrypt_wait_api_state = -ETIME;
break;
default:
/* other failure */
ZCRYPT_DBF(DBF_DEBUG,
"%s ap_wait_init_apqn_bindings_complete() failure rc=%d\n",
__func__, rc);
ZCRYPT_DBF_DBG("%s ap_wait_init_apqn_bindings_complete()=%d\n",
__func__, rc);
break;
}
break;
@ -2079,7 +2076,7 @@ EXPORT_SYMBOL(zcrypt_wait_api_operational);
int __init zcrypt_debug_init(void)
{
zcrypt_dbf_info = debug_register("zcrypt", 1, 1,
zcrypt_dbf_info = debug_register("zcrypt", 2, 1,
DBF_MAX_SPRINTF_ARGS * sizeof(long));
debug_register_view(zcrypt_dbf_info, &debug_sprintf_view);
debug_set_level(zcrypt_dbf_info, DBF_ERR);

View File

@ -76,7 +76,7 @@ static ssize_t online_store(struct device *dev,
zc->online = online;
id = zc->card->id;
ZCRYPT_DBF(DBF_INFO, "card=%02x online=%d\n", id, online);
ZCRYPT_DBF_INFO("%s card=%02x online=%d\n", __func__, id, online);
ap_send_online_uevent(&ac->ap_dev, online);
@ -189,7 +189,8 @@ int zcrypt_card_register(struct zcrypt_card *zc)
zc->online = 1;
ZCRYPT_DBF(DBF_INFO, "card=%02x register online=1\n", zc->card->id);
ZCRYPT_DBF_INFO("%s card=%02x register online=1\n",
__func__, zc->card->id);
rc = sysfs_create_group(&zc->card->ap_dev.device.kobj,
&zcrypt_card_attr_group);
@ -211,7 +212,8 @@ EXPORT_SYMBOL(zcrypt_card_register);
*/
void zcrypt_card_unregister(struct zcrypt_card *zc)
{
ZCRYPT_DBF(DBF_INFO, "card=%02x unregister\n", zc->card->id);
ZCRYPT_DBF_INFO("%s card=%02x unregister\n",
__func__, zc->card->id);
spin_lock(&zcrypt_list_lock);
list_del_init(&zc->list);

View File

@ -17,7 +17,7 @@
#define RC2ERR(rc) ((rc) ? DBF_ERR : DBF_INFO)
#define RC2WARN(rc) ((rc) ? DBF_WARN : DBF_INFO)
#define DBF_MAX_SPRINTF_ARGS 5
#define DBF_MAX_SPRINTF_ARGS 6
#define ZCRYPT_DBF(...) \
debug_sprintf_event(zcrypt_dbf_info, ##__VA_ARGS__)

View File

@ -98,9 +98,8 @@ static inline int convert_error(struct zcrypt_queue *zq,
case REP88_ERROR_MESSAGE_MALFORMD: /* 0x22 */
case REP88_ERROR_KEY_TYPE: /* 0x34 */
/* RY indicates malformed request */
ZCRYPT_DBF(DBF_WARN,
"dev=%02x.%04x RY=0x%02x => rc=EINVAL\n",
card, queue, ehdr->reply_code);
ZCRYPT_DBF_WARN("%s dev=%02x.%04x RY=0x%02x => rc=EINVAL\n",
__func__, card, queue, ehdr->reply_code);
return -EINVAL;
case REP82_ERROR_MACHINE_FAILURE: /* 0x10 */
case REP82_ERROR_MESSAGE_TYPE: /* 0x20 */
@ -119,19 +118,18 @@ static inline int convert_error(struct zcrypt_queue *zq,
} __packed * head = reply->msg;
unsigned int apfs = *((u32 *)head->fmt2.apfs);
ZCRYPT_DBF(DBF_WARN,
"dev=%02x.%04x RY=0x%02x apfs=0x%x => bus rescan, rc=EAGAIN\n",
card, queue, ehdr->reply_code, apfs);
ZCRYPT_DBF_WARN(
"%s dev=%02x.%04x RY=0x%02x apfs=0x%x => bus rescan, rc=EAGAIN\n",
__func__, card, queue, ehdr->reply_code, apfs);
} else
ZCRYPT_DBF(DBF_WARN,
"dev=%02x.%04x RY=0x%02x => bus rescan, rc=EAGAIN\n",
card, queue, ehdr->reply_code);
ZCRYPT_DBF_WARN("%s dev=%02x.%04x RY=0x%02x => bus rescan, rc=EAGAIN\n",
__func__, card, queue,
ehdr->reply_code);
return -EAGAIN;
default:
/* Assume request is valid and a retry will be worth it */
ZCRYPT_DBF(DBF_WARN,
"dev=%02x.%04x RY=0x%02x => rc=EAGAIN\n",
card, queue, ehdr->reply_code);
ZCRYPT_DBF_WARN("%s dev=%02x.%04x RY=0x%02x => rc=EAGAIN\n",
__func__, card, queue, ehdr->reply_code);
return -EAGAIN;
}
}

View File

@ -369,12 +369,10 @@ static int convert_type80(struct zcrypt_queue *zq,
zq->online = 0;
pr_err("Crypto dev=%02x.%04x code=0x%02x => online=0 rc=EAGAIN\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
t80h->code);
ZCRYPT_DBF_ERR("dev=%02x.%04x code=0x%02x => online=0 rc=EAGAIN\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
t80h->code);
AP_QID_QUEUE(zq->queue->qid), t80h->code);
ZCRYPT_DBF_ERR("%s dev=%02x.%04x code=0x%02x => online=0 rc=EAGAIN\n",
__func__, AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid), t80h->code);
ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
return -EAGAIN;
}
@ -409,10 +407,10 @@ static int convert_response_cex2a(struct zcrypt_queue *zq,
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) rtype);
ZCRYPT_DBF_ERR("dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) rtype);
ZCRYPT_DBF_ERR(
"%s dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n",
__func__, AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid), (int) rtype);
ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
return -EAGAIN;
}

View File

@ -649,8 +649,8 @@ static int convert_type86_ica(struct zcrypt_queue *zq,
(service_rc == 8 && service_rs == 72) ||
(service_rc == 8 && service_rs == 770) ||
(service_rc == 12 && service_rs == 769)) {
ZCRYPT_DBF_WARN("dev=%02x.%04x rc/rs=%d/%d => rc=EINVAL\n",
AP_QID_CARD(zq->queue->qid),
ZCRYPT_DBF_WARN("%s dev=%02x.%04x rc/rs=%d/%d => rc=EINVAL\n",
__func__, AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) service_rc, (int) service_rs);
return -EINVAL;
@ -660,8 +660,8 @@ static int convert_type86_ica(struct zcrypt_queue *zq,
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) service_rc, (int) service_rs);
ZCRYPT_DBF_ERR("dev=%02x.%04x rc/rs=%d/%d => online=0 rc=EAGAIN\n",
AP_QID_CARD(zq->queue->qid),
ZCRYPT_DBF_ERR("%s dev=%02x.%04x rc/rs=%d/%d => online=0 rc=EAGAIN\n",
__func__, AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) service_rc, (int) service_rs);
ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
@ -806,10 +806,10 @@ static int convert_response_ica(struct zcrypt_queue *zq,
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) msg->hdr.type);
ZCRYPT_DBF_ERR("dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) msg->hdr.type);
ZCRYPT_DBF_ERR(
"%s dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n",
__func__, AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid), (int) msg->hdr.type);
ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
return -EAGAIN;
}
@ -841,10 +841,10 @@ static int convert_response_xcrb(bool userspace, struct zcrypt_queue *zq,
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) msg->hdr.type);
ZCRYPT_DBF_ERR("dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) msg->hdr.type);
ZCRYPT_DBF_ERR(
"%s dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n",
__func__, AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid), (int) msg->hdr.type);
ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
return -EAGAIN;
}
@ -871,10 +871,10 @@ static int convert_response_ep11_xcrb(bool userspace, struct zcrypt_queue *zq,
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) msg->hdr.type);
ZCRYPT_DBF_ERR("dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) msg->hdr.type);
ZCRYPT_DBF_ERR(
"%s dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n",
__func__, AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid), (int) msg->hdr.type);
ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
return -EAGAIN;
}
@ -902,10 +902,10 @@ static int convert_response_rng(struct zcrypt_queue *zq,
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) msg->hdr.type);
ZCRYPT_DBF_ERR("dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) msg->hdr.type);
ZCRYPT_DBF_ERR(
"%s dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n",
__func__, AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid), (int) msg->hdr.type);
ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
return -EAGAIN;
}

View File

@ -65,10 +65,9 @@ static ssize_t online_store(struct device *dev,
return -EINVAL;
zq->online = online;
ZCRYPT_DBF(DBF_INFO, "queue=%02x.%04x online=%d\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
online);
ZCRYPT_DBF_INFO("%s queue=%02x.%04x online=%d\n",
__func__, AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid), online);
ap_send_online_uevent(&aq->ap_dev, online);
@ -175,8 +174,9 @@ int zcrypt_queue_register(struct zcrypt_queue *zq)
zq->zcard = zc;
zq->online = 1; /* New devices are online by default. */
ZCRYPT_DBF(DBF_INFO, "queue=%02x.%04x register online=1\n",
AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid));
ZCRYPT_DBF_INFO("%s queue=%02x.%04x register online=1\n",
__func__, AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid));
list_add_tail(&zq->list, &zc->zqueues);
spin_unlock(&zcrypt_list_lock);
@ -215,8 +215,9 @@ void zcrypt_queue_unregister(struct zcrypt_queue *zq)
{
struct zcrypt_card *zc;
ZCRYPT_DBF(DBF_INFO, "queue=%02x.%04x unregister\n",
AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid));
ZCRYPT_DBF_INFO("%s queue=%02x.%04x unregister\n",
__func__, AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid));
zc = zq->zcard;
spin_lock(&zcrypt_list_lock);

View File

@ -26,7 +26,7 @@ config SAMPLE_TRACE_PRINTK
config SAMPLE_FTRACE_DIRECT
tristate "Build register_ftrace_direct() example"
depends on DYNAMIC_FTRACE_WITH_DIRECT_CALLS && m
depends on X86_64 # has x86_64 inlined asm
depends on HAVE_SAMPLE_FTRACE_DIRECT
help
This builds an ftrace direct function example
that hooks to wake_up_process and prints the parameters.
@ -224,3 +224,9 @@ config SAMPLE_WATCH_QUEUE
sb_notify() syscalls and the KEYCTL_WATCH_KEY keyctl() function.
endif # SAMPLES
config HAVE_SAMPLE_FTRACE_DIRECT
bool
config HAVE_SAMPLE_FTRACE_MULTI_DIRECT
bool

View File

@ -21,6 +21,7 @@ subdir-$(CONFIG_SAMPLE_TIMER) += timers
obj-$(CONFIG_SAMPLE_TRACE_EVENTS) += trace_events/
obj-$(CONFIG_SAMPLE_TRACE_PRINTK) += trace_printk/
obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace/
obj-$(CONFIG_SAMPLE_FTRACE_MULTI_DIRECT) += ftrace/
obj-$(CONFIG_SAMPLE_TRACE_ARRAY) += ftrace/
subdir-$(CONFIG_SAMPLE_UHID) += uhid
obj-$(CONFIG_VIDEO_PCI_SKELETON) += v4l/

View File

@ -3,7 +3,7 @@
obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct.o
obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct-too.o
obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct-modify.o
obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct-multi.o
obj-$(CONFIG_SAMPLE_FTRACE_MULTI_DIRECT) += ftrace-direct-multi.o
CFLAGS_sample-trace-array.o := -I$(src)
obj-$(CONFIG_SAMPLE_TRACE_ARRAY) += sample-trace-array.o

View File

@ -2,6 +2,7 @@
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/ftrace.h>
#include <asm/asm-offsets.h>
void my_direct_func1(void)
{
@ -18,6 +19,8 @@ extern void my_tramp2(void *);
static unsigned long my_ip = (unsigned long)schedule;
#ifdef CONFIG_X86_64
asm (
" .pushsection .text, \"ax\", @progbits\n"
" .type my_tramp1, @function\n"
@ -41,6 +44,47 @@ asm (
" .popsection\n"
);
#endif /* CONFIG_X86_64 */
#ifdef CONFIG_S390
asm (
" .pushsection .text, \"ax\", @progbits\n"
" .type my_tramp1, @function\n"
" .globl my_tramp1\n"
" my_tramp1:"
" lgr %r1,%r15\n"
" stmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
" stg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
" aghi %r15,"__stringify(-STACK_FRAME_OVERHEAD)"\n"
" stg %r1,"__stringify(__SF_BACKCHAIN)"(%r15)\n"
" brasl %r14,my_direct_func1\n"
" aghi %r15,"__stringify(STACK_FRAME_OVERHEAD)"\n"
" lmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
" lg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
" lgr %r1,%r0\n"
" br %r1\n"
" .size my_tramp1, .-my_tramp1\n"
" .type my_tramp2, @function\n"
" .globl my_tramp2\n"
" my_tramp2:"
" lgr %r1,%r15\n"
" stmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
" stg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
" aghi %r15,"__stringify(-STACK_FRAME_OVERHEAD)"\n"
" stg %r1,"__stringify(__SF_BACKCHAIN)"(%r15)\n"
" brasl %r14,my_direct_func2\n"
" aghi %r15,"__stringify(STACK_FRAME_OVERHEAD)"\n"
" lmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
" lg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
" lgr %r1,%r0\n"
" br %r1\n"
" .size my_tramp2, .-my_tramp2\n"
" .popsection\n"
);
#endif /* CONFIG_S390 */
static unsigned long my_tramp = (unsigned long)my_tramp1;
static unsigned long tramps[2] = {
(unsigned long)my_tramp1,

View File

@ -3,6 +3,7 @@
#include <linux/mm.h> /* for handle_mm_fault() */
#include <linux/ftrace.h>
#include <asm/asm-offsets.h>
void my_direct_func(struct vm_area_struct *vma,
unsigned long address, unsigned int flags)
@ -13,6 +14,8 @@ void my_direct_func(struct vm_area_struct *vma,
extern void my_tramp(void *);
#ifdef CONFIG_X86_64
asm (
" .pushsection .text, \"ax\", @progbits\n"
" .type my_tramp, @function\n"
@ -33,6 +36,31 @@ asm (
" .popsection\n"
);
#endif /* CONFIG_X86_64 */
#ifdef CONFIG_S390
asm (
" .pushsection .text, \"ax\", @progbits\n"
" .type my_tramp, @function\n"
" .globl my_tramp\n"
" my_tramp:"
" lgr %r1,%r15\n"
" stmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
" stg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
" aghi %r15,"__stringify(-STACK_FRAME_OVERHEAD)"\n"
" stg %r1,"__stringify(__SF_BACKCHAIN)"(%r15)\n"
" brasl %r14,my_direct_func\n"
" aghi %r15,"__stringify(STACK_FRAME_OVERHEAD)"\n"
" lmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
" lg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
" lgr %r1,%r0\n"
" br %r1\n"
" .size my_tramp, .-my_tramp\n"
" .popsection\n"
);
#endif /* CONFIG_S390 */
static int __init ftrace_direct_init(void)
{

View File

@ -3,6 +3,7 @@
#include <linux/sched.h> /* for wake_up_process() */
#include <linux/ftrace.h>
#include <asm/asm-offsets.h>
void my_direct_func(struct task_struct *p)
{
@ -11,6 +12,8 @@ void my_direct_func(struct task_struct *p)
extern void my_tramp(void *);
#ifdef CONFIG_X86_64
asm (
" .pushsection .text, \"ax\", @progbits\n"
" .type my_tramp, @function\n"
@ -27,6 +30,31 @@ asm (
" .popsection\n"
);
#endif /* CONFIG_X86_64 */
#ifdef CONFIG_S390
asm (
" .pushsection .text, \"ax\", @progbits\n"
" .type my_tramp, @function\n"
" .globl my_tramp\n"
" my_tramp:"
" lgr %r1,%r15\n"
" stmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
" stg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
" aghi %r15,"__stringify(-STACK_FRAME_OVERHEAD)"\n"
" stg %r1,"__stringify(__SF_BACKCHAIN)"(%r15)\n"
" brasl %r14,my_direct_func\n"
" aghi %r15,"__stringify(STACK_FRAME_OVERHEAD)"\n"
" lmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
" lg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
" lgr %r1,%r0\n"
" br %r1\n"
" .size my_tramp, .-my_tramp\n"
" .popsection\n"
);
#endif /* CONFIG_S390 */
static int __init ftrace_direct_init(void)
{

View File

@ -22,6 +22,9 @@ ppc64*)
ppc*)
ARG1=%r3
;;
s390*)
ARG1=%r2
;;
*)
echo "Please implement other architecture here"
exit_untested

View File

@ -32,6 +32,10 @@ ppc*)
GOODREG=%r3
BADREG=%msr
;;
s390*)
GOODREG=%r2
BADREG=%s2
;;
*)
echo "Please implement other architecture here"
exit_untested