GIT ac89a00f7b89de3f556546ce5ae339603e606432 git://git390.osdl.marist.edu/pub/scm/linux-2.6.git#for-andrew commit Author: Martin Schwidefsky Date: Thu May 3 16:44:37 2007 +0200 [S390] add hardware capability support (ELF_HWCAP). Signed-off-by: Martin Schwidefsky commit 43fa66ab604e49ba4b53b1376e98277a6ce716e3 Author: Martin Schwidefsky Date: Thu May 3 16:43:49 2007 +0200 [S390] Export uaccess as non-gpl symbol. Commit c1821c2e9711adc3cd298a16b7237c92a2cee78d introduced the uaccess structure that is used to select the correct set of user copy functions for the different execution modes (standard vs. noexec vs. z9 optimized user copy). The uaccess symbol is exported with EXPORT_SYMBOL_GPL. This breaks all non-gpl modules that use user copy. To make them work again change the export to EXPORT_SYMBOL. Signed-off-by: Martin Schwidefsky commit e028c305e336837ad62ede6b732259f6225a37a2 Author: Jan Glauber Date: Thu May 3 16:43:48 2007 +0200 [S390] aes-s390 key length. Register aes-s390 algorithms with the actual supported max keylen size Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky commit 39059a8842b79b003812616cefa320dbe2df7d60 Author: Christoph Hellwig Date: Thu May 3 16:43:47 2007 +0200 [S390] get rid of kprobes notifier call chain. And here's a port of the powerpc patch to get rid of the notifier chain completely to s390. It's ontop of Martins patch as that one is in mainline already. Signed-off-by: Christoph Hellwig Signed-off-by: Martin Schwidefsky arch/s390/crypto/aes_s390.c | 15 ++++-- arch/s390/kernel/kprobes.c | 3 - arch/s390/kernel/setup.c | 111 +++++++++++++++++++++++++++++++++++++++++++ arch/s390/mm/fault.c | 40 +++++---------- include/asm-s390/elf.h | 7 ++- include/asm-s390/kdebug.h | 18 ++++++- include/asm-s390/kprobes.h | 16 ++---- include/asm-s390/lowcore.h | 10 ++-- 8 files changed, 165 insertions(+), 55 deletions(-) diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 9163635..3660ca6 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -119,7 +119,8 @@ static struct crypto_alg aes_alg = { .cra_name = "aes", .cra_driver_name = "aes-s390", .cra_priority = CRYPT_S390_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER | + CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_module = THIS_MODULE, @@ -206,7 +207,8 @@ static struct crypto_alg ecb_aes_alg = { .cra_name = "ecb(aes)", .cra_driver_name = "ecb-aes-s390", .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | + CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_type = &crypto_blkcipher_type, @@ -300,7 +302,8 @@ static struct crypto_alg cbc_aes_alg = { .cra_name = "cbc(aes)", .cra_driver_name = "cbc-aes-s390", .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | + CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_type = &crypto_blkcipher_type, @@ -333,10 +336,14 @@ static int __init aes_init(void) return -EOPNOTSUPP; /* z9 109 and z9 BC/EC only support 128 bit key length */ - if (keylen_flag == AES_KEYLEN_128) + if (keylen_flag == AES_KEYLEN_128) { + aes_alg.cra_u.cipher.cia_max_keysize = AES_MIN_KEY_SIZE; + ecb_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE; + cbc_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE; printk(KERN_INFO "aes_s390: hardware acceleration only available for" "128 bit keys\n"); + } ret = crypto_register_alg(&aes_alg); if (ret) diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 993f353..23c61f6 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -516,7 +516,7 @@ out: return 1; } -static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) +int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) { struct kprobe *cur = kprobe_running(); struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); @@ -603,7 +603,6 @@ int __kprobes kprobe_exceptions_notify(s ret = NOTIFY_STOP; break; case DIE_TRAP: - case DIE_PAGE_FAULT: /* kprobe_running() needs smp_processor_id() */ preempt_disable(); if (kprobe_running() && diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 3dfd098..6bfb088 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -65,7 +65,7 @@ long psw_user_bits = (PSW_BASE_BITS | PS * User copy operations. */ struct uaccess_ops uaccess; -EXPORT_SYMBOL_GPL(uaccess); +EXPORT_SYMBOL(uaccess); /* * Machine setup.. @@ -74,6 +74,8 @@ unsigned int console_mode = 0; unsigned int console_devno = -1; unsigned int console_irq = -1; unsigned long machine_flags = 0; +unsigned long elf_hwcap = 0; +char elf_platform[ELF_PLATFORM_SIZE]; struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS]; volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ @@ -749,6 +751,98 @@ #ifdef CONFIG_BLK_DEV_INITRD #endif } +static __init unsigned int stfl(void) +{ + asm volatile( + " .insn s,0xb2b10000,0(0)\n" /* stfl */ + "0:\n" + EX_TABLE(0b,0b)); + return S390_lowcore.stfl_fac_list; +} + +static __init int stfle(unsigned long long *list, int doublewords) +{ + typedef struct { unsigned long long _[doublewords]; } addrtype; + register unsigned long __nr asm("0") = doublewords - 1; + + asm volatile(".insn s,0xb2b00000,%0" /* stfle */ + : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc"); + return __nr + 1; +} + +/* + * Setup hardware capabilities. + */ +static void __init setup_hwcaps(void) +{ + static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 }; + struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data; + unsigned long long facility_list_extended; + unsigned int facility_list; + int i; + + facility_list = stfl(); + /* + * The store facility list bits numbers as found in the principles + * of operation are numbered with bit 1UL<<31 as number 0 to + * bit 1UL<<0 as number 31. + * Bit 0: instructions named N3, "backported" to esa-mode + * Bit 2: z/Architecture mode is active + * Bit 7: the store-facility-list-extended facility is installed + * Bit 17: the message-security assist is installed + * Bit 19: the long-displacement facility is installed + * Bit 21: the extended-immediate facility is installed + * These get translated to: + * HWCAP_S390_ESAN3 bit 0, HWCAP_S390_ZARCH bit 1, + * HWCAP_S390_STFLE bit 2, HWCAP_S390_MSA bit 3, + * HWCAP_S390_LDISP bit 4, and HWCAP_S390_EIMM bit 5. + */ + for (i = 0; i < 6; i++) + if (facility_list & (1UL << (31 - stfl_bits[i]))) + elf_hwcap |= 1UL << i; + + /* + * Check for additional facilities with store-facility-list-extended. + * stfle stores doublewords (8 byte) with bit 1ULL<<63 as bit 0 + * and 1ULL<<0 as bit 63. Bits 0-31 contain the same information + * as stored by stfl, bits 32-xxx contain additional facilities. + * How many facility words are stored depends on the number of + * doublewords passed to the instruction. The additional facilites + * are: + * Bit 43: decimal floating point facility is installed + * translated to: + * HWCAP_S390_DFP bit 6. + */ + if ((elf_hwcap & (1UL << 2)) && + stfle(&facility_list_extended, 1) > 0) { + if (facility_list_extended & (1ULL << (64 - 43))) + elf_hwcap |= 1UL << 6; + } + + switch (cpuinfo->cpu_id.machine) { + case 0x9672: +#if !defined(CONFIG_64BIT) + default: /* Use "g5" as default for 31 bit kernels. */ +#endif + strcpy(elf_platform, "g5"); + break; + case 0x2064: + case 0x2066: +#if defined(CONFIG_64BIT) + default: /* Use "z900" as default for 64 bit kernels. */ +#endif + strcpy(elf_platform, "z900"); + break; + case 0x2084: + case 0x2086: + strcpy(elf_platform, "z990"); + break; + case 0x2094: + strcpy(elf_platform, "z9-109"); + break; + } +} + /* * Setup function called from init/main.c just after the banner * was printed. @@ -805,6 +899,11 @@ #endif /* CONFIG_64BIT */ smp_setup_cpu_possible_map(); /* + * Setup capabilities (ELF_HWCAP & ELF_PLATFORM). + */ + setup_hwcaps(); + + /* * Create kernel page tables and switch to virtual addressing. */ paging_init(); @@ -839,8 +938,12 @@ #endif static int show_cpuinfo(struct seq_file *m, void *v) { + static const char *hwcap_str[7] = { + "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp" + }; struct cpuinfo_S390 *cpuinfo; unsigned long n = (unsigned long) v - 1; + int i; s390_adjust_jiffies(); preempt_disable(); @@ -850,7 +953,13 @@ static int show_cpuinfo(struct seq_file "bogomips per cpu: %lu.%02lu\n", num_online_cpus(), loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ))%100); + seq_puts(m, "features\t: "); + for (i = 0; i < 7; i++) + if (hwcap_str[i] && (elf_hwcap & (1UL << i))) + seq_printf(m, "%s ", hwcap_str[i]); + seq_puts(m, "\n"); } + if (cpu_online(n)) { #ifdef CONFIG_SMP if (smp_processor_id() == n) diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 2b76a87..91f705a 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -52,38 +52,24 @@ #endif extern void die(const char *,struct pt_regs *,long); #ifdef CONFIG_KPROBES -static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); -int register_page_fault_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); -} - -int unregister_page_fault_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); -} - -static int __kprobes __notify_page_fault(struct pt_regs *regs, long err) -{ - struct die_args args = { .str = "page fault", - .trapnr = 14, - .signr = SIGSEGV }; - args.regs = regs; - args.err = err; - return atomic_notifier_call_chain(¬ify_page_fault_chain, - DIE_PAGE_FAULT, &args); -} - static inline int notify_page_fault(struct pt_regs *regs, long err) { - if (unlikely(kprobe_running())) - return __notify_page_fault(regs, err); - return NOTIFY_DONE; + int ret = 0; + + /* kprobe_running() needs smp_processor_id() */ + if (!user_mode(regs)) { + preempt_disable(); + if (kprobe_running() && kprobe_fault_handler(regs, 14)) + ret = 1; + preempt_enable(); + } + + return ret; } #else static inline int notify_page_fault(struct pt_regs *regs, long err) { - return NOTIFY_DONE; + return 0; } #endif @@ -319,7 +305,7 @@ do_exception(struct pt_regs *regs, unsig int space; int si_code; - if (notify_page_fault(regs, error_code) == NOTIFY_STOP) + if (notify_page_fault(regs, error_code)) return; tsk = current; diff --git a/include/asm-s390/elf.h b/include/asm-s390/elf.h index c0d629d..91d0632 100644 --- a/include/asm-s390/elf.h +++ b/include/asm-s390/elf.h @@ -188,7 +188,8 @@ #define ELF_CORE_COPY_FPREGS(tsk, fpregs /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. */ -#define ELF_HWCAP (0) +extern unsigned long elf_hwcap; +#define ELF_HWCAP (elf_hwcap) /* This yields a string that ld.so will use to load implementation specific libraries for optimization. This is more specific in @@ -197,7 +198,9 @@ #define ELF_HWCAP (0) For the moment, we have only optimizations for the Intel generations, but that could change... */ -#define ELF_PLATFORM (NULL) +#define ELF_PLATFORM_SIZE 8 +extern char elf_platform[]; +#define ELF_PLATFORM (elf_platform) #ifndef __s390x__ #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) diff --git a/include/asm-s390/kdebug.h b/include/asm-s390/kdebug.h index 1b50f89..d2d7ad2 100644 --- a/include/asm-s390/kdebug.h +++ b/include/asm-s390/kdebug.h @@ -22,8 +22,21 @@ struct die_args { */ extern int register_die_notifier(struct notifier_block *); extern int unregister_die_notifier(struct notifier_block *); -extern int register_page_fault_notifier(struct notifier_block *); -extern int unregister_page_fault_notifier(struct notifier_block *); + +/* + * These are only here because kprobes.c wants them to implement a + * blatant layering violation. Will hopefully go away soon once all + * architectures are updated. + */ +static inline int register_page_fault_notifier(struct notifier_block *nb) +{ + return 0; +} +static inline int unregister_page_fault_notifier(struct notifier_block *nb) +{ + return 0; +} + extern struct atomic_notifier_head s390die_chain; enum die_val { @@ -39,7 +52,6 @@ enum die_val { DIE_GPF, DIE_CALL, DIE_NMI_IPI, - DIE_PAGE_FAULT, }; static inline int notify_die(enum die_val val, const char *str, diff --git a/include/asm-s390/kprobes.h b/include/asm-s390/kprobes.h index b847ff0..830fe4c 100644 --- a/include/asm-s390/kprobes.h +++ b/include/asm-s390/kprobes.h @@ -97,18 +97,10 @@ void kretprobe_trampoline(void); int is_prohibited_opcode(kprobe_opcode_t *instruction); void get_instruction_type(struct arch_specific_insn *ainsn); +int kprobe_fault_handler(struct pt_regs *regs, int trapnr); +int kprobe_exceptions_notify(struct notifier_block *self, + unsigned long val, void *data); + #define flush_insn_slot(p) do { } while (0) #endif /* _ASM_S390_KPROBES_H */ - -#ifdef CONFIG_KPROBES - -extern int kprobe_exceptions_notify(struct notifier_block *self, - unsigned long val, void *data); -#else /* !CONFIG_KPROBES */ -static inline int kprobe_exceptions_notify(struct notifier_block *self, - unsigned long val, void *data) -{ - return 0; -} -#endif diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h index ffc9788..801a6fd 100644 --- a/include/asm-s390/lowcore.h +++ b/include/asm-s390/lowcore.h @@ -229,17 +229,19 @@ #ifndef __s390x__ __u16 subchannel_nr; /* 0x0ba */ __u32 io_int_parm; /* 0x0bc */ __u32 io_int_word; /* 0x0c0 */ - __u8 pad3[0xD4-0xC4]; /* 0x0c4 */ + __u8 pad3[0xc8-0xc4]; /* 0x0c4 */ + __u32 stfl_fac_list; /* 0x0c8 */ + __u8 pad4[0xd4-0xcc]; /* 0x0cc */ __u32 extended_save_area_addr; /* 0x0d4 */ __u32 cpu_timer_save_area[2]; /* 0x0d8 */ __u32 clock_comp_save_area[2]; /* 0x0e0 */ __u32 mcck_interruption_code[2]; /* 0x0e8 */ - __u8 pad4[0xf4-0xf0]; /* 0x0f0 */ + __u8 pad5[0xf4-0xf0]; /* 0x0f0 */ __u32 external_damage_code; /* 0x0f4 */ __u32 failing_storage_address; /* 0x0f8 */ - __u8 pad5[0x100-0xfc]; /* 0x0fc */ + __u8 pad6[0x100-0xfc]; /* 0x0fc */ __u32 st_status_fixed_logout[4];/* 0x100 */ - __u8 pad6[0x120-0x110]; /* 0x110 */ + __u8 pad7[0x120-0x110]; /* 0x110 */ __u32 access_regs_save_area[16];/* 0x120 */ __u32 floating_pt_save_area[8]; /* 0x160 */ __u32 gpregs_save_area[16]; /* 0x180 */