more s390 updates for 6.10 merge window
- Switch read and write software bits for PUDs - Add missing hardware bits for PUDs and PMDs - Generate unwind information for C modules to fix GDB unwind error for vDSO functions - Create .build-id links for unstripped vDSO files to enable vDSO debugging with symbols - Use standard stack frame layout for vDSO generated stack frames to manually walk stack frames without DWARF information - Rework perf_callchain_user() and arch_stack_walk_user() functions to reduce code duplication - Skip first stack frame when walking user stack - Add basic checks to identify invalid instruction pointers when walking stack frames - Introduce and use struct stack_frame_vdso_wrapper within vDSO user wrapper code to automatically generate an asm-offset define. Also use STACK_FRAME_USER_OVERHEAD instead of STACK_FRAME_OVERHEAD to document that the code works with user space stack - Clear the backchain of the extra stack frame added by the vDSO user wrapper code. This allows the user stack walker to detect and skip the non-standard stack frame. Without this an incorrect instruction pointer would be added to stack traces. - Rewrite psw_idle() function in C to ease maintenance and further enhancements - Remove get_vtimer() function and use get_cpu_timer() instead - Mark psw variable in __load_psw_mask() as __unitialized to avoid superfluous clearing of PSW - Remove obsolete and superfluous comment about removed TIF_FPU flag - Replace memzero_explicit() and kfree() with kfree_sensitive() to fix warnings reported by Coccinelle - Wipe sensitive data and all copies of protected- or secure-keys from stack when an IOCTL fails - Both do_airq_interrupt() and do_io_interrupt() functions set CIF_NOHZ_DELAY flag. Move it in do_io_irq() to simplify the code - Provide iucv_alloc_device() and iucv_release_device() helpers, which can be used to deduplicate more or less identical IUCV device allocation and release code in four different drivers - Make use of iucv_alloc_device() and iucv_release_device() helpers to get rid of quite some code and also remove a cast to an incompatible function (clang W=1) - There is no user of iucv_root outside of the core IUCV code left. Therefore remove the EXPORT_SYMBOL - __apply_alternatives() contains a runtime check which verifies that the size of the to be patched code area is even. Convert this to a compile time check - Increase size of buffers for sending z/VM CP DIAGNOSE X'008' commands from 128 to 240 - Do not accept z/VM CP DIAGNOSE X'008' commands longer than maximally allowed - Use correct defines IPL_BP_NVME_LEN and IPL_BP0_NVME_LEN instead of IPL_BP_FCP_LEN and IPL_BP0_FCP_LEN ones to initialize NVMe reIPL block on 'scp_data' sysfs attribute update - Initialize the correct fields of the NVMe dump block, which were confused with FCP fields - Refactor macros for 'scp_data' (re-)IPL sysfs attribute to reduce code duplication - Introduce 'scp_data' sysfs attribute for dump IPL to allow tools such as dumpconf passing additional kernel command line parameters to a stand-alone dumper - Rework the CPACF query functions to use the correct RRE or RRF instruction formats and set instruction register fields correctly - Instead of calling BUG() at runtime force a link error during compile when a unsupported opcode is used with __cpacf_query() or __cpacf_check_opcode() functions - Fix a crash in ap_parse_bitmap_str() function on /sys/bus/ap/apmask or /sys/bus/ap/aqmask sysfs file update with a relative mask value - Fix "bindings complete" udev event which should be sent once all AP devices have been bound to device drivers and again when unbind/bind actions take place and all AP devices are bound again - Facility list alt_stfle_fac_list is nowhere used in the decompressor, therefore remove it there - Remove custom kprobes insn slot allocator in favour of the standard module_alloc() one, since kernel image and module areas are located within 4GB - Use kvcalloc() instead of kvmalloc_array() in zcrypt driver to avoid calling memset() with a large byte count and get rid of the sparse warning as result -----BEGIN PGP SIGNATURE----- iI0EABYIADUWIQQrtrZiYVkVzKQcYivNdxKlNrRb8AUCZkyx2BccYWdvcmRlZXZA bGludXguaWJtLmNvbQAKCRDNdxKlNrRb8PYZAP9KxEfTyUmIh61Gx8+m3BW5dy7p E2Q8yotlUpGj49ul+AD8CEAyTiWR95AlMOVZZLV/0J7XIjhALvpKAGfiJWkvXgc= =pife -----END PGP SIGNATURE----- Merge tag 's390-6.10-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux Pull more s390 updates from Alexander Gordeev: - Switch read and write software bits for PUDs - Add missing hardware bits for PUDs and PMDs - Generate unwind information for C modules to fix GDB unwind error for vDSO functions - Create .build-id links for unstripped vDSO files to enable vDSO debugging with symbols - Use standard stack frame layout for vDSO generated stack frames to manually walk stack frames without DWARF information - Rework perf_callchain_user() and arch_stack_walk_user() functions to reduce code duplication - Skip first stack frame when walking user stack - Add basic checks to identify invalid instruction pointers when walking stack frames - Introduce and use struct stack_frame_vdso_wrapper within vDSO user wrapper code to automatically generate an asm-offset define. Also use STACK_FRAME_USER_OVERHEAD instead of STACK_FRAME_OVERHEAD to document that the code works with user space stack - Clear the backchain of the extra stack frame added by the vDSO user wrapper code. This allows the user stack walker to detect and skip the non-standard stack frame. Without this an incorrect instruction pointer would be added to stack traces. - Rewrite psw_idle() function in C to ease maintenance and further enhancements - Remove get_vtimer() function and use get_cpu_timer() instead - Mark psw variable in __load_psw_mask() as __unitialized to avoid superfluous clearing of PSW - Remove obsolete and superfluous comment about removed TIF_FPU flag - Replace memzero_explicit() and kfree() with kfree_sensitive() to fix warnings reported by Coccinelle - Wipe sensitive data and all copies of protected- or secure-keys from stack when an IOCTL fails - Both do_airq_interrupt() and do_io_interrupt() functions set CIF_NOHZ_DELAY flag. Move it in do_io_irq() to simplify the code - Provide iucv_alloc_device() and iucv_release_device() helpers, which can be used to deduplicate more or less identical IUCV device allocation and release code in four different drivers - Make use of iucv_alloc_device() and iucv_release_device() helpers to get rid of quite some code and also remove a cast to an incompatible function (clang W=1) - There is no user of iucv_root outside of the core IUCV code left. Therefore remove the EXPORT_SYMBOL - __apply_alternatives() contains a runtime check which verifies that the size of the to be patched code area is even. Convert this to a compile time check - Increase size of buffers for sending z/VM CP DIAGNOSE X'008' commands from 128 to 240 - Do not accept z/VM CP DIAGNOSE X'008' commands longer than maximally allowed - Use correct defines IPL_BP_NVME_LEN and IPL_BP0_NVME_LEN instead of IPL_BP_FCP_LEN and IPL_BP0_FCP_LEN ones to initialize NVMe reIPL block on 'scp_data' sysfs attribute update - Initialize the correct fields of the NVMe dump block, which were confused with FCP fields - Refactor macros for 'scp_data' (re-)IPL sysfs attribute to reduce code duplication - Introduce 'scp_data' sysfs attribute for dump IPL to allow tools such as dumpconf passing additional kernel command line parameters to a stand-alone dumper - Rework the CPACF query functions to use the correct RRE or RRF instruction formats and set instruction register fields correctly - Instead of calling BUG() at runtime force a link error during compile when a unsupported opcode is used with __cpacf_query() or __cpacf_check_opcode() functions - Fix a crash in ap_parse_bitmap_str() function on /sys/bus/ap/apmask or /sys/bus/ap/aqmask sysfs file update with a relative mask value - Fix "bindings complete" udev event which should be sent once all AP devices have been bound to device drivers and again when unbind/bind actions take place and all AP devices are bound again - Facility list alt_stfle_fac_list is nowhere used in the decompressor, therefore remove it there - Remove custom kprobes insn slot allocator in favour of the standard module_alloc() one, since kernel image and module areas are located within 4GB - Use kvcalloc() instead of kvmalloc_array() in zcrypt driver to avoid calling memset() with a large byte count and get rid of the sparse warning as result * tag 's390-6.10-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (39 commits) s390/zcrypt: Use kvcalloc() instead of kvmalloc_array() s390/kprobes: Remove custom insn slot allocator s390/boot: Remove alt_stfle_fac_list from decompressor s390/ap: Fix bind complete udev event sent after each AP bus scan s390/ap: Fix crash in AP internal function modify_bitmap() s390/cpacf: Make use of invalid opcode produce a link error s390/cpacf: Split and rework cpacf query functions s390/ipl: Introduce sysfs attribute 'scp_data' for dump ipl s390/ipl: Introduce macros for (re)ipl sysfs attribute 'scp_data' s390/ipl: Fix incorrect initialization of nvme dump block s390/ipl: Fix incorrect initialization of len fields in nvme reipl block s390/ipl: Do not accept z/VM CP diag X'008' cmds longer than max length s390/ipl: Fix size of vmcmd buffers for sending z/VM CP diag X'008' cmds s390/alternatives: Convert runtime sanity check into compile time check s390/iucv: Unexport iucv_root tty: hvc-iucv: Make use of iucv_alloc_device() s390/smsgiucv_app: Make use of iucv_alloc_device() s390/netiucv: Make use of iucv_alloc_device() s390/vmlogrdr: Make use of iucv_alloc_device() s390/iucv: Provide iucv_alloc_device() / iucv_release_device() ...
This commit is contained in:
commit
2a8120d7b4
arch/s390
boot
include/asm
kernel
drivers
s390
char
cio
crypto
net
tty/hvc
include/net/iucv
net/iucv
scripts
@ -32,7 +32,6 @@ unsigned long __bootdata_preserved(MODULES_END);
|
||||
unsigned long __bootdata_preserved(max_mappable);
|
||||
|
||||
u64 __bootdata_preserved(stfle_fac_list[16]);
|
||||
u64 __bootdata_preserved(alt_stfle_fac_list[16]);
|
||||
struct oldmem_data __bootdata_preserved(oldmem_data);
|
||||
|
||||
struct machine_info machine;
|
||||
|
@ -15,6 +15,7 @@
|
||||
.long \alt_start - .
|
||||
.word \feature
|
||||
.byte \orig_end - \orig_start
|
||||
.org . - ( \orig_end - \orig_start ) & 1
|
||||
.org . - ( \orig_end - \orig_start ) + ( \alt_end - \alt_start )
|
||||
.org . - ( \alt_end - \alt_start ) + ( \orig_end - \orig_start )
|
||||
.endm
|
||||
|
@ -53,6 +53,7 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
|
||||
"\t.long " b_altinstr(num)"b - .\n" /* alt instruction */ \
|
||||
"\t.word " __stringify(facility) "\n" /* facility bit */ \
|
||||
"\t.byte " oldinstr_len "\n" /* instruction len */ \
|
||||
"\t.org . - (" oldinstr_len ") & 1\n" \
|
||||
"\t.org . - (" oldinstr_len ") + (" altinstr_len(num) ")\n" \
|
||||
"\t.org . - (" altinstr_len(num) ") + (" oldinstr_len ")\n"
|
||||
|
||||
|
@ -166,28 +166,86 @@
|
||||
|
||||
typedef struct { unsigned char bytes[16]; } cpacf_mask_t;
|
||||
|
||||
/**
|
||||
* cpacf_query() - check if a specific CPACF function is available
|
||||
* @opcode: the opcode of the crypto instruction
|
||||
* @func: the function code to test for
|
||||
*
|
||||
* Executes the query function for the given crypto instruction @opcode
|
||||
* and checks if @func is available
|
||||
*
|
||||
* Returns 1 if @func is available for @opcode, 0 otherwise
|
||||
/*
|
||||
* Prototype for a not existing function to produce a link
|
||||
* error if __cpacf_query() or __cpacf_check_opcode() is used
|
||||
* with an invalid compile time const opcode.
|
||||
*/
|
||||
static __always_inline void __cpacf_query(unsigned int opcode, cpacf_mask_t *mask)
|
||||
void __cpacf_bad_opcode(void);
|
||||
|
||||
static __always_inline void __cpacf_query_rre(u32 opc, u8 r1, u8 r2,
|
||||
cpacf_mask_t *mask)
|
||||
{
|
||||
asm volatile(
|
||||
" lghi 0,0\n" /* query function */
|
||||
" lgr 1,%[mask]\n"
|
||||
" spm 0\n" /* pckmo doesn't change the cc */
|
||||
/* Parameter regs are ignored, but must be nonzero and unique */
|
||||
"0: .insn rrf,%[opc] << 16,2,4,6,0\n"
|
||||
" brc 1,0b\n" /* handle partial completion */
|
||||
: "=m" (*mask)
|
||||
: [mask] "d" ((unsigned long)mask), [opc] "i" (opcode)
|
||||
: "cc", "0", "1");
|
||||
" la %%r1,%[mask]\n"
|
||||
" xgr %%r0,%%r0\n"
|
||||
" .insn rre,%[opc] << 16,%[r1],%[r2]\n"
|
||||
: [mask] "=R" (*mask)
|
||||
: [opc] "i" (opc),
|
||||
[r1] "i" (r1), [r2] "i" (r2)
|
||||
: "cc", "r0", "r1");
|
||||
}
|
||||
|
||||
static __always_inline void __cpacf_query_rrf(u32 opc,
|
||||
u8 r1, u8 r2, u8 r3, u8 m4,
|
||||
cpacf_mask_t *mask)
|
||||
{
|
||||
asm volatile(
|
||||
" la %%r1,%[mask]\n"
|
||||
" xgr %%r0,%%r0\n"
|
||||
" .insn rrf,%[opc] << 16,%[r1],%[r2],%[r3],%[m4]\n"
|
||||
: [mask] "=R" (*mask)
|
||||
: [opc] "i" (opc), [r1] "i" (r1), [r2] "i" (r2),
|
||||
[r3] "i" (r3), [m4] "i" (m4)
|
||||
: "cc", "r0", "r1");
|
||||
}
|
||||
|
||||
static __always_inline void __cpacf_query(unsigned int opcode,
|
||||
cpacf_mask_t *mask)
|
||||
{
|
||||
switch (opcode) {
|
||||
case CPACF_KDSA:
|
||||
__cpacf_query_rre(CPACF_KDSA, 0, 2, mask);
|
||||
break;
|
||||
case CPACF_KIMD:
|
||||
__cpacf_query_rre(CPACF_KIMD, 0, 2, mask);
|
||||
break;
|
||||
case CPACF_KLMD:
|
||||
__cpacf_query_rre(CPACF_KLMD, 0, 2, mask);
|
||||
break;
|
||||
case CPACF_KM:
|
||||
__cpacf_query_rre(CPACF_KM, 2, 4, mask);
|
||||
break;
|
||||
case CPACF_KMA:
|
||||
__cpacf_query_rrf(CPACF_KMA, 2, 4, 6, 0, mask);
|
||||
break;
|
||||
case CPACF_KMAC:
|
||||
__cpacf_query_rre(CPACF_KMAC, 0, 2, mask);
|
||||
break;
|
||||
case CPACF_KMC:
|
||||
__cpacf_query_rre(CPACF_KMC, 2, 4, mask);
|
||||
break;
|
||||
case CPACF_KMCTR:
|
||||
__cpacf_query_rrf(CPACF_KMCTR, 2, 4, 6, 0, mask);
|
||||
break;
|
||||
case CPACF_KMF:
|
||||
__cpacf_query_rre(CPACF_KMF, 2, 4, mask);
|
||||
break;
|
||||
case CPACF_KMO:
|
||||
__cpacf_query_rre(CPACF_KMO, 2, 4, mask);
|
||||
break;
|
||||
case CPACF_PCC:
|
||||
__cpacf_query_rre(CPACF_PCC, 0, 0, mask);
|
||||
break;
|
||||
case CPACF_PCKMO:
|
||||
__cpacf_query_rre(CPACF_PCKMO, 0, 0, mask);
|
||||
break;
|
||||
case CPACF_PRNO:
|
||||
__cpacf_query_rre(CPACF_PRNO, 2, 4, mask);
|
||||
break;
|
||||
default:
|
||||
__cpacf_bad_opcode();
|
||||
}
|
||||
}
|
||||
|
||||
static __always_inline int __cpacf_check_opcode(unsigned int opcode)
|
||||
@ -211,10 +269,21 @@ static __always_inline int __cpacf_check_opcode(unsigned int opcode)
|
||||
case CPACF_KMA:
|
||||
return test_facility(146); /* check for MSA8 */
|
||||
default:
|
||||
BUG();
|
||||
__cpacf_bad_opcode();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* cpacf_query() - check if a specific CPACF function is available
|
||||
* @opcode: the opcode of the crypto instruction
|
||||
* @func: the function code to test for
|
||||
*
|
||||
* Executes the query function for the given crypto instruction @opcode
|
||||
* and checks if @func is available
|
||||
*
|
||||
* Returns 1 if @func is available for @opcode, 0 otherwise
|
||||
*/
|
||||
static __always_inline int cpacf_query(unsigned int opcode, cpacf_mask_t *mask)
|
||||
{
|
||||
if (__cpacf_check_opcode(opcode)) {
|
||||
|
@ -268,12 +268,14 @@ static inline int is_module_addr(void *addr)
|
||||
#define _REGION3_ENTRY (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_LENGTH)
|
||||
#define _REGION3_ENTRY_EMPTY (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INVALID)
|
||||
|
||||
#define _REGION3_ENTRY_HARDWARE_BITS 0xfffffffffffff6ffUL
|
||||
#define _REGION3_ENTRY_HARDWARE_BITS_LARGE 0xffffffff8001073cUL
|
||||
#define _REGION3_ENTRY_ORIGIN_LARGE ~0x7fffffffUL /* large page address */
|
||||
#define _REGION3_ENTRY_DIRTY 0x2000 /* SW region dirty bit */
|
||||
#define _REGION3_ENTRY_YOUNG 0x1000 /* SW region young bit */
|
||||
#define _REGION3_ENTRY_LARGE 0x0400 /* RTTE-format control, large page */
|
||||
#define _REGION3_ENTRY_READ 0x0002 /* SW region read bit */
|
||||
#define _REGION3_ENTRY_WRITE 0x0001 /* SW region write bit */
|
||||
#define _REGION3_ENTRY_WRITE 0x0002 /* SW region write bit */
|
||||
#define _REGION3_ENTRY_READ 0x0001 /* SW region read bit */
|
||||
|
||||
#ifdef CONFIG_MEM_SOFT_DIRTY
|
||||
#define _REGION3_ENTRY_SOFT_DIRTY 0x4000 /* SW region soft dirty bit */
|
||||
@ -284,9 +286,9 @@ static inline int is_module_addr(void *addr)
|
||||
#define _REGION_ENTRY_BITS 0xfffffffffffff22fUL
|
||||
|
||||
/* Bits in the segment table entry */
|
||||
#define _SEGMENT_ENTRY_BITS 0xfffffffffffffe33UL
|
||||
#define _SEGMENT_ENTRY_HARDWARE_BITS 0xfffffffffffffe30UL
|
||||
#define _SEGMENT_ENTRY_HARDWARE_BITS_LARGE 0xfffffffffff00730UL
|
||||
#define _SEGMENT_ENTRY_BITS 0xfffffffffffffe3fUL
|
||||
#define _SEGMENT_ENTRY_HARDWARE_BITS 0xfffffffffffffe3cUL
|
||||
#define _SEGMENT_ENTRY_HARDWARE_BITS_LARGE 0xfffffffffff1073cUL
|
||||
#define _SEGMENT_ENTRY_ORIGIN_LARGE ~0xfffffUL /* large page address */
|
||||
#define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* page table origin */
|
||||
#define _SEGMENT_ENTRY_PROTECT 0x200 /* segment protection bit */
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <asm/setup.h>
|
||||
#include <asm/runtime_instr.h>
|
||||
#include <asm/irqflags.h>
|
||||
#include <asm/alternative.h>
|
||||
|
||||
typedef long (*sys_call_ptr_t)(struct pt_regs *regs);
|
||||
|
||||
@ -92,12 +93,21 @@ static inline void get_cpu_id(struct cpuid *ptr)
|
||||
asm volatile("stidp %0" : "=Q" (*ptr));
|
||||
}
|
||||
|
||||
static __always_inline unsigned long get_cpu_timer(void)
|
||||
{
|
||||
unsigned long timer;
|
||||
|
||||
asm volatile("stpt %[timer]" : [timer] "=Q" (timer));
|
||||
return timer;
|
||||
}
|
||||
|
||||
void s390_adjust_jiffies(void);
|
||||
void s390_update_cpu_mhz(void);
|
||||
void cpu_detect_mhz_feature(void);
|
||||
|
||||
extern const struct seq_operations cpuinfo_op;
|
||||
extern void execve_tail(void);
|
||||
unsigned long vdso_text_size(void);
|
||||
unsigned long vdso_size(void);
|
||||
|
||||
/*
|
||||
@ -304,8 +314,8 @@ static inline void __load_psw(psw_t psw)
|
||||
*/
|
||||
static __always_inline void __load_psw_mask(unsigned long mask)
|
||||
{
|
||||
psw_t psw __uninitialized;
|
||||
unsigned long addr;
|
||||
psw_t psw;
|
||||
|
||||
psw.mask = mask;
|
||||
|
||||
@ -393,6 +403,11 @@ static __always_inline bool regs_irqs_disabled(struct pt_regs *regs)
|
||||
return arch_irqs_disabled_flags(regs->psw.mask);
|
||||
}
|
||||
|
||||
static __always_inline void bpon(void)
|
||||
{
|
||||
asm volatile(ALTERNATIVE("nop", ".insn rrf,0xb2e80000,0,0,13,0", 82));
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* __ASM_S390_PROCESSOR_H */
|
||||
|
@ -2,6 +2,7 @@
|
||||
#ifndef _ASM_S390_STACKTRACE_H
|
||||
#define _ASM_S390_STACKTRACE_H
|
||||
|
||||
#include <linux/stacktrace.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/ptrace.h>
|
||||
|
||||
@ -12,6 +13,17 @@ struct stack_frame_user {
|
||||
unsigned long empty2[4];
|
||||
};
|
||||
|
||||
struct stack_frame_vdso_wrapper {
|
||||
struct stack_frame_user sf;
|
||||
unsigned long return_address;
|
||||
};
|
||||
|
||||
struct perf_callchain_entry_ctx;
|
||||
|
||||
void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *cookie,
|
||||
struct perf_callchain_entry_ctx *entry,
|
||||
const struct pt_regs *regs, bool perf);
|
||||
|
||||
enum stack_type {
|
||||
STACK_TYPE_UNKNOWN,
|
||||
STACK_TYPE_TASK,
|
||||
|
@ -59,7 +59,6 @@ obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o
|
||||
obj-$(CONFIG_COMPAT) += $(compat-obj-y)
|
||||
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes_insn_page.o
|
||||
obj-$(CONFIG_KPROBES) += mcount.o
|
||||
obj-$(CONFIG_RETHOOK) += rethook.o
|
||||
obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o
|
||||
|
@ -33,13 +33,6 @@ static void __init_or_module __apply_alternatives(struct alt_instr *start,
|
||||
|
||||
if (!__test_facility(a->facility, alt_stfle_fac_list))
|
||||
continue;
|
||||
|
||||
if (unlikely(a->instrlen % 2)) {
|
||||
WARN_ONCE(1, "cpu alternatives instructions length is "
|
||||
"odd, skipping patching\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
s390_kernel_write(instr, replacement, a->instrlen);
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include <linux/purgatory.h>
|
||||
#include <linux/pgtable.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <asm/idle.h>
|
||||
#include <asm/gmap.h>
|
||||
#include <asm/stacktrace.h>
|
||||
|
||||
@ -66,10 +65,10 @@ int main(void)
|
||||
OFFSET(__SF_SIE_CONTROL_PHYS, stack_frame, sie_control_block_phys);
|
||||
DEFINE(STACK_FRAME_OVERHEAD, sizeof(struct stack_frame));
|
||||
BLANK();
|
||||
/* idle data offsets */
|
||||
OFFSET(__CLOCK_IDLE_ENTER, s390_idle_data, clock_idle_enter);
|
||||
OFFSET(__TIMER_IDLE_ENTER, s390_idle_data, timer_idle_enter);
|
||||
OFFSET(__MT_CYCLES_ENTER, s390_idle_data, mt_cycles_enter);
|
||||
OFFSET(__SFUSER_BACKCHAIN, stack_frame_user, back_chain);
|
||||
DEFINE(STACK_FRAME_USER_OVERHEAD, sizeof(struct stack_frame_user));
|
||||
OFFSET(__SFVDSO_RETURN_ADDRESS, stack_frame_vdso_wrapper, return_address);
|
||||
DEFINE(STACK_FRAME_VDSO_OVERHEAD, sizeof(struct stack_frame_vdso_wrapper));
|
||||
BLANK();
|
||||
/* hardware defined lowcore locations 0x000 - 0x1ff */
|
||||
OFFSET(__LC_EXT_PARAMS, lowcore, ext_params);
|
||||
|
@ -440,29 +440,6 @@ SYM_CODE_END(\name)
|
||||
INT_HANDLER ext_int_handler,__LC_EXT_OLD_PSW,do_ext_irq
|
||||
INT_HANDLER io_int_handler,__LC_IO_OLD_PSW,do_io_irq
|
||||
|
||||
/*
|
||||
* Load idle PSW.
|
||||
*/
|
||||
SYM_FUNC_START(psw_idle)
|
||||
stg %r14,(__SF_GPRS+8*8)(%r15)
|
||||
stg %r3,__SF_EMPTY(%r15)
|
||||
larl %r1,psw_idle_exit
|
||||
stg %r1,__SF_EMPTY+8(%r15)
|
||||
larl %r1,smp_cpu_mtid
|
||||
llgf %r1,0(%r1)
|
||||
ltgr %r1,%r1
|
||||
jz .Lpsw_idle_stcctm
|
||||
.insn rsy,0xeb0000000017,%r1,5,__MT_CYCLES_ENTER(%r2)
|
||||
.Lpsw_idle_stcctm:
|
||||
oi __LC_CPU_FLAGS+7,_CIF_ENABLED_WAIT
|
||||
BPON
|
||||
stckf __CLOCK_IDLE_ENTER(%r2)
|
||||
stpt __TIMER_IDLE_ENTER(%r2)
|
||||
lpswe __SF_EMPTY(%r15)
|
||||
SYM_INNER_LABEL(psw_idle_exit, SYM_L_GLOBAL)
|
||||
BR_EX %r14
|
||||
SYM_FUNC_END(psw_idle)
|
||||
|
||||
/*
|
||||
* Machine check handler routines
|
||||
*/
|
||||
|
@ -57,9 +57,13 @@ void noinstr arch_cpu_idle(void)
|
||||
psw_mask = PSW_KERNEL_BITS | PSW_MASK_WAIT |
|
||||
PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;
|
||||
clear_cpu_flag(CIF_NOHZ_DELAY);
|
||||
|
||||
/* psw_idle() returns with interrupts disabled. */
|
||||
psw_idle(idle, psw_mask);
|
||||
set_cpu_flag(CIF_ENABLED_WAIT);
|
||||
if (smp_cpu_mtid)
|
||||
stcctm(MT_DIAG, smp_cpu_mtid, (u64 *)&idle->mt_cycles_enter);
|
||||
idle->clock_idle_enter = get_tod_clock_fast();
|
||||
idle->timer_idle_enter = get_cpu_timer();
|
||||
bpon();
|
||||
__load_psw_mask(psw_mask);
|
||||
}
|
||||
|
||||
static ssize_t show_idle_count(struct device *dev,
|
||||
|
@ -267,7 +267,11 @@ static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
|
||||
struct kobj_attribute *attr, \
|
||||
const char *buf, size_t len) \
|
||||
{ \
|
||||
strscpy(_value, buf, sizeof(_value)); \
|
||||
if (len >= sizeof(_value)) \
|
||||
return -E2BIG; \
|
||||
len = strscpy(_value, buf, sizeof(_value)); \
|
||||
if (len < 0) \
|
||||
return len; \
|
||||
strim(_value); \
|
||||
return len; \
|
||||
} \
|
||||
@ -276,6 +280,61 @@ static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
|
||||
sys_##_prefix##_##_name##_show, \
|
||||
sys_##_prefix##_##_name##_store)
|
||||
|
||||
#define IPL_ATTR_SCP_DATA_SHOW_FN(_prefix, _ipl_block) \
|
||||
static ssize_t sys_##_prefix##_scp_data_show(struct file *filp, \
|
||||
struct kobject *kobj, \
|
||||
struct bin_attribute *attr, \
|
||||
char *buf, loff_t off, \
|
||||
size_t count) \
|
||||
{ \
|
||||
size_t size = _ipl_block.scp_data_len; \
|
||||
void *scp_data = _ipl_block.scp_data; \
|
||||
\
|
||||
return memory_read_from_buffer(buf, count, &off, \
|
||||
scp_data, size); \
|
||||
}
|
||||
|
||||
#define IPL_ATTR_SCP_DATA_STORE_FN(_prefix, _ipl_block_hdr, _ipl_block, _ipl_bp_len, _ipl_bp0_len)\
|
||||
static ssize_t sys_##_prefix##_scp_data_store(struct file *filp, \
|
||||
struct kobject *kobj, \
|
||||
struct bin_attribute *attr, \
|
||||
char *buf, loff_t off, \
|
||||
size_t count) \
|
||||
{ \
|
||||
size_t scpdata_len = count; \
|
||||
size_t padding; \
|
||||
\
|
||||
if (off) \
|
||||
return -EINVAL; \
|
||||
\
|
||||
memcpy(_ipl_block.scp_data, buf, count); \
|
||||
if (scpdata_len % 8) { \
|
||||
padding = 8 - (scpdata_len % 8); \
|
||||
memset(_ipl_block.scp_data + scpdata_len, \
|
||||
0, padding); \
|
||||
scpdata_len += padding; \
|
||||
} \
|
||||
\
|
||||
_ipl_block_hdr.len = _ipl_bp_len + scpdata_len; \
|
||||
_ipl_block.len = _ipl_bp0_len + scpdata_len; \
|
||||
_ipl_block.scp_data_len = scpdata_len; \
|
||||
\
|
||||
return count; \
|
||||
}
|
||||
|
||||
#define DEFINE_IPL_ATTR_SCP_DATA_RO(_prefix, _ipl_block, _size) \
|
||||
IPL_ATTR_SCP_DATA_SHOW_FN(_prefix, _ipl_block) \
|
||||
static struct bin_attribute sys_##_prefix##_scp_data_attr = \
|
||||
__BIN_ATTR(scp_data, 0444, sys_##_prefix##_scp_data_show, \
|
||||
NULL, _size)
|
||||
|
||||
#define DEFINE_IPL_ATTR_SCP_DATA_RW(_prefix, _ipl_block_hdr, _ipl_block, _ipl_bp_len, _ipl_bp0_len, _size)\
|
||||
IPL_ATTR_SCP_DATA_SHOW_FN(_prefix, _ipl_block) \
|
||||
IPL_ATTR_SCP_DATA_STORE_FN(_prefix, _ipl_block_hdr, _ipl_block, _ipl_bp_len, _ipl_bp0_len)\
|
||||
static struct bin_attribute sys_##_prefix##_scp_data_attr = \
|
||||
__BIN_ATTR(scp_data, 0644, sys_##_prefix##_scp_data_show, \
|
||||
sys_##_prefix##_scp_data_store, _size)
|
||||
|
||||
/*
|
||||
* ipl section
|
||||
*/
|
||||
@ -374,71 +433,38 @@ static ssize_t sys_ipl_device_show(struct kobject *kobj,
|
||||
static struct kobj_attribute sys_ipl_device_attr =
|
||||
__ATTR(device, 0444, sys_ipl_device_show, NULL);
|
||||
|
||||
static ssize_t ipl_parameter_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t off, size_t count)
|
||||
static ssize_t sys_ipl_parameter_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t off, size_t count)
|
||||
{
|
||||
return memory_read_from_buffer(buf, count, &off, &ipl_block,
|
||||
ipl_block.hdr.len);
|
||||
}
|
||||
static struct bin_attribute ipl_parameter_attr =
|
||||
__BIN_ATTR(binary_parameter, 0444, ipl_parameter_read, NULL,
|
||||
static struct bin_attribute sys_ipl_parameter_attr =
|
||||
__BIN_ATTR(binary_parameter, 0444, sys_ipl_parameter_read, NULL,
|
||||
PAGE_SIZE);
|
||||
|
||||
static ssize_t ipl_scp_data_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t off, size_t count)
|
||||
{
|
||||
unsigned int size = ipl_block.fcp.scp_data_len;
|
||||
void *scp_data = &ipl_block.fcp.scp_data;
|
||||
|
||||
return memory_read_from_buffer(buf, count, &off, scp_data, size);
|
||||
}
|
||||
|
||||
static ssize_t ipl_nvme_scp_data_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t off, size_t count)
|
||||
{
|
||||
unsigned int size = ipl_block.nvme.scp_data_len;
|
||||
void *scp_data = &ipl_block.nvme.scp_data;
|
||||
|
||||
return memory_read_from_buffer(buf, count, &off, scp_data, size);
|
||||
}
|
||||
|
||||
static ssize_t ipl_eckd_scp_data_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t off, size_t count)
|
||||
{
|
||||
unsigned int size = ipl_block.eckd.scp_data_len;
|
||||
void *scp_data = &ipl_block.eckd.scp_data;
|
||||
|
||||
return memory_read_from_buffer(buf, count, &off, scp_data, size);
|
||||
}
|
||||
|
||||
static struct bin_attribute ipl_scp_data_attr =
|
||||
__BIN_ATTR(scp_data, 0444, ipl_scp_data_read, NULL, PAGE_SIZE);
|
||||
|
||||
static struct bin_attribute ipl_nvme_scp_data_attr =
|
||||
__BIN_ATTR(scp_data, 0444, ipl_nvme_scp_data_read, NULL, PAGE_SIZE);
|
||||
|
||||
static struct bin_attribute ipl_eckd_scp_data_attr =
|
||||
__BIN_ATTR(scp_data, 0444, ipl_eckd_scp_data_read, NULL, PAGE_SIZE);
|
||||
DEFINE_IPL_ATTR_SCP_DATA_RO(ipl_fcp, ipl_block.fcp, PAGE_SIZE);
|
||||
|
||||
static struct bin_attribute *ipl_fcp_bin_attrs[] = {
|
||||
&ipl_parameter_attr,
|
||||
&ipl_scp_data_attr,
|
||||
&sys_ipl_parameter_attr,
|
||||
&sys_ipl_fcp_scp_data_attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
DEFINE_IPL_ATTR_SCP_DATA_RO(ipl_nvme, ipl_block.nvme, PAGE_SIZE);
|
||||
|
||||
static struct bin_attribute *ipl_nvme_bin_attrs[] = {
|
||||
&ipl_parameter_attr,
|
||||
&ipl_nvme_scp_data_attr,
|
||||
&sys_ipl_parameter_attr,
|
||||
&sys_ipl_nvme_scp_data_attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
DEFINE_IPL_ATTR_SCP_DATA_RO(ipl_eckd, ipl_block.eckd, PAGE_SIZE);
|
||||
|
||||
static struct bin_attribute *ipl_eckd_bin_attrs[] = {
|
||||
&ipl_parameter_attr,
|
||||
&ipl_eckd_scp_data_attr,
|
||||
&sys_ipl_parameter_attr,
|
||||
&sys_ipl_eckd_scp_data_attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -777,44 +803,10 @@ static struct kobj_attribute sys_reipl_ccw_vmparm_attr =
|
||||
|
||||
/* FCP reipl device attributes */
|
||||
|
||||
static ssize_t reipl_fcp_scpdata_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
size_t size = reipl_block_fcp->fcp.scp_data_len;
|
||||
void *scp_data = reipl_block_fcp->fcp.scp_data;
|
||||
|
||||
return memory_read_from_buffer(buf, count, &off, scp_data, size);
|
||||
}
|
||||
|
||||
static ssize_t reipl_fcp_scpdata_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
size_t scpdata_len = count;
|
||||
size_t padding;
|
||||
|
||||
|
||||
if (off)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(reipl_block_fcp->fcp.scp_data, buf, count);
|
||||
if (scpdata_len % 8) {
|
||||
padding = 8 - (scpdata_len % 8);
|
||||
memset(reipl_block_fcp->fcp.scp_data + scpdata_len,
|
||||
0, padding);
|
||||
scpdata_len += padding;
|
||||
}
|
||||
|
||||
reipl_block_fcp->hdr.len = IPL_BP_FCP_LEN + scpdata_len;
|
||||
reipl_block_fcp->fcp.len = IPL_BP0_FCP_LEN + scpdata_len;
|
||||
reipl_block_fcp->fcp.scp_data_len = scpdata_len;
|
||||
|
||||
return count;
|
||||
}
|
||||
static struct bin_attribute sys_reipl_fcp_scp_data_attr =
|
||||
__BIN_ATTR(scp_data, 0644, reipl_fcp_scpdata_read,
|
||||
reipl_fcp_scpdata_write, DIAG308_SCPDATA_SIZE);
|
||||
DEFINE_IPL_ATTR_SCP_DATA_RW(reipl_fcp, reipl_block_fcp->hdr,
|
||||
reipl_block_fcp->fcp,
|
||||
IPL_BP_FCP_LEN, IPL_BP0_FCP_LEN,
|
||||
DIAG308_SCPDATA_SIZE);
|
||||
|
||||
static struct bin_attribute *reipl_fcp_bin_attrs[] = {
|
||||
&sys_reipl_fcp_scp_data_attr,
|
||||
@ -935,44 +927,10 @@ static struct kobj_attribute sys_reipl_fcp_clear_attr =
|
||||
|
||||
/* NVME reipl device attributes */
|
||||
|
||||
static ssize_t reipl_nvme_scpdata_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
size_t size = reipl_block_nvme->nvme.scp_data_len;
|
||||
void *scp_data = reipl_block_nvme->nvme.scp_data;
|
||||
|
||||
return memory_read_from_buffer(buf, count, &off, scp_data, size);
|
||||
}
|
||||
|
||||
static ssize_t reipl_nvme_scpdata_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
size_t scpdata_len = count;
|
||||
size_t padding;
|
||||
|
||||
if (off)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(reipl_block_nvme->nvme.scp_data, buf, count);
|
||||
if (scpdata_len % 8) {
|
||||
padding = 8 - (scpdata_len % 8);
|
||||
memset(reipl_block_nvme->nvme.scp_data + scpdata_len,
|
||||
0, padding);
|
||||
scpdata_len += padding;
|
||||
}
|
||||
|
||||
reipl_block_nvme->hdr.len = IPL_BP_FCP_LEN + scpdata_len;
|
||||
reipl_block_nvme->nvme.len = IPL_BP0_FCP_LEN + scpdata_len;
|
||||
reipl_block_nvme->nvme.scp_data_len = scpdata_len;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct bin_attribute sys_reipl_nvme_scp_data_attr =
|
||||
__BIN_ATTR(scp_data, 0644, reipl_nvme_scpdata_read,
|
||||
reipl_nvme_scpdata_write, DIAG308_SCPDATA_SIZE);
|
||||
DEFINE_IPL_ATTR_SCP_DATA_RW(reipl_nvme, reipl_block_nvme->hdr,
|
||||
reipl_block_nvme->nvme,
|
||||
IPL_BP_NVME_LEN, IPL_BP0_NVME_LEN,
|
||||
DIAG308_SCPDATA_SIZE);
|
||||
|
||||
static struct bin_attribute *reipl_nvme_bin_attrs[] = {
|
||||
&sys_reipl_nvme_scp_data_attr,
|
||||
@ -1068,44 +1026,10 @@ static struct attribute_group reipl_ccw_attr_group_lpar = {
|
||||
|
||||
/* ECKD reipl device attributes */
|
||||
|
||||
static ssize_t reipl_eckd_scpdata_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
size_t size = reipl_block_eckd->eckd.scp_data_len;
|
||||
void *scp_data = reipl_block_eckd->eckd.scp_data;
|
||||
|
||||
return memory_read_from_buffer(buf, count, &off, scp_data, size);
|
||||
}
|
||||
|
||||
static ssize_t reipl_eckd_scpdata_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
size_t scpdata_len = count;
|
||||
size_t padding;
|
||||
|
||||
if (off)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(reipl_block_eckd->eckd.scp_data, buf, count);
|
||||
if (scpdata_len % 8) {
|
||||
padding = 8 - (scpdata_len % 8);
|
||||
memset(reipl_block_eckd->eckd.scp_data + scpdata_len,
|
||||
0, padding);
|
||||
scpdata_len += padding;
|
||||
}
|
||||
|
||||
reipl_block_eckd->hdr.len = IPL_BP_ECKD_LEN + scpdata_len;
|
||||
reipl_block_eckd->eckd.len = IPL_BP0_ECKD_LEN + scpdata_len;
|
||||
reipl_block_eckd->eckd.scp_data_len = scpdata_len;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct bin_attribute sys_reipl_eckd_scp_data_attr =
|
||||
__BIN_ATTR(scp_data, 0644, reipl_eckd_scpdata_read,
|
||||
reipl_eckd_scpdata_write, DIAG308_SCPDATA_SIZE);
|
||||
DEFINE_IPL_ATTR_SCP_DATA_RW(reipl_eckd, reipl_block_eckd->hdr,
|
||||
reipl_block_eckd->eckd,
|
||||
IPL_BP_ECKD_LEN, IPL_BP0_ECKD_LEN,
|
||||
DIAG308_SCPDATA_SIZE);
|
||||
|
||||
static struct bin_attribute *reipl_eckd_bin_attrs[] = {
|
||||
&sys_reipl_eckd_scp_data_attr,
|
||||
@ -1649,6 +1573,11 @@ DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
|
||||
DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
|
||||
dump_block_fcp->fcp.devno);
|
||||
|
||||
DEFINE_IPL_ATTR_SCP_DATA_RW(dump_fcp, dump_block_fcp->hdr,
|
||||
dump_block_fcp->fcp,
|
||||
IPL_BP_FCP_LEN, IPL_BP0_FCP_LEN,
|
||||
DIAG308_SCPDATA_SIZE);
|
||||
|
||||
static struct attribute *dump_fcp_attrs[] = {
|
||||
&sys_dump_fcp_device_attr.attr,
|
||||
&sys_dump_fcp_wwpn_attr.attr,
|
||||
@ -1658,9 +1587,15 @@ static struct attribute *dump_fcp_attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct bin_attribute *dump_fcp_bin_attrs[] = {
|
||||
&sys_dump_fcp_scp_data_attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group dump_fcp_attr_group = {
|
||||
.name = IPL_FCP_STR,
|
||||
.attrs = dump_fcp_attrs,
|
||||
.bin_attrs = dump_fcp_bin_attrs,
|
||||
};
|
||||
|
||||
/* NVME dump device attributes */
|
||||
@ -1673,6 +1608,11 @@ DEFINE_IPL_ATTR_RW(dump_nvme, bootprog, "%lld\n", "%llx\n",
|
||||
DEFINE_IPL_ATTR_RW(dump_nvme, br_lba, "%lld\n", "%llx\n",
|
||||
dump_block_nvme->nvme.br_lba);
|
||||
|
||||
DEFINE_IPL_ATTR_SCP_DATA_RW(dump_nvme, dump_block_nvme->hdr,
|
||||
dump_block_nvme->nvme,
|
||||
IPL_BP_NVME_LEN, IPL_BP0_NVME_LEN,
|
||||
DIAG308_SCPDATA_SIZE);
|
||||
|
||||
static struct attribute *dump_nvme_attrs[] = {
|
||||
&sys_dump_nvme_fid_attr.attr,
|
||||
&sys_dump_nvme_nsid_attr.attr,
|
||||
@ -1681,9 +1621,15 @@ static struct attribute *dump_nvme_attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct bin_attribute *dump_nvme_bin_attrs[] = {
|
||||
&sys_dump_nvme_scp_data_attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group dump_nvme_attr_group = {
|
||||
.name = IPL_NVME_STR,
|
||||
.attrs = dump_nvme_attrs,
|
||||
.bin_attrs = dump_nvme_bin_attrs,
|
||||
};
|
||||
|
||||
/* ECKD dump device attributes */
|
||||
@ -1697,6 +1643,11 @@ IPL_ATTR_BR_CHR_STORE_FN(dump, dump_block_eckd->eckd);
|
||||
static struct kobj_attribute sys_dump_eckd_br_chr_attr =
|
||||
__ATTR(br_chr, 0644, eckd_dump_br_chr_show, eckd_dump_br_chr_store);
|
||||
|
||||
DEFINE_IPL_ATTR_SCP_DATA_RW(dump_eckd, dump_block_eckd->hdr,
|
||||
dump_block_eckd->eckd,
|
||||
IPL_BP_ECKD_LEN, IPL_BP0_ECKD_LEN,
|
||||
DIAG308_SCPDATA_SIZE);
|
||||
|
||||
static struct attribute *dump_eckd_attrs[] = {
|
||||
&sys_dump_eckd_device_attr.attr,
|
||||
&sys_dump_eckd_bootprog_attr.attr,
|
||||
@ -1704,9 +1655,15 @@ static struct attribute *dump_eckd_attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct bin_attribute *dump_eckd_bin_attrs[] = {
|
||||
&sys_dump_eckd_scp_data_attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group dump_eckd_attr_group = {
|
||||
.name = IPL_ECKD_STR,
|
||||
.attrs = dump_eckd_attrs,
|
||||
.bin_attrs = dump_eckd_bin_attrs,
|
||||
};
|
||||
|
||||
/* CCW dump device attributes */
|
||||
@ -1859,9 +1816,9 @@ static int __init dump_nvme_init(void)
|
||||
}
|
||||
dump_block_nvme->hdr.len = IPL_BP_NVME_LEN;
|
||||
dump_block_nvme->hdr.version = IPL_PARM_BLOCK_VERSION;
|
||||
dump_block_nvme->fcp.len = IPL_BP0_NVME_LEN;
|
||||
dump_block_nvme->fcp.pbt = IPL_PBT_NVME;
|
||||
dump_block_nvme->fcp.opt = IPL_PB0_NVME_OPT_DUMP;
|
||||
dump_block_nvme->nvme.len = IPL_BP0_NVME_LEN;
|
||||
dump_block_nvme->nvme.pbt = IPL_PBT_NVME;
|
||||
dump_block_nvme->nvme.opt = IPL_PB0_NVME_OPT_DUMP;
|
||||
dump_capabilities |= DUMP_TYPE_NVME;
|
||||
return 0;
|
||||
}
|
||||
@ -1959,11 +1916,13 @@ static struct shutdown_action __refdata dump_reipl_action = {
|
||||
* vmcmd shutdown action: Trigger vm command on shutdown.
|
||||
*/
|
||||
|
||||
static char vmcmd_on_reboot[128];
|
||||
static char vmcmd_on_panic[128];
|
||||
static char vmcmd_on_halt[128];
|
||||
static char vmcmd_on_poff[128];
|
||||
static char vmcmd_on_restart[128];
|
||||
#define VMCMD_MAX_SIZE 240
|
||||
|
||||
static char vmcmd_on_reboot[VMCMD_MAX_SIZE + 1];
|
||||
static char vmcmd_on_panic[VMCMD_MAX_SIZE + 1];
|
||||
static char vmcmd_on_halt[VMCMD_MAX_SIZE + 1];
|
||||
static char vmcmd_on_poff[VMCMD_MAX_SIZE + 1];
|
||||
static char vmcmd_on_restart[VMCMD_MAX_SIZE + 1];
|
||||
|
||||
DEFINE_IPL_ATTR_STR_RW(vmcmd, on_reboot, "%s\n", "%s\n", vmcmd_on_reboot);
|
||||
DEFINE_IPL_ATTR_STR_RW(vmcmd, on_panic, "%s\n", "%s\n", vmcmd_on_panic);
|
||||
@ -2289,8 +2248,8 @@ static int __init vmcmd_on_reboot_setup(char *str)
|
||||
{
|
||||
if (!MACHINE_IS_VM)
|
||||
return 1;
|
||||
strncpy_skip_quote(vmcmd_on_reboot, str, 127);
|
||||
vmcmd_on_reboot[127] = 0;
|
||||
strncpy_skip_quote(vmcmd_on_reboot, str, VMCMD_MAX_SIZE);
|
||||
vmcmd_on_reboot[VMCMD_MAX_SIZE] = 0;
|
||||
on_reboot_trigger.action = &vmcmd_action;
|
||||
return 1;
|
||||
}
|
||||
@ -2300,8 +2259,8 @@ static int __init vmcmd_on_panic_setup(char *str)
|
||||
{
|
||||
if (!MACHINE_IS_VM)
|
||||
return 1;
|
||||
strncpy_skip_quote(vmcmd_on_panic, str, 127);
|
||||
vmcmd_on_panic[127] = 0;
|
||||
strncpy_skip_quote(vmcmd_on_panic, str, VMCMD_MAX_SIZE);
|
||||
vmcmd_on_panic[VMCMD_MAX_SIZE] = 0;
|
||||
on_panic_trigger.action = &vmcmd_action;
|
||||
return 1;
|
||||
}
|
||||
@ -2311,8 +2270,8 @@ static int __init vmcmd_on_halt_setup(char *str)
|
||||
{
|
||||
if (!MACHINE_IS_VM)
|
||||
return 1;
|
||||
strncpy_skip_quote(vmcmd_on_halt, str, 127);
|
||||
vmcmd_on_halt[127] = 0;
|
||||
strncpy_skip_quote(vmcmd_on_halt, str, VMCMD_MAX_SIZE);
|
||||
vmcmd_on_halt[VMCMD_MAX_SIZE] = 0;
|
||||
on_halt_trigger.action = &vmcmd_action;
|
||||
return 1;
|
||||
}
|
||||
@ -2322,8 +2281,8 @@ static int __init vmcmd_on_poff_setup(char *str)
|
||||
{
|
||||
if (!MACHINE_IS_VM)
|
||||
return 1;
|
||||
strncpy_skip_quote(vmcmd_on_poff, str, 127);
|
||||
vmcmd_on_poff[127] = 0;
|
||||
strncpy_skip_quote(vmcmd_on_poff, str, VMCMD_MAX_SIZE);
|
||||
vmcmd_on_poff[VMCMD_MAX_SIZE] = 0;
|
||||
on_poff_trigger.action = &vmcmd_action;
|
||||
return 1;
|
||||
}
|
||||
|
@ -151,6 +151,7 @@ void noinstr do_io_irq(struct pt_regs *regs)
|
||||
if (from_idle)
|
||||
account_idle_time_irq();
|
||||
|
||||
set_cpu_flag(CIF_NOHZ_DELAY);
|
||||
do {
|
||||
regs->tpi_info = S390_lowcore.tpi_info;
|
||||
if (S390_lowcore.tpi_info.adapter_IO)
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include <asm/set_memory.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/dis.h>
|
||||
#include "kprobes.h"
|
||||
#include "entry.h"
|
||||
|
||||
DEFINE_PER_CPU(struct kprobe *, current_kprobe);
|
||||
@ -32,8 +31,6 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
|
||||
|
||||
struct kretprobe_blackpoint kretprobe_blacklist[] = { };
|
||||
|
||||
static int insn_page_in_use;
|
||||
|
||||
void *alloc_insn_page(void)
|
||||
{
|
||||
void *page;
|
||||
@ -45,26 +42,6 @@ void *alloc_insn_page(void)
|
||||
return page;
|
||||
}
|
||||
|
||||
static void *alloc_s390_insn_page(void)
|
||||
{
|
||||
if (xchg(&insn_page_in_use, 1) == 1)
|
||||
return NULL;
|
||||
return &kprobes_insn_page;
|
||||
}
|
||||
|
||||
static void free_s390_insn_page(void *page)
|
||||
{
|
||||
xchg(&insn_page_in_use, 0);
|
||||
}
|
||||
|
||||
struct kprobe_insn_cache kprobe_s390_insn_slots = {
|
||||
.mutex = __MUTEX_INITIALIZER(kprobe_s390_insn_slots.mutex),
|
||||
.alloc = alloc_s390_insn_page,
|
||||
.free = free_s390_insn_page,
|
||||
.pages = LIST_HEAD_INIT(kprobe_s390_insn_slots.pages),
|
||||
.insn_size = MAX_INSN_SIZE,
|
||||
};
|
||||
|
||||
static void copy_instruction(struct kprobe *p)
|
||||
{
|
||||
kprobe_opcode_t insn[MAX_INSN_SIZE];
|
||||
@ -78,10 +55,10 @@ static void copy_instruction(struct kprobe *p)
|
||||
if (probe_is_insn_relative_long(&insn[0])) {
|
||||
/*
|
||||
* For pc-relative instructions in RIL-b or RIL-c format patch
|
||||
* the RI2 displacement field. We have already made sure that
|
||||
* the insn slot for the patched instruction is within the same
|
||||
* 2GB area as the original instruction (either kernel image or
|
||||
* module area). Therefore the new displacement will always fit.
|
||||
* the RI2 displacement field. The insn slot for the to be
|
||||
* patched instruction is within the same 4GB area like the
|
||||
* original instruction. Therefore the new displacement will
|
||||
* always fit.
|
||||
*/
|
||||
disp = *(s32 *)&insn[1];
|
||||
addr = (u64)(unsigned long)p->addr;
|
||||
@ -93,34 +70,6 @@ static void copy_instruction(struct kprobe *p)
|
||||
}
|
||||
NOKPROBE_SYMBOL(copy_instruction);
|
||||
|
||||
static int s390_get_insn_slot(struct kprobe *p)
|
||||
{
|
||||
/*
|
||||
* Get an insn slot that is within the same 2GB area like the original
|
||||
* instruction. That way instructions with a 32bit signed displacement
|
||||
* field can be patched and executed within the insn slot.
|
||||
*/
|
||||
p->ainsn.insn = NULL;
|
||||
if (is_kernel((unsigned long)p->addr))
|
||||
p->ainsn.insn = get_s390_insn_slot();
|
||||
else if (is_module_addr(p->addr))
|
||||
p->ainsn.insn = get_insn_slot();
|
||||
return p->ainsn.insn ? 0 : -ENOMEM;
|
||||
}
|
||||
NOKPROBE_SYMBOL(s390_get_insn_slot);
|
||||
|
||||
static void s390_free_insn_slot(struct kprobe *p)
|
||||
{
|
||||
if (!p->ainsn.insn)
|
||||
return;
|
||||
if (is_kernel((unsigned long)p->addr))
|
||||
free_s390_insn_slot(p->ainsn.insn, 0);
|
||||
else
|
||||
free_insn_slot(p->ainsn.insn, 0);
|
||||
p->ainsn.insn = NULL;
|
||||
}
|
||||
NOKPROBE_SYMBOL(s390_free_insn_slot);
|
||||
|
||||
/* Check if paddr is at an instruction boundary */
|
||||
static bool can_probe(unsigned long paddr)
|
||||
{
|
||||
@ -174,7 +123,8 @@ int arch_prepare_kprobe(struct kprobe *p)
|
||||
/* Make sure the probe isn't going on a difficult instruction */
|
||||
if (probe_is_prohibited_opcode(p->addr))
|
||||
return -EINVAL;
|
||||
if (s390_get_insn_slot(p))
|
||||
p->ainsn.insn = get_insn_slot();
|
||||
if (!p->ainsn.insn)
|
||||
return -ENOMEM;
|
||||
copy_instruction(p);
|
||||
return 0;
|
||||
@ -216,7 +166,10 @@ NOKPROBE_SYMBOL(arch_disarm_kprobe);
|
||||
|
||||
void arch_remove_kprobe(struct kprobe *p)
|
||||
{
|
||||
s390_free_insn_slot(p);
|
||||
if (!p->ainsn.insn)
|
||||
return;
|
||||
free_insn_slot(p->ainsn.insn, 0);
|
||||
p->ainsn.insn = NULL;
|
||||
}
|
||||
NOKPROBE_SYMBOL(arch_remove_kprobe);
|
||||
|
||||
|
@ -1,9 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
#ifndef _ARCH_S390_KPROBES_H
|
||||
#define _ARCH_S390_KPROBES_H
|
||||
|
||||
#include <linux/kprobes.h>
|
||||
|
||||
DEFINE_INSN_CACHE_OPS(s390_insn);
|
||||
|
||||
#endif
|
@ -1,22 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
/*
|
||||
* insn_page is a special 4k aligned dummy function for kprobes.
|
||||
* It will contain all kprobed instructions that are out-of-line executed.
|
||||
* The page must be within the kernel image to guarantee that the
|
||||
* out-of-line instructions are within 2GB distance of their original
|
||||
* location. Using a dummy function ensures that the insn_page is within
|
||||
* the text section of the kernel and mapped read-only/executable from
|
||||
* the beginning on, thus avoiding to split large mappings if the page
|
||||
* would be in the data section instead.
|
||||
*/
|
||||
.section .kprobes.text, "ax"
|
||||
.balign 4096
|
||||
SYM_CODE_START(kprobes_insn_page)
|
||||
.rept 2048
|
||||
.word 0x07fe
|
||||
.endr
|
||||
SYM_CODE_END(kprobes_insn_page)
|
||||
.previous
|
@ -218,39 +218,7 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
|
||||
void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
struct stack_frame_user __user *sf;
|
||||
unsigned long ip, sp;
|
||||
bool first = true;
|
||||
|
||||
if (is_compat_task())
|
||||
return;
|
||||
perf_callchain_store(entry, instruction_pointer(regs));
|
||||
sf = (void __user *)user_stack_pointer(regs);
|
||||
pagefault_disable();
|
||||
while (entry->nr < entry->max_stack) {
|
||||
if (__get_user(sp, &sf->back_chain))
|
||||
break;
|
||||
if (__get_user(ip, &sf->gprs[8]))
|
||||
break;
|
||||
if (ip & 0x1) {
|
||||
/*
|
||||
* If the instruction address is invalid, and this
|
||||
* is the first stack frame, assume r14 has not
|
||||
* been written to the stack yet. Otherwise exit.
|
||||
*/
|
||||
if (first && !(regs->gprs[14] & 0x1))
|
||||
ip = regs->gprs[14];
|
||||
else
|
||||
break;
|
||||
}
|
||||
perf_callchain_store(entry, ip);
|
||||
/* Sanity check: ABI requires SP to be aligned 8 bytes. */
|
||||
if (!sp || sp & 0x7)
|
||||
break;
|
||||
sf = (void __user *)sp;
|
||||
first = false;
|
||||
}
|
||||
pagefault_enable();
|
||||
arch_stack_walk_user_common(NULL, NULL, entry, regs, true);
|
||||
}
|
||||
|
||||
/* Perf definitions for PMU event attributes in sysfs */
|
||||
|
@ -86,11 +86,6 @@ void arch_release_task_struct(struct task_struct *tsk)
|
||||
|
||||
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
|
||||
{
|
||||
/*
|
||||
* Save the floating-point or vector register state of the current
|
||||
* task and set the TIF_FPU flag to lazy restore the FPU register
|
||||
* state when returning to user space.
|
||||
*/
|
||||
save_user_fpu_regs();
|
||||
|
||||
*dst = *src;
|
||||
|
@ -155,7 +155,7 @@ unsigned int __bootdata_preserved(zlib_dfltcc_support);
|
||||
EXPORT_SYMBOL(zlib_dfltcc_support);
|
||||
u64 __bootdata_preserved(stfle_fac_list[16]);
|
||||
EXPORT_SYMBOL(stfle_fac_list);
|
||||
u64 __bootdata_preserved(alt_stfle_fac_list[16]);
|
||||
u64 alt_stfle_fac_list[16];
|
||||
struct oldmem_data __bootdata_preserved(oldmem_data);
|
||||
|
||||
unsigned long VMALLOC_START;
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright IBM Corp. 2006
|
||||
*/
|
||||
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/stacktrace.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/compat.h>
|
||||
@ -62,46 +63,106 @@ int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
|
||||
const struct pt_regs *regs)
|
||||
static inline bool store_ip(stack_trace_consume_fn consume_entry, void *cookie,
|
||||
struct perf_callchain_entry_ctx *entry, bool perf,
|
||||
unsigned long ip)
|
||||
{
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
if (perf) {
|
||||
if (perf_callchain_store(entry, ip))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return consume_entry(cookie, ip);
|
||||
}
|
||||
|
||||
static inline bool ip_invalid(unsigned long ip)
|
||||
{
|
||||
/*
|
||||
* Perform some basic checks if an instruction address taken
|
||||
* from unreliable source is invalid.
|
||||
*/
|
||||
if (ip & 1)
|
||||
return true;
|
||||
if (ip < mmap_min_addr)
|
||||
return true;
|
||||
if (ip >= current->mm->context.asce_limit)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool ip_within_vdso(unsigned long ip)
|
||||
{
|
||||
return in_range(ip, current->mm->context.vdso_base, vdso_text_size());
|
||||
}
|
||||
|
||||
void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *cookie,
|
||||
struct perf_callchain_entry_ctx *entry,
|
||||
const struct pt_regs *regs, bool perf)
|
||||
{
|
||||
struct stack_frame_vdso_wrapper __user *sf_vdso;
|
||||
struct stack_frame_user __user *sf;
|
||||
unsigned long ip, sp;
|
||||
bool first = true;
|
||||
|
||||
if (is_compat_task())
|
||||
return;
|
||||
if (!consume_entry(cookie, instruction_pointer(regs)))
|
||||
if (!current->mm)
|
||||
return;
|
||||
ip = instruction_pointer(regs);
|
||||
if (!store_ip(consume_entry, cookie, entry, perf, ip))
|
||||
return;
|
||||
sf = (void __user *)user_stack_pointer(regs);
|
||||
pagefault_disable();
|
||||
while (1) {
|
||||
if (__get_user(sp, &sf->back_chain))
|
||||
break;
|
||||
if (__get_user(ip, &sf->gprs[8]))
|
||||
/*
|
||||
* VDSO entry code has a non-standard stack frame layout.
|
||||
* See VDSO user wrapper code for details.
|
||||
*/
|
||||
if (!sp && ip_within_vdso(ip)) {
|
||||
sf_vdso = (void __user *)sf;
|
||||
if (__get_user(ip, &sf_vdso->return_address))
|
||||
break;
|
||||
sp = (unsigned long)sf + STACK_FRAME_VDSO_OVERHEAD;
|
||||
sf = (void __user *)sp;
|
||||
if (__get_user(sp, &sf->back_chain))
|
||||
break;
|
||||
} else {
|
||||
sf = (void __user *)sp;
|
||||
if (__get_user(ip, &sf->gprs[8]))
|
||||
break;
|
||||
}
|
||||
/* Sanity check: ABI requires SP to be 8 byte aligned. */
|
||||
if (sp & 0x7)
|
||||
break;
|
||||
if (ip & 0x1) {
|
||||
if (ip_invalid(ip)) {
|
||||
/*
|
||||
* If the instruction address is invalid, and this
|
||||
* is the first stack frame, assume r14 has not
|
||||
* been written to the stack yet. Otherwise exit.
|
||||
*/
|
||||
if (first && !(regs->gprs[14] & 0x1))
|
||||
ip = regs->gprs[14];
|
||||
else
|
||||
if (!first)
|
||||
break;
|
||||
ip = regs->gprs[14];
|
||||
if (ip_invalid(ip))
|
||||
break;
|
||||
}
|
||||
if (!consume_entry(cookie, ip))
|
||||
break;
|
||||
/* Sanity check: ABI requires SP to be aligned 8 bytes. */
|
||||
if (!sp || sp & 0x7)
|
||||
break;
|
||||
sf = (void __user *)sp;
|
||||
if (!store_ip(consume_entry, cookie, entry, perf, ip))
|
||||
return;
|
||||
first = false;
|
||||
}
|
||||
pagefault_enable();
|
||||
}
|
||||
|
||||
void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
|
||||
const struct pt_regs *regs)
|
||||
{
|
||||
arch_stack_walk_user_common(consume_entry, cookie, NULL, regs, false);
|
||||
}
|
||||
|
||||
unsigned long return_address(unsigned int n)
|
||||
{
|
||||
struct unwind_state state;
|
||||
|
@ -210,17 +210,22 @@ static unsigned long vdso_addr(unsigned long start, unsigned long len)
|
||||
return addr;
|
||||
}
|
||||
|
||||
unsigned long vdso_size(void)
|
||||
unsigned long vdso_text_size(void)
|
||||
{
|
||||
unsigned long size = VVAR_NR_PAGES * PAGE_SIZE;
|
||||
unsigned long size;
|
||||
|
||||
if (is_compat_task())
|
||||
size += vdso32_end - vdso32_start;
|
||||
size = vdso32_end - vdso32_start;
|
||||
else
|
||||
size += vdso64_end - vdso64_start;
|
||||
size = vdso64_end - vdso64_start;
|
||||
return PAGE_ALIGN(size);
|
||||
}
|
||||
|
||||
unsigned long vdso_size(void)
|
||||
{
|
||||
return vdso_text_size() + VVAR_NR_PAGES * PAGE_SIZE;
|
||||
}
|
||||
|
||||
int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
|
||||
{
|
||||
unsigned long addr = VDSO_BASE;
|
||||
|
@ -17,8 +17,10 @@ KBUILD_AFLAGS_32 := $(filter-out -m64,$(KBUILD_AFLAGS))
|
||||
KBUILD_AFLAGS_32 += -m31 -s
|
||||
|
||||
KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS))
|
||||
KBUILD_CFLAGS_32 := $(filter-out -mpacked-stack,$(KBUILD_CFLAGS))
|
||||
KBUILD_CFLAGS_32 := $(filter-out -mno-pic-data-is-text-relative,$(KBUILD_CFLAGS_32))
|
||||
KBUILD_CFLAGS_32 += -m31 -fPIC -shared -fno-common -fno-builtin
|
||||
KBUILD_CFLAGS_32 := $(filter-out -fno-asynchronous-unwind-tables,$(KBUILD_CFLAGS_32))
|
||||
KBUILD_CFLAGS_32 += -m31 -fPIC -shared -fno-common -fno-builtin -fasynchronous-unwind-tables
|
||||
|
||||
LDFLAGS_vdso32.so.dbg += -shared -soname=linux-vdso32.so.1 \
|
||||
--hash-style=both --build-id=sha1 -melf_s390 -T
|
||||
|
@ -22,9 +22,11 @@ KBUILD_AFLAGS_64 := $(filter-out -m64,$(KBUILD_AFLAGS))
|
||||
KBUILD_AFLAGS_64 += -m64
|
||||
|
||||
KBUILD_CFLAGS_64 := $(filter-out -m64,$(KBUILD_CFLAGS))
|
||||
KBUILD_CFLAGS_64 := $(filter-out -mpacked-stack,$(KBUILD_CFLAGS_64))
|
||||
KBUILD_CFLAGS_64 := $(filter-out -mno-pic-data-is-text-relative,$(KBUILD_CFLAGS_64))
|
||||
KBUILD_CFLAGS_64 := $(filter-out -munaligned-symbols,$(KBUILD_CFLAGS_64))
|
||||
KBUILD_CFLAGS_64 += -m64 -fPIC -fno-common -fno-builtin
|
||||
KBUILD_CFLAGS_64 := $(filter-out -fno-asynchronous-unwind-tables,$(KBUILD_CFLAGS_64))
|
||||
KBUILD_CFLAGS_64 += -m64 -fPIC -fno-common -fno-builtin -fasynchronous-unwind-tables
|
||||
ldflags-y := -shared -soname=linux-vdso64.so.1 \
|
||||
--hash-style=both --build-id=sha1 -T
|
||||
|
||||
|
@ -6,8 +6,6 @@
|
||||
#include <asm/dwarf.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
#define WRAPPER_FRAME_SIZE (STACK_FRAME_OVERHEAD+8)
|
||||
|
||||
/*
|
||||
* Older glibc version called vdso without allocating a stackframe. This wrapper
|
||||
* is just used to allocate a stackframe. See
|
||||
@ -20,16 +18,17 @@
|
||||
__ALIGN
|
||||
__kernel_\func:
|
||||
CFI_STARTPROC
|
||||
aghi %r15,-WRAPPER_FRAME_SIZE
|
||||
CFI_DEF_CFA_OFFSET (STACK_FRAME_OVERHEAD + WRAPPER_FRAME_SIZE)
|
||||
CFI_VAL_OFFSET 15, -STACK_FRAME_OVERHEAD
|
||||
stg %r14,STACK_FRAME_OVERHEAD(%r15)
|
||||
CFI_REL_OFFSET 14, STACK_FRAME_OVERHEAD
|
||||
aghi %r15,-STACK_FRAME_VDSO_OVERHEAD
|
||||
CFI_DEF_CFA_OFFSET (STACK_FRAME_USER_OVERHEAD + STACK_FRAME_VDSO_OVERHEAD)
|
||||
CFI_VAL_OFFSET 15,-STACK_FRAME_USER_OVERHEAD
|
||||
stg %r14,__SFVDSO_RETURN_ADDRESS(%r15)
|
||||
CFI_REL_OFFSET 14,__SFVDSO_RETURN_ADDRESS
|
||||
xc __SFUSER_BACKCHAIN(8,%r15),__SFUSER_BACKCHAIN(%r15)
|
||||
brasl %r14,__s390_vdso_\func
|
||||
lg %r14,STACK_FRAME_OVERHEAD(%r15)
|
||||
lg %r14,__SFVDSO_RETURN_ADDRESS(%r15)
|
||||
CFI_RESTORE 14
|
||||
aghi %r15,WRAPPER_FRAME_SIZE
|
||||
CFI_DEF_CFA_OFFSET STACK_FRAME_OVERHEAD
|
||||
aghi %r15,STACK_FRAME_VDSO_OVERHEAD
|
||||
CFI_DEF_CFA_OFFSET STACK_FRAME_USER_OVERHEAD
|
||||
CFI_RESTORE 15
|
||||
br %r14
|
||||
CFI_ENDPROC
|
||||
|
@ -33,14 +33,6 @@ static DEFINE_PER_CPU(u64, mt_scaling_mult) = { 1 };
|
||||
static DEFINE_PER_CPU(u64, mt_scaling_div) = { 1 };
|
||||
static DEFINE_PER_CPU(u64, mt_scaling_jiffies);
|
||||
|
||||
static inline u64 get_vtimer(void)
|
||||
{
|
||||
u64 timer;
|
||||
|
||||
asm volatile("stpt %0" : "=Q" (timer));
|
||||
return timer;
|
||||
}
|
||||
|
||||
static inline void set_vtimer(u64 expires)
|
||||
{
|
||||
u64 timer;
|
||||
@ -223,7 +215,7 @@ static u64 vtime_delta(void)
|
||||
{
|
||||
u64 timer = S390_lowcore.last_update_timer;
|
||||
|
||||
S390_lowcore.last_update_timer = get_vtimer();
|
||||
S390_lowcore.last_update_timer = get_cpu_timer();
|
||||
|
||||
return timer - S390_lowcore.last_update_timer;
|
||||
}
|
||||
|
@ -728,23 +728,9 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
|
||||
struct device *dev;
|
||||
int ret;
|
||||
|
||||
dev = kzalloc(sizeof(struct device), GFP_KERNEL);
|
||||
if (dev) {
|
||||
dev_set_name(dev, "%s", priv->internal_name);
|
||||
dev->bus = &iucv_bus;
|
||||
dev->parent = iucv_root;
|
||||
dev->driver = &vmlogrdr_driver;
|
||||
dev->groups = vmlogrdr_attr_groups;
|
||||
dev_set_drvdata(dev, priv);
|
||||
/*
|
||||
* The release function could be called after the
|
||||
* module has been unloaded. It's _only_ task is to
|
||||
* free the struct. Therefore, we specify kfree()
|
||||
* directly here. (Probably a little bit obfuscating
|
||||
* but legitime ...).
|
||||
*/
|
||||
dev->release = (void (*)(struct device *))kfree;
|
||||
} else
|
||||
dev = iucv_alloc_device(vmlogrdr_attr_groups, &vmlogrdr_driver,
|
||||
priv, priv->internal_name);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
ret = device_register(dev);
|
||||
if (ret) {
|
||||
|
@ -90,7 +90,6 @@ static irqreturn_t do_airq_interrupt(int irq, void *dummy)
|
||||
struct airq_struct *airq;
|
||||
struct hlist_head *head;
|
||||
|
||||
set_cpu_flag(CIF_NOHZ_DELAY);
|
||||
tpi_info = &get_irq_regs()->tpi_info;
|
||||
trace_s390_cio_adapter_int(tpi_info);
|
||||
head = &airq_lists[tpi_info->isc];
|
||||
|
@ -535,7 +535,6 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy)
|
||||
struct subchannel *sch;
|
||||
struct irb *irb;
|
||||
|
||||
set_cpu_flag(CIF_NOHZ_DELAY);
|
||||
tpi_info = &get_irq_regs()->tpi_info;
|
||||
trace_s390_cio_interrupt(tpi_info);
|
||||
irb = this_cpu_ptr(&cio_irb);
|
||||
|
@ -732,9 +732,9 @@ static void ap_check_bindings_complete(void)
|
||||
if (bound == apqns) {
|
||||
if (!completion_done(&ap_apqn_bindings_complete)) {
|
||||
complete_all(&ap_apqn_bindings_complete);
|
||||
ap_send_bindings_complete_uevent();
|
||||
pr_debug("%s all apqn bindings complete\n", __func__);
|
||||
}
|
||||
ap_send_bindings_complete_uevent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -894,6 +894,12 @@ static int ap_device_probe(struct device *dev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rearm the bindings complete completion to trigger
|
||||
* bindings complete when all devices are bound again
|
||||
*/
|
||||
reinit_completion(&ap_apqn_bindings_complete);
|
||||
|
||||
/* Add queue/card to list of active queues/cards */
|
||||
spin_lock_bh(&ap_queues_lock);
|
||||
if (is_queue_dev(dev))
|
||||
@ -1091,7 +1097,7 @@ EXPORT_SYMBOL(ap_hex2bitmap);
|
||||
*/
|
||||
static int modify_bitmap(const char *str, unsigned long *bitmap, int bits)
|
||||
{
|
||||
int a, i, z;
|
||||
unsigned long a, i, z;
|
||||
char *np, sign;
|
||||
|
||||
/* bits needs to be a multiple of 8 */
|
||||
|
@ -1359,10 +1359,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
rc = cca_genseckey(kgs.cardnr, kgs.domain,
|
||||
kgs.keytype, kgs.seckey.seckey);
|
||||
pr_debug("%s cca_genseckey()=%d\n", __func__, rc);
|
||||
if (rc)
|
||||
break;
|
||||
if (copy_to_user(ugs, &kgs, sizeof(kgs)))
|
||||
return -EFAULT;
|
||||
if (!rc && copy_to_user(ugs, &kgs, sizeof(kgs)))
|
||||
rc = -EFAULT;
|
||||
memzero_explicit(&kgs, sizeof(kgs));
|
||||
break;
|
||||
}
|
||||
case PKEY_CLR2SECK: {
|
||||
@ -1374,10 +1373,8 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
rc = cca_clr2seckey(kcs.cardnr, kcs.domain, kcs.keytype,
|
||||
kcs.clrkey.clrkey, kcs.seckey.seckey);
|
||||
pr_debug("%s cca_clr2seckey()=%d\n", __func__, rc);
|
||||
if (rc)
|
||||
break;
|
||||
if (copy_to_user(ucs, &kcs, sizeof(kcs)))
|
||||
return -EFAULT;
|
||||
if (!rc && copy_to_user(ucs, &kcs, sizeof(kcs)))
|
||||
rc = -EFAULT;
|
||||
memzero_explicit(&kcs, sizeof(kcs));
|
||||
break;
|
||||
}
|
||||
@ -1392,10 +1389,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
ksp.seckey.seckey, ksp.protkey.protkey,
|
||||
&ksp.protkey.len, &ksp.protkey.type);
|
||||
pr_debug("%s cca_sec2protkey()=%d\n", __func__, rc);
|
||||
if (rc)
|
||||
break;
|
||||
if (copy_to_user(usp, &ksp, sizeof(ksp)))
|
||||
return -EFAULT;
|
||||
if (!rc && copy_to_user(usp, &ksp, sizeof(ksp)))
|
||||
rc = -EFAULT;
|
||||
memzero_explicit(&ksp, sizeof(ksp));
|
||||
break;
|
||||
}
|
||||
case PKEY_CLR2PROTK: {
|
||||
@ -1409,10 +1405,8 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
kcp.protkey.protkey,
|
||||
&kcp.protkey.len, &kcp.protkey.type);
|
||||
pr_debug("%s pkey_clr2protkey()=%d\n", __func__, rc);
|
||||
if (rc)
|
||||
break;
|
||||
if (copy_to_user(ucp, &kcp, sizeof(kcp)))
|
||||
return -EFAULT;
|
||||
if (!rc && copy_to_user(ucp, &kcp, sizeof(kcp)))
|
||||
rc = -EFAULT;
|
||||
memzero_explicit(&kcp, sizeof(kcp));
|
||||
break;
|
||||
}
|
||||
@ -1441,10 +1435,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
rc = pkey_skey2pkey(ksp.seckey.seckey, ksp.protkey.protkey,
|
||||
&ksp.protkey.len, &ksp.protkey.type);
|
||||
pr_debug("%s pkey_skey2pkey()=%d\n", __func__, rc);
|
||||
if (rc)
|
||||
break;
|
||||
if (copy_to_user(usp, &ksp, sizeof(ksp)))
|
||||
return -EFAULT;
|
||||
if (!rc && copy_to_user(usp, &ksp, sizeof(ksp)))
|
||||
rc = -EFAULT;
|
||||
memzero_explicit(&ksp, sizeof(ksp));
|
||||
break;
|
||||
}
|
||||
case PKEY_VERIFYKEY: {
|
||||
@ -1456,10 +1449,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
rc = pkey_verifykey(&kvk.seckey, &kvk.cardnr, &kvk.domain,
|
||||
&kvk.keysize, &kvk.attributes);
|
||||
pr_debug("%s pkey_verifykey()=%d\n", __func__, rc);
|
||||
if (rc)
|
||||
break;
|
||||
if (copy_to_user(uvk, &kvk, sizeof(kvk)))
|
||||
return -EFAULT;
|
||||
if (!rc && copy_to_user(uvk, &kvk, sizeof(kvk)))
|
||||
rc = -EFAULT;
|
||||
memzero_explicit(&kvk, sizeof(kvk));
|
||||
break;
|
||||
}
|
||||
case PKEY_GENPROTK: {
|
||||
@ -1472,10 +1464,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
rc = pkey_genprotkey(kgp.keytype, kgp.protkey.protkey,
|
||||
&kgp.protkey.len, &kgp.protkey.type);
|
||||
pr_debug("%s pkey_genprotkey()=%d\n", __func__, rc);
|
||||
if (rc)
|
||||
break;
|
||||
if (copy_to_user(ugp, &kgp, sizeof(kgp)))
|
||||
return -EFAULT;
|
||||
if (!rc && copy_to_user(ugp, &kgp, sizeof(kgp)))
|
||||
rc = -EFAULT;
|
||||
memzero_explicit(&kgp, sizeof(kgp));
|
||||
break;
|
||||
}
|
||||
case PKEY_VERIFYPROTK: {
|
||||
@ -1487,6 +1478,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
rc = pkey_verifyprotkey(kvp.protkey.protkey,
|
||||
kvp.protkey.len, kvp.protkey.type);
|
||||
pr_debug("%s pkey_verifyprotkey()=%d\n", __func__, rc);
|
||||
memzero_explicit(&kvp, sizeof(kvp));
|
||||
break;
|
||||
}
|
||||
case PKEY_KBLOB2PROTK: {
|
||||
@ -1503,12 +1495,10 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
rc = pkey_keyblob2pkey(kkey, ktp.keylen, ktp.protkey.protkey,
|
||||
&ktp.protkey.len, &ktp.protkey.type);
|
||||
pr_debug("%s pkey_keyblob2pkey()=%d\n", __func__, rc);
|
||||
memzero_explicit(kkey, ktp.keylen);
|
||||
kfree(kkey);
|
||||
if (rc)
|
||||
break;
|
||||
if (copy_to_user(utp, &ktp, sizeof(ktp)))
|
||||
return -EFAULT;
|
||||
kfree_sensitive(kkey);
|
||||
if (!rc && copy_to_user(utp, &ktp, sizeof(ktp)))
|
||||
rc = -EFAULT;
|
||||
memzero_explicit(&ktp, sizeof(ktp));
|
||||
break;
|
||||
}
|
||||
case PKEY_GENSECK2: {
|
||||
@ -1534,23 +1524,23 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
pr_debug("%s pkey_genseckey2()=%d\n", __func__, rc);
|
||||
kfree(apqns);
|
||||
if (rc) {
|
||||
kfree(kkey);
|
||||
kfree_sensitive(kkey);
|
||||
break;
|
||||
}
|
||||
if (kgs.key) {
|
||||
if (kgs.keylen < klen) {
|
||||
kfree(kkey);
|
||||
kfree_sensitive(kkey);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (copy_to_user(kgs.key, kkey, klen)) {
|
||||
kfree(kkey);
|
||||
kfree_sensitive(kkey);
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
kgs.keylen = klen;
|
||||
if (copy_to_user(ugs, &kgs, sizeof(kgs)))
|
||||
rc = -EFAULT;
|
||||
kfree(kkey);
|
||||
kfree_sensitive(kkey);
|
||||
break;
|
||||
}
|
||||
case PKEY_CLR2SECK2: {
|
||||
@ -1563,11 +1553,14 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
if (copy_from_user(&kcs, ucs, sizeof(kcs)))
|
||||
return -EFAULT;
|
||||
apqns = _copy_apqns_from_user(kcs.apqns, kcs.apqn_entries);
|
||||
if (IS_ERR(apqns))
|
||||
if (IS_ERR(apqns)) {
|
||||
memzero_explicit(&kcs, sizeof(kcs));
|
||||
return PTR_ERR(apqns);
|
||||
}
|
||||
kkey = kzalloc(klen, GFP_KERNEL);
|
||||
if (!kkey) {
|
||||
kfree(apqns);
|
||||
memzero_explicit(&kcs, sizeof(kcs));
|
||||
return -ENOMEM;
|
||||
}
|
||||
rc = pkey_clr2seckey2(apqns, kcs.apqn_entries,
|
||||
@ -1576,16 +1569,19 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
pr_debug("%s pkey_clr2seckey2()=%d\n", __func__, rc);
|
||||
kfree(apqns);
|
||||
if (rc) {
|
||||
kfree(kkey);
|
||||
kfree_sensitive(kkey);
|
||||
memzero_explicit(&kcs, sizeof(kcs));
|
||||
break;
|
||||
}
|
||||
if (kcs.key) {
|
||||
if (kcs.keylen < klen) {
|
||||
kfree(kkey);
|
||||
kfree_sensitive(kkey);
|
||||
memzero_explicit(&kcs, sizeof(kcs));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (copy_to_user(kcs.key, kkey, klen)) {
|
||||
kfree(kkey);
|
||||
kfree_sensitive(kkey);
|
||||
memzero_explicit(&kcs, sizeof(kcs));
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
@ -1593,7 +1589,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
if (copy_to_user(ucs, &kcs, sizeof(kcs)))
|
||||
rc = -EFAULT;
|
||||
memzero_explicit(&kcs, sizeof(kcs));
|
||||
kfree(kkey);
|
||||
kfree_sensitive(kkey);
|
||||
break;
|
||||
}
|
||||
case PKEY_VERIFYKEY2: {
|
||||
@ -1610,7 +1606,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
&kvk.cardnr, &kvk.domain,
|
||||
&kvk.type, &kvk.size, &kvk.flags);
|
||||
pr_debug("%s pkey_verifykey2()=%d\n", __func__, rc);
|
||||
kfree(kkey);
|
||||
kfree_sensitive(kkey);
|
||||
if (rc)
|
||||
break;
|
||||
if (copy_to_user(uvk, &kvk, sizeof(kvk)))
|
||||
@ -1640,12 +1636,10 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
&ktp.protkey.type);
|
||||
pr_debug("%s pkey_keyblob2pkey2()=%d\n", __func__, rc);
|
||||
kfree(apqns);
|
||||
memzero_explicit(kkey, ktp.keylen);
|
||||
kfree(kkey);
|
||||
if (rc)
|
||||
break;
|
||||
if (copy_to_user(utp, &ktp, sizeof(ktp)))
|
||||
return -EFAULT;
|
||||
kfree_sensitive(kkey);
|
||||
if (!rc && copy_to_user(utp, &ktp, sizeof(ktp)))
|
||||
rc = -EFAULT;
|
||||
memzero_explicit(&ktp, sizeof(ktp));
|
||||
break;
|
||||
}
|
||||
case PKEY_APQNS4K: {
|
||||
@ -1673,7 +1667,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
rc = pkey_apqns4key(kkey, kak.keylen, kak.flags,
|
||||
apqns, &nr_apqns);
|
||||
pr_debug("%s pkey_apqns4key()=%d\n", __func__, rc);
|
||||
kfree(kkey);
|
||||
kfree_sensitive(kkey);
|
||||
if (rc && rc != -ENOSPC) {
|
||||
kfree(apqns);
|
||||
break;
|
||||
@ -1759,7 +1753,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
protkey = kmalloc(protkeylen, GFP_KERNEL);
|
||||
if (!protkey) {
|
||||
kfree(apqns);
|
||||
kfree(kkey);
|
||||
kfree_sensitive(kkey);
|
||||
return -ENOMEM;
|
||||
}
|
||||
rc = pkey_keyblob2pkey3(apqns, ktp.apqn_entries,
|
||||
@ -1767,23 +1761,22 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
protkey, &protkeylen, &ktp.pkeytype);
|
||||
pr_debug("%s pkey_keyblob2pkey3()=%d\n", __func__, rc);
|
||||
kfree(apqns);
|
||||
memzero_explicit(kkey, ktp.keylen);
|
||||
kfree(kkey);
|
||||
kfree_sensitive(kkey);
|
||||
if (rc) {
|
||||
kfree(protkey);
|
||||
kfree_sensitive(protkey);
|
||||
break;
|
||||
}
|
||||
if (ktp.pkey && ktp.pkeylen) {
|
||||
if (protkeylen > ktp.pkeylen) {
|
||||
kfree(protkey);
|
||||
kfree_sensitive(protkey);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (copy_to_user(ktp.pkey, protkey, protkeylen)) {
|
||||
kfree(protkey);
|
||||
kfree_sensitive(protkey);
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
kfree(protkey);
|
||||
kfree_sensitive(protkey);
|
||||
ktp.pkeylen = protkeylen;
|
||||
if (copy_to_user(utp, &ktp, sizeof(ktp)))
|
||||
return -EFAULT;
|
||||
|
@ -1300,9 +1300,6 @@ void zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus)
|
||||
struct zcrypt_device_status_ext *stat;
|
||||
int card, queue;
|
||||
|
||||
memset(devstatus, 0, MAX_ZDEV_ENTRIES_EXT
|
||||
* sizeof(struct zcrypt_device_status_ext));
|
||||
|
||||
spin_lock(&zcrypt_list_lock);
|
||||
for_each_zcrypt_card(zc) {
|
||||
for_each_zcrypt_queue(zq, zc) {
|
||||
@ -1607,9 +1604,9 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
size_t total_size = MAX_ZDEV_ENTRIES_EXT
|
||||
* sizeof(struct zcrypt_device_status_ext);
|
||||
|
||||
device_status = kvmalloc_array(MAX_ZDEV_ENTRIES_EXT,
|
||||
sizeof(struct zcrypt_device_status_ext),
|
||||
GFP_KERNEL);
|
||||
device_status = kvcalloc(MAX_ZDEV_ENTRIES_EXT,
|
||||
sizeof(struct zcrypt_device_status_ext),
|
||||
GFP_KERNEL);
|
||||
if (!device_status)
|
||||
return -ENOMEM;
|
||||
zcrypt_device_status_mask_ext(device_status);
|
||||
|
@ -1762,9 +1762,9 @@ static int findcard(u64 mkvp, u16 *pcardnr, u16 *pdomain,
|
||||
return -EINVAL;
|
||||
|
||||
/* fetch status of all crypto cards */
|
||||
device_status = kvmalloc_array(MAX_ZDEV_ENTRIES_EXT,
|
||||
sizeof(struct zcrypt_device_status_ext),
|
||||
GFP_KERNEL);
|
||||
device_status = kvcalloc(MAX_ZDEV_ENTRIES_EXT,
|
||||
sizeof(struct zcrypt_device_status_ext),
|
||||
GFP_KERNEL);
|
||||
if (!device_status)
|
||||
return -ENOMEM;
|
||||
zcrypt_device_status_mask_ext(device_status);
|
||||
@ -1878,9 +1878,9 @@ int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
||||
struct cca_info ci;
|
||||
|
||||
/* fetch status of all crypto cards */
|
||||
device_status = kvmalloc_array(MAX_ZDEV_ENTRIES_EXT,
|
||||
sizeof(struct zcrypt_device_status_ext),
|
||||
GFP_KERNEL);
|
||||
device_status = kvcalloc(MAX_ZDEV_ENTRIES_EXT,
|
||||
sizeof(struct zcrypt_device_status_ext),
|
||||
GFP_KERNEL);
|
||||
if (!device_status)
|
||||
return -ENOMEM;
|
||||
zcrypt_device_status_mask_ext(device_status);
|
||||
|
@ -1588,9 +1588,9 @@ int ep11_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
||||
struct ep11_card_info eci;
|
||||
|
||||
/* fetch status of all crypto cards */
|
||||
device_status = kvmalloc_array(MAX_ZDEV_ENTRIES_EXT,
|
||||
sizeof(struct zcrypt_device_status_ext),
|
||||
GFP_KERNEL);
|
||||
device_status = kvcalloc(MAX_ZDEV_ENTRIES_EXT,
|
||||
sizeof(struct zcrypt_device_status_ext),
|
||||
GFP_KERNEL);
|
||||
if (!device_status)
|
||||
return -ENOMEM;
|
||||
zcrypt_device_status_mask_ext(device_status);
|
||||
|
@ -1696,26 +1696,14 @@ static const struct attribute_group *netiucv_attr_groups[] = {
|
||||
static int netiucv_register_device(struct net_device *ndev)
|
||||
{
|
||||
struct netiucv_priv *priv = netdev_priv(ndev);
|
||||
struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
|
||||
struct device *dev;
|
||||
int ret;
|
||||
|
||||
IUCV_DBF_TEXT(trace, 3, __func__);
|
||||
|
||||
if (dev) {
|
||||
dev_set_name(dev, "net%s", ndev->name);
|
||||
dev->bus = &iucv_bus;
|
||||
dev->parent = iucv_root;
|
||||
dev->groups = netiucv_attr_groups;
|
||||
/*
|
||||
* The release function could be called after the
|
||||
* module has been unloaded. It's _only_ task is to
|
||||
* free the struct. Therefore, we specify kfree()
|
||||
* directly here. (Probably a little bit obfuscating
|
||||
* but legitime ...).
|
||||
*/
|
||||
dev->release = (void (*)(struct device *))kfree;
|
||||
dev->driver = &netiucv_driver;
|
||||
} else
|
||||
dev = iucv_alloc_device(netiucv_attr_groups, &netiucv_driver, NULL,
|
||||
"net%s", ndev->name);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = device_register(dev);
|
||||
|
@ -156,25 +156,14 @@ static int __init smsgiucv_app_init(void)
|
||||
if (!MACHINE_IS_VM)
|
||||
return -ENODEV;
|
||||
|
||||
smsg_app_dev = kzalloc(sizeof(*smsg_app_dev), GFP_KERNEL);
|
||||
smsgiucv_drv = driver_find(SMSGIUCV_DRV_NAME, &iucv_bus);
|
||||
if (!smsgiucv_drv)
|
||||
return -ENODEV;
|
||||
|
||||
smsg_app_dev = iucv_alloc_device(NULL, smsgiucv_drv, NULL, KMSG_COMPONENT);
|
||||
if (!smsg_app_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
smsgiucv_drv = driver_find(SMSGIUCV_DRV_NAME, &iucv_bus);
|
||||
if (!smsgiucv_drv) {
|
||||
kfree(smsg_app_dev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = dev_set_name(smsg_app_dev, KMSG_COMPONENT);
|
||||
if (rc) {
|
||||
kfree(smsg_app_dev);
|
||||
goto fail;
|
||||
}
|
||||
smsg_app_dev->bus = &iucv_bus;
|
||||
smsg_app_dev->parent = iucv_root;
|
||||
smsg_app_dev->release = (void (*)(struct device *)) kfree;
|
||||
smsg_app_dev->driver = smsgiucv_drv;
|
||||
rc = device_register(smsg_app_dev);
|
||||
if (rc) {
|
||||
put_device(smsg_app_dev);
|
||||
|
@ -1035,11 +1035,6 @@ static const struct attribute_group *hvc_iucv_dev_attr_groups[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void hvc_iucv_free(struct device *data)
|
||||
{
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance
|
||||
* @id: hvc_iucv_table index
|
||||
@ -1090,18 +1085,12 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)
|
||||
memcpy(priv->srv_name, name, 8);
|
||||
ASCEBC(priv->srv_name, 8);
|
||||
|
||||
/* create and setup device */
|
||||
priv->dev = kzalloc(sizeof(*priv->dev), GFP_KERNEL);
|
||||
priv->dev = iucv_alloc_device(hvc_iucv_dev_attr_groups, NULL,
|
||||
priv, "hvc_iucv%d", id);
|
||||
if (!priv->dev) {
|
||||
rc = -ENOMEM;
|
||||
goto out_error_dev;
|
||||
}
|
||||
dev_set_name(priv->dev, "hvc_iucv%d", id);
|
||||
dev_set_drvdata(priv->dev, priv);
|
||||
priv->dev->bus = &iucv_bus;
|
||||
priv->dev->parent = iucv_root;
|
||||
priv->dev->groups = hvc_iucv_dev_attr_groups;
|
||||
priv->dev->release = hvc_iucv_free;
|
||||
rc = device_register(priv->dev);
|
||||
if (rc) {
|
||||
put_device(priv->dev);
|
||||
|
@ -82,7 +82,12 @@ struct iucv_array {
|
||||
} __attribute__ ((aligned (8)));
|
||||
|
||||
extern const struct bus_type iucv_bus;
|
||||
extern struct device *iucv_root;
|
||||
|
||||
struct device_driver;
|
||||
|
||||
struct device *iucv_alloc_device(const struct attribute_group **attrs,
|
||||
struct device_driver *driver, void *priv,
|
||||
const char *fmt, ...) __printf(4, 5);
|
||||
|
||||
/*
|
||||
* struct iucv_path
|
||||
|
@ -73,8 +73,42 @@ const struct bus_type iucv_bus = {
|
||||
};
|
||||
EXPORT_SYMBOL(iucv_bus);
|
||||
|
||||
struct device *iucv_root;
|
||||
EXPORT_SYMBOL(iucv_root);
|
||||
static struct device *iucv_root;
|
||||
|
||||
static void iucv_release_device(struct device *device)
|
||||
{
|
||||
kfree(device);
|
||||
}
|
||||
|
||||
struct device *iucv_alloc_device(const struct attribute_group **attrs,
|
||||
struct device_driver *driver,
|
||||
void *priv, const char *fmt, ...)
|
||||
{
|
||||
struct device *dev;
|
||||
va_list vargs;
|
||||
int rc;
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
goto out_error;
|
||||
va_start(vargs, fmt);
|
||||
rc = dev_set_name(dev, fmt, vargs);
|
||||
va_end(vargs);
|
||||
if (rc)
|
||||
goto out_error;
|
||||
dev->bus = &iucv_bus;
|
||||
dev->parent = iucv_root;
|
||||
dev->driver = driver;
|
||||
dev->groups = attrs;
|
||||
dev->release = iucv_release_device;
|
||||
dev_set_drvdata(dev, priv);
|
||||
return dev;
|
||||
|
||||
out_error:
|
||||
kfree(dev);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(iucv_alloc_device);
|
||||
|
||||
static int iucv_available;
|
||||
|
||||
|
@ -20,7 +20,7 @@ $$(dest): $(1) FORCE
|
||||
$$(call cmd,install)
|
||||
|
||||
# Some architectures create .build-id symlinks
|
||||
ifneq ($(filter arm sparc x86, $(SRCARCH)),)
|
||||
ifneq ($(filter arm s390 sparc x86, $(SRCARCH)),)
|
||||
link := $(install-dir)/.build-id/$$(shell $(READELF) -n $(1) | sed -n 's@^.*Build ID: \(..\)\(.*\)@\1/\2@p').debug
|
||||
|
||||
__default: $$(link)
|
||||
|
Loading…
Reference in New Issue
Block a user