Pull s390 updates from Vasily Gorbik: - Add support for stackleak feature. Also allow specifying architecture-specific stackleak poison function to enable faster implementation. On s390, the mvc-based implementation helps decrease typical overhead from a factor of 3 to just 25% - Convert all assembler files to use SYM* style macros, deprecating the ENTRY() macro and other annotations. Select ARCH_USE_SYM_ANNOTATIONS - Improve KASLR to also randomize module and special amode31 code base load addresses - Rework decompressor memory tracking to support memory holes and improve error handling - Add support for protected virtualization AP binding - Add support for set_direct_map() calls - Implement set_memory_rox() and noexec module_alloc() - Remove obsolete overriding of mem*() functions for KASAN - Rework kexec/kdump to avoid using nodat_stack to call purgatory - Convert the rest of the s390 code to use flexible-array member instead of a zero-length array - Clean up uaccess inline asm - Enable ARCH_HAS_MEMBARRIER_SYNC_CORE - Convert to using CONFIG_FUNCTION_ALIGNMENT and enable DEBUG_FORCE_FUNCTION_ALIGN_64B - Resolve last_break in userspace fault reports - Simplify one-level sysctl registration - Clean up branch prediction handling - Rework CPU counter facility to retrieve available counter sets just once - Other various small fixes and improvements all over the code * tag 's390-6.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (118 commits) s390/stackleak: provide fast __stackleak_poison() implementation stackleak: allow to specify arch specific stackleak poison function s390: select ARCH_USE_SYM_ANNOTATIONS s390/mm: use VM_FLUSH_RESET_PERMS in module_alloc() s390: wire up memfd_secret system call s390/mm: enable ARCH_HAS_SET_DIRECT_MAP s390/mm: use BIT macro to generate SET_MEMORY bit masks s390/relocate_kernel: adjust indentation s390/relocate_kernel: use SYM* macros instead of ENTRY(), etc. s390/entry: use SYM* macros instead of ENTRY(), etc. s390/purgatory: use SYM* macros instead of ENTRY(), etc. s390/kprobes: use SYM* macros instead of ENTRY(), etc. s390/reipl: use SYM* macros instead of ENTRY(), etc. s390/head64: use SYM* macros instead of ENTRY(), etc. s390/earlypgm: use SYM* macros instead of ENTRY(), etc. s390/mcount: use SYM* macros instead of ENTRY(), etc. s390/crc32le: use SYM* macros instead of ENTRY(), etc. s390/crc32be: use SYM* macros instead of ENTRY(), etc. s390/crypto,chacha: use SYM* macros instead of ENTRY(), etc. s390/amode31: use SYM* macros instead of ENTRY(), etc. ...
Unified · Split
| @@ -5,7 +5,7 @@ · 4 unmodified lines | |||
| 5 | # | 5 | # |
| 6 | # Architecture requirements | 6 | # Architecture requirements |
| 7 | # | 7 | # |
| 8 | # * arm/arm64/powerpc | 8 | # * arm/arm64/powerpc/s390 |
| 9 | # | 9 | # |
| 10 | # Rely on implicit context synchronization as a result of exception return | 10 | # Rely on implicit context synchronization as a result of exception return |
| 11 | # when returning from IPI handler, and when returning to user-space. | 11 | # when returning from IPI handler, and when returning to user-space. |
| @@ -45,7 +45,7 @@ · 33 unmodified lines | |||
| 45 | | parisc: | TODO | | 45 | | parisc: | TODO | |
| 46 | | powerpc: | ok | | 46 | | powerpc: | ok | |
| 47 | | riscv: | TODO | | 47 | | riscv: | TODO | |
| 48 | | s390: | TODO | | 48 | | s390: | ok | |
| 49 | | sh: | TODO | | 49 | | sh: | TODO | |
| 50 | | sparc: | TODO | | 50 | | sparc: | TODO | |
| 51 | | um: | TODO | | 51 | | um: | TODO | |
| @@ -26,10 +26,6 @@ config GENERIC_BUG · 25 unmodified lines | |||
| 26 | config GENERIC_BUG_RELATIVE_POINTERS | 26 | config GENERIC_BUG_RELATIVE_POINTERS |
| 27 | def_bool y | 27 | def_bool y |
| 28 | 28 | ||
| 29 | config GENERIC_CSUM | ||
| 30 | bool | ||
| 31 | default y if KASAN | ||
| 32 | |||
| 33 | config GENERIC_LOCKBREAK | 29 | config GENERIC_LOCKBREAK |
| 34 | def_bool y if PREEMPTION | 30 | def_bool y if PREEMPTION |
| 35 | 31 | ||
| @@ -76,10 +72,12 @@ config S390 · 40 unmodified lines | |||
| 76 | select ARCH_HAS_GCOV_PROFILE_ALL | 72 | select ARCH_HAS_GCOV_PROFILE_ALL |
| 77 | select ARCH_HAS_GIGANTIC_PAGE | 73 | select ARCH_HAS_GIGANTIC_PAGE |
| 78 | select ARCH_HAS_KCOV | 74 | select ARCH_HAS_KCOV |
| 75 | select ARCH_HAS_MEMBARRIER_SYNC_CORE | ||
| 79 | select ARCH_HAS_MEM_ENCRYPT | 76 | select ARCH_HAS_MEM_ENCRYPT |
| 80 | select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS | 77 | select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS |
| 81 | select ARCH_HAS_PTE_SPECIAL | 78 | select ARCH_HAS_PTE_SPECIAL |
| 82 | select ARCH_HAS_SCALED_CPUTIME | 79 | select ARCH_HAS_SCALED_CPUTIME |
| 80 | select ARCH_HAS_SET_DIRECT_MAP | ||
| 83 | select ARCH_HAS_SET_MEMORY | 81 | select ARCH_HAS_SET_MEMORY |
| 84 | select ARCH_HAS_STRICT_KERNEL_RWX | 82 | select ARCH_HAS_STRICT_KERNEL_RWX |
| 85 | select ARCH_HAS_STRICT_MODULE_RWX | 83 | select ARCH_HAS_STRICT_MODULE_RWX |
| @@ -123,6 +121,7 @@ config S390 · 37 unmodified lines | |||
| 123 | select ARCH_SUPPORTS_PER_VMA_LOCK | 121 | select ARCH_SUPPORTS_PER_VMA_LOCK |
| 124 | select ARCH_USE_BUILTIN_BSWAP | 122 | select ARCH_USE_BUILTIN_BSWAP |
| 125 | select ARCH_USE_CMPXCHG_LOCKREF | 123 | select ARCH_USE_CMPXCHG_LOCKREF |
| 124 | select ARCH_USE_SYM_ANNOTATIONS | ||
| 126 | select ARCH_WANTS_DYNAMIC_TASK_STRUCT | 125 | select ARCH_WANTS_DYNAMIC_TASK_STRUCT |
| 127 | select ARCH_WANTS_NO_INSTR | 126 | select ARCH_WANTS_NO_INSTR |
| 128 | select ARCH_WANT_DEFAULT_BPF_JIT | 127 | select ARCH_WANT_DEFAULT_BPF_JIT |
| @@ -132,6 +131,8 @@ config S390 · 3 unmodified lines | |||
| 132 | select CLONE_BACKWARDS2 | 131 | select CLONE_BACKWARDS2 |
| 133 | select DMA_OPS if PCI | 132 | select DMA_OPS if PCI |
| 134 | select DYNAMIC_FTRACE if FUNCTION_TRACER | 133 | select DYNAMIC_FTRACE if FUNCTION_TRACER |
| 134 | select FUNCTION_ALIGNMENT_8B if CC_IS_GCC | ||
| 135 | select FUNCTION_ALIGNMENT_16B if !CC_IS_GCC | ||
| 135 | select GCC12_NO_ARRAY_BOUNDS | 136 | select GCC12_NO_ARRAY_BOUNDS |
| 136 | select GENERIC_ALLOCATOR | 137 | select GENERIC_ALLOCATOR |
| 137 | select GENERIC_CPU_AUTOPROBE | 138 | select GENERIC_CPU_AUTOPROBE |
| @@ -153,6 +154,7 @@ config S390 · 15 unmodified lines | |||
| 153 | select HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET | 154 | select HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET |
| 154 | select HAVE_ARCH_SECCOMP_FILTER | 155 | select HAVE_ARCH_SECCOMP_FILTER |
| 155 | select HAVE_ARCH_SOFT_DIRTY | 156 | select HAVE_ARCH_SOFT_DIRTY |
| 157 | select HAVE_ARCH_STACKLEAK | ||
| 156 | select HAVE_ARCH_TRACEHOOK | 158 | select HAVE_ARCH_TRACEHOOK |
| 157 | select HAVE_ARCH_TRANSPARENT_HUGEPAGE | 159 | select HAVE_ARCH_TRANSPARENT_HUGEPAGE |
| 158 | select HAVE_ARCH_VMAP_STACK | 160 | select HAVE_ARCH_VMAP_STACK |
| @@ -66,16 +66,6 @@ static struct ctl_table appldata_table[] = { · 65 unmodified lines | |||
| 66 | { }, | 66 | { }, |
| 67 | }; | 67 | }; |
| 68 | 68 | ||
| 69 | static struct ctl_table appldata_dir_table[] = { | ||
| 70 | { | ||
| 71 | .procname = appldata_proc_name, | ||
| 72 | .maxlen = 0, | ||
| 73 | .mode = S_IRUGO | S_IXUGO, | ||
| 74 | .child = appldata_table, | ||
| 75 | }, | ||
| 76 | { }, | ||
| 77 | }; | ||
| 78 | |||
| 79 | /* | 69 | /* |
| 80 | * Timer | 70 | * Timer |
| 81 | */ | 71 | */ |
| @@ -291,7 +281,7 @@ appldata_generic_handler(struct ctl_table *ctl, int write, · 209 unmodified lines | |||
| 291 | mutex_lock(&appldata_ops_mutex); | 281 | mutex_lock(&appldata_ops_mutex); |
| 292 | list_for_each(lh, &appldata_ops_list) { | 282 | list_for_each(lh, &appldata_ops_list) { |
| 293 | tmp_ops = list_entry(lh, struct appldata_ops, list); | 283 | tmp_ops = list_entry(lh, struct appldata_ops, list); |
| 294 | if (&tmp_ops->ctl_table[2] == ctl) { | 284 | if (&tmp_ops->ctl_table[0] == ctl) { |
| 295 | found = 1; | 285 | found = 1; |
| 296 | } | 286 | } |
| 297 | } | 287 | } |
| @@ -361,7 +351,8 @@ int appldata_register_ops(struct appldata_ops *ops) · 63 unmodified lines | |||
| 361 | if (ops->size > APPLDATA_MAX_REC_SIZE) | 351 | if (ops->size > APPLDATA_MAX_REC_SIZE) |
| 362 | return -EINVAL; | 352 | return -EINVAL; |
| 363 | 353 | ||
| 364 | ops->ctl_table = kcalloc(4, sizeof(struct ctl_table), GFP_KERNEL); | 354 | /* The last entry must be an empty one */ |
| 355 | ops->ctl_table = kcalloc(2, sizeof(struct ctl_table), GFP_KERNEL); | ||
| 365 | if (!ops->ctl_table) | 356 | if (!ops->ctl_table) |
| 366 | return -ENOMEM; | 357 | return -ENOMEM; |
| 367 | 358 | ||
| @@ -369,17 +360,12 @@ int appldata_register_ops(struct appldata_ops *ops) · 1 unmodified line | |||
| 369 | list_add(&ops->list, &appldata_ops_list); | 360 | list_add(&ops->list, &appldata_ops_list); |
| 370 | mutex_unlock(&appldata_ops_mutex); | 361 | mutex_unlock(&appldata_ops_mutex); |
| 371 | 362 | ||
| 372 | ops->ctl_table[0].procname = appldata_proc_name; | 363 | ops->ctl_table[0].procname = ops->name; |
| 373 | ops->ctl_table[0].maxlen = 0; | 364 | ops->ctl_table[0].mode = S_IRUGO | S_IWUSR; |
| 374 | ops->ctl_table[0].mode = S_IRUGO | S_IXUGO; | 365 | ops->ctl_table[0].proc_handler = appldata_generic_handler; |
| 375 | ops->ctl_table[0].child = &ops->ctl_table[2]; | 366 | ops->ctl_table[0].data = ops; |
| 376 | |||
| 377 | ops->ctl_table[2].procname = ops->name; | ||
| 378 | ops->ctl_table[2].mode = S_IRUGO | S_IWUSR; | ||
| 379 | ops->ctl_table[2].proc_handler = appldata_generic_handler; | ||
| 380 | ops->ctl_table[2].data = ops; | ||
| 381 | 367 | ||
| 382 | ops->sysctl_header = register_sysctl_table(ops->ctl_table); | 368 | ops->sysctl_header = register_sysctl(appldata_proc_name, ops->ctl_table); |
| 383 | if (!ops->sysctl_header) | 369 | if (!ops->sysctl_header) |
| 384 | goto out; | 370 | goto out; |
| 385 | return 0; | 371 | return 0; |
| @@ -422,7 +408,7 @@ static int __init appldata_init(void) · 36 unmodified lines | |||
| 422 | appldata_wq = alloc_ordered_workqueue("appldata", 0); | 408 | appldata_wq = alloc_ordered_workqueue("appldata", 0); |
| 423 | if (!appldata_wq) | 409 | if (!appldata_wq) |
| 424 | return -ENOMEM; | 410 | return -ENOMEM; |
| 425 | appldata_sysctl_header = register_sysctl_table(appldata_dir_table); | 411 | appldata_sysctl_header = register_sysctl(appldata_proc_name, appldata_table); |
| 426 | return 0; | 412 | return 0; |
| 427 | } | 413 | } |
| 428 | 414 | ||
| @@ -35,7 +35,7 @@ endif · 34 unmodified lines | |||
| 35 | 35 | ||
| 36 | CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char | 36 | CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char |
| 37 | 37 | ||
| 38 | obj-y := head.o als.o startup.o mem_detect.o ipl_parm.o ipl_report.o vmem.o | 38 | obj-y := head.o als.o startup.o physmem_info.o ipl_parm.o ipl_report.o vmem.o |
| 39 | obj-y += string.o ebcdic.o sclp_early_core.o mem.o ipl_vmparm.o cmdline.o | 39 | obj-y += string.o ebcdic.o sclp_early_core.o mem.o ipl_vmparm.o cmdline.o |
| 40 | obj-y += version.o pgm_check_info.o ctype.o ipl_data.o machine_kexec_reloc.o | 40 | obj-y += version.o pgm_check_info.o ctype.o ipl_data.o machine_kexec_reloc.o |
| 41 | obj-$(findstring y, $(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) $(CONFIG_PGSTE)) += uv.o | 41 | obj-$(findstring y, $(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) $(CONFIG_PGSTE)) += uv.o |
| @@ -8,6 +8,8 @@ · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | #ifndef __ASSEMBLY__ | 9 | #ifndef __ASSEMBLY__ |
| 10 | 10 | ||
| 11 | #include <asm/physmem_info.h> | ||
| 12 | |||
| 11 | struct machine_info { | 13 | struct machine_info { |
| 12 | unsigned char has_edat1 : 1; | 14 | unsigned char has_edat1 : 1; |
| 13 | unsigned char has_edat2 : 1; | 15 | unsigned char has_edat2 : 1; |
| @@ -30,24 +32,46 @@ struct vmlinux_info { · 16 unmodified lines | |||
| 30 | unsigned long init_mm_off; | 32 | unsigned long init_mm_off; |
| 31 | unsigned long swapper_pg_dir_off; | 33 | unsigned long swapper_pg_dir_off; |
| 32 | unsigned long invalid_pg_dir_off; | 34 | unsigned long invalid_pg_dir_off; |
| 35 | #ifdef CONFIG_KASAN | ||
| 36 | unsigned long kasan_early_shadow_page_off; | ||
| 37 | unsigned long kasan_early_shadow_pte_off; | ||
| 38 | unsigned long kasan_early_shadow_pmd_off; | ||
| 39 | unsigned long kasan_early_shadow_pud_off; | ||
| 40 | unsigned long kasan_early_shadow_p4d_off; | ||
| 41 | #endif | ||
| 33 | }; | 42 | }; |
| 34 | 43 | ||
| 35 | void startup_kernel(void); | 44 | void startup_kernel(void); |
| 36 | unsigned long detect_memory(unsigned long *safe_addr); | 45 | unsigned long detect_max_physmem_end(void); |
| 37 | void mem_detect_set_usable_limit(unsigned long limit); | 46 | void detect_physmem_online_ranges(unsigned long max_physmem_end); |
| 47 | void physmem_set_usable_limit(unsigned long limit); | ||
| 48 | void physmem_reserve(enum reserved_range_type type, unsigned long addr, unsigned long size); | ||
| 49 | void physmem_free(enum reserved_range_type type); | ||
| 50 | /* for continuous/multiple allocations per type */ | ||
| 51 | unsigned long physmem_alloc_top_down(enum reserved_range_type type, unsigned long size, | ||
| 52 | unsigned long align); | ||
| 53 | /* for single allocations, 1 per type */ | ||
| 54 | unsigned long physmem_alloc_range(enum reserved_range_type type, unsigned long size, | ||
| 55 | unsigned long align, unsigned long min, unsigned long max, | ||
| 56 | bool die_on_oom); | ||
| 57 | unsigned long get_physmem_alloc_pos(void); | ||
| 58 | bool ipl_report_certs_intersects(unsigned long addr, unsigned long size, | ||
| 59 | unsigned long *intersection_start); | ||
| 38 | bool is_ipl_block_dump(void); | 60 | bool is_ipl_block_dump(void); |
| 39 | void store_ipl_parmblock(void); | 61 | void store_ipl_parmblock(void); |
| 40 | unsigned long read_ipl_report(unsigned long safe_addr); | 62 | int read_ipl_report(void); |
| 63 | void save_ipl_cert_comp_list(void); | ||
| 41 | void setup_boot_command_line(void); | 64 | void setup_boot_command_line(void); |
| 42 | void parse_boot_command_line(void); | 65 | void parse_boot_command_line(void); |
| 43 | void verify_facilities(void); | 66 | void verify_facilities(void); |
| 44 | void print_missing_facilities(void); | 67 | void print_missing_facilities(void); |
| 45 | void sclp_early_setup_buffer(void); | 68 | void sclp_early_setup_buffer(void); |
| 46 | void print_pgm_check_info(void); | 69 | void print_pgm_check_info(void); |
| 47 | unsigned long get_random_base(unsigned long safe_addr); | 70 | unsigned long randomize_within_range(unsigned long size, unsigned long align, |
| 71 | unsigned long min, unsigned long max); | ||
| 48 | void setup_vmem(unsigned long asce_limit); | 72 | void setup_vmem(unsigned long asce_limit); |
| 49 | unsigned long vmem_estimate_memory_needs(unsigned long online_mem_total); | ||
| 50 | void __printf(1, 2) decompressor_printk(const char *fmt, ...); | 73 | void __printf(1, 2) decompressor_printk(const char *fmt, ...); |
| 74 | void print_stacktrace(unsigned long sp); | ||
| 51 | void error(char *m); | 75 | void error(char *m); |
| 52 | 76 | ||
| 53 | extern struct machine_info machine; | 77 | extern struct machine_info machine; |
| @@ -57,12 +81,11 @@ extern const char kernel_version[]; · 3 unmodified lines | |||
| 57 | extern unsigned long memory_limit; | 81 | extern unsigned long memory_limit; |
| 58 | extern unsigned long vmalloc_size; | 82 | extern unsigned long vmalloc_size; |
| 59 | extern int vmalloc_size_set; | 83 | extern int vmalloc_size_set; |
| 60 | extern int kaslr_enabled; | ||
| 61 | extern char __boot_data_start[], __boot_data_end[]; | 84 | extern char __boot_data_start[], __boot_data_end[]; |
| 62 | extern char __boot_data_preserved_start[], __boot_data_preserved_end[]; | 85 | extern char __boot_data_preserved_start[], __boot_data_preserved_end[]; |
| 63 | extern char _decompressor_syms_start[], _decompressor_syms_end[]; | 86 | extern char _decompressor_syms_start[], _decompressor_syms_end[]; |
| 64 | extern char _stack_start[], _stack_end[]; | 87 | extern char _stack_start[], _stack_end[]; |
| 65 | extern char _end[]; | 88 | extern char _end[], _decompressor_end[]; |
| 66 | extern unsigned char _compressed_start[]; | 89 | extern unsigned char _compressed_start[]; |
| 67 | extern unsigned char _compressed_end[]; | 90 | extern unsigned char _compressed_end[]; |
| 68 | extern struct vmlinux_info _vmlinux_info; | 91 | extern struct vmlinux_info _vmlinux_info; |
| @@ -70,5 +93,10 @@ extern struct vmlinux_info _vmlinux_info; · 1 unmodified line | |||
| 70 | 93 | ||
| 71 | #define __abs_lowcore_pa(x) (((unsigned long)(x) - __abs_lowcore) % sizeof(struct lowcore)) | 94 | #define __abs_lowcore_pa(x) (((unsigned long)(x) - __abs_lowcore) % sizeof(struct lowcore)) |
| 72 | 95 | ||
| 96 | static inline bool intersects(unsigned long addr0, unsigned long size0, | ||
| 97 | unsigned long addr1, unsigned long size1) | ||
| 98 | { | ||
| 99 | return addr0 + size0 > addr1 && addr1 + size1 > addr0; | ||
| 100 | } | ||
| 73 | #endif /* __ASSEMBLY__ */ | 101 | #endif /* __ASSEMBLY__ */ |
| 74 | #endif /* BOOT_BOOT_H */ | 102 | #endif /* BOOT_BOOT_H */ |
| @@ -17,8 +17,8 @@ · 16 unmodified lines | |||
| 17 | 17 | ||
| 18 | echo "Warning: '${INSTALLKERNEL}' command not available - additional " \ | 18 | echo "Warning: '${INSTALLKERNEL}' command not available - additional " \ |
| 19 | "bootloader config required" >&2 | 19 | "bootloader config required" >&2 |
| 20 | if [ -f $4/vmlinuz-$1 ]; then mv $4/vmlinuz-$1 $4/vmlinuz-$1.old; fi | 20 | if [ -f "$4/vmlinuz-$1" ]; then mv -- "$4/vmlinuz-$1" "$4/vmlinuz-$1.old"; fi |
| 21 | if [ -f $4/System.map-$1 ]; then mv $4/System.map-$1 $4/System.map-$1.old; fi | 21 | if [ -f "$4/System.map-$1" ]; then mv -- "$4/System.map-$1" "$4/System.map-$1.old"; fi |
| 22 | 22 | ||
| 23 | cat $2 > $4/vmlinuz-$1 | 23 | cat -- "$2" > "$4/vmlinuz-$1" |
| 24 | cp $3 $4/System.map-$1 | 24 | cp -- "$3" "$4/System.map-$1" |
| @@ -24,11 +24,11 @@ int __bootdata(noexec_disabled); · 23 unmodified lines | |||
| 24 | unsigned int __bootdata_preserved(zlib_dfltcc_support) = ZLIB_DFLTCC_FULL; | 24 | unsigned int __bootdata_preserved(zlib_dfltcc_support) = ZLIB_DFLTCC_FULL; |
| 25 | struct ipl_parameter_block __bootdata_preserved(ipl_block); | 25 | struct ipl_parameter_block __bootdata_preserved(ipl_block); |
| 26 | int __bootdata_preserved(ipl_block_valid); | 26 | int __bootdata_preserved(ipl_block_valid); |
| 27 | int __bootdata_preserved(__kaslr_enabled); | ||
| 27 | 28 | ||
| 28 | unsigned long vmalloc_size = VMALLOC_DEFAULT_SIZE; | 29 | unsigned long vmalloc_size = VMALLOC_DEFAULT_SIZE; |
| 29 | unsigned long memory_limit; | 30 | unsigned long memory_limit; |
| 30 | int vmalloc_size_set; | 31 | int vmalloc_size_set; |
| 31 | int kaslr_enabled; | ||
| 32 | 32 | ||
| 33 | static inline int __diag308(unsigned long subcode, void *addr) | 33 | static inline int __diag308(unsigned long subcode, void *addr) |
| 34 | { | 34 | { |
| @@ -264,7 +264,7 @@ void parse_boot_command_line(void) · 229 unmodified lines | |||
| 264 | char *args; | 264 | char *args; |
| 265 | int rc; | 265 | int rc; |
| 266 | 266 | ||
| 267 | kaslr_enabled = IS_ENABLED(CONFIG_RANDOMIZE_BASE); | 267 | __kaslr_enabled = IS_ENABLED(CONFIG_RANDOMIZE_BASE); |
| 268 | args = strcpy(command_line_buf, early_command_line); | 268 | args = strcpy(command_line_buf, early_command_line); |
| 269 | while (*args) { | 269 | while (*args) { |
| 270 | args = next_arg(args, ¶m, &val); | 270 | args = next_arg(args, ¶m, &val); |
| @@ -300,7 +300,7 @@ void parse_boot_command_line(void) · 29 unmodified lines | |||
| 300 | modify_fac_list(val); | 300 | modify_fac_list(val); |
| 301 | 301 | ||
| 302 | if (!strcmp(param, "nokaslr")) | 302 | if (!strcmp(param, "nokaslr")) |
| 303 | kaslr_enabled = 0; | 303 | __kaslr_enabled = 0; |
| 304 | 304 | ||
| 305 | #if IS_ENABLED(CONFIG_KVM) | 305 | #if IS_ENABLED(CONFIG_KVM) |
| 306 | if (!strcmp(param, "prot_virt")) { | 306 | if (!strcmp(param, "prot_virt")) { |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | |||
| 5 | #include <asm/sclp.h> | 5 | #include <asm/sclp.h> |
| 6 | #include <asm/sections.h> | 6 | #include <asm/sections.h> |
| 7 | #include <asm/boot_data.h> | 7 | #include <asm/boot_data.h> |
| 8 | #include <asm/physmem_info.h> | ||
| 8 | #include <uapi/asm/ipl.h> | 9 | #include <uapi/asm/ipl.h> |
| 9 | #include "boot.h" | 10 | #include "boot.h" |
| 10 | 11 | ||
| @@ -16,20 +17,16 @@ unsigned long __bootdata_preserved(ipl_cert_list_size); · 5 unmodified lines | |||
| 16 | unsigned long __bootdata(early_ipl_comp_list_addr); | 17 | unsigned long __bootdata(early_ipl_comp_list_addr); |
| 17 | unsigned long __bootdata(early_ipl_comp_list_size); | 18 | unsigned long __bootdata(early_ipl_comp_list_size); |
| 18 | 19 | ||
| 20 | static struct ipl_rb_certificates *certs; | ||
| 21 | static struct ipl_rb_components *comps; | ||
| 22 | static bool ipl_report_needs_saving; | ||
| 23 | |||
| 19 | #define for_each_rb_entry(entry, rb) \ | 24 | #define for_each_rb_entry(entry, rb) \ |
| 20 | for (entry = rb->entries; \ | 25 | for (entry = rb->entries; \ |
| 21 | (void *) entry + sizeof(*entry) <= (void *) rb + rb->len; \ | 26 | (void *) entry + sizeof(*entry) <= (void *) rb + rb->len; \ |
| 22 | entry++) | 27 | entry++) |
| 23 | 28 | ||
| 24 | static inline bool intersects(unsigned long addr0, unsigned long size0, | 29 | static unsigned long get_cert_comp_list_size(void) |
| 25 | unsigned long addr1, unsigned long size1) | ||
| 26 | { | ||
| 27 | return addr0 + size0 > addr1 && addr1 + size1 > addr0; | ||
| 28 | } | ||
| 29 | |||
| 30 | static unsigned long find_bootdata_space(struct ipl_rb_components *comps, | ||
| 31 | struct ipl_rb_certificates *certs, | ||
| 32 | unsigned long safe_addr) | ||
| 33 | { | 30 | { |
| 34 | struct ipl_rb_certificate_entry *cert; | 31 | struct ipl_rb_certificate_entry *cert; |
| 35 | struct ipl_rb_component_entry *comp; | 32 | struct ipl_rb_component_entry *comp; |
| @@ -44,44 +41,27 @@ static unsigned long find_bootdata_space(struct ipl_rb_components *comps, · 8 unmodified lines | |||
| 44 | ipl_cert_list_size = 0; | 41 | ipl_cert_list_size = 0; |
| 45 | for_each_rb_entry(cert, certs) | 42 | for_each_rb_entry(cert, certs) |
| 46 | ipl_cert_list_size += sizeof(unsigned int) + cert->len; | 43 | ipl_cert_list_size += sizeof(unsigned int) + cert->len; |
| 47 | size = ipl_cert_list_size + early_ipl_comp_list_size; | 44 | return ipl_cert_list_size + early_ipl_comp_list_size; |
| 45 | } | ||
| 48 | 46 | ||
| 49 | /* | 47 | bool ipl_report_certs_intersects(unsigned long addr, unsigned long size, |
| 50 | * Start from safe_addr to find a free memory area large | 48 | unsigned long *intersection_start) |
| 51 | * enough for the IPL report boot data. This area is used | 49 | { |
| 52 | * for ipl_cert_list_addr/ipl_cert_list_size and | 50 | struct ipl_rb_certificate_entry *cert; |
| 53 | * early_ipl_comp_list_addr/early_ipl_comp_list_size. It must | 51 | |
| 54 | * not overlap with any component or any certificate. | 52 | if (!ipl_report_needs_saving) |
| 55 | */ | 53 | return false; |
| 56 | repeat: | 54 | |
| 57 | if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && initrd_data.start && initrd_data.size && | 55 | for_each_rb_entry(cert, certs) { |
| 58 | intersects(initrd_data.start, initrd_data.size, safe_addr, size)) | 56 | if (intersects(addr, size, cert->addr, cert->len)) { |
| 59 | safe_addr = initrd_data.start + initrd_data.size; | 57 | *intersection_start = cert->addr; |
| 60 | if (intersects(safe_addr, size, (unsigned long)comps, comps->len)) { | 58 | return true; |
| 61 | safe_addr = (unsigned long)comps + comps->len; | ||
| 62 | goto repeat; | ||
| 63 | } | ||
| 64 | for_each_rb_entry(comp, comps) | ||
| 65 | if (intersects(safe_addr, size, comp->addr, comp->len)) { | ||
| 66 | safe_addr = comp->addr + comp->len; | ||
| 67 | goto repeat; | ||
| 68 | } | 59 | } |
| 69 | if (intersects(safe_addr, size, (unsigned long)certs, certs->len)) { | ||
| 70 | safe_addr = (unsigned long)certs + certs->len; | ||
| 71 | goto repeat; | ||
| 72 | } | 60 | } |
| 73 | for_each_rb_entry(cert, certs) | 61 | return false; |
| 74 | if (intersects(safe_addr, size, cert->addr, cert->len)) { | ||
| 75 | safe_addr = cert->addr + cert->len; | ||
| 76 | goto repeat; | ||
| 77 | } | ||
| 78 | early_ipl_comp_list_addr = safe_addr; | ||
| 79 | ipl_cert_list_addr = safe_addr + early_ipl_comp_list_size; | ||
| 80 | |||
| 81 | return safe_addr + size; | ||
| 82 | } | 62 | } |
| 83 | 63 | ||
| 84 | static void copy_components_bootdata(struct ipl_rb_components *comps) | 64 | static void copy_components_bootdata(void) |
| 85 | { | 65 | { |
| 86 | struct ipl_rb_component_entry *comp, *ptr; | 66 | struct ipl_rb_component_entry *comp, *ptr; |
| 87 | 67 | ||
| @@ -90,7 +70,7 @@ static void copy_components_bootdata(struct ipl_rb_components *comps) · 2 unmodified lines | |||
| 90 | memcpy(ptr++, comp, sizeof(*ptr)); | 70 | memcpy(ptr++, comp, sizeof(*ptr)); |
| 91 | } | 71 | } |
| 92 | 72 | ||
| 93 | static void copy_certificates_bootdata(struct ipl_rb_certificates *certs) | 73 | static void copy_certificates_bootdata(void) |
| 94 | { | 74 | { |
| 95 | struct ipl_rb_certificate_entry *cert; | 75 | struct ipl_rb_certificate_entry *cert; |
| 96 | void *ptr; | 76 | void *ptr; |
| @@ -104,10 +84,8 @@ static void copy_certificates_bootdata(struct ipl_rb_certificates *certs) · 7 unmodified lines | |||
| 104 | } | 84 | } |
| 105 | } | 85 | } |
| 106 | 86 | ||
| 107 | unsigned long read_ipl_report(unsigned long safe_addr) | 87 | int read_ipl_report(void) |
| 108 | { | 88 | { |
| 109 | struct ipl_rb_certificates *certs; | ||
| 110 | struct ipl_rb_components *comps; | ||
| 111 | struct ipl_pl_hdr *pl_hdr; | 89 | struct ipl_pl_hdr *pl_hdr; |
| 112 | struct ipl_rl_hdr *rl_hdr; | 90 | struct ipl_rl_hdr *rl_hdr; |
| 113 | struct ipl_rb_hdr *rb_hdr; | 91 | struct ipl_rb_hdr *rb_hdr; |
| @@ -120,7 +98,7 @@ unsigned long read_ipl_report(unsigned long safe_addr) · 6 unmodified lines | |||
| 120 | */ | 98 | */ |
| 121 | if (!ipl_block_valid || | 99 | if (!ipl_block_valid || |
| 122 | !(ipl_block.hdr.flags & IPL_PL_FLAG_IPLSR)) | 100 | !(ipl_block.hdr.flags & IPL_PL_FLAG_IPLSR)) |
| 123 | return safe_addr; | 101 | return -1; |
| 124 | ipl_secure_flag = !!(ipl_block.hdr.flags & IPL_PL_FLAG_SIPL); | 102 | ipl_secure_flag = !!(ipl_block.hdr.flags & IPL_PL_FLAG_SIPL); |
| 125 | /* | 103 | /* |
| 126 | * There is an IPL report, to find it load the pointer to the | 104 | * There is an IPL report, to find it load the pointer to the |
| @@ -158,16 +136,30 @@ unsigned long read_ipl_report(unsigned long safe_addr) · 31 unmodified lines | |||
| 158 | * With either the component list or the certificate list | 136 | * With either the component list or the certificate list |
| 159 | * missing the kernel will stay ignorant of secure IPL. | 137 | * missing the kernel will stay ignorant of secure IPL. |
| 160 | */ | 138 | */ |
| 161 | if (!comps || !certs) | 139 | if (!comps || !certs) { |
| 162 | return safe_addr; | 140 | certs = NULL; |
| 141 | return -1; | ||
| 142 | } | ||
| 163 | 143 | ||
| 164 | /* | 144 | ipl_report_needs_saving = true; |
| 165 | * Copy component and certificate list to a safe area | 145 | physmem_reserve(RR_IPLREPORT, (unsigned long)pl_hdr, |
| 166 | * where the decompressed kernel can find them. | 146 | (unsigned long)rl_end - (unsigned long)pl_hdr); |
| 167 | */ | 147 | return 0; |
| 168 | safe_addr = find_bootdata_space(comps, certs, safe_addr); | 148 | } |
| 169 | copy_components_bootdata(comps); | 149 | |
| 170 | copy_certificates_bootdata(certs); | 150 | void save_ipl_cert_comp_list(void) |
| 151 | { | ||
| 152 | unsigned long size; | ||
| 153 | |||
| 154 | if (!ipl_report_needs_saving) | ||
| 155 | return; | ||
| 156 | |||
| 157 | size = get_cert_comp_list_size(); | ||
| 158 | early_ipl_comp_list_addr = physmem_alloc_top_down(RR_CERT_COMP_LIST, size, sizeof(int)); | ||
| 159 | ipl_cert_list_addr = early_ipl_comp_list_addr + early_ipl_comp_list_size; | ||
| 171 | 160 | ||
| 172 | return safe_addr; | 161 | copy_components_bootdata(); |
| 162 | copy_certificates_bootdata(); | ||
| 163 | physmem_free(RR_IPLREPORT); | ||
| 164 | ipl_report_needs_saving = false; | ||
| 173 | } | 165 | } |
| @@ -3,7 +3,7 @@ · 2 unmodified lines | |||
| 3 | * Copyright IBM Corp. 2019 | 3 | * Copyright IBM Corp. 2019 |
| 4 | */ | 4 | */ |
| 5 | #include <linux/pgtable.h> | 5 | #include <linux/pgtable.h> |
| 6 | #include <asm/mem_detect.h> | 6 | #include <asm/physmem_info.h> |
| 7 | #include <asm/cpacf.h> | 7 | #include <asm/cpacf.h> |
| 8 | #include <asm/timex.h> | 8 | #include <asm/timex.h> |
| 9 | #include <asm/sclp.h> | 9 | #include <asm/sclp.h> |
| @@ -91,113 +91,108 @@ static int get_random(unsigned long limit, unsigned long *value) · 81 unmodified lines | |||
| 91 | return 0; | 91 | return 0; |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | /* | 94 | static void sort_reserved_ranges(struct reserved_range *res, unsigned long size) |
| 95 | * To randomize kernel base address we have to consider several facts: | ||
| 96 | * 1. physical online memory might not be continuous and have holes. mem_detect | ||
| 97 | * info contains list of online memory ranges we should consider. | ||
| 98 | * 2. we have several memory regions which are occupied and we should not | ||
| 99 | * overlap and destroy them. Currently safe_addr tells us the border below | ||
| 100 | * which all those occupied regions are. We are safe to use anything above | ||
| 101 | * safe_addr. | ||
| 102 | * 3. the upper limit might apply as well, even if memory above that limit is | ||
| 103 | * online. Currently those limitations are: | ||
| 104 | * 3.1. Limit set by "mem=" kernel command line option | ||
| 105 | * 3.2. memory reserved at the end for kasan initialization. | ||
| 106 | * 4. kernel base address must be aligned to THREAD_SIZE (kernel stack size). | ||
| 107 | * Which is required for CONFIG_CHECK_STACK. Currently THREAD_SIZE is 4 pages | ||
| 108 | * (16 pages when the kernel is built with kasan enabled) | ||
| 109 | * Assumptions: | ||
| 110 | * 1. kernel size (including .bss size) and upper memory limit are page aligned. | ||
| 111 | * 2. mem_detect memory region start is THREAD_SIZE aligned / end is PAGE_SIZE | ||
| 112 | * aligned (in practice memory configurations granularity on z/VM and LPAR | ||
| 113 | * is 1mb). | ||
| 114 | * | ||
| 115 | * To guarantee uniform distribution of kernel base address among all suitable | ||
| 116 | * addresses we generate random value just once. For that we need to build a | ||
| 117 | * continuous range in which every value would be suitable. We can build this | ||
| 118 | * range by simply counting all suitable addresses (let's call them positions) | ||
| 119 | * which would be valid as kernel base address. To count positions we iterate | ||
| 120 | * over online memory ranges. For each range which is big enough for the | ||
| 121 | * kernel image we count all suitable addresses we can put the kernel image at | ||
| 122 | * that is | ||
| 123 | * (end - start - kernel_size) / THREAD_SIZE + 1 | ||
| 124 | * Two functions count_valid_kernel_positions and position_to_address help | ||
| 125 | * to count positions in memory range given and then convert position back | ||
| 126 | * to address. | ||
| 127 | */ | ||
| 128 | static unsigned long count_valid_kernel_positions(unsigned long kernel_size, | ||
| 129 | unsigned long _min, | ||
| 130 | unsigned long _max) | ||
| 131 | { | 95 | { |
| 132 | unsigned long start, end, pos = 0; | 96 | struct reserved_range tmp; |
| 133 | int i; | 97 | int i, j; |
| 134 | 98 | ||
| 135 | for_each_mem_detect_usable_block(i, &start, &end) { | 99 | for (i = 1; i < size; i++) { |
| 136 | if (_min >= end) | 100 | tmp = res[i]; |
| 137 | continue; | 101 | for (j = i - 1; j >= 0 && res[j].start > tmp.start; j--) |
| 138 | if (start >= _max) | 102 | res[j + 1] = res[j]; |
| 139 | break; | 103 | res[j + 1] = tmp; |
| 140 | start = max(_min, start); | ||
| 141 | end = min(_max, end); | ||
| 142 | if (end - start < kernel_size) | ||
| 143 | continue; | ||
| 144 | pos += (end - start - kernel_size) / THREAD_SIZE + 1; | ||
| 145 | } | 104 | } |
| 146 | |||
| 147 | return pos; | ||
| 148 | } | 105 | } |
| 149 | 106 | ||
| 150 | static unsigned long position_to_address(unsigned long pos, unsigned long kernel_size, | 107 | static unsigned long iterate_valid_positions(unsigned long size, unsigned long align, |
| 151 | unsigned long _min, unsigned long _max) | 108 | unsigned long _min, unsigned long _max, |
| 109 | struct reserved_range *res, size_t res_count, | ||
| 110 | bool pos_count, unsigned long find_pos) | ||
| 152 | { | 111 | { |
| 153 | unsigned long start, end; | 112 | unsigned long start, end, tmp_end, range_pos, pos = 0; |
| 113 | struct reserved_range *res_end = res + res_count; | ||
| 114 | struct reserved_range *skip_res; | ||
| 154 | int i; | 115 | int i; |
| 155 | 116 | ||
| 156 | for_each_mem_detect_usable_block(i, &start, &end) { | 117 | align = max(align, 8UL); |
| 118 | _min = round_up(_min, align); | ||
| 119 | for_each_physmem_usable_range(i, &start, &end) { | ||
| 157 | if (_min >= end) | 120 | if (_min >= end) |
| 158 | continue; | 121 | continue; |
| 122 | start = round_up(start, align); | ||
| 159 | if (start >= _max) | 123 | if (start >= _max) |
| 160 | break; | 124 | break; |
| 161 | start = max(_min, start); | 125 | start = max(_min, start); |
| 162 | end = min(_max, end); | 126 | end = min(_max, end); |
| 163 | if (end - start < kernel_size) | 127 | |
| 164 | continue; | 128 | while (start + size <= end) { |
| 165 | if ((end - start - kernel_size) / THREAD_SIZE + 1 >= pos) | 129 | /* skip reserved ranges below the start */ |
| 166 | return start + (pos - 1) * THREAD_SIZE; | 130 | while (res && res->end <= start) { |
| 167 | pos -= (end - start - kernel_size) / THREAD_SIZE + 1; | 131 | res++; |
| 132 | if (res >= res_end) | ||
| 133 | res = NULL; | ||
| 134 | } | ||
| 135 | skip_res = NULL; | ||
| 136 | tmp_end = end; | ||
| 137 | /* has intersecting reserved range */ | ||
| 138 | if (res && res->start < end) { | ||
| 139 | skip_res = res; | ||
| 140 | tmp_end = res->start; | ||
| 141 | } | ||
| 142 | if (start + size <= tmp_end) { | ||
| 143 | range_pos = (tmp_end - start - size) / align + 1; | ||
| 144 | if (pos_count) { | ||
| 145 | pos += range_pos; | ||
| 146 | } else { | ||
| 147 | if (range_pos >= find_pos) | ||
| 148 | return start + (find_pos - 1) * align; | ||
| 149 | find_pos -= range_pos; | ||
| 150 | } | ||
| 151 | } | ||
| 152 | if (!skip_res) | ||
| 153 | break; | ||
| 154 | start = round_up(skip_res->end, align); | ||
| 155 | } | ||
| 168 | } | 156 | } |
| 169 | 157 | ||
| 170 | return 0; | 158 | return pos_count ? pos : 0; |
| 171 | } | 159 | } |
| 172 | 160 | ||
| 173 | unsigned long get_random_base(unsigned long safe_addr) | 161 | /* |
| 162 | * Two types of decompressor memory allocations/reserves are considered | ||
| 163 | * differently. | ||
| 164 | * | ||
| 165 | * "Static" or "single" allocations are done via physmem_alloc_range() and | ||
| 166 | * physmem_reserve(), and they are listed in physmem_info.reserved[]. Each | ||
| 167 | * type of "static" allocation can only have one allocation per type and | ||
| 168 | * cannot have chains. | ||
| 169 | * | ||
| 170 | * On the other hand, "dynamic" or "repetitive" allocations are done via | ||
| 171 | * physmem_alloc_top_down(). These allocations are tightly packed together | ||
| 172 | * top down from the end of online memory. physmem_alloc_pos represents | ||
| 173 | * current position where those allocations start. | ||
| 174 | * | ||
| 175 | * Functions randomize_within_range() and iterate_valid_positions() | ||
| 176 | * only consider "dynamic" allocations by never looking above | ||
| 177 | * physmem_alloc_pos. "Static" allocations, however, are explicitly | ||
| 178 | * considered by checking the "res" (reserves) array. The first | ||
| 179 | * reserved_range of a "dynamic" allocation may also be checked along the | ||
| 180 | * way, but it will always be above the maximum value anyway. | ||
| 181 | */ | ||
| 182 | unsigned long randomize_within_range(unsigned long size, unsigned long align, | ||
| 183 | unsigned long min, unsigned long max) | ||
| 174 | { | 184 | { |
| 175 | unsigned long usable_total = get_mem_detect_usable_total(); | 185 | struct reserved_range res[RR_MAX]; |
| 176 | unsigned long memory_limit = get_mem_detect_end(); | 186 | unsigned long max_pos, pos; |
| 177 | unsigned long base_pos, max_pos, kernel_size; | ||
| 178 | int i; | ||
| 179 | |||
| 180 | /* | ||
| 181 | * Avoid putting kernel in the end of physical memory | ||
| 182 | * which vmem and kasan code will use for shadow memory and | ||
| 183 | * pgtable mapping allocations. | ||
| 184 | */ | ||
| 185 | memory_limit -= kasan_estimate_memory_needs(usable_total); | ||
| 186 | memory_limit -= vmem_estimate_memory_needs(usable_total); | ||
| 187 | 187 | ||
| 188 | safe_addr = ALIGN(safe_addr, THREAD_SIZE); | 188 | memcpy(res, physmem_info.reserved, sizeof(res)); |
| 189 | kernel_size = vmlinux.image_size + vmlinux.bss_size; | 189 | sort_reserved_ranges(res, ARRAY_SIZE(res)); |
| 190 | if (safe_addr + kernel_size > memory_limit) | 190 | max = min(max, get_physmem_alloc_pos()); |
| 191 | return 0; | ||
| 192 | 191 | ||
| 193 | max_pos = count_valid_kernel_positions(kernel_size, safe_addr, memory_limit); | 192 | max_pos = iterate_valid_positions(size, align, min, max, res, ARRAY_SIZE(res), true, 0); |
| 194 | if (!max_pos) { | 193 | if (!max_pos) |
| 195 | sclp_early_printk("KASLR disabled: not enough memory\n"); | ||
| 196 | return 0; | 194 | return 0; |
| 197 | } | 195 | if (get_random(max_pos, &pos)) |
| 198 | |||
| 199 | /* we need a value in the range [1, base_pos] inclusive */ | ||
| 200 | if (get_random(max_pos, &base_pos)) | ||
| 201 | return 0; | 196 | return 0; |
| 202 | return position_to_address(base_pos + 1, kernel_size, safe_addr, memory_limit); | 197 | return iterate_valid_positions(size, align, min, max, res, ARRAY_SIZE(res), false, pos + 1); |
| 203 | } | 198 | } |
| @@ -1,191 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | #include <linux/errno.h> | ||
| 3 | #include <linux/init.h> | ||
| 4 | #include <asm/setup.h> | ||
| 5 | #include <asm/processor.h> | ||
| 6 | #include <asm/sclp.h> | ||
| 7 | #include <asm/sections.h> | ||
| 8 | #include <asm/mem_detect.h> | ||
| 9 | #include <asm/sparsemem.h> | ||
| 10 | #include "decompressor.h" | ||
| 11 | #include "boot.h" | ||
| 12 | |||
| 13 | struct mem_detect_info __bootdata(mem_detect); | ||
| 14 | |||
| 15 | /* up to 256 storage elements, 1020 subincrements each */ | ||
| 16 | #define ENTRIES_EXTENDED_MAX \ | ||
| 17 | (256 * (1020 / 2) * sizeof(struct mem_detect_block)) | ||
| 18 | |||
| 19 | static struct mem_detect_block *__get_mem_detect_block_ptr(u32 n) | ||
| 20 | { | ||
| 21 | if (n < MEM_INLINED_ENTRIES) | ||
| 22 | return &mem_detect.entries[n]; | ||
| 23 | return &mem_detect.entries_extended[n - MEM_INLINED_ENTRIES]; | ||
| 24 | } | ||
| 25 | |||
| 26 | /* | ||
| 27 | * sequential calls to add_mem_detect_block with adjacent memory areas | ||
| 28 | * are merged together into single memory block. | ||
| 29 | */ | ||
| 30 | void add_mem_detect_block(u64 start, u64 end) | ||
| 31 | { | ||
| 32 | struct mem_detect_block *block; | ||
| 33 | |||
| 34 | if (mem_detect.count) { | ||
| 35 | block = __get_mem_detect_block_ptr(mem_detect.count - 1); | ||
| 36 | if (block->end == start) { | ||
| 37 | block->end = end; | ||
| 38 | return; | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | block = __get_mem_detect_block_ptr(mem_detect.count); | ||
| 43 | block->start = start; | ||
| 44 | block->end = end; | ||
| 45 | mem_detect.count++; | ||
| 46 | } | ||
| 47 | |||
| 48 | static int __diag260(unsigned long rx1, unsigned long rx2) | ||
| 49 | { | ||
| 50 | unsigned long reg1, reg2, ry; | ||
| 51 | union register_pair rx; | ||
| 52 | psw_t old; | ||
| 53 | int rc; | ||
| 54 | |||
| 55 | rx.even = rx1; | ||
| 56 | rx.odd = rx2; | ||
| 57 | ry = 0x10; /* storage configuration */ | ||
| 58 | rc = -1; /* fail */ | ||
| 59 | asm volatile( | ||
| 60 | " mvc 0(16,%[psw_old]),0(%[psw_pgm])\n" | ||
| 61 | " epsw %[reg1],%[reg2]\n" | ||
| 62 | " st %[reg1],0(%[psw_pgm])\n" | ||
| 63 | " st %[reg2],4(%[psw_pgm])\n" | ||
| 64 | " larl %[reg1],1f\n" | ||
| 65 | " stg %[reg1],8(%[psw_pgm])\n" | ||
| 66 | " diag %[rx],%[ry],0x260\n" | ||
| 67 | " ipm %[rc]\n" | ||
| 68 | " srl %[rc],28\n" | ||
| 69 | "1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n" | ||
| 70 | : [reg1] "=&d" (reg1), | ||
| 71 | [reg2] "=&a" (reg2), | ||
| 72 | [rc] "+&d" (rc), | ||
| 73 | [ry] "+&d" (ry), | ||
| 74 | "+Q" (S390_lowcore.program_new_psw), | ||
| 75 | "=Q" (old) | ||
| 76 | : [rx] "d" (rx.pair), | ||
| 77 | [psw_old] "a" (&old), | ||
| 78 | [psw_pgm] "a" (&S390_lowcore.program_new_psw) | ||
| 79 | : "cc", "memory"); | ||
| 80 | return rc == 0 ? ry : -1; | ||
| 81 | } | ||
| 82 | |||
| 83 | static int diag260(void) | ||
| 84 | { | ||
| 85 | int rc, i; | ||
| 86 | |||
| 87 | struct { | ||
| 88 | unsigned long start; | ||
| 89 | unsigned long end; | ||
| 90 | } storage_extents[8] __aligned(16); /* VM supports up to 8 extends */ | ||
| 91 | |||
| 92 | memset(storage_extents, 0, sizeof(storage_extents)); | ||
| 93 | rc = __diag260((unsigned long)storage_extents, sizeof(storage_extents)); | ||
| 94 | if (rc == -1) | ||
| 95 | return -1; | ||
| 96 | |||
| 97 | for (i = 0; i < min_t(int, rc, ARRAY_SIZE(storage_extents)); i++) | ||
| 98 | add_mem_detect_block(storage_extents[i].start, storage_extents[i].end + 1); | ||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | static int tprot(unsigned long addr) | ||
| 103 | { | ||
| 104 | unsigned long reg1, reg2; | ||
| 105 | int rc = -EFAULT; | ||
| 106 | psw_t old; | ||
| 107 | |||
| 108 | asm volatile( | ||
| 109 | " mvc 0(16,%[psw_old]),0(%[psw_pgm])\n" | ||
| 110 | " epsw %[reg1],%[reg2]\n" | ||
| 111 | " st %[reg1],0(%[psw_pgm])\n" | ||
| 112 | " st %[reg2],4(%[psw_pgm])\n" | ||
| 113 | " larl %[reg1],1f\n" | ||
| 114 | " stg %[reg1],8(%[psw_pgm])\n" | ||
| 115 | " tprot 0(%[addr]),0\n" | ||
| 116 | " ipm %[rc]\n" | ||
| 117 | " srl %[rc],28\n" | ||
| 118 | "1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n" | ||
| 119 | : [reg1] "=&d" (reg1), | ||
| 120 | [reg2] "=&a" (reg2), | ||
| 121 | [rc] "+&d" (rc), | ||
| 122 | "=Q" (S390_lowcore.program_new_psw.addr), | ||
| 123 | "=Q" (old) | ||
| 124 | : [psw_old] "a" (&old), | ||
| 125 | [psw_pgm] "a" (&S390_lowcore.program_new_psw), | ||
| 126 | [addr] "a" (addr) | ||
| 127 | : "cc", "memory"); | ||
| 128 | return rc; | ||
| 129 | } | ||
| 130 | |||
| 131 | static unsigned long search_mem_end(void) | ||
| 132 | { | ||
| 133 | unsigned long range = 1 << (MAX_PHYSMEM_BITS - 20); /* in 1MB blocks */ | ||
| 134 | unsigned long offset = 0; | ||
| 135 | unsigned long pivot; | ||
| 136 | |||
| 137 | while (range > 1) { | ||
| 138 | range >>= 1; | ||
| 139 | pivot = offset + range; | ||
| 140 | if (!tprot(pivot << 20)) | ||
| 141 | offset = pivot; | ||
| 142 | } | ||
| 143 | return (offset + 1) << 20; | ||
| 144 | } | ||
| 145 | |||
| 146 | unsigned long detect_memory(unsigned long *safe_addr) | ||
| 147 | { | ||
| 148 | unsigned long max_physmem_end = 0; | ||
| 149 | |||
| 150 | sclp_early_get_memsize(&max_physmem_end); | ||
| 151 | mem_detect.entries_extended = (struct mem_detect_block *)ALIGN(*safe_addr, sizeof(u64)); | ||
| 152 | |||
| 153 | if (!sclp_early_read_storage_info()) { | ||
| 154 | mem_detect.info_source = MEM_DETECT_SCLP_STOR_INFO; | ||
| 155 | } else if (!diag260()) { | ||
| 156 | mem_detect.info_source = MEM_DETECT_DIAG260; | ||
| 157 | max_physmem_end = max_physmem_end ?: get_mem_detect_end(); | ||
| 158 | } else if (max_physmem_end) { | ||
| 159 | add_mem_detect_block(0, max_physmem_end); | ||
| 160 | mem_detect.info_source = MEM_DETECT_SCLP_READ_INFO; | ||
| 161 | } else { | ||
| 162 | max_physmem_end = search_mem_end(); | ||
| 163 | add_mem_detect_block(0, max_physmem_end); | ||
| 164 | mem_detect.info_source = MEM_DETECT_BIN_SEARCH; | ||
| 165 | } | ||
| 166 | |||
| 167 | if (mem_detect.count > MEM_INLINED_ENTRIES) { | ||
| 168 | *safe_addr += (mem_detect.count - MEM_INLINED_ENTRIES) * | ||
| 169 | sizeof(struct mem_detect_block); | ||
| 170 | } | ||
| 171 | |||
| 172 | return max_physmem_end; | ||
| 173 | } | ||
| 174 | |||
| 175 | void mem_detect_set_usable_limit(unsigned long limit) | ||
| 176 | { | ||
| 177 | struct mem_detect_block *block; | ||
| 178 | int i; | ||
| 179 | |||
| 180 | /* make sure mem_detect.usable ends up within online memory block */ | ||
| 181 | for (i = 0; i < mem_detect.count; i++) { | ||
| 182 | block = __get_mem_detect_block_ptr(i); | ||
| 183 | if (block->start >= limit) | ||
| 184 | break; | ||
| 185 | if (block->end >= limit) { | ||
| 186 | mem_detect.usable = limit; | ||
| 187 | break; | ||
| 188 | } | ||
| 189 | mem_detect.usable = block->end; | ||
| 190 | } | ||
| 191 | } | ||
| @@ -123,11 +123,10 @@ out: · 122 unmodified lines | |||
| 123 | sclp_early_printk(buf); | 123 | sclp_early_printk(buf); |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | static noinline void print_stacktrace(void) | 126 | void print_stacktrace(unsigned long sp) |
| 127 | { | 127 | { |
| 128 | struct stack_info boot_stack = { STACK_TYPE_TASK, (unsigned long)_stack_start, | 128 | struct stack_info boot_stack = { STACK_TYPE_TASK, (unsigned long)_stack_start, |
| 129 | (unsigned long)_stack_end }; | 129 | (unsigned long)_stack_end }; |
| 130 | unsigned long sp = S390_lowcore.gpregs_save_area[15]; | ||
| 131 | bool first = true; | 130 | bool first = true; |
| 132 | 131 | ||
| 133 | decompressor_printk("Call Trace:\n"); | 132 | decompressor_printk("Call Trace:\n"); |
| @@ -154,7 +153,7 @@ void print_pgm_check_info(void) · 20 unmodified lines | |||
| 154 | decompressor_printk("Kernel command line: %s\n", early_command_line); | 153 | decompressor_printk("Kernel command line: %s\n", early_command_line); |
| 155 | decompressor_printk("Kernel fault: interruption code %04x ilc:%x\n", | 154 | decompressor_printk("Kernel fault: interruption code %04x ilc:%x\n", |
| 156 | S390_lowcore.pgm_code, S390_lowcore.pgm_ilc >> 1); | 155 | S390_lowcore.pgm_code, S390_lowcore.pgm_ilc >> 1); |
| 157 | if (kaslr_enabled) | 156 | if (kaslr_enabled()) |
| 158 | decompressor_printk("Kernel random base: %lx\n", __kaslr_offset); | 157 | decompressor_printk("Kernel random base: %lx\n", __kaslr_offset); |
| 159 | decompressor_printk("PSW : %016lx %016lx (%pS)\n", | 158 | decompressor_printk("PSW : %016lx %016lx (%pS)\n", |
| 160 | S390_lowcore.psw_save_area.mask, | 159 | S390_lowcore.psw_save_area.mask, |
| @@ -173,7 +172,7 @@ void print_pgm_check_info(void) · 12 unmodified lines | |||
| 173 | gpregs[8], gpregs[9], gpregs[10], gpregs[11]); | 172 | gpregs[8], gpregs[9], gpregs[10], gpregs[11]); |
| 174 | decompressor_printk(" %016lx %016lx %016lx %016lx\n", | 173 | decompressor_printk(" %016lx %016lx %016lx %016lx\n", |
| 175 | gpregs[12], gpregs[13], gpregs[14], gpregs[15]); | 174 | gpregs[12], gpregs[13], gpregs[14], gpregs[15]); |
| 176 | print_stacktrace(); | 175 | print_stacktrace(S390_lowcore.gpregs_save_area[15]); |
| 177 | decompressor_printk("Last Breaking-Event-Address:\n"); | 176 | decompressor_printk("Last Breaking-Event-Address:\n"); |
| 178 | decompressor_printk(" [<%016lx>] %pS\n", (unsigned long)S390_lowcore.pgm_last_break, | 177 | decompressor_printk(" [<%016lx>] %pS\n", (unsigned long)S390_lowcore.pgm_last_break, |
| 179 | (void *)S390_lowcore.pgm_last_break); | 178 | (void *)S390_lowcore.pgm_last_break); |
| @@ -0,0 +1,328 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | #include <linux/processor.h> | ||
| 3 | #include <linux/errno.h> | ||
| 4 | #include <linux/init.h> | ||
| 5 | #include <asm/physmem_info.h> | ||
| 6 | #include <asm/stacktrace.h> | ||
| 7 | #include <asm/boot_data.h> | ||
| 8 | #include <asm/sparsemem.h> | ||
| 9 | #include <asm/sections.h> | ||
| 10 | #include <asm/setup.h> | ||
| 11 | #include <asm/sclp.h> | ||
| 12 | #include <asm/uv.h> | ||
| 13 | #include "decompressor.h" | ||
| 14 | #include "boot.h" | ||
| 15 | |||
| 16 | struct physmem_info __bootdata(physmem_info); | ||
| 17 | static unsigned int physmem_alloc_ranges; | ||
| 18 | static unsigned long physmem_alloc_pos; | ||
| 19 | |||
| 20 | /* up to 256 storage elements, 1020 subincrements each */ | ||
| 21 | #define ENTRIES_EXTENDED_MAX \ | ||
| 22 | (256 * (1020 / 2) * sizeof(struct physmem_range)) | ||
| 23 | |||
| 24 | static struct physmem_range *__get_physmem_range_ptr(u32 n) | ||
| 25 | { | ||
| 26 | if (n < MEM_INLINED_ENTRIES) | ||
| 27 | return &physmem_info.online[n]; | ||
| 28 | if (unlikely(!physmem_info.online_extended)) { | ||
| 29 | physmem_info.online_extended = (struct physmem_range *)physmem_alloc_range( | ||
| 30 | RR_MEM_DETECT_EXTENDED, ENTRIES_EXTENDED_MAX, sizeof(long), 0, | ||
| 31 | physmem_alloc_pos, true); | ||
| 32 | } | ||
| 33 | return &physmem_info.online_extended[n - MEM_INLINED_ENTRIES]; | ||
| 34 | } | ||
| 35 | |||
| 36 | /* | ||
| 37 | * sequential calls to add_physmem_online_range with adjacent memory ranges | ||
| 38 | * are merged together into single memory range. | ||
| 39 | */ | ||
| 40 | void add_physmem_online_range(u64 start, u64 end) | ||
| 41 | { | ||
| 42 | struct physmem_range *range; | ||
| 43 | |||
| 44 | if (physmem_info.range_count) { | ||
| 45 | range = __get_physmem_range_ptr(physmem_info.range_count - 1); | ||
| 46 | if (range->end == start) { | ||
| 47 | range->end = end; | ||
| 48 | return; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | range = __get_physmem_range_ptr(physmem_info.range_count); | ||
| 53 | range->start = start; | ||
| 54 | range->end = end; | ||
| 55 | physmem_info.range_count++; | ||
| 56 | } | ||
| 57 | |||
| 58 | static int __diag260(unsigned long rx1, unsigned long rx2) | ||
| 59 | { | ||
| 60 | unsigned long reg1, reg2, ry; | ||
| 61 | union register_pair rx; | ||
| 62 | psw_t old; | ||
| 63 | int rc; | ||
| 64 | |||
| 65 | rx.even = rx1; | ||
| 66 | rx.odd = rx2; | ||
| 67 | ry = 0x10; /* storage configuration */ | ||
| 68 | rc = -1; /* fail */ | ||
| 69 | asm volatile( | ||
| 70 | " mvc 0(16,%[psw_old]),0(%[psw_pgm])\n" | ||
| 71 | " epsw %[reg1],%[reg2]\n" | ||
| 72 | " st %[reg1],0(%[psw_pgm])\n" | ||
| 73 | " st %[reg2],4(%[psw_pgm])\n" | ||
| 74 | " larl %[reg1],1f\n" | ||
| 75 | " stg %[reg1],8(%[psw_pgm])\n" | ||
| 76 | " diag %[rx],%[ry],0x260\n" | ||
| 77 | " ipm %[rc]\n" | ||
| 78 | " srl %[rc],28\n" | ||
| 79 | "1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n" | ||
| 80 | : [reg1] "=&d" (reg1), | ||
| 81 | [reg2] "=&a" (reg2), | ||
| 82 | [rc] "+&d" (rc), | ||
| 83 | [ry] "+&d" (ry), | ||
| 84 | "+Q" (S390_lowcore.program_new_psw), | ||
| 85 | "=Q" (old) | ||
| 86 | : [rx] "d" (rx.pair), | ||
| 87 | [psw_old] "a" (&old), | ||
| 88 | [psw_pgm] "a" (&S390_lowcore.program_new_psw) | ||
| 89 | : "cc", "memory"); | ||
| 90 | return rc == 0 ? ry : -1; | ||
| 91 | } | ||
| 92 | |||
| 93 | static int diag260(void) | ||
| 94 | { | ||
| 95 | int rc, i; | ||
| 96 | |||
| 97 | struct { | ||
| 98 | unsigned long start; | ||
| 99 | unsigned long end; | ||
| 100 | } storage_extents[8] __aligned(16); /* VM supports up to 8 extends */ | ||
| 101 | |||
| 102 | memset(storage_extents, 0, sizeof(storage_extents)); | ||
| 103 | rc = __diag260((unsigned long)storage_extents, sizeof(storage_extents)); | ||
| 104 | if (rc == -1) | ||
| 105 | return -1; | ||
| 106 | |||
| 107 | for (i = 0; i < min_t(int, rc, ARRAY_SIZE(storage_extents)); i++) | ||
| 108 | add_physmem_online_range(storage_extents[i].start, storage_extents[i].end + 1); | ||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | static int tprot(unsigned long addr) | ||
| 113 | { | ||
| 114 | unsigned long reg1, reg2; | ||
| 115 | int rc = -EFAULT; | ||
| 116 | psw_t old; | ||
| 117 | |||
| 118 | asm volatile( | ||
| 119 | " mvc 0(16,%[psw_old]),0(%[psw_pgm])\n" | ||
| 120 | " epsw %[reg1],%[reg2]\n" | ||
| 121 | " st %[reg1],0(%[psw_pgm])\n" | ||
| 122 | " st %[reg2],4(%[psw_pgm])\n" | ||
| 123 | " larl %[reg1],1f\n" | ||
| 124 | " stg %[reg1],8(%[psw_pgm])\n" | ||
| 125 | " tprot 0(%[addr]),0\n" | ||
| 126 | " ipm %[rc]\n" | ||
| 127 | " srl %[rc],28\n" | ||
| 128 | "1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n" | ||
| 129 | : [reg1] "=&d" (reg1), | ||
| 130 | [reg2] "=&a" (reg2), | ||
| 131 | [rc] "+&d" (rc), | ||
| 132 | "=Q" (S390_lowcore.program_new_psw.addr), | ||
| 133 | "=Q" (old) | ||
| 134 | : [psw_old] "a" (&old), | ||
| 135 | [psw_pgm] "a" (&S390_lowcore.program_new_psw), | ||
| 136 | [addr] "a" (addr) | ||
| 137 | : "cc", "memory"); | ||
| 138 | return rc; | ||
| 139 | } | ||
| 140 | |||
| 141 | static unsigned long search_mem_end(void) | ||
| 142 | { | ||
| 143 | unsigned long range = 1 << (MAX_PHYSMEM_BITS - 20); /* in 1MB blocks */ | ||
| 144 | unsigned long offset = 0; | ||
| 145 | unsigned long pivot; | ||
| 146 | |||
| 147 | while (range > 1) { | ||
| 148 | range >>= 1; | ||
| 149 | pivot = offset + range; | ||
| 150 | if (!tprot(pivot << 20)) | ||
| 151 | offset = pivot; | ||
| 152 | } | ||
| 153 | return (offset + 1) << 20; | ||
| 154 | } | ||
| 155 | |||
| 156 | unsigned long detect_max_physmem_end(void) | ||
| 157 | { | ||
| 158 | unsigned long max_physmem_end = 0; | ||
| 159 | |||
| 160 | if (!sclp_early_get_memsize(&max_physmem_end)) { | ||
| 161 | physmem_info.info_source = MEM_DETECT_SCLP_READ_INFO; | ||
| 162 | } else { | ||
| 163 | max_physmem_end = search_mem_end(); | ||
| 164 | physmem_info.info_source = MEM_DETECT_BIN_SEARCH; | ||
| 165 | } | ||
| 166 | return max_physmem_end; | ||
| 167 | } | ||
| 168 | |||
| 169 | void detect_physmem_online_ranges(unsigned long max_physmem_end) | ||
| 170 | { | ||
| 171 | if (!sclp_early_read_storage_info()) { | ||
| 172 | physmem_info.info_source = MEM_DETECT_SCLP_STOR_INFO; | ||
| 173 | } else if (!diag260()) { | ||
| 174 | physmem_info.info_source = MEM_DETECT_DIAG260; | ||
| 175 | } else if (max_physmem_end) { | ||
| 176 | add_physmem_online_range(0, max_physmem_end); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | void physmem_set_usable_limit(unsigned long limit) | ||
| 181 | { | ||
| 182 | physmem_info.usable = limit; | ||
| 183 | physmem_alloc_pos = limit; | ||
| 184 | } | ||
| 185 | |||
| 186 | static void die_oom(unsigned long size, unsigned long align, unsigned long min, unsigned long max) | ||
| 187 | { | ||
| 188 | unsigned long start, end, total_mem = 0, total_reserved_mem = 0; | ||
| 189 | struct reserved_range *range; | ||
| 190 | enum reserved_range_type t; | ||
| 191 | int i; | ||
| 192 | |||
| 193 | decompressor_printk("Linux version %s\n", kernel_version); | ||
| 194 | if (!is_prot_virt_guest() && early_command_line[0]) | ||
| 195 | decompressor_printk("Kernel command line: %s\n", early_command_line); | ||
| 196 | decompressor_printk("Out of memory allocating %lx bytes %lx aligned in range %lx:%lx\n", | ||
| 197 | size, align, min, max); | ||
| 198 | decompressor_printk("Reserved memory ranges:\n"); | ||
| 199 | for_each_physmem_reserved_range(t, range, &start, &end) { | ||
| 200 | decompressor_printk("%016lx %016lx %s\n", start, end, get_rr_type_name(t)); | ||
| 201 | total_reserved_mem += end - start; | ||
| 202 | } | ||
| 203 | decompressor_printk("Usable online memory ranges (info source: %s [%x]):\n", | ||
| 204 | get_physmem_info_source(), physmem_info.info_source); | ||
| 205 | for_each_physmem_usable_range(i, &start, &end) { | ||
| 206 | decompressor_printk("%016lx %016lx\n", start, end); | ||
| 207 | total_mem += end - start; | ||
| 208 | } | ||
| 209 | decompressor_printk("Usable online memory total: %lx Reserved: %lx Free: %lx\n", | ||
| 210 | total_mem, total_reserved_mem, | ||
| 211 | total_mem > total_reserved_mem ? total_mem - total_reserved_mem : 0); | ||
| 212 | print_stacktrace(current_frame_address()); | ||
| 213 | sclp_early_printk("\n\n -- System halted\n"); | ||
| 214 | disabled_wait(); | ||
| 215 | } | ||
| 216 | |||
| 217 | void physmem_reserve(enum reserved_range_type type, unsigned long addr, unsigned long size) | ||
| 218 | { | ||
| 219 | physmem_info.reserved[type].start = addr; | ||
| 220 | physmem_info.reserved[type].end = addr + size; | ||
| 221 | } | ||
| 222 | |||
| 223 | void physmem_free(enum reserved_range_type type) | ||
| 224 | { | ||
| 225 | physmem_info.reserved[type].start = 0; | ||
| 226 | physmem_info.reserved[type].end = 0; | ||
| 227 | } | ||
| 228 | |||
| 229 | static bool __physmem_alloc_intersects(unsigned long addr, unsigned long size, | ||
| 230 | unsigned long *intersection_start) | ||
| 231 | { | ||
| 232 | unsigned long res_addr, res_size; | ||
| 233 | int t; | ||
| 234 | |||
| 235 | for (t = 0; t < RR_MAX; t++) { | ||
| 236 | if (!get_physmem_reserved(t, &res_addr, &res_size)) | ||
| 237 | continue; | ||
| 238 | if (intersects(addr, size, res_addr, res_size)) { | ||
| 239 | *intersection_start = res_addr; | ||
| 240 | return true; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | return ipl_report_certs_intersects(addr, size, intersection_start); | ||
| 244 | } | ||
| 245 | |||
| 246 | static unsigned long __physmem_alloc_range(unsigned long size, unsigned long align, | ||
| 247 | unsigned long min, unsigned long max, | ||
| 248 | unsigned int from_ranges, unsigned int *ranges_left, | ||
| 249 | bool die_on_oom) | ||
| 250 | { | ||
| 251 | unsigned int nranges = from_ranges ?: physmem_info.range_count; | ||
| 252 | unsigned long range_start, range_end; | ||
| 253 | unsigned long intersection_start; | ||
| 254 | unsigned long addr, pos = max; | ||
| 255 | |||
| 256 | align = max(align, 8UL); | ||
| 257 | while (nranges) { | ||
| 258 | __get_physmem_range(nranges - 1, &range_start, &range_end, false); | ||
| 259 | pos = min(range_end, pos); | ||
| 260 | |||
| 261 | if (round_up(min, align) + size > pos) | ||
| 262 | break; | ||
| 263 | addr = round_down(pos - size, align); | ||
| 264 | if (range_start > addr) { | ||
| 265 | nranges--; | ||
| 266 | continue; | ||
| 267 | } | ||
| 268 | if (__physmem_alloc_intersects(addr, size, &intersection_start)) { | ||
| 269 | pos = intersection_start; | ||
| 270 | continue; | ||
| 271 | } | ||
| 272 | |||
| 273 | if (ranges_left) | ||
| 274 | *ranges_left = nranges; | ||
| 275 | return addr; | ||
| 276 | } | ||
| 277 | if (die_on_oom) | ||
| 278 | die_oom(size, align, min, max); | ||
| 279 | return 0; | ||
| 280 | } | ||
| 281 | |||
| 282 | unsigned long physmem_alloc_range(enum reserved_range_type type, unsigned long size, | ||
| 283 | unsigned long align, unsigned long min, unsigned long max, | ||
| 284 | bool die_on_oom) | ||
| 285 | { | ||
| 286 | unsigned long addr; | ||
| 287 | |||
| 288 | max = min(max, physmem_alloc_pos); | ||
| 289 | addr = __physmem_alloc_range(size, align, min, max, 0, NULL, die_on_oom); | ||
| 290 | if (addr) | ||
| 291 | physmem_reserve(type, addr, size); | ||
| 292 | return addr; | ||
| 293 | } | ||
| 294 | |||
| 295 | unsigned long physmem_alloc_top_down(enum reserved_range_type type, unsigned long size, | ||
| 296 | unsigned long align) | ||
| 297 | { | ||
| 298 | struct reserved_range *range = &physmem_info.reserved[type]; | ||
| 299 | struct reserved_range *new_range; | ||
| 300 | unsigned int ranges_left; | ||
| 301 | unsigned long addr; | ||
| 302 | |||
| 303 | addr = __physmem_alloc_range(size, align, 0, physmem_alloc_pos, physmem_alloc_ranges, | ||
| 304 | &ranges_left, true); | ||
| 305 | /* if not a consecutive allocation of the same type or first allocation */ | ||
| 306 | if (range->start != addr + size) { | ||
| 307 | if (range->end) { | ||
| 308 | physmem_alloc_pos = __physmem_alloc_range( | ||
| 309 | sizeof(struct reserved_range), 0, 0, physmem_alloc_pos, | ||
| 310 | physmem_alloc_ranges, &ranges_left, true); | ||
| 311 | new_range = (struct reserved_range *)physmem_alloc_pos; | ||
| 312 | *new_range = *range; | ||
| 313 | range->chain = new_range; | ||
| 314 | addr = __physmem_alloc_range(size, align, 0, physmem_alloc_pos, | ||
| 315 | ranges_left, &ranges_left, true); | ||
| 316 | } | ||
| 317 | range->end = addr + size; | ||
| 318 | } | ||
| 319 | range->start = addr; | ||
| 320 | physmem_alloc_pos = addr; | ||
| 321 | physmem_alloc_ranges = ranges_left; | ||
| 322 | return addr; | ||
| 323 | } | ||
| 324 | |||
| 325 | unsigned long get_physmem_alloc_pos(void) | ||
| 326 | { | ||
| 327 | return physmem_alloc_pos; | ||
| 328 | } | ||
| @@ -12,7 +12,7 @@ · 11 unmodified lines | |||
| 12 | #include <asm/diag.h> | 12 | #include <asm/diag.h> |
| 13 | #include <asm/uv.h> | 13 | #include <asm/uv.h> |
| 14 | #include <asm/abs_lowcore.h> | 14 | #include <asm/abs_lowcore.h> |
| 15 | #include <asm/mem_detect.h> | 15 | #include <asm/physmem_info.h> |
| 16 | #include "decompressor.h" | 16 | #include "decompressor.h" |
| 17 | #include "boot.h" | 17 | #include "boot.h" |
| 18 | #include "uv.h" | 18 | #include "uv.h" |
| @@ -21,7 +21,6 @@ unsigned long __bootdata_preserved(__kaslr_offset); · 2 unmodified lines | |||
| 21 | unsigned long __bootdata_preserved(__abs_lowcore); | 21 | unsigned long __bootdata_preserved(__abs_lowcore); |
| 22 | unsigned long __bootdata_preserved(__memcpy_real_area); | 22 | unsigned long __bootdata_preserved(__memcpy_real_area); |
| 23 | pte_t *__bootdata_preserved(memcpy_real_ptep); | 23 | pte_t *__bootdata_preserved(memcpy_real_ptep); |
| 24 | unsigned long __bootdata(__amode31_base); | ||
| 25 | unsigned long __bootdata_preserved(VMALLOC_START); | 24 | unsigned long __bootdata_preserved(VMALLOC_START); |
| 26 | unsigned long __bootdata_preserved(VMALLOC_END); | 25 | unsigned long __bootdata_preserved(VMALLOC_END); |
| 27 | struct page *__bootdata_preserved(vmemmap); | 26 | struct page *__bootdata_preserved(vmemmap); |
| @@ -29,8 +28,6 @@ unsigned long __bootdata_preserved(vmemmap_size); · 1 unmodified line | |||
| 29 | unsigned long __bootdata_preserved(MODULES_VADDR); | 28 | unsigned long __bootdata_preserved(MODULES_VADDR); |
| 30 | unsigned long __bootdata_preserved(MODULES_END); | 29 | unsigned long __bootdata_preserved(MODULES_END); |
| 31 | unsigned long __bootdata(ident_map_size); | 30 | unsigned long __bootdata(ident_map_size); |
| 32 | int __bootdata(is_full_image) = 1; | ||
| 33 | struct initrd_data __bootdata(initrd_data); | ||
| 34 | 31 | ||
| 35 | u64 __bootdata_preserved(stfle_fac_list[16]); | 32 | u64 __bootdata_preserved(stfle_fac_list[16]); |
| 36 | u64 __bootdata_preserved(alt_stfle_fac_list[16]); | 33 | u64 __bootdata_preserved(alt_stfle_fac_list[16]); |
| @@ -76,17 +73,20 @@ unsigned long mem_safe_offset(void) · 39 unmodified lines | |||
| 76 | } | 73 | } |
| 77 | #endif | 74 | #endif |
| 78 | 75 | ||
| 79 | static unsigned long rescue_initrd(unsigned long safe_addr) | 76 | static void rescue_initrd(unsigned long min, unsigned long max) |
| 80 | { | 77 | { |
| 78 | unsigned long old_addr, addr, size; | ||
| 79 | |||
| 81 | if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD)) | 80 | if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD)) |
| 82 | return safe_addr; | 81 | return; |
| 83 | if (!initrd_data.start || !initrd_data.size) | 82 | if (!get_physmem_reserved(RR_INITRD, &addr, &size)) |
| 84 | return safe_addr; | 83 | return; |
| 85 | if (initrd_data.start < safe_addr) { | 84 | if (addr >= min && addr + size <= max) |
| 86 | memmove((void *)safe_addr, (void *)initrd_data.start, initrd_data.size); | 85 | return; |
| 87 | initrd_data.start = safe_addr; | 86 | old_addr = addr; |
| 88 | } | 87 | physmem_free(RR_INITRD); |
| 89 | return initrd_data.start + initrd_data.size; | 88 | addr = physmem_alloc_top_down(RR_INITRD, size, 0); |
| 89 | memmove((void *)addr, (void *)old_addr, size); | ||
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | static void copy_bootdata(void) | 92 | static void copy_bootdata(void) |
| @@ -140,7 +140,7 @@ static void handle_relocs(unsigned long offset) · 47 unmodified lines | |||
| 140 | * | 140 | * |
| 141 | * Consider the following factors: | 141 | * Consider the following factors: |
| 142 | * 1. max_physmem_end - end of physical memory online or standby. | 142 | * 1. max_physmem_end - end of physical memory online or standby. |
| 143 | * Always <= end of the last online memory block (get_mem_detect_end()). | 143 | * Always >= end of the last online memory range (get_physmem_online_end()). |
| 144 | * 2. CONFIG_MAX_PHYSMEM_BITS - the maximum size of physical memory the | 144 | * 2. CONFIG_MAX_PHYSMEM_BITS - the maximum size of physical memory the |
| 145 | * kernel is able to support. | 145 | * kernel is able to support. |
| 146 | * 3. "mem=" kernel command line option which limits physical memory usage. | 146 | * 3. "mem=" kernel command line option which limits physical memory usage. |
| @@ -160,10 +160,10 @@ static void setup_ident_map_size(unsigned long max_physmem_end) · 13 unmodified lines | |||
| 160 | 160 | ||
| 161 | #ifdef CONFIG_CRASH_DUMP | 161 | #ifdef CONFIG_CRASH_DUMP |
| 162 | if (oldmem_data.start) { | 162 | if (oldmem_data.start) { |
| 163 | kaslr_enabled = 0; | 163 | __kaslr_enabled = 0; |
| 164 | ident_map_size = min(ident_map_size, oldmem_data.size); | 164 | ident_map_size = min(ident_map_size, oldmem_data.size); |
| 165 | } else if (ipl_block_valid && is_ipl_block_dump()) { | 165 | } else if (ipl_block_valid && is_ipl_block_dump()) { |
| 166 | kaslr_enabled = 0; | 166 | __kaslr_enabled = 0; |
| 167 | if (!sclp_early_get_hsa_size(&hsa_size) && hsa_size) | 167 | if (!sclp_early_get_hsa_size(&hsa_size) && hsa_size) |
| 168 | ident_map_size = min(ident_map_size, hsa_size); | 168 | ident_map_size = min(ident_map_size, hsa_size); |
| 169 | } | 169 | } |
| @@ -235,9 +235,9 @@ static unsigned long setup_kernel_memory_layout(void) · 65 unmodified lines | |||
| 235 | /* | 235 | /* |
| 236 | * This function clears the BSS section of the decompressed Linux kernel and NOT the decompressor's. | 236 | * This function clears the BSS section of the decompressed Linux kernel and NOT the decompressor's. |
| 237 | */ | 237 | */ |
| 238 | static void clear_bss_section(void) | 238 | static void clear_bss_section(unsigned long vmlinux_lma) |
| 239 | { | 239 | { |
| 240 | memset((void *)vmlinux.default_lma + vmlinux.image_size, 0, vmlinux.bss_size); | 240 | memset((void *)vmlinux_lma + vmlinux.image_size, 0, vmlinux.bss_size); |
| 241 | } | 241 | } |
| 242 | 242 | ||
| 243 | /* | 243 | /* |
| @@ -256,7 +256,6 @@ static void setup_vmalloc_size(void) · 12 unmodified lines | |||
| 256 | 256 | ||
| 257 | static void offset_vmlinux_info(unsigned long offset) | 257 | static void offset_vmlinux_info(unsigned long offset) |
| 258 | { | 258 | { |
| 259 | vmlinux.default_lma += offset; | ||
| 260 | *(unsigned long *)(&vmlinux.entry) += offset; | 259 | *(unsigned long *)(&vmlinux.entry) += offset; |
| 261 | vmlinux.bootdata_off += offset; | 260 | vmlinux.bootdata_off += offset; |
| 262 | vmlinux.bootdata_preserved_off += offset; | 261 | vmlinux.bootdata_preserved_off += offset; |
| @@ -266,60 +265,83 @@ static void offset_vmlinux_info(unsigned long offset) · 3 unmodified lines | |||
| 266 | vmlinux.init_mm_off += offset; | 265 | vmlinux.init_mm_off += offset; |
| 267 | vmlinux.swapper_pg_dir_off += offset; | 266 | vmlinux.swapper_pg_dir_off += offset; |
| 268 | vmlinux.invalid_pg_dir_off += offset; | 267 | vmlinux.invalid_pg_dir_off += offset; |
| 269 | } | 268 | #ifdef CONFIG_KASAN |
| 270 | 269 | vmlinux.kasan_early_shadow_page_off += offset; | |
| 271 | static unsigned long reserve_amode31(unsigned long safe_addr) | 270 | vmlinux.kasan_early_shadow_pte_off += offset; |
| 272 | { | 271 | vmlinux.kasan_early_shadow_pmd_off += offset; |
| 273 | __amode31_base = PAGE_ALIGN(safe_addr); | 272 | vmlinux.kasan_early_shadow_pud_off += offset; |
| 274 | return __amode31_base + vmlinux.amode31_size; | 273 | vmlinux.kasan_early_shadow_p4d_off += offset; |
| 274 | #endif | ||
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | void startup_kernel(void) | 277 | void startup_kernel(void) |
| 278 | { | 278 | { |
| 279 | unsigned long max_physmem_end; | 279 | unsigned long max_physmem_end; |
| 280 | unsigned long random_lma; | 280 | unsigned long vmlinux_lma = 0; |
| 281 | unsigned long safe_addr; | 281 | unsigned long amode31_lma = 0; |
| 282 | unsigned long asce_limit; | 282 | unsigned long asce_limit; |
| 283 | unsigned long safe_addr; | ||
| 283 | void *img; | 284 | void *img; |
| 284 | psw_t psw; | 285 | psw_t psw; |
| 285 | 286 | ||
| 286 | initrd_data.start = parmarea.initrd_start; | 287 | setup_lpp(); |
| 287 | initrd_data.size = parmarea.initrd_size; | 288 | safe_addr = mem_safe_offset(); |
| 289 | /* | ||
| 290 | * reserve decompressor memory together with decompression heap, buffer and | ||
| 291 | * memory which might be occupied by uncompressed kernel at default 1Mb | ||
| 292 | * position (if KASLR is off or failed). | ||
| 293 | */ | ||
| 294 | physmem_reserve(RR_DECOMPRESSOR, 0, safe_addr); | ||
| 295 | if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && parmarea.initrd_size) | ||
| 296 | physmem_reserve(RR_INITRD, parmarea.initrd_start, parmarea.initrd_size); | ||
| 288 | oldmem_data.start = parmarea.oldmem_base; | 297 | oldmem_data.start = parmarea.oldmem_base; |
| 289 | oldmem_data.size = parmarea.oldmem_size; | 298 | oldmem_data.size = parmarea.oldmem_size; |
| 290 | 299 | ||
| 291 | setup_lpp(); | ||
| 292 | store_ipl_parmblock(); | 300 | store_ipl_parmblock(); |
| 293 | safe_addr = mem_safe_offset(); | 301 | read_ipl_report(); |
| 294 | safe_addr = reserve_amode31(safe_addr); | ||
| 295 | safe_addr = read_ipl_report(safe_addr); | ||
| 296 | uv_query_info(); | 302 | uv_query_info(); |
| 297 | safe_addr = rescue_initrd(safe_addr); | ||
| 298 | sclp_early_read_info(); | 303 | sclp_early_read_info(); |
| 299 | setup_boot_command_line(); | 304 | setup_boot_command_line(); |
| 300 | parse_boot_command_line(); | 305 | parse_boot_command_line(); |
| 301 | detect_facilities(); | 306 | detect_facilities(); |
| 302 | sanitize_prot_virt_host(); | 307 | sanitize_prot_virt_host(); |
| 303 | max_physmem_end = detect_memory(&safe_addr); | 308 | max_physmem_end = detect_max_physmem_end(); |
| 304 | setup_ident_map_size(max_physmem_end); | 309 | setup_ident_map_size(max_physmem_end); |
| 305 | setup_vmalloc_size(); | 310 | setup_vmalloc_size(); |
| 306 | asce_limit = setup_kernel_memory_layout(); | 311 | asce_limit = setup_kernel_memory_layout(); |
| 307 | mem_detect_set_usable_limit(ident_map_size); | 312 | /* got final ident_map_size, physmem allocations could be performed now */ |
| 308 | 313 | physmem_set_usable_limit(ident_map_size); | |
| 309 | if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && kaslr_enabled) { | 314 | detect_physmem_online_ranges(max_physmem_end); |
| 310 | random_lma = get_random_base(safe_addr); | 315 | save_ipl_cert_comp_list(); |
| 311 | if (random_lma) { | 316 | rescue_initrd(safe_addr, ident_map_size); |
| 312 | __kaslr_offset = random_lma - vmlinux.default_lma; | 317 | |
| 313 | img = (void *)vmlinux.default_lma; | 318 | if (kaslr_enabled()) { |
| 319 | vmlinux_lma = randomize_within_range(vmlinux.image_size + vmlinux.bss_size, | ||
| 320 | THREAD_SIZE, vmlinux.default_lma, | ||
| 321 | ident_map_size); | ||
| 322 | if (vmlinux_lma) { | ||
| 323 | __kaslr_offset = vmlinux_lma - vmlinux.default_lma; | ||
| 314 | offset_vmlinux_info(__kaslr_offset); | 324 | offset_vmlinux_info(__kaslr_offset); |
| 315 | } | 325 | } |
| 316 | } | 326 | } |
| 327 | vmlinux_lma = vmlinux_lma ?: vmlinux.default_lma; | ||
| 328 | physmem_reserve(RR_VMLINUX, vmlinux_lma, vmlinux.image_size + vmlinux.bss_size); | ||
| 317 | 329 | ||
| 318 | if (!IS_ENABLED(CONFIG_KERNEL_UNCOMPRESSED)) { | 330 | if (!IS_ENABLED(CONFIG_KERNEL_UNCOMPRESSED)) { |
| 319 | img = decompress_kernel(); | 331 | img = decompress_kernel(); |
| 320 | memmove((void *)vmlinux.default_lma, img, vmlinux.image_size); | 332 | memmove((void *)vmlinux_lma, img, vmlinux.image_size); |
| 321 | } else if (__kaslr_offset) | 333 | } else if (__kaslr_offset) { |
| 322 | memcpy((void *)vmlinux.default_lma, img, vmlinux.image_size); | 334 | img = (void *)vmlinux.default_lma; |
| 335 | memmove((void *)vmlinux_lma, img, vmlinux.image_size); | ||
| 336 | memset(img, 0, vmlinux.image_size); | ||
| 337 | } | ||
| 338 | |||
| 339 | /* vmlinux decompression is done, shrink reserved low memory */ | ||
| 340 | physmem_reserve(RR_DECOMPRESSOR, 0, (unsigned long)_decompressor_end); | ||
| 341 | if (kaslr_enabled()) | ||
| 342 | amode31_lma = randomize_within_range(vmlinux.amode31_size, PAGE_SIZE, 0, SZ_2G); | ||
| 343 | amode31_lma = amode31_lma ?: vmlinux.default_lma - vmlinux.amode31_size; | ||
| 344 | physmem_reserve(RR_AMODE31, amode31_lma, vmlinux.amode31_size); | ||
| 323 | 345 | ||
| 324 | /* | 346 | /* |
| 325 | * The order of the following operations is important: | 347 | * The order of the following operations is important: |
| @@ -334,21 +356,16 @@ void startup_kernel(void) · 8 unmodified lines | |||
| 334 | * - copy_bootdata() must follow setup_vmem() to propagate changes to | 356 | * - copy_bootdata() must follow setup_vmem() to propagate changes to |
| 335 | * bootdata made by setup_vmem() | 357 | * bootdata made by setup_vmem() |
| 336 | */ | 358 | */ |
| 337 | clear_bss_section(); | 359 | clear_bss_section(vmlinux_lma); |
| 338 | handle_relocs(__kaslr_offset); | 360 | handle_relocs(__kaslr_offset); |
| 339 | setup_vmem(asce_limit); | 361 | setup_vmem(asce_limit); |
| 340 | copy_bootdata(); | 362 | copy_bootdata(); |
| 341 | 363 | ||
| 342 | if (__kaslr_offset) { | 364 | /* |
| 343 | /* | 365 | * Save KASLR offset for early dumps, before vmcore_info is set. |
| 344 | * Save KASLR offset for early dumps, before vmcore_info is set. | 366 | * Mark as uneven to distinguish from real vmcore_info pointer. |
| 345 | * Mark as uneven to distinguish from real vmcore_info pointer. | 367 | */ |
| 346 | */ | 368 | S390_lowcore.vmcore_info = __kaslr_offset ? __kaslr_offset | 0x1UL : 0; |
| 347 | S390_lowcore.vmcore_info = __kaslr_offset | 0x1UL; | ||
| 348 | /* Clear non-relocated kernel */ | ||
| 349 | if (IS_ENABLED(CONFIG_KERNEL_UNCOMPRESSED)) | ||
| 350 | memset(img, 0, vmlinux.image_size); | ||
| 351 | } | ||
| 352 | 369 | ||
| 353 | /* | 370 | /* |
| 354 | * Jump to the decompressed kernel entry point and switch DAT mode on. | 371 | * Jump to the decompressed kernel entry point and switch DAT mode on. |
| @@ -1,81 +1,217 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | #include <linux/sched/task.h> | 2 | #include <linux/sched/task.h> |
| 3 | #include <linux/pgtable.h> | 3 | #include <linux/pgtable.h> |
| 4 | #include <linux/kasan.h> | ||
| 4 | #include <asm/pgalloc.h> | 5 | #include <asm/pgalloc.h> |
| 5 | #include <asm/facility.h> | 6 | #include <asm/facility.h> |
| 6 | #include <asm/sections.h> | 7 | #include <asm/sections.h> |
| 7 | #include <asm/mem_detect.h> | 8 | #include <asm/physmem_info.h> |
| 8 | #include <asm/maccess.h> | 9 | #include <asm/maccess.h> |
| 9 | #include <asm/abs_lowcore.h> | 10 | #include <asm/abs_lowcore.h> |
| 10 | #include "decompressor.h" | 11 | #include "decompressor.h" |
| 11 | #include "boot.h" | 12 | #include "boot.h" |
| 12 | 13 | ||
| 14 | unsigned long __bootdata_preserved(s390_invalid_asce); | ||
| 15 | |||
| 16 | #ifdef CONFIG_PROC_FS | ||
| 17 | atomic_long_t __bootdata_preserved(direct_pages_count[PG_DIRECT_MAP_MAX]); | ||
| 18 | #endif | ||
| 19 | |||
| 13 | #define init_mm (*(struct mm_struct *)vmlinux.init_mm_off) | 20 | #define init_mm (*(struct mm_struct *)vmlinux.init_mm_off) |
| 14 | #define swapper_pg_dir vmlinux.swapper_pg_dir_off | 21 | #define swapper_pg_dir vmlinux.swapper_pg_dir_off |
| 15 | #define invalid_pg_dir vmlinux.invalid_pg_dir_off | 22 | #define invalid_pg_dir vmlinux.invalid_pg_dir_off |
| 16 | 23 | ||
| 17 | /* | ||
| 18 | * Mimic virt_to_kpte() in lack of init_mm symbol. Skip pmd NULL check though. | ||
| 19 | */ | ||
| 20 | static inline pte_t *__virt_to_kpte(unsigned long va) | ||
| 21 | { | ||
| 22 | return pte_offset_kernel(pmd_offset(pud_offset(p4d_offset(pgd_offset_k(va), va), va), va), va); | ||
| 23 | } | ||
| 24 | |||
| 25 | unsigned long __bootdata_preserved(s390_invalid_asce); | ||
| 26 | unsigned long __bootdata(pgalloc_pos); | ||
| 27 | unsigned long __bootdata(pgalloc_end); | ||
| 28 | unsigned long __bootdata(pgalloc_low); | ||
| 29 | |||
| 30 | enum populate_mode { | 24 | enum populate_mode { |
| 31 | POPULATE_NONE, | 25 | POPULATE_NONE, |
| 32 | POPULATE_ONE2ONE, | 26 | POPULATE_DIRECT, |
| 33 | POPULATE_ABS_LOWCORE, | 27 | POPULATE_ABS_LOWCORE, |
| 28 | #ifdef CONFIG_KASAN | ||
| 29 | POPULATE_KASAN_MAP_SHADOW, | ||
| 30 | POPULATE_KASAN_ZERO_SHADOW, | ||
| 31 | POPULATE_KASAN_SHALLOW | ||
| 32 | #endif | ||
| 34 | }; | 33 | }; |
| 35 | 34 | ||
| 36 | static void boot_check_oom(void) | 35 | static void pgtable_populate(unsigned long addr, unsigned long end, enum populate_mode mode); |
| 36 | |||
| 37 | #ifdef CONFIG_KASAN | ||
| 38 | |||
| 39 | #define kasan_early_shadow_page vmlinux.kasan_early_shadow_page_off | ||
| 40 | #define kasan_early_shadow_pte ((pte_t *)vmlinux.kasan_early_shadow_pte_off) | ||
| 41 | #define kasan_early_shadow_pmd ((pmd_t *)vmlinux.kasan_early_shadow_pmd_off) | ||
| 42 | #define kasan_early_shadow_pud ((pud_t *)vmlinux.kasan_early_shadow_pud_off) | ||
| 43 | #define kasan_early_shadow_p4d ((p4d_t *)vmlinux.kasan_early_shadow_p4d_off) | ||
| 44 | #define __sha(x) ((unsigned long)kasan_mem_to_shadow((void *)x)) | ||
| 45 | |||
| 46 | static pte_t pte_z; | ||
| 47 | |||
| 48 | static void kasan_populate_shadow(void) | ||
| 49 | { | ||
| 50 | pmd_t pmd_z = __pmd(__pa(kasan_early_shadow_pte) | _SEGMENT_ENTRY); | ||
| 51 | pud_t pud_z = __pud(__pa(kasan_early_shadow_pmd) | _REGION3_ENTRY); | ||
| 52 | p4d_t p4d_z = __p4d(__pa(kasan_early_shadow_pud) | _REGION2_ENTRY); | ||
| 53 | unsigned long untracked_end; | ||
| 54 | unsigned long start, end; | ||
| 55 | int i; | ||
| 56 | |||
| 57 | pte_z = __pte(__pa(kasan_early_shadow_page) | pgprot_val(PAGE_KERNEL_RO)); | ||
| 58 | if (!machine.has_nx) | ||
| 59 | pte_z = clear_pte_bit(pte_z, __pgprot(_PAGE_NOEXEC)); | ||
| 60 | crst_table_init((unsigned long *)kasan_early_shadow_p4d, p4d_val(p4d_z)); | ||
| 61 | crst_table_init((unsigned long *)kasan_early_shadow_pud, pud_val(pud_z)); | ||
| 62 | crst_table_init((unsigned long *)kasan_early_shadow_pmd, pmd_val(pmd_z)); | ||
| 63 | memset64((u64 *)kasan_early_shadow_pte, pte_val(pte_z), PTRS_PER_PTE); | ||
| 64 | |||
| 65 | /* | ||
| 66 | * Current memory layout: | ||
| 67 | * +- 0 -------------+ +- shadow start -+ | ||
| 68 | * |1:1 ident mapping| /|1/8 of ident map| | ||
| 69 | * | | / | | | ||
| 70 | * +-end of ident map+ / +----------------+ | ||
| 71 | * | ... gap ... | / | kasan | | ||
| 72 | * | | / | zero page | | ||
| 73 | * +- vmalloc area -+ / | mapping | | ||
| 74 | * | vmalloc_size | / | (untracked) | | ||
| 75 | * +- modules vaddr -+ / +----------------+ | ||
| 76 | * | 2Gb |/ | unmapped | allocated per module | ||
| 77 | * +- shadow start -+ +----------------+ | ||
| 78 | * | 1/8 addr space | | zero pg mapping| (untracked) | ||
| 79 | * +- shadow end ----+---------+- shadow end ---+ | ||
| 80 | * | ||
| 81 | * Current memory layout (KASAN_VMALLOC): | ||
| 82 | * +- 0 -------------+ +- shadow start -+ | ||
| 83 | * |1:1 ident mapping| /|1/8 of ident map| | ||
| 84 | * | | / | | | ||
| 85 | * +-end of ident map+ / +----------------+ | ||
| 86 | * | ... gap ... | / | kasan zero page| (untracked) | ||
| 87 | * | | / | mapping | | ||
| 88 | * +- vmalloc area -+ / +----------------+ | ||
| 89 | * | vmalloc_size | / |shallow populate| | ||
| 90 | * +- modules vaddr -+ / +----------------+ | ||
| 91 | * | 2Gb |/ |shallow populate| | ||
| 92 | * +- shadow start -+ +----------------+ | ||
| 93 | * | 1/8 addr space | | zero pg mapping| (untracked) | ||
| 94 | * +- shadow end ----+---------+- shadow end ---+ | ||
| 95 | */ | ||
| 96 | |||
| 97 | for_each_physmem_usable_range(i, &start, &end) | ||
| 98 | pgtable_populate(__sha(start), __sha(end), POPULATE_KASAN_MAP_SHADOW); | ||
| 99 | if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) { | ||
| 100 | untracked_end = VMALLOC_START; | ||
| 101 | /* shallowly populate kasan shadow for vmalloc and modules */ | ||
| 102 | pgtable_populate(__sha(VMALLOC_START), __sha(MODULES_END), POPULATE_KASAN_SHALLOW); | ||
| 103 | } else { | ||
| 104 | untracked_end = MODULES_VADDR; | ||
| 105 | } | ||
| 106 | /* populate kasan shadow for untracked memory */ | ||
| 107 | pgtable_populate(__sha(ident_map_size), __sha(untracked_end), POPULATE_KASAN_ZERO_SHADOW); | ||
| 108 | pgtable_populate(__sha(MODULES_END), __sha(_REGION1_SIZE), POPULATE_KASAN_ZERO_SHADOW); | ||
| 109 | } | ||
| 110 | |||
| 111 | static bool kasan_pgd_populate_zero_shadow(pgd_t *pgd, unsigned long addr, | ||
| 112 | unsigned long end, enum populate_mode mode) | ||
| 37 | { | 113 | { |
| 38 | if (pgalloc_pos < pgalloc_low) | 114 | if (mode == POPULATE_KASAN_ZERO_SHADOW && |
| 39 | error("out of memory on boot\n"); | 115 | IS_ALIGNED(addr, PGDIR_SIZE) && end - addr >= PGDIR_SIZE) { |
| 116 | pgd_populate(&init_mm, pgd, kasan_early_shadow_p4d); | ||
| 117 | return true; | ||
| 118 | } | ||
| 119 | return false; | ||
| 40 | } | 120 | } |
| 41 | 121 | ||
| 42 | static void pgtable_populate_init(void) | 122 | static bool kasan_p4d_populate_zero_shadow(p4d_t *p4d, unsigned long addr, |
| 123 | unsigned long end, enum populate_mode mode) | ||
| 43 | { | 124 | { |
| 44 | unsigned long initrd_end; | 125 | if (mode == POPULATE_KASAN_ZERO_SHADOW && |
| 45 | unsigned long kernel_end; | 126 | IS_ALIGNED(addr, P4D_SIZE) && end - addr >= P4D_SIZE) { |
| 46 | 127 | p4d_populate(&init_mm, p4d, kasan_early_shadow_pud); | |
| 47 | kernel_end = vmlinux.default_lma + vmlinux.image_size + vmlinux.bss_size; | 128 | return true; |
| 48 | pgalloc_low = round_up(kernel_end, PAGE_SIZE); | ||
| 49 | if (IS_ENABLED(CONFIG_BLK_DEV_INITRD)) { | ||
| 50 | initrd_end = round_up(initrd_data.start + initrd_data.size, _SEGMENT_SIZE); | ||
| 51 | pgalloc_low = max(pgalloc_low, initrd_end); | ||
| 52 | } | 129 | } |
| 130 | return false; | ||
| 131 | } | ||
| 53 | 132 | ||
| 54 | pgalloc_end = round_down(get_mem_detect_end(), PAGE_SIZE); | 133 | static bool kasan_pud_populate_zero_shadow(pud_t *pud, unsigned long addr, |
| 55 | pgalloc_pos = pgalloc_end; | 134 | unsigned long end, enum populate_mode mode) |
| 135 | { | ||
| 136 | if (mode == POPULATE_KASAN_ZERO_SHADOW && | ||
| 137 | IS_ALIGNED(addr, PUD_SIZE) && end - addr >= PUD_SIZE) { | ||
| 138 | pud_populate(&init_mm, pud, kasan_early_shadow_pmd); | ||
| 139 | return true; | ||
| 140 | } | ||
| 141 | return false; | ||
| 142 | } | ||
| 56 | 143 | ||
| 57 | boot_check_oom(); | 144 | static bool kasan_pmd_populate_zero_shadow(pmd_t *pmd, unsigned long addr, |
| 145 | unsigned long end, enum populate_mode mode) | ||
| 146 | { | ||
| 147 | if (mode == POPULATE_KASAN_ZERO_SHADOW && | ||
| 148 | IS_ALIGNED(addr, PMD_SIZE) && end - addr >= PMD_SIZE) { | ||
| 149 | pmd_populate(&init_mm, pmd, kasan_early_shadow_pte); | ||
| 150 | return true; | ||
| 151 | } | ||
| 152 | return false; | ||
| 58 | } | 153 | } |
| 59 | 154 | ||
| 60 | static void *boot_alloc_pages(unsigned int order) | 155 | static bool kasan_pte_populate_zero_shadow(pte_t *pte, enum populate_mode mode) |
| 61 | { | 156 | { |
| 62 | unsigned long size = PAGE_SIZE << order; | 157 | pte_t entry; |
| 63 | 158 | ||
| 64 | pgalloc_pos -= size; | 159 | if (mode == POPULATE_KASAN_ZERO_SHADOW) { |
| 65 | pgalloc_pos = round_down(pgalloc_pos, size); | 160 | set_pte(pte, pte_z); |
| 161 | return true; | ||
| 162 | } | ||
| 163 | return false; | ||
| 164 | } | ||
| 165 | #else | ||
| 66 | 166 | ||
| 67 | boot_check_oom(); | 167 | static inline void kasan_populate_shadow(void) {} |
| 68 | 168 | ||
| 69 | return (void *)pgalloc_pos; | 169 | static inline bool kasan_pgd_populate_zero_shadow(pgd_t *pgd, unsigned long addr, |
| 170 | unsigned long end, enum populate_mode mode) | ||
| 171 | { | ||
| 172 | return false; | ||
| 173 | } | ||
| 174 | |||
| 175 | static inline bool kasan_p4d_populate_zero_shadow(p4d_t *p4d, unsigned long addr, | ||
| 176 | unsigned long end, enum populate_mode mode) | ||
| 177 | { | ||
| 178 | return false; | ||
| 179 | } | ||
| 180 | |||
| 181 | static inline bool kasan_pud_populate_zero_shadow(pud_t *pud, unsigned long addr, | ||
| 182 | unsigned long end, enum populate_mode mode) | ||
| 183 | { | ||
| 184 | return false; | ||
| 185 | } | ||
| 186 | |||
| 187 | static inline bool kasan_pmd_populate_zero_shadow(pmd_t *pmd, unsigned long addr, | ||
| 188 | unsigned long end, enum populate_mode mode) | ||
| 189 | { | ||
| 190 | return false; | ||
| 191 | } | ||
| 192 | |||
| 193 | static bool kasan_pte_populate_zero_shadow(pte_t *pte, enum populate_mode mode) | ||
| 194 | { | ||
| 195 | return false; | ||
| 196 | } | ||
| 197 | |||
| 198 | #endif | ||
| 199 | |||
| 200 | /* | ||
| 201 | * Mimic virt_to_kpte() in lack of init_mm symbol. Skip pmd NULL check though. | ||
| 202 | */ | ||
| 203 | static inline pte_t *__virt_to_kpte(unsigned long va) | ||
| 204 | { | ||
| 205 | return pte_offset_kernel(pmd_offset(pud_offset(p4d_offset(pgd_offset_k(va), va), va), va), va); | ||
| 70 | } | 206 | } |
| 71 | 207 | ||
| 72 | static void *boot_crst_alloc(unsigned long val) | 208 | static void *boot_crst_alloc(unsigned long val) |
| 73 | { | 209 | { |
| 210 | unsigned long size = PAGE_SIZE << CRST_ALLOC_ORDER; | ||
| 74 | unsigned long *table; | 211 | unsigned long *table; |
| 75 | 212 | ||
| 76 | table = boot_alloc_pages(CRST_ALLOC_ORDER); | 213 | table = (unsigned long *)physmem_alloc_top_down(RR_VMEM, size, size); |
| 77 | if (table) | 214 | crst_table_init(table, val); |
| 78 | crst_table_init(table, val); | ||
| 79 | return table; | 215 | return table; |
| 80 | } | 216 | } |
| 81 | 217 | ||
| @@ -84,28 +220,37 @@ static pte_t *boot_pte_alloc(void) · 2 unmodified lines | |||
| 84 | static void *pte_leftover; | 220 | static void *pte_leftover; |
| 85 | pte_t *pte; | 221 | pte_t *pte; |
| 86 | 222 | ||
| 87 | BUILD_BUG_ON(_PAGE_TABLE_SIZE * 2 != PAGE_SIZE); | 223 | /* |
| 88 | 224 | * handling pte_leftovers this way helps to avoid memory fragmentation | |
| 225 | * during POPULATE_KASAN_MAP_SHADOW when EDAT is off | ||
| 226 | */ | ||
| 89 | if (!pte_leftover) { | 227 | if (!pte_leftover) { |
| 90 | pte_leftover = boot_alloc_pages(0); | 228 | pte_leftover = (void *)physmem_alloc_top_down(RR_VMEM, PAGE_SIZE, PAGE_SIZE); |
| 91 | pte = pte_leftover + _PAGE_TABLE_SIZE; | 229 | pte = pte_leftover + _PAGE_TABLE_SIZE; |
| 92 | } else { | 230 | } else { |
| 93 | pte = pte_leftover; | 231 | pte = pte_leftover; |
| 94 | pte_leftover = NULL; | 232 | pte_leftover = NULL; |
| 95 | } | 233 | } |
| 234 | |||
| 96 | memset64((u64 *)pte, _PAGE_INVALID, PTRS_PER_PTE); | 235 | memset64((u64 *)pte, _PAGE_INVALID, PTRS_PER_PTE); |
| 97 | return pte; | 236 | return pte; |
| 98 | } | 237 | } |
| 99 | 238 | ||
| 100 | static unsigned long _pa(unsigned long addr, enum populate_mode mode) | 239 | static unsigned long _pa(unsigned long addr, unsigned long size, enum populate_mode mode) |
| 101 | { | 240 | { |
| 102 | switch (mode) { | 241 | switch (mode) { |
| 103 | case POPULATE_NONE: | 242 | case POPULATE_NONE: |
| 104 | return -1; | 243 | return -1; |
| 105 | case POPULATE_ONE2ONE: | 244 | case POPULATE_DIRECT: |
| 106 | return addr; | 245 | return addr; |
| 107 | case POPULATE_ABS_LOWCORE: | 246 | case POPULATE_ABS_LOWCORE: |
| 108 | return __abs_lowcore_pa(addr); | 247 | return __abs_lowcore_pa(addr); |
| 248 | #ifdef CONFIG_KASAN | ||
| 249 | case POPULATE_KASAN_MAP_SHADOW: | ||
| 250 | addr = physmem_alloc_top_down(RR_VMEM, size, size); | ||
| 251 | memset((void *)addr, 0, size); | ||
| 252 | return addr; | ||
| 253 | #endif | ||
| 109 | default: | 254 | default: |
| 110 | return -1; | 255 | return -1; |
| 111 | } | 256 | } |
| @@ -126,23 +271,28 @@ static bool can_large_pmd(pmd_t *pm_dir, unsigned long addr, unsigned long end) · 14 unmodified lines | |||
| 126 | static void pgtable_pte_populate(pmd_t *pmd, unsigned long addr, unsigned long end, | 271 | static void pgtable_pte_populate(pmd_t *pmd, unsigned long addr, unsigned long end, |
| 127 | enum populate_mode mode) | 272 | enum populate_mode mode) |
| 128 | { | 273 | { |
| 129 | unsigned long next; | 274 | unsigned long pages = 0; |
| 130 | pte_t *pte, entry; | 275 | pte_t *pte, entry; |
| 131 | 276 | ||
| 132 | pte = pte_offset_kernel(pmd, addr); | 277 | pte = pte_offset_kernel(pmd, addr); |
| 133 | for (; addr < end; addr += PAGE_SIZE, pte++) { | 278 | for (; addr < end; addr += PAGE_SIZE, pte++) { |
| 134 | if (pte_none(*pte)) { | 279 | if (pte_none(*pte)) { |
| 135 | entry = __pte(_pa(addr, mode)); | 280 | if (kasan_pte_populate_zero_shadow(pte, mode)) |
| 281 | continue; | ||
| 282 | entry = __pte(_pa(addr, PAGE_SIZE, mode)); | ||
| 136 | entry = set_pte_bit(entry, PAGE_KERNEL_EXEC); | 283 | entry = set_pte_bit(entry, PAGE_KERNEL_EXEC); |
| 137 | set_pte(pte, entry); | 284 | set_pte(pte, entry); |
| 285 | pages++; | ||
| 138 | } | 286 | } |
| 139 | } | 287 | } |
| 288 | if (mode == POPULATE_DIRECT) | ||
| 289 | update_page_count(PG_DIRECT_MAP_4K, pages); | ||
| 140 | } | 290 | } |
| 141 | 291 | ||
| 142 | static void pgtable_pmd_populate(pud_t *pud, unsigned long addr, unsigned long end, | 292 | static void pgtable_pmd_populate(pud_t *pud, unsigned long addr, unsigned long end, |
| 143 | enum populate_mode mode) | 293 | enum populate_mode mode) |
| 144 | { | 294 | { |
| 145 | unsigned long next; | 295 | unsigned long next, pages = 0; |
| 146 | pmd_t *pmd, entry; | 296 | pmd_t *pmd, entry; |
| 147 | pte_t *pte; | 297 | pte_t *pte; |
| 148 | 298 | ||
| @@ -150,10 +300,13 @@ static void pgtable_pmd_populate(pud_t *pud, unsigned long addr, unsigned long e · 1 unmodified line | |||
| 150 | for (; addr < end; addr = next, pmd++) { | 300 | for (; addr < end; addr = next, pmd++) { |
| 151 | next = pmd_addr_end(addr, end); | 301 | next = pmd_addr_end(addr, end); |
| 152 | if (pmd_none(*pmd)) { | 302 | if (pmd_none(*pmd)) { |
| 303 | if (kasan_pmd_populate_zero_shadow(pmd, addr, next, mode)) | ||
| 304 | continue; | ||
| 153 | if (can_large_pmd(pmd, addr, next)) { | 305 | if (can_large_pmd(pmd, addr, next)) { |
| 154 | entry = __pmd(_pa(addr, mode)); | 306 | entry = __pmd(_pa(addr, _SEGMENT_SIZE, mode)); |
| 155 | entry = set_pmd_bit(entry, SEGMENT_KERNEL_EXEC); | 307 | entry = set_pmd_bit(entry, SEGMENT_KERNEL_EXEC); |
| 156 | set_pmd(pmd, entry); | 308 | set_pmd(pmd, entry); |
| 309 | pages++; | ||
| 157 | continue; | 310 | continue; |
| 158 | } | 311 | } |
| 159 | pte = boot_pte_alloc(); | 312 | pte = boot_pte_alloc(); |
| @@ -163,12 +316,14 @@ static void pgtable_pmd_populate(pud_t *pud, unsigned long addr, unsigned long e · 3 unmodified lines | |||
| 163 | } | 316 | } |
| 164 | pgtable_pte_populate(pmd, addr, next, mode); | 317 | pgtable_pte_populate(pmd, addr, next, mode); |
| 165 | } | 318 | } |
| 319 | if (mode == POPULATE_DIRECT) | ||
| 320 | update_page_count(PG_DIRECT_MAP_1M, pages); | ||
| 166 | } | 321 | } |
| 167 | 322 | ||
| 168 | static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long end, | 323 | static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long end, |
| 169 | enum populate_mode mode) | 324 | enum populate_mode mode) |
| 170 | { | 325 | { |
| 171 | unsigned long next; | 326 | unsigned long next, pages = 0; |
| 172 | pud_t *pud, entry; | 327 | pud_t *pud, entry; |
| 173 | pmd_t *pmd; | 328 | pmd_t *pmd; |
| 174 | 329 | ||
| @@ -176,10 +331,13 @@ static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long e · 1 unmodified line | |||
| 176 | for (; addr < end; addr = next, pud++) { | 331 | for (; addr < end; addr = next, pud++) { |
| 177 | next = pud_addr_end(addr, end); | 332 | next = pud_addr_end(addr, end); |
| 178 | if (pud_none(*pud)) { | 333 | if (pud_none(*pud)) { |
| 334 | if (kasan_pud_populate_zero_shadow(pud, addr, next, mode)) | ||
| 335 | continue; | ||
| 179 | if (can_large_pud(pud, addr, next)) { | 336 | if (can_large_pud(pud, addr, next)) { |
| 180 | entry = __pud(_pa(addr, mode)); | 337 | entry = __pud(_pa(addr, _REGION3_SIZE, mode)); |
| 181 | entry = set_pud_bit(entry, REGION3_KERNEL_EXEC); | 338 | entry = set_pud_bit(entry, REGION3_KERNEL_EXEC); |
| 182 | set_pud(pud, entry); | 339 | set_pud(pud, entry); |
| 340 | pages++; | ||
| 183 | continue; | 341 | continue; |
| 184 | } | 342 | } |
| 185 | pmd = boot_crst_alloc(_SEGMENT_ENTRY_EMPTY); | 343 | pmd = boot_crst_alloc(_SEGMENT_ENTRY_EMPTY); |
| @@ -189,6 +347,8 @@ static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long e · 3 unmodified lines | |||
| 189 | } | 347 | } |
| 190 | pgtable_pmd_populate(pud, addr, next, mode); | 348 | pgtable_pmd_populate(pud, addr, next, mode); |
| 191 | } | 349 | } |
| 350 | if (mode == POPULATE_DIRECT) | ||
| 351 | update_page_count(PG_DIRECT_MAP_2G, pages); | ||
| 192 | } | 352 | } |
| 193 | 353 | ||
| 194 | static void pgtable_p4d_populate(pgd_t *pgd, unsigned long addr, unsigned long end, | 354 | static void pgtable_p4d_populate(pgd_t *pgd, unsigned long addr, unsigned long end, |
| @@ -202,6 +362,8 @@ static void pgtable_p4d_populate(pgd_t *pgd, unsigned long addr, unsigned long e · 7 unmodified lines | |||
| 202 | for (; addr < end; addr = next, p4d++) { | 362 | for (; addr < end; addr = next, p4d++) { |
| 203 | next = p4d_addr_end(addr, end); | 363 | next = p4d_addr_end(addr, end); |
| 204 | if (p4d_none(*p4d)) { | 364 | if (p4d_none(*p4d)) { |
| 365 | if (kasan_p4d_populate_zero_shadow(p4d, addr, next, mode)) | ||
| 366 | continue; | ||
| 205 | pud = boot_crst_alloc(_REGION3_ENTRY_EMPTY); | 367 | pud = boot_crst_alloc(_REGION3_ENTRY_EMPTY); |
| 206 | p4d_populate(&init_mm, p4d, pud); | 368 | p4d_populate(&init_mm, p4d, pud); |
| 207 | } | 369 | } |
| @@ -219,9 +381,15 @@ static void pgtable_populate(unsigned long addr, unsigned long end, enum populat · 11 unmodified lines | |||
| 219 | for (; addr < end; addr = next, pgd++) { | 381 | for (; addr < end; addr = next, pgd++) { |
| 220 | next = pgd_addr_end(addr, end); | 382 | next = pgd_addr_end(addr, end); |
| 221 | if (pgd_none(*pgd)) { | 383 | if (pgd_none(*pgd)) { |
| 384 | if (kasan_pgd_populate_zero_shadow(pgd, addr, next, mode)) | ||
| 385 | continue; | ||
| 222 | p4d = boot_crst_alloc(_REGION2_ENTRY_EMPTY); | 386 | p4d = boot_crst_alloc(_REGION2_ENTRY_EMPTY); |
| 223 | pgd_populate(&init_mm, pgd, p4d); | 387 | pgd_populate(&init_mm, pgd, p4d); |
| 224 | } | 388 | } |
| 389 | #ifdef CONFIG_KASAN | ||
| 390 | if (mode == POPULATE_KASAN_SHALLOW) | ||
| 391 | continue; | ||
| 392 | #endif | ||
| 225 | pgtable_p4d_populate(pgd, addr, next, mode); | 393 | pgtable_p4d_populate(pgd, addr, next, mode); |
| 226 | } | 394 | } |
| 227 | } | 395 | } |
| @@ -250,16 +418,17 @@ void setup_vmem(unsigned long asce_limit) · 22 unmodified lines | |||
| 250 | * To prevent creation of a large page at address 0 first map | 418 | * To prevent creation of a large page at address 0 first map |
| 251 | * the lowcore and create the identity mapping only afterwards. | 419 | * the lowcore and create the identity mapping only afterwards. |
| 252 | */ | 420 | */ |
| 253 | pgtable_populate_init(); | 421 | pgtable_populate(0, sizeof(struct lowcore), POPULATE_DIRECT); |
| 254 | pgtable_populate(0, sizeof(struct lowcore), POPULATE_ONE2ONE); | 422 | for_each_physmem_usable_range(i, &start, &end) |
| 255 | for_each_mem_detect_usable_block(i, &start, &end) | 423 | pgtable_populate(start, end, POPULATE_DIRECT); |
| 256 | pgtable_populate(start, end, POPULATE_ONE2ONE); | ||
| 257 | pgtable_populate(__abs_lowcore, __abs_lowcore + sizeof(struct lowcore), | 424 | pgtable_populate(__abs_lowcore, __abs_lowcore + sizeof(struct lowcore), |
| 258 | POPULATE_ABS_LOWCORE); | 425 | POPULATE_ABS_LOWCORE); |
| 259 | pgtable_populate(__memcpy_real_area, __memcpy_real_area + PAGE_SIZE, | 426 | pgtable_populate(__memcpy_real_area, __memcpy_real_area + PAGE_SIZE, |
| 260 | POPULATE_NONE); | 427 | POPULATE_NONE); |
| 261 | memcpy_real_ptep = __virt_to_kpte(__memcpy_real_area); | 428 | memcpy_real_ptep = __virt_to_kpte(__memcpy_real_area); |
| 262 | 429 | ||
| 430 | kasan_populate_shadow(); | ||
| 431 | |||
| 263 | S390_lowcore.kernel_asce = swapper_pg_dir | asce_bits; | 432 | S390_lowcore.kernel_asce = swapper_pg_dir | asce_bits; |
| 264 | S390_lowcore.user_asce = s390_invalid_asce; | 433 | S390_lowcore.user_asce = s390_invalid_asce; |
| 265 | 434 | ||
| @@ -269,10 +438,3 @@ void setup_vmem(unsigned long asce_limit) · 3 unmodified lines | |||
| 269 | 438 | ||
| 270 | init_mm.context.asce = S390_lowcore.kernel_asce; | 439 | init_mm.context.asce = S390_lowcore.kernel_asce; |
| 271 | } | 440 | } |
| 272 | |||
| 273 | unsigned long vmem_estimate_memory_needs(unsigned long online_mem_total) | ||
| 274 | { | ||
| 275 | unsigned long pages = DIV_ROUND_UP(online_mem_total, PAGE_SIZE); | ||
| 276 | |||
| 277 | return DIV_ROUND_UP(pages, _PAGE_ENTRIES) * _PAGE_TABLE_SIZE * 2; | ||
| 278 | } | ||
| @@ -93,6 +93,8 @@ SECTIONS · 92 unmodified lines | |||
| 93 | _decompressor_syms_end = .; | 93 | _decompressor_syms_end = .; |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | _decompressor_end = .; | ||
| 97 | |||
| 96 | #ifdef CONFIG_KERNEL_UNCOMPRESSED | 98 | #ifdef CONFIG_KERNEL_UNCOMPRESSED |
| 97 | . = 0x100000; | 99 | . = 0x100000; |
| 98 | #else | 100 | #else |
| @@ -13,27 +13,28 @@ · 12 unmodified lines | |||
| 13 | #define SP %r15 | 13 | #define SP %r15 |
| 14 | #define FRAME (16 * 8 + 4 * 8) | 14 | #define FRAME (16 * 8 + 4 * 8) |
| 15 | 15 | ||
| 16 | .data | 16 | .data |
| 17 | .align 32 | 17 | .balign 32 |
| 18 | |||
| 19 | .Lsigma: | ||
| 20 | .long 0x61707865,0x3320646e,0x79622d32,0x6b206574 # endian-neutral | ||
| 21 | .long 1,0,0,0 | ||
| 22 | .long 2,0,0,0 | ||
| 23 | .long 3,0,0,0 | ||
| 24 | .long 0x03020100,0x07060504,0x0b0a0908,0x0f0e0d0c # byte swap | ||
| 25 | |||
| 26 | .long 0,1,2,3 | ||
| 27 | .long 0x61707865,0x61707865,0x61707865,0x61707865 # smashed sigma | ||
| 28 | .long 0x3320646e,0x3320646e,0x3320646e,0x3320646e | ||
| 29 | .long 0x79622d32,0x79622d32,0x79622d32,0x79622d32 | ||
| 30 | .long 0x6b206574,0x6b206574,0x6b206574,0x6b206574 | ||
| 31 | 18 | ||
| 32 | .previous | 19 | SYM_DATA_START_LOCAL(sigma) |
| 20 | .long 0x61707865,0x3320646e,0x79622d32,0x6b206574 # endian-neutral | ||
| 21 | .long 1,0,0,0 | ||
| 22 | .long 2,0,0,0 | ||
| 23 | .long 3,0,0,0 | ||
| 24 | .long 0x03020100,0x07060504,0x0b0a0908,0x0f0e0d0c # byte swap | ||
| 25 | |||
| 26 | .long 0,1,2,3 | ||
| 27 | .long 0x61707865,0x61707865,0x61707865,0x61707865 # smashed sigma | ||
| 28 | .long 0x3320646e,0x3320646e,0x3320646e,0x3320646e | ||
| 29 | .long 0x79622d32,0x79622d32,0x79622d32,0x79622d32 | ||
| 30 | .long 0x6b206574,0x6b206574,0x6b206574,0x6b206574 | ||
| 31 | SYM_DATA_END(sigma) | ||
| 32 | |||
| 33 | .previous | ||
| 33 | 34 | ||
| 34 | GEN_BR_THUNK %r14 | 35 | GEN_BR_THUNK %r14 |
| 35 | 36 | ||
| 36 | .text | 37 | .text |
| 37 | 38 | ||
| 38 | ############################################################################# | 39 | ############################################################################# |
| 39 | # void chacha20_vx_4x(u8 *out, counst u8 *inp, size_t len, | 40 | # void chacha20_vx_4x(u8 *out, counst u8 *inp, size_t len, |
| @@ -78,10 +79,10 @@ · 38 unmodified lines | |||
| 78 | #define XT2 %v29 | 79 | #define XT2 %v29 |
| 79 | #define XT3 %v30 | 80 | #define XT3 %v30 |
| 80 | 81 | ||
| 81 | ENTRY(chacha20_vx_4x) | 82 | SYM_FUNC_START(chacha20_vx_4x) |
| 82 | stmg %r6,%r7,6*8(SP) | 83 | stmg %r6,%r7,6*8(SP) |
| 83 | 84 | ||
| 84 | larl %r7,.Lsigma | 85 | larl %r7,sigma |
| 85 | lhi %r0,10 | 86 | lhi %r0,10 |
| 86 | lhi %r1,0 | 87 | lhi %r1,0 |
| 87 | 88 | ||
| @@ -403,7 +404,7 @@ ENTRY(chacha20_vx_4x) · 315 unmodified lines | |||
| 403 | 404 | ||
| 404 | lmg %r6,%r7,6*8(SP) | 405 | lmg %r6,%r7,6*8(SP) |
| 405 | BR_EX %r14 | 406 | BR_EX %r14 |
| 406 | ENDPROC(chacha20_vx_4x) | 407 | SYM_FUNC_END(chacha20_vx_4x) |
| 407 | 408 | ||
| 408 | #undef OUT | 409 | #undef OUT |
| 409 | #undef INP | 410 | #undef INP |
| @@ -471,7 +472,7 @@ ENDPROC(chacha20_vx_4x) · 61 unmodified lines | |||
| 471 | #define T2 %v29 | 472 | #define T2 %v29 |
| 472 | #define T3 %v30 | 473 | #define T3 %v30 |
| 473 | 474 | ||
| 474 | ENTRY(chacha20_vx) | 475 | SYM_FUNC_START(chacha20_vx) |
| 475 | clgfi LEN,256 | 476 | clgfi LEN,256 |
| 476 | jle chacha20_vx_4x | 477 | jle chacha20_vx_4x |
| 477 | stmg %r6,%r7,6*8(SP) | 478 | stmg %r6,%r7,6*8(SP) |
| @@ -481,7 +482,7 @@ ENTRY(chacha20_vx) · 3 unmodified lines | |||
| 481 | la SP,0(%r1,SP) | 482 | la SP,0(%r1,SP) |
| 482 | stg %r0,0(SP) # back-chain | 483 | stg %r0,0(SP) # back-chain |
| 483 | 484 | ||
| 484 | larl %r7,.Lsigma | 485 | larl %r7,sigma |
| 485 | lhi %r0,10 | 486 | lhi %r0,10 |
| 486 | 487 | ||
| 487 | VLM K1,K2,0,KEY,0 # load key | 488 | VLM K1,K2,0,KEY,0 # load key |
| @@ -902,6 +903,6 @@ ENTRY(chacha20_vx) · 414 unmodified lines | |||
| 902 | lmg %r6,%r7,FRAME+6*8(SP) | 903 | lmg %r6,%r7,FRAME+6*8(SP) |
| 903 | la SP,FRAME(SP) | 904 | la SP,FRAME(SP) |
| 904 | BR_EX %r14 | 905 | BR_EX %r14 |
| 905 | ENDPROC(chacha20_vx) | 906 | SYM_FUNC_END(chacha20_vx) |
| 906 | 907 | ||
| 907 | .previous | 908 | .previous |
| @@ -24,8 +24,8 @@ · 23 unmodified lines | |||
| 24 | #define CONST_RU_POLY %v13 | 24 | #define CONST_RU_POLY %v13 |
| 25 | #define CONST_CRC_POLY %v14 | 25 | #define CONST_CRC_POLY %v14 |
| 26 | 26 | ||
| 27 | .data | 27 | .data |
| 28 | .align 8 | 28 | .balign 8 |
| 29 | 29 | ||
| 30 | /* | 30 | /* |
| 31 | * The CRC-32 constant block contains reduction constants to fold and | 31 | * The CRC-32 constant block contains reduction constants to fold and |
| @@ -58,19 +58,20 @@ · 26 unmodified lines | |||
| 58 | * P'(x) = 0xEDB88320 | 58 | * P'(x) = 0xEDB88320 |
| 59 | */ | 59 | */ |
| 60 | 60 | ||
| 61 | .Lconstants_CRC_32_BE: | 61 | SYM_DATA_START_LOCAL(constants_CRC_32_BE) |
| 62 | .quad 0x08833794c, 0x0e6228b11 # R1, R2 | 62 | .quad 0x08833794c, 0x0e6228b11 # R1, R2 |
| 63 | .quad 0x0c5b9cd4c, 0x0e8a45605 # R3, R4 | 63 | .quad 0x0c5b9cd4c, 0x0e8a45605 # R3, R4 |
| 64 | .quad 0x0f200aa66, 1 << 32 # R5, x32 | 64 | .quad 0x0f200aa66, 1 << 32 # R5, x32 |
| 65 | .quad 0x0490d678d, 1 # R6, 1 | 65 | .quad 0x0490d678d, 1 # R6, 1 |
| 66 | .quad 0x104d101df, 0 # u | 66 | .quad 0x104d101df, 0 # u |
| 67 | .quad 0x104C11DB7, 0 # P(x) | 67 | .quad 0x104C11DB7, 0 # P(x) |
| 68 | SYM_DATA_END(constants_CRC_32_BE) | ||
| 68 | 69 | ||
| 69 | .previous | 70 | .previous |
| 70 | 71 | ||
| 71 | GEN_BR_THUNK %r14 | 72 | GEN_BR_THUNK %r14 |
| 72 | 73 | ||
| 73 | .text | 74 | .text |
| 74 | /* | 75 | /* |
| 75 | * The CRC-32 function(s) use these calling conventions: | 76 | * The CRC-32 function(s) use these calling conventions: |
| 76 | * | 77 | * |
| @@ -90,9 +91,9 @@ · 13 unmodified lines | |||
| 90 | * | 91 | * |
| 91 | * V9..V14: CRC-32 constants. | 92 | * V9..V14: CRC-32 constants. |
| 92 | */ | 93 | */ |
| 93 | ENTRY(crc32_be_vgfm_16) | 94 | SYM_FUNC_START(crc32_be_vgfm_16) |
| 94 | /* Load CRC-32 constants */ | 95 | /* Load CRC-32 constants */ |
| 95 | larl %r5,.Lconstants_CRC_32_BE | 96 | larl %r5,constants_CRC_32_BE |
| 96 | VLM CONST_R1R2,CONST_CRC_POLY,0,%r5 | 97 | VLM CONST_R1R2,CONST_CRC_POLY,0,%r5 |
| 97 | 98 | ||
| 98 | /* Load the initial CRC value into the leftmost word of V0. */ | 99 | /* Load the initial CRC value into the leftmost word of V0. */ |
| @@ -207,6 +208,6 @@ ENTRY(crc32_be_vgfm_16) · 108 unmodified lines | |||
| 207 | .Ldone: | 208 | .Ldone: |
| 208 | VLGVF %r2,%v2,3 | 209 | VLGVF %r2,%v2,3 |
| 209 | BR_EX %r14 | 210 | BR_EX %r14 |
| 210 | ENDPROC(crc32_be_vgfm_16) | 211 | SYM_FUNC_END(crc32_be_vgfm_16) |
| 211 | 212 | ||
| 212 | .previous | 213 | .previous |
| @@ -25,8 +25,8 @@ · 24 unmodified lines | |||
| 25 | #define CONST_RU_POLY %v13 | 25 | #define CONST_RU_POLY %v13 |
| 26 | #define CONST_CRC_POLY %v14 | 26 | #define CONST_CRC_POLY %v14 |
| 27 | 27 | ||
| 28 | .data | 28 | .data |
| 29 | .align 8 | 29 | .balign 8 |
| 30 | 30 | ||
| 31 | /* | 31 | /* |
| 32 | * The CRC-32 constant block contains reduction constants to fold and | 32 | * The CRC-32 constant block contains reduction constants to fold and |
| @@ -59,27 +59,29 @@ · 26 unmodified lines | |||
| 59 | * P'(x) = 0x82F63B78 | 59 | * P'(x) = 0x82F63B78 |
| 60 | */ | 60 | */ |
| 61 | 61 | ||
| 62 | .Lconstants_CRC_32_LE: | 62 | SYM_DATA_START_LOCAL(constants_CRC_32_LE) |
| 63 | .octa 0x0F0E0D0C0B0A09080706050403020100 # BE->LE mask | 63 | .octa 0x0F0E0D0C0B0A09080706050403020100 # BE->LE mask |
| 64 | .quad 0x1c6e41596, 0x154442bd4 # R2, R1 | 64 | .quad 0x1c6e41596, 0x154442bd4 # R2, R1 |
| 65 | .quad 0x0ccaa009e, 0x1751997d0 # R4, R3 | 65 | .quad 0x0ccaa009e, 0x1751997d0 # R4, R3 |
| 66 | .octa 0x163cd6124 # R5 | 66 | .octa 0x163cd6124 # R5 |
| 67 | .octa 0x1F7011641 # u' | 67 | .octa 0x1F7011641 # u' |
| 68 | .octa 0x1DB710641 # P'(x) << 1 | 68 | .octa 0x1DB710641 # P'(x) << 1 |
| 69 | SYM_DATA_END(constants_CRC_32_LE) | ||
| 69 | 70 | ||
| 70 | .Lconstants_CRC_32C_LE: | 71 | SYM_DATA_START_LOCAL(constants_CRC_32C_LE) |
| 71 | .octa 0x0F0E0D0C0B0A09080706050403020100 # BE->LE mask | 72 | .octa 0x0F0E0D0C0B0A09080706050403020100 # BE->LE mask |
| 72 | .quad 0x09e4addf8, 0x740eef02 # R2, R1 | 73 | .quad 0x09e4addf8, 0x740eef02 # R2, R1 |
| 73 | .quad 0x14cd00bd6, 0xf20c0dfe # R4, R3 | 74 | .quad 0x14cd00bd6, 0xf20c0dfe # R4, R3 |
| 74 | .octa 0x0dd45aab8 # R5 | 75 | .octa 0x0dd45aab8 # R5 |
| 75 | .octa 0x0dea713f1 # u' | 76 | .octa 0x0dea713f1 # u' |
| 76 | .octa 0x105ec76f0 # P'(x) << 1 | 77 | .octa 0x105ec76f0 # P'(x) << 1 |
| 78 | SYM_DATA_END(constants_CRC_32C_LE) | ||
| 77 | 79 | ||
| 78 | .previous | 80 | .previous |
| 79 | 81 | ||
| 80 | GEN_BR_THUNK %r14 | 82 | GEN_BR_THUNK %r14 |
| 81 | 83 | ||
| 82 | .text | 84 | .text |
| 83 | 85 | ||
| 84 | /* | 86 | /* |
| 85 | * The CRC-32 functions use these calling conventions: | 87 | * The CRC-32 functions use these calling conventions: |
| @@ -102,17 +104,17 @@ · 16 unmodified lines | |||
| 102 | * V10..V14: CRC-32 constants. | 104 | * V10..V14: CRC-32 constants. |
| 103 | */ | 105 | */ |
| 104 | 106 | ||
| 105 | ENTRY(crc32_le_vgfm_16) | 107 | SYM_FUNC_START(crc32_le_vgfm_16) |
| 106 | larl %r5,.Lconstants_CRC_32_LE | 108 | larl %r5,constants_CRC_32_LE |
| 107 | j crc32_le_vgfm_generic | 109 | j crc32_le_vgfm_generic |
| 108 | ENDPROC(crc32_le_vgfm_16) | 110 | SYM_FUNC_END(crc32_le_vgfm_16) |
| 109 | 111 | ||
| 110 | ENTRY(crc32c_le_vgfm_16) | 112 | SYM_FUNC_START(crc32c_le_vgfm_16) |
| 111 | larl %r5,.Lconstants_CRC_32C_LE | 113 | larl %r5,constants_CRC_32C_LE |
| 112 | j crc32_le_vgfm_generic | 114 | j crc32_le_vgfm_generic |
| 113 | ENDPROC(crc32c_le_vgfm_16) | 115 | SYM_FUNC_END(crc32c_le_vgfm_16) |
| 114 | 116 | ||
| 115 | ENTRY(crc32_le_vgfm_generic) | 117 | SYM_FUNC_START(crc32_le_vgfm_generic) |
| 116 | /* Load CRC-32 constants */ | 118 | /* Load CRC-32 constants */ |
| 117 | VLM CONST_PERM_LE2BE,CONST_CRC_POLY,0,%r5 | 119 | VLM CONST_PERM_LE2BE,CONST_CRC_POLY,0,%r5 |
| 118 | 120 | ||
| @@ -268,6 +270,6 @@ ENTRY(crc32_le_vgfm_generic) · 149 unmodified lines | |||
| 268 | .Ldone: | 270 | .Ldone: |
| 269 | VLGVF %r2,%v2,2 | 271 | VLGVF %r2,%v2,2 |
| 270 | BR_EX %r14 | 272 | BR_EX %r14 |
| 271 | ENDPROC(crc32_le_vgfm_generic) | 273 | SYM_FUNC_END(crc32_le_vgfm_generic) |
| 272 | 274 | ||
| 273 | .previous | 275 | .previous |
| @@ -43,10 +43,11 @@ struct ap_queue_status { · 42 unmodified lines | |||
| 43 | unsigned int queue_empty : 1; | 43 | unsigned int queue_empty : 1; |
| 44 | unsigned int replies_waiting : 1; | 44 | unsigned int replies_waiting : 1; |
| 45 | unsigned int queue_full : 1; | 45 | unsigned int queue_full : 1; |
| 46 | unsigned int _pad1 : 4; | 46 | unsigned int : 3; |
| 47 | unsigned int async : 1; | ||
| 47 | unsigned int irq_enabled : 1; | 48 | unsigned int irq_enabled : 1; |
| 48 | unsigned int response_code : 8; | 49 | unsigned int response_code : 8; |
| 49 | unsigned int _pad2 : 16; | 50 | unsigned int : 16; |
| 50 | }; | 51 | }; |
| 51 | 52 | ||
| 52 | /* | 53 | /* |
| @@ -86,6 +87,42 @@ static inline bool ap_instructions_available(void) · 33 unmodified lines | |||
| 86 | return reg1 != 0; | 87 | return reg1 != 0; |
| 87 | } | 88 | } |
| 88 | 89 | ||
| 90 | /* TAPQ register GR2 response struct */ | ||
| 91 | struct ap_tapq_gr2 { | ||
| 92 | union { | ||
| 93 | unsigned long value; | ||
| 94 | struct { | ||
| 95 | unsigned int fac : 32; /* facility bits */ | ||
| 96 | unsigned int apinfo : 32; /* ap type, ... */ | ||
| 97 | }; | ||
| 98 | struct { | ||
| 99 | unsigned int s : 1; /* APSC */ | ||
| 100 | unsigned int m : 1; /* AP4KM */ | ||
| 101 | unsigned int c : 1; /* AP4KC */ | ||
| 102 | unsigned int mode : 3; | ||
| 103 | unsigned int n : 1; /* APXA */ | ||
| 104 | unsigned int : 1; | ||
| 105 | unsigned int class : 8; | ||
| 106 | unsigned int bs : 2; /* SE bind/assoc */ | ||
| 107 | unsigned int : 14; | ||
| 108 | unsigned int at : 8; /* ap type */ | ||
| 109 | unsigned int nd : 8; /* nr of domains */ | ||
| 110 | unsigned int : 4; | ||
| 111 | unsigned int ml : 4; /* apxl ml */ | ||
| 112 | unsigned int : 4; | ||
| 113 | unsigned int qd : 4; /* queue depth */ | ||
| 114 | }; | ||
| 115 | }; | ||
| 116 | }; | ||
| 117 | |||
| 118 | /* | ||
| 119 | * Convenience defines to be used with the bs field from struct ap_tapq_gr2 | ||
| 120 | */ | ||
| 121 | #define AP_BS_Q_USABLE 0 | ||
| 122 | #define AP_BS_Q_USABLE_NO_SECURE_KEY 1 | ||
| 123 | #define AP_BS_Q_AVAIL_FOR_BINDING 2 | ||
| 124 | #define AP_BS_Q_UNUSABLE 3 | ||
| 125 | |||
| 89 | /** | 126 | /** |
| 90 | * ap_tapq(): Test adjunct processor queue. | 127 | * ap_tapq(): Test adjunct processor queue. |
| 91 | * @qid: The AP queue number | 128 | * @qid: The AP queue number |
| @@ -93,7 +130,7 @@ static inline bool ap_instructions_available(void) · 1 unmodified line | |||
| 93 | * | 130 | * |
| 94 | * Returns AP queue status structure. | 131 | * Returns AP queue status structure. |
| 95 | */ | 132 | */ |
| 96 | static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info) | 133 | static inline struct ap_queue_status ap_tapq(ap_qid_t qid, struct ap_tapq_gr2 *info) |
| 97 | { | 134 | { |
| 98 | union ap_queue_status_reg reg1; | 135 | union ap_queue_status_reg reg1; |
| 99 | unsigned long reg2; | 136 | unsigned long reg2; |
| @@ -108,7 +145,7 @@ static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info) · 8 unmodified lines | |||
| 108 | : [qid] "d" (qid) | 145 | : [qid] "d" (qid) |
| 109 | : "cc", "0", "1", "2"); | 146 | : "cc", "0", "1", "2"); |
| 110 | if (info) | 147 | if (info) |
| 111 | *info = reg2; | 148 | info->value = reg2; |
| 112 | return reg1.status; | 149 | return reg1.status; |
| 113 | } | 150 | } |
| 114 | 151 | ||
| @@ -116,13 +153,12 @@ static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info) · 1 unmodified line | |||
| 116 | * ap_test_queue(): Test adjunct processor queue. | 153 | * ap_test_queue(): Test adjunct processor queue. |
| 117 | * @qid: The AP queue number | 154 | * @qid: The AP queue number |
| 118 | * @tbit: Test facilities bit | 155 | * @tbit: Test facilities bit |
| 119 | * @info: Pointer to queue descriptor | 156 | * @info: Ptr to tapq gr2 struct |
| 120 | * | 157 | * |
| 121 | * Returns AP queue status structure. | 158 | * Returns AP queue status structure. |
| 122 | */ | 159 | */ |
| 123 | static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, | 160 | static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, int tbit, |
| 124 | int tbit, | 161 | struct ap_tapq_gr2 *info) |
| 125 | unsigned long *info) | ||
| 126 | { | 162 | { |
| 127 | if (tbit) | 163 | if (tbit) |
| 128 | qid |= 1UL << 23; /* set T bit*/ | 164 | qid |= 1UL << 23; /* set T bit*/ |
| @@ -132,14 +168,18 @@ static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, · 3 unmodified lines | |||
| 132 | /** | 168 | /** |
| 133 | * ap_pqap_rapq(): Reset adjunct processor queue. | 169 | * ap_pqap_rapq(): Reset adjunct processor queue. |
| 134 | * @qid: The AP queue number | 170 | * @qid: The AP queue number |
| 171 | * @fbit: if != 0 set F bit | ||
| 135 | * | 172 | * |
| 136 | * Returns AP queue status structure. | 173 | * Returns AP queue status structure. |
| 137 | */ | 174 | */ |
| 138 | static inline struct ap_queue_status ap_rapq(ap_qid_t qid) | 175 | static inline struct ap_queue_status ap_rapq(ap_qid_t qid, int fbit) |
| 139 | { | 176 | { |
| 140 | unsigned long reg0 = qid | (1UL << 24); /* fc 1UL is RAPQ */ | 177 | unsigned long reg0 = qid | (1UL << 24); /* fc 1UL is RAPQ */ |
| 141 | union ap_queue_status_reg reg1; | 178 | union ap_queue_status_reg reg1; |
| 142 | 179 | ||
| 180 | if (fbit) | ||
| 181 | reg0 |= 1UL << 22; | ||
| 182 | |||
| 143 | asm volatile( | 183 | asm volatile( |
| 144 | " lgr 0,%[reg0]\n" /* qid arg into gr0 */ | 184 | " lgr 0,%[reg0]\n" /* qid arg into gr0 */ |
| 145 | " .insn rre,0xb2af0000,0,0\n" /* PQAP(RAPQ) */ | 185 | " .insn rre,0xb2af0000,0,0\n" /* PQAP(RAPQ) */ |
| @@ -153,14 +193,18 @@ static inline struct ap_queue_status ap_rapq(ap_qid_t qid) · 7 unmodified lines | |||
| 153 | /** | 193 | /** |
| 154 | * ap_pqap_zapq(): Reset and zeroize adjunct processor queue. | 194 | * ap_pqap_zapq(): Reset and zeroize adjunct processor queue. |
| 155 | * @qid: The AP queue number | 195 | * @qid: The AP queue number |
| 196 | * @fbit: if != 0 set F bit | ||
| 156 | * | 197 | * |
| 157 | * Returns AP queue status structure. | 198 | * Returns AP queue status structure. |
| 158 | */ | 199 | */ |
| 159 | static inline struct ap_queue_status ap_zapq(ap_qid_t qid) | 200 | static inline struct ap_queue_status ap_zapq(ap_qid_t qid, int fbit) |
| 160 | { | 201 | { |
| 161 | unsigned long reg0 = qid | (2UL << 24); /* fc 2UL is ZAPQ */ | 202 | unsigned long reg0 = qid | (2UL << 24); /* fc 2UL is ZAPQ */ |
| 162 | union ap_queue_status_reg reg1; | 203 | union ap_queue_status_reg reg1; |
| 163 | 204 | ||
| 205 | if (fbit) | ||
| 206 | reg0 |= 1UL << 22; | ||
| 207 | |||
| 164 | asm volatile( | 208 | asm volatile( |
| 165 | " lgr 0,%[reg0]\n" /* qid arg into gr0 */ | 209 | " lgr 0,%[reg0]\n" /* qid arg into gr0 */ |
| 166 | " .insn rre,0xb2af0000,0,0\n" /* PQAP(ZAPQ) */ | 210 | " .insn rre,0xb2af0000,0,0\n" /* PQAP(ZAPQ) */ |
| @@ -180,15 +224,16 @@ struct ap_config_info { · 13 unmodified lines | |||
| 180 | unsigned int apxa : 1; /* N bit */ | 224 | unsigned int apxa : 1; /* N bit */ |
| 181 | unsigned int qact : 1; /* C bit */ | 225 | unsigned int qact : 1; /* C bit */ |
| 182 | unsigned int rc8a : 1; /* R bit */ | 226 | unsigned int rc8a : 1; /* R bit */ |
| 183 | unsigned char _reserved1 : 4; | 227 | unsigned int : 4; |
| 184 | unsigned char _reserved2[3]; | 228 | unsigned int apsb : 1; /* B bit */ |
| 185 | unsigned char Na; /* max # of APs - 1 */ | 229 | unsigned int : 23; |
| 186 | unsigned char Nd; /* max # of Domains - 1 */ | 230 | unsigned char na; /* max # of APs - 1 */ |
| 187 | unsigned char _reserved3[10]; | 231 | unsigned char nd; /* max # of Domains - 1 */ |
| 232 | unsigned char _reserved0[10]; | ||
| 188 | unsigned int apm[8]; /* AP ID mask */ | 233 | unsigned int apm[8]; /* AP ID mask */ |
| 189 | unsigned int aqm[8]; /* AP (usage) queue mask */ | 234 | unsigned int aqm[8]; /* AP (usage) queue mask */ |
| 190 | unsigned int adm[8]; /* AP (control) domain mask */ | 235 | unsigned int adm[8]; /* AP (control) domain mask */ |
| 191 | unsigned char _reserved4[16]; | 236 | unsigned char _reserved1[16]; |
| 192 | } __aligned(8); | 237 | } __aligned(8); |
| 193 | 238 | ||
| 194 | /** | 239 | /** |
| @@ -318,6 +363,59 @@ static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit, · 123 unmodified lines | |||
| 318 | return reg1.status; | 363 | return reg1.status; |
| 319 | } | 364 | } |
| 320 | 365 | ||
| 366 | /* | ||
| 367 | * ap_bapq(): SE bind AP queue. | ||
| 368 | * @qid: The AP queue number | ||
| 369 | * | ||
| 370 | * Returns AP queue status structure. | ||
| 371 | * | ||
| 372 | * Invoking this function in a non-SE environment | ||
| 373 | * may case a specification exception. | ||
| 374 | */ | ||
| 375 | static inline struct ap_queue_status ap_bapq(ap_qid_t qid) | ||
| 376 | { | ||
| 377 | unsigned long reg0 = qid | (7UL << 24); /* fc 7 is BAPQ */ | ||
| 378 | union ap_queue_status_reg reg1; | ||
| 379 | |||
| 380 | asm volatile( | ||
| 381 | " lgr 0,%[reg0]\n" /* qid arg into gr0 */ | ||
| 382 | " .insn rre,0xb2af0000,0,0\n" /* PQAP(BAPQ) */ | ||
| 383 | " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ | ||
| 384 | : [reg1] "=&d" (reg1.value) | ||
| 385 | : [reg0] "d" (reg0) | ||
| 386 | : "cc", "0", "1"); | ||
| 387 | |||
| 388 | return reg1.status; | ||
| 389 | } | ||
| 390 | |||
| 391 | /* | ||
| 392 | * ap_aapq(): SE associate AP queue. | ||
| 393 | * @qid: The AP queue number | ||
| 394 | * @sec_idx: The secret index | ||
| 395 | * | ||
| 396 | * Returns AP queue status structure. | ||
| 397 | * | ||
| 398 | * Invoking this function in a non-SE environment | ||
| 399 | * may case a specification exception. | ||
| 400 | */ | ||
| 401 | static inline struct ap_queue_status ap_aapq(ap_qid_t qid, unsigned int sec_idx) | ||
| 402 | { | ||
| 403 | unsigned long reg0 = qid | (8UL << 24); /* fc 8 is AAPQ */ | ||
| 404 | unsigned long reg2 = sec_idx; | ||
| 405 | union ap_queue_status_reg reg1; | ||
| 406 | |||
| 407 | asm volatile( | ||
| 408 | " lgr 0,%[reg0]\n" /* qid arg into gr0 */ | ||
| 409 | " lgr 2,%[reg2]\n" /* secret index into gr2 */ | ||
| 410 | " .insn rre,0xb2af0000,0,0\n" /* PQAP(AAPQ) */ | ||
| 411 | " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ | ||
| 412 | : [reg1] "=&d" (reg1.value) | ||
| 413 | : [reg0] "d" (reg0), [reg2] "d" (reg2) | ||
| 414 | : "cc", "0", "1", "2"); | ||
| 415 | |||
| 416 | return reg1.status; | ||
| 417 | } | ||
| 418 | |||
| 321 | /** | 419 | /** |
| 322 | * ap_nqap(): Send message to adjunct processor queue. | 420 | * ap_nqap(): Send message to adjunct processor queue. |
| 323 | * @qid: The AP queue number | 421 | * @qid: The AP queue number |
| @@ -359,10 +457,11 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, · 35 unmodified lines | |||
| 359 | * ap_dqap(): Receive message from adjunct processor queue. | 457 | * ap_dqap(): Receive message from adjunct processor queue. |
| 360 | * @qid: The AP queue number | 458 | * @qid: The AP queue number |
| 361 | * @psmid: Pointer to program supplied message identifier | 459 | * @psmid: Pointer to program supplied message identifier |
| 362 | * @msg: The message text | 460 | * @msg: Pointer to message buffer |
| 363 | * @length: The message length | 461 | * @msglen: Message buffer size |
| 364 | * @reslength: Resitual length on return | 462 | * @length: Pointer to length of actually written bytes |
| 365 | * @resgr0: input: gr0 value (only used if != 0), output: resitual gr0 content | 463 | * @reslength: Residual length on return |
| 464 | * @resgr0: input: gr0 value (only used if != 0), output: residual gr0 content | ||
| 366 | * | 465 | * |
| 367 | * Returns AP queue status structure. | 466 | * Returns AP queue status structure. |
| 368 | * Condition code 1 on DQAP means the receive has taken place | 467 | * Condition code 1 on DQAP means the receive has taken place |
| @@ -386,8 +485,9 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, · 17 unmodified lines | |||
| 386 | * *resgr0 is to be used instead of qid to further process this entry. | 485 | * *resgr0 is to be used instead of qid to further process this entry. |
| 387 | */ | 486 | */ |
| 388 | static inline struct ap_queue_status ap_dqap(ap_qid_t qid, | 487 | static inline struct ap_queue_status ap_dqap(ap_qid_t qid, |
| 389 | unsigned long long *psmid, | 488 | unsigned long *psmid, |
| 390 | void *msg, size_t length, | 489 | void *msg, size_t msglen, |
| 490 | size_t *length, | ||
| 391 | size_t *reslength, | 491 | size_t *reslength, |
| 392 | unsigned long *resgr0) | 492 | unsigned long *resgr0) |
| 393 | { | 493 | { |
| @@ -399,7 +499,7 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, · 5 unmodified lines | |||
| 399 | rp1.even = 0UL; | 499 | rp1.even = 0UL; |
| 400 | rp1.odd = 0UL; | 500 | rp1.odd = 0UL; |
| 401 | rp2.even = (unsigned long)msg; | 501 | rp2.even = (unsigned long)msg; |
| 402 | rp2.odd = (unsigned long)length; | 502 | rp2.odd = (unsigned long)msglen; |
| 403 | 503 | ||
| 404 | asm volatile( | 504 | asm volatile( |
| 405 | " lgr 0,%[reg0]\n" /* qid param into gr0 */ | 505 | " lgr 0,%[reg0]\n" /* qid param into gr0 */ |
| @@ -429,11 +529,15 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, · 23 unmodified lines | |||
| 429 | if (resgr0) | 529 | if (resgr0) |
| 430 | *resgr0 = reg0; | 530 | *resgr0 = reg0; |
| 431 | } else { | 531 | } else { |
| 432 | *psmid = (((unsigned long long)rp1.even) << 32) + rp1.odd; | 532 | *psmid = (rp1.even << 32) + rp1.odd; |
| 433 | if (resgr0) | 533 | if (resgr0) |
| 434 | *resgr0 = 0; | 534 | *resgr0 = 0; |
| 435 | } | 535 | } |
| 436 | 536 | ||
| 537 | /* update *length with the nr of bytes stored into the msg buffer */ | ||
| 538 | if (length) | ||
| 539 | *length = msglen - rp2.odd; | ||
| 540 | |||
| 437 | return reg1.status; | 541 | return reg1.status; |
| 438 | } | 542 | } |
| 439 | 543 | ||
| @@ -12,13 +12,7 @@ · 11 unmodified lines | |||
| 12 | #ifndef _S390_CHECKSUM_H | 12 | #ifndef _S390_CHECKSUM_H |
| 13 | #define _S390_CHECKSUM_H | 13 | #define _S390_CHECKSUM_H |
| 14 | 14 | ||
| 15 | #ifdef CONFIG_GENERIC_CSUM | 15 | #include <linux/kasan-checks.h> |
| 16 | |||
| 17 | #include <asm-generic/checksum.h> | ||
| 18 | |||
| 19 | #else /* CONFIG_GENERIC_CSUM */ | ||
| 20 | |||
| 21 | #include <linux/uaccess.h> | ||
| 22 | #include <linux/in6.h> | 16 | #include <linux/in6.h> |
| 23 | 17 | ||
| 24 | /* | 18 | /* |
| @@ -40,6 +34,7 @@ static inline __wsum csum_partial(const void *buff, int len, __wsum sum) · 15 unmodified lines | |||
| 40 | .odd = (unsigned long) len, | 34 | .odd = (unsigned long) len, |
| 41 | }; | 35 | }; |
| 42 | 36 | ||
| 37 | kasan_check_read(buff, len); | ||
| 43 | asm volatile( | 38 | asm volatile( |
| 44 | "0: cksm %[sum],%[rp]\n" | 39 | "0: cksm %[sum],%[rp]\n" |
| 45 | " jo 0b\n" | 40 | " jo 0b\n" |
| @@ -135,5 +130,4 @@ static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr, · 89 unmodified lines | |||
| 135 | return csum_fold((__force __wsum)(sum >> 32)); | 130 | return csum_fold((__force __wsum)(sum >> 32)); |
| 136 | } | 131 | } |
| 137 | 132 | ||
| 138 | #endif /* CONFIG_GENERIC_CSUM */ | ||
| 139 | #endif /* _S390_CHECKSUM_H */ | 133 | #endif /* _S390_CHECKSUM_H */ |
| @@ -90,7 +90,7 @@ struct diag8c { · 89 unmodified lines | |||
| 90 | u8 num_partitions; | 90 | u8 num_partitions; |
| 91 | u16 width; | 91 | u16 width; |
| 92 | u16 height; | 92 | u16 height; |
| 93 | u8 data[0]; | 93 | u8 data[]; |
| 94 | } __packed __aligned(4); | 94 | } __packed __aligned(4); |
| 95 | 95 | ||
| 96 | extern int diag8c(struct diag8c *out, struct ccw_dev_id *devno); | 96 | extern int diag8c(struct diag8c *out, struct ccw_dev_id *devno); |
| @@ -60,9 +60,4 @@ static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs, · 59 unmodified lines | |||
| 60 | 60 | ||
| 61 | #define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare | 61 | #define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare |
| 62 | 62 | ||
| 63 | static inline bool on_thread_stack(void) | ||
| 64 | { | ||
| 65 | return !(((unsigned long)(current->stack) ^ current_stack_pointer) & ~(THREAD_SIZE - 1)); | ||
| 66 | } | ||
| 67 | |||
| 68 | #endif | 63 | #endif |
| @@ -286,7 +286,7 @@ struct tccb_tcat { · 285 unmodified lines | |||
| 286 | */ | 286 | */ |
| 287 | struct tccb { | 287 | struct tccb { |
| 288 | struct tccb_tcah tcah; | 288 | struct tccb_tcah tcah; |
| 289 | u8 tca[0]; | 289 | u8 tca[]; |
| 290 | } __attribute__ ((packed, aligned(8))); | 290 | } __attribute__ ((packed, aligned(8))); |
| 291 | 291 | ||
| 292 | struct tcw *tcw_get_intrg(struct tcw *tcw); | 292 | struct tcw *tcw_get_intrg(struct tcw *tcw); |
| @@ -2,7 +2,7 @@ · 1 unmodified line | |||
| 2 | #ifndef __ASM_KASAN_H | 2 | #ifndef __ASM_KASAN_H |
| 3 | #define __ASM_KASAN_H | 3 | #define __ASM_KASAN_H |
| 4 | 4 | ||
| 5 | #include <asm/pgtable.h> | 5 | #include <linux/const.h> |
| 6 | 6 | ||
| 7 | #ifdef CONFIG_KASAN | 7 | #ifdef CONFIG_KASAN |
| 8 | 8 | ||
| @@ -13,35 +13,6 @@ · 4 unmodified lines | |||
| 13 | #define KASAN_SHADOW_START KASAN_SHADOW_OFFSET | 13 | #define KASAN_SHADOW_START KASAN_SHADOW_OFFSET |
| 14 | #define KASAN_SHADOW_END (KASAN_SHADOW_START + KASAN_SHADOW_SIZE) | 14 | #define KASAN_SHADOW_END (KASAN_SHADOW_START + KASAN_SHADOW_SIZE) |
| 15 | 15 | ||
| 16 | extern void kasan_early_init(void); | ||
| 17 | |||
| 18 | /* | ||
| 19 | * Estimate kasan memory requirements, which it will reserve | ||
| 20 | * at the very end of available physical memory. To estimate | ||
| 21 | * that, we take into account that kasan would require | ||
| 22 | * 1/8 of available physical memory (for shadow memory) + | ||
| 23 | * creating page tables for the shadow memory region. | ||
| 24 | * To keep page tables estimates simple take the double of | ||
| 25 | * combined ptes size. | ||
| 26 | * | ||
| 27 | * physmem parameter has to be already adjusted if not entire physical memory | ||
| 28 | * would be used (e.g. due to effect of "mem=" option). | ||
| 29 | */ | ||
| 30 | static inline unsigned long kasan_estimate_memory_needs(unsigned long physmem) | ||
| 31 | { | ||
| 32 | unsigned long kasan_needs; | ||
| 33 | unsigned long pages; | ||
| 34 | /* for shadow memory */ | ||
| 35 | kasan_needs = round_up(physmem / 8, PAGE_SIZE); | ||
| 36 | /* for paging structures */ | ||
| 37 | pages = DIV_ROUND_UP(kasan_needs, PAGE_SIZE); | ||
| 38 | kasan_needs += DIV_ROUND_UP(pages, _PAGE_ENTRIES) * _PAGE_TABLE_SIZE * 2; | ||
| 39 | |||
| 40 | return kasan_needs; | ||
| 41 | } | ||
| 42 | #else | ||
| 43 | static inline void kasan_early_init(void) { } | ||
| 44 | static inline unsigned long kasan_estimate_memory_needs(unsigned long physmem) { return 0; } | ||
| 45 | #endif | 16 | #endif |
| 46 | 17 | ||
| 47 | #endif | 18 | #endif |
| @@ -4,7 +4,7 @@ · 3 unmodified lines | |||
| 4 | 4 | ||
| 5 | #include <linux/stringify.h> | 5 | #include <linux/stringify.h> |
| 6 | 6 | ||
| 7 | #define __ALIGN .align 16, 0x07 | 7 | #define __ALIGN .balign CONFIG_FUNCTION_ALIGNMENT, 0x07 |
| 8 | #define __ALIGN_STR __stringify(__ALIGN) | 8 | #define __ALIGN_STR __stringify(__ALIGN) |
| 9 | 9 | ||
| 10 | #endif | 10 | #endif |
| @@ -1,117 +0,0 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | #ifndef _ASM_S390_MEM_DETECT_H | ||
| 3 | #define _ASM_S390_MEM_DETECT_H | ||
| 4 | |||
| 5 | #include <linux/types.h> | ||
| 6 | |||
| 7 | enum mem_info_source { | ||
| 8 | MEM_DETECT_NONE = 0, | ||
| 9 | MEM_DETECT_SCLP_STOR_INFO, | ||
| 10 | MEM_DETECT_DIAG260, | ||
| 11 | MEM_DETECT_SCLP_READ_INFO, | ||
| 12 | MEM_DETECT_BIN_SEARCH | ||
| 13 | }; | ||
| 14 | |||
| 15 | struct mem_detect_block { | ||
| 16 | u64 start; | ||
| 17 | u64 end; | ||
| 18 | }; | ||
| 19 | |||
| 20 | /* | ||
| 21 | * Storage element id is defined as 1 byte (up to 256 storage elements). | ||
| 22 | * In practise only storage element id 0 and 1 are used). | ||
| 23 | * According to architecture one storage element could have as much as | ||
| 24 | * 1020 subincrements. 255 mem_detect_blocks are embedded in mem_detect_info. | ||
| 25 | * If more mem_detect_blocks are required, a block of memory from already | ||
| 26 | * known mem_detect_block is taken (entries_extended points to it). | ||
| 27 | */ | ||
| 28 | #define MEM_INLINED_ENTRIES 255 /* (PAGE_SIZE - 16) / 16 */ | ||
| 29 | |||
| 30 | struct mem_detect_info { | ||
| 31 | u32 count; | ||
| 32 | u8 info_source; | ||
| 33 | unsigned long usable; | ||
| 34 | struct mem_detect_block entries[MEM_INLINED_ENTRIES]; | ||
| 35 | struct mem_detect_block *entries_extended; | ||
| 36 | }; | ||
| 37 | extern struct mem_detect_info mem_detect; | ||
| 38 | |||
| 39 | void add_mem_detect_block(u64 start, u64 end); | ||
| 40 | |||
| 41 | static inline int __get_mem_detect_block(u32 n, unsigned long *start, | ||
| 42 | unsigned long *end, bool respect_usable_limit) | ||
| 43 | { | ||
| 44 | if (n >= mem_detect.count) { | ||
| 45 | *start = 0; | ||
| 46 | *end = 0; | ||
| 47 | return -1; | ||
| 48 | } | ||
| 49 | |||
| 50 | if (n < MEM_INLINED_ENTRIES) { | ||
| 51 | *start = (unsigned long)mem_detect.entries[n].start; | ||
| 52 | *end = (unsigned long)mem_detect.entries[n].end; | ||
| 53 | } else { | ||
| 54 | *start = (unsigned long)mem_detect.entries_extended[n - MEM_INLINED_ENTRIES].start; | ||
| 55 | *end = (unsigned long)mem_detect.entries_extended[n - MEM_INLINED_ENTRIES].end; | ||
| 56 | } | ||
| 57 | |||
| 58 | if (respect_usable_limit && mem_detect.usable) { | ||
| 59 | if (*start >= mem_detect.usable) | ||
| 60 | return -1; | ||
| 61 | if (*end > mem_detect.usable) | ||
| 62 | *end = mem_detect.usable; | ||
| 63 | } | ||
| 64 | return 0; | ||
| 65 | } | ||
| 66 | |||
| 67 | /** | ||
| 68 | * for_each_mem_detect_usable_block - early online memory range iterator | ||
| 69 | * @i: an integer used as loop variable | ||
| 70 | * @p_start: ptr to unsigned long for start address of the range | ||
| 71 | * @p_end: ptr to unsigned long for end address of the range | ||
| 72 | * | ||
| 73 | * Walks over detected online memory ranges below usable limit. | ||
| 74 | */ | ||
| 75 | #define for_each_mem_detect_usable_block(i, p_start, p_end) \ | ||
| 76 | for (i = 0; !__get_mem_detect_block(i, p_start, p_end, true); i++) | ||
| 77 | |||
| 78 | /* Walks over all detected online memory ranges disregarding usable limit. */ | ||
| 79 | #define for_each_mem_detect_block(i, p_start, p_end) \ | ||
| 80 | for (i = 0; !__get_mem_detect_block(i, p_start, p_end, false); i++) | ||
| 81 | |||
| 82 | static inline unsigned long get_mem_detect_usable_total(void) | ||
| 83 | { | ||
| 84 | unsigned long start, end, total = 0; | ||
| 85 | int i; | ||
| 86 | |||
| 87 | for_each_mem_detect_usable_block(i, &start, &end) | ||
| 88 | total += end - start; | ||
| 89 | |||
| 90 | return total; | ||
| 91 | } | ||
| 92 | |||
| 93 | static inline void get_mem_detect_reserved(unsigned long *start, | ||
| 94 | unsigned long *size) | ||
| 95 | { | ||
| 96 | *start = (unsigned long)mem_detect.entries_extended; | ||
| 97 | if (mem_detect.count > MEM_INLINED_ENTRIES) | ||
| 98 | *size = (mem_detect.count - MEM_INLINED_ENTRIES) * sizeof(struct mem_detect_block); | ||
| 99 | else | ||
| 100 | *size = 0; | ||
| 101 | } | ||
| 102 | |||
| 103 | static inline unsigned long get_mem_detect_end(void) | ||
| 104 | { | ||
| 105 | unsigned long start; | ||
| 106 | unsigned long end; | ||
| 107 | |||
| 108 | if (mem_detect.usable) | ||
| 109 | return mem_detect.usable; | ||
| 110 | if (mem_detect.count) { | ||
| 111 | __get_mem_detect_block(mem_detect.count - 1, &start, &end, false); | ||
| 112 | return end; | ||
| 113 | } | ||
| 114 | return 0; | ||
| 115 | } | ||
| 116 | |||
| 117 | #endif | ||
| @@ -2,6 +2,7 @@ · 1 unmodified line | |||
| 2 | #ifndef _ASM_S390_NOSPEC_ASM_H | 2 | #ifndef _ASM_S390_NOSPEC_ASM_H |
| 3 | #define _ASM_S390_NOSPEC_ASM_H | 3 | #define _ASM_S390_NOSPEC_ASM_H |
| 4 | 4 | ||
| 5 | #include <linux/linkage.h> | ||
| 5 | #include <asm/dwarf.h> | 6 | #include <asm/dwarf.h> |
| 6 | 7 | ||
| 7 | #ifdef __ASSEMBLY__ | 8 | #ifdef __ASSEMBLY__ |
| @@ -16,7 +17,7 @@ · 8 unmodified lines | |||
| 16 | .macro __THUNK_PROLOG_NAME name | 17 | .macro __THUNK_PROLOG_NAME name |
| 17 | #ifdef CONFIG_EXPOLINE_EXTERN | 18 | #ifdef CONFIG_EXPOLINE_EXTERN |
| 18 | .pushsection .text,"ax",@progbits | 19 | .pushsection .text,"ax",@progbits |
| 19 | .align 16,0x07 | 20 | __ALIGN |
| 20 | #else | 21 | #else |
| 21 | .pushsection .text.\name,"axG",@progbits,\name,comdat | 22 | .pushsection .text.\name,"axG",@progbits,\name,comdat |
| 22 | #endif | 23 | #endif |
| @@ -60,7 +60,6 @@ struct perf_sf_sde_regs { · 59 unmodified lines | |||
| 60 | #define PERF_CPUM_SF_DIAG_MODE 0x0002 /* Diagnostic-sampling flag */ | 60 | #define PERF_CPUM_SF_DIAG_MODE 0x0002 /* Diagnostic-sampling flag */ |
| 61 | #define PERF_CPUM_SF_MODE_MASK (PERF_CPUM_SF_BASIC_MODE| \ | 61 | #define PERF_CPUM_SF_MODE_MASK (PERF_CPUM_SF_BASIC_MODE| \ |
| 62 | PERF_CPUM_SF_DIAG_MODE) | 62 | PERF_CPUM_SF_DIAG_MODE) |
| 63 | #define PERF_CPUM_SF_FULL_BLOCKS 0x0004 /* Process full SDBs only */ | ||
| 64 | #define PERF_CPUM_SF_FREQ_MODE 0x0008 /* Sampling with frequency */ | 63 | #define PERF_CPUM_SF_FREQ_MODE 0x0008 /* Sampling with frequency */ |
| 65 | 64 | ||
| 66 | #define REG_NONE 0 | 65 | #define REG_NONE 0 |
| @@ -71,7 +70,6 @@ struct perf_sf_sde_regs { · 4 unmodified lines | |||
| 71 | #define SAMPL_RATE(hwc) ((hwc)->event_base) | 70 | #define SAMPL_RATE(hwc) ((hwc)->event_base) |
| 72 | #define SAMPL_FLAGS(hwc) ((hwc)->config_base) | 71 | #define SAMPL_FLAGS(hwc) ((hwc)->config_base) |
| 73 | #define SAMPL_DIAG_MODE(hwc) (SAMPL_FLAGS(hwc) & PERF_CPUM_SF_DIAG_MODE) | 72 | #define SAMPL_DIAG_MODE(hwc) (SAMPL_FLAGS(hwc) & PERF_CPUM_SF_DIAG_MODE) |
| 74 | #define SDB_FULL_BLOCKS(hwc) (SAMPL_FLAGS(hwc) & PERF_CPUM_SF_FULL_BLOCKS) | ||
| 75 | #define SAMPLE_FREQ_MODE(hwc) (SAMPL_FLAGS(hwc) & PERF_CPUM_SF_FREQ_MODE) | 73 | #define SAMPLE_FREQ_MODE(hwc) (SAMPL_FLAGS(hwc) & PERF_CPUM_SF_FREQ_MODE) |
| 76 | 74 | ||
| 77 | #define perf_arch_fetch_caller_regs(regs, __ip) do { \ | 75 | #define perf_arch_fetch_caller_regs(regs, __ip) do { \ |
| @@ -34,7 +34,7 @@ enum { · 33 unmodified lines | |||
| 34 | PG_DIRECT_MAP_MAX | 34 | PG_DIRECT_MAP_MAX |
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | extern atomic_long_t direct_pages_count[PG_DIRECT_MAP_MAX]; | 37 | extern atomic_long_t __bootdata_preserved(direct_pages_count[PG_DIRECT_MAP_MAX]); |
| 38 | 38 | ||
| 39 | static inline void update_page_count(int level, long count) | 39 | static inline void update_page_count(int level, long count) |
| 40 | { | 40 | { |
| @@ -0,0 +1,171 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | #ifndef _ASM_S390_MEM_DETECT_H | ||
| 3 | #define _ASM_S390_MEM_DETECT_H | ||
| 4 | |||
| 5 | #include <linux/types.h> | ||
| 6 | |||
| 7 | enum physmem_info_source { | ||
| 8 | MEM_DETECT_NONE = 0, | ||
| 9 | MEM_DETECT_SCLP_STOR_INFO, | ||
| 10 | MEM_DETECT_DIAG260, | ||
| 11 | MEM_DETECT_SCLP_READ_INFO, | ||
| 12 | MEM_DETECT_BIN_SEARCH | ||
| 13 | }; | ||
| 14 | |||
| 15 | struct physmem_range { | ||
| 16 | u64 start; | ||
| 17 | u64 end; | ||
| 18 | }; | ||
| 19 | |||
| 20 | enum reserved_range_type { | ||
| 21 | RR_DECOMPRESSOR, | ||
| 22 | RR_INITRD, | ||
| 23 | RR_VMLINUX, | ||
| 24 | RR_AMODE31, | ||
| 25 | RR_IPLREPORT, | ||
| 26 | RR_CERT_COMP_LIST, | ||
| 27 | RR_MEM_DETECT_EXTENDED, | ||
| 28 | RR_VMEM, | ||
| 29 | RR_MAX | ||
| 30 | }; | ||
| 31 | |||
| 32 | struct reserved_range { | ||
| 33 | unsigned long start; | ||
| 34 | unsigned long end; | ||
| 35 | struct reserved_range *chain; | ||
| 36 | }; | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Storage element id is defined as 1 byte (up to 256 storage elements). | ||
| 40 | * In practise only storage element id 0 and 1 are used). | ||
| 41 | * According to architecture one storage element could have as much as | ||
| 42 | * 1020 subincrements. 255 physmem_ranges are embedded in physmem_info. | ||
| 43 | * If more physmem_ranges are required, a block of memory from already | ||
| 44 | * known physmem_range is taken (online_extended points to it). | ||
| 45 | */ | ||
| 46 | #define MEM_INLINED_ENTRIES 255 /* (PAGE_SIZE - 16) / 16 */ | ||
| 47 | |||
| 48 | struct physmem_info { | ||
| 49 | u32 range_count; | ||
| 50 | u8 info_source; | ||
| 51 | unsigned long usable; | ||
| 52 | struct reserved_range reserved[RR_MAX]; | ||
| 53 | struct physmem_range online[MEM_INLINED_ENTRIES]; | ||
| 54 | struct physmem_range *online_extended; | ||
| 55 | }; | ||
| 56 | |||
| 57 | extern struct physmem_info physmem_info; | ||
| 58 | |||
| 59 | void add_physmem_online_range(u64 start, u64 end); | ||
| 60 | |||
| 61 | static inline int __get_physmem_range(u32 n, unsigned long *start, | ||
| 62 | unsigned long *end, bool respect_usable_limit) | ||
| 63 | { | ||
| 64 | if (n >= physmem_info.range_count) { | ||
| 65 | *start = 0; | ||
| 66 | *end = 0; | ||
| 67 | return -1; | ||
| 68 | } | ||
| 69 | |||
| 70 | if (n < MEM_INLINED_ENTRIES) { | ||
| 71 | *start = (unsigned long)physmem_info.online[n].start; | ||
| 72 | *end = (unsigned long)physmem_info.online[n].end; | ||
| 73 | } else { | ||
| 74 | *start = (unsigned long)physmem_info.online_extended[n - MEM_INLINED_ENTRIES].start; | ||
| 75 | *end = (unsigned long)physmem_info.online_extended[n - MEM_INLINED_ENTRIES].end; | ||
| 76 | } | ||
| 77 | |||
| 78 | if (respect_usable_limit && physmem_info.usable) { | ||
| 79 | if (*start >= physmem_info.usable) | ||
| 80 | return -1; | ||
| 81 | if (*end > physmem_info.usable) | ||
| 82 | *end = physmem_info.usable; | ||
| 83 | } | ||
| 84 | return 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | /** | ||
| 88 | * for_each_physmem_usable_range - early online memory range iterator | ||
| 89 | * @i: an integer used as loop variable | ||
| 90 | * @p_start: ptr to unsigned long for start address of the range | ||
| 91 | * @p_end: ptr to unsigned long for end address of the range | ||
| 92 | * | ||
| 93 | * Walks over detected online memory ranges below usable limit. | ||
| 94 | */ | ||
| 95 | #define for_each_physmem_usable_range(i, p_start, p_end) \ | ||
| 96 | for (i = 0; !__get_physmem_range(i, p_start, p_end, true); i++) | ||
| 97 | |||
| 98 | /* Walks over all detected online memory ranges disregarding usable limit. */ | ||
| 99 | #define for_each_physmem_online_range(i, p_start, p_end) \ | ||
| 100 | for (i = 0; !__get_physmem_range(i, p_start, p_end, false); i++) | ||
| 101 | |||
| 102 | static inline const char *get_physmem_info_source(void) | ||
| 103 | { | ||
| 104 | switch (physmem_info.info_source) { | ||
| 105 | case MEM_DETECT_SCLP_STOR_INFO: | ||
| 106 | return "sclp storage info"; | ||
| 107 | case MEM_DETECT_DIAG260: | ||
| 108 | return "diag260"; | ||
| 109 | case MEM_DETECT_SCLP_READ_INFO: | ||
| 110 | return "sclp read info"; | ||
| 111 | case MEM_DETECT_BIN_SEARCH: | ||
| 112 | return "binary search"; | ||
| 113 | } | ||
| 114 | return "none"; | ||
| 115 | } | ||
| 116 | |||
| 117 | #define RR_TYPE_NAME(t) case RR_ ## t: return #t | ||
| 118 | static inline const char *get_rr_type_name(enum reserved_range_type t) | ||
| 119 | { | ||
| 120 | switch (t) { | ||
| 121 | RR_TYPE_NAME(DECOMPRESSOR); | ||
| 122 | RR_TYPE_NAME(INITRD); | ||
| 123 | RR_TYPE_NAME(VMLINUX); | ||
| 124 | RR_TYPE_NAME(AMODE31); | ||
| 125 | RR_TYPE_NAME(IPLREPORT); | ||
| 126 | RR_TYPE_NAME(CERT_COMP_LIST); | ||
| 127 | RR_TYPE_NAME(MEM_DETECT_EXTENDED); | ||
| 128 | RR_TYPE_NAME(VMEM); | ||
| 129 | default: | ||
| 130 | return "UNKNOWN"; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | #define for_each_physmem_reserved_type_range(t, range, p_start, p_end) \ | ||
| 135 | for (range = &physmem_info.reserved[t], *p_start = range->start, *p_end = range->end; \ | ||
| 136 | range && range->end; range = range->chain, \ | ||
| 137 | *p_start = range ? range->start : 0, *p_end = range ? range->end : 0) | ||
| 138 | |||
| 139 | static inline struct reserved_range *__physmem_reserved_next(enum reserved_range_type *t, | ||
| 140 | struct reserved_range *range) | ||
| 141 | { | ||
| 142 | if (!range) { | ||
| 143 | range = &physmem_info.reserved[*t]; | ||
| 144 | if (range->end) | ||
| 145 | return range; | ||
| 146 | } | ||
| 147 | if (range->chain) | ||
| 148 | return range->chain; | ||
| 149 | while (++*t < RR_MAX) { | ||
| 150 | range = &physmem_info.reserved[*t]; | ||
| 151 | if (range->end) | ||
| 152 | return range; | ||
| 153 | } | ||
| 154 | return NULL; | ||
| 155 | } | ||
| 156 | |||
| 157 | #define for_each_physmem_reserved_range(t, range, p_start, p_end) \ | ||
| 158 | for (t = 0, range = __physmem_reserved_next(&t, NULL), \ | ||
| 159 | *p_start = range ? range->start : 0, *p_end = range ? range->end : 0; \ | ||
| 160 | range; range = __physmem_reserved_next(&t, range), \ | ||
| 161 | *p_start = range ? range->start : 0, *p_end = range ? range->end : 0) | ||
| 162 | |||
| 163 | static inline unsigned long get_physmem_reserved(enum reserved_range_type type, | ||
| 164 | unsigned long *addr, unsigned long *size) | ||
| 165 | { | ||
| 166 | *addr = physmem_info.reserved[type].start; | ||
| 167 | *size = physmem_info.reserved[type].end - physmem_info.reserved[type].start; | ||
| 168 | return *size; | ||
| 169 | } | ||
| 170 | |||
| 171 | #endif | ||
| @@ -99,7 +99,6 @@ void cpu_detect_mhz_feature(void); · 98 unmodified lines | |||
| 99 | 99 | ||
| 100 | extern const struct seq_operations cpuinfo_op; | 100 | extern const struct seq_operations cpuinfo_op; |
| 101 | extern void execve_tail(void); | 101 | extern void execve_tail(void); |
| 102 | extern void __bpon(void); | ||
| 103 | unsigned long vdso_size(void); | 102 | unsigned long vdso_size(void); |
| 104 | 103 | ||
| 105 | /* | 104 | /* |
| @@ -119,6 +118,41 @@ unsigned long vdso_size(void); · 13 unmodified lines | |||
| 119 | 118 | ||
| 120 | #define HAVE_ARCH_PICK_MMAP_LAYOUT | 119 | #define HAVE_ARCH_PICK_MMAP_LAYOUT |
| 121 | 120 | ||
| 121 | #define __stackleak_poison __stackleak_poison | ||
| 122 | static __always_inline void __stackleak_poison(unsigned long erase_low, | ||
| 123 | unsigned long erase_high, | ||
| 124 | unsigned long poison) | ||
| 125 | { | ||
| 126 | unsigned long tmp, count; | ||
| 127 | |||
| 128 | count = erase_high - erase_low; | ||
| 129 | if (!count) | ||
| 130 | return; | ||
| 131 | asm volatile( | ||
| 132 | " cghi %[count],8\n" | ||
| 133 | " je 2f\n" | ||
| 134 | " aghi %[count],-(8+1)\n" | ||
| 135 | " srlg %[tmp],%[count],8\n" | ||
| 136 | " ltgr %[tmp],%[tmp]\n" | ||
| 137 | " jz 1f\n" | ||
| 138 | "0: stg %[poison],0(%[addr])\n" | ||
| 139 | " mvc 8(256-8,%[addr]),0(%[addr])\n" | ||
| 140 | " la %[addr],256(%[addr])\n" | ||
| 141 | " brctg %[tmp],0b\n" | ||
| 142 | "1: stg %[poison],0(%[addr])\n" | ||
| 143 | " larl %[tmp],3f\n" | ||
| 144 | " ex %[count],0(%[tmp])\n" | ||
| 145 | " j 4f\n" | ||
| 146 | "2: stg %[poison],0(%[addr])\n" | ||
| 147 | " j 4f\n" | ||
| 148 | "3: mvc 8(1,%[addr]),0(%[addr])\n" | ||
| 149 | "4:\n" | ||
| 150 | : [addr] "+&a" (erase_low), [count] "+&d" (count), [tmp] "=&a" (tmp) | ||
| 151 | : [poison] "d" (poison) | ||
| 152 | : "memory", "cc" | ||
| 153 | ); | ||
| 154 | } | ||
| 155 | |||
| 122 | /* | 156 | /* |
| 123 | * Thread structure | 157 | * Thread structure |
| 124 | */ | 158 | */ |
| @@ -227,6 +261,13 @@ static __always_inline unsigned long __current_stack_pointer(void) · 102 unmodified lines | |||
| 227 | return sp; | 261 | return sp; |
| 228 | } | 262 | } |
| 229 | 263 | ||
| 264 | static __always_inline bool on_thread_stack(void) | ||
| 265 | { | ||
| 266 | unsigned long ksp = S390_lowcore.kernel_stack; | ||
| 267 | |||
| 268 | return !((ksp ^ current_stack_pointer) & ~(THREAD_SIZE - 1)); | ||
| 269 | } | ||
| 270 | |||
| 230 | static __always_inline unsigned short stap(void) | 271 | static __always_inline unsigned short stap(void) |
| 231 | { | 272 | { |
| 232 | unsigned short cpu_address; | 273 | unsigned short cpu_address; |
| @@ -329,9 +370,6 @@ static __always_inline void __noreturn disabled_wait(void) · 96 unmodified lines | |||
| 329 | 370 | ||
| 330 | #define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL | 371 | #define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL |
| 331 | 372 | ||
| 332 | extern int s390_isolate_bp(void); | ||
| 333 | extern int s390_isolate_bp_guest(void); | ||
| 334 | |||
| 335 | static __always_inline bool regs_irqs_disabled(struct pt_regs *regs) | 373 | static __always_inline bool regs_irqs_disabled(struct pt_regs *regs) |
| 336 | { | 374 | { |
| 337 | return arch_irqs_disabled_flags(regs->psw.mask); | 375 | return arch_irqs_disabled_flags(regs->psw.mask); |
| @@ -6,11 +6,23 @@ · 5 unmodified lines | |||
| 6 | 6 | ||
| 7 | extern struct mutex cpa_mutex; | 7 | extern struct mutex cpa_mutex; |
| 8 | 8 | ||
| 9 | #define SET_MEMORY_RO 1UL | 9 | enum { |
| 10 | #define SET_MEMORY_RW 2UL | 10 | _SET_MEMORY_RO_BIT, |
| 11 | #define SET_MEMORY_NX 4UL | 11 | _SET_MEMORY_RW_BIT, |
| 12 | #define SET_MEMORY_X 8UL | 12 | _SET_MEMORY_NX_BIT, |
| 13 | #define SET_MEMORY_4K 16UL | 13 | _SET_MEMORY_X_BIT, |
| 14 | _SET_MEMORY_4K_BIT, | ||
| 15 | _SET_MEMORY_INV_BIT, | ||
| 16 | _SET_MEMORY_DEF_BIT, | ||
| 17 | }; | ||
| 18 | |||
| 19 | #define SET_MEMORY_RO BIT(_SET_MEMORY_RO_BIT) | ||
| 20 | #define SET_MEMORY_RW BIT(_SET_MEMORY_RW_BIT) | ||
| 21 | #define SET_MEMORY_NX BIT(_SET_MEMORY_NX_BIT) | ||
| 22 | #define SET_MEMORY_X BIT(_SET_MEMORY_X_BIT) | ||
| 23 | #define SET_MEMORY_4K BIT(_SET_MEMORY_4K_BIT) | ||
| 24 | #define SET_MEMORY_INV BIT(_SET_MEMORY_INV_BIT) | ||
| 25 | #define SET_MEMORY_DEF BIT(_SET_MEMORY_DEF_BIT) | ||
| 14 | 26 | ||
| 15 | int __set_memory(unsigned long addr, int numpages, unsigned long flags); | 27 | int __set_memory(unsigned long addr, int numpages, unsigned long flags); |
| 16 | 28 | ||
| @@ -34,9 +46,23 @@ static inline int set_memory_x(unsigned long addr, int numpages) · 17 unmodified lines | |||
| 34 | return __set_memory(addr, numpages, SET_MEMORY_X); | 46 | return __set_memory(addr, numpages, SET_MEMORY_X); |
| 35 | } | 47 | } |
| 36 | 48 | ||
| 49 | #define set_memory_rox set_memory_rox | ||
| 50 | static inline int set_memory_rox(unsigned long addr, int numpages) | ||
| 51 | { | ||
| 52 | return __set_memory(addr, numpages, SET_MEMORY_RO | SET_MEMORY_X); | ||
| 53 | } | ||
| 54 | |||
| 55 | static inline int set_memory_rwnx(unsigned long addr, int numpages) | ||
| 56 | { | ||
| 57 | return __set_memory(addr, numpages, SET_MEMORY_RW | SET_MEMORY_NX); | ||
| 58 | } | ||
| 59 | |||
| 37 | static inline int set_memory_4k(unsigned long addr, int numpages) | 60 | static inline int set_memory_4k(unsigned long addr, int numpages) |
| 38 | { | 61 | { |
| 39 | return __set_memory(addr, numpages, SET_MEMORY_4K); | 62 | return __set_memory(addr, numpages, SET_MEMORY_4K); |
| 40 | } | 63 | } |
| 41 | 64 | ||
| 65 | int set_direct_map_invalid_noflush(struct page *page); | ||
| 66 | int set_direct_map_default_noflush(struct page *page); | ||
| 67 | |||
| 42 | #endif | 68 | #endif |
| @@ -74,10 +74,6 @@ extern unsigned int zlib_dfltcc_support; · 73 unmodified lines | |||
| 74 | 74 | ||
| 75 | extern int noexec_disabled; | 75 | extern int noexec_disabled; |
| 76 | extern unsigned long ident_map_size; | 76 | extern unsigned long ident_map_size; |
| 77 | extern unsigned long pgalloc_pos; | ||
| 78 | extern unsigned long pgalloc_end; | ||
| 79 | extern unsigned long pgalloc_low; | ||
| 80 | extern unsigned long __amode31_base; | ||
| 81 | 77 | ||
| 82 | /* The Write Back bit position in the physaddr is given by the SLPC PCI */ | 78 | /* The Write Back bit position in the physaddr is given by the SLPC PCI */ |
| 83 | extern unsigned long mio_wb_bit_mask; | 79 | extern unsigned long mio_wb_bit_mask; |
| @@ -150,13 +146,13 @@ static inline unsigned long kaslr_offset(void) · 66 unmodified lines | |||
| 150 | return __kaslr_offset; | 146 | return __kaslr_offset; |
| 151 | } | 147 | } |
| 152 | 148 | ||
| 153 | extern int is_full_image; | 149 | extern int __kaslr_enabled; |
| 154 | 150 | static inline int kaslr_enabled(void) | |
| 155 | struct initrd_data { | 151 | { |
| 156 | unsigned long start; | 152 | if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) |
| 157 | unsigned long size; | 153 | return __kaslr_enabled; |
| 158 | }; | 154 | return 0; |
| 159 | extern struct initrd_data initrd_data; | 155 | } |
| 160 | 156 | ||
| 161 | struct oldmem_data { | 157 | struct oldmem_data { |
| 162 | unsigned long start; | 158 | unsigned long start; |
| @@ -164,7 +160,7 @@ struct oldmem_data { · 1 unmodified line | |||
| 164 | }; | 160 | }; |
| 165 | extern struct oldmem_data oldmem_data; | 161 | extern struct oldmem_data oldmem_data; |
| 166 | 162 | ||
| 167 | static inline u32 gen_lpswe(unsigned long addr) | 163 | static __always_inline u32 gen_lpswe(unsigned long addr) |
| 168 | { | 164 | { |
| 169 | BUILD_BUG_ON(addr > 0xfff); | 165 | BUILD_BUG_ON(addr > 0xfff); |
| 170 | return 0xb2b20000 | addr; | 166 | return 0xb2b20000 | addr; |
| @@ -189,17 +189,53 @@ static __always_inline unsigned long get_stack_pointer(struct task_struct *task, · 188 unmodified lines | |||
| 189 | (rettype)r2; \ | 189 | (rettype)r2; \ |
| 190 | }) | 190 | }) |
| 191 | 191 | ||
| 192 | #define call_on_stack_noreturn(fn, stack) \ | 192 | /* |
| 193 | * Use call_nodat() to call a function with DAT disabled. | ||
| 194 | * Proper sign and zero extension of function arguments is done. | ||
| 195 | * Usage: | ||
| 196 | * | ||
| 197 | * rc = call_nodat(nr, rettype, fn, t1, a1, t2, a2, ...) | ||
| 198 | * | ||
| 199 | * - nr specifies the number of function arguments of fn. | ||
| 200 | * - fn is the function to be called, where fn is a physical address. | ||
| 201 | * - rettype is the return type of fn. | ||
| 202 | * - t1, a1, ... are pairs, where t1 must match the type of the first | ||
| 203 | * argument of fn, t2 the second, etc. a1 is the corresponding | ||
| 204 | * first function argument (not name), etc. | ||
| 205 | * | ||
| 206 | * fn() is called with standard C function call ABI, with the exception | ||
| 207 | * that no useful stackframe or stackpointer is passed via register 15. | ||
| 208 | * Therefore the called function must not use r15 to access the stack. | ||
| 209 | */ | ||
| 210 | #define call_nodat(nr, rettype, fn, ...) \ | ||
| 193 | ({ \ | 211 | ({ \ |
| 194 | void (*__fn)(void) = fn; \ | 212 | rettype (*__fn)(CALL_PARM_##nr(__VA_ARGS__)) = (fn); \ |
| 213 | /* aligned since psw_leave must not cross page boundary */ \ | ||
| 214 | psw_t __aligned(16) psw_leave; \ | ||
| 215 | psw_t psw_enter; \ | ||
| 216 | CALL_LARGS_##nr(__VA_ARGS__); \ | ||
| 217 | CALL_REGS_##nr; \ | ||
| 195 | \ | 218 | \ |
| 219 | CALL_TYPECHECK_##nr(__VA_ARGS__); \ | ||
| 220 | psw_enter.mask = PSW_KERNEL_BITS & ~PSW_MASK_DAT; \ | ||
| 221 | psw_enter.addr = (unsigned long)__fn; \ | ||
| 196 | asm volatile( \ | 222 | asm volatile( \ |
| 197 | " la 15,0(%[_stack])\n" \ | 223 | " epsw 0,1\n" \ |
| 198 | " xc %[_bc](8,15),%[_bc](15)\n" \ | 224 | " risbg 1,0,0,31,32\n" \ |
| 199 | " brasl 14,%[_fn]\n" \ | 225 | " larl 7,1f\n" \ |
| 200 | ::[_bc] "i" (offsetof(struct stack_frame, back_chain)), \ | 226 | " stg 1,%[psw_leave]\n" \ |
| 201 | [_stack] "a" (stack), [_fn] "X" (__fn)); \ | 227 | " stg 7,8+%[psw_leave]\n" \ |
| 202 | BUG(); \ | 228 | " la 7,%[psw_leave]\n" \ |
| 229 | " lra 7,0(7)\n" \ | ||
| 230 | " larl 1,0f\n" \ | ||
| 231 | " lra 14,0(1)\n" \ | ||
| 232 | " lpswe %[psw_enter]\n" \ | ||
| 233 | "0: lpswe 0(7)\n" \ | ||
| 234 | "1:\n" \ | ||
| 235 | : CALL_FMT_##nr, [psw_leave] "=Q" (psw_leave) \ | ||
| 236 | : [psw_enter] "Q" (psw_enter) \ | ||
| 237 | : "7", CALL_CLOBBER_##nr); \ | ||
| 238 | (rettype)r2; \ | ||
| 203 | }) | 239 | }) |
| 204 | 240 | ||
| 205 | #endif /* _ASM_S390_STACKTRACE_H */ | 241 | #endif /* _ASM_S390_STACKTRACE_H */ |
| @@ -55,18 +55,6 @@ char *strstr(const char *s1, const char *s2); · 54 unmodified lines | |||
| 55 | 55 | ||
| 56 | #if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__) | 56 | #if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__) |
| 57 | 57 | ||
| 58 | extern void *__memcpy(void *dest, const void *src, size_t n); | ||
| 59 | extern void *__memset(void *s, int c, size_t n); | ||
| 60 | extern void *__memmove(void *dest, const void *src, size_t n); | ||
| 61 | |||
| 62 | /* | ||
| 63 | * For files that are not instrumented (e.g. mm/slub.c) we | ||
| 64 | * should use not instrumented version of mem* functions. | ||
| 65 | */ | ||
| 66 | |||
| 67 | #define memcpy(dst, src, len) __memcpy(dst, src, len) | ||
| 68 | #define memmove(dst, src, len) __memmove(dst, src, len) | ||
| 69 | #define memset(s, c, n) __memset(s, c, n) | ||
| 70 | #define strlen(s) __strlen(s) | 58 | #define strlen(s) __strlen(s) |
| 71 | 59 | ||
| 72 | #define __no_sanitize_prefix_strfunc(x) __##x | 60 | #define __no_sanitize_prefix_strfunc(x) __##x |
| @@ -79,6 +67,9 @@ extern void *__memmove(void *dest, const void *src, size_t n); · 6 unmodified lines | |||
| 79 | #define __no_sanitize_prefix_strfunc(x) x | 67 | #define __no_sanitize_prefix_strfunc(x) x |
| 80 | #endif /* defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__) */ | 68 | #endif /* defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__) */ |
| 81 | 69 | ||
| 70 | void *__memcpy(void *dest, const void *src, size_t n); | ||
| 71 | void *__memset(void *s, int c, size_t n); | ||
| 72 | void *__memmove(void *dest, const void *src, size_t n); | ||
| 82 | void *__memset16(uint16_t *s, uint16_t v, size_t count); | 73 | void *__memset16(uint16_t *s, uint16_t v, size_t count); |
| 83 | void *__memset32(uint32_t *s, uint32_t v, size_t count); | 74 | void *__memset32(uint32_t *s, uint32_t v, size_t count); |
| 84 | void *__memset64(uint64_t *s, uint64_t v, size_t count); | 75 | void *__memset64(uint64_t *s, uint64_t v, size_t count); |
| @@ -9,6 +9,9 @@ · 8 unmodified lines | |||
| 9 | #define _ASM_THREAD_INFO_H | 9 | #define _ASM_THREAD_INFO_H |
| 10 | 10 | ||
| 11 | #include <linux/bits.h> | 11 | #include <linux/bits.h> |
| 12 | #ifndef ASM_OFFSETS_C | ||
| 13 | #include <asm/asm-offsets.h> | ||
| 14 | #endif | ||
| 12 | 15 | ||
| 13 | /* | 16 | /* |
| 14 | * General size of kernel stacks | 17 | * General size of kernel stacks |
| @@ -21,13 +24,12 @@ · 6 unmodified lines | |||
| 21 | #define BOOT_STACK_SIZE (PAGE_SIZE << 2) | 24 | #define BOOT_STACK_SIZE (PAGE_SIZE << 2) |
| 22 | #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) | 25 | #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) |
| 23 | 26 | ||
| 27 | #define STACK_INIT_OFFSET (THREAD_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE) | ||
| 28 | |||
| 24 | #ifndef __ASSEMBLY__ | 29 | #ifndef __ASSEMBLY__ |
| 25 | #include <asm/lowcore.h> | 30 | #include <asm/lowcore.h> |
| 26 | #include <asm/page.h> | 31 | #include <asm/page.h> |
| 27 | 32 | ||
| 28 | #define STACK_INIT_OFFSET \ | ||
| 29 | (THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs)) | ||
| 30 | |||
| 31 | /* | 33 | /* |
| 32 | * low level task data that entry.S needs immediate access to | 34 | * low level task data that entry.S needs immediate access to |
| 33 | * - this struct should fit entirely inside of one cache line | 35 | * - this struct should fit entirely inside of one cache line |
| @@ -70,7 +72,6 @@ void arch_setup_new_exec(void); · 36 unmodified lines | |||
| 70 | #define TIF_PATCH_PENDING 5 /* pending live patching update */ | 72 | #define TIF_PATCH_PENDING 5 /* pending live patching update */ |
| 71 | #define TIF_PGSTE 6 /* New mm's will use 4K page tables */ | 73 | #define TIF_PGSTE 6 /* New mm's will use 4K page tables */ |
| 72 | #define TIF_NOTIFY_SIGNAL 7 /* signal notifications exist */ | 74 | #define TIF_NOTIFY_SIGNAL 7 /* signal notifications exist */ |
| 73 | #define TIF_ISOLATE_BP 8 /* Run process with isolated BP */ | ||
| 74 | #define TIF_ISOLATE_BP_GUEST 9 /* Run KVM guests with isolated BP */ | 75 | #define TIF_ISOLATE_BP_GUEST 9 /* Run KVM guests with isolated BP */ |
| 75 | #define TIF_PER_TRAP 10 /* Need to handle PER trap on exit to usermode */ | 76 | #define TIF_PER_TRAP 10 /* Need to handle PER trap on exit to usermode */ |
| 76 | 77 | ||
| @@ -94,7 +95,6 @@ void arch_setup_new_exec(void); · 17 unmodified lines | |||
| 94 | #define _TIF_UPROBE BIT(TIF_UPROBE) | 95 | #define _TIF_UPROBE BIT(TIF_UPROBE) |
| 95 | #define _TIF_GUARDED_STORAGE BIT(TIF_GUARDED_STORAGE) | 96 | #define _TIF_GUARDED_STORAGE BIT(TIF_GUARDED_STORAGE) |
| 96 | #define _TIF_PATCH_PENDING BIT(TIF_PATCH_PENDING) | 97 | #define _TIF_PATCH_PENDING BIT(TIF_PATCH_PENDING) |
| 97 | #define _TIF_ISOLATE_BP BIT(TIF_ISOLATE_BP) | ||
| 98 | #define _TIF_ISOLATE_BP_GUEST BIT(TIF_ISOLATE_BP_GUEST) | 98 | #define _TIF_ISOLATE_BP_GUEST BIT(TIF_ISOLATE_BP_GUEST) |
| 99 | #define _TIF_PER_TRAP BIT(TIF_PER_TRAP) | 99 | #define _TIF_PER_TRAP BIT(TIF_PER_TRAP) |
| 100 | 100 | ||
| @@ -60,7 +60,7 @@ typedef struct { · 59 unmodified lines | |||
| 60 | * except of floats, and long long (32 bit) | 60 | * except of floats, and long long (32 bit) |
| 61 | * | 61 | * |
| 62 | */ | 62 | */ |
| 63 | long args[0]; | 63 | long args[]; |
| 64 | } debug_sprintf_entry_t; | 64 | } debug_sprintf_entry_t; |
| 65 | 65 | ||
| 66 | /* internal function prototyes */ | 66 | /* internal function prototyes */ |
| @@ -981,16 +981,6 @@ static struct ctl_table s390dbf_table[] = { · 914 unmodified lines | |||
| 981 | { } | 981 | { } |
| 982 | }; | 982 | }; |
| 983 | 983 | ||
| 984 | static struct ctl_table s390dbf_dir_table[] = { | ||
| 985 | { | ||
| 986 | .procname = "s390dbf", | ||
| 987 | .maxlen = 0, | ||
| 988 | .mode = S_IRUGO | S_IXUGO, | ||
| 989 | .child = s390dbf_table, | ||
| 990 | }, | ||
| 991 | { } | ||
| 992 | }; | ||
| 993 | |||
| 994 | static struct ctl_table_header *s390dbf_sysctl_header; | 984 | static struct ctl_table_header *s390dbf_sysctl_header; |
| 995 | 985 | ||
| 996 | /** | 986 | /** |
| @@ -1574,7 +1564,7 @@ out: · 577 unmodified lines | |||
| 1574 | */ | 1564 | */ |
| 1575 | static int __init debug_init(void) | 1565 | static int __init debug_init(void) |
| 1576 | { | 1566 | { |
| 1577 | s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table); | 1567 | s390dbf_sysctl_header = register_sysctl("s390dbf", s390dbf_table); |
| 1578 | mutex_lock(&debug_mutex); | 1568 | mutex_lock(&debug_mutex); |
| 1579 | debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT, NULL); | 1569 | debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT, NULL); |
| 1580 | initialized = 1; | 1570 | initialized = 1; |
| @@ -41,60 +41,50 @@ const char *stack_type_name(enum stack_type type) · 40 unmodified lines | |||
| 41 | EXPORT_SYMBOL_GPL(stack_type_name); | 41 | EXPORT_SYMBOL_GPL(stack_type_name); |
| 42 | 42 | ||
| 43 | static inline bool in_stack(unsigned long sp, struct stack_info *info, | 43 | static inline bool in_stack(unsigned long sp, struct stack_info *info, |
| 44 | enum stack_type type, unsigned long low, | 44 | enum stack_type type, unsigned long stack) |
| 45 | unsigned long high) | ||
| 46 | { | 45 | { |
| 47 | if (sp < low || sp >= high) | 46 | if (sp < stack || sp >= stack + THREAD_SIZE) |
| 48 | return false; | 47 | return false; |
| 49 | info->type = type; | 48 | info->type = type; |
| 50 | info->begin = low; | 49 | info->begin = stack; |
| 51 | info->end = high; | 50 | info->end = stack + THREAD_SIZE; |
| 52 | return true; | 51 | return true; |
| 53 | } | 52 | } |
| 54 | 53 | ||
| 55 | static bool in_task_stack(unsigned long sp, struct task_struct *task, | 54 | static bool in_task_stack(unsigned long sp, struct task_struct *task, |
| 56 | struct stack_info *info) | 55 | struct stack_info *info) |
| 57 | { | 56 | { |
| 58 | unsigned long stack; | 57 | unsigned long stack = (unsigned long)task_stack_page(task); |
| 59 | 58 | ||
| 60 | stack = (unsigned long) task_stack_page(task); | 59 | return in_stack(sp, info, STACK_TYPE_TASK, stack); |
| 61 | return in_stack(sp, info, STACK_TYPE_TASK, stack, stack + THREAD_SIZE); | ||
| 62 | } | 60 | } |
| 63 | 61 | ||
| 64 | static bool in_irq_stack(unsigned long sp, struct stack_info *info) | 62 | static bool in_irq_stack(unsigned long sp, struct stack_info *info) |
| 65 | { | 63 | { |
| 66 | unsigned long frame_size, top; | 64 | unsigned long stack = S390_lowcore.async_stack - STACK_INIT_OFFSET; |
| 67 | 65 | ||
| 68 | frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); | 66 | return in_stack(sp, info, STACK_TYPE_IRQ, stack); |
| 69 | top = S390_lowcore.async_stack + frame_size; | ||
| 70 | return in_stack(sp, info, STACK_TYPE_IRQ, top - THREAD_SIZE, top); | ||
| 71 | } | 67 | } |
| 72 | 68 | ||
| 73 | static bool in_nodat_stack(unsigned long sp, struct stack_info *info) | 69 | static bool in_nodat_stack(unsigned long sp, struct stack_info *info) |
| 74 | { | 70 | { |
| 75 | unsigned long frame_size, top; | 71 | unsigned long stack = S390_lowcore.nodat_stack - STACK_INIT_OFFSET; |
| 76 | 72 | ||
| 77 | frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); | 73 | return in_stack(sp, info, STACK_TYPE_NODAT, stack); |
| 78 | top = S390_lowcore.nodat_stack + frame_size; | ||
| 79 | return in_stack(sp, info, STACK_TYPE_NODAT, top - THREAD_SIZE, top); | ||
| 80 | } | 74 | } |
| 81 | 75 | ||
| 82 | static bool in_mcck_stack(unsigned long sp, struct stack_info *info) | 76 | static bool in_mcck_stack(unsigned long sp, struct stack_info *info) |
| 83 | { | 77 | { |
| 84 | unsigned long frame_size, top; | 78 | unsigned long stack = S390_lowcore.mcck_stack - STACK_INIT_OFFSET; |
| 85 | 79 | ||
| 86 | frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); | 80 | return in_stack(sp, info, STACK_TYPE_MCCK, stack); |
| 87 | top = S390_lowcore.mcck_stack + frame_size; | ||
| 88 | return in_stack(sp, info, STACK_TYPE_MCCK, top - THREAD_SIZE, top); | ||
| 89 | } | 81 | } |
| 90 | 82 | ||
| 91 | static bool in_restart_stack(unsigned long sp, struct stack_info *info) | 83 | static bool in_restart_stack(unsigned long sp, struct stack_info *info) |
| 92 | { | 84 | { |
| 93 | unsigned long frame_size, top; | 85 | unsigned long stack = S390_lowcore.restart_stack - STACK_INIT_OFFSET; |
| 94 | 86 | ||
| 95 | frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); | 87 | return in_stack(sp, info, STACK_TYPE_RESTART, stack); |
| 96 | top = S390_lowcore.restart_stack + frame_size; | ||
| 97 | return in_stack(sp, info, STACK_TYPE_RESTART, top - THREAD_SIZE, top); | ||
| 98 | } | 88 | } |
| 99 | 89 | ||
| 100 | int get_stack_info(unsigned long sp, struct task_struct *task, | 90 | int get_stack_info(unsigned long sp, struct task_struct *task, |
| @@ -152,7 +142,13 @@ void show_stack(struct task_struct *task, unsigned long *stack, · 51 unmodified lines | |||
| 152 | static void show_last_breaking_event(struct pt_regs *regs) | 142 | static void show_last_breaking_event(struct pt_regs *regs) |
| 153 | { | 143 | { |
| 154 | printk("Last Breaking-Event-Address:\n"); | 144 | printk("Last Breaking-Event-Address:\n"); |
| 155 | printk(" [<%016lx>] %pSR\n", regs->last_break, (void *)regs->last_break); | 145 | printk(" [<%016lx>] ", regs->last_break); |
| 146 | if (user_mode(regs)) { | ||
| 147 | print_vma_addr(KERN_CONT, regs->last_break); | ||
| 148 | pr_cont("\n"); | ||
| 149 | } else { | ||
| 150 | pr_cont("%pSR\n", (void *)regs->last_break); | ||
| 151 | } | ||
| 156 | } | 152 | } |
| 157 | 153 | ||
| 158 | void show_registers(struct pt_regs *regs) | 154 | void show_registers(struct pt_regs *regs) |
| @@ -34,8 +34,6 @@ · 33 unmodified lines | |||
| 34 | #include <asm/switch_to.h> | 34 | #include <asm/switch_to.h> |
| 35 | #include "entry.h" | 35 | #include "entry.h" |
| 36 | 36 | ||
| 37 | int __bootdata(is_full_image); | ||
| 38 | |||
| 39 | #define decompressor_handled_param(param) \ | 37 | #define decompressor_handled_param(param) \ |
| 40 | static int __init ignore_decompressor_param_##param(char *s) \ | 38 | static int __init ignore_decompressor_param_##param(char *s) \ |
| 41 | { \ | 39 | { \ |
| @@ -53,6 +51,14 @@ decompressor_handled_param(nokaslr); · 11 unmodified lines | |||
| 53 | decompressor_handled_param(prot_virt); | 51 | decompressor_handled_param(prot_virt); |
| 54 | #endif | 52 | #endif |
| 55 | 53 | ||
| 54 | static void __init kasan_early_init(void) | ||
| 55 | { | ||
| 56 | #ifdef CONFIG_KASAN | ||
| 57 | init_task.kasan_depth = 0; | ||
| 58 | sclp_early_printk("KernelAddressSanitizer initialized\n"); | ||
| 59 | #endif | ||
| 60 | } | ||
| 61 | |||
| 56 | static void __init reset_tod_clock(void) | 62 | static void __init reset_tod_clock(void) |
| 57 | { | 63 | { |
| 58 | union tod_clock clk; | 64 | union tod_clock clk; |
| @@ -288,17 +294,6 @@ static void __init setup_boot_command_line(void) · 229 unmodified lines | |||
| 288 | strscpy(boot_command_line, early_command_line, COMMAND_LINE_SIZE); | 294 | strscpy(boot_command_line, early_command_line, COMMAND_LINE_SIZE); |
| 289 | } | 295 | } |
| 290 | 296 | ||
| 291 | static void __init check_image_bootable(void) | ||
| 292 | { | ||
| 293 | if (is_full_image) | ||
| 294 | return; | ||
| 295 | |||
| 296 | sclp_early_printk("Linux kernel boot failure: An attempt to boot a vmlinux ELF image failed.\n"); | ||
| 297 | sclp_early_printk("This image does not contain all parts necessary for starting up. Use\n"); | ||
| 298 | sclp_early_printk("bzImage or arch/s390/boot/compressed/vmlinux instead.\n"); | ||
| 299 | disabled_wait(); | ||
| 300 | } | ||
| 301 | |||
| 302 | static void __init sort_amode31_extable(void) | 297 | static void __init sort_amode31_extable(void) |
| 303 | { | 298 | { |
| 304 | sort_extable(__start_amode31_ex_table, __stop_amode31_ex_table); | 299 | sort_extable(__start_amode31_ex_table, __stop_amode31_ex_table); |
| @@ -306,8 +301,8 @@ static void __init sort_amode31_extable(void) · 1 unmodified line | |||
| 306 | 301 | ||
| 307 | void __init startup_init(void) | 302 | void __init startup_init(void) |
| 308 | { | 303 | { |
| 304 | kasan_early_init(); | ||
| 309 | reset_tod_clock(); | 305 | reset_tod_clock(); |
| 310 | check_image_bootable(); | ||
| 311 | time_early_init(); | 306 | time_early_init(); |
| 312 | init_kernel_storage_key(); | 307 | init_kernel_storage_key(); |
| 313 | lockdep_off(); | 308 | lockdep_off(); |
| @@ -7,7 +7,7 @@ · 6 unmodified lines | |||
| 7 | #include <linux/linkage.h> | 7 | #include <linux/linkage.h> |
| 8 | #include <asm/asm-offsets.h> | 8 | #include <asm/asm-offsets.h> |
| 9 | 9 | ||
| 10 | ENTRY(early_pgm_check_handler) | 10 | SYM_CODE_START(early_pgm_check_handler) |
| 11 | stmg %r8,%r15,__LC_SAVE_AREA_SYNC | 11 | stmg %r8,%r15,__LC_SAVE_AREA_SYNC |
| 12 | aghi %r15,-(STACK_FRAME_OVERHEAD+__PT_SIZE) | 12 | aghi %r15,-(STACK_FRAME_OVERHEAD+__PT_SIZE) |
| 13 | la %r11,STACK_FRAME_OVERHEAD(%r15) | 13 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
| @@ -20,4 +20,4 @@ ENTRY(early_pgm_check_handler) · 6 unmodified lines | |||
| 20 | mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15) | 20 | mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15) |
| 21 | lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15) | 21 | lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15) |
| 22 | lpswe __LC_RETURN_PSW | 22 | lpswe __LC_RETURN_PSW |
| 23 | ENDPROC(early_pgm_check_handler) | 23 | SYM_CODE_END(early_pgm_check_handler) |
| @@ -29,10 +29,6 @@ · 28 unmodified lines | |||
| 29 | #include <asm/export.h> | 29 | #include <asm/export.h> |
| 30 | #include <asm/nospec-insn.h> | 30 | #include <asm/nospec-insn.h> |
| 31 | 31 | ||
| 32 | STACK_SHIFT = PAGE_SHIFT + THREAD_SIZE_ORDER | ||
| 33 | STACK_SIZE = 1 << STACK_SHIFT | ||
| 34 | STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE | ||
| 35 | |||
| 36 | _LPP_OFFSET = __LC_LPP | 32 | _LPP_OFFSET = __LC_LPP |
| 37 | 33 | ||
| 38 | .macro STBEAR address | 34 | .macro STBEAR address |
| @@ -53,7 +49,7 @@ _LPP_OFFSET = __LC_LPP · 14 unmodified lines | |||
| 53 | 49 | ||
| 54 | .macro CHECK_STACK savearea | 50 | .macro CHECK_STACK savearea |
| 55 | #ifdef CONFIG_CHECK_STACK | 51 | #ifdef CONFIG_CHECK_STACK |
| 56 | tml %r15,STACK_SIZE - CONFIG_STACK_GUARD | 52 | tml %r15,THREAD_SIZE - CONFIG_STACK_GUARD |
| 57 | lghi %r14,\savearea | 53 | lghi %r14,\savearea |
| 58 | jz stack_overflow | 54 | jz stack_overflow |
| 59 | #endif | 55 | #endif |
| @@ -62,8 +58,8 @@ _LPP_OFFSET = __LC_LPP · 2 unmodified lines | |||
| 62 | .macro CHECK_VMAP_STACK savearea,oklabel | 58 | .macro CHECK_VMAP_STACK savearea,oklabel |
| 63 | #ifdef CONFIG_VMAP_STACK | 59 | #ifdef CONFIG_VMAP_STACK |
| 64 | lgr %r14,%r15 | 60 | lgr %r14,%r15 |
| 65 | nill %r14,0x10000 - STACK_SIZE | 61 | nill %r14,0x10000 - THREAD_SIZE |
| 66 | oill %r14,STACK_INIT | 62 | oill %r14,STACK_INIT_OFFSET |
| 67 | clg %r14,__LC_KERNEL_STACK | 63 | clg %r14,__LC_KERNEL_STACK |
| 68 | je \oklabel | 64 | je \oklabel |
| 69 | clg %r14,__LC_ASYNC_STACK | 65 | clg %r14,__LC_ASYNC_STACK |
| @@ -154,26 +150,26 @@ _LPP_OFFSET = __LC_LPP · 84 unmodified lines | |||
| 154 | .endm | 150 | .endm |
| 155 | #endif | 151 | #endif |
| 156 | 152 | ||
| 153 | .macro STACKLEAK_ERASE | ||
| 154 | #ifdef CONFIG_GCC_PLUGIN_STACKLEAK | ||
| 155 | brasl %r14,stackleak_erase_on_task_stack | ||
| 156 | #endif | ||
| 157 | .endm | ||
| 158 | |||
| 157 | GEN_BR_THUNK %r14 | 159 | GEN_BR_THUNK %r14 |
| 158 | 160 | ||
| 159 | .section .kprobes.text, "ax" | 161 | .section .kprobes.text, "ax" |
| 160 | .Ldummy: | 162 | .Ldummy: |
| 161 | /* | 163 | /* |
| 162 | * This nop exists only in order to avoid that __bpon starts at | 164 | * The following nop exists only in order to avoid that the next |
| 163 | * the beginning of the kprobes text section. In that case we would | 165 | * symbol starts at the beginning of the kprobes text section. |
| 164 | * have several symbols at the same address. E.g. objdump would take | 166 | * In that case there would be several symbols at the same address. |
| 165 | * an arbitrary symbol name when disassembling this code. | 167 | * E.g. objdump would take an arbitrary symbol when disassembling |
| 166 | * With the added nop in between the __bpon symbol is unique | 168 | * the code. |
| 167 | * again. | 169 | * With the added nop in between this cannot happen. |
| 168 | */ | 170 | */ |
| 169 | nop 0 | 171 | nop 0 |
| 170 | 172 | ||
| 171 | ENTRY(__bpon) | ||
| 172 | .globl __bpon | ||
| 173 | BPON | ||
| 174 | BR_EX %r14 | ||
| 175 | ENDPROC(__bpon) | ||
| 176 | |||
| 177 | /* | 173 | /* |
| 178 | * Scheduler resume function, called by switch_to | 174 | * Scheduler resume function, called by switch_to |
| 179 | * gpr2 = (task_struct *) prev | 175 | * gpr2 = (task_struct *) prev |
| @@ -181,11 +177,11 @@ ENDPROC(__bpon) · 1 unmodified line | |||
| 181 | * Returns: | 177 | * Returns: |
| 182 | * gpr2 = prev | 178 | * gpr2 = prev |
| 183 | */ | 179 | */ |
| 184 | ENTRY(__switch_to) | 180 | SYM_FUNC_START(__switch_to) |
| 185 | stmg %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task | 181 | stmg %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task |
| 186 | lghi %r4,__TASK_stack | 182 | lghi %r4,__TASK_stack |
| 187 | lghi %r1,__TASK_thread | 183 | lghi %r1,__TASK_thread |
| 188 | llill %r5,STACK_INIT | 184 | llill %r5,STACK_INIT_OFFSET |
| 189 | stg %r15,__THREAD_ksp(%r1,%r2) # store kernel stack of prev | 185 | stg %r15,__THREAD_ksp(%r1,%r2) # store kernel stack of prev |
| 190 | lg %r15,0(%r4,%r3) # start of kernel stack of next | 186 | lg %r15,0(%r4,%r3) # start of kernel stack of next |
| 191 | agr %r15,%r5 # end of kernel stack of next | 187 | agr %r15,%r5 # end of kernel stack of next |
| @@ -197,7 +193,7 @@ ENTRY(__switch_to) · 5 unmodified lines | |||
| 197 | lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task | 193 | lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task |
| 198 | ALTERNATIVE "nop", "lpp _LPP_OFFSET", 40 | 194 | ALTERNATIVE "nop", "lpp _LPP_OFFSET", 40 |
| 199 | BR_EX %r14 | 195 | BR_EX %r14 |
| 200 | ENDPROC(__switch_to) | 196 | SYM_FUNC_END(__switch_to) |
| 201 | 197 | ||
| 202 | #if IS_ENABLED(CONFIG_KVM) | 198 | #if IS_ENABLED(CONFIG_KVM) |
| 203 | /* | 199 | /* |
| @@ -206,7 +202,7 @@ ENDPROC(__switch_to) · 2 unmodified lines | |||
| 206 | * %r3 pointer to sie control block virt | 202 | * %r3 pointer to sie control block virt |
| 207 | * %r4 guest register save area | 203 | * %r4 guest register save area |
| 208 | */ | 204 | */ |
| 209 | ENTRY(__sie64a) | 205 | SYM_FUNC_START(__sie64a) |
| 210 | stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers | 206 | stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers |
| 211 | lg %r12,__LC_CURRENT | 207 | lg %r12,__LC_CURRENT |
| 212 | stg %r2,__SF_SIE_CONTROL_PHYS(%r15) # save sie block physical.. | 208 | stg %r2,__SF_SIE_CONTROL_PHYS(%r15) # save sie block physical.. |
| @@ -227,7 +223,7 @@ ENTRY(__sie64a) · 14 unmodified lines | |||
| 227 | TSTMSK __LC_CPU_FLAGS,_CIF_FPU | 223 | TSTMSK __LC_CPU_FLAGS,_CIF_FPU |
| 228 | jo .Lsie_skip # exit if fp/vx regs changed | 224 | jo .Lsie_skip # exit if fp/vx regs changed |
| 229 | lg %r14,__SF_SIE_CONTROL_PHYS(%r15) # get sie block phys addr | 225 | lg %r14,__SF_SIE_CONTROL_PHYS(%r15) # get sie block phys addr |
| 230 | BPEXIT __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) | 226 | BPEXIT __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST |
| 231 | .Lsie_entry: | 227 | .Lsie_entry: |
| 232 | sie 0(%r14) | 228 | sie 0(%r14) |
| 233 | # Let the next instruction be NOP to avoid triggering a machine check | 229 | # Let the next instruction be NOP to avoid triggering a machine check |
| @@ -235,7 +231,7 @@ ENTRY(__sie64a) · 1 unmodified line | |||
| 235 | nopr 7 | 231 | nopr 7 |
| 236 | .Lsie_leave: | 232 | .Lsie_leave: |
| 237 | BPOFF | 233 | BPOFF |
| 238 | BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) | 234 | BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST |
| 239 | .Lsie_skip: | 235 | .Lsie_skip: |
| 240 | lg %r14,__SF_SIE_CONTROL(%r15) # get control block pointer | 236 | lg %r14,__SF_SIE_CONTROL(%r15) # get control block pointer |
| 241 | ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE | 237 | ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE |
| @@ -252,8 +248,7 @@ ENTRY(__sie64a) · 10 unmodified lines | |||
| 252 | nopr 7 | 248 | nopr 7 |
| 253 | .Lrewind_pad2: | 249 | .Lrewind_pad2: |
| 254 | nopr 7 | 250 | nopr 7 |
| 255 | .globl sie_exit | 251 | SYM_INNER_LABEL(sie_exit, SYM_L_GLOBAL) |
| 256 | sie_exit: | ||
| 257 | lg %r14,__SF_SIE_SAVEAREA(%r15) # load guest register save area | 252 | lg %r14,__SF_SIE_SAVEAREA(%r15) # load guest register save area |
| 258 | stmg %r0,%r13,0(%r14) # save guest gprs 0-13 | 253 | stmg %r0,%r13,0(%r14) # save guest gprs 0-13 |
| 259 | xgr %r0,%r0 # clear guest registers to | 254 | xgr %r0,%r0 # clear guest registers to |
| @@ -273,7 +268,7 @@ sie_exit: · 13 unmodified lines | |||
| 273 | EX_TABLE(.Lrewind_pad4,.Lsie_fault) | 268 | EX_TABLE(.Lrewind_pad4,.Lsie_fault) |
| 274 | EX_TABLE(.Lrewind_pad2,.Lsie_fault) | 269 | EX_TABLE(.Lrewind_pad2,.Lsie_fault) |
| 275 | EX_TABLE(sie_exit,.Lsie_fault) | 270 | EX_TABLE(sie_exit,.Lsie_fault) |
| 276 | ENDPROC(__sie64a) | 271 | SYM_FUNC_END(__sie64a) |
| 277 | EXPORT_SYMBOL(__sie64a) | 272 | EXPORT_SYMBOL(__sie64a) |
| 278 | EXPORT_SYMBOL(sie_exit) | 273 | EXPORT_SYMBOL(sie_exit) |
| 279 | #endif | 274 | #endif |
| @@ -283,7 +278,7 @@ EXPORT_SYMBOL(sie_exit) · 3 unmodified lines | |||
| 283 | * are entered with interrupts disabled. | 278 | * are entered with interrupts disabled. |
| 284 | */ | 279 | */ |
| 285 | 280 | ||
| 286 | ENTRY(system_call) | 281 | SYM_CODE_START(system_call) |
| 287 | stpt __LC_SYS_ENTER_TIMER | 282 | stpt __LC_SYS_ENTER_TIMER |
| 288 | stmg %r8,%r15,__LC_SAVE_AREA_SYNC | 283 | stmg %r8,%r15,__LC_SAVE_AREA_SYNC |
| 289 | BPOFF | 284 | BPOFF |
| @@ -291,11 +286,9 @@ ENTRY(system_call) · 1 unmodified line | |||
| 291 | .Lsysc_per: | 286 | .Lsysc_per: |
| 292 | STBEAR __LC_LAST_BREAK | 287 | STBEAR __LC_LAST_BREAK |
| 293 | lctlg %c1,%c1,__LC_KERNEL_ASCE | 288 | lctlg %c1,%c1,__LC_KERNEL_ASCE |
| 294 | lg %r12,__LC_CURRENT | ||
| 295 | lg %r15,__LC_KERNEL_STACK | 289 | lg %r15,__LC_KERNEL_STACK |
| 296 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | 290 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
| 297 | stmg %r0,%r7,STACK_FRAME_OVERHEAD+__PT_R0(%r15) | 291 | stmg %r0,%r7,STACK_FRAME_OVERHEAD+__PT_R0(%r15) |
| 298 | BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP | ||
| 299 | # clear user controlled register to prevent speculative use | 292 | # clear user controlled register to prevent speculative use |
| 300 | xgr %r0,%r0 | 293 | xgr %r0,%r0 |
| 301 | xgr %r1,%r1 | 294 | xgr %r1,%r1 |
| @@ -312,39 +305,40 @@ ENTRY(system_call) · 10 unmodified lines | |||
| 312 | MBEAR %r2 | 305 | MBEAR %r2 |
| 313 | lgr %r3,%r14 | 306 | lgr %r3,%r14 |
| 314 | brasl %r14,__do_syscall | 307 | brasl %r14,__do_syscall |
| 308 | STACKLEAK_ERASE | ||
| 315 | lctlg %c1,%c1,__LC_USER_ASCE | 309 | lctlg %c1,%c1,__LC_USER_ASCE |
| 316 | mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15) | 310 | mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15) |
| 317 | BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP | 311 | BPON |
| 318 | LBEAR STACK_FRAME_OVERHEAD+__PT_LAST_BREAK(%r15) | 312 | LBEAR STACK_FRAME_OVERHEAD+__PT_LAST_BREAK(%r15) |
| 319 | lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15) | 313 | lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15) |
| 320 | stpt __LC_EXIT_TIMER | 314 | stpt __LC_EXIT_TIMER |
| 321 | LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE | 315 | LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE |
| 322 | ENDPROC(system_call) | 316 | SYM_CODE_END(system_call) |
| 323 | 317 | ||
| 324 | # | 318 | # |
| 325 | # a new process exits the kernel with ret_from_fork | 319 | # a new process exits the kernel with ret_from_fork |
| 326 | # | 320 | # |
| 327 | ENTRY(ret_from_fork) | 321 | SYM_CODE_START(ret_from_fork) |
| 328 | lgr %r3,%r11 | 322 | lgr %r3,%r11 |
| 329 | brasl %r14,__ret_from_fork | 323 | brasl %r14,__ret_from_fork |
| 324 | STACKLEAK_ERASE | ||
| 330 | lctlg %c1,%c1,__LC_USER_ASCE | 325 | lctlg %c1,%c1,__LC_USER_ASCE |
| 331 | mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15) | 326 | mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15) |
| 332 | BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP | 327 | BPON |
| 333 | LBEAR STACK_FRAME_OVERHEAD+__PT_LAST_BREAK(%r15) | 328 | LBEAR STACK_FRAME_OVERHEAD+__PT_LAST_BREAK(%r15) |
| 334 | lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15) | 329 | lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15) |
| 335 | stpt __LC_EXIT_TIMER | 330 | stpt __LC_EXIT_TIMER |
| 336 | LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE | 331 | LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE |
| 337 | ENDPROC(ret_from_fork) | 332 | SYM_CODE_END(ret_from_fork) |
| 338 | 333 | ||
| 339 | /* | 334 | /* |
| 340 | * Program check handler routine | 335 | * Program check handler routine |
| 341 | */ | 336 | */ |
| 342 | 337 | ||
| 343 | ENTRY(pgm_check_handler) | 338 | SYM_CODE_START(pgm_check_handler) |
| 344 | stpt __LC_SYS_ENTER_TIMER | 339 | stpt __LC_SYS_ENTER_TIMER |
| 345 | BPOFF | 340 | BPOFF |
| 346 | stmg %r8,%r15,__LC_SAVE_AREA_SYNC | 341 | stmg %r8,%r15,__LC_SAVE_AREA_SYNC |
| 347 | lg %r12,__LC_CURRENT | ||
| 348 | lghi %r10,0 | 342 | lghi %r10,0 |
| 349 | lmg %r8,%r9,__LC_PGM_OLD_PSW | 343 | lmg %r8,%r9,__LC_PGM_OLD_PSW |
| 350 | tmhh %r8,0x0001 # coming from user space? | 344 | tmhh %r8,0x0001 # coming from user space? |
| @@ -355,6 +349,7 @@ ENTRY(pgm_check_handler) · 4 unmodified lines | |||
| 355 | #if IS_ENABLED(CONFIG_KVM) | 349 | #if IS_ENABLED(CONFIG_KVM) |
| 356 | # cleanup critical section for program checks in __sie64a | 350 | # cleanup critical section for program checks in __sie64a |
| 357 | OUTSIDE %r9,.Lsie_gmap,.Lsie_done,1f | 351 | OUTSIDE %r9,.Lsie_gmap,.Lsie_done,1f |
| 352 | BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST | ||
| 358 | SIEEXIT | 353 | SIEEXIT |
| 359 | lghi %r10,_PIF_GUEST_FAULT | 354 | lghi %r10,_PIF_GUEST_FAULT |
| 360 | #endif | 355 | #endif |
| @@ -366,8 +361,7 @@ ENTRY(pgm_check_handler) · 5 unmodified lines | |||
| 366 | aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 361 | aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
| 367 | # CHECK_VMAP_STACK branches to stack_overflow or 4f | 362 | # CHECK_VMAP_STACK branches to stack_overflow or 4f |
| 368 | CHECK_VMAP_STACK __LC_SAVE_AREA_SYNC,4f | 363 | CHECK_VMAP_STACK __LC_SAVE_AREA_SYNC,4f |
| 369 | 3: BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP | 364 | 3: lg %r15,__LC_KERNEL_STACK |
| 370 | lg %r15,__LC_KERNEL_STACK | ||
| 371 | 4: la %r11,STACK_FRAME_OVERHEAD(%r15) | 365 | 4: la %r11,STACK_FRAME_OVERHEAD(%r15) |
| 372 | stg %r10,__PT_FLAGS(%r11) | 366 | stg %r10,__PT_FLAGS(%r11) |
| 373 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | 367 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
| @@ -388,8 +382,9 @@ ENTRY(pgm_check_handler) · 14 unmodified lines | |||
| 388 | brasl %r14,__do_pgm_check | 382 | brasl %r14,__do_pgm_check |
| 389 | tmhh %r8,0x0001 # returning to user space? | 383 | tmhh %r8,0x0001 # returning to user space? |
| 390 | jno .Lpgm_exit_kernel | 384 | jno .Lpgm_exit_kernel |
| 385 | STACKLEAK_ERASE | ||
| 391 | lctlg %c1,%c1,__LC_USER_ASCE | 386 | lctlg %c1,%c1,__LC_USER_ASCE |
| 392 | BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP | 387 | BPON |
| 393 | stpt __LC_EXIT_TIMER | 388 | stpt __LC_EXIT_TIMER |
| 394 | .Lpgm_exit_kernel: | 389 | .Lpgm_exit_kernel: |
| 395 | mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15) | 390 | mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15) |
| @@ -407,32 +402,30 @@ ENTRY(pgm_check_handler) · 11 unmodified lines | |||
| 407 | lghi %r14,1 | 402 | lghi %r14,1 |
| 408 | LBEAR __LC_PGM_LAST_BREAK | 403 | LBEAR __LC_PGM_LAST_BREAK |
| 409 | LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE # branch to .Lsysc_per | 404 | LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE # branch to .Lsysc_per |
| 410 | ENDPROC(pgm_check_handler) | 405 | SYM_CODE_END(pgm_check_handler) |
| 411 | 406 | ||
| 412 | /* | 407 | /* |
| 413 | * Interrupt handler macro used for external and IO interrupts. | 408 | * Interrupt handler macro used for external and IO interrupts. |
| 414 | */ | 409 | */ |
| 415 | .macro INT_HANDLER name,lc_old_psw,handler | 410 | .macro INT_HANDLER name,lc_old_psw,handler |
| 416 | ENTRY(\name) | 411 | SYM_CODE_START(\name) |
| 417 | stckf __LC_INT_CLOCK | 412 | stckf __LC_INT_CLOCK |
| 418 | stpt __LC_SYS_ENTER_TIMER | 413 | stpt __LC_SYS_ENTER_TIMER |
| 419 | STBEAR __LC_LAST_BREAK | 414 | STBEAR __LC_LAST_BREAK |
| 420 | BPOFF | 415 | BPOFF |
| 421 | stmg %r8,%r15,__LC_SAVE_AREA_ASYNC | 416 | stmg %r8,%r15,__LC_SAVE_AREA_ASYNC |
| 422 | lg %r12,__LC_CURRENT | ||
| 423 | lmg %r8,%r9,\lc_old_psw | 417 | lmg %r8,%r9,\lc_old_psw |
| 424 | tmhh %r8,0x0001 # interrupting from user ? | 418 | tmhh %r8,0x0001 # interrupting from user ? |
| 425 | jnz 1f | 419 | jnz 1f |
| 426 | #if IS_ENABLED(CONFIG_KVM) | 420 | #if IS_ENABLED(CONFIG_KVM) |
| 427 | OUTSIDE %r9,.Lsie_gmap,.Lsie_done,0f | 421 | OUTSIDE %r9,.Lsie_gmap,.Lsie_done,0f |
| 428 | BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) | 422 | BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST |
| 429 | SIEEXIT | 423 | SIEEXIT |
| 430 | #endif | 424 | #endif |
| 431 | 0: CHECK_STACK __LC_SAVE_AREA_ASYNC | 425 | 0: CHECK_STACK __LC_SAVE_AREA_ASYNC |
| 432 | aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 426 | aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
| 433 | j 2f | 427 | j 2f |
| 434 | 1: BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP | 428 | 1: lctlg %c1,%c1,__LC_KERNEL_ASCE |
| 435 | lctlg %c1,%c1,__LC_KERNEL_ASCE | ||
| 436 | lg %r15,__LC_KERNEL_STACK | 429 | lg %r15,__LC_KERNEL_STACK |
| 437 | 2: xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | 430 | 2: xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
| 438 | la %r11,STACK_FRAME_OVERHEAD(%r15) | 431 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
| @@ -455,13 +448,14 @@ ENTRY(\name) · 16 unmodified lines | |||
| 455 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) | 448 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) |
| 456 | tmhh %r8,0x0001 # returning to user ? | 449 | tmhh %r8,0x0001 # returning to user ? |
| 457 | jno 2f | 450 | jno 2f |
| 451 | STACKLEAK_ERASE | ||
| 458 | lctlg %c1,%c1,__LC_USER_ASCE | 452 | lctlg %c1,%c1,__LC_USER_ASCE |
| 459 | BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP | 453 | BPON |
| 460 | stpt __LC_EXIT_TIMER | 454 | stpt __LC_EXIT_TIMER |
| 461 | 2: LBEAR __PT_LAST_BREAK(%r11) | 455 | 2: LBEAR __PT_LAST_BREAK(%r11) |
| 462 | lmg %r0,%r15,__PT_R0(%r11) | 456 | lmg %r0,%r15,__PT_R0(%r11) |
| 463 | LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE | 457 | LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE |
| 464 | ENDPROC(\name) | 458 | SYM_CODE_END(\name) |
| 465 | .endm | 459 | .endm |
| 466 | 460 | ||
| 467 | INT_HANDLER ext_int_handler,__LC_EXT_OLD_PSW,do_ext_irq | 461 | INT_HANDLER ext_int_handler,__LC_EXT_OLD_PSW,do_ext_irq |
| @@ -470,7 +464,7 @@ INT_HANDLER io_int_handler,__LC_IO_OLD_PSW,do_io_irq · 2 unmodified lines | |||
| 470 | /* | 464 | /* |
| 471 | * Load idle PSW. | 465 | * Load idle PSW. |
| 472 | */ | 466 | */ |
| 473 | ENTRY(psw_idle) | 467 | SYM_FUNC_START(psw_idle) |
| 474 | stg %r14,(__SF_GPRS+8*8)(%r15) | 468 | stg %r14,(__SF_GPRS+8*8)(%r15) |
| 475 | stg %r3,__SF_EMPTY(%r15) | 469 | stg %r3,__SF_EMPTY(%r15) |
| 476 | larl %r1,psw_idle_exit | 470 | larl %r1,psw_idle_exit |
| @@ -486,29 +480,26 @@ ENTRY(psw_idle) · 9 unmodified lines | |||
| 486 | stckf __CLOCK_IDLE_ENTER(%r2) | 480 | stckf __CLOCK_IDLE_ENTER(%r2) |
| 487 | stpt __TIMER_IDLE_ENTER(%r2) | 481 | stpt __TIMER_IDLE_ENTER(%r2) |
| 488 | lpswe __SF_EMPTY(%r15) | 482 | lpswe __SF_EMPTY(%r15) |
| 489 | .globl psw_idle_exit | 483 | SYM_INNER_LABEL(psw_idle_exit, SYM_L_GLOBAL) |
| 490 | psw_idle_exit: | ||
| 491 | BR_EX %r14 | 484 | BR_EX %r14 |
| 492 | ENDPROC(psw_idle) | 485 | SYM_FUNC_END(psw_idle) |
| 493 | 486 | ||
| 494 | /* | 487 | /* |
| 495 | * Machine check handler routines | 488 | * Machine check handler routines |
| 496 | */ | 489 | */ |
| 497 | ENTRY(mcck_int_handler) | 490 | SYM_CODE_START(mcck_int_handler) |
| 498 | stckf __LC_MCCK_CLOCK | 491 | stckf __LC_MCCK_CLOCK |
| 499 | BPOFF | 492 | BPOFF |
| 500 | la %r1,4095 # validate r1 | 493 | la %r1,4095 # validate r1 |
| 501 | spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # validate cpu timer | 494 | spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # validate cpu timer |
| 502 | LBEAR __LC_LAST_BREAK_SAVE_AREA-4095(%r1) # validate bear | 495 | LBEAR __LC_LAST_BREAK_SAVE_AREA-4095(%r1) # validate bear |
| 503 | lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# validate gprs | 496 | lmg %r0,%r15,__LC_GPREGS_SAVE_AREA # validate gprs |
| 504 | lg %r12,__LC_CURRENT | ||
| 505 | lmg %r8,%r9,__LC_MCK_OLD_PSW | 497 | lmg %r8,%r9,__LC_MCK_OLD_PSW |
| 506 | TSTMSK __LC_MCCK_CODE,MCCK_CODE_SYSTEM_DAMAGE | 498 | TSTMSK __LC_MCCK_CODE,MCCK_CODE_SYSTEM_DAMAGE |
| 507 | jo .Lmcck_panic # yes -> rest of mcck code invalid | 499 | jo .Lmcck_panic # yes -> rest of mcck code invalid |
| 508 | TSTMSK __LC_MCCK_CODE,MCCK_CODE_CR_VALID | 500 | TSTMSK __LC_MCCK_CODE,MCCK_CODE_CR_VALID |
| 509 | jno .Lmcck_panic # control registers invalid -> panic | 501 | jno .Lmcck_panic # control registers invalid -> panic |
| 510 | la %r14,4095 | 502 | lctlg %c0,%c15,__LC_CREGS_SAVE_AREA # validate ctl regs |
| 511 | lctlg %c0,%c15,__LC_CREGS_SAVE_AREA-4095(%r14) # validate ctl regs | ||
| 512 | ptlb | 503 | ptlb |
| 513 | lghi %r14,__LC_CPU_TIMER_SAVE_AREA | 504 | lghi %r14,__LC_CPU_TIMER_SAVE_AREA |
| 514 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) | 505 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) |
| @@ -530,16 +521,13 @@ ENTRY(mcck_int_handler) · 15 unmodified lines | |||
| 530 | TSTMSK __LC_MCCK_CODE,MCCK_CODE_PSW_IA_VALID | 521 | TSTMSK __LC_MCCK_CODE,MCCK_CODE_PSW_IA_VALID |
| 531 | jno .Lmcck_panic | 522 | jno .Lmcck_panic |
| 532 | #if IS_ENABLED(CONFIG_KVM) | 523 | #if IS_ENABLED(CONFIG_KVM) |
| 533 | OUTSIDE %r9,.Lsie_gmap,.Lsie_done,.Lmcck_stack | 524 | OUTSIDE %r9,.Lsie_gmap,.Lsie_done,.Lmcck_user |
| 534 | OUTSIDE %r9,.Lsie_entry,.Lsie_leave,4f | 525 | OUTSIDE %r9,.Lsie_entry,.Lsie_leave,4f |
| 535 | oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST | 526 | oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST |
| 536 | 4: BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) | 527 | 4: BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST |
| 537 | SIEEXIT | 528 | SIEEXIT |
| 538 | j .Lmcck_stack | ||
| 539 | #endif | 529 | #endif |
| 540 | .Lmcck_user: | 530 | .Lmcck_user: |
| 541 | BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP | ||
| 542 | .Lmcck_stack: | ||
| 543 | lg %r15,__LC_MCCK_STACK | 531 | lg %r15,__LC_MCCK_STACK |
| 544 | la %r11,STACK_FRAME_OVERHEAD(%r15) | 532 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
| 545 | stctg %c1,%c1,__PT_CR1(%r11) | 533 | stctg %c1,%c1,__PT_CR1(%r11) |
| @@ -567,7 +555,7 @@ ENTRY(mcck_int_handler) · 21 unmodified lines | |||
| 567 | mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW | 555 | mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW |
| 568 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? | 556 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? |
| 569 | jno 0f | 557 | jno 0f |
| 570 | BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP | 558 | BPON |
| 571 | stpt __LC_EXIT_TIMER | 559 | stpt __LC_EXIT_TIMER |
| 572 | 0: ALTERNATIVE "nop", __stringify(lghi %r12,__LC_LAST_BREAK_SAVE_AREA),193 | 560 | 0: ALTERNATIVE "nop", __stringify(lghi %r12,__LC_LAST_BREAK_SAVE_AREA),193 |
| 573 | LBEAR 0(%r12) | 561 | LBEAR 0(%r12) |
| @@ -583,10 +571,10 @@ ENTRY(mcck_int_handler) · 9 unmodified lines | |||
| 583 | */ | 571 | */ |
| 584 | lhi %r5,0 | 572 | lhi %r5,0 |
| 585 | lhi %r6,1 | 573 | lhi %r6,1 |
| 586 | larl %r7,.Lstop_lock | 574 | larl %r7,stop_lock |
| 587 | cs %r5,%r6,0(%r7) # single CPU-stopper only | 575 | cs %r5,%r6,0(%r7) # single CPU-stopper only |
| 588 | jnz 4f | 576 | jnz 4f |
| 589 | larl %r7,.Lthis_cpu | 577 | larl %r7,this_cpu |
| 590 | stap 0(%r7) # this CPU address | 578 | stap 0(%r7) # this CPU address |
| 591 | lh %r4,0(%r7) | 579 | lh %r4,0(%r7) |
| 592 | nilh %r4,0 | 580 | nilh %r4,0 |
| @@ -602,16 +590,15 @@ ENTRY(mcck_int_handler) · 9 unmodified lines | |||
| 602 | 3: sigp %r1,%r4,SIGP_STOP # stop this CPU | 590 | 3: sigp %r1,%r4,SIGP_STOP # stop this CPU |
| 603 | brc SIGP_CC_BUSY,3b | 591 | brc SIGP_CC_BUSY,3b |
| 604 | 4: j 4b | 592 | 4: j 4b |
| 605 | ENDPROC(mcck_int_handler) | 593 | SYM_CODE_END(mcck_int_handler) |
| 606 | 594 | ||
| 607 | ENTRY(restart_int_handler) | 595 | SYM_CODE_START(restart_int_handler) |
| 608 | ALTERNATIVE "nop", "lpp _LPP_OFFSET", 40 | 596 | ALTERNATIVE "nop", "lpp _LPP_OFFSET", 40 |
| 609 | stg %r15,__LC_SAVE_AREA_RESTART | 597 | stg %r15,__LC_SAVE_AREA_RESTART |
| 610 | TSTMSK __LC_RESTART_FLAGS,RESTART_FLAG_CTLREGS,4 | 598 | TSTMSK __LC_RESTART_FLAGS,RESTART_FLAG_CTLREGS,4 |
| 611 | jz 0f | 599 | jz 0f |
| 612 | la %r15,4095 | 600 | lctlg %c0,%c15,__LC_CREGS_SAVE_AREA |
| 613 | lctlg %c0,%c15,__LC_CREGS_SAVE_AREA-4095(%r15) | 601 | 0: larl %r15,stosm_tmp |
| 614 | 0: larl %r15,.Lstosm_tmp | ||
| 615 | stosm 0(%r15),0x04 # turn dat on, keep irqs off | 602 | stosm 0(%r15),0x04 # turn dat on, keep irqs off |
| 616 | lg %r15,__LC_RESTART_STACK | 603 | lg %r15,__LC_RESTART_STACK |
| 617 | xc STACK_FRAME_OVERHEAD(__PT_SIZE,%r15),STACK_FRAME_OVERHEAD(%r15) | 604 | xc STACK_FRAME_OVERHEAD(__PT_SIZE,%r15),STACK_FRAME_OVERHEAD(%r15) |
| @@ -632,7 +619,7 @@ ENTRY(restart_int_handler) · 14 unmodified lines | |||
| 632 | 2: sigp %r4,%r3,SIGP_STOP # sigp stop to current cpu | 619 | 2: sigp %r4,%r3,SIGP_STOP # sigp stop to current cpu |
| 633 | brc 2,2b | 620 | brc 2,2b |
| 634 | 3: j 3b | 621 | 3: j 3b |
| 635 | ENDPROC(restart_int_handler) | 622 | SYM_CODE_END(restart_int_handler) |
| 636 | 623 | ||
| 637 | .section .kprobes.text, "ax" | 624 | .section .kprobes.text, "ax" |
| 638 | 625 | ||
| @@ -642,7 +629,7 @@ ENDPROC(restart_int_handler) · 3 unmodified lines | |||
| 642 | * No need to properly save the registers, we are going to panic anyway. | 629 | * No need to properly save the registers, we are going to panic anyway. |
| 643 | * Setup a pt_regs so that show_trace can provide a good call trace. | 630 | * Setup a pt_regs so that show_trace can provide a good call trace. |
| 644 | */ | 631 | */ |
| 645 | ENTRY(stack_overflow) | 632 | SYM_CODE_START(stack_overflow) |
| 646 | lg %r15,__LC_NODAT_STACK # change to panic stack | 633 | lg %r15,__LC_NODAT_STACK # change to panic stack |
| 647 | la %r11,STACK_FRAME_OVERHEAD(%r15) | 634 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
| 648 | stmg %r0,%r7,__PT_R0(%r11) | 635 | stmg %r0,%r7,__PT_R0(%r11) |
| @@ -652,26 +639,27 @@ ENTRY(stack_overflow) · 3 unmodified lines | |||
| 652 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | 639 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
| 653 | lgr %r2,%r11 # pass pointer to pt_regs | 640 | lgr %r2,%r11 # pass pointer to pt_regs |
| 654 | jg kernel_stack_overflow | 641 | jg kernel_stack_overflow |
| 655 | ENDPROC(stack_overflow) | 642 | SYM_CODE_END(stack_overflow) |
| 656 | #endif | 643 | #endif |
| 657 | 644 | ||
| 658 | .section .data, "aw" | 645 | .section .data, "aw" |
| 659 | .align 4 | 646 | .balign 4 |
| 660 | .Lstop_lock: .long 0 | 647 | SYM_DATA_LOCAL(stop_lock, .long 0) |
| 661 | .Lthis_cpu: .short 0 | 648 | SYM_DATA_LOCAL(this_cpu, .short 0) |
| 662 | .Lstosm_tmp: .byte 0 | 649 | SYM_DATA_LOCAL(stosm_tmp, .byte 0) |
| 650 | |||
| 663 | .section .rodata, "a" | 651 | .section .rodata, "a" |
| 664 | #define SYSCALL(esame,emu) .quad __s390x_ ## esame | 652 | #define SYSCALL(esame,emu) .quad __s390x_ ## esame |
| 665 | .globl sys_call_table | 653 | SYM_DATA_START(sys_call_table) |
| 666 | sys_call_table: | ||
| 667 | #include "asm/syscall_table.h" | 654 | #include "asm/syscall_table.h" |
| 655 | SYM_DATA_END(sys_call_table) | ||
| 668 | #undef SYSCALL | 656 | #undef SYSCALL |
| 669 | 657 | ||
| 670 | #ifdef CONFIG_COMPAT | 658 | #ifdef CONFIG_COMPAT |
| 671 | 659 | ||
| 672 | #define SYSCALL(esame,emu) .quad __s390_ ## emu | 660 | #define SYSCALL(esame,emu) .quad __s390_ ## emu |
| 673 | .globl sys_call_table_emu | 661 | SYM_DATA_START(sys_call_table_emu) |
| 674 | sys_call_table_emu: | ||
| 675 | #include "asm/syscall_table.h" | 662 | #include "asm/syscall_table.h" |
| 663 | SYM_DATA_END(sys_call_table_emu) | ||
| 676 | #undef SYSCALL | 664 | #undef SYSCALL |
| 677 | #endif | 665 | #endif |
| @@ -49,26 +49,6 @@ struct ftrace_insn { · 48 unmodified lines | |||
| 49 | s32 disp; | 49 | s32 disp; |
| 50 | } __packed; | 50 | } __packed; |
| 51 | 51 | ||
| 52 | asm( | ||
| 53 | " .align 16\n" | ||
| 54 | "ftrace_shared_hotpatch_trampoline_br:\n" | ||
| 55 | " lmg %r0,%r1,2(%r1)\n" | ||
| 56 | " br %r1\n" | ||
| 57 | "ftrace_shared_hotpatch_trampoline_br_end:\n" | ||
| 58 | ); | ||
| 59 | |||
| 60 | #ifdef CONFIG_EXPOLINE | ||
| 61 | asm( | ||
| 62 | " .align 16\n" | ||
| 63 | "ftrace_shared_hotpatch_trampoline_exrl:\n" | ||
| 64 | " lmg %r0,%r1,2(%r1)\n" | ||
| 65 | " exrl %r0,0f\n" | ||
| 66 | " j .\n" | ||
| 67 | "0: br %r1\n" | ||
| 68 | "ftrace_shared_hotpatch_trampoline_exrl_end:\n" | ||
| 69 | ); | ||
| 70 | #endif /* CONFIG_EXPOLINE */ | ||
| 71 | |||
| 72 | #ifdef CONFIG_MODULES | 52 | #ifdef CONFIG_MODULES |
| 73 | static char *ftrace_plt; | 53 | static char *ftrace_plt; |
| 74 | #endif /* CONFIG_MODULES */ | 54 | #endif /* CONFIG_MODULES */ |
| @@ -246,7 +226,7 @@ static int __init ftrace_plt_init(void) · 171 unmodified lines | |||
| 246 | 226 | ||
| 247 | start = ftrace_shared_hotpatch_trampoline(&end); | 227 | start = ftrace_shared_hotpatch_trampoline(&end); |
| 248 | memcpy(ftrace_plt, start, end - start); | 228 | memcpy(ftrace_plt, start, end - start); |
| 249 | set_memory_ro((unsigned long)ftrace_plt, 1); | 229 | set_memory_rox((unsigned long)ftrace_plt, 1); |
| 250 | return 0; | 230 | return 0; |
| 251 | } | 231 | } |
| 252 | device_initcall(ftrace_plt_init); | 232 | device_initcall(ftrace_plt_init); |
| @@ -16,7 +16,7 @@ · 15 unmodified lines | |||
| 16 | #include <asm/ptrace.h> | 16 | #include <asm/ptrace.h> |
| 17 | 17 | ||
| 18 | __HEAD | 18 | __HEAD |
| 19 | ENTRY(startup_continue) | 19 | SYM_CODE_START(startup_continue) |
| 20 | larl %r1,tod_clock_base | 20 | larl %r1,tod_clock_base |
| 21 | mvc 0(16,%r1),__LC_BOOT_CLOCK | 21 | mvc 0(16,%r1),__LC_BOOT_CLOCK |
| 22 | # | 22 | # |
| @@ -24,19 +24,17 @@ ENTRY(startup_continue) · 1 unmodified line | |||
| 24 | # | 24 | # |
| 25 | larl %r14,init_task | 25 | larl %r14,init_task |
| 26 | stg %r14,__LC_CURRENT | 26 | stg %r14,__LC_CURRENT |
| 27 | larl %r15,init_thread_union+THREAD_SIZE-STACK_FRAME_OVERHEAD-__PT_SIZE | 27 | larl %r15,init_thread_union+STACK_INIT_OFFSET |
| 28 | stg %r15,__LC_KERNEL_STACK | ||
| 28 | brasl %r14,sclp_early_adjust_va # allow sclp_early_printk | 29 | brasl %r14,sclp_early_adjust_va # allow sclp_early_printk |
| 29 | #ifdef CONFIG_KASAN | ||
| 30 | brasl %r14,kasan_early_init | ||
| 31 | #endif | ||
| 32 | brasl %r14,startup_init # s390 specific early init | 30 | brasl %r14,startup_init # s390 specific early init |
| 33 | brasl %r14,start_kernel # common init code | 31 | brasl %r14,start_kernel # common init code |
| 34 | # | 32 | # |
| 35 | # We returned from start_kernel ?!? PANIK | 33 | # We returned from start_kernel ?!? PANIK |
| 36 | # | 34 | # |
| 37 | basr %r13,0 | 35 | basr %r13,0 |
| 38 | lpswe .Ldw-.(%r13) # load disabled wait psw | 36 | lpswe dw_psw-.(%r13) # load disabled wait psw |
| 37 | SYM_CODE_END(startup_continue) | ||
| 39 | 38 | ||
| 40 | .align 16 | 39 | .align 16 |
| 41 | .LPG1: | 40 | SYM_DATA_LOCAL(dw_psw, .quad 0x0002000180000000,0x0000000000000000) |
| 42 | .Ldw: .quad 0x0002000180000000,0x0000000000000000 | ||
| @@ -176,11 +176,11 @@ static bool reipl_fcp_clear; · 175 unmodified lines | |||
| 176 | static bool reipl_ccw_clear; | 176 | static bool reipl_ccw_clear; |
| 177 | static bool reipl_eckd_clear; | 177 | static bool reipl_eckd_clear; |
| 178 | 178 | ||
| 179 | static inline int __diag308(unsigned long subcode, void *addr) | 179 | static inline int __diag308(unsigned long subcode, unsigned long addr) |
| 180 | { | 180 | { |
| 181 | union register_pair r1; | 181 | union register_pair r1; |
| 182 | 182 | ||
| 183 | r1.even = (unsigned long) addr; | 183 | r1.even = addr; |
| 184 | r1.odd = 0; | 184 | r1.odd = 0; |
| 185 | asm volatile( | 185 | asm volatile( |
| 186 | " diag %[r1],%[subcode],0x308\n" | 186 | " diag %[r1],%[subcode],0x308\n" |
| @@ -195,7 +195,7 @@ static inline int __diag308(unsigned long subcode, void *addr) · 8 unmodified lines | |||
| 195 | int diag308(unsigned long subcode, void *addr) | 195 | int diag308(unsigned long subcode, void *addr) |
| 196 | { | 196 | { |
| 197 | diag_stat_inc(DIAG_STAT_X308); | 197 | diag_stat_inc(DIAG_STAT_X308); |
| 198 | return __diag308(subcode, addr); | 198 | return __diag308(subcode, addr ? virt_to_phys(addr) : 0); |
| 199 | } | 199 | } |
| 200 | EXPORT_SYMBOL_GPL(diag308); | 200 | EXPORT_SYMBOL_GPL(diag308); |
| 201 | 201 | ||
| @@ -649,7 +649,6 @@ static struct kset *ipl_kset; · 447 unmodified lines | |||
| 649 | 649 | ||
| 650 | static void __ipl_run(void *unused) | 650 | static void __ipl_run(void *unused) |
| 651 | { | 651 | { |
| 652 | __bpon(); | ||
| 653 | diag308(DIAG308_LOAD_CLEAR, NULL); | 652 | diag308(DIAG308_LOAD_CLEAR, NULL); |
| 654 | } | 653 | } |
| 655 | 654 | ||
| @@ -41,7 +41,7 @@ void *alloc_insn_page(void) · 40 unmodified lines | |||
| 41 | page = module_alloc(PAGE_SIZE); | 41 | page = module_alloc(PAGE_SIZE); |
| 42 | if (!page) | 42 | if (!page) |
| 43 | return NULL; | 43 | return NULL; |
| 44 | __set_memory((unsigned long) page, 1, SET_MEMORY_RO | SET_MEMORY_X); | 44 | set_memory_rox((unsigned long)page, 1); |
| 45 | return page; | 45 | return page; |
| 46 | } | 46 | } |
| 47 | 47 | ||
| @@ -14,9 +14,9 @@ · 13 unmodified lines | |||
| 14 | */ | 14 | */ |
| 15 | .section .kprobes.text, "ax" | 15 | .section .kprobes.text, "ax" |
| 16 | .align 4096 | 16 | .align 4096 |
| 17 | ENTRY(kprobes_insn_page) | 17 | SYM_CODE_START(kprobes_insn_page) |
| 18 | .rept 2048 | 18 | .rept 2048 |
| 19 | .word 0x07fe | 19 | .word 0x07fe |
| 20 | .endr | 20 | .endr |
| 21 | ENDPROC(kprobes_insn_page) | 21 | SYM_CODE_END(kprobes_insn_page) |
| 22 | .previous | 22 | .previous |
| @@ -29,8 +29,8 @@ · 28 unmodified lines | |||
| 29 | #include <asm/nmi.h> | 29 | #include <asm/nmi.h> |
| 30 | #include <asm/sclp.h> | 30 | #include <asm/sclp.h> |
| 31 | 31 | ||
| 32 | typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long, | 32 | typedef void (*relocate_kernel_t)(unsigned long, unsigned long, unsigned long); |
| 33 | unsigned long); | 33 | typedef int (*purgatory_t)(int); |
| 34 | 34 | ||
| 35 | extern const unsigned char relocate_kernel[]; | 35 | extern const unsigned char relocate_kernel[]; |
| 36 | extern const unsigned long long relocate_kernel_len; | 36 | extern const unsigned long long relocate_kernel_len; |
| @@ -41,11 +41,14 @@ extern const unsigned long long relocate_kernel_len; · 4 unmodified lines | |||
| 41 | * Reset the system, copy boot CPU registers to absolute zero, | 41 | * Reset the system, copy boot CPU registers to absolute zero, |
| 42 | * and jump to the kdump image | 42 | * and jump to the kdump image |
| 43 | */ | 43 | */ |
| 44 | static void __do_machine_kdump(void *image) | 44 | static void __do_machine_kdump(void *data) |
| 45 | { | 45 | { |
| 46 | int (*start_kdump)(int); | 46 | struct kimage *image = data; |
| 47 | purgatory_t purgatory; | ||
| 47 | unsigned long prefix; | 48 | unsigned long prefix; |
| 48 | 49 | ||
| 50 | purgatory = (purgatory_t)image->start; | ||
| 51 | |||
| 49 | /* store_status() saved the prefix register to lowcore */ | 52 | /* store_status() saved the prefix register to lowcore */ |
| 50 | prefix = (unsigned long) S390_lowcore.prefixreg_save_area; | 53 | prefix = (unsigned long) S390_lowcore.prefixreg_save_area; |
| 51 | 54 | ||
| @@ -58,13 +61,11 @@ static void __do_machine_kdump(void *image) · 6 unmodified lines | |||
| 58 | * prefix register of this CPU to zero | 61 | * prefix register of this CPU to zero |
| 59 | */ | 62 | */ |
| 60 | memcpy(absolute_pointer(__LC_FPREGS_SAVE_AREA), | 63 | memcpy(absolute_pointer(__LC_FPREGS_SAVE_AREA), |
| 61 | (void *)(prefix + __LC_FPREGS_SAVE_AREA), 512); | 64 | phys_to_virt(prefix + __LC_FPREGS_SAVE_AREA), 512); |
| 62 | 65 | ||
| 63 | __load_psw_mask(PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA); | 66 | call_nodat(1, int, purgatory, int, 1); |
| 64 | start_kdump = (void *)((struct kimage *) image)->start; | ||
| 65 | start_kdump(1); | ||
| 66 | 67 | ||
| 67 | /* Die if start_kdump returns */ | 68 | /* Die if kdump returns */ |
| 68 | disabled_wait(); | 69 | disabled_wait(); |
| 69 | } | 70 | } |
| 70 | 71 | ||
| @@ -111,18 +112,6 @@ static noinline void __machine_kdump(void *image) · 40 unmodified lines | |||
| 111 | store_status(__do_machine_kdump, image); | 112 | store_status(__do_machine_kdump, image); |
| 112 | } | 113 | } |
| 113 | 114 | ||
| 114 | static unsigned long do_start_kdump(unsigned long addr) | ||
| 115 | { | ||
| 116 | struct kimage *image = (struct kimage *) addr; | ||
| 117 | int (*start_kdump)(int) = (void *)image->start; | ||
| 118 | int rc; | ||
| 119 | |||
| 120 | __arch_local_irq_stnsm(0xfb); /* disable DAT */ | ||
| 121 | rc = start_kdump(0); | ||
| 122 | __arch_local_irq_stosm(0x04); /* enable DAT */ | ||
| 123 | return rc; | ||
| 124 | } | ||
| 125 | |||
| 126 | #endif /* CONFIG_CRASH_DUMP */ | 115 | #endif /* CONFIG_CRASH_DUMP */ |
| 127 | 116 | ||
| 128 | /* | 117 | /* |
| @@ -131,12 +120,10 @@ static unsigned long do_start_kdump(unsigned long addr) · 2 unmodified lines | |||
| 131 | static bool kdump_csum_valid(struct kimage *image) | 120 | static bool kdump_csum_valid(struct kimage *image) |
| 132 | { | 121 | { |
| 133 | #ifdef CONFIG_CRASH_DUMP | 122 | #ifdef CONFIG_CRASH_DUMP |
| 123 | purgatory_t purgatory = (purgatory_t)image->start; | ||
| 134 | int rc; | 124 | int rc; |
| 135 | 125 | ||
| 136 | preempt_disable(); | 126 | rc = call_nodat(1, int, purgatory, int, 0); |
| 137 | rc = call_on_stack(1, S390_lowcore.nodat_stack, unsigned long, do_start_kdump, | ||
| 138 | unsigned long, (unsigned long)image); | ||
| 139 | preempt_enable(); | ||
| 140 | return rc == 0; | 127 | return rc == 0; |
| 141 | #else | 128 | #else |
| 142 | return false; | 129 | return false; |
| @@ -210,7 +197,7 @@ int machine_kexec_prepare(struct kimage *image) · 67 unmodified lines | |||
| 210 | return -EINVAL; | 197 | return -EINVAL; |
| 211 | 198 | ||
| 212 | /* Get the destination where the assembler code should be copied to.*/ | 199 | /* Get the destination where the assembler code should be copied to.*/ |
| 213 | reboot_code_buffer = (void *) page_to_phys(image->control_code_page); | 200 | reboot_code_buffer = page_to_virt(image->control_code_page); |
| 214 | 201 | ||
| 215 | /* Then copy it */ | 202 | /* Then copy it */ |
| 216 | memcpy(reboot_code_buffer, relocate_kernel, relocate_kernel_len); | 203 | memcpy(reboot_code_buffer, relocate_kernel, relocate_kernel_len); |
| @@ -250,19 +237,20 @@ void machine_crash_shutdown(struct pt_regs *regs) · 33 unmodified lines | |||
| 250 | */ | 237 | */ |
| 251 | static void __do_machine_kexec(void *data) | 238 | static void __do_machine_kexec(void *data) |
| 252 | { | 239 | { |
| 253 | unsigned long diag308_subcode; | 240 | unsigned long data_mover, entry, diag308_subcode; |
| 254 | relocate_kernel_t data_mover; | ||
| 255 | struct kimage *image = data; | 241 | struct kimage *image = data; |
| 256 | 242 | ||
| 257 | s390_reset_system(); | 243 | data_mover = page_to_phys(image->control_code_page); |
| 258 | data_mover = (relocate_kernel_t) page_to_phys(image->control_code_page); | 244 | entry = virt_to_phys(&image->head); |
| 259 | |||
| 260 | __arch_local_irq_stnsm(0xfb); /* disable DAT - avoid no-execute */ | ||
| 261 | /* Call the moving routine */ | ||
| 262 | diag308_subcode = DIAG308_CLEAR_RESET; | 245 | diag308_subcode = DIAG308_CLEAR_RESET; |
| 263 | if (sclp.has_iplcc) | 246 | if (sclp.has_iplcc) |
| 264 | diag308_subcode |= DIAG308_FLAG_EI; | 247 | diag308_subcode |= DIAG308_FLAG_EI; |
| 265 | (*data_mover)(&image->head, image->start, diag308_subcode); | 248 | s390_reset_system(); |
| 249 | |||
| 250 | call_nodat(3, void, (relocate_kernel_t)data_mover, | ||
| 251 | unsigned long, entry, | ||
| 252 | unsigned long, image->start, | ||
| 253 | unsigned long, diag308_subcode); | ||
| 266 | 254 | ||
| 267 | /* Die if kexec returns */ | 255 | /* Die if kexec returns */ |
| 268 | disabled_wait(); | 256 | disabled_wait(); |
| @@ -28,9 +28,9 @@ · 27 unmodified lines | |||
| 28 | 28 | ||
| 29 | .section .kprobes.text, "ax" | 29 | .section .kprobes.text, "ax" |
| 30 | 30 | ||
| 31 | ENTRY(ftrace_stub) | 31 | SYM_FUNC_START(ftrace_stub) |
| 32 | BR_EX %r14 | 32 | BR_EX %r14 |
| 33 | ENDPROC(ftrace_stub) | 33 | SYM_FUNC_END(ftrace_stub) |
| 34 | 34 | ||
| 35 | SYM_CODE_START(ftrace_stub_direct_tramp) | 35 | SYM_CODE_START(ftrace_stub_direct_tramp) |
| 36 | lgr %r1, %r0 | 36 | lgr %r1, %r0 |
| @@ -140,10 +140,25 @@ SYM_FUNC_END(return_to_handler) · 103 unmodified lines | |||
| 140 | #endif | 140 | #endif |
| 141 | #endif /* CONFIG_FUNCTION_TRACER */ | 141 | #endif /* CONFIG_FUNCTION_TRACER */ |
| 142 | 142 | ||
| 143 | #ifdef CONFIG_RETHOOK | 143 | SYM_CODE_START(ftrace_shared_hotpatch_trampoline_br) |
| 144 | lmg %r0,%r1,2(%r1) | ||
| 145 | br %r1 | ||
| 146 | SYM_INNER_LABEL(ftrace_shared_hotpatch_trampoline_br_end, SYM_L_GLOBAL) | ||
| 147 | SYM_CODE_END(ftrace_shared_hotpatch_trampoline_br) | ||
| 148 | |||
| 149 | #ifdef CONFIG_EXPOLINE | ||
| 150 | SYM_CODE_START(ftrace_shared_hotpatch_trampoline_exrl) | ||
| 151 | lmg %r0,%r1,2(%r1) | ||
| 152 | exrl %r0,0f | ||
| 153 | j . | ||
| 154 | 0: br %r1 | ||
| 155 | SYM_INNER_LABEL(ftrace_shared_hotpatch_trampoline_exrl_end, SYM_L_GLOBAL) | ||
| 156 | SYM_CODE_END(ftrace_shared_hotpatch_trampoline_exrl) | ||
| 157 | #endif /* CONFIG_EXPOLINE */ | ||
| 144 | 158 | ||
| 145 | SYM_FUNC_START(arch_rethook_trampoline) | 159 | #ifdef CONFIG_RETHOOK |
| 146 | 160 | ||
| 161 | SYM_CODE_START(arch_rethook_trampoline) | ||
| 147 | stg %r14,(__SF_GPRS+8*8)(%r15) | 162 | stg %r14,(__SF_GPRS+8*8)(%r15) |
| 148 | lay %r15,-STACK_FRAME_SIZE(%r15) | 163 | lay %r15,-STACK_FRAME_SIZE(%r15) |
| 149 | stmg %r0,%r14,STACK_PTREGS_GPRS(%r15) | 164 | stmg %r0,%r14,STACK_PTREGS_GPRS(%r15) |
| @@ -166,7 +181,6 @@ SYM_FUNC_START(arch_rethook_trampoline) · 16 unmodified lines | |||
| 166 | mvc __SF_EMPTY(16,%r7),STACK_PTREGS_PSW(%r15) | 181 | mvc __SF_EMPTY(16,%r7),STACK_PTREGS_PSW(%r15) |
| 167 | lmg %r0,%r15,STACK_PTREGS_GPRS(%r15) | 182 | lmg %r0,%r15,STACK_PTREGS_GPRS(%r15) |
| 168 | lpswe __SF_EMPTY(%r15) | 183 | lpswe __SF_EMPTY(%r15) |
| 169 | 184 | SYM_CODE_END(arch_rethook_trampoline) | |
| 170 | SYM_FUNC_END(arch_rethook_trampoline) | ||
| 171 | 185 | ||
| 172 | #endif /* CONFIG_RETHOOK */ | 186 | #endif /* CONFIG_RETHOOK */ |
| @@ -26,6 +26,7 @@ · 25 unmodified lines | |||
| 26 | #include <asm/facility.h> | 26 | #include <asm/facility.h> |
| 27 | #include <asm/ftrace.lds.h> | 27 | #include <asm/ftrace.lds.h> |
| 28 | #include <asm/set_memory.h> | 28 | #include <asm/set_memory.h> |
| 29 | #include <asm/setup.h> | ||
| 29 | 30 | ||
| 30 | #if 0 | 31 | #if 0 |
| 31 | #define DEBUGP printk | 32 | #define DEBUGP printk |
| @@ -35,6 +36,24 @@ · 3 unmodified lines | |||
| 35 | 36 | ||
| 36 | #define PLT_ENTRY_SIZE 22 | 37 | #define PLT_ENTRY_SIZE 22 |
| 37 | 38 | ||
| 39 | static unsigned long get_module_load_offset(void) | ||
| 40 | { | ||
| 41 | static DEFINE_MUTEX(module_kaslr_mutex); | ||
| 42 | static unsigned long module_load_offset; | ||
| 43 | |||
| 44 | if (!kaslr_enabled()) | ||
| 45 | return 0; | ||
| 46 | /* | ||
| 47 | * Calculate the module_load_offset the first time this code | ||
| 48 | * is called. Once calculated it stays the same until reboot. | ||
| 49 | */ | ||
| 50 | mutex_lock(&module_kaslr_mutex); | ||
| 51 | if (!module_load_offset) | ||
| 52 | module_load_offset = get_random_u32_inclusive(1, 1024) * PAGE_SIZE; | ||
| 53 | mutex_unlock(&module_kaslr_mutex); | ||
| 54 | return module_load_offset; | ||
| 55 | } | ||
| 56 | |||
| 38 | void *module_alloc(unsigned long size) | 57 | void *module_alloc(unsigned long size) |
| 39 | { | 58 | { |
| 40 | gfp_t gfp_mask = GFP_KERNEL; | 59 | gfp_t gfp_mask = GFP_KERNEL; |
| @@ -42,9 +61,11 @@ void *module_alloc(unsigned long size) · 1 unmodified line | |||
| 42 | 61 | ||
| 43 | if (PAGE_ALIGN(size) > MODULES_LEN) | 62 | if (PAGE_ALIGN(size) > MODULES_LEN) |
| 44 | return NULL; | 63 | return NULL; |
| 45 | p = __vmalloc_node_range(size, MODULE_ALIGN, MODULES_VADDR, MODULES_END, | 64 | p = __vmalloc_node_range(size, MODULE_ALIGN, |
| 46 | gfp_mask, PAGE_KERNEL_EXEC, VM_DEFER_KMEMLEAK, NUMA_NO_NODE, | 65 | MODULES_VADDR + get_module_load_offset(), |
| 47 | __builtin_return_address(0)); | 66 | MODULES_END, gfp_mask, PAGE_KERNEL, |
| 67 | VM_FLUSH_RESET_PERMS | VM_DEFER_KMEMLEAK, | ||
| 68 | NUMA_NO_NODE, __builtin_return_address(0)); | ||
| 48 | if (p && (kasan_alloc_module_shadow(p, size, gfp_mask) < 0)) { | 69 | if (p && (kasan_alloc_module_shadow(p, size, gfp_mask) < 0)) { |
| 49 | vfree(p); | 70 | vfree(p); |
| 50 | return NULL; | 71 | return NULL; |
| @@ -491,7 +512,7 @@ static int module_alloc_ftrace_hotpatch_trampolines(struct module *me, · 440 unmodified lines | |||
| 491 | start = module_alloc(numpages * PAGE_SIZE); | 512 | start = module_alloc(numpages * PAGE_SIZE); |
| 492 | if (!start) | 513 | if (!start) |
| 493 | return -ENOMEM; | 514 | return -ENOMEM; |
| 494 | set_memory_ro((unsigned long)start, numpages); | 515 | set_memory_rox((unsigned long)start, numpages); |
| 495 | end = start + size; | 516 | end = start + size; |
| 496 | 517 | ||
| 497 | me->arch.trampolines_start = (struct ftrace_hotpatch_trampoline *)start; | 518 | me->arch.trampolines_start = (struct ftrace_hotpatch_trampoline *)start; |
| @@ -76,7 +76,6 @@ static inline int ctr_stcctm(enum cpumf_ctr_set set, u64 range, u64 *dest) · 75 unmodified lines | |||
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | struct cpu_cf_events { | 78 | struct cpu_cf_events { |
| 79 | struct cpumf_ctr_info info; | ||
| 80 | atomic_t ctr_set[CPUMF_CTR_SET_MAX]; | 79 | atomic_t ctr_set[CPUMF_CTR_SET_MAX]; |
| 81 | u64 state; /* For perf_event_open SVC */ | 80 | u64 state; /* For perf_event_open SVC */ |
| 82 | u64 dev_state; /* For /dev/hwctr */ | 81 | u64 dev_state; /* For /dev/hwctr */ |
| @@ -95,6 +94,15 @@ static DEFINE_PER_CPU(struct cpu_cf_events, cpu_cf_events); · 12 unmodified lines | |||
| 95 | static unsigned int cfdiag_cpu_speed; /* CPU speed for CF_DIAG trailer */ | 94 | static unsigned int cfdiag_cpu_speed; /* CPU speed for CF_DIAG trailer */ |
| 96 | static debug_info_t *cf_dbg; | 95 | static debug_info_t *cf_dbg; |
| 97 | 96 | ||
| 97 | /* | ||
| 98 | * The CPU Measurement query counter information instruction contains | ||
| 99 | * information which varies per machine generation, but is constant and | ||
| 100 | * does not change when running on a particular machine, such as counter | ||
| 101 | * first and second version number. This is needed to determine the size | ||
| 102 | * of counter sets. Extract this information at device driver initialization. | ||
| 103 | */ | ||
| 104 | static struct cpumf_ctr_info cpumf_ctr_info; | ||
| 105 | |||
| 98 | #define CF_DIAG_CTRSET_DEF 0xfeef /* Counter set header mark */ | 106 | #define CF_DIAG_CTRSET_DEF 0xfeef /* Counter set header mark */ |
| 99 | /* interval in seconds */ | 107 | /* interval in seconds */ |
| 100 | 108 | ||
| @@ -167,11 +175,10 @@ struct cf_trailer_entry { /* CPU-M CF_DIAG trailer (64 byte) */ · 66 unmodified lines | |||
| 167 | /* Create the trailer data at the end of a page. */ | 175 | /* Create the trailer data at the end of a page. */ |
| 168 | static void cfdiag_trailer(struct cf_trailer_entry *te) | 176 | static void cfdiag_trailer(struct cf_trailer_entry *te) |
| 169 | { | 177 | { |
| 170 | struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); | ||
| 171 | struct cpuid cpuid; | 178 | struct cpuid cpuid; |
| 172 | 179 | ||
| 173 | te->cfvn = cpuhw->info.cfvn; /* Counter version numbers */ | 180 | te->cfvn = cpumf_ctr_info.cfvn; /* Counter version numbers */ |
| 174 | te->csvn = cpuhw->info.csvn; | 181 | te->csvn = cpumf_ctr_info.csvn; |
| 175 | 182 | ||
| 176 | get_cpu_id(&cpuid); /* Machine type */ | 183 | get_cpu_id(&cpuid); /* Machine type */ |
| 177 | te->mach_type = cpuid.machine; | 184 | te->mach_type = cpuid.machine; |
| @@ -184,50 +191,60 @@ static void cfdiag_trailer(struct cf_trailer_entry *te) · 6 unmodified lines | |||
| 184 | } | 191 | } |
| 185 | 192 | ||
| 186 | /* | 193 | /* |
| 187 | * Return the maximum possible counter set size (in number of 8 byte counters) | 194 | * The number of counters per counter set varies between machine generations, |
| 188 | * depending on type and model number. | 195 | * but is constant when running on a particular machine generation. |
| 196 | * Determine each counter set size at device driver initialization and | ||
| 197 | * retrieve it later. | ||
| 189 | */ | 198 | */ |
| 190 | static size_t cpum_cf_ctrset_size(enum cpumf_ctr_set ctrset, | 199 | static size_t cpumf_ctr_setsizes[CPUMF_CTR_SET_MAX]; |
| 191 | struct cpumf_ctr_info *info) | 200 | static void cpum_cf_make_setsize(enum cpumf_ctr_set ctrset) |
| 192 | { | 201 | { |
| 193 | size_t ctrset_size = 0; | 202 | size_t ctrset_size = 0; |
| 194 | 203 | ||
| 195 | switch (ctrset) { | 204 | switch (ctrset) { |
| 196 | case CPUMF_CTR_SET_BASIC: | 205 | case CPUMF_CTR_SET_BASIC: |
| 197 | if (info->cfvn >= 1) | 206 | if (cpumf_ctr_info.cfvn >= 1) |
| 198 | ctrset_size = 6; | 207 | ctrset_size = 6; |
| 199 | break; | 208 | break; |
| 200 | case CPUMF_CTR_SET_USER: | 209 | case CPUMF_CTR_SET_USER: |
| 201 | if (info->cfvn == 1) | 210 | if (cpumf_ctr_info.cfvn == 1) |
| 202 | ctrset_size = 6; | 211 | ctrset_size = 6; |
| 203 | else if (info->cfvn >= 3) | 212 | else if (cpumf_ctr_info.cfvn >= 3) |
| 204 | ctrset_size = 2; | 213 | ctrset_size = 2; |
| 205 | break; | 214 | break; |
| 206 | case CPUMF_CTR_SET_CRYPTO: | 215 | case CPUMF_CTR_SET_CRYPTO: |
| 207 | if (info->csvn >= 1 && info->csvn <= 5) | 216 | if (cpumf_ctr_info.csvn >= 1 && cpumf_ctr_info.csvn <= 5) |
| 208 | ctrset_size = 16; | 217 | ctrset_size = 16; |
| 209 | else if (info->csvn == 6 || info->csvn == 7) | 218 | else if (cpumf_ctr_info.csvn == 6 || cpumf_ctr_info.csvn == 7) |
| 210 | ctrset_size = 20; | 219 | ctrset_size = 20; |
| 211 | break; | 220 | break; |
| 212 | case CPUMF_CTR_SET_EXT: | 221 | case CPUMF_CTR_SET_EXT: |
| 213 | if (info->csvn == 1) | 222 | if (cpumf_ctr_info.csvn == 1) |
| 214 | ctrset_size = 32; | 223 | ctrset_size = 32; |
| 215 | else if (info->csvn == 2) | 224 | else if (cpumf_ctr_info.csvn == 2) |
| 216 | ctrset_size = 48; | 225 | ctrset_size = 48; |
| 217 | else if (info->csvn >= 3 && info->csvn <= 5) | 226 | else if (cpumf_ctr_info.csvn >= 3 && cpumf_ctr_info.csvn <= 5) |
| 218 | ctrset_size = 128; | 227 | ctrset_size = 128; |
| 219 | else if (info->csvn == 6 || info->csvn == 7) | 228 | else if (cpumf_ctr_info.csvn == 6 || cpumf_ctr_info.csvn == 7) |
| 220 | ctrset_size = 160; | 229 | ctrset_size = 160; |
| 221 | break; | 230 | break; |
| 222 | case CPUMF_CTR_SET_MT_DIAG: | 231 | case CPUMF_CTR_SET_MT_DIAG: |
| 223 | if (info->csvn > 3) | 232 | if (cpumf_ctr_info.csvn > 3) |
| 224 | ctrset_size = 48; | 233 | ctrset_size = 48; |
| 225 | break; | 234 | break; |
| 226 | case CPUMF_CTR_SET_MAX: | 235 | case CPUMF_CTR_SET_MAX: |
| 227 | break; | 236 | break; |
| 228 | } | 237 | } |
| 238 | cpumf_ctr_setsizes[ctrset] = ctrset_size; | ||
| 239 | } | ||
| 229 | 240 | ||
| 230 | return ctrset_size; | 241 | /* |
| 242 | * Return the maximum possible counter set size (in number of 8 byte counters) | ||
| 243 | * depending on type and model number. | ||
| 244 | */ | ||
| 245 | static size_t cpum_cf_read_setsize(enum cpumf_ctr_set ctrset) | ||
| 246 | { | ||
| 247 | return cpumf_ctr_setsizes[ctrset]; | ||
| 231 | } | 248 | } |
| 232 | 249 | ||
| 233 | /* Read a counter set. The counter set number determines the counter set and | 250 | /* Read a counter set. The counter set number determines the counter set and |
| @@ -248,14 +265,13 @@ static size_t cpum_cf_ctrset_size(enum cpumf_ctr_set ctrset, · 14 unmodified lines | |||
| 248 | static size_t cfdiag_getctrset(struct cf_ctrset_entry *ctrdata, int ctrset, | 265 | static size_t cfdiag_getctrset(struct cf_ctrset_entry *ctrdata, int ctrset, |
| 249 | size_t room, bool error_ok) | 266 | size_t room, bool error_ok) |
| 250 | { | 267 | { |
| 251 | struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); | ||
| 252 | size_t ctrset_size, need = 0; | 268 | size_t ctrset_size, need = 0; |
| 253 | int rc = 3; /* Assume write failure */ | 269 | int rc = 3; /* Assume write failure */ |
| 254 | 270 | ||
| 255 | ctrdata->def = CF_DIAG_CTRSET_DEF; | 271 | ctrdata->def = CF_DIAG_CTRSET_DEF; |
| 256 | ctrdata->set = ctrset; | 272 | ctrdata->set = ctrset; |
| 257 | ctrdata->res1 = 0; | 273 | ctrdata->res1 = 0; |
| 258 | ctrset_size = cpum_cf_ctrset_size(ctrset, &cpuhw->info); | 274 | ctrset_size = cpum_cf_read_setsize(ctrset); |
| 259 | 275 | ||
| 260 | if (ctrset_size) { /* Save data */ | 276 | if (ctrset_size) { /* Save data */ |
| 261 | need = ctrset_size * sizeof(u64) + sizeof(*ctrdata); | 277 | need = ctrset_size * sizeof(u64) + sizeof(*ctrdata); |
| @@ -269,10 +285,6 @@ static size_t cfdiag_getctrset(struct cf_ctrset_entry *ctrdata, int ctrset, · 7 unmodified lines | |||
| 269 | need = 0; | 285 | need = 0; |
| 270 | } | 286 | } |
| 271 | 287 | ||
| 272 | debug_sprintf_event(cf_dbg, 3, | ||
| 273 | "%s ctrset %d ctrset_size %zu cfvn %d csvn %d" | ||
| 274 | " need %zd rc %d\n", __func__, ctrset, ctrset_size, | ||
| 275 | cpuhw->info.cfvn, cpuhw->info.csvn, need, rc); | ||
| 276 | return need; | 288 | return need; |
| 277 | } | 289 | } |
| 278 | 290 | ||
| @@ -377,40 +389,35 @@ static enum cpumf_ctr_set get_counter_set(u64 event) · 98 unmodified lines | |||
| 377 | return set; | 389 | return set; |
| 378 | } | 390 | } |
| 379 | 391 | ||
| 380 | static int validate_ctr_version(const struct hw_perf_event *hwc, | 392 | static int validate_ctr_version(const u64 config, enum cpumf_ctr_set set) |
| 381 | enum cpumf_ctr_set set) | ||
| 382 | { | 393 | { |
| 383 | struct cpu_cf_events *cpuhw; | ||
| 384 | int err = 0; | ||
| 385 | u16 mtdiag_ctl; | 394 | u16 mtdiag_ctl; |
| 386 | 395 | int err = 0; | |
| 387 | cpuhw = &get_cpu_var(cpu_cf_events); | ||
| 388 | 396 | ||
| 389 | /* check required version for counter sets */ | 397 | /* check required version for counter sets */ |
| 390 | switch (set) { | 398 | switch (set) { |
| 391 | case CPUMF_CTR_SET_BASIC: | 399 | case CPUMF_CTR_SET_BASIC: |
| 392 | case CPUMF_CTR_SET_USER: | 400 | case CPUMF_CTR_SET_USER: |
| 393 | if (cpuhw->info.cfvn < 1) | 401 | if (cpumf_ctr_info.cfvn < 1) |
| 394 | err = -EOPNOTSUPP; | 402 | err = -EOPNOTSUPP; |
| 395 | break; | 403 | break; |
| 396 | case CPUMF_CTR_SET_CRYPTO: | 404 | case CPUMF_CTR_SET_CRYPTO: |
| 397 | if ((cpuhw->info.csvn >= 1 && cpuhw->info.csvn <= 5 && | 405 | if ((cpumf_ctr_info.csvn >= 1 && cpumf_ctr_info.csvn <= 5 && |
| 398 | hwc->config > 79) || | 406 | config > 79) || (cpumf_ctr_info.csvn >= 6 && config > 83)) |
| 399 | (cpuhw->info.csvn >= 6 && hwc->config > 83)) | ||
| 400 | err = -EOPNOTSUPP; | 407 | err = -EOPNOTSUPP; |
| 401 | break; | 408 | break; |
| 402 | case CPUMF_CTR_SET_EXT: | 409 | case CPUMF_CTR_SET_EXT: |
| 403 | if (cpuhw->info.csvn < 1) | 410 | if (cpumf_ctr_info.csvn < 1) |
| 404 | err = -EOPNOTSUPP; | 411 | err = -EOPNOTSUPP; |
| 405 | if ((cpuhw->info.csvn == 1 && hwc->config > 159) || | 412 | if ((cpumf_ctr_info.csvn == 1 && config > 159) || |
| 406 | (cpuhw->info.csvn == 2 && hwc->config > 175) || | 413 | (cpumf_ctr_info.csvn == 2 && config > 175) || |
| 407 | (cpuhw->info.csvn >= 3 && cpuhw->info.csvn <= 5 | 414 | (cpumf_ctr_info.csvn >= 3 && cpumf_ctr_info.csvn <= 5 && |
| 408 | && hwc->config > 255) || | 415 | config > 255) || |
| 409 | (cpuhw->info.csvn >= 6 && hwc->config > 287)) | 416 | (cpumf_ctr_info.csvn >= 6 && config > 287)) |
| 410 | err = -EOPNOTSUPP; | 417 | err = -EOPNOTSUPP; |
| 411 | break; | 418 | break; |
| 412 | case CPUMF_CTR_SET_MT_DIAG: | 419 | case CPUMF_CTR_SET_MT_DIAG: |
| 413 | if (cpuhw->info.csvn <= 3) | 420 | if (cpumf_ctr_info.csvn <= 3) |
| 414 | err = -EOPNOTSUPP; | 421 | err = -EOPNOTSUPP; |
| 415 | /* | 422 | /* |
| 416 | * MT-diagnostic counters are read-only. The counter set | 423 | * MT-diagnostic counters are read-only. The counter set |
| @@ -425,35 +432,15 @@ static int validate_ctr_version(const struct hw_perf_event *hwc, · 8 unmodified lines | |||
| 425 | * counter set is enabled and active. | 432 | * counter set is enabled and active. |
| 426 | */ | 433 | */ |
| 427 | mtdiag_ctl = cpumf_ctr_ctl[CPUMF_CTR_SET_MT_DIAG]; | 434 | mtdiag_ctl = cpumf_ctr_ctl[CPUMF_CTR_SET_MT_DIAG]; |
| 428 | if (!((cpuhw->info.auth_ctl & mtdiag_ctl) && | 435 | if (!((cpumf_ctr_info.auth_ctl & mtdiag_ctl) && |
| 429 | (cpuhw->info.enable_ctl & mtdiag_ctl) && | 436 | (cpumf_ctr_info.enable_ctl & mtdiag_ctl) && |
| 430 | (cpuhw->info.act_ctl & mtdiag_ctl))) | 437 | (cpumf_ctr_info.act_ctl & mtdiag_ctl))) |
| 431 | err = -EOPNOTSUPP; | 438 | err = -EOPNOTSUPP; |
| 432 | break; | 439 | break; |
| 433 | case CPUMF_CTR_SET_MAX: | 440 | case CPUMF_CTR_SET_MAX: |
| 434 | err = -EOPNOTSUPP; | 441 | err = -EOPNOTSUPP; |
| 435 | } | 442 | } |
| 436 | 443 | ||
| 437 | put_cpu_var(cpu_cf_events); | ||
| 438 | return err; | ||
| 439 | } | ||
| 440 | |||
| 441 | static int validate_ctr_auth(const struct hw_perf_event *hwc) | ||
| 442 | { | ||
| 443 | struct cpu_cf_events *cpuhw; | ||
| 444 | int err = 0; | ||
| 445 | |||
| 446 | cpuhw = &get_cpu_var(cpu_cf_events); | ||
| 447 | |||
| 448 | /* Check authorization for cpu counter sets. | ||
| 449 | * If the particular CPU counter set is not authorized, | ||
| 450 | * return with -ENOENT in order to fall back to other | ||
| 451 | * PMUs that might suffice the event request. | ||
| 452 | */ | ||
| 453 | if (!(hwc->config_base & cpuhw->info.auth_ctl)) | ||
| 454 | err = -ENOENT; | ||
| 455 | |||
| 456 | put_cpu_var(cpu_cf_events); | ||
| 457 | return err; | 444 | return err; |
| 458 | } | 445 | } |
| 459 | 446 | ||
| @@ -471,13 +458,10 @@ static void cpumf_pmu_enable(struct pmu *pmu) · 11 unmodified lines | |||
| 471 | return; | 458 | return; |
| 472 | 459 | ||
| 473 | err = lcctl(cpuhw->state | cpuhw->dev_state); | 460 | err = lcctl(cpuhw->state | cpuhw->dev_state); |
| 474 | if (err) { | 461 | if (err) |
| 475 | pr_err("Enabling the performance measuring unit " | 462 | pr_err("Enabling the performance measuring unit failed with rc=%x\n", err); |
| 476 | "failed with rc=%x\n", err); | 463 | else |
| 477 | return; | 464 | cpuhw->flags |= PMU_F_ENABLED; |
| 478 | } | ||
| 479 | |||
| 480 | cpuhw->flags |= PMU_F_ENABLED; | ||
| 481 | } | 465 | } |
| 482 | 466 | ||
| 483 | /* | 467 | /* |
| @@ -497,13 +481,10 @@ static void cpumf_pmu_disable(struct pmu *pmu) · 13 unmodified lines | |||
| 497 | inactive = cpuhw->state & ~((1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1); | 481 | inactive = cpuhw->state & ~((1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1); |
| 498 | inactive |= cpuhw->dev_state; | 482 | inactive |= cpuhw->dev_state; |
| 499 | err = lcctl(inactive); | 483 | err = lcctl(inactive); |
| 500 | if (err) { | 484 | if (err) |
| 501 | pr_err("Disabling the performance measuring unit " | 485 | pr_err("Disabling the performance measuring unit failed with rc=%x\n", err); |
| 502 | "failed with rc=%x\n", err); | 486 | else |
| 503 | return; | 487 | cpuhw->flags &= ~PMU_F_ENABLED; |
| 504 | } | ||
| 505 | |||
| 506 | cpuhw->flags &= ~PMU_F_ENABLED; | ||
| 507 | } | 488 | } |
| 508 | 489 | ||
| 509 | #define PMC_INIT 0UL | 490 | #define PMC_INIT 0UL |
| @@ -515,8 +496,6 @@ static void cpum_cf_setup_cpu(void *flags) · 5 unmodified lines | |||
| 515 | 496 | ||
| 516 | switch ((unsigned long)flags) { | 497 | switch ((unsigned long)flags) { |
| 517 | case PMC_INIT: | 498 | case PMC_INIT: |
| 518 | memset(&cpuhw->info, 0, sizeof(cpuhw->info)); | ||
| 519 | qctri(&cpuhw->info); | ||
| 520 | cpuhw->flags |= PMU_F_RESERVED; | 499 | cpuhw->flags |= PMU_F_RESERVED; |
| 521 | break; | 500 | break; |
| 522 | 501 | ||
| @@ -602,7 +581,6 @@ static int __hw_perf_event_init(struct perf_event *event, unsigned int type) · 79 unmodified lines | |||
| 602 | struct perf_event_attr *attr = &event->attr; | 581 | struct perf_event_attr *attr = &event->attr; |
| 603 | struct hw_perf_event *hwc = &event->hw; | 582 | struct hw_perf_event *hwc = &event->hw; |
| 604 | enum cpumf_ctr_set set; | 583 | enum cpumf_ctr_set set; |
| 605 | int err = 0; | ||
| 606 | u64 ev; | 584 | u64 ev; |
| 607 | 585 | ||
| 608 | switch (type) { | 586 | switch (type) { |
| @@ -678,12 +656,15 @@ static int __hw_perf_event_init(struct perf_event *event, unsigned int type) · 69 unmodified lines | |||
| 678 | cpumf_hw_inuse(); | 656 | cpumf_hw_inuse(); |
| 679 | event->destroy = hw_perf_event_destroy; | 657 | event->destroy = hw_perf_event_destroy; |
| 680 | 658 | ||
| 681 | /* Finally, validate version and authorization of the counter set */ | 659 | /* |
| 682 | err = validate_ctr_auth(hwc); | 660 | * Finally, validate version and authorization of the counter set. |
| 683 | if (!err) | 661 | * If the particular CPU counter set is not authorized, |
| 684 | err = validate_ctr_version(hwc, set); | 662 | * return with -ENOENT in order to fall back to other |
| 685 | 663 | * PMUs that might suffice the event request. | |
| 686 | return err; | 664 | */ |
| 665 | if (!(hwc->config_base & cpumf_ctr_info.auth_ctl)) | ||
| 666 | return -ENOENT; | ||
| 667 | return validate_ctr_version(hwc->config, set); | ||
| 687 | } | 668 | } |
| 688 | 669 | ||
| 689 | /* Events CPU_CYLCES and INSTRUCTIONS can be submitted with two different | 670 | /* Events CPU_CYLCES and INSTRUCTIONS can be submitted with two different |
| @@ -983,7 +964,7 @@ static void cpumf_measurement_alert(struct ext_code ext_code, · 293 unmodified lines | |||
| 983 | 964 | ||
| 984 | /* counter authorization change alert */ | 965 | /* counter authorization change alert */ |
| 985 | if (alert & CPU_MF_INT_CF_CACA) | 966 | if (alert & CPU_MF_INT_CF_CACA) |
| 986 | qctri(&cpuhw->info); | 967 | qctri(&cpumf_ctr_info); |
| 987 | 968 | ||
| 988 | /* loss of counter data alert */ | 969 | /* loss of counter data alert */ |
| 989 | if (alert & CPU_MF_INT_CF_LCDA) | 970 | if (alert & CPU_MF_INT_CF_LCDA) |
| @@ -1000,9 +981,14 @@ static int __init cpumf_pmu_init(void) · 10 unmodified lines | |||
| 1000 | { | 981 | { |
| 1001 | int rc; | 982 | int rc; |
| 1002 | 983 | ||
| 1003 | if (!cpum_cf_avail()) | 984 | /* Extract counter measurement facility information */ |
| 985 | if (!cpum_cf_avail() || qctri(&cpumf_ctr_info)) | ||
| 1004 | return -ENODEV; | 986 | return -ENODEV; |
| 1005 | 987 | ||
| 988 | /* Determine and store counter set sizes for later reference */ | ||
| 989 | for (rc = CPUMF_CTR_SET_BASIC; rc < CPUMF_CTR_SET_MAX; ++rc) | ||
| 990 | cpum_cf_make_setsize(rc); | ||
| 991 | |||
| 1006 | /* | 992 | /* |
| 1007 | * Clear bit 15 of cr0 to unauthorize problem-state to | 993 | * Clear bit 15 of cr0 to unauthorize problem-state to |
| 1008 | * extract measurement counters | 994 | * extract measurement counters |
| @@ -1269,28 +1255,26 @@ static int cfset_all_start(struct cfset_request *req) · 260 unmodified lines | |||
| 1269 | */ | 1255 | */ |
| 1270 | static size_t cfset_needspace(unsigned int sets) | 1256 | static size_t cfset_needspace(unsigned int sets) |
| 1271 | { | 1257 | { |
| 1272 | struct cpu_cf_events *cpuhw = get_cpu_ptr(&cpu_cf_events); | ||
| 1273 | size_t bytes = 0; | 1258 | size_t bytes = 0; |
| 1274 | int i; | 1259 | int i; |
| 1275 | 1260 | ||
| 1276 | for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { | 1261 | for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { |
| 1277 | if (!(sets & cpumf_ctr_ctl[i])) | 1262 | if (!(sets & cpumf_ctr_ctl[i])) |
| 1278 | continue; | 1263 | continue; |
| 1279 | bytes += cpum_cf_ctrset_size(i, &cpuhw->info) * sizeof(u64) + | 1264 | bytes += cpum_cf_read_setsize(i) * sizeof(u64) + |
| 1280 | sizeof(((struct s390_ctrset_setdata *)0)->set) + | 1265 | sizeof(((struct s390_ctrset_setdata *)0)->set) + |
| 1281 | sizeof(((struct s390_ctrset_setdata *)0)->no_cnts); | 1266 | sizeof(((struct s390_ctrset_setdata *)0)->no_cnts); |
| 1282 | } | 1267 | } |
| 1283 | bytes = sizeof(((struct s390_ctrset_read *)0)->no_cpus) + nr_cpu_ids * | 1268 | bytes = sizeof(((struct s390_ctrset_read *)0)->no_cpus) + nr_cpu_ids * |
| 1284 | (bytes + sizeof(((struct s390_ctrset_cpudata *)0)->cpu_nr) + | 1269 | (bytes + sizeof(((struct s390_ctrset_cpudata *)0)->cpu_nr) + |
| 1285 | sizeof(((struct s390_ctrset_cpudata *)0)->no_sets)); | 1270 | sizeof(((struct s390_ctrset_cpudata *)0)->no_sets)); |
| 1286 | put_cpu_ptr(&cpu_cf_events); | ||
| 1287 | return bytes; | 1271 | return bytes; |
| 1288 | } | 1272 | } |
| 1289 | 1273 | ||
| 1290 | static int cfset_all_copy(unsigned long arg, cpumask_t *mask) | 1274 | static int cfset_all_copy(unsigned long arg, cpumask_t *mask) |
| 1291 | { | 1275 | { |
| 1292 | struct s390_ctrset_read __user *ctrset_read; | 1276 | struct s390_ctrset_read __user *ctrset_read; |
| 1293 | unsigned int cpu, cpus, rc; | 1277 | unsigned int cpu, cpus, rc = 0; |
| 1294 | void __user *uptr; | 1278 | void __user *uptr; |
| 1295 | 1279 | ||
| 1296 | ctrset_read = (struct s390_ctrset_read __user *)arg; | 1280 | ctrset_read = (struct s390_ctrset_read __user *)arg; |
| @@ -1304,17 +1288,20 @@ static int cfset_all_copy(unsigned long arg, cpumask_t *mask) · 7 unmodified lines | |||
| 1304 | rc |= put_user(cpuhw->sets, &ctrset_cpudata->no_sets); | 1288 | rc |= put_user(cpuhw->sets, &ctrset_cpudata->no_sets); |
| 1305 | rc |= copy_to_user(ctrset_cpudata->data, cpuhw->data, | 1289 | rc |= copy_to_user(ctrset_cpudata->data, cpuhw->data, |
| 1306 | cpuhw->used); | 1290 | cpuhw->used); |
| 1307 | if (rc) | 1291 | if (rc) { |
| 1308 | return -EFAULT; | 1292 | rc = -EFAULT; |
| 1293 | goto out; | ||
| 1294 | } | ||
| 1309 | uptr += sizeof(struct s390_ctrset_cpudata) + cpuhw->used; | 1295 | uptr += sizeof(struct s390_ctrset_cpudata) + cpuhw->used; |
| 1310 | cond_resched(); | 1296 | cond_resched(); |
| 1311 | } | 1297 | } |
| 1312 | cpus = cpumask_weight(mask); | 1298 | cpus = cpumask_weight(mask); |
| 1313 | if (put_user(cpus, &ctrset_read->no_cpus)) | 1299 | if (put_user(cpus, &ctrset_read->no_cpus)) |
| 1314 | return -EFAULT; | 1300 | rc = -EFAULT; |
| 1315 | debug_sprintf_event(cf_dbg, 4, "%s copied %ld\n", __func__, | 1301 | out: |
| 1302 | debug_sprintf_event(cf_dbg, 4, "%s rc %d copied %ld\n", __func__, rc, | ||
| 1316 | uptr - (void __user *)ctrset_read->data); | 1303 | uptr - (void __user *)ctrset_read->data); |
| 1317 | return 0; | 1304 | return rc; |
| 1318 | } | 1305 | } |
| 1319 | 1306 | ||
| 1320 | static size_t cfset_cpuset_read(struct s390_ctrset_setdata *p, int ctrset, | 1307 | static size_t cfset_cpuset_read(struct s390_ctrset_setdata *p, int ctrset, |
| @@ -1354,7 +1341,7 @@ static void cfset_cpu_read(void *parm) · 33 unmodified lines | |||
| 1354 | 1341 | ||
| 1355 | if (!(p->sets & cpumf_ctr_ctl[set])) | 1342 | if (!(p->sets & cpumf_ctr_ctl[set])) |
| 1356 | continue; /* Counter set not in list */ | 1343 | continue; /* Counter set not in list */ |
| 1357 | set_size = cpum_cf_ctrset_size(set, &cpuhw->info); | 1344 | set_size = cpum_cf_read_setsize(set); |
| 1358 | space = sizeof(cpuhw->data) - cpuhw->used; | 1345 | space = sizeof(cpuhw->data) - cpuhw->used; |
| 1359 | space = cfset_cpuset_read(sp, set, set_size, space); | 1346 | space = cfset_cpuset_read(sp, set, set_size, space); |
| 1360 | if (space) { | 1347 | if (space) { |
| @@ -1385,14 +1372,10 @@ static int cfset_all_read(unsigned long arg, struct cfset_request *req) · 24 unmodified lines | |||
| 1385 | 1372 | ||
| 1386 | static long cfset_ioctl_read(unsigned long arg, struct cfset_request *req) | 1373 | static long cfset_ioctl_read(unsigned long arg, struct cfset_request *req) |
| 1387 | { | 1374 | { |
| 1388 | struct s390_ctrset_read read; | ||
| 1389 | int ret = -ENODATA; | 1375 | int ret = -ENODATA; |
| 1390 | 1376 | ||
| 1391 | if (req && req->ctrset) { | 1377 | if (req && req->ctrset) |
| 1392 | if (copy_from_user(&read, (char __user *)arg, sizeof(read))) | ||
| 1393 | return -EFAULT; | ||
| 1394 | ret = cfset_all_read(arg, req); | 1378 | ret = cfset_all_read(arg, req); |
| 1395 | } | ||
| 1396 | return ret; | 1379 | return ret; |
| 1397 | } | 1380 | } |
| 1398 | 1381 | ||
| @@ -1569,16 +1552,13 @@ static void cfdiag_read(struct perf_event *event) · 170 unmodified lines | |||
| 1569 | 1552 | ||
| 1570 | static int get_authctrsets(void) | 1553 | static int get_authctrsets(void) |
| 1571 | { | 1554 | { |
| 1572 | struct cpu_cf_events *cpuhw; | ||
| 1573 | unsigned long auth = 0; | 1555 | unsigned long auth = 0; |
| 1574 | enum cpumf_ctr_set i; | 1556 | enum cpumf_ctr_set i; |
| 1575 | 1557 | ||
| 1576 | cpuhw = &get_cpu_var(cpu_cf_events); | ||
| 1577 | for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { | 1558 | for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { |
| 1578 | if (cpuhw->info.auth_ctl & cpumf_ctr_ctl[i]) | 1559 | if (cpumf_ctr_info.auth_ctl & cpumf_ctr_ctl[i]) |
| 1579 | auth |= cpumf_ctr_ctl[i]; | 1560 | auth |= cpumf_ctr_ctl[i]; |
| 1580 | } | 1561 | } |
| 1581 | put_cpu_var(cpu_cf_events); | ||
| 1582 | return auth; | 1562 | return auth; |
| 1583 | } | 1563 | } |
| 1584 | 1564 | ||
| @@ -1716,7 +1696,7 @@ static size_t cfdiag_maxsize(struct cpumf_ctr_info *info) · 131 unmodified lines | |||
| 1716 | enum cpumf_ctr_set i; | 1696 | enum cpumf_ctr_set i; |
| 1717 | 1697 | ||
| 1718 | for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { | 1698 | for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { |
| 1719 | size_t size = cpum_cf_ctrset_size(i, info); | 1699 | size_t size = cpum_cf_read_setsize(i); |
| 1720 | 1700 | ||
| 1721 | if (size) | 1701 | if (size) |
| 1722 | max_size += size * sizeof(u64) + | 1702 | max_size += size * sizeof(u64) + |
| @@ -1750,16 +1730,12 @@ static void cfdiag_get_cpu_speed(void) · 27 unmodified lines | |||
| 1750 | 1730 | ||
| 1751 | static int cfset_init(void) | 1731 | static int cfset_init(void) |
| 1752 | { | 1732 | { |
| 1753 | struct cpumf_ctr_info info; | ||
| 1754 | size_t need; | 1733 | size_t need; |
| 1755 | int rc; | 1734 | int rc; |
| 1756 | 1735 | ||
| 1757 | if (qctri(&info)) | ||
| 1758 | return -ENODEV; | ||
| 1759 | |||
| 1760 | cfdiag_get_cpu_speed(); | 1736 | cfdiag_get_cpu_speed(); |
| 1761 | /* Make sure the counter set data fits into predefined buffer. */ | 1737 | /* Make sure the counter set data fits into predefined buffer. */ |
| 1762 | need = cfdiag_maxsize(&info); | 1738 | need = cfdiag_maxsize(&cpumf_ctr_info); |
| 1763 | if (need > sizeof(((struct cpu_cf_events *)0)->start)) { | 1739 | if (need > sizeof(((struct cpu_cf_events *)0)->start)) { |
| 1764 | pr_err("Insufficient memory for PMU(cpum_cf_diag) need=%zu\n", | 1740 | pr_err("Insufficient memory for PMU(cpum_cf_diag) need=%zu\n", |
| 1765 | need); | 1741 | need); |
| @@ -882,10 +882,6 @@ static int __hw_perf_event_init(struct perf_event *event) · 881 unmodified lines | |||
| 882 | SAMPL_FLAGS(hwc) |= PERF_CPUM_SF_DIAG_MODE; | 882 | SAMPL_FLAGS(hwc) |= PERF_CPUM_SF_DIAG_MODE; |
| 883 | } | 883 | } |
| 884 | 884 | ||
| 885 | /* Check and set other sampling flags */ | ||
| 886 | if (attr->config1 & PERF_CPUM_SF_FULL_BLOCKS) | ||
| 887 | SAMPL_FLAGS(hwc) |= PERF_CPUM_SF_FULL_BLOCKS; | ||
| 888 | |||
| 889 | err = __hw_perf_event_init_rate(event, &si); | 885 | err = __hw_perf_event_init_rate(event, &si); |
| 890 | if (err) | 886 | if (err) |
| 891 | goto out; | 887 | goto out; |
| @@ -1293,11 +1289,8 @@ static inline __uint128_t __cdsg(__uint128_t *ptr, __uint128_t old, __uint128_t · 401 unmodified lines | |||
| 1293 | * The sampling buffer position are retrieved and saved in the TEAR_REG | 1289 | * The sampling buffer position are retrieved and saved in the TEAR_REG |
| 1294 | * register of the specified perf event. | 1290 | * register of the specified perf event. |
| 1295 | * | 1291 | * |
| 1296 | * Only full sample-data-blocks are processed. Specify the flash_all flag | 1292 | * Only full sample-data-blocks are processed. Specify the flush_all flag |
| 1297 | * to also walk through partially filled sample-data-blocks. It is ignored | 1293 | * to also walk through partially filled sample-data-blocks. |
| 1298 | * if PERF_CPUM_SF_FULL_BLOCKS is set. The PERF_CPUM_SF_FULL_BLOCKS flag | ||
| 1299 | * enforces the processing of full sample-data-blocks only (trailer entries | ||
| 1300 | * with the block-full-indicator bit set). | ||
| 1301 | */ | 1294 | */ |
| 1302 | static void hw_perf_event_update(struct perf_event *event, int flush_all) | 1295 | static void hw_perf_event_update(struct perf_event *event, int flush_all) |
| 1303 | { | 1296 | { |
| @@ -1315,9 +1308,6 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all) · 11 unmodified lines | |||
| 1315 | if (SAMPL_DIAG_MODE(&event->hw)) | 1308 | if (SAMPL_DIAG_MODE(&event->hw)) |
| 1316 | return; | 1309 | return; |
| 1317 | 1310 | ||
| 1318 | if (flush_all && SDB_FULL_BLOCKS(hwc)) | ||
| 1319 | flush_all = 0; | ||
| 1320 | |||
| 1321 | sdbt = (unsigned long *) TEAR_REG(hwc); | 1311 | sdbt = (unsigned long *) TEAR_REG(hwc); |
| 1322 | done = event_overflow = sampl_overflow = num_sdb = 0; | 1312 | done = event_overflow = sampl_overflow = num_sdb = 0; |
| 1323 | while (!done) { | 1313 | while (!done) { |
| @@ -136,12 +136,12 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) · 135 unmodified lines | |||
| 136 | p->thread.last_break = 1; | 136 | p->thread.last_break = 1; |
| 137 | 137 | ||
| 138 | frame->sf.back_chain = 0; | 138 | frame->sf.back_chain = 0; |
| 139 | frame->sf.gprs[5] = (unsigned long)frame + sizeof(struct stack_frame); | 139 | frame->sf.gprs[11 - 6] = (unsigned long)&frame->childregs; |
| 140 | frame->sf.gprs[6] = (unsigned long)p; | 140 | frame->sf.gprs[12 - 6] = (unsigned long)p; |
| 141 | /* new return point is ret_from_fork */ | 141 | /* new return point is ret_from_fork */ |
| 142 | frame->sf.gprs[8] = (unsigned long)ret_from_fork; | 142 | frame->sf.gprs[14 - 6] = (unsigned long)ret_from_fork; |
| 143 | /* fake return stack for resume(), don't go back to schedule */ | 143 | /* fake return stack for resume(), don't go back to schedule */ |
| 144 | frame->sf.gprs[9] = (unsigned long)frame; | 144 | frame->sf.gprs[15 - 6] = (unsigned long)frame; |
| 145 | 145 | ||
| 146 | /* Store access registers to kernel stack of new process. */ | 146 | /* Store access registers to kernel stack of new process. */ |
| 147 | if (unlikely(args->fn)) { | 147 | if (unlikely(args->fn)) { |
| @@ -149,8 +149,6 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) · 1 unmodified line | |||
| 149 | memset(&frame->childregs, 0, sizeof(struct pt_regs)); | 149 | memset(&frame->childregs, 0, sizeof(struct pt_regs)); |
| 150 | frame->childregs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | | 150 | frame->childregs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | |
| 151 | PSW_MASK_EXT | PSW_MASK_MCHECK; | 151 | PSW_MASK_EXT | PSW_MASK_MCHECK; |
| 152 | frame->childregs.psw.addr = | ||
| 153 | (unsigned long)__ret_from_fork; | ||
| 154 | frame->childregs.gprs[9] = (unsigned long)args->fn; | 152 | frame->childregs.gprs[9] = (unsigned long)args->fn; |
| 155 | frame->childregs.gprs[10] = (unsigned long)args->fn_arg; | 153 | frame->childregs.gprs[10] = (unsigned long)args->fn_arg; |
| 156 | frame->childregs.orig_gpr2 = -1; | 154 | frame->childregs.orig_gpr2 = -1; |
| @@ -364,21 +364,3 @@ const struct seq_operations cpuinfo_op = { · 363 unmodified lines | |||
| 364 | .stop = c_stop, | 364 | .stop = c_stop, |
| 365 | .show = show_cpuinfo, | 365 | .show = show_cpuinfo, |
| 366 | }; | 366 | }; |
| 367 | |||
| 368 | int s390_isolate_bp(void) | ||
| 369 | { | ||
| 370 | if (!test_facility(82)) | ||
| 371 | return -EOPNOTSUPP; | ||
| 372 | set_thread_flag(TIF_ISOLATE_BP); | ||
| 373 | return 0; | ||
| 374 | } | ||
| 375 | EXPORT_SYMBOL(s390_isolate_bp); | ||
| 376 | |||
| 377 | int s390_isolate_bp_guest(void) | ||
| 378 | { | ||
| 379 | if (!test_facility(82)) | ||
| 380 | return -EOPNOTSUPP; | ||
| 381 | set_thread_flag(TIF_ISOLATE_BP_GUEST); | ||
| 382 | return 0; | ||
| 383 | } | ||
| 384 | EXPORT_SYMBOL(s390_isolate_bp_guest); | ||
| @@ -19,7 +19,7 @@ · 18 unmodified lines | |||
| 19 | # r2 = Function to be called after store status | 19 | # r2 = Function to be called after store status |
| 20 | # r3 = Parameter for function | 20 | # r3 = Parameter for function |
| 21 | # | 21 | # |
| 22 | ENTRY(store_status) | 22 | SYM_CODE_START(store_status) |
| 23 | /* Save register one and load save area base */ | 23 | /* Save register one and load save area base */ |
| 24 | stg %r1,__LC_SAVE_AREA_RESTART | 24 | stg %r1,__LC_SAVE_AREA_RESTART |
| 25 | /* General purpose registers */ | 25 | /* General purpose registers */ |
| @@ -61,7 +61,7 @@ ENTRY(store_status) · 35 unmodified lines | |||
| 61 | stpx 0(%r1) | 61 | stpx 0(%r1) |
| 62 | /* Clock comparator - seven bytes */ | 62 | /* Clock comparator - seven bytes */ |
| 63 | lghi %r1,__LC_CLOCK_COMP_SAVE_AREA | 63 | lghi %r1,__LC_CLOCK_COMP_SAVE_AREA |
| 64 | larl %r4,.Lclkcmp | 64 | larl %r4,clkcmp |
| 65 | stckc 0(%r4) | 65 | stckc 0(%r4) |
| 66 | mvc 1(7,%r1),1(%r4) | 66 | mvc 1(7,%r1),1(%r4) |
| 67 | /* Program status word */ | 67 | /* Program status word */ |
| @@ -73,9 +73,9 @@ ENTRY(store_status) · 5 unmodified lines | |||
| 73 | lgr %r9,%r2 | 73 | lgr %r9,%r2 |
| 74 | lgr %r2,%r3 | 74 | lgr %r2,%r3 |
| 75 | BR_EX %r9 | 75 | BR_EX %r9 |
| 76 | ENDPROC(store_status) | 76 | SYM_CODE_END(store_status) |
| 77 | 77 | ||
| 78 | .section .bss | 78 | .section .bss |
| 79 | .align 8 | 79 | .balign 8 |
| 80 | .Lclkcmp: .quad 0x0000000000000000 | 80 | SYM_DATA_LOCAL(clkcmp, .quad 0x0000000000000000) |
| 81 | .previous | 81 | .previous |
| @@ -26,53 +26,51 @@ · 25 unmodified lines | |||
| 26 | */ | 26 | */ |
| 27 | 27 | ||
| 28 | .text | 28 | .text |
| 29 | ENTRY(relocate_kernel) | 29 | SYM_CODE_START(relocate_kernel) |
| 30 | basr %r13,0 # base address | 30 | basr %r13,0 # base address |
| 31 | .base: | 31 | .base: |
| 32 | lghi %r7,PAGE_SIZE # load PAGE_SIZE in r7 | 32 | lghi %r7,PAGE_SIZE # load PAGE_SIZE in r7 |
| 33 | lghi %r9,PAGE_SIZE # load PAGE_SIZE in r9 | 33 | lghi %r9,PAGE_SIZE # load PAGE_SIZE in r9 |
| 34 | lg %r5,0(%r2) # read another word for indirection page | 34 | lg %r5,0(%r2) # read another word for indirection page |
| 35 | aghi %r2,8 # increment pointer | 35 | aghi %r2,8 # increment pointer |
| 36 | tml %r5,0x1 # is it a destination page? | 36 | tml %r5,0x1 # is it a destination page? |
| 37 | je .indir_check # NO, goto "indir_check" | 37 | je .indir_check # NO, goto "indir_check" |
| 38 | lgr %r6,%r5 # r6 = r5 | 38 | lgr %r6,%r5 # r6 = r5 |
| 39 | nill %r6,0xf000 # mask it out and... | 39 | nill %r6,0xf000 # mask it out and... |
| 40 | j .base # ...next iteration | 40 | j .base # ...next iteration |
| 41 | .indir_check: | 41 | .indir_check: |
| 42 | tml %r5,0x2 # is it a indirection page? | 42 | tml %r5,0x2 # is it a indirection page? |
| 43 | je .done_test # NO, goto "done_test" | 43 | je .done_test # NO, goto "done_test" |
| 44 | nill %r5,0xf000 # YES, mask out, | 44 | nill %r5,0xf000 # YES, mask out, |
| 45 | lgr %r2,%r5 # move it into the right register, | 45 | lgr %r2,%r5 # move it into the right register, |
| 46 | j .base # and read next... | 46 | j .base # and read next... |
| 47 | .done_test: | 47 | .done_test: |
| 48 | tml %r5,0x4 # is it the done indicator? | 48 | tml %r5,0x4 # is it the done indicator? |
| 49 | je .source_test # NO! Well, then it should be the source indicator... | 49 | je .source_test # NO! Well, then it should be the source indicator... |
| 50 | j .done # ok, lets finish it here... | 50 | j .done # ok, lets finish it here... |
| 51 | .source_test: | 51 | .source_test: |
| 52 | tml %r5,0x8 # it should be a source indicator... | 52 | tml %r5,0x8 # it should be a source indicator... |
| 53 | je .base # NO, ignore it... | 53 | je .base # NO, ignore it... |
| 54 | lgr %r8,%r5 # r8 = r5 | 54 | lgr %r8,%r5 # r8 = r5 |
| 55 | nill %r8,0xf000 # masking | 55 | nill %r8,0xf000 # masking |
| 56 | 0: mvcle %r6,%r8,0x0 # copy PAGE_SIZE bytes from r8 to r6 - pad with 0 | 56 | 0: mvcle %r6,%r8,0x0 # copy PAGE_SIZE bytes from r8 to r6 - pad with 0 |
| 57 | jo 0b | 57 | jo 0b |
| 58 | j .base | 58 | j .base |
| 59 | .done: | 59 | .done: |
| 60 | lgr %r0,%r4 # subcode | 60 | lgr %r0,%r4 # subcode |
| 61 | cghi %r3,0 | 61 | cghi %r3,0 |
| 62 | je .diag | 62 | je .diag |
| 63 | la %r4,load_psw-.base(%r13) # load psw-address into the register | 63 | la %r4,load_psw-.base(%r13) # load psw-address into the register |
| 64 | o %r3,4(%r4) # or load address into psw | 64 | o %r3,4(%r4) # or load address into psw |
| 65 | st %r3,4(%r4) | 65 | st %r3,4(%r4) |
| 66 | mvc 0(8,%r0),0(%r4) # copy psw to absolute address 0 | 66 | mvc 0(8,%r0),0(%r4) # copy psw to absolute address 0 |
| 67 | .diag: | 67 | .diag: |
| 68 | diag %r0,%r0,0x308 | 68 | diag %r0,%r0,0x308 |
| 69 | ENDPROC(relocate_kernel) | 69 | SYM_CODE_END(relocate_kernel) |
| 70 | 70 | ||
| 71 | .align 8 | 71 | .balign 8 |
| 72 | load_psw: | 72 | SYM_DATA_START_LOCAL(load_psw) |
| 73 | .long 0x00080000,0x80000000 | 73 | .long 0x00080000,0x80000000 |
| 74 | relocate_kernel_end: | 74 | SYM_DATA_END_LABEL(load_psw, SYM_L_LOCAL, relocate_kernel_end) |
| 75 | .align 8 | 75 | .balign 8 |
| 76 | .globl relocate_kernel_len | 76 | SYM_DATA(relocate_kernel_len, .quad relocate_kernel_end - relocate_kernel) |
| 77 | relocate_kernel_len: | ||
| 78 | .quad relocate_kernel_end - relocate_kernel | ||
| @@ -74,7 +74,7 @@ · 73 unmodified lines | |||
| 74 | #include <asm/numa.h> | 74 | #include <asm/numa.h> |
| 75 | #include <asm/alternative.h> | 75 | #include <asm/alternative.h> |
| 76 | #include <asm/nospec-branch.h> | 76 | #include <asm/nospec-branch.h> |
| 77 | #include <asm/mem_detect.h> | 77 | #include <asm/physmem_info.h> |
| 78 | #include <asm/maccess.h> | 78 | #include <asm/maccess.h> |
| 79 | #include <asm/uv.h> | 79 | #include <asm/uv.h> |
| 80 | #include <asm/asm-offsets.h> | 80 | #include <asm/asm-offsets.h> |
| @@ -147,14 +147,10 @@ static u32 __amode31_ref *__ctl_duct = __ctl_duct_amode31; · 66 unmodified lines | |||
| 147 | 147 | ||
| 148 | int __bootdata(noexec_disabled); | 148 | int __bootdata(noexec_disabled); |
| 149 | unsigned long __bootdata(ident_map_size); | 149 | unsigned long __bootdata(ident_map_size); |
| 150 | struct mem_detect_info __bootdata(mem_detect); | 150 | struct physmem_info __bootdata(physmem_info); |
| 151 | struct initrd_data __bootdata(initrd_data); | ||
| 152 | unsigned long __bootdata(pgalloc_pos); | ||
| 153 | unsigned long __bootdata(pgalloc_end); | ||
| 154 | unsigned long __bootdata(pgalloc_low); | ||
| 155 | 151 | ||
| 156 | unsigned long __bootdata_preserved(__kaslr_offset); | 152 | unsigned long __bootdata_preserved(__kaslr_offset); |
| 157 | unsigned long __bootdata(__amode31_base); | 153 | int __bootdata_preserved(__kaslr_enabled); |
| 158 | unsigned int __bootdata_preserved(zlib_dfltcc_support); | 154 | unsigned int __bootdata_preserved(zlib_dfltcc_support); |
| 159 | EXPORT_SYMBOL(zlib_dfltcc_support); | 155 | EXPORT_SYMBOL(zlib_dfltcc_support); |
| 160 | u64 __bootdata_preserved(stfle_fac_list[16]); | 156 | u64 __bootdata_preserved(stfle_fac_list[16]); |
| @@ -385,39 +381,27 @@ void stack_free(unsigned long stack) · 224 unmodified lines | |||
| 385 | #endif | 381 | #endif |
| 386 | } | 382 | } |
| 387 | 383 | ||
| 388 | int __init arch_early_irq_init(void) | 384 | void __init __noreturn arch_call_rest_init(void) |
| 389 | { | 385 | { |
| 390 | unsigned long stack; | 386 | smp_reinit_ipl_cpu(); |
| 391 | 387 | rest_init(); | |
| 392 | stack = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER); | ||
| 393 | if (!stack) | ||
| 394 | panic("Couldn't allocate async stack"); | ||
| 395 | S390_lowcore.async_stack = stack + STACK_INIT_OFFSET; | ||
| 396 | return 0; | ||
| 397 | } | 388 | } |
| 398 | 389 | ||
| 399 | void __init __noreturn arch_call_rest_init(void) | 390 | static unsigned long __init stack_alloc_early(void) |
| 400 | { | 391 | { |
| 401 | unsigned long stack; | 392 | unsigned long stack; |
| 402 | 393 | ||
| 403 | smp_reinit_ipl_cpu(); | 394 | stack = (unsigned long)memblock_alloc(THREAD_SIZE, THREAD_SIZE); |
| 404 | stack = stack_alloc(); | 395 | if (!stack) { |
| 405 | if (!stack) | 396 | panic("%s: Failed to allocate %lu bytes align=0x%lx\n", |
| 406 | panic("Couldn't allocate kernel stack"); | 397 | __func__, THREAD_SIZE, THREAD_SIZE); |
| 407 | current->stack = (void *) stack; | 398 | } |
| 408 | #ifdef CONFIG_VMAP_STACK | 399 | return stack; |
| 409 | current->stack_vm_area = (void *) stack; | ||
| 410 | #endif | ||
| 411 | set_task_stack_end_magic(current); | ||
| 412 | stack += STACK_INIT_OFFSET; | ||
| 413 | S390_lowcore.kernel_stack = stack; | ||
| 414 | call_on_stack_noreturn(rest_init, stack); | ||
| 415 | } | 400 | } |
| 416 | 401 | ||
| 417 | static void __init setup_lowcore(void) | 402 | static void __init setup_lowcore(void) |
| 418 | { | 403 | { |
| 419 | struct lowcore *lc, *abs_lc; | 404 | struct lowcore *lc, *abs_lc; |
| 420 | unsigned long mcck_stack; | ||
| 421 | 405 | ||
| 422 | /* | 406 | /* |
| 423 | * Setup lowcore for boot cpu | 407 | * Setup lowcore for boot cpu |
| @@ -441,8 +425,6 @@ static void __init setup_lowcore(void) · 17 unmodified lines | |||
| 441 | lc->io_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK; | 425 | lc->io_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK; |
| 442 | lc->io_new_psw.addr = (unsigned long) io_int_handler; | 426 | lc->io_new_psw.addr = (unsigned long) io_int_handler; |
| 443 | lc->clock_comparator = clock_comparator_max; | 427 | lc->clock_comparator = clock_comparator_max; |
| 444 | lc->nodat_stack = ((unsigned long) &init_thread_union) | ||
| 445 | + THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs); | ||
| 446 | lc->current_task = (unsigned long)&init_task; | 428 | lc->current_task = (unsigned long)&init_task; |
| 447 | lc->lpp = LPP_MAGIC; | 429 | lc->lpp = LPP_MAGIC; |
| 448 | lc->machine_flags = S390_lowcore.machine_flags; | 430 | lc->machine_flags = S390_lowcore.machine_flags; |
| @@ -455,17 +437,15 @@ static void __init setup_lowcore(void) · 6 unmodified lines | |||
| 455 | lc->steal_timer = S390_lowcore.steal_timer; | 437 | lc->steal_timer = S390_lowcore.steal_timer; |
| 456 | lc->last_update_timer = S390_lowcore.last_update_timer; | 438 | lc->last_update_timer = S390_lowcore.last_update_timer; |
| 457 | lc->last_update_clock = S390_lowcore.last_update_clock; | 439 | lc->last_update_clock = S390_lowcore.last_update_clock; |
| 458 | |||
| 459 | /* | 440 | /* |
| 460 | * Allocate the global restart stack which is the same for | 441 | * Allocate the global restart stack which is the same for |
| 461 | * all CPUs in cast *one* of them does a PSW restart. | 442 | * all CPUs in case *one* of them does a PSW restart. |
| 462 | */ | 443 | */ |
| 463 | restart_stack = memblock_alloc(THREAD_SIZE, THREAD_SIZE); | 444 | restart_stack = (void *)(stack_alloc_early() + STACK_INIT_OFFSET); |
| 464 | if (!restart_stack) | 445 | lc->mcck_stack = stack_alloc_early() + STACK_INIT_OFFSET; |
| 465 | panic("%s: Failed to allocate %lu bytes align=0x%lx\n", | 446 | lc->async_stack = stack_alloc_early() + STACK_INIT_OFFSET; |
| 466 | __func__, THREAD_SIZE, THREAD_SIZE); | 447 | lc->nodat_stack = stack_alloc_early() + STACK_INIT_OFFSET; |
| 467 | restart_stack += STACK_INIT_OFFSET; | 448 | lc->kernel_stack = S390_lowcore.kernel_stack; |
| 468 | |||
| 469 | /* | 449 | /* |
| 470 | * Set up PSW restart to call ipl.c:do_restart(). Copy the relevant | 450 | * Set up PSW restart to call ipl.c:do_restart(). Copy the relevant |
| 471 | * restart data to the absolute zero lowcore. This is necessary if | 451 | * restart data to the absolute zero lowcore. This is necessary if |
| @@ -476,13 +456,6 @@ static void __init setup_lowcore(void) · 4 unmodified lines | |||
| 476 | lc->restart_data = 0; | 456 | lc->restart_data = 0; |
| 477 | lc->restart_source = -1U; | 457 | lc->restart_source = -1U; |
| 478 | __ctl_store(lc->cregs_save_area, 0, 15); | 458 | __ctl_store(lc->cregs_save_area, 0, 15); |
| 479 | |||
| 480 | mcck_stack = (unsigned long)memblock_alloc(THREAD_SIZE, THREAD_SIZE); | ||
| 481 | if (!mcck_stack) | ||
| 482 | panic("%s: Failed to allocate %lu bytes align=0x%lx\n", | ||
| 483 | __func__, THREAD_SIZE, THREAD_SIZE); | ||
| 484 | lc->mcck_stack = mcck_stack + STACK_INIT_OFFSET; | ||
| 485 | |||
| 486 | lc->spinlock_lockval = arch_spin_lockval(0); | 459 | lc->spinlock_lockval = arch_spin_lockval(0); |
| 487 | lc->spinlock_index = 0; | 460 | lc->spinlock_index = 0; |
| 488 | arch_spin_lock_setup(0); | 461 | arch_spin_lock_setup(0); |
| @@ -635,7 +608,11 @@ static struct notifier_block kdump_mem_nb = { · 146 unmodified lines | |||
| 635 | */ | 608 | */ |
| 636 | static void __init reserve_pgtables(void) | 609 | static void __init reserve_pgtables(void) |
| 637 | { | 610 | { |
| 638 | memblock_reserve(pgalloc_pos, pgalloc_end - pgalloc_pos); | 611 | unsigned long start, end; |
| 612 | struct reserved_range *range; | ||
| 613 | |||
| 614 | for_each_physmem_reserved_type_range(RR_VMEM, range, &start, &end) | ||
| 615 | memblock_reserve(start, end - start); | ||
| 639 | } | 616 | } |
| 640 | 617 | ||
| 641 | /* | 618 | /* |
| @@ -712,13 +689,13 @@ static void __init reserve_crashkernel(void) · 70 unmodified lines | |||
| 712 | */ | 689 | */ |
| 713 | static void __init reserve_initrd(void) | 690 | static void __init reserve_initrd(void) |
| 714 | { | 691 | { |
| 715 | #ifdef CONFIG_BLK_DEV_INITRD | 692 | unsigned long addr, size; |
| 716 | if (!initrd_data.start || !initrd_data.size) | 693 | |
| 694 | if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD) || !get_physmem_reserved(RR_INITRD, &addr, &size)) | ||
| 717 | return; | 695 | return; |
| 718 | initrd_start = (unsigned long)__va(initrd_data.start); | 696 | initrd_start = (unsigned long)__va(addr); |
| 719 | initrd_end = initrd_start + initrd_data.size; | 697 | initrd_end = initrd_start + size; |
| 720 | memblock_reserve(initrd_data.start, initrd_data.size); | 698 | memblock_reserve(addr, size); |
| 721 | #endif | ||
| 722 | } | 699 | } |
| 723 | 700 | ||
| 724 | /* | 701 | /* |
| @@ -730,71 +707,39 @@ static void __init reserve_certificate_list(void) · 5 unmodified lines | |||
| 730 | memblock_reserve(ipl_cert_list_addr, ipl_cert_list_size); | 707 | memblock_reserve(ipl_cert_list_addr, ipl_cert_list_size); |
| 731 | } | 708 | } |
| 732 | 709 | ||
| 733 | static void __init reserve_mem_detect_info(void) | 710 | static void __init reserve_physmem_info(void) |
| 734 | { | 711 | { |
| 735 | unsigned long start, size; | 712 | unsigned long addr, size; |
| 736 | 713 | ||
| 737 | get_mem_detect_reserved(&start, &size); | 714 | if (get_physmem_reserved(RR_MEM_DETECT_EXTENDED, &addr, &size)) |
| 738 | if (size) | 715 | memblock_reserve(addr, size); |
| 739 | memblock_reserve(start, size); | ||
| 740 | } | 716 | } |
| 741 | 717 | ||
| 742 | static void __init free_mem_detect_info(void) | 718 | static void __init free_physmem_info(void) |
| 743 | { | 719 | { |
| 744 | unsigned long start, size; | 720 | unsigned long addr, size; |
| 745 | 721 | ||
| 746 | get_mem_detect_reserved(&start, &size); | 722 | if (get_physmem_reserved(RR_MEM_DETECT_EXTENDED, &addr, &size)) |
| 747 | if (size) | 723 | memblock_phys_free(addr, size); |
| 748 | memblock_phys_free(start, size); | ||
| 749 | } | 724 | } |
| 750 | 725 | ||
| 751 | static const char * __init get_mem_info_source(void) | 726 | static void __init memblock_add_physmem_info(void) |
| 752 | { | ||
| 753 | switch (mem_detect.info_source) { | ||
| 754 | case MEM_DETECT_SCLP_STOR_INFO: | ||
| 755 | return "sclp storage info"; | ||
| 756 | case MEM_DETECT_DIAG260: | ||
| 757 | return "diag260"; | ||
| 758 | case MEM_DETECT_SCLP_READ_INFO: | ||
| 759 | return "sclp read info"; | ||
| 760 | case MEM_DETECT_BIN_SEARCH: | ||
| 761 | return "binary search"; | ||
| 762 | } | ||
| 763 | return "none"; | ||
| 764 | } | ||
| 765 | |||
| 766 | static void __init memblock_add_mem_detect_info(void) | ||
| 767 | { | 727 | { |
| 768 | unsigned long start, end; | 728 | unsigned long start, end; |
| 769 | int i; | 729 | int i; |
| 770 | 730 | ||
| 771 | pr_debug("physmem info source: %s (%hhd)\n", | 731 | pr_debug("physmem info source: %s (%hhd)\n", |
| 772 | get_mem_info_source(), mem_detect.info_source); | 732 | get_physmem_info_source(), physmem_info.info_source); |
| 773 | /* keep memblock lists close to the kernel */ | 733 | /* keep memblock lists close to the kernel */ |
| 774 | memblock_set_bottom_up(true); | 734 | memblock_set_bottom_up(true); |
| 775 | for_each_mem_detect_usable_block(i, &start, &end) | 735 | for_each_physmem_usable_range(i, &start, &end) |
| 776 | memblock_add(start, end - start); | 736 | memblock_add(start, end - start); |
| 777 | for_each_mem_detect_block(i, &start, &end) | 737 | for_each_physmem_online_range(i, &start, &end) |
| 778 | memblock_physmem_add(start, end - start); | 738 | memblock_physmem_add(start, end - start); |
| 779 | memblock_set_bottom_up(false); | 739 | memblock_set_bottom_up(false); |
| 780 | memblock_set_node(0, ULONG_MAX, &memblock.memory, 0); | 740 | memblock_set_node(0, ULONG_MAX, &memblock.memory, 0); |
| 781 | } | 741 | } |
| 782 | 742 | ||
| 783 | /* | ||
| 784 | * Check for initrd being in usable memory | ||
| 785 | */ | ||
| 786 | static void __init check_initrd(void) | ||
| 787 | { | ||
| 788 | #ifdef CONFIG_BLK_DEV_INITRD | ||
| 789 | if (initrd_data.start && initrd_data.size && | ||
| 790 | !memblock_is_region_memory(initrd_data.start, initrd_data.size)) { | ||
| 791 | pr_err("The initial RAM disk does not fit into the memory\n"); | ||
| 792 | memblock_phys_free(initrd_data.start, initrd_data.size); | ||
| 793 | initrd_start = initrd_end = 0; | ||
| 794 | } | ||
| 795 | #endif | ||
| 796 | } | ||
| 797 | |||
| 798 | /* | 743 | /* |
| 799 | * Reserve memory used for lowcore/command line/kernel image. | 744 | * Reserve memory used for lowcore/command line/kernel image. |
| 800 | */ | 745 | */ |
| @@ -803,7 +748,7 @@ static void __init reserve_kernel(void) · 2 unmodified lines | |||
| 803 | memblock_reserve(0, STARTUP_NORMAL_OFFSET); | 748 | memblock_reserve(0, STARTUP_NORMAL_OFFSET); |
| 804 | memblock_reserve(OLDMEM_BASE, sizeof(unsigned long)); | 749 | memblock_reserve(OLDMEM_BASE, sizeof(unsigned long)); |
| 805 | memblock_reserve(OLDMEM_SIZE, sizeof(unsigned long)); | 750 | memblock_reserve(OLDMEM_SIZE, sizeof(unsigned long)); |
| 806 | memblock_reserve(__amode31_base, __eamode31 - __samode31); | 751 | memblock_reserve(physmem_info.reserved[RR_AMODE31].start, __eamode31 - __samode31); |
| 807 | memblock_reserve(__pa(sclp_early_sccb), EXT_SCCB_READ_SCP); | 752 | memblock_reserve(__pa(sclp_early_sccb), EXT_SCCB_READ_SCP); |
| 808 | memblock_reserve(__pa(_stext), _end - _stext); | 753 | memblock_reserve(__pa(_stext), _end - _stext); |
| 809 | } | 754 | } |
| @@ -825,13 +770,13 @@ static void __init setup_memory(void) · 15 unmodified lines | |||
| 825 | static void __init relocate_amode31_section(void) | 770 | static void __init relocate_amode31_section(void) |
| 826 | { | 771 | { |
| 827 | unsigned long amode31_size = __eamode31 - __samode31; | 772 | unsigned long amode31_size = __eamode31 - __samode31; |
| 828 | long amode31_offset = __amode31_base - __samode31; | 773 | long amode31_offset = physmem_info.reserved[RR_AMODE31].start - __samode31; |
| 829 | long *ptr; | 774 | long *ptr; |
| 830 | 775 | ||
| 831 | pr_info("Relocating AMODE31 section of size 0x%08lx\n", amode31_size); | 776 | pr_info("Relocating AMODE31 section of size 0x%08lx\n", amode31_size); |
| 832 | 777 | ||
| 833 | /* Move original AMODE31 section to the new one */ | 778 | /* Move original AMODE31 section to the new one */ |
| 834 | memmove((void *)__amode31_base, (void *)__samode31, amode31_size); | 779 | memmove((void *)physmem_info.reserved[RR_AMODE31].start, (void *)__samode31, amode31_size); |
| 835 | /* Zero out the old AMODE31 section to catch invalid accesses within it */ | 780 | /* Zero out the old AMODE31 section to catch invalid accesses within it */ |
| 836 | memset((void *)__samode31, 0, amode31_size); | 781 | memset((void *)__samode31, 0, amode31_size); |
| 837 | 782 | ||
| @@ -997,14 +942,14 @@ void __init setup_arch(char **cmdline_p) · 159 unmodified lines | |||
| 997 | reserve_kernel(); | 942 | reserve_kernel(); |
| 998 | reserve_initrd(); | 943 | reserve_initrd(); |
| 999 | reserve_certificate_list(); | 944 | reserve_certificate_list(); |
| 1000 | reserve_mem_detect_info(); | 945 | reserve_physmem_info(); |
| 1001 | memblock_set_current_limit(ident_map_size); | 946 | memblock_set_current_limit(ident_map_size); |
| 1002 | memblock_allow_resize(); | 947 | memblock_allow_resize(); |
| 1003 | 948 | ||
| 1004 | /* Get information about *all* installed memory */ | 949 | /* Get information about *all* installed memory */ |
| 1005 | memblock_add_mem_detect_info(); | 950 | memblock_add_physmem_info(); |
| 1006 | 951 | ||
| 1007 | free_mem_detect_info(); | 952 | free_physmem_info(); |
| 1008 | setup_memory_end(); | 953 | setup_memory_end(); |
| 1009 | memblock_dump_all(); | 954 | memblock_dump_all(); |
| 1010 | setup_memory(); | 955 | setup_memory(); |
| @@ -1017,7 +962,6 @@ void __init setup_arch(char **cmdline_p) · 6 unmodified lines | |||
| 1017 | if (MACHINE_HAS_EDAT2) | 962 | if (MACHINE_HAS_EDAT2) |
| 1018 | hugetlb_cma_reserve(PUD_SHIFT - PAGE_SHIFT); | 963 | hugetlb_cma_reserve(PUD_SHIFT - PAGE_SHIFT); |
| 1019 | 964 | ||
| 1020 | check_initrd(); | ||
| 1021 | reserve_crashkernel(); | 965 | reserve_crashkernel(); |
| 1022 | #ifdef CONFIG_CRASH_DUMP | 966 | #ifdef CONFIG_CRASH_DUMP |
| 1023 | /* | 967 | /* |
| @@ -280,9 +280,8 @@ static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk) · 279 unmodified lines | |||
| 280 | 280 | ||
| 281 | cpu = pcpu - pcpu_devices; | 281 | cpu = pcpu - pcpu_devices; |
| 282 | lc = lowcore_ptr[cpu]; | 282 | lc = lowcore_ptr[cpu]; |
| 283 | lc->kernel_stack = (unsigned long) task_stack_page(tsk) | 283 | lc->kernel_stack = (unsigned long)task_stack_page(tsk) + STACK_INIT_OFFSET; |
| 284 | + THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs); | 284 | lc->current_task = (unsigned long)tsk; |
| 285 | lc->current_task = (unsigned long) tsk; | ||
| 286 | lc->lpp = LPP_MAGIC; | 285 | lc->lpp = LPP_MAGIC; |
| 287 | lc->current_pid = tsk->pid; | 286 | lc->current_pid = tsk->pid; |
| 288 | lc->user_timer = tsk->thread.user_timer; | 287 | lc->user_timer = tsk->thread.user_timer; |
| @@ -348,7 +347,6 @@ static void pcpu_delegate(struct pcpu *pcpu, · 59 unmodified lines | |||
| 348 | abs_lc->restart_source = source_cpu; | 347 | abs_lc->restart_source = source_cpu; |
| 349 | put_abs_lowcore(abs_lc); | 348 | put_abs_lowcore(abs_lc); |
| 350 | } | 349 | } |
| 351 | __bpon(); | ||
| 352 | asm volatile( | 350 | asm volatile( |
| 353 | "0: sigp 0,%0,%2 # sigp restart to target cpu\n" | 351 | "0: sigp 0,%0,%2 # sigp restart to target cpu\n" |
| 354 | " brc 2,0b # busy, try again\n" | 352 | " brc 2,0b # busy, try again\n" |
| @@ -986,7 +984,6 @@ void __cpu_die(unsigned int cpu) · 631 unmodified lines | |||
| 986 | void __noreturn cpu_die(void) | 984 | void __noreturn cpu_die(void) |
| 987 | { | 985 | { |
| 988 | idle_task_exit(); | 986 | idle_task_exit(); |
| 989 | __bpon(); | ||
| 990 | pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0); | 987 | pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0); |
| 991 | for (;;) ; | 988 | for (;;) ; |
| 992 | } | 989 | } |
| @@ -1302,9 +1299,9 @@ int __init smp_reinit_ipl_cpu(void) · 309 unmodified lines | |||
| 1302 | local_mcck_enable(); | 1299 | local_mcck_enable(); |
| 1303 | local_irq_restore(flags); | 1300 | local_irq_restore(flags); |
| 1304 | 1301 | ||
| 1305 | free_pages(lc_ipl->async_stack - STACK_INIT_OFFSET, THREAD_SIZE_ORDER); | ||
| 1306 | memblock_free_late(__pa(lc_ipl->mcck_stack - STACK_INIT_OFFSET), THREAD_SIZE); | 1302 | memblock_free_late(__pa(lc_ipl->mcck_stack - STACK_INIT_OFFSET), THREAD_SIZE); |
| 1303 | memblock_free_late(__pa(lc_ipl->async_stack - STACK_INIT_OFFSET), THREAD_SIZE); | ||
| 1304 | memblock_free_late(__pa(lc_ipl->nodat_stack - STACK_INIT_OFFSET), THREAD_SIZE); | ||
| 1307 | memblock_free_late(__pa(lc_ipl), sizeof(*lc_ipl)); | 1305 | memblock_free_late(__pa(lc_ipl), sizeof(*lc_ipl)); |
| 1308 | |||
| 1309 | return 0; | 1306 | return 0; |
| 1310 | } | 1307 | } |
| @@ -449,7 +449,7 @@ · 448 unmodified lines | |||
| 449 | 444 common landlock_create_ruleset sys_landlock_create_ruleset sys_landlock_create_ruleset | 449 | 444 common landlock_create_ruleset sys_landlock_create_ruleset sys_landlock_create_ruleset |
| 450 | 445 common landlock_add_rule sys_landlock_add_rule sys_landlock_add_rule | 450 | 445 common landlock_add_rule sys_landlock_add_rule sys_landlock_add_rule |
| 451 | 446 common landlock_restrict_self sys_landlock_restrict_self sys_landlock_restrict_self | 451 | 446 common landlock_restrict_self sys_landlock_restrict_self sys_landlock_restrict_self |
| 452 | # 447 reserved for memfd_secret | 452 | 447 common memfd_secret sys_memfd_secret sys_memfd_secret |
| 453 | 448 common process_mrelease sys_process_mrelease sys_process_mrelease | 453 | 448 common process_mrelease sys_process_mrelease sys_process_mrelease |
| 454 | 449 common futex_waitv sys_futex_waitv sys_futex_waitv | 454 | 449 common futex_waitv sys_futex_waitv sys_futex_waitv |
| 455 | 450 common set_mempolicy_home_node sys_set_mempolicy_home_node sys_set_mempolicy_home_node | 455 | 450 common set_mempolicy_home_node sys_set_mempolicy_home_node sys_set_mempolicy_home_node |
| @@ -27,7 +27,7 @@ · 26 unmodified lines | |||
| 27 | /* | 27 | /* |
| 28 | * int _diag14_amode31(unsigned long rx, unsigned long ry1, unsigned long subcode) | 28 | * int _diag14_amode31(unsigned long rx, unsigned long ry1, unsigned long subcode) |
| 29 | */ | 29 | */ |
| 30 | ENTRY(_diag14_amode31) | 30 | SYM_FUNC_START(_diag14_amode31) |
| 31 | lgr %r1,%r2 | 31 | lgr %r1,%r2 |
| 32 | lgr %r2,%r3 | 32 | lgr %r2,%r3 |
| 33 | lgr %r3,%r4 | 33 | lgr %r3,%r4 |
| @@ -42,12 +42,12 @@ ENTRY(_diag14_amode31) · 8 unmodified lines | |||
| 42 | lgfr %r2,%r5 | 42 | lgfr %r2,%r5 |
| 43 | BR_EX_AMODE31_r14 | 43 | BR_EX_AMODE31_r14 |
| 44 | EX_TABLE_AMODE31(.Ldiag14_ex, .Ldiag14_fault) | 44 | EX_TABLE_AMODE31(.Ldiag14_ex, .Ldiag14_fault) |
| 45 | ENDPROC(_diag14_amode31) | 45 | SYM_FUNC_END(_diag14_amode31) |
| 46 | 46 | ||
| 47 | /* | 47 | /* |
| 48 | * int _diag210_amode31(struct diag210 *addr) | 48 | * int _diag210_amode31(struct diag210 *addr) |
| 49 | */ | 49 | */ |
| 50 | ENTRY(_diag210_amode31) | 50 | SYM_FUNC_START(_diag210_amode31) |
| 51 | lgr %r1,%r2 | 51 | lgr %r1,%r2 |
| 52 | lhi %r2,-1 | 52 | lhi %r2,-1 |
| 53 | sam31 | 53 | sam31 |
| @@ -60,12 +60,12 @@ ENTRY(_diag210_amode31) · 6 unmodified lines | |||
| 60 | lgfr %r2,%r2 | 60 | lgfr %r2,%r2 |
| 61 | BR_EX_AMODE31_r14 | 61 | BR_EX_AMODE31_r14 |
| 62 | EX_TABLE_AMODE31(.Ldiag210_ex, .Ldiag210_fault) | 62 | EX_TABLE_AMODE31(.Ldiag210_ex, .Ldiag210_fault) |
| 63 | ENDPROC(_diag210_amode31) | 63 | SYM_FUNC_END(_diag210_amode31) |
| 64 | 64 | ||
| 65 | /* | 65 | /* |
| 66 | * int diag8c(struct diag8c *addr, struct ccw_dev_id *devno, size_t len) | 66 | * int diag8c(struct diag8c *addr, struct ccw_dev_id *devno, size_t len) |
| 67 | */ | 67 | */ |
| 68 | ENTRY(_diag8c_amode31) | 68 | SYM_FUNC_START(_diag8c_amode31) |
| 69 | llgf %r3,0(%r3) | 69 | llgf %r3,0(%r3) |
| 70 | sam31 | 70 | sam31 |
| 71 | diag %r2,%r4,0x8c | 71 | diag %r2,%r4,0x8c |
| @@ -74,11 +74,11 @@ ENTRY(_diag8c_amode31) · 2 unmodified lines | |||
| 74 | lgfr %r2,%r3 | 74 | lgfr %r2,%r3 |
| 75 | BR_EX_AMODE31_r14 | 75 | BR_EX_AMODE31_r14 |
| 76 | EX_TABLE_AMODE31(.Ldiag8c_ex, .Ldiag8c_ex) | 76 | EX_TABLE_AMODE31(.Ldiag8c_ex, .Ldiag8c_ex) |
| 77 | ENDPROC(_diag8c_amode31) | 77 | SYM_FUNC_END(_diag8c_amode31) |
| 78 | /* | 78 | /* |
| 79 | * int _diag26c_amode31(void *req, void *resp, enum diag26c_sc subcode) | 79 | * int _diag26c_amode31(void *req, void *resp, enum diag26c_sc subcode) |
| 80 | */ | 80 | */ |
| 81 | ENTRY(_diag26c_amode31) | 81 | SYM_FUNC_START(_diag26c_amode31) |
| 82 | lghi %r5,-EOPNOTSUPP | 82 | lghi %r5,-EOPNOTSUPP |
| 83 | sam31 | 83 | sam31 |
| 84 | diag %r2,%r4,0x26c | 84 | diag %r2,%r4,0x26c |
| @@ -87,42 +87,42 @@ ENTRY(_diag26c_amode31) · 2 unmodified lines | |||
| 87 | lgfr %r2,%r5 | 87 | lgfr %r2,%r5 |
| 88 | BR_EX_AMODE31_r14 | 88 | BR_EX_AMODE31_r14 |
| 89 | EX_TABLE_AMODE31(.Ldiag26c_ex, .Ldiag26c_ex) | 89 | EX_TABLE_AMODE31(.Ldiag26c_ex, .Ldiag26c_ex) |
| 90 | ENDPROC(_diag26c_amode31) | 90 | SYM_FUNC_END(_diag26c_amode31) |
| 91 | 91 | ||
| 92 | /* | 92 | /* |
| 93 | * void _diag0c_amode31(struct hypfs_diag0c_entry *entry) | 93 | * void _diag0c_amode31(struct hypfs_diag0c_entry *entry) |
| 94 | */ | 94 | */ |
| 95 | ENTRY(_diag0c_amode31) | 95 | SYM_FUNC_START(_diag0c_amode31) |
| 96 | sam31 | 96 | sam31 |
| 97 | diag %r2,%r2,0x0c | 97 | diag %r2,%r2,0x0c |
| 98 | sam64 | 98 | sam64 |
| 99 | BR_EX_AMODE31_r14 | 99 | BR_EX_AMODE31_r14 |
| 100 | ENDPROC(_diag0c_amode31) | 100 | SYM_FUNC_END(_diag0c_amode31) |
| 101 | 101 | ||
| 102 | /* | 102 | /* |
| 103 | * void _diag308_reset_amode31(void) | 103 | * void _diag308_reset_amode31(void) |
| 104 | * | 104 | * |
| 105 | * Calls diag 308 subcode 1 and continues execution | 105 | * Calls diag 308 subcode 1 and continues execution |
| 106 | */ | 106 | */ |
| 107 | ENTRY(_diag308_reset_amode31) | 107 | SYM_FUNC_START(_diag308_reset_amode31) |
| 108 | larl %r4,.Lctlregs # Save control registers | 108 | larl %r4,ctlregs # Save control registers |
| 109 | stctg %c0,%c15,0(%r4) | 109 | stctg %c0,%c15,0(%r4) |
| 110 | lg %r2,0(%r4) # Disable lowcore protection | 110 | lg %r2,0(%r4) # Disable lowcore protection |
| 111 | nilh %r2,0xefff | 111 | nilh %r2,0xefff |
| 112 | larl %r4,.Lctlreg0 | 112 | larl %r4,ctlreg0 |
| 113 | stg %r2,0(%r4) | 113 | stg %r2,0(%r4) |
| 114 | lctlg %c0,%c0,0(%r4) | 114 | lctlg %c0,%c0,0(%r4) |
| 115 | larl %r4,.Lfpctl # Floating point control register | 115 | larl %r4,fpctl # Floating point control register |
| 116 | stfpc 0(%r4) | 116 | stfpc 0(%r4) |
| 117 | larl %r4,.Lprefix # Save prefix register | 117 | larl %r4,prefix # Save prefix register |
| 118 | stpx 0(%r4) | 118 | stpx 0(%r4) |
| 119 | larl %r4,.Lprefix_zero # Set prefix register to 0 | 119 | larl %r4,prefix_zero # Set prefix register to 0 |
| 120 | spx 0(%r4) | 120 | spx 0(%r4) |
| 121 | larl %r4,.Lcontinue_psw # Save PSW flags | 121 | larl %r4,continue_psw # Save PSW flags |
| 122 | epsw %r2,%r3 | 122 | epsw %r2,%r3 |
| 123 | stm %r2,%r3,0(%r4) | 123 | stm %r2,%r3,0(%r4) |
| 124 | larl %r4,.Lrestart_part2 # Setup restart PSW at absolute 0 | 124 | larl %r4,.Lrestart_part2 # Setup restart PSW at absolute 0 |
| 125 | larl %r3,.Lrestart_diag308_psw | 125 | larl %r3,restart_diag308_psw |
| 126 | og %r4,0(%r3) # Save PSW | 126 | og %r4,0(%r3) # Save PSW |
| 127 | lghi %r3,0 | 127 | lghi %r3,0 |
| 128 | sturg %r4,%r3 # Use sturg, because of large pages | 128 | sturg %r4,%r3 # Use sturg, because of large pages |
| @@ -134,39 +134,26 @@ ENTRY(_diag308_reset_amode31) · 5 unmodified lines | |||
| 134 | lhi %r1,2 # Use mode 2 = ESAME (dump) | 134 | lhi %r1,2 # Use mode 2 = ESAME (dump) |
| 135 | sigp %r1,%r0,SIGP_SET_ARCHITECTURE # Switch to ESAME mode | 135 | sigp %r1,%r0,SIGP_SET_ARCHITECTURE # Switch to ESAME mode |
| 136 | sam64 # Switch to 64 bit addressing mode | 136 | sam64 # Switch to 64 bit addressing mode |
| 137 | larl %r4,.Lctlregs # Restore control registers | 137 | larl %r4,ctlregs # Restore control registers |
| 138 | lctlg %c0,%c15,0(%r4) | 138 | lctlg %c0,%c15,0(%r4) |
| 139 | larl %r4,.Lfpctl # Restore floating point ctl register | 139 | larl %r4,fpctl # Restore floating point ctl register |
| 140 | lfpc 0(%r4) | 140 | lfpc 0(%r4) |
| 141 | larl %r4,.Lprefix # Restore prefix register | 141 | larl %r4,prefix # Restore prefix register |
| 142 | spx 0(%r4) | 142 | spx 0(%r4) |
| 143 | larl %r4,.Lcontinue_psw # Restore PSW flags | 143 | larl %r4,continue_psw # Restore PSW flags |
| 144 | larl %r2,.Lcontinue | 144 | larl %r2,.Lcontinue |
| 145 | stg %r2,8(%r4) | 145 | stg %r2,8(%r4) |
| 146 | lpswe 0(%r4) | 146 | lpswe 0(%r4) |
| 147 | .Lcontinue: | 147 | .Lcontinue: |
| 148 | BR_EX_AMODE31_r14 | 148 | BR_EX_AMODE31_r14 |
| 149 | ENDPROC(_diag308_reset_amode31) | 149 | SYM_FUNC_END(_diag308_reset_amode31) |
| 150 | 150 | ||
| 151 | .section .amode31.data,"aw",@progbits | 151 | .section .amode31.data,"aw",@progbits |
| 152 | .align 8 | 152 | .balign 8 |
| 153 | .Lrestart_diag308_psw: | 153 | SYM_DATA_LOCAL(restart_diag308_psw, .long 0x00080000,0x80000000) |
| 154 | .long 0x00080000,0x80000000 | 154 | SYM_DATA_LOCAL(continue_psw, .quad 0,0) |
| 155 | 155 | SYM_DATA_LOCAL(ctlreg0, .quad 0) | |
| 156 | .align 8 | 156 | SYM_DATA_LOCAL(ctlregs, .fill 16,8,0) |
| 157 | .Lcontinue_psw: | 157 | SYM_DATA_LOCAL(fpctl, .long 0) |
| 158 | .quad 0,0 | 158 | SYM_DATA_LOCAL(prefix, .long 0) |
| 159 | 159 | SYM_DATA_LOCAL(prefix_zero, .long 0) | |
| 160 | .align 8 | ||
| 161 | .Lctlreg0: | ||
| 162 | .quad 0 | ||
| 163 | .Lctlregs: | ||
| 164 | .rept 16 | ||
| 165 | .quad 0 | ||
| 166 | .endr | ||
| 167 | .Lfpctl: | ||
| 168 | .long 0 | ||
| 169 | .Lprefix: | ||
| 170 | .long 0 | ||
| 171 | .Lprefix_zero: | ||
| 172 | .long 0 | ||
| @@ -637,16 +637,6 @@ static struct ctl_table topology_ctl_table[] = { · 636 unmodified lines | |||
| 637 | { }, | 637 | { }, |
| 638 | }; | 638 | }; |
| 639 | 639 | ||
| 640 | static struct ctl_table topology_dir_table[] = { | ||
| 641 | { | ||
| 642 | .procname = "s390", | ||
| 643 | .maxlen = 0, | ||
| 644 | .mode = 0555, | ||
| 645 | .child = topology_ctl_table, | ||
| 646 | }, | ||
| 647 | { }, | ||
| 648 | }; | ||
| 649 | |||
| 650 | static int __init topology_init(void) | 640 | static int __init topology_init(void) |
| 651 | { | 641 | { |
| 652 | struct device *dev_root; | 642 | struct device *dev_root; |
| @@ -657,7 +647,7 @@ static int __init topology_init(void) · 4 unmodified lines | |||
| 657 | set_topology_timer(); | 647 | set_topology_timer(); |
| 658 | else | 648 | else |
| 659 | topology_update_polarization_simple(); | 649 | topology_update_polarization_simple(); |
| 660 | register_sysctl_table(topology_dir_table); | 650 | register_sysctl("s390", topology_ctl_table); |
| 661 | 651 | ||
| 662 | dev_root = bus_get_dev_root(&cpu_subsys); | 652 | dev_root = bus_get_dev_root(&cpu_subsys); |
| 663 | if (dev_root) { | 653 | if (dev_root) { |
| @@ -1,12 +1,13 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | 2 | ||
| 3 | #include <linux/linkage.h> | ||
| 3 | #include <asm/unistd.h> | 4 | #include <asm/unistd.h> |
| 4 | #include <asm/dwarf.h> | 5 | #include <asm/dwarf.h> |
| 5 | 6 | ||
| 6 | .macro vdso_syscall func,syscall | 7 | .macro vdso_syscall func,syscall |
| 7 | .globl __kernel_compat_\func | 8 | .globl __kernel_compat_\func |
| 8 | .type __kernel_compat_\func,@function | 9 | .type __kernel_compat_\func,@function |
| 9 | .align 8 | 10 | __ALIGN |
| 10 | __kernel_compat_\func: | 11 | __kernel_compat_\func: |
| 11 | CFI_STARTPROC | 12 | CFI_STARTPROC |
| 12 | svc \syscall | 13 | svc \syscall |
| @@ -1,4 +1,5 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | #include <linux/linkage.h> | ||
| 2 | #include <asm/vdso.h> | 3 | #include <asm/vdso.h> |
| 3 | #include <asm/unistd.h> | 4 | #include <asm/unistd.h> |
| 4 | #include <asm/asm-offsets.h> | 5 | #include <asm/asm-offsets.h> |
| @@ -16,7 +17,7 @@ · 11 unmodified lines | |||
| 16 | .macro vdso_func func | 17 | .macro vdso_func func |
| 17 | .globl __kernel_\func | 18 | .globl __kernel_\func |
| 18 | .type __kernel_\func,@function | 19 | .type __kernel_\func,@function |
| 19 | .align 8 | 20 | __ALIGN |
| 20 | __kernel_\func: | 21 | __kernel_\func: |
| 21 | CFI_STARTPROC | 22 | CFI_STARTPROC |
| 22 | aghi %r15,-WRAPPER_FRAME_SIZE | 23 | aghi %r15,-WRAPPER_FRAME_SIZE |
| @@ -41,7 +42,7 @@ vdso_func getcpu · 18 unmodified lines | |||
| 41 | .macro vdso_syscall func,syscall | 42 | .macro vdso_syscall func,syscall |
| 42 | .globl __kernel_\func | 43 | .globl __kernel_\func |
| 43 | .type __kernel_\func,@function | 44 | .type __kernel_\func,@function |
| 44 | .align 8 | 45 | __ALIGN |
| 45 | __kernel_\func: | 46 | __kernel_\func: |
| 46 | CFI_STARTPROC | 47 | CFI_STARTPROC |
| 47 | svc \syscall | 48 | svc \syscall |
| @@ -14,6 +14,8 @@ · 13 unmodified lines | |||
| 14 | #define BSS_FIRST_SECTIONS *(.bss..swapper_pg_dir) \ | 14 | #define BSS_FIRST_SECTIONS *(.bss..swapper_pg_dir) \ |
| 15 | *(.bss..invalid_pg_dir) | 15 | *(.bss..invalid_pg_dir) |
| 16 | 16 | ||
| 17 | #define RO_EXCEPTION_TABLE_ALIGN 16 | ||
| 18 | |||
| 17 | /* Handle ro_after_init data on our own. */ | 19 | /* Handle ro_after_init data on our own. */ |
| 18 | #define RO_AFTER_INIT_DATA | 20 | #define RO_AFTER_INIT_DATA |
| 19 | 21 | ||
| @@ -66,7 +68,6 @@ SECTIONS · 46 unmodified lines | |||
| 66 | *(.data..ro_after_init) | 68 | *(.data..ro_after_init) |
| 67 | JUMP_TABLE_DATA | 69 | JUMP_TABLE_DATA |
| 68 | } :data | 70 | } :data |
| 69 | EXCEPTION_TABLE(16) | ||
| 70 | . = ALIGN(PAGE_SIZE); | 71 | . = ALIGN(PAGE_SIZE); |
| 71 | __end_ro_after_init = .; | 72 | __end_ro_after_init = .; |
| 72 | 73 | ||
| @@ -219,6 +220,13 @@ SECTIONS · 146 unmodified lines | |||
| 219 | QUAD(init_mm) | 220 | QUAD(init_mm) |
| 220 | QUAD(swapper_pg_dir) | 221 | QUAD(swapper_pg_dir) |
| 221 | QUAD(invalid_pg_dir) | 222 | QUAD(invalid_pg_dir) |
| 223 | #ifdef CONFIG_KASAN | ||
| 224 | QUAD(kasan_early_shadow_page) | ||
| 225 | QUAD(kasan_early_shadow_pte) | ||
| 226 | QUAD(kasan_early_shadow_pmd) | ||
| 227 | QUAD(kasan_early_shadow_pud) | ||
| 228 | QUAD(kasan_early_shadow_p4d) | ||
| 229 | #endif | ||
| 222 | } :NONE | 230 | } :NONE |
| 223 | 231 | ||
| 224 | /* Debugging sections. */ | 232 | /* Debugging sections. */ |
| @@ -14,8 +14,7 @@ · 13 unmodified lines | |||
| 14 | /* | 14 | /* |
| 15 | * void *memmove(void *dest, const void *src, size_t n) | 15 | * void *memmove(void *dest, const void *src, size_t n) |
| 16 | */ | 16 | */ |
| 17 | WEAK(memmove) | 17 | SYM_FUNC_START(__memmove) |
| 18 | ENTRY(__memmove) | ||
| 19 | ltgr %r4,%r4 | 18 | ltgr %r4,%r4 |
| 20 | lgr %r1,%r2 | 19 | lgr %r1,%r2 |
| 21 | jz .Lmemmove_exit | 20 | jz .Lmemmove_exit |
| @@ -48,7 +47,10 @@ ENTRY(__memmove) · 26 unmodified lines | |||
| 48 | BR_EX %r14 | 47 | BR_EX %r14 |
| 49 | .Lmemmove_mvc: | 48 | .Lmemmove_mvc: |
| 50 | mvc 0(1,%r1),0(%r3) | 49 | mvc 0(1,%r1),0(%r3) |
| 51 | ENDPROC(__memmove) | 50 | SYM_FUNC_END(__memmove) |
| 51 | EXPORT_SYMBOL(__memmove) | ||
| 52 | |||
| 53 | SYM_FUNC_ALIAS(memmove, __memmove) | ||
| 52 | EXPORT_SYMBOL(memmove) | 54 | EXPORT_SYMBOL(memmove) |
| 53 | 55 | ||
| 54 | /* | 56 | /* |
| @@ -66,8 +68,7 @@ EXPORT_SYMBOL(memmove) · 11 unmodified lines | |||
| 66 | * return __builtin_memset(s, c, n); | 68 | * return __builtin_memset(s, c, n); |
| 67 | * } | 69 | * } |
| 68 | */ | 70 | */ |
| 69 | WEAK(memset) | 71 | SYM_FUNC_START(__memset) |
| 70 | ENTRY(__memset) | ||
| 71 | ltgr %r4,%r4 | 72 | ltgr %r4,%r4 |
| 72 | jz .Lmemset_exit | 73 | jz .Lmemset_exit |
| 73 | ltgr %r3,%r3 | 74 | ltgr %r3,%r3 |
| @@ -111,7 +112,10 @@ ENTRY(__memset) · 37 unmodified lines | |||
| 111 | xc 0(1,%r1),0(%r1) | 112 | xc 0(1,%r1),0(%r1) |
| 112 | .Lmemset_mvc: | 113 | .Lmemset_mvc: |
| 113 | mvc 1(1,%r1),0(%r1) | 114 | mvc 1(1,%r1),0(%r1) |
| 114 | ENDPROC(__memset) | 115 | SYM_FUNC_END(__memset) |
| 116 | EXPORT_SYMBOL(__memset) | ||
| 117 | |||
| 118 | SYM_FUNC_ALIAS(memset, __memset) | ||
| 115 | EXPORT_SYMBOL(memset) | 119 | EXPORT_SYMBOL(memset) |
| 116 | 120 | ||
| 117 | /* | 121 | /* |
| @@ -119,8 +123,7 @@ EXPORT_SYMBOL(memset) · 1 unmodified line | |||
| 119 | * | 123 | * |
| 120 | * void *memcpy(void *dest, const void *src, size_t n) | 124 | * void *memcpy(void *dest, const void *src, size_t n) |
| 121 | */ | 125 | */ |
| 122 | WEAK(memcpy) | 126 | SYM_FUNC_START(__memcpy) |
| 123 | ENTRY(__memcpy) | ||
| 124 | ltgr %r4,%r4 | 127 | ltgr %r4,%r4 |
| 125 | jz .Lmemcpy_exit | 128 | jz .Lmemcpy_exit |
| 126 | aghi %r4,-1 | 129 | aghi %r4,-1 |
| @@ -141,7 +144,10 @@ ENTRY(__memcpy) · 14 unmodified lines | |||
| 141 | j .Lmemcpy_remainder | 144 | j .Lmemcpy_remainder |
| 142 | .Lmemcpy_mvc: | 145 | .Lmemcpy_mvc: |
| 143 | mvc 0(1,%r1),0(%r3) | 146 | mvc 0(1,%r1),0(%r3) |
| 144 | ENDPROC(__memcpy) | 147 | SYM_FUNC_END(__memcpy) |
| 148 | EXPORT_SYMBOL(__memcpy) | ||
| 149 | |||
| 150 | SYM_FUNC_ALIAS(memcpy, __memcpy) | ||
| 145 | EXPORT_SYMBOL(memcpy) | 151 | EXPORT_SYMBOL(memcpy) |
| 146 | 152 | ||
| 147 | /* | 153 | /* |
| @@ -152,7 +158,7 @@ EXPORT_SYMBOL(memcpy) · 4 unmodified lines | |||
| 152 | * void *__memset64(uint64_t *s, uint64_t v, size_t count) | 158 | * void *__memset64(uint64_t *s, uint64_t v, size_t count) |
| 153 | */ | 159 | */ |
| 154 | .macro __MEMSET bits,bytes,insn | 160 | .macro __MEMSET bits,bytes,insn |
| 155 | ENTRY(__memset\bits) | 161 | SYM_FUNC_START(__memset\bits) |
| 156 | ltgr %r4,%r4 | 162 | ltgr %r4,%r4 |
| 157 | jz .L__memset_exit\bits | 163 | jz .L__memset_exit\bits |
| 158 | cghi %r4,\bytes | 164 | cghi %r4,\bytes |
| @@ -178,7 +184,7 @@ ENTRY(__memset\bits) · 19 unmodified lines | |||
| 178 | BR_EX %r14 | 184 | BR_EX %r14 |
| 179 | .L__memset_mvc\bits: | 185 | .L__memset_mvc\bits: |
| 180 | mvc \bytes(1,%r1),0(%r1) | 186 | mvc \bytes(1,%r1),0(%r1) |
| 181 | ENDPROC(__memset\bits) | 187 | SYM_FUNC_END(__memset\bits) |
| 182 | .endm | 188 | .endm |
| 183 | 189 | ||
| 184 | __MEMSET 16,2,sth | 190 | __MEMSET 16,2,sth |
| @@ -27,14 +27,13 @@ void debug_user_asce(int exit) · 26 unmodified lines | |||
| 27 | "kernel: %016llx user: %016llx\n", | 27 | "kernel: %016llx user: %016llx\n", |
| 28 | exit ? "exit" : "entry", cr1, cr7, | 28 | exit ? "exit" : "entry", cr1, cr7, |
| 29 | S390_lowcore.kernel_asce, S390_lowcore.user_asce); | 29 | S390_lowcore.kernel_asce, S390_lowcore.user_asce); |
| 30 | |||
| 31 | } | 30 | } |
| 32 | #endif /*CONFIG_DEBUG_ENTRY */ | 31 | #endif /*CONFIG_DEBUG_ENTRY */ |
| 33 | 32 | ||
| 34 | static unsigned long raw_copy_from_user_key(void *to, const void __user *from, | 33 | static unsigned long raw_copy_from_user_key(void *to, const void __user *from, |
| 35 | unsigned long size, unsigned long key) | 34 | unsigned long size, unsigned long key) |
| 36 | { | 35 | { |
| 37 | unsigned long tmp1, tmp2; | 36 | unsigned long rem; |
| 38 | union oac spec = { | 37 | union oac spec = { |
| 39 | .oac2.key = key, | 38 | .oac2.key = key, |
| 40 | .oac2.as = PSW_BITS_AS_SECONDARY, | 39 | .oac2.as = PSW_BITS_AS_SECONDARY, |
| @@ -42,28 +41,30 @@ static unsigned long raw_copy_from_user_key(void *to, const void __user *from, · 1 unmodified line | |||
| 42 | .oac2.a = 1, | 41 | .oac2.a = 1, |
| 43 | }; | 42 | }; |
| 44 | 43 | ||
| 45 | tmp1 = -4096UL; | ||
| 46 | asm volatile( | 44 | asm volatile( |
| 47 | " lr 0,%[spec]\n" | 45 | " lr 0,%[spec]\n" |
| 48 | "0: mvcos 0(%2),0(%1),%0\n" | 46 | "0: mvcos 0(%[to]),0(%[from]),%[size]\n" |
| 49 | "6: jz 4f\n" | 47 | "1: jz 5f\n" |
| 50 | "1: algr %0,%3\n" | 48 | " algr %[size],%[val]\n" |
| 51 | " slgr %1,%3\n" | 49 | " slgr %[from],%[val]\n" |
| 52 | " slgr %2,%3\n" | 50 | " slgr %[to],%[val]\n" |
| 53 | " j 0b\n" | 51 | " j 0b\n" |
| 54 | "2: la %4,4095(%1)\n"/* %4 = ptr + 4095 */ | 52 | "2: la %[rem],4095(%[from])\n" /* rem = from + 4095 */ |
| 55 | " nr %4,%3\n" /* %4 = (ptr + 4095) & -4096 */ | 53 | " nr %[rem],%[val]\n" /* rem = (from + 4095) & -4096 */ |
| 56 | " slgr %4,%1\n" | 54 | " slgr %[rem],%[from]\n" |
| 57 | " clgr %0,%4\n" /* copy crosses next page boundary? */ | 55 | " clgr %[size],%[rem]\n" /* copy crosses next page boundary? */ |
| 58 | " jnh 5f\n" | 56 | " jnh 6f\n" |
| 59 | "3: mvcos 0(%2),0(%1),%4\n" | 57 | "3: mvcos 0(%[to]),0(%[from]),%[rem]\n" |
| 60 | "7: slgr %0,%4\n" | 58 | "4: slgr %[size],%[rem]\n" |
| 61 | " j 5f\n" | 59 | " j 6f\n" |
| 62 | "4: slgr %0,%0\n" | 60 | "5: slgr %[size],%[size]\n" |
| 63 | "5:\n" | 61 | "6:\n" |
| 64 | EX_TABLE(0b,2b) EX_TABLE(3b,5b) EX_TABLE(6b,2b) EX_TABLE(7b,5b) | 62 | EX_TABLE(0b, 2b) |
| 65 | : "+a" (size), "+a" (from), "+a" (to), "+a" (tmp1), "=a" (tmp2) | 63 | EX_TABLE(1b, 2b) |
| 66 | : [spec] "d" (spec.val) | 64 | EX_TABLE(3b, 6b) |
| 65 | EX_TABLE(4b, 6b) | ||
| 66 | : [size] "+&a" (size), [from] "+&a" (from), [to] "+&a" (to), [rem] "=&a" (rem) | ||
| 67 | : [val] "a" (-4096UL), [spec] "d" (spec.val) | ||
| 67 | : "cc", "memory", "0"); | 68 | : "cc", "memory", "0"); |
| 68 | return size; | 69 | return size; |
| 69 | } | 70 | } |
| @@ -94,7 +95,7 @@ EXPORT_SYMBOL(_copy_from_user_key); · 24 unmodified lines | |||
| 94 | static unsigned long raw_copy_to_user_key(void __user *to, const void *from, | 95 | static unsigned long raw_copy_to_user_key(void __user *to, const void *from, |
| 95 | unsigned long size, unsigned long key) | 96 | unsigned long size, unsigned long key) |
| 96 | { | 97 | { |
| 97 | unsigned long tmp1, tmp2; | 98 | unsigned long rem; |
| 98 | union oac spec = { | 99 | union oac spec = { |
| 99 | .oac1.key = key, | 100 | .oac1.key = key, |
| 100 | .oac1.as = PSW_BITS_AS_SECONDARY, | 101 | .oac1.as = PSW_BITS_AS_SECONDARY, |
| @@ -102,28 +103,30 @@ static unsigned long raw_copy_to_user_key(void __user *to, const void *from, · 1 unmodified line | |||
| 102 | .oac1.a = 1, | 103 | .oac1.a = 1, |
| 103 | }; | 104 | }; |
| 104 | 105 | ||
| 105 | tmp1 = -4096UL; | ||
| 106 | asm volatile( | 106 | asm volatile( |
| 107 | " lr 0,%[spec]\n" | 107 | " lr 0,%[spec]\n" |
| 108 | "0: mvcos 0(%1),0(%2),%0\n" | 108 | "0: mvcos 0(%[to]),0(%[from]),%[size]\n" |
| 109 | "6: jz 4f\n" | 109 | "1: jz 5f\n" |
| 110 | "1: algr %0,%3\n" | 110 | " algr %[size],%[val]\n" |
| 111 | " slgr %1,%3\n" | 111 | " slgr %[to],%[val]\n" |
| 112 | " slgr %2,%3\n" | 112 | " slgr %[from],%[val]\n" |
| 113 | " j 0b\n" | 113 | " j 0b\n" |
| 114 | "2: la %4,4095(%1)\n"/* %4 = ptr + 4095 */ | 114 | "2: la %[rem],4095(%[to])\n" /* rem = to + 4095 */ |
| 115 | " nr %4,%3\n" /* %4 = (ptr + 4095) & -4096 */ | 115 | " nr %[rem],%[val]\n" /* rem = (to + 4095) & -4096 */ |
| 116 | " slgr %4,%1\n" | 116 | " slgr %[rem],%[to]\n" |
| 117 | " clgr %0,%4\n" /* copy crosses next page boundary? */ | 117 | " clgr %[size],%[rem]\n" /* copy crosses next page boundary? */ |
| 118 | " jnh 5f\n" | 118 | " jnh 6f\n" |
| 119 | "3: mvcos 0(%1),0(%2),%4\n" | 119 | "3: mvcos 0(%[to]),0(%[from]),%[rem]\n" |
| 120 | "7: slgr %0,%4\n" | 120 | "4: slgr %[size],%[rem]\n" |
| 121 | " j 5f\n" | 121 | " j 6f\n" |
| 122 | "4: slgr %0,%0\n" | 122 | "5: slgr %[size],%[size]\n" |
| 123 | "5:\n" | 123 | "6:\n" |
| 124 | EX_TABLE(0b,2b) EX_TABLE(3b,5b) EX_TABLE(6b,2b) EX_TABLE(7b,5b) | 124 | EX_TABLE(0b, 2b) |
| 125 | : "+a" (size), "+a" (to), "+a" (from), "+a" (tmp1), "=a" (tmp2) | 125 | EX_TABLE(1b, 2b) |
| 126 | : [spec] "d" (spec.val) | 126 | EX_TABLE(3b, 6b) |
| 127 | EX_TABLE(4b, 6b) | ||
| 128 | : [size] "+&a" (size), [to] "+&a" (to), [from] "+&a" (from), [rem] "=&a" (rem) | ||
| 129 | : [val] "a" (-4096UL), [spec] "d" (spec.val) | ||
| 127 | : "cc", "memory", "0"); | 130 | : "cc", "memory", "0"); |
| 128 | return size; | 131 | return size; |
| 129 | } | 132 | } |
| @@ -147,33 +150,35 @@ EXPORT_SYMBOL(_copy_to_user_key); · 17 unmodified lines | |||
| 147 | 150 | ||
| 148 | unsigned long __clear_user(void __user *to, unsigned long size) | 151 | unsigned long __clear_user(void __user *to, unsigned long size) |
| 149 | { | 152 | { |
| 150 | unsigned long tmp1, tmp2; | 153 | unsigned long rem; |
| 151 | union oac spec = { | 154 | union oac spec = { |
| 152 | .oac1.as = PSW_BITS_AS_SECONDARY, | 155 | .oac1.as = PSW_BITS_AS_SECONDARY, |
| 153 | .oac1.a = 1, | 156 | .oac1.a = 1, |
| 154 | }; | 157 | }; |
| 155 | 158 | ||
| 156 | tmp1 = -4096UL; | ||
| 157 | asm volatile( | 159 | asm volatile( |
| 158 | " lr 0,%[spec]\n" | 160 | " lr 0,%[spec]\n" |
| 159 | "0: mvcos 0(%1),0(%4),%0\n" | 161 | "0: mvcos 0(%[to]),0(%[zeropg]),%[size]\n" |
| 160 | "6: jz 4f\n" | 162 | "1: jz 5f\n" |
| 161 | "1: algr %0,%2\n" | 163 | " algr %[size],%[val]\n" |
| 162 | " slgr %1,%2\n" | 164 | " slgr %[to],%[val]\n" |
| 163 | " j 0b\n" | 165 | " j 0b\n" |
| 164 | "2: la %3,4095(%1)\n"/* %4 = to + 4095 */ | 166 | "2: la %[rem],4095(%[to])\n" /* rem = to + 4095 */ |
| 165 | " nr %3,%2\n" /* %4 = (to + 4095) & -4096 */ | 167 | " nr %[rem],%[val]\n" /* rem = (to + 4095) & -4096 */ |
| 166 | " slgr %3,%1\n" | 168 | " slgr %[rem],%[to]\n" |
| 167 | " clgr %0,%3\n" /* copy crosses next page boundary? */ | 169 | " clgr %[size],%[rem]\n" /* copy crosses next page boundary? */ |
| 168 | " jnh 5f\n" | 170 | " jnh 6f\n" |
| 169 | "3: mvcos 0(%1),0(%4),%3\n" | 171 | "3: mvcos 0(%[to]),0(%[zeropg]),%[rem]\n" |
| 170 | "7: slgr %0,%3\n" | 172 | "4: slgr %[size],%[rem]\n" |
| 171 | " j 5f\n" | 173 | " j 6f\n" |
| 172 | "4: slgr %0,%0\n" | 174 | "5: slgr %[size],%[size]\n" |
| 173 | "5:\n" | 175 | "6:\n" |
| 174 | EX_TABLE(0b,2b) EX_TABLE(6b,2b) EX_TABLE(3b,5b) EX_TABLE(7b,5b) | 176 | EX_TABLE(0b, 2b) |
| 175 | : "+&a" (size), "+&a" (to), "+a" (tmp1), "=&a" (tmp2) | 177 | EX_TABLE(1b, 2b) |
| 176 | : "a" (empty_zero_page), [spec] "d" (spec.val) | 178 | EX_TABLE(3b, 6b) |
| 179 | EX_TABLE(4b, 6b) | ||
| 180 | : [size] "+&a" (size), [to] "+&a" (to), [rem] "=&a" (rem) | ||
| 181 | : [val] "a" (-4096UL), [zeropg] "a" (empty_zero_page), [spec] "d" (spec.val) | ||
| 177 | : "cc", "memory", "0"); | 182 | : "cc", "memory", "0"); |
| 178 | return size; | 183 | return size; |
| 179 | } | 184 | } |
| @@ -10,6 +10,3 @@ obj-$(CONFIG_CMM) += cmm.o · 9 unmodified lines | |||
| 10 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | 10 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o |
| 11 | obj-$(CONFIG_PTDUMP_CORE) += dump_pagetables.o | 11 | obj-$(CONFIG_PTDUMP_CORE) += dump_pagetables.o |
| 12 | obj-$(CONFIG_PGSTE) += gmap.o | 12 | obj-$(CONFIG_PGSTE) += gmap.o |
| 13 | |||
| 14 | KASAN_SANITIZE_kasan_init.o := n | ||
| 15 | obj-$(CONFIG_KASAN) += kasan_init.o | ||
| @@ -335,16 +335,6 @@ static struct ctl_table cmm_table[] = { · 334 unmodified lines | |||
| 335 | { } | 335 | { } |
| 336 | }; | 336 | }; |
| 337 | 337 | ||
| 338 | static struct ctl_table cmm_dir_table[] = { | ||
| 339 | { | ||
| 340 | .procname = "vm", | ||
| 341 | .maxlen = 0, | ||
| 342 | .mode = 0555, | ||
| 343 | .child = cmm_table, | ||
| 344 | }, | ||
| 345 | { } | ||
| 346 | }; | ||
| 347 | |||
| 348 | #ifdef CONFIG_CMM_IUCV | 338 | #ifdef CONFIG_CMM_IUCV |
| 349 | #define SMSG_PREFIX "CMM" | 339 | #define SMSG_PREFIX "CMM" |
| 350 | static void cmm_smsg_target(const char *from, char *msg) | 340 | static void cmm_smsg_target(const char *from, char *msg) |
| @@ -389,7 +379,7 @@ static int __init cmm_init(void) · 38 unmodified lines | |||
| 389 | { | 379 | { |
| 390 | int rc = -ENOMEM; | 380 | int rc = -ENOMEM; |
| 391 | 381 | ||
| 392 | cmm_sysctl_header = register_sysctl_table(cmm_dir_table); | 382 | cmm_sysctl_header = register_sysctl("vm", cmm_table); |
| 393 | if (!cmm_sysctl_header) | 383 | if (!cmm_sysctl_header) |
| 394 | goto out_sysctl; | 384 | goto out_sysctl; |
| 395 | #ifdef CONFIG_CMM_IUCV | 385 | #ifdef CONFIG_CMM_IUCV |
| @@ -176,9 +176,8 @@ void __init mem_init(void) · 175 unmodified lines | |||
| 176 | 176 | ||
| 177 | void free_initmem(void) | 177 | void free_initmem(void) |
| 178 | { | 178 | { |
| 179 | __set_memory((unsigned long)_sinittext, | 179 | set_memory_rwnx((unsigned long)_sinittext, |
| 180 | (unsigned long)(_einittext - _sinittext) >> PAGE_SHIFT, | 180 | (unsigned long)(_einittext - _sinittext) >> PAGE_SHIFT); |
| 181 | SET_MEMORY_RW | SET_MEMORY_NX); | ||
| 182 | free_initmem_default(POISON_FREE_INITMEM); | 181 | free_initmem_default(POISON_FREE_INITMEM); |
| 183 | } | 182 | } |
| 184 | 183 | ||
| @@ -1,301 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | #include <linux/kasan.h> | ||
| 3 | #include <linux/sched/task.h> | ||
| 4 | #include <linux/pgtable.h> | ||
| 5 | #include <asm/pgalloc.h> | ||
| 6 | #include <asm/kasan.h> | ||
| 7 | #include <asm/mem_detect.h> | ||
| 8 | #include <asm/processor.h> | ||
| 9 | #include <asm/sclp.h> | ||
| 10 | #include <asm/facility.h> | ||
| 11 | #include <asm/sections.h> | ||
| 12 | #include <asm/setup.h> | ||
| 13 | #include <asm/uv.h> | ||
| 14 | |||
| 15 | static unsigned long segment_pos __initdata; | ||
| 16 | static unsigned long segment_low __initdata; | ||
| 17 | static bool has_edat __initdata; | ||
| 18 | static bool has_nx __initdata; | ||
| 19 | |||
| 20 | #define __sha(x) ((unsigned long)kasan_mem_to_shadow((void *)x)) | ||
| 21 | |||
| 22 | static void __init kasan_early_panic(const char *reason) | ||
| 23 | { | ||
| 24 | sclp_early_printk("The Linux kernel failed to boot with the KernelAddressSanitizer:\n"); | ||
| 25 | sclp_early_printk(reason); | ||
| 26 | disabled_wait(); | ||
| 27 | } | ||
| 28 | |||
| 29 | static void * __init kasan_early_alloc_segment(void) | ||
| 30 | { | ||
| 31 | segment_pos -= _SEGMENT_SIZE; | ||
| 32 | |||
| 33 | if (segment_pos < segment_low) | ||
| 34 | kasan_early_panic("out of memory during initialisation\n"); | ||
| 35 | |||
| 36 | return __va(segment_pos); | ||
| 37 | } | ||
| 38 | |||
| 39 | static void * __init kasan_early_alloc_pages(unsigned int order) | ||
| 40 | { | ||
| 41 | pgalloc_pos -= (PAGE_SIZE << order); | ||
| 42 | |||
| 43 | if (pgalloc_pos < pgalloc_low) | ||
| 44 | kasan_early_panic("out of memory during initialisation\n"); | ||
| 45 | |||
| 46 | return __va(pgalloc_pos); | ||
| 47 | } | ||
| 48 | |||
| 49 | static void * __init kasan_early_crst_alloc(unsigned long val) | ||
| 50 | { | ||
| 51 | unsigned long *table; | ||
| 52 | |||
| 53 | table = kasan_early_alloc_pages(CRST_ALLOC_ORDER); | ||
| 54 | if (table) | ||
| 55 | crst_table_init(table, val); | ||
| 56 | return table; | ||
| 57 | } | ||
| 58 | |||
| 59 | static pte_t * __init kasan_early_pte_alloc(void) | ||
| 60 | { | ||
| 61 | static void *pte_leftover; | ||
| 62 | pte_t *pte; | ||
| 63 | |||
| 64 | BUILD_BUG_ON(_PAGE_TABLE_SIZE * 2 != PAGE_SIZE); | ||
| 65 | |||
| 66 | if (!pte_leftover) { | ||
| 67 | pte_leftover = kasan_early_alloc_pages(0); | ||
| 68 | pte = pte_leftover + _PAGE_TABLE_SIZE; | ||
| 69 | } else { | ||
| 70 | pte = pte_leftover; | ||
| 71 | pte_leftover = NULL; | ||
| 72 | } | ||
| 73 | memset64((u64 *)pte, _PAGE_INVALID, PTRS_PER_PTE); | ||
| 74 | return pte; | ||
| 75 | } | ||
| 76 | |||
| 77 | enum populate_mode { | ||
| 78 | POPULATE_MAP, | ||
| 79 | POPULATE_ZERO_SHADOW, | ||
| 80 | POPULATE_SHALLOW | ||
| 81 | }; | ||
| 82 | |||
| 83 | static inline pgprot_t pgprot_clear_bit(pgprot_t pgprot, unsigned long bit) | ||
| 84 | { | ||
| 85 | return __pgprot(pgprot_val(pgprot) & ~bit); | ||
| 86 | } | ||
| 87 | |||
| 88 | static void __init kasan_early_pgtable_populate(unsigned long address, | ||
| 89 | unsigned long end, | ||
| 90 | enum populate_mode mode) | ||
| 91 | { | ||
| 92 | pgprot_t pgt_prot_zero = PAGE_KERNEL_RO; | ||
| 93 | pgprot_t pgt_prot = PAGE_KERNEL; | ||
| 94 | pgprot_t sgt_prot = SEGMENT_KERNEL; | ||
| 95 | pgd_t *pg_dir; | ||
| 96 | p4d_t *p4_dir; | ||
| 97 | pud_t *pu_dir; | ||
| 98 | pmd_t *pm_dir; | ||
| 99 | pte_t *pt_dir; | ||
| 100 | pmd_t pmd; | ||
| 101 | pte_t pte; | ||
| 102 | |||
| 103 | if (!has_nx) { | ||
| 104 | pgt_prot_zero = pgprot_clear_bit(pgt_prot_zero, _PAGE_NOEXEC); | ||
| 105 | pgt_prot = pgprot_clear_bit(pgt_prot, _PAGE_NOEXEC); | ||
| 106 | sgt_prot = pgprot_clear_bit(sgt_prot, _SEGMENT_ENTRY_NOEXEC); | ||
| 107 | } | ||
| 108 | |||
| 109 | while (address < end) { | ||
| 110 | pg_dir = pgd_offset_k(address); | ||
| 111 | if (pgd_none(*pg_dir)) { | ||
| 112 | if (mode == POPULATE_ZERO_SHADOW && | ||
| 113 | IS_ALIGNED(address, PGDIR_SIZE) && | ||
| 114 | end - address >= PGDIR_SIZE) { | ||
| 115 | pgd_populate(&init_mm, pg_dir, | ||
| 116 | kasan_early_shadow_p4d); | ||
| 117 | address = (address + PGDIR_SIZE) & PGDIR_MASK; | ||
| 118 | continue; | ||
| 119 | } | ||
| 120 | p4_dir = kasan_early_crst_alloc(_REGION2_ENTRY_EMPTY); | ||
| 121 | pgd_populate(&init_mm, pg_dir, p4_dir); | ||
| 122 | } | ||
| 123 | |||
| 124 | if (mode == POPULATE_SHALLOW) { | ||
| 125 | address = (address + P4D_SIZE) & P4D_MASK; | ||
| 126 | continue; | ||
| 127 | } | ||
| 128 | |||
| 129 | p4_dir = p4d_offset(pg_dir, address); | ||
| 130 | if (p4d_none(*p4_dir)) { | ||
| 131 | if (mode == POPULATE_ZERO_SHADOW && | ||
| 132 | IS_ALIGNED(address, P4D_SIZE) && | ||
| 133 | end - address >= P4D_SIZE) { | ||
| 134 | p4d_populate(&init_mm, p4_dir, | ||
| 135 | kasan_early_shadow_pud); | ||
| 136 | address = (address + P4D_SIZE) & P4D_MASK; | ||
| 137 | continue; | ||
| 138 | } | ||
| 139 | pu_dir = kasan_early_crst_alloc(_REGION3_ENTRY_EMPTY); | ||
| 140 | p4d_populate(&init_mm, p4_dir, pu_dir); | ||
| 141 | } | ||
| 142 | |||
| 143 | pu_dir = pud_offset(p4_dir, address); | ||
| 144 | if (pud_none(*pu_dir)) { | ||
| 145 | if (mode == POPULATE_ZERO_SHADOW && | ||
| 146 | IS_ALIGNED(address, PUD_SIZE) && | ||
| 147 | end - address >= PUD_SIZE) { | ||
| 148 | pud_populate(&init_mm, pu_dir, | ||
| 149 | kasan_early_shadow_pmd); | ||
| 150 | address = (address + PUD_SIZE) & PUD_MASK; | ||
| 151 | continue; | ||
| 152 | } | ||
| 153 | pm_dir = kasan_early_crst_alloc(_SEGMENT_ENTRY_EMPTY); | ||
| 154 | pud_populate(&init_mm, pu_dir, pm_dir); | ||
| 155 | } | ||
| 156 | |||
| 157 | pm_dir = pmd_offset(pu_dir, address); | ||
| 158 | if (pmd_none(*pm_dir)) { | ||
| 159 | if (IS_ALIGNED(address, PMD_SIZE) && | ||
| 160 | end - address >= PMD_SIZE) { | ||
| 161 | if (mode == POPULATE_ZERO_SHADOW) { | ||
| 162 | pmd_populate(&init_mm, pm_dir, kasan_early_shadow_pte); | ||
| 163 | address = (address + PMD_SIZE) & PMD_MASK; | ||
| 164 | continue; | ||
| 165 | } else if (has_edat) { | ||
| 166 | void *page = kasan_early_alloc_segment(); | ||
| 167 | |||
| 168 | memset(page, 0, _SEGMENT_SIZE); | ||
| 169 | pmd = __pmd(__pa(page)); | ||
| 170 | pmd = set_pmd_bit(pmd, sgt_prot); | ||
| 171 | set_pmd(pm_dir, pmd); | ||
| 172 | address = (address + PMD_SIZE) & PMD_MASK; | ||
| 173 | continue; | ||
| 174 | } | ||
| 175 | } | ||
| 176 | pt_dir = kasan_early_pte_alloc(); | ||
| 177 | pmd_populate(&init_mm, pm_dir, pt_dir); | ||
| 178 | } else if (pmd_large(*pm_dir)) { | ||
| 179 | address = (address + PMD_SIZE) & PMD_MASK; | ||
| 180 | continue; | ||
| 181 | } | ||
| 182 | |||
| 183 | pt_dir = pte_offset_kernel(pm_dir, address); | ||
| 184 | if (pte_none(*pt_dir)) { | ||
| 185 | void *page; | ||
| 186 | |||
| 187 | switch (mode) { | ||
| 188 | case POPULATE_MAP: | ||
| 189 | page = kasan_early_alloc_pages(0); | ||
| 190 | memset(page, 0, PAGE_SIZE); | ||
| 191 | pte = __pte(__pa(page)); | ||
| 192 | pte = set_pte_bit(pte, pgt_prot); | ||
| 193 | set_pte(pt_dir, pte); | ||
| 194 | break; | ||
| 195 | case POPULATE_ZERO_SHADOW: | ||
| 196 | page = kasan_early_shadow_page; | ||
| 197 | pte = __pte(__pa(page)); | ||
| 198 | pte = set_pte_bit(pte, pgt_prot_zero); | ||
| 199 | set_pte(pt_dir, pte); | ||
| 200 | break; | ||
| 201 | case POPULATE_SHALLOW: | ||
| 202 | /* should never happen */ | ||
| 203 | break; | ||
| 204 | } | ||
| 205 | } | ||
| 206 | address += PAGE_SIZE; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | static void __init kasan_early_detect_facilities(void) | ||
| 211 | { | ||
| 212 | if (test_facility(8)) { | ||
| 213 | has_edat = true; | ||
| 214 | __ctl_set_bit(0, 23); | ||
| 215 | } | ||
| 216 | if (!noexec_disabled && test_facility(130)) { | ||
| 217 | has_nx = true; | ||
| 218 | __ctl_set_bit(0, 20); | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 | void __init kasan_early_init(void) | ||
| 223 | { | ||
| 224 | pte_t pte_z = __pte(__pa(kasan_early_shadow_page) | pgprot_val(PAGE_KERNEL_RO)); | ||
| 225 | pmd_t pmd_z = __pmd(__pa(kasan_early_shadow_pte) | _SEGMENT_ENTRY); | ||
| 226 | pud_t pud_z = __pud(__pa(kasan_early_shadow_pmd) | _REGION3_ENTRY); | ||
| 227 | p4d_t p4d_z = __p4d(__pa(kasan_early_shadow_pud) | _REGION2_ENTRY); | ||
| 228 | unsigned long untracked_end = MODULES_VADDR; | ||
| 229 | unsigned long shadow_alloc_size; | ||
| 230 | unsigned long start, end; | ||
| 231 | int i; | ||
| 232 | |||
| 233 | kasan_early_detect_facilities(); | ||
| 234 | if (!has_nx) | ||
| 235 | pte_z = clear_pte_bit(pte_z, __pgprot(_PAGE_NOEXEC)); | ||
| 236 | |||
| 237 | BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_START, P4D_SIZE)); | ||
| 238 | BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_END, P4D_SIZE)); | ||
| 239 | |||
| 240 | /* init kasan zero shadow */ | ||
| 241 | crst_table_init((unsigned long *)kasan_early_shadow_p4d, p4d_val(p4d_z)); | ||
| 242 | crst_table_init((unsigned long *)kasan_early_shadow_pud, pud_val(pud_z)); | ||
| 243 | crst_table_init((unsigned long *)kasan_early_shadow_pmd, pmd_val(pmd_z)); | ||
| 244 | memset64((u64 *)kasan_early_shadow_pte, pte_val(pte_z), PTRS_PER_PTE); | ||
| 245 | |||
| 246 | if (has_edat) { | ||
| 247 | shadow_alloc_size = get_mem_detect_usable_total() >> KASAN_SHADOW_SCALE_SHIFT; | ||
| 248 | segment_pos = round_down(pgalloc_pos, _SEGMENT_SIZE); | ||
| 249 | segment_low = segment_pos - shadow_alloc_size; | ||
| 250 | segment_low = round_down(segment_low, _SEGMENT_SIZE); | ||
| 251 | pgalloc_pos = segment_low; | ||
| 252 | } | ||
| 253 | /* | ||
| 254 | * Current memory layout: | ||
| 255 | * +- 0 -------------+ +- shadow start -+ | ||
| 256 | * |1:1 ident mapping| /|1/8 of ident map| | ||
| 257 | * | | / | | | ||
| 258 | * +-end of ident map+ / +----------------+ | ||
| 259 | * | ... gap ... | / | kasan | | ||
| 260 | * | | / | zero page | | ||
| 261 | * +- vmalloc area -+ / | mapping | | ||
| 262 | * | vmalloc_size | / | (untracked) | | ||
| 263 | * +- modules vaddr -+ / +----------------+ | ||
| 264 | * | 2Gb |/ | unmapped | allocated per module | ||
| 265 | * +- shadow start -+ +----------------+ | ||
| 266 | * | 1/8 addr space | | zero pg mapping| (untracked) | ||
| 267 | * +- shadow end ----+---------+- shadow end ---+ | ||
| 268 | * | ||
| 269 | * Current memory layout (KASAN_VMALLOC): | ||
| 270 | * +- 0 -------------+ +- shadow start -+ | ||
| 271 | * |1:1 ident mapping| /|1/8 of ident map| | ||
| 272 | * | | / | | | ||
| 273 | * +-end of ident map+ / +----------------+ | ||
| 274 | * | ... gap ... | / | kasan zero page| (untracked) | ||
| 275 | * | | / | mapping | | ||
| 276 | * +- vmalloc area -+ / +----------------+ | ||
| 277 | * | vmalloc_size | / |shallow populate| | ||
| 278 | * +- modules vaddr -+ / +----------------+ | ||
| 279 | * | 2Gb |/ |shallow populate| | ||
| 280 | * +- shadow start -+ +----------------+ | ||
| 281 | * | 1/8 addr space | | zero pg mapping| (untracked) | ||
| 282 | * +- shadow end ----+---------+- shadow end ---+ | ||
| 283 | */ | ||
| 284 | /* populate kasan shadow (for identity mapping and zero page mapping) */ | ||
| 285 | for_each_mem_detect_usable_block(i, &start, &end) | ||
| 286 | kasan_early_pgtable_populate(__sha(start), __sha(end), POPULATE_MAP); | ||
| 287 | if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) { | ||
| 288 | untracked_end = VMALLOC_START; | ||
| 289 | /* shallowly populate kasan shadow for vmalloc and modules */ | ||
| 290 | kasan_early_pgtable_populate(__sha(VMALLOC_START), __sha(MODULES_END), | ||
| 291 | POPULATE_SHALLOW); | ||
| 292 | } | ||
| 293 | /* populate kasan shadow for untracked memory */ | ||
| 294 | kasan_early_pgtable_populate(__sha(ident_map_size), __sha(untracked_end), | ||
| 295 | POPULATE_ZERO_SHADOW); | ||
| 296 | kasan_early_pgtable_populate(__sha(MODULES_END), __sha(_REGION1_SIZE), | ||
| 297 | POPULATE_ZERO_SHADOW); | ||
| 298 | /* enable kasan */ | ||
| 299 | init_task.kasan_depth = 0; | ||
| 300 | sclp_early_printk("KernelAddressSanitizer initialized\n"); | ||
| 301 | } | ||
| @@ -4,6 +4,7 @@ · 3 unmodified lines | |||
| 4 | * Author(s): Jan Glauber <jang@linux.vnet.ibm.com> | 4 | * Author(s): Jan Glauber <jang@linux.vnet.ibm.com> |
| 5 | */ | 5 | */ |
| 6 | #include <linux/hugetlb.h> | 6 | #include <linux/hugetlb.h> |
| 7 | #include <linux/vmalloc.h> | ||
| 7 | #include <linux/mm.h> | 8 | #include <linux/mm.h> |
| 8 | #include <asm/cacheflush.h> | 9 | #include <asm/cacheflush.h> |
| 9 | #include <asm/facility.h> | 10 | #include <asm/facility.h> |
| @@ -41,7 +42,7 @@ void __storage_key_init_range(unsigned long start, unsigned long end) · 31 unmodified lines | |||
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | #ifdef CONFIG_PROC_FS | 44 | #ifdef CONFIG_PROC_FS |
| 44 | atomic_long_t direct_pages_count[PG_DIRECT_MAP_MAX]; | 45 | atomic_long_t __bootdata_preserved(direct_pages_count[PG_DIRECT_MAP_MAX]); |
| 45 | 46 | ||
| 46 | void arch_report_meminfo(struct seq_file *m) | 47 | void arch_report_meminfo(struct seq_file *m) |
| 47 | { | 48 | { |
| @@ -101,6 +102,14 @@ static int walk_pte_level(pmd_t *pmdp, unsigned long addr, unsigned long end, · 53 unmodified lines | |||
| 101 | new = set_pte_bit(new, __pgprot(_PAGE_NOEXEC)); | 102 | new = set_pte_bit(new, __pgprot(_PAGE_NOEXEC)); |
| 102 | else if (flags & SET_MEMORY_X) | 103 | else if (flags & SET_MEMORY_X) |
| 103 | new = clear_pte_bit(new, __pgprot(_PAGE_NOEXEC)); | 104 | new = clear_pte_bit(new, __pgprot(_PAGE_NOEXEC)); |
| 105 | if (flags & SET_MEMORY_INV) { | ||
| 106 | new = set_pte_bit(new, __pgprot(_PAGE_INVALID)); | ||
| 107 | } else if (flags & SET_MEMORY_DEF) { | ||
| 108 | new = __pte(pte_val(new) & PAGE_MASK); | ||
| 109 | new = set_pte_bit(new, PAGE_KERNEL); | ||
| 110 | if (!MACHINE_HAS_NX) | ||
| 111 | new = clear_pte_bit(new, __pgprot(_PAGE_NOEXEC)); | ||
| 112 | } | ||
| 104 | pgt_set((unsigned long *)ptep, pte_val(new), addr, CRDTE_DTT_PAGE); | 113 | pgt_set((unsigned long *)ptep, pte_val(new), addr, CRDTE_DTT_PAGE); |
| 105 | ptep++; | 114 | ptep++; |
| 106 | addr += PAGE_SIZE; | 115 | addr += PAGE_SIZE; |
| @@ -151,6 +160,14 @@ static void modify_pmd_page(pmd_t *pmdp, unsigned long addr, · 44 unmodified lines | |||
| 151 | new = set_pmd_bit(new, __pgprot(_SEGMENT_ENTRY_NOEXEC)); | 160 | new = set_pmd_bit(new, __pgprot(_SEGMENT_ENTRY_NOEXEC)); |
| 152 | else if (flags & SET_MEMORY_X) | 161 | else if (flags & SET_MEMORY_X) |
| 153 | new = clear_pmd_bit(new, __pgprot(_SEGMENT_ENTRY_NOEXEC)); | 162 | new = clear_pmd_bit(new, __pgprot(_SEGMENT_ENTRY_NOEXEC)); |
| 163 | if (flags & SET_MEMORY_INV) { | ||
| 164 | new = set_pmd_bit(new, __pgprot(_SEGMENT_ENTRY_INVALID)); | ||
| 165 | } else if (flags & SET_MEMORY_DEF) { | ||
| 166 | new = __pmd(pmd_val(new) & PMD_MASK); | ||
| 167 | new = set_pmd_bit(new, SEGMENT_KERNEL); | ||
| 168 | if (!MACHINE_HAS_NX) | ||
| 169 | new = clear_pmd_bit(new, __pgprot(_SEGMENT_ENTRY_NOEXEC)); | ||
| 170 | } | ||
| 154 | pgt_set((unsigned long *)pmdp, pmd_val(new), addr, CRDTE_DTT_SEGMENT); | 171 | pgt_set((unsigned long *)pmdp, pmd_val(new), addr, CRDTE_DTT_SEGMENT); |
| 155 | } | 172 | } |
| 156 | 173 | ||
| @@ -232,6 +249,14 @@ static void modify_pud_page(pud_t *pudp, unsigned long addr, · 75 unmodified lines | |||
| 232 | new = set_pud_bit(new, __pgprot(_REGION_ENTRY_NOEXEC)); | 249 | new = set_pud_bit(new, __pgprot(_REGION_ENTRY_NOEXEC)); |
| 233 | else if (flags & SET_MEMORY_X) | 250 | else if (flags & SET_MEMORY_X) |
| 234 | new = clear_pud_bit(new, __pgprot(_REGION_ENTRY_NOEXEC)); | 251 | new = clear_pud_bit(new, __pgprot(_REGION_ENTRY_NOEXEC)); |
| 252 | if (flags & SET_MEMORY_INV) { | ||
| 253 | new = set_pud_bit(new, __pgprot(_REGION_ENTRY_INVALID)); | ||
| 254 | } else if (flags & SET_MEMORY_DEF) { | ||
| 255 | new = __pud(pud_val(new) & PUD_MASK); | ||
| 256 | new = set_pud_bit(new, REGION3_KERNEL); | ||
| 257 | if (!MACHINE_HAS_NX) | ||
| 258 | new = clear_pud_bit(new, __pgprot(_REGION_ENTRY_NOEXEC)); | ||
| 259 | } | ||
| 235 | pgt_set((unsigned long *)pudp, pud_val(new), addr, CRDTE_DTT_REGION3); | 260 | pgt_set((unsigned long *)pudp, pud_val(new), addr, CRDTE_DTT_REGION3); |
| 236 | } | 261 | } |
| 237 | 262 | ||
| @@ -298,11 +323,6 @@ static int change_page_attr(unsigned long addr, unsigned long end, · 60 unmodified lines | |||
| 298 | int rc = -EINVAL; | 323 | int rc = -EINVAL; |
| 299 | pgd_t *pgdp; | 324 | pgd_t *pgdp; |
| 300 | 325 | ||
| 301 | if (addr == end) | ||
| 302 | return 0; | ||
| 303 | if (end >= MODULES_END) | ||
| 304 | return -EINVAL; | ||
| 305 | mutex_lock(&cpa_mutex); | ||
| 306 | pgdp = pgd_offset_k(addr); | 326 | pgdp = pgd_offset_k(addr); |
| 307 | do { | 327 | do { |
| 308 | if (pgd_none(*pgdp)) | 328 | if (pgd_none(*pgdp)) |
| @@ -313,18 +333,76 @@ static int change_page_attr(unsigned long addr, unsigned long end, · 4 unmodified lines | |||
| 313 | break; | 333 | break; |
| 314 | cond_resched(); | 334 | cond_resched(); |
| 315 | } while (pgdp++, addr = next, addr < end && !rc); | 335 | } while (pgdp++, addr = next, addr < end && !rc); |
| 316 | mutex_unlock(&cpa_mutex); | 336 | return rc; |
| 337 | } | ||
| 338 | |||
| 339 | static int change_page_attr_alias(unsigned long addr, unsigned long end, | ||
| 340 | unsigned long flags) | ||
| 341 | { | ||
| 342 | unsigned long alias, offset, va_start, va_end; | ||
| 343 | struct vm_struct *area; | ||
| 344 | int rc = 0; | ||
| 345 | |||
| 346 | /* | ||
| 347 | * Changes to read-only permissions on kernel VA mappings are also | ||
| 348 | * applied to the kernel direct mapping. Execute permissions are | ||
| 349 | * intentionally not transferred to keep all allocated pages within | ||
| 350 | * the direct mapping non-executable. | ||
| 351 | */ | ||
| 352 | flags &= SET_MEMORY_RO | SET_MEMORY_RW; | ||
| 353 | if (!flags) | ||
| 354 | return 0; | ||
| 355 | area = NULL; | ||
| 356 | while (addr < end) { | ||
| 357 | if (!area) | ||
| 358 | area = find_vm_area((void *)addr); | ||
| 359 | if (!area || !(area->flags & VM_ALLOC)) | ||
| 360 | return 0; | ||
| 361 | va_start = (unsigned long)area->addr; | ||
| 362 | va_end = va_start + area->nr_pages * PAGE_SIZE; | ||
| 363 | offset = (addr - va_start) >> PAGE_SHIFT; | ||
| 364 | alias = (unsigned long)page_address(area->pages[offset]); | ||
| 365 | rc = change_page_attr(alias, alias + PAGE_SIZE, flags); | ||
| 366 | if (rc) | ||
| 367 | break; | ||
| 368 | addr += PAGE_SIZE; | ||
| 369 | if (addr >= va_end) | ||
| 370 | area = NULL; | ||
| 371 | } | ||
| 317 | return rc; | 372 | return rc; |
| 318 | } | 373 | } |
| 319 | 374 | ||
| 320 | int __set_memory(unsigned long addr, int numpages, unsigned long flags) | 375 | int __set_memory(unsigned long addr, int numpages, unsigned long flags) |
| 321 | { | 376 | { |
| 377 | unsigned long end; | ||
| 378 | int rc; | ||
| 379 | |||
| 322 | if (!MACHINE_HAS_NX) | 380 | if (!MACHINE_HAS_NX) |
| 323 | flags &= ~(SET_MEMORY_NX | SET_MEMORY_X); | 381 | flags &= ~(SET_MEMORY_NX | SET_MEMORY_X); |
| 324 | if (!flags) | 382 | if (!flags) |
| 325 | return 0; | 383 | return 0; |
| 384 | if (!numpages) | ||
| 385 | return 0; | ||
| 326 | addr &= PAGE_MASK; | 386 | addr &= PAGE_MASK; |
| 327 | return change_page_attr(addr, addr + numpages * PAGE_SIZE, flags); | 387 | end = addr + numpages * PAGE_SIZE; |
| 388 | mutex_lock(&cpa_mutex); | ||
| 389 | rc = change_page_attr(addr, end, flags); | ||
| 390 | if (rc) | ||
| 391 | goto out; | ||
| 392 | rc = change_page_attr_alias(addr, end, flags); | ||
| 393 | out: | ||
| 394 | mutex_unlock(&cpa_mutex); | ||
| 395 | return rc; | ||
| 396 | } | ||
| 397 | |||
| 398 | int set_direct_map_invalid_noflush(struct page *page) | ||
| 399 | { | ||
| 400 | return __set_memory((unsigned long)page_to_virt(page), 1, SET_MEMORY_INV); | ||
| 401 | } | ||
| 402 | |||
| 403 | int set_direct_map_default_noflush(struct page *page) | ||
| 404 | { | ||
| 405 | return __set_memory((unsigned long)page_to_virt(page), 1, SET_MEMORY_DEF); | ||
| 328 | } | 406 | } |
| 329 | 407 | ||
| 330 | #if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KFENCE) | 408 | #if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KFENCE) |
| @@ -33,19 +33,9 @@ static struct ctl_table page_table_sysctl[] = { · 32 unmodified lines | |||
| 33 | { } | 33 | { } |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | static struct ctl_table page_table_sysctl_dir[] = { | ||
| 37 | { | ||
| 38 | .procname = "vm", | ||
| 39 | .maxlen = 0, | ||
| 40 | .mode = 0555, | ||
| 41 | .child = page_table_sysctl, | ||
| 42 | }, | ||
| 43 | { } | ||
| 44 | }; | ||
| 45 | |||
| 46 | static int __init page_table_register_sysctl(void) | 36 | static int __init page_table_register_sysctl(void) |
| 47 | { | 37 | { |
| 48 | return register_sysctl_table(page_table_sysctl_dir) ? 0 : -ENOMEM; | 38 | return register_sysctl("vm", page_table_sysctl) ? 0 : -ENOMEM; |
| 49 | } | 39 | } |
| 50 | __initcall(page_table_register_sysctl); | 40 | __initcall(page_table_register_sysctl); |
| 51 | 41 | ||
| @@ -143,13 +133,7 @@ err_p4d: · 91 unmodified lines | |||
| 143 | 133 | ||
| 144 | static inline unsigned int atomic_xor_bits(atomic_t *v, unsigned int bits) | 134 | static inline unsigned int atomic_xor_bits(atomic_t *v, unsigned int bits) |
| 145 | { | 135 | { |
| 146 | unsigned int old, new; | 136 | return atomic_fetch_xor(bits, v) ^ bits; |
| 147 | |||
| 148 | do { | ||
| 149 | old = atomic_read(v); | ||
| 150 | new = old ^ bits; | ||
| 151 | } while (atomic_cmpxchg(v, old, new) != old); | ||
| 152 | return new; | ||
| 153 | } | 137 | } |
| 154 | 138 | ||
| 155 | #ifdef CONFIG_PGSTE | 139 | #ifdef CONFIG_PGSTE |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | |||
| 5 | 5 | ||
| 6 | #include <linux/memory_hotplug.h> | 6 | #include <linux/memory_hotplug.h> |
| 7 | #include <linux/memblock.h> | 7 | #include <linux/memblock.h> |
| 8 | #include <linux/kasan.h> | ||
| 8 | #include <linux/pfn.h> | 9 | #include <linux/pfn.h> |
| 9 | #include <linux/mm.h> | 10 | #include <linux/mm.h> |
| 10 | #include <linux/init.h> | 11 | #include <linux/init.h> |
| @@ -664,6 +665,9 @@ static void __init memblock_region_swap(void *a, void *b, int size) · 653 unmodified lines | |||
| 664 | swap(*(struct memblock_region *)a, *(struct memblock_region *)b); | 665 | swap(*(struct memblock_region *)a, *(struct memblock_region *)b); |
| 665 | } | 666 | } |
| 666 | 667 | ||
| 668 | #ifdef CONFIG_KASAN | ||
| 669 | #define __sha(x) ((unsigned long)kasan_mem_to_shadow((void *)x)) | ||
| 670 | #endif | ||
| 667 | /* | 671 | /* |
| 668 | * map whole physical memory to virtual memory (identity mapping) | 672 | * map whole physical memory to virtual memory (identity mapping) |
| 669 | * we reserve enough space in the vmalloc area for vmemmap to hotplug | 673 | * we reserve enough space in the vmalloc area for vmemmap to hotplug |
| @@ -728,23 +732,24 @@ void __init vmem_map_init(void) · 58 unmodified lines | |||
| 728 | memblock_region_cmp, memblock_region_swap); | 732 | memblock_region_cmp, memblock_region_swap); |
| 729 | __for_each_mem_range(i, &memblock.memory, &memory_rwx, | 733 | __for_each_mem_range(i, &memblock.memory, &memory_rwx, |
| 730 | NUMA_NO_NODE, MEMBLOCK_NONE, &base, &end, NULL) { | 734 | NUMA_NO_NODE, MEMBLOCK_NONE, &base, &end, NULL) { |
| 731 | __set_memory((unsigned long)__va(base), | 735 | set_memory_rwnx((unsigned long)__va(base), |
| 732 | (end - base) >> PAGE_SHIFT, | 736 | (end - base) >> PAGE_SHIFT); |
| 733 | SET_MEMORY_RW | SET_MEMORY_NX); | ||
| 734 | } | 737 | } |
| 735 | 738 | ||
| 736 | __set_memory((unsigned long)_stext, | 739 | #ifdef CONFIG_KASAN |
| 737 | (unsigned long)(_etext - _stext) >> PAGE_SHIFT, | 740 | for_each_mem_range(i, &base, &end) { |
| 738 | SET_MEMORY_RO | SET_MEMORY_X); | 741 | set_memory_rwnx(__sha(base), |
| 739 | __set_memory((unsigned long)_etext, | 742 | (__sha(end) - __sha(base)) >> PAGE_SHIFT); |
| 740 | (unsigned long)(__end_rodata - _etext) >> PAGE_SHIFT, | 743 | } |
| 741 | SET_MEMORY_RO); | 744 | #endif |
| 742 | __set_memory((unsigned long)_sinittext, | 745 | set_memory_rox((unsigned long)_stext, |
| 743 | (unsigned long)(_einittext - _sinittext) >> PAGE_SHIFT, | 746 | (unsigned long)(_etext - _stext) >> PAGE_SHIFT); |
| 744 | SET_MEMORY_RO | SET_MEMORY_X); | 747 | set_memory_ro((unsigned long)_etext, |
| 745 | __set_memory(__stext_amode31, | 748 | (unsigned long)(__end_rodata - _etext) >> PAGE_SHIFT); |
| 746 | (__etext_amode31 - __stext_amode31) >> PAGE_SHIFT, | 749 | set_memory_rox((unsigned long)_sinittext, |
| 747 | SET_MEMORY_RO | SET_MEMORY_X); | 750 | (unsigned long)(_einittext - _sinittext) >> PAGE_SHIFT); |
| 751 | set_memory_rox(__stext_amode31, | ||
| 752 | (__etext_amode31 - __stext_amode31) >> PAGE_SHIFT); | ||
| 748 | 753 | ||
| 749 | /* lowcore must be executable for LPSWE */ | 754 | /* lowcore must be executable for LPSWE */ |
| 750 | if (static_key_enabled(&cpu_has_bear)) | 755 | if (static_key_enabled(&cpu_has_bear)) |
| @@ -874,32 +874,15 @@ bool zpci_is_device_configured(struct zpci_dev *zdev) · 873 unmodified lines | |||
| 874 | * @fh: The general function handle supplied by the platform | 874 | * @fh: The general function handle supplied by the platform |
| 875 | * | 875 | * |
| 876 | * Given a device in the configuration state Configured, enables, scans and | 876 | * Given a device in the configuration state Configured, enables, scans and |
| 877 | * adds it to the common code PCI subsystem if possible. If the PCI device is | 877 | * adds it to the common code PCI subsystem if possible. If any failure occurs, |
| 878 | * parked because we can not yet create a PCI bus because we have not seen | 878 | * the zpci_dev is left disabled. |
| 879 | * function 0, it is ignored but will be scanned once function 0 appears. | ||
| 880 | * If any failure occurs, the zpci_dev is left disabled. | ||
| 881 | * | 879 | * |
| 882 | * Return: 0 on success, or an error code otherwise | 880 | * Return: 0 on success, or an error code otherwise |
| 883 | */ | 881 | */ |
| 884 | int zpci_scan_configured_device(struct zpci_dev *zdev, u32 fh) | 882 | int zpci_scan_configured_device(struct zpci_dev *zdev, u32 fh) |
| 885 | { | 883 | { |
| 886 | int rc; | ||
| 887 | |||
| 888 | zpci_update_fh(zdev, fh); | 884 | zpci_update_fh(zdev, fh); |
| 889 | /* the PCI function will be scanned once function 0 appears */ | 885 | return zpci_bus_scan_device(zdev); |
| 890 | if (!zdev->zbus->bus) | ||
| 891 | return 0; | ||
| 892 | |||
| 893 | /* For function 0 on a multi-function bus scan whole bus as we might | ||
| 894 | * have to pick up existing functions waiting for it to allow creating | ||
| 895 | * the PCI bus | ||
| 896 | */ | ||
| 897 | if (zdev->devfn == 0 && zdev->zbus->multifunction) | ||
| 898 | rc = zpci_bus_scan_bus(zdev->zbus); | ||
| 899 | else | ||
| 900 | rc = zpci_bus_scan_device(zdev); | ||
| 901 | |||
| 902 | return rc; | ||
| 903 | } | 886 | } |
| 904 | 887 | ||
| 905 | /** | 888 | /** |
| @@ -85,9 +85,8 @@ int zpci_bus_scan_device(struct zpci_dev *zdev) · 84 unmodified lines | |||
| 85 | if (!pdev) | 85 | if (!pdev) |
| 86 | return -ENODEV; | 86 | return -ENODEV; |
| 87 | 87 | ||
| 88 | pci_bus_add_device(pdev); | ||
| 89 | pci_lock_rescan_remove(); | 88 | pci_lock_rescan_remove(); |
| 90 | pci_bus_add_devices(zdev->zbus->bus); | 89 | pci_bus_add_device(pdev); |
| 91 | pci_unlock_rescan_remove(); | 90 | pci_unlock_rescan_remove(); |
| 92 | 91 | ||
| 93 | return 0; | 92 | return 0; |
| @@ -130,11 +129,8 @@ void zpci_bus_remove_device(struct zpci_dev *zdev, bool set_error) · 36 unmodified lines | |||
| 130 | * @zbus: the zbus to be scanned | 129 | * @zbus: the zbus to be scanned |
| 131 | * | 130 | * |
| 132 | * Enables and scans all PCI functions on the bus making them available to the | 131 | * Enables and scans all PCI functions on the bus making them available to the |
| 133 | * common PCI code. If there is no function 0 on the zbus nothing is scanned. If | 132 | * common PCI code. If a PCI function fails to be initialized an error will be |
| 134 | * a function does not have a slot yet because it was added to the zbus before | 133 | * returned but attempts will still be made for all other functions on the bus. |
| 135 | * function 0 the slot is created. If a PCI function fails to be initialized | ||
| 136 | * an error will be returned but attempts will still be made for all other | ||
| 137 | * functions on the bus. | ||
| 138 | * | 134 | * |
| 139 | * Return: 0 on success, an error value otherwise | 135 | * Return: 0 on success, an error value otherwise |
| 140 | */ | 136 | */ |
| @@ -211,7 +207,6 @@ static int zpci_bus_create_pci_bus(struct zpci_bus *zbus, struct zpci_dev *fr, s · 70 unmodified lines | |||
| 211 | } | 207 | } |
| 212 | 208 | ||
| 213 | zbus->bus = bus; | 209 | zbus->bus = bus; |
| 214 | pci_bus_add_devices(bus); | ||
| 215 | 210 | ||
| 216 | return 0; | 211 | return 0; |
| 217 | } | 212 | } |
| @@ -76,9 +76,9 @@ · 75 unmodified lines | |||
| 76 | diag %r0,%r1,0x308 | 76 | diag %r0,%r1,0x308 |
| 77 | .endm | 77 | .endm |
| 78 | 78 | ||
| 79 | .text | 79 | .text |
| 80 | .align PAGE_SIZE | 80 | .balign PAGE_SIZE |
| 81 | ENTRY(purgatory_start) | 81 | SYM_CODE_START(purgatory_start) |
| 82 | /* The purgatory might be called after a diag308 so better set | 82 | /* The purgatory might be called after a diag308 so better set |
| 83 | * architecture and addressing mode. | 83 | * architecture and addressing mode. |
| 84 | */ | 84 | */ |
| @@ -245,45 +245,21 @@ ENTRY(purgatory_start) · 160 unmodified lines | |||
| 245 | 245 | ||
| 246 | /* start crash kernel */ | 246 | /* start crash kernel */ |
| 247 | START_NEXT_KERNEL .base_dst 1 | 247 | START_NEXT_KERNEL .base_dst 1 |
| 248 | 248 | SYM_CODE_END(purgatory_start) | |
| 249 | 249 | ||
| 250 | load_psw_mask: | 250 | SYM_DATA_LOCAL(load_psw_mask, .long 0x00080000,0x80000000) |
| 251 | .long 0x00080000,0x80000000 | 251 | .balign 8 |
| 252 | 252 | SYM_DATA_LOCAL(disabled_wait_psw, .quad 0x0002000180000000,.do_checksum_verification) | |
| 253 | .align 8 | 253 | SYM_DATA_LOCAL(gprregs, .fill 10,8,0) |
| 254 | disabled_wait_psw: | 254 | SYM_DATA(purgatory_sha256_digest, .skip 32) |
| 255 | .quad 0x0002000180000000 | 255 | SYM_DATA(purgatory_sha_regions, .skip 16*__KEXEC_SHA_REGION_SIZE) |
| 256 | .quad 0x0000000000000000 + .do_checksum_verification | 256 | SYM_DATA(kernel_entry, .skip 8) |
| 257 | 257 | SYM_DATA(kernel_type, .skip 8) | |
| 258 | gprregs: | 258 | SYM_DATA(crash_start, .skip 8) |
| 259 | .rept 10 | 259 | SYM_DATA(crash_size, .skip 8) |
| 260 | .quad 0 | 260 | .balign PAGE_SIZE |
| 261 | .endr | 261 | SYM_DATA_START_LOCAL(stack) |
| 262 | |||
| 263 | /* Macro to define a global variable with name and size (in bytes) to be | ||
| 264 | * shared with C code. | ||
| 265 | * | ||
| 266 | * Add the .size and .type attribute to satisfy checks on the Elf_Sym during | ||
| 267 | * purgatory load. | ||
| 268 | */ | ||
| 269 | .macro GLOBAL_VARIABLE name,size | ||
| 270 | \name: | ||
| 271 | .global \name | ||
| 272 | .size \name,\size | ||
| 273 | .type \name,object | ||
| 274 | .skip \size,0 | ||
| 275 | .endm | ||
| 276 | |||
| 277 | GLOBAL_VARIABLE purgatory_sha256_digest,32 | ||
| 278 | GLOBAL_VARIABLE purgatory_sha_regions,16*__KEXEC_SHA_REGION_SIZE | ||
| 279 | GLOBAL_VARIABLE kernel_entry,8 | ||
| 280 | GLOBAL_VARIABLE kernel_type,8 | ||
| 281 | GLOBAL_VARIABLE crash_start,8 | ||
| 282 | GLOBAL_VARIABLE crash_size,8 | ||
| 283 | |||
| 284 | .align PAGE_SIZE | ||
| 285 | stack: | ||
| 286 | /* The buffer to move this code must be as big as the code. */ | 262 | /* The buffer to move this code must be as big as the code. */ |
| 287 | .skip stack-purgatory_start | 263 | .skip stack-purgatory_start |
| 288 | .align PAGE_SIZE | 264 | .balign PAGE_SIZE |
| 289 | purgatory_end: | 265 | SYM_DATA_END_LABEL(stack, SYM_L_LOCAL, purgatory_end) |
| @@ -1,14 +1,12 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | #include <linux/linkage.h> | ||
| 2 | 3 | ||
| 3 | .section .rodata, "a" | 4 | .section .rodata, "a" |
| 4 | 5 | ||
| 5 | .align 8 | 6 | .balign 8 |
| 6 | kexec_purgatory: | 7 | SYM_DATA_START(kexec_purgatory) |
| 7 | .globl kexec_purgatory | ||
| 8 | .incbin "arch/s390/purgatory/purgatory.ro" | 8 | .incbin "arch/s390/purgatory/purgatory.ro" |
| 9 | .Lkexec_purgatroy_end: | 9 | SYM_DATA_END_LABEL(kexec_purgatory, SYM_L_LOCAL, kexec_purgatory_end) |
| 10 | 10 | ||
| 11 | .align 8 | 11 | .balign 8 |
| 12 | kexec_purgatory_size: | 12 | SYM_DATA(kexec_purgatory_size, .quad kexec_purgatory_end-kexec_purgatory) |
| 13 | .globl kexec_purgatory_size | ||
| 14 | .quad .Lkexec_purgatroy_end - kexec_purgatory | ||
| @@ -204,7 +204,7 @@ struct read_storage_sccb { · 203 unmodified lines | |||
| 204 | u16 assigned; | 204 | u16 assigned; |
| 205 | u16 standby; | 205 | u16 standby; |
| 206 | u16 :16; | 206 | u16 :16; |
| 207 | u32 entries[0]; | 207 | u32 entries[]; |
| 208 | } __packed; | 208 | } __packed; |
| 209 | 209 | ||
| 210 | static inline void sclp_fill_core_info(struct sclp_core_info *info, | 210 | static inline void sclp_fill_core_info(struct sclp_core_info *info, |
| @@ -241,7 +241,7 @@ struct attach_storage_sccb { · 240 unmodified lines | |||
| 241 | u16 :16; | 241 | u16 :16; |
| 242 | u16 assigned; | 242 | u16 assigned; |
| 243 | u32 :32; | 243 | u32 :32; |
| 244 | u32 entries[0]; | 244 | u32 entries[]; |
| 245 | } __packed; | 245 | } __packed; |
| 246 | 246 | ||
| 247 | static int sclp_attach_storage(u8 id) | 247 | static int sclp_attach_storage(u8 id) |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | |||
| 10 | #include <asm/ebcdic.h> | 10 | #include <asm/ebcdic.h> |
| 11 | #include <asm/irq.h> | 11 | #include <asm/irq.h> |
| 12 | #include <asm/sections.h> | 12 | #include <asm/sections.h> |
| 13 | #include <asm/mem_detect.h> | 13 | #include <asm/physmem_info.h> |
| 14 | #include <asm/facility.h> | 14 | #include <asm/facility.h> |
| 15 | #include "sclp.h" | 15 | #include "sclp.h" |
| 16 | #include "sclp_rw.h" | 16 | #include "sclp_rw.h" |
| @@ -336,7 +336,7 @@ int __init sclp_early_get_hsa_size(unsigned long *hsa_size) · 319 unmodified lines | |||
| 336 | 336 | ||
| 337 | #define SCLP_STORAGE_INFO_FACILITY 0x0000400000000000UL | 337 | #define SCLP_STORAGE_INFO_FACILITY 0x0000400000000000UL |
| 338 | 338 | ||
| 339 | void __weak __init add_mem_detect_block(u64 start, u64 end) {} | 339 | void __weak __init add_physmem_online_range(u64 start, u64 end) {} |
| 340 | int __init sclp_early_read_storage_info(void) | 340 | int __init sclp_early_read_storage_info(void) |
| 341 | { | 341 | { |
| 342 | struct read_storage_sccb *sccb = (struct read_storage_sccb *)sclp_early_sccb; | 342 | struct read_storage_sccb *sccb = (struct read_storage_sccb *)sclp_early_sccb; |
| @@ -369,7 +369,7 @@ int __init sclp_early_read_storage_info(void) · 26 unmodified lines | |||
| 369 | if (!sccb->entries[sn]) | 369 | if (!sccb->entries[sn]) |
| 370 | continue; | 370 | continue; |
| 371 | rn = sccb->entries[sn] >> 16; | 371 | rn = sccb->entries[sn] >> 16; |
| 372 | add_mem_detect_block((rn - 1) * rzm, rn * rzm); | 372 | add_physmem_online_range((rn - 1) * rzm, rn * rzm); |
| 373 | } | 373 | } |
| 374 | break; | 374 | break; |
| 375 | case 0x0310: | 375 | case 0x0310: |
| @@ -382,6 +382,6 @@ int __init sclp_early_read_storage_info(void) · 6 unmodified lines | |||
| 382 | 382 | ||
| 383 | return 0; | 383 | return 0; |
| 384 | fail: | 384 | fail: |
| 385 | mem_detect.count = 0; | 385 | physmem_info.range_count = 0; |
| 386 | return -EIO; | 386 | return -EIO; |
| 387 | } | 387 | } |
| @@ -1171,7 +1171,7 @@ int __init chsc_get_cssid_iid(int idx, u8 *cssid, u8 *iid) · 1170 unmodified lines | |||
| 1171 | u8 cssid; | 1171 | u8 cssid; |
| 1172 | u8 iid; | 1172 | u8 iid; |
| 1173 | u32 : 16; | 1173 | u32 : 16; |
| 1174 | } list[0]; | 1174 | } list[]; |
| 1175 | } *sdcal_area; | 1175 | } *sdcal_area; |
| 1176 | int ret; | 1176 | int ret; |
| 1177 | 1177 | ||
| @@ -120,7 +120,7 @@ struct chsc_scpd { · 119 unmodified lines | |||
| 120 | u32 zeroes1; | 120 | u32 zeroes1; |
| 121 | struct chsc_header response; | 121 | struct chsc_header response; |
| 122 | u32:32; | 122 | u32:32; |
| 123 | u8 data[0]; | 123 | u8 data[]; |
| 124 | } __packed __aligned(PAGE_SIZE); | 124 | } __packed __aligned(PAGE_SIZE); |
| 125 | 125 | ||
| 126 | struct chsc_sda_area { | 126 | struct chsc_sda_area { |
| @@ -122,7 +122,13 @@ static struct hrtimer ap_poll_timer; · 121 unmodified lines | |||
| 122 | * In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. | 122 | * In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. |
| 123 | * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling. | 123 | * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling. |
| 124 | */ | 124 | */ |
| 125 | static unsigned long long poll_timeout = 250000; | 125 | static unsigned long poll_high_timeout = 250000UL; |
| 126 | |||
| 127 | /* | ||
| 128 | * Some state machine states only require a low frequency polling. | ||
| 129 | * We use 25 Hz frequency for these. | ||
| 130 | */ | ||
| 131 | static unsigned long poll_low_timeout = 40000000UL; | ||
| 126 | 132 | ||
| 127 | /* Maximum domain id, if not given via qci */ | 133 | /* Maximum domain id, if not given via qci */ |
| 128 | static int ap_max_domain_id = 15; | 134 | static int ap_max_domain_id = 15; |
| @@ -200,6 +206,18 @@ static inline int ap_qact_available(void) · 71 unmodified lines | |||
| 200 | return 0; | 206 | return 0; |
| 201 | } | 207 | } |
| 202 | 208 | ||
| 209 | /* | ||
| 210 | * ap_sb_available(): Test if the AP secure binding facility is available. | ||
| 211 | * | ||
| 212 | * Returns 1 if secure binding facility is available. | ||
| 213 | */ | ||
| 214 | int ap_sb_available(void) | ||
| 215 | { | ||
| 216 | if (ap_qci_info) | ||
| 217 | return ap_qci_info->apsb; | ||
| 218 | return 0; | ||
| 219 | } | ||
| 220 | |||
| 203 | /* | 221 | /* |
| 204 | * ap_fetch_qci_info(): Fetch cryptographic config info | 222 | * ap_fetch_qci_info(): Fetch cryptographic config info |
| 205 | * | 223 | * |
| @@ -248,13 +266,13 @@ static void __init ap_init_qci_info(void) · 42 unmodified lines | |||
| 248 | AP_DBF_INFO("%s successful fetched initial qci info\n", __func__); | 266 | AP_DBF_INFO("%s successful fetched initial qci info\n", __func__); |
| 249 | 267 | ||
| 250 | if (ap_qci_info->apxa) { | 268 | if (ap_qci_info->apxa) { |
| 251 | if (ap_qci_info->Na) { | 269 | if (ap_qci_info->na) { |
| 252 | ap_max_adapter_id = ap_qci_info->Na; | 270 | ap_max_adapter_id = ap_qci_info->na; |
| 253 | AP_DBF_INFO("%s new ap_max_adapter_id is %d\n", | 271 | AP_DBF_INFO("%s new ap_max_adapter_id is %d\n", |
| 254 | __func__, ap_max_adapter_id); | 272 | __func__, ap_max_adapter_id); |
| 255 | } | 273 | } |
| 256 | if (ap_qci_info->Nd) { | 274 | if (ap_qci_info->nd) { |
| 257 | ap_max_domain_id = ap_qci_info->Nd; | 275 | ap_max_domain_id = ap_qci_info->nd; |
| 258 | AP_DBF_INFO("%s new ap_max_domain_id is %d\n", | 276 | AP_DBF_INFO("%s new ap_max_domain_id is %d\n", |
| 259 | __func__, ap_max_domain_id); | 277 | __func__, ap_max_domain_id); |
| 260 | } | 278 | } |
| @@ -324,35 +342,32 @@ EXPORT_SYMBOL(ap_test_config_ctrl_domain); · 63 unmodified lines | |||
| 324 | 342 | ||
| 325 | /* | 343 | /* |
| 326 | * ap_queue_info(): Check and get AP queue info. | 344 | * ap_queue_info(): Check and get AP queue info. |
| 327 | * Returns true if TAPQ succeeded and the info is filled or | 345 | * Returns: 1 if APQN exists and info is filled, |
| 328 | * false otherwise. | 346 | * 0 if APQN seems to exit but there is no info |
| 347 | * available (eg. caused by an asynch pending error) | ||
| 348 | * -1 invalid APQN, TAPQ error or AP queue status which | ||
| 349 | * indicates there is no APQN. | ||
| 329 | */ | 350 | */ |
| 330 | static bool ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac, | 351 | static int ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac, |
| 331 | int *q_depth, int *q_ml, bool *q_decfg, bool *q_cstop) | 352 | int *q_depth, int *q_ml, bool *q_decfg, bool *q_cstop) |
| 332 | { | 353 | { |
| 333 | struct ap_queue_status status; | 354 | struct ap_queue_status status; |
| 334 | union { | 355 | struct ap_tapq_gr2 tapq_info; |
| 335 | unsigned long value; | ||
| 336 | struct { | ||
| 337 | unsigned int fac : 32; /* facility bits */ | ||
| 338 | unsigned int at : 8; /* ap type */ | ||
| 339 | unsigned int _res1 : 8; | ||
| 340 | unsigned int _res2 : 4; | ||
| 341 | unsigned int ml : 4; /* apxl ml */ | ||
| 342 | unsigned int _res3 : 4; | ||
| 343 | unsigned int qd : 4; /* queue depth */ | ||
| 344 | } tapq_gr2; | ||
| 345 | } tapq_info; | ||
| 346 | 356 | ||
| 347 | tapq_info.value = 0; | 357 | tapq_info.value = 0; |
| 348 | 358 | ||
| 349 | /* make sure we don't run into a specifiation exception */ | 359 | /* make sure we don't run into a specifiation exception */ |
| 350 | if (AP_QID_CARD(qid) > ap_max_adapter_id || | 360 | if (AP_QID_CARD(qid) > ap_max_adapter_id || |
| 351 | AP_QID_QUEUE(qid) > ap_max_domain_id) | 361 | AP_QID_QUEUE(qid) > ap_max_domain_id) |
| 352 | return false; | 362 | return -1; |
| 353 | 363 | ||
| 354 | /* call TAPQ on this APQN */ | 364 | /* call TAPQ on this APQN */ |
| 355 | status = ap_test_queue(qid, ap_apft_available(), &tapq_info.value); | 365 | status = ap_test_queue(qid, ap_apft_available(), &tapq_info); |
| 366 | |||
| 367 | /* handle pending async error with return 'no info available' */ | ||
| 368 | if (status.async) | ||
| 369 | return 0; | ||
| 370 | |||
| 356 | switch (status.response_code) { | 371 | switch (status.response_code) { |
| 357 | case AP_RESPONSE_NORMAL: | 372 | case AP_RESPONSE_NORMAL: |
| 358 | case AP_RESPONSE_RESET_IN_PROGRESS: | 373 | case AP_RESPONSE_RESET_IN_PROGRESS: |
| @@ -365,11 +380,11 @@ static bool ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac, · 6 unmodified lines | |||
| 365 | * there is at least one of the mode bits set. | 380 | * there is at least one of the mode bits set. |
| 366 | */ | 381 | */ |
| 367 | if (WARN_ON_ONCE(!tapq_info.value)) | 382 | if (WARN_ON_ONCE(!tapq_info.value)) |
| 368 | return false; | 383 | return 0; |
| 369 | *q_type = tapq_info.tapq_gr2.at; | 384 | *q_type = tapq_info.at; |
| 370 | *q_fac = tapq_info.tapq_gr2.fac; | 385 | *q_fac = tapq_info.fac; |
| 371 | *q_depth = tapq_info.tapq_gr2.qd; | 386 | *q_depth = tapq_info.qd; |
| 372 | *q_ml = tapq_info.tapq_gr2.ml; | 387 | *q_ml = tapq_info.ml; |
| 373 | *q_decfg = status.response_code == AP_RESPONSE_DECONFIGURED; | 388 | *q_decfg = status.response_code == AP_RESPONSE_DECONFIGURED; |
| 374 | *q_cstop = status.response_code == AP_RESPONSE_CHECKSTOPPED; | 389 | *q_cstop = status.response_code == AP_RESPONSE_CHECKSTOPPED; |
| 375 | switch (*q_type) { | 390 | switch (*q_type) { |
| @@ -389,12 +404,12 @@ static bool ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac, · 13 unmodified lines | |||
| 389 | default: | 404 | default: |
| 390 | break; | 405 | break; |
| 391 | } | 406 | } |
| 392 | return true; | 407 | return 1; |
| 393 | default: | 408 | default: |
| 394 | /* | 409 | /* |
| 395 | * A response code which indicates, there is no info available. | 410 | * A response code which indicates, there is no info available. |
| 396 | */ | 411 | */ |
| 397 | return false; | 412 | return -1; |
| 398 | } | 413 | } |
| 399 | } | 414 | } |
| 400 | 415 | ||
| @@ -412,10 +427,13 @@ void ap_wait(enum ap_sm_wait wait) · 11 unmodified lines | |||
| 412 | break; | 427 | break; |
| 413 | } | 428 | } |
| 414 | fallthrough; | 429 | fallthrough; |
| 415 | case AP_SM_WAIT_TIMEOUT: | 430 | case AP_SM_WAIT_LOW_TIMEOUT: |
| 431 | case AP_SM_WAIT_HIGH_TIMEOUT: | ||
| 416 | spin_lock_bh(&ap_poll_timer_lock); | 432 | spin_lock_bh(&ap_poll_timer_lock); |
| 417 | if (!hrtimer_is_queued(&ap_poll_timer)) { | 433 | if (!hrtimer_is_queued(&ap_poll_timer)) { |
| 418 | hr_time = poll_timeout; | 434 | hr_time = |
| 435 | wait == AP_SM_WAIT_LOW_TIMEOUT ? | ||
| 436 | poll_low_timeout : poll_high_timeout; | ||
| 419 | hrtimer_forward_now(&ap_poll_timer, hr_time); | 437 | hrtimer_forward_now(&ap_poll_timer, hr_time); |
| 420 | hrtimer_restart(&ap_poll_timer); | 438 | hrtimer_restart(&ap_poll_timer); |
| 421 | } | 439 | } |
| @@ -1168,7 +1186,7 @@ EXPORT_SYMBOL(ap_parse_mask_str); · 746 unmodified lines | |||
| 1168 | 1186 | ||
| 1169 | static ssize_t ap_domain_show(const struct bus_type *bus, char *buf) | 1187 | static ssize_t ap_domain_show(const struct bus_type *bus, char *buf) |
| 1170 | { | 1188 | { |
| 1171 | return scnprintf(buf, PAGE_SIZE, "%d\n", ap_domain_index); | 1189 | return sysfs_emit(buf, "%d\n", ap_domain_index); |
| 1172 | } | 1190 | } |
| 1173 | 1191 | ||
| 1174 | static ssize_t ap_domain_store(const struct bus_type *bus, | 1192 | static ssize_t ap_domain_store(const struct bus_type *bus, |
| @@ -1196,14 +1214,13 @@ static BUS_ATTR_RW(ap_domain); · 21 unmodified lines | |||
| 1196 | static ssize_t ap_control_domain_mask_show(const struct bus_type *bus, char *buf) | 1214 | static ssize_t ap_control_domain_mask_show(const struct bus_type *bus, char *buf) |
| 1197 | { | 1215 | { |
| 1198 | if (!ap_qci_info) /* QCI not supported */ | 1216 | if (!ap_qci_info) /* QCI not supported */ |
| 1199 | return scnprintf(buf, PAGE_SIZE, "not supported\n"); | 1217 | return sysfs_emit(buf, "not supported\n"); |
| 1200 | 1218 | ||
| 1201 | return scnprintf(buf, PAGE_SIZE, | 1219 | return sysfs_emit(buf, "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", |
| 1202 | "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", | 1220 | ap_qci_info->adm[0], ap_qci_info->adm[1], |
| 1203 | ap_qci_info->adm[0], ap_qci_info->adm[1], | 1221 | ap_qci_info->adm[2], ap_qci_info->adm[3], |
| 1204 | ap_qci_info->adm[2], ap_qci_info->adm[3], | 1222 | ap_qci_info->adm[4], ap_qci_info->adm[5], |
| 1205 | ap_qci_info->adm[4], ap_qci_info->adm[5], | 1223 | ap_qci_info->adm[6], ap_qci_info->adm[7]); |
| 1206 | ap_qci_info->adm[6], ap_qci_info->adm[7]); | ||
| 1207 | } | 1224 | } |
| 1208 | 1225 | ||
| 1209 | static BUS_ATTR_RO(ap_control_domain_mask); | 1226 | static BUS_ATTR_RO(ap_control_domain_mask); |
| @@ -1211,14 +1228,13 @@ static BUS_ATTR_RO(ap_control_domain_mask); · 1 unmodified line | |||
| 1211 | static ssize_t ap_usage_domain_mask_show(const struct bus_type *bus, char *buf) | 1228 | static ssize_t ap_usage_domain_mask_show(const struct bus_type *bus, char *buf) |
| 1212 | { | 1229 | { |
| 1213 | if (!ap_qci_info) /* QCI not supported */ | 1230 | if (!ap_qci_info) /* QCI not supported */ |
| 1214 | return scnprintf(buf, PAGE_SIZE, "not supported\n"); | 1231 | return sysfs_emit(buf, "not supported\n"); |
| 1215 | 1232 | ||
| 1216 | return scnprintf(buf, PAGE_SIZE, | 1233 | return sysfs_emit(buf, "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", |
| 1217 | "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", | 1234 | ap_qci_info->aqm[0], ap_qci_info->aqm[1], |
| 1218 | ap_qci_info->aqm[0], ap_qci_info->aqm[1], | 1235 | ap_qci_info->aqm[2], ap_qci_info->aqm[3], |
| 1219 | ap_qci_info->aqm[2], ap_qci_info->aqm[3], | 1236 | ap_qci_info->aqm[4], ap_qci_info->aqm[5], |
| 1220 | ap_qci_info->aqm[4], ap_qci_info->aqm[5], | 1237 | ap_qci_info->aqm[6], ap_qci_info->aqm[7]); |
| 1221 | ap_qci_info->aqm[6], ap_qci_info->aqm[7]); | ||
| 1222 | } | 1238 | } |
| 1223 | 1239 | ||
| 1224 | static BUS_ATTR_RO(ap_usage_domain_mask); | 1240 | static BUS_ATTR_RO(ap_usage_domain_mask); |
| @@ -1226,29 +1242,27 @@ static BUS_ATTR_RO(ap_usage_domain_mask); · 1 unmodified line | |||
| 1226 | static ssize_t ap_adapter_mask_show(const struct bus_type *bus, char *buf) | 1242 | static ssize_t ap_adapter_mask_show(const struct bus_type *bus, char *buf) |
| 1227 | { | 1243 | { |
| 1228 | if (!ap_qci_info) /* QCI not supported */ | 1244 | if (!ap_qci_info) /* QCI not supported */ |
| 1229 | return scnprintf(buf, PAGE_SIZE, "not supported\n"); | 1245 | return sysfs_emit(buf, "not supported\n"); |
| 1230 | 1246 | ||
| 1231 | return scnprintf(buf, PAGE_SIZE, | 1247 | return sysfs_emit(buf, "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", |
| 1232 | "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", | 1248 | ap_qci_info->apm[0], ap_qci_info->apm[1], |
| 1233 | ap_qci_info->apm[0], ap_qci_info->apm[1], | 1249 | ap_qci_info->apm[2], ap_qci_info->apm[3], |
| 1234 | ap_qci_info->apm[2], ap_qci_info->apm[3], | 1250 | ap_qci_info->apm[4], ap_qci_info->apm[5], |
| 1235 | ap_qci_info->apm[4], ap_qci_info->apm[5], | 1251 | ap_qci_info->apm[6], ap_qci_info->apm[7]); |
| 1236 | ap_qci_info->apm[6], ap_qci_info->apm[7]); | ||
| 1237 | } | 1252 | } |
| 1238 | 1253 | ||
| 1239 | static BUS_ATTR_RO(ap_adapter_mask); | 1254 | static BUS_ATTR_RO(ap_adapter_mask); |
| 1240 | 1255 | ||
| 1241 | static ssize_t ap_interrupts_show(const struct bus_type *bus, char *buf) | 1256 | static ssize_t ap_interrupts_show(const struct bus_type *bus, char *buf) |
| 1242 | { | 1257 | { |
| 1243 | return scnprintf(buf, PAGE_SIZE, "%d\n", | 1258 | return sysfs_emit(buf, "%d\n", ap_irq_flag ? 1 : 0); |
| 1244 | ap_irq_flag ? 1 : 0); | ||
| 1245 | } | 1259 | } |
| 1246 | 1260 | ||
| 1247 | static BUS_ATTR_RO(ap_interrupts); | 1261 | static BUS_ATTR_RO(ap_interrupts); |
| 1248 | 1262 | ||
| 1249 | static ssize_t config_time_show(const struct bus_type *bus, char *buf) | 1263 | static ssize_t config_time_show(const struct bus_type *bus, char *buf) |
| 1250 | { | 1264 | { |
| 1251 | return scnprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); | 1265 | return sysfs_emit(buf, "%d\n", ap_config_time); |
| 1252 | } | 1266 | } |
| 1253 | 1267 | ||
| 1254 | static ssize_t config_time_store(const struct bus_type *bus, | 1268 | static ssize_t config_time_store(const struct bus_type *bus, |
| @@ -1267,17 +1281,20 @@ static BUS_ATTR_RW(config_time); · 12 unmodified lines | |||
| 1267 | 1281 | ||
| 1268 | static ssize_t poll_thread_show(const struct bus_type *bus, char *buf) | 1282 | static ssize_t poll_thread_show(const struct bus_type *bus, char *buf) |
| 1269 | { | 1283 | { |
| 1270 | return scnprintf(buf, PAGE_SIZE, "%d\n", ap_poll_kthread ? 1 : 0); | 1284 | return sysfs_emit(buf, "%d\n", ap_poll_kthread ? 1 : 0); |
| 1271 | } | 1285 | } |
| 1272 | 1286 | ||
| 1273 | static ssize_t poll_thread_store(const struct bus_type *bus, | 1287 | static ssize_t poll_thread_store(const struct bus_type *bus, |
| 1274 | const char *buf, size_t count) | 1288 | const char *buf, size_t count) |
| 1275 | { | 1289 | { |
| 1276 | int flag, rc; | 1290 | bool value; |
| 1291 | int rc; | ||
| 1277 | 1292 | ||
| 1278 | if (sscanf(buf, "%d\n", &flag) != 1) | 1293 | rc = kstrtobool(buf, &value); |
| 1279 | return -EINVAL; | 1294 | if (rc) |
| 1280 | if (flag) { | 1295 | return rc; |
| 1296 | |||
| 1297 | if (value) { | ||
| 1281 | rc = ap_poll_thread_start(); | 1298 | rc = ap_poll_thread_start(); |
| 1282 | if (rc) | 1299 | if (rc) |
| 1283 | count = rc; | 1300 | count = rc; |
| @@ -1291,21 +1308,25 @@ static BUS_ATTR_RW(poll_thread); · 7 unmodified lines | |||
| 1291 | 1308 | ||
| 1292 | static ssize_t poll_timeout_show(const struct bus_type *bus, char *buf) | 1309 | static ssize_t poll_timeout_show(const struct bus_type *bus, char *buf) |
| 1293 | { | 1310 | { |
| 1294 | return scnprintf(buf, PAGE_SIZE, "%llu\n", poll_timeout); | 1311 | return sysfs_emit(buf, "%lu\n", poll_high_timeout); |
| 1295 | } | 1312 | } |
| 1296 | 1313 | ||
| 1297 | static ssize_t poll_timeout_store(const struct bus_type *bus, const char *buf, | 1314 | static ssize_t poll_timeout_store(const struct bus_type *bus, const char *buf, |
| 1298 | size_t count) | 1315 | size_t count) |
| 1299 | { | 1316 | { |
| 1300 | unsigned long long time; | 1317 | unsigned long value; |
| 1301 | ktime_t hr_time; | 1318 | ktime_t hr_time; |
| 1319 | int rc; | ||
| 1320 | |||
| 1321 | rc = kstrtoul(buf, 0, &value); | ||
| 1322 | if (rc) | ||
| 1323 | return rc; | ||
| 1302 | 1324 | ||
| 1303 | /* 120 seconds = maximum poll interval */ | 1325 | /* 120 seconds = maximum poll interval */ |
| 1304 | if (sscanf(buf, "%llu\n", &time) != 1 || time < 1 || | 1326 | if (value > 120000000000UL) |
| 1305 | time > 120000000000ULL) | ||
| 1306 | return -EINVAL; | 1327 | return -EINVAL; |
| 1307 | poll_timeout = time; | 1328 | poll_high_timeout = value; |
| 1308 | hr_time = poll_timeout; | 1329 | hr_time = poll_high_timeout; |
| 1309 | 1330 | ||
| 1310 | spin_lock_bh(&ap_poll_timer_lock); | 1331 | spin_lock_bh(&ap_poll_timer_lock); |
| 1311 | hrtimer_cancel(&ap_poll_timer); | 1332 | hrtimer_cancel(&ap_poll_timer); |
| @@ -1320,14 +1341,14 @@ static BUS_ATTR_RW(poll_timeout); · 8 unmodified lines | |||
| 1320 | 1341 | ||
| 1321 | static ssize_t ap_max_domain_id_show(const struct bus_type *bus, char *buf) | 1342 | static ssize_t ap_max_domain_id_show(const struct bus_type *bus, char *buf) |
| 1322 | { | 1343 | { |
| 1323 | return scnprintf(buf, PAGE_SIZE, "%d\n", ap_max_domain_id); | 1344 | return sysfs_emit(buf, "%d\n", ap_max_domain_id); |
| 1324 | } | 1345 | } |
| 1325 | 1346 | ||
| 1326 | static BUS_ATTR_RO(ap_max_domain_id); | 1347 | static BUS_ATTR_RO(ap_max_domain_id); |
| 1327 | 1348 | ||
| 1328 | static ssize_t ap_max_adapter_id_show(const struct bus_type *bus, char *buf) | 1349 | static ssize_t ap_max_adapter_id_show(const struct bus_type *bus, char *buf) |
| 1329 | { | 1350 | { |
| 1330 | return scnprintf(buf, PAGE_SIZE, "%d\n", ap_max_adapter_id); | 1351 | return sysfs_emit(buf, "%d\n", ap_max_adapter_id); |
| 1331 | } | 1352 | } |
| 1332 | 1353 | ||
| 1333 | static BUS_ATTR_RO(ap_max_adapter_id); | 1354 | static BUS_ATTR_RO(ap_max_adapter_id); |
| @@ -1338,10 +1359,9 @@ static ssize_t apmask_show(const struct bus_type *bus, char *buf) · 4 unmodified lines | |||
| 1338 | 1359 | ||
| 1339 | if (mutex_lock_interruptible(&ap_perms_mutex)) | 1360 | if (mutex_lock_interruptible(&ap_perms_mutex)) |
| 1340 | return -ERESTARTSYS; | 1361 | return -ERESTARTSYS; |
| 1341 | rc = scnprintf(buf, PAGE_SIZE, | 1362 | rc = sysfs_emit(buf, "0x%016lx%016lx%016lx%016lx\n", |
| 1342 | "0x%016lx%016lx%016lx%016lx\n", | 1363 | ap_perms.apm[0], ap_perms.apm[1], |
| 1343 | ap_perms.apm[0], ap_perms.apm[1], | 1364 | ap_perms.apm[2], ap_perms.apm[3]); |
| 1344 | ap_perms.apm[2], ap_perms.apm[3]); | ||
| 1345 | mutex_unlock(&ap_perms_mutex); | 1365 | mutex_unlock(&ap_perms_mutex); |
| 1346 | 1366 | ||
| 1347 | return rc; | 1367 | return rc; |
| @@ -1431,10 +1451,9 @@ static ssize_t aqmask_show(const struct bus_type *bus, char *buf) · 83 unmodified lines | |||
| 1431 | 1451 | ||
| 1432 | if (mutex_lock_interruptible(&ap_perms_mutex)) | 1452 | if (mutex_lock_interruptible(&ap_perms_mutex)) |
| 1433 | return -ERESTARTSYS; | 1453 | return -ERESTARTSYS; |
| 1434 | rc = scnprintf(buf, PAGE_SIZE, | 1454 | rc = sysfs_emit(buf, "0x%016lx%016lx%016lx%016lx\n", |
| 1435 | "0x%016lx%016lx%016lx%016lx\n", | 1455 | ap_perms.aqm[0], ap_perms.aqm[1], |
| 1436 | ap_perms.aqm[0], ap_perms.aqm[1], | 1456 | ap_perms.aqm[2], ap_perms.aqm[3]); |
| 1437 | ap_perms.aqm[2], ap_perms.aqm[3]); | ||
| 1438 | mutex_unlock(&ap_perms_mutex); | 1457 | mutex_unlock(&ap_perms_mutex); |
| 1439 | 1458 | ||
| 1440 | return rc; | 1459 | return rc; |
| @@ -1520,8 +1539,7 @@ static BUS_ATTR_RW(aqmask); · 79 unmodified lines | |||
| 1520 | 1539 | ||
| 1521 | static ssize_t scans_show(const struct bus_type *bus, char *buf) | 1540 | static ssize_t scans_show(const struct bus_type *bus, char *buf) |
| 1522 | { | 1541 | { |
| 1523 | return scnprintf(buf, PAGE_SIZE, "%llu\n", | 1542 | return sysfs_emit(buf, "%llu\n", atomic64_read(&ap_scan_bus_count)); |
| 1524 | atomic64_read(&ap_scan_bus_count)); | ||
| 1525 | } | 1543 | } |
| 1526 | 1544 | ||
| 1527 | static ssize_t scans_store(const struct bus_type *bus, const char *buf, | 1545 | static ssize_t scans_store(const struct bus_type *bus, const char *buf, |
| @@ -1543,15 +1561,40 @@ static ssize_t bindings_show(const struct bus_type *bus, char *buf) · 15 unmodified lines | |||
| 1543 | 1561 | ||
| 1544 | ap_calc_bound_apqns(&apqns, &n); | 1562 | ap_calc_bound_apqns(&apqns, &n); |
| 1545 | if (atomic64_read(&ap_scan_bus_count) >= 1 && n == apqns) | 1563 | if (atomic64_read(&ap_scan_bus_count) >= 1 && n == apqns) |
| 1546 | rc = scnprintf(buf, PAGE_SIZE, "%u/%u (complete)\n", n, apqns); | 1564 | rc = sysfs_emit(buf, "%u/%u (complete)\n", n, apqns); |
| 1547 | else | 1565 | else |
| 1548 | rc = scnprintf(buf, PAGE_SIZE, "%u/%u\n", n, apqns); | 1566 | rc = sysfs_emit(buf, "%u/%u\n", n, apqns); |
| 1549 | 1567 | ||
| 1550 | return rc; | 1568 | return rc; |
| 1551 | } | 1569 | } |
| 1552 | 1570 | ||
| 1553 | static BUS_ATTR_RO(bindings); | 1571 | static BUS_ATTR_RO(bindings); |
| 1554 | 1572 | ||
| 1573 | static ssize_t features_show(const struct bus_type *bus, char *buf) | ||
| 1574 | { | ||
| 1575 | int n = 0; | ||
| 1576 | |||
| 1577 | if (!ap_qci_info) /* QCI not supported */ | ||
| 1578 | return sysfs_emit(buf, "-\n"); | ||
| 1579 | |||
| 1580 | if (ap_qci_info->apsc) | ||
| 1581 | n += sysfs_emit_at(buf, n, "APSC "); | ||
| 1582 | if (ap_qci_info->apxa) | ||
| 1583 | n += sysfs_emit_at(buf, n, "APXA "); | ||
| 1584 | if (ap_qci_info->qact) | ||
| 1585 | n += sysfs_emit_at(buf, n, "QACT "); | ||
| 1586 | if (ap_qci_info->rc8a) | ||
| 1587 | n += sysfs_emit_at(buf, n, "RC8A "); | ||
| 1588 | if (ap_qci_info->apsb) | ||
| 1589 | n += sysfs_emit_at(buf, n, "APSB "); | ||
| 1590 | |||
| 1591 | sysfs_emit_at(buf, n == 0 ? 0 : n - 1, "\n"); | ||
| 1592 | |||
| 1593 | return n; | ||
| 1594 | } | ||
| 1595 | |||
| 1596 | static BUS_ATTR_RO(features); | ||
| 1597 | |||
| 1555 | static struct attribute *ap_bus_attrs[] = { | 1598 | static struct attribute *ap_bus_attrs[] = { |
| 1556 | &bus_attr_ap_domain.attr, | 1599 | &bus_attr_ap_domain.attr, |
| 1557 | &bus_attr_ap_control_domain_mask.attr, | 1600 | &bus_attr_ap_control_domain_mask.attr, |
| @@ -1567,6 +1610,7 @@ static struct attribute *ap_bus_attrs[] = { · 9 unmodified lines | |||
| 1567 | &bus_attr_aqmask.attr, | 1610 | &bus_attr_aqmask.attr, |
| 1568 | &bus_attr_scans.attr, | 1611 | &bus_attr_scans.attr, |
| 1569 | &bus_attr_bindings.attr, | 1612 | &bus_attr_bindings.attr, |
| 1613 | &bus_attr_features.attr, | ||
| 1570 | NULL, | 1614 | NULL, |
| 1571 | }; | 1615 | }; |
| 1572 | ATTRIBUTE_GROUPS(ap_bus); | 1616 | ATTRIBUTE_GROUPS(ap_bus); |
| @@ -1762,12 +1806,12 @@ static inline void ap_scan_rm_card_dev_and_queue_devs(struct ap_card *ac) · 189 unmodified lines | |||
| 1762 | */ | 1806 | */ |
| 1763 | static inline void ap_scan_domains(struct ap_card *ac) | 1807 | static inline void ap_scan_domains(struct ap_card *ac) |
| 1764 | { | 1808 | { |
| 1809 | int rc, dom, depth, type, ml; | ||
| 1765 | bool decfg, chkstop; | 1810 | bool decfg, chkstop; |
| 1766 | ap_qid_t qid; | ||
| 1767 | unsigned int func; | ||
| 1768 | struct device *dev; | ||
| 1769 | struct ap_queue *aq; | 1811 | struct ap_queue *aq; |
| 1770 | int rc, dom, depth, type, ml; | 1812 | struct device *dev; |
| 1813 | unsigned int func; | ||
| 1814 | ap_qid_t qid; | ||
| 1771 | 1815 | ||
| 1772 | /* | 1816 | /* |
| 1773 | * Go through the configuration for the domains and compare them | 1817 | * Go through the configuration for the domains and compare them |
| @@ -1786,20 +1830,24 @@ static inline void ap_scan_domains(struct ap_card *ac) · 12 unmodified lines | |||
| 1786 | AP_DBF_INFO("%s(%d,%d) not in config anymore, rm queue dev\n", | 1830 | AP_DBF_INFO("%s(%d,%d) not in config anymore, rm queue dev\n", |
| 1787 | __func__, ac->id, dom); | 1831 | __func__, ac->id, dom); |
| 1788 | device_unregister(dev); | 1832 | device_unregister(dev); |
| 1789 | put_device(dev); | ||
| 1790 | } | 1833 | } |
| 1791 | continue; | 1834 | goto put_dev_and_continue; |
| 1792 | } | 1835 | } |
| 1793 | /* domain is valid, get info from this APQN */ | 1836 | /* domain is valid, get info from this APQN */ |
| 1794 | if (!ap_queue_info(qid, &type, &func, &depth, | 1837 | rc = ap_queue_info(qid, &type, &func, &depth, |
| 1795 | &ml, &decfg, &chkstop)) { | 1838 | &ml, &decfg, &chkstop); |
| 1796 | if (aq) { | 1839 | switch (rc) { |
| 1840 | case -1: | ||
| 1841 | if (dev) { | ||
| 1797 | AP_DBF_INFO("%s(%d,%d) queue_info() failed, rm queue dev\n", | 1842 | AP_DBF_INFO("%s(%d,%d) queue_info() failed, rm queue dev\n", |
| 1798 | __func__, ac->id, dom); | 1843 | __func__, ac->id, dom); |
| 1799 | device_unregister(dev); | 1844 | device_unregister(dev); |
| 1800 | put_device(dev); | ||
| 1801 | } | 1845 | } |
| 1802 | continue; | 1846 | fallthrough; |
| 1847 | case 0: | ||
| 1848 | goto put_dev_and_continue; | ||
| 1849 | default: | ||
| 1850 | break; | ||
| 1803 | } | 1851 | } |
| 1804 | /* if no queue device exists, create a new one */ | 1852 | /* if no queue device exists, create a new one */ |
| 1805 | if (!aq) { | 1853 | if (!aq) { |
| @@ -1915,12 +1963,12 @@ put_dev_and_continue: · 109 unmodified lines | |||
| 1915 | */ | 1963 | */ |
| 1916 | static inline void ap_scan_adapter(int ap) | 1964 | static inline void ap_scan_adapter(int ap) |
| 1917 | { | 1965 | { |
| 1966 | int rc, dom, depth, type, comp_type, ml; | ||
| 1918 | bool decfg, chkstop; | 1967 | bool decfg, chkstop; |
| 1919 | ap_qid_t qid; | ||
| 1920 | unsigned int func; | ||
| 1921 | struct device *dev; | ||
| 1922 | struct ap_card *ac; | 1968 | struct ap_card *ac; |
| 1923 | int rc, dom, depth, type, comp_type, ml; | 1969 | struct device *dev; |
| 1970 | unsigned int func; | ||
| 1971 | ap_qid_t qid; | ||
| 1924 | 1972 | ||
| 1925 | /* Is there currently a card device for this adapter ? */ | 1973 | /* Is there currently a card device for this adapter ? */ |
| 1926 | dev = bus_find_device(&ap_bus_type, NULL, | 1974 | dev = bus_find_device(&ap_bus_type, NULL, |
| @@ -1950,11 +1998,11 @@ static inline void ap_scan_adapter(int ap) · 23 unmodified lines | |||
| 1950 | if (ap_test_config_usage_domain(dom)) { | 1998 | if (ap_test_config_usage_domain(dom)) { |
| 1951 | qid = AP_MKQID(ap, dom); | 1999 | qid = AP_MKQID(ap, dom); |
| 1952 | if (ap_queue_info(qid, &type, &func, &depth, | 2000 | if (ap_queue_info(qid, &type, &func, &depth, |
| 1953 | &ml, &decfg, &chkstop)) | 2001 | &ml, &decfg, &chkstop) > 0) |
| 1954 | break; | 2002 | break; |
| 1955 | } | 2003 | } |
| 1956 | if (dom > ap_max_domain_id) { | 2004 | if (dom > ap_max_domain_id) { |
| 1957 | /* Could not find a valid APQN for this adapter */ | 2005 | /* Could not find one valid APQN for this adapter */ |
| 1958 | if (ac) { | 2006 | if (ac) { |
| 1959 | AP_DBF_INFO("%s(%d) no type info (no APQN found), rm card and queue devs\n", | 2007 | AP_DBF_INFO("%s(%d) no type info (no APQN found), rm card and queue devs\n", |
| 1960 | __func__, ap); | 2008 | __func__, ap); |
| @@ -1979,7 +2027,6 @@ static inline void ap_scan_adapter(int ap) · 18 unmodified lines | |||
| 1979 | } | 2027 | } |
| 1980 | return; | 2028 | return; |
| 1981 | } | 2029 | } |
| 1982 | |||
| 1983 | if (ac) { | 2030 | if (ac) { |
| 1984 | /* Check APQN against existing card device for changes */ | 2031 | /* Check APQN against existing card device for changes */ |
| 1985 | if (ac->raw_hwtype != type) { | 2032 | if (ac->raw_hwtype != type) { |
| @@ -1988,9 +2035,10 @@ static inline void ap_scan_adapter(int ap) · 2 unmodified lines | |||
| 1988 | ap_scan_rm_card_dev_and_queue_devs(ac); | 2035 | ap_scan_rm_card_dev_and_queue_devs(ac); |
| 1989 | put_device(dev); | 2036 | put_device(dev); |
| 1990 | ac = NULL; | 2037 | ac = NULL; |
| 1991 | } else if (ac->functions != func) { | 2038 | } else if ((ac->functions & TAPQ_CARD_FUNC_CMP_MASK) != |
| 2039 | (func & TAPQ_CARD_FUNC_CMP_MASK)) { | ||
| 1992 | AP_DBF_INFO("%s(%d) functions 0x%08x changed, rm card and queue devs\n", | 2040 | AP_DBF_INFO("%s(%d) functions 0x%08x changed, rm card and queue devs\n", |
| 1993 | __func__, ap, type); | 2041 | __func__, ap, func); |
| 1994 | ap_scan_rm_card_dev_and_queue_devs(ac); | 2042 | ap_scan_rm_card_dev_and_queue_devs(ac); |
| 1995 | put_device(dev); | 2043 | put_device(dev); |
| 1996 | ac = NULL; | 2044 | ac = NULL; |
| @@ -2245,7 +2293,7 @@ static int __init ap_module_init(void) · 248 unmodified lines | |||
| 2245 | * If we are running under z/VM adjust polling to z/VM polling rate. | 2293 | * If we are running under z/VM adjust polling to z/VM polling rate. |
| 2246 | */ | 2294 | */ |
| 2247 | if (MACHINE_IS_VM) | 2295 | if (MACHINE_IS_VM) |
| 2248 | poll_timeout = 1500000; | 2296 | poll_high_timeout = 1500000; |
| 2249 | hrtimer_init(&ap_poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | 2297 | hrtimer_init(&ap_poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); |
| 2250 | ap_poll_timer.function = ap_poll_timeout; | 2298 | ap_poll_timer.function = ap_poll_timeout; |
| 2251 | 2299 | ||
| @@ -39,22 +39,32 @@ static inline int ap_test_bit(unsigned int *ptr, unsigned int nr) · 38 unmodified lines | |||
| 39 | return (*ptr & (0x80000000u >> nr)) != 0; | 39 | return (*ptr & (0x80000000u >> nr)) != 0; |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | #define AP_RESPONSE_NORMAL 0x00 | 42 | #define AP_RESPONSE_NORMAL 0x00 |
| 43 | #define AP_RESPONSE_Q_NOT_AVAIL 0x01 | 43 | #define AP_RESPONSE_Q_NOT_AVAIL 0x01 |
| 44 | #define AP_RESPONSE_RESET_IN_PROGRESS 0x02 | 44 | #define AP_RESPONSE_RESET_IN_PROGRESS 0x02 |
| 45 | #define AP_RESPONSE_DECONFIGURED 0x03 | 45 | #define AP_RESPONSE_DECONFIGURED 0x03 |
| 46 | #define AP_RESPONSE_CHECKSTOPPED 0x04 | 46 | #define AP_RESPONSE_CHECKSTOPPED 0x04 |
| 47 | #define AP_RESPONSE_BUSY 0x05 | 47 | #define AP_RESPONSE_BUSY 0x05 |
| 48 | #define AP_RESPONSE_INVALID_ADDRESS 0x06 | 48 | #define AP_RESPONSE_INVALID_ADDRESS 0x06 |
| 49 | #define AP_RESPONSE_OTHERWISE_CHANGED 0x07 | 49 | #define AP_RESPONSE_OTHERWISE_CHANGED 0x07 |
| 50 | #define AP_RESPONSE_INVALID_GISA 0x08 | 50 | #define AP_RESPONSE_INVALID_GISA 0x08 |
| 51 | #define AP_RESPONSE_Q_FULL 0x10 | 51 | #define AP_RESPONSE_Q_BOUND_TO_ANOTHER 0x09 |
| 52 | #define AP_RESPONSE_NO_PENDING_REPLY 0x10 | 52 | #define AP_RESPONSE_STATE_CHANGE_IN_PROGRESS 0x0A |
| 53 | #define AP_RESPONSE_INDEX_TOO_BIG 0x11 | 53 | #define AP_RESPONSE_Q_NOT_BOUND 0x0B |
| 54 | #define AP_RESPONSE_NO_FIRST_PART 0x13 | 54 | #define AP_RESPONSE_Q_FULL 0x10 |
| 55 | #define AP_RESPONSE_MESSAGE_TOO_BIG 0x15 | 55 | #define AP_RESPONSE_NO_PENDING_REPLY 0x10 |
| 56 | #define AP_RESPONSE_REQ_FAC_NOT_INST 0x16 | 56 | #define AP_RESPONSE_INDEX_TOO_BIG 0x11 |
| 57 | #define AP_RESPONSE_INVALID_DOMAIN 0x42 | 57 | #define AP_RESPONSE_NO_FIRST_PART 0x13 |
| 58 | #define AP_RESPONSE_MESSAGE_TOO_BIG 0x15 | ||
| 59 | #define AP_RESPONSE_REQ_FAC_NOT_INST 0x16 | ||
| 60 | #define AP_RESPONSE_Q_BIND_ERROR 0x30 | ||
| 61 | #define AP_RESPONSE_Q_NOT_AVAIL_FOR_ASSOC 0x31 | ||
| 62 | #define AP_RESPONSE_Q_NOT_EMPTY 0x32 | ||
| 63 | #define AP_RESPONSE_BIND_LIMIT_EXCEEDED 0x33 | ||
| 64 | #define AP_RESPONSE_INVALID_ASSOC_SECRET 0x34 | ||
| 65 | #define AP_RESPONSE_ASSOC_SECRET_NOT_UNIQUE 0x35 | ||
| 66 | #define AP_RESPONSE_ASSOC_FAILED 0x36 | ||
| 67 | #define AP_RESPONSE_INVALID_DOMAIN 0x42 | ||
| 58 | 68 | ||
| 59 | /* | 69 | /* |
| 60 | * Known device types | 70 | * Known device types |
| @@ -92,6 +102,7 @@ enum ap_sm_state { · 31 unmodified lines | |||
| 92 | AP_SM_STATE_IDLE, | 102 | AP_SM_STATE_IDLE, |
| 93 | AP_SM_STATE_WORKING, | 103 | AP_SM_STATE_WORKING, |
| 94 | AP_SM_STATE_QUEUE_FULL, | 104 | AP_SM_STATE_QUEUE_FULL, |
| 105 | AP_SM_STATE_ASSOC_WAIT, | ||
| 95 | NR_AP_SM_STATES | 106 | NR_AP_SM_STATES |
| 96 | }; | 107 | }; |
| 97 | 108 | ||
| @@ -108,10 +119,11 @@ enum ap_sm_event { · 10 unmodified lines | |||
| 108 | * AP queue state wait behaviour | 119 | * AP queue state wait behaviour |
| 109 | */ | 120 | */ |
| 110 | enum ap_sm_wait { | 121 | enum ap_sm_wait { |
| 111 | AP_SM_WAIT_AGAIN = 0, /* retry immediately */ | 122 | AP_SM_WAIT_AGAIN = 0, /* retry immediately */ |
| 112 | AP_SM_WAIT_TIMEOUT, /* wait for timeout */ | 123 | AP_SM_WAIT_HIGH_TIMEOUT, /* poll high freq, wait for timeout */ |
| 113 | AP_SM_WAIT_INTERRUPT, /* wait for thin interrupt (if available) */ | 124 | AP_SM_WAIT_LOW_TIMEOUT, /* poll low freq, wait for timeout */ |
| 114 | AP_SM_WAIT_NONE, /* no wait */ | 125 | AP_SM_WAIT_INTERRUPT, /* wait for thin interrupt (if available) */ |
| 126 | AP_SM_WAIT_NONE, /* no wait */ | ||
| 115 | NR_AP_SM_WAIT | 127 | NR_AP_SM_WAIT |
| 116 | }; | 128 | }; |
| 117 | 129 | ||
| @@ -178,7 +190,7 @@ struct ap_device { · 60 unmodified lines | |||
| 178 | struct ap_card { | 190 | struct ap_card { |
| 179 | struct ap_device ap_dev; | 191 | struct ap_device ap_dev; |
| 180 | int raw_hwtype; /* AP raw hardware type. */ | 192 | int raw_hwtype; /* AP raw hardware type. */ |
| 181 | unsigned int functions; /* AP device function bitfield. */ | 193 | unsigned int functions; /* TAPQ GR2 upper 32 facility bits */ |
| 182 | int queue_depth; /* AP queue depth.*/ | 194 | int queue_depth; /* AP queue depth.*/ |
| 183 | int id; /* AP card number. */ | 195 | int id; /* AP card number. */ |
| 184 | unsigned int maxmsgsize; /* AP msg limit for this card */ | 196 | unsigned int maxmsgsize; /* AP msg limit for this card */ |
| @@ -187,6 +199,9 @@ struct ap_card { · 2 unmodified lines | |||
| 187 | atomic64_t total_request_count; /* # requests ever for this AP device.*/ | 199 | atomic64_t total_request_count; /* # requests ever for this AP device.*/ |
| 188 | }; | 200 | }; |
| 189 | 201 | ||
| 202 | #define TAPQ_CARD_FUNC_CMP_MASK 0xFFFF0000 | ||
| 203 | #define ASSOC_IDX_INVALID 0x10000 | ||
| 204 | |||
| 190 | #define to_ap_card(x) container_of((x), struct ap_card, ap_dev.device) | 205 | #define to_ap_card(x) container_of((x), struct ap_card, ap_dev.device) |
| 191 | 206 | ||
| 192 | struct ap_queue { | 207 | struct ap_queue { |
| @@ -199,6 +214,7 @@ struct ap_queue { · 6 unmodified lines | |||
| 199 | bool chkstop; /* checkstop state */ | 214 | bool chkstop; /* checkstop state */ |
| 200 | ap_qid_t qid; /* AP queue id. */ | 215 | ap_qid_t qid; /* AP queue id. */ |
| 201 | bool interrupt; /* indicate if interrupts are enabled */ | 216 | bool interrupt; /* indicate if interrupts are enabled */ |
| 217 | unsigned int assoc_idx; /* SE association index */ | ||
| 202 | int queue_count; /* # messages currently on AP queue. */ | 218 | int queue_count; /* # messages currently on AP queue. */ |
| 203 | int pendingq_count; /* # requests on pendingq list. */ | 219 | int pendingq_count; /* # requests on pendingq list. */ |
| 204 | int requestq_count; /* # requests on requestq list. */ | 220 | int requestq_count; /* # requests on requestq list. */ |
| @@ -209,6 +225,7 @@ struct ap_queue { · 4 unmodified lines | |||
| 209 | struct list_head requestq; /* List of message yet to be sent. */ | 225 | struct list_head requestq; /* List of message yet to be sent. */ |
| 210 | struct ap_message *reply; /* Per device reply message. */ | 226 | struct ap_message *reply; /* Per device reply message. */ |
| 211 | enum ap_sm_state sm_state; /* ap queue state machine state */ | 227 | enum ap_sm_state sm_state; /* ap queue state machine state */ |
| 228 | int rapq_fbit; /* fbit arg for next rapq invocation */ | ||
| 212 | int last_err_rc; /* last error state response code */ | 229 | int last_err_rc; /* last error state response code */ |
| 213 | }; | 230 | }; |
| 214 | 231 | ||
| @@ -242,10 +259,10 @@ enum ap_fi_flags { · 27 unmodified lines | |||
| 242 | 259 | ||
| 243 | struct ap_message { | 260 | struct ap_message { |
| 244 | struct list_head list; /* Request queueing. */ | 261 | struct list_head list; /* Request queueing. */ |
| 245 | unsigned long long psmid; /* Message id. */ | 262 | unsigned long psmid; /* Message id. */ |
| 246 | void *msg; /* Pointer to message buffer. */ | 263 | void *msg; /* Pointer to message buffer. */ |
| 247 | unsigned int len; /* actual msg len in msg buffer */ | 264 | size_t len; /* actual msg len in msg buffer */ |
| 248 | unsigned int bufsize; /* allocated msg buffer size */ | 265 | size_t bufsize; /* allocated msg buffer size */ |
| 249 | u16 flags; /* Flags, see AP_MSG_FLAG_xxx */ | 266 | u16 flags; /* Flags, see AP_MSG_FLAG_xxx */ |
| 250 | struct ap_fi fi; /* Failure Injection cmd */ | 267 | struct ap_fi fi; /* Failure Injection cmd */ |
| 251 | int rc; /* Return code for this message */ | 268 | int rc; /* Return code for this message */ |
| @@ -285,8 +302,8 @@ static inline void ap_release_message(struct ap_message *ap_msg) · 33 unmodified lines | |||
| 285 | * for the first time. Otherwise the ap message queue will get | 302 | * for the first time. Otherwise the ap message queue will get |
| 286 | * confused. | 303 | * confused. |
| 287 | */ | 304 | */ |
| 288 | int ap_send(ap_qid_t, unsigned long long, void *, size_t); | 305 | int ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t msglen); |
| 289 | int ap_recv(ap_qid_t, unsigned long long *, void *, size_t); | 306 | int ap_recv(ap_qid_t qid, unsigned long *psmid, void *msg, size_t msglen); |
| 290 | 307 | ||
| 291 | enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event); | 308 | enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event); |
| 292 | enum ap_sm_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_sm_event event); | 309 | enum ap_sm_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_sm_event event); |
| @@ -296,6 +313,7 @@ void ap_cancel_message(struct ap_queue *aq, struct ap_message *ap_msg); · 3 unmodified lines | |||
| 296 | void ap_flush_queue(struct ap_queue *aq); | 313 | void ap_flush_queue(struct ap_queue *aq); |
| 297 | 314 | ||
| 298 | void *ap_airq_ptr(void); | 315 | void *ap_airq_ptr(void); |
| 316 | int ap_sb_available(void); | ||
| 299 | void ap_wait(enum ap_sm_wait wait); | 317 | void ap_wait(enum ap_sm_wait wait); |
| 300 | void ap_request_timeout(struct timer_list *t); | 318 | void ap_request_timeout(struct timer_list *t); |
| 301 | void ap_bus_force_rescan(void); | 319 | void ap_bus_force_rescan(void); |
| @@ -24,7 +24,7 @@ static ssize_t hwtype_show(struct device *dev, · 23 unmodified lines | |||
| 24 | { | 24 | { |
| 25 | struct ap_card *ac = to_ap_card(dev); | 25 | struct ap_card *ac = to_ap_card(dev); |
| 26 | 26 | ||
| 27 | return scnprintf(buf, PAGE_SIZE, "%d\n", ac->ap_dev.device_type); | 27 | return sysfs_emit(buf, "%d\n", ac->ap_dev.device_type); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | static DEVICE_ATTR_RO(hwtype); | 30 | static DEVICE_ATTR_RO(hwtype); |
| @@ -34,7 +34,7 @@ static ssize_t raw_hwtype_show(struct device *dev, · 3 unmodified lines | |||
| 34 | { | 34 | { |
| 35 | struct ap_card *ac = to_ap_card(dev); | 35 | struct ap_card *ac = to_ap_card(dev); |
| 36 | 36 | ||
| 37 | return scnprintf(buf, PAGE_SIZE, "%d\n", ac->raw_hwtype); | 37 | return sysfs_emit(buf, "%d\n", ac->raw_hwtype); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | static DEVICE_ATTR_RO(raw_hwtype); | 40 | static DEVICE_ATTR_RO(raw_hwtype); |
| @@ -44,7 +44,7 @@ static ssize_t depth_show(struct device *dev, struct device_attribute *attr, · 3 unmodified lines | |||
| 44 | { | 44 | { |
| 45 | struct ap_card *ac = to_ap_card(dev); | 45 | struct ap_card *ac = to_ap_card(dev); |
| 46 | 46 | ||
| 47 | return scnprintf(buf, PAGE_SIZE, "%d\n", ac->queue_depth); | 47 | return sysfs_emit(buf, "%d\n", ac->queue_depth); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | static DEVICE_ATTR_RO(depth); | 50 | static DEVICE_ATTR_RO(depth); |
| @@ -54,7 +54,7 @@ static ssize_t ap_functions_show(struct device *dev, · 3 unmodified lines | |||
| 54 | { | 54 | { |
| 55 | struct ap_card *ac = to_ap_card(dev); | 55 | struct ap_card *ac = to_ap_card(dev); |
| 56 | 56 | ||
| 57 | return scnprintf(buf, PAGE_SIZE, "0x%08X\n", ac->functions); | 57 | return sysfs_emit(buf, "0x%08X\n", ac->functions); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | static DEVICE_ATTR_RO(ap_functions); | 60 | static DEVICE_ATTR_RO(ap_functions); |
| @@ -70,7 +70,7 @@ static ssize_t request_count_show(struct device *dev, · 9 unmodified lines | |||
| 70 | spin_lock_bh(&ap_queues_lock); | 70 | spin_lock_bh(&ap_queues_lock); |
| 71 | req_cnt = atomic64_read(&ac->total_request_count); | 71 | req_cnt = atomic64_read(&ac->total_request_count); |
| 72 | spin_unlock_bh(&ap_queues_lock); | 72 | spin_unlock_bh(&ap_queues_lock); |
| 73 | return scnprintf(buf, PAGE_SIZE, "%llu\n", req_cnt); | 73 | return sysfs_emit(buf, "%llu\n", req_cnt); |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | static ssize_t request_count_store(struct device *dev, | 76 | static ssize_t request_count_store(struct device *dev, |
| @@ -107,7 +107,7 @@ static ssize_t requestq_count_show(struct device *dev, · 30 unmodified lines | |||
| 107 | if (ac == aq->card) | 107 | if (ac == aq->card) |
| 108 | reqq_cnt += aq->requestq_count; | 108 | reqq_cnt += aq->requestq_count; |
| 109 | spin_unlock_bh(&ap_queues_lock); | 109 | spin_unlock_bh(&ap_queues_lock); |
| 110 | return scnprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); | 110 | return sysfs_emit(buf, "%d\n", reqq_cnt); |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | static DEVICE_ATTR_RO(requestq_count); | 113 | static DEVICE_ATTR_RO(requestq_count); |
| @@ -126,7 +126,7 @@ static ssize_t pendingq_count_show(struct device *dev, · 12 unmodified lines | |||
| 126 | if (ac == aq->card) | 126 | if (ac == aq->card) |
| 127 | penq_cnt += aq->pendingq_count; | 127 | penq_cnt += aq->pendingq_count; |
| 128 | spin_unlock_bh(&ap_queues_lock); | 128 | spin_unlock_bh(&ap_queues_lock); |
| 129 | return scnprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); | 129 | return sysfs_emit(buf, "%d\n", penq_cnt); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | static DEVICE_ATTR_RO(pendingq_count); | 132 | static DEVICE_ATTR_RO(pendingq_count); |
| @@ -134,8 +134,7 @@ static DEVICE_ATTR_RO(pendingq_count); · 1 unmodified line | |||
| 134 | static ssize_t modalias_show(struct device *dev, | 134 | static ssize_t modalias_show(struct device *dev, |
| 135 | struct device_attribute *attr, char *buf) | 135 | struct device_attribute *attr, char *buf) |
| 136 | { | 136 | { |
| 137 | return scnprintf(buf, PAGE_SIZE, "ap:t%02X\n", | 137 | return sysfs_emit(buf, "ap:t%02X\n", to_ap_dev(dev)->device_type); |
| 138 | to_ap_dev(dev)->device_type); | ||
| 139 | } | 138 | } |
| 140 | 139 | ||
| 141 | static DEVICE_ATTR_RO(modalias); | 140 | static DEVICE_ATTR_RO(modalias); |
| @@ -145,7 +144,7 @@ static ssize_t config_show(struct device *dev, · 3 unmodified lines | |||
| 145 | { | 144 | { |
| 146 | struct ap_card *ac = to_ap_card(dev); | 145 | struct ap_card *ac = to_ap_card(dev); |
| 147 | 146 | ||
| 148 | return scnprintf(buf, PAGE_SIZE, "%d\n", ac->config ? 1 : 0); | 147 | return sysfs_emit(buf, "%d\n", ac->config ? 1 : 0); |
| 149 | } | 148 | } |
| 150 | 149 | ||
| 151 | static ssize_t config_store(struct device *dev, | 150 | static ssize_t config_store(struct device *dev, |
| @@ -179,7 +178,7 @@ static ssize_t chkstop_show(struct device *dev, · 27 unmodified lines | |||
| 179 | { | 178 | { |
| 180 | struct ap_card *ac = to_ap_card(dev); | 179 | struct ap_card *ac = to_ap_card(dev); |
| 181 | 180 | ||
| 182 | return scnprintf(buf, PAGE_SIZE, "%d\n", ac->chkstop ? 1 : 0); | 181 | return sysfs_emit(buf, "%d\n", ac->chkstop ? 1 : 0); |
| 183 | } | 182 | } |
| 184 | 183 | ||
| 185 | static DEVICE_ATTR_RO(chkstop); | 184 | static DEVICE_ATTR_RO(chkstop); |
| @@ -189,7 +188,7 @@ static ssize_t max_msg_size_show(struct device *dev, · 3 unmodified lines | |||
| 189 | { | 188 | { |
| 190 | struct ap_card *ac = to_ap_card(dev); | 189 | struct ap_card *ac = to_ap_card(dev); |
| 191 | 190 | ||
| 192 | return scnprintf(buf, PAGE_SIZE, "%u\n", ac->maxmsgsize); | 191 | return sysfs_emit(buf, "%u\n", ac->maxmsgsize); |
| 193 | } | 192 | } |
| 194 | 193 | ||
| 195 | static DEVICE_ATTR_RO(max_msg_size); | 194 | static DEVICE_ATTR_RO(max_msg_size); |
| @@ -18,6 +18,21 @@ · 17 unmodified lines | |||
| 18 | 18 | ||
| 19 | static void __ap_flush_queue(struct ap_queue *aq); | 19 | static void __ap_flush_queue(struct ap_queue *aq); |
| 20 | 20 | ||
| 21 | /* | ||
| 22 | * some AP queue helper functions | ||
| 23 | */ | ||
| 24 | |||
| 25 | static inline bool ap_q_supports_bind(struct ap_queue *aq) | ||
| 26 | { | ||
| 27 | return ap_test_bit(&aq->card->functions, AP_FUNC_EP11) || | ||
| 28 | ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL); | ||
| 29 | } | ||
| 30 | |||
| 31 | static inline bool ap_q_supports_assoc(struct ap_queue *aq) | ||
| 32 | { | ||
| 33 | return ap_test_bit(&aq->card->functions, AP_FUNC_EP11); | ||
| 34 | } | ||
| 35 | |||
| 21 | /** | 36 | /** |
| 22 | * ap_queue_enable_irq(): Enable interrupt support on this AP queue. | 37 | * ap_queue_enable_irq(): Enable interrupt support on this AP queue. |
| 23 | * @aq: The AP queue | 38 | * @aq: The AP queue |
| @@ -35,6 +50,8 @@ static int ap_queue_enable_irq(struct ap_queue *aq, void *ind) · 11 unmodified lines | |||
| 35 | qirqctrl.ir = 1; | 50 | qirqctrl.ir = 1; |
| 36 | qirqctrl.isc = AP_ISC; | 51 | qirqctrl.isc = AP_ISC; |
| 37 | status = ap_aqic(aq->qid, qirqctrl, virt_to_phys(ind)); | 52 | status = ap_aqic(aq->qid, qirqctrl, virt_to_phys(ind)); |
| 53 | if (status.async) | ||
| 54 | return -EPERM; | ||
| 38 | switch (status.response_code) { | 55 | switch (status.response_code) { |
| 39 | case AP_RESPONSE_NORMAL: | 56 | case AP_RESPONSE_NORMAL: |
| 40 | case AP_RESPONSE_OTHERWISE_CHANGED: | 57 | case AP_RESPONSE_OTHERWISE_CHANGED: |
| @@ -59,7 +76,7 @@ static int ap_queue_enable_irq(struct ap_queue *aq, void *ind) · 18 unmodified lines | |||
| 59 | * @qid: The AP queue number | 76 | * @qid: The AP queue number |
| 60 | * @psmid: The program supplied message identifier | 77 | * @psmid: The program supplied message identifier |
| 61 | * @msg: The message text | 78 | * @msg: The message text |
| 62 | * @length: The message length | 79 | * @msglen: The message length |
| 63 | * @special: Special Bit | 80 | * @special: Special Bit |
| 64 | * | 81 | * |
| 65 | * Returns AP queue status structure. | 82 | * Returns AP queue status structure. |
| @@ -68,19 +85,21 @@ static int ap_queue_enable_irq(struct ap_queue *aq, void *ind) · 2 unmodified lines | |||
| 68 | * because a segment boundary was reached. The NQAP is repeated. | 85 | * because a segment boundary was reached. The NQAP is repeated. |
| 69 | */ | 86 | */ |
| 70 | static inline struct ap_queue_status | 87 | static inline struct ap_queue_status |
| 71 | __ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length, | 88 | __ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t msglen, |
| 72 | int special) | 89 | int special) |
| 73 | { | 90 | { |
| 74 | if (special) | 91 | if (special) |
| 75 | qid |= 0x400000UL; | 92 | qid |= 0x400000UL; |
| 76 | return ap_nqap(qid, psmid, msg, length); | 93 | return ap_nqap(qid, psmid, msg, msglen); |
| 77 | } | 94 | } |
| 78 | 95 | ||
| 79 | int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) | 96 | int ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t msglen) |
| 80 | { | 97 | { |
| 81 | struct ap_queue_status status; | 98 | struct ap_queue_status status; |
| 82 | 99 | ||
| 83 | status = __ap_send(qid, psmid, msg, length, 0); | 100 | status = __ap_send(qid, psmid, msg, msglen, 0); |
| 101 | if (status.async) | ||
| 102 | return -EPERM; | ||
| 84 | switch (status.response_code) { | 103 | switch (status.response_code) { |
| 85 | case AP_RESPONSE_NORMAL: | 104 | case AP_RESPONSE_NORMAL: |
| 86 | return 0; | 105 | return 0; |
| @@ -95,13 +114,15 @@ int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) · 8 unmodified lines | |||
| 95 | } | 114 | } |
| 96 | EXPORT_SYMBOL(ap_send); | 115 | EXPORT_SYMBOL(ap_send); |
| 97 | 116 | ||
| 98 | int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) | 117 | int ap_recv(ap_qid_t qid, unsigned long *psmid, void *msg, size_t msglen) |
| 99 | { | 118 | { |
| 100 | struct ap_queue_status status; | 119 | struct ap_queue_status status; |
| 101 | 120 | ||
| 102 | if (!msg) | 121 | if (!msg) |
| 103 | return -EINVAL; | 122 | return -EINVAL; |
| 104 | status = ap_dqap(qid, psmid, msg, length, NULL, NULL); | 123 | status = ap_dqap(qid, psmid, msg, msglen, NULL, NULL, NULL); |
| 124 | if (status.async) | ||
| 125 | return -EPERM; | ||
| 105 | switch (status.response_code) { | 126 | switch (status.response_code) { |
| 106 | case AP_RESPONSE_NORMAL: | 127 | case AP_RESPONSE_NORMAL: |
| 107 | return 0; | 128 | return 0; |
| @@ -150,7 +171,7 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq) · 42 unmodified lines | |||
| 150 | do { | 171 | do { |
| 151 | status = ap_dqap(aq->qid, &aq->reply->psmid, | 172 | status = ap_dqap(aq->qid, &aq->reply->psmid, |
| 152 | aq->reply->msg, aq->reply->bufsize, | 173 | aq->reply->msg, aq->reply->bufsize, |
| 153 | &reslen, &resgr0); | 174 | &aq->reply->len, &reslen, &resgr0); |
| 154 | parts++; | 175 | parts++; |
| 155 | } while (status.response_code == 0xFF && resgr0 != 0); | 176 | } while (status.response_code == 0xFF && resgr0 != 0); |
| 156 | 177 | ||
| @@ -177,7 +198,7 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq) · 20 unmodified lines | |||
| 177 | break; | 198 | break; |
| 178 | } | 199 | } |
| 179 | if (!found) { | 200 | if (!found) { |
| 180 | AP_DBF_WARN("%s unassociated reply psmid=0x%016llx on 0x%02x.%04x\n", | 201 | AP_DBF_WARN("%s unassociated reply psmid=0x%016lx on 0x%02x.%04x\n", |
| 181 | __func__, aq->reply->psmid, | 202 | __func__, aq->reply->psmid, |
| 182 | AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); | 203 | AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); |
| 183 | } | 204 | } |
| @@ -210,6 +231,8 @@ static enum ap_sm_wait ap_sm_read(struct ap_queue *aq) · 26 unmodified lines | |||
| 210 | if (!aq->reply) | 231 | if (!aq->reply) |
| 211 | return AP_SM_WAIT_NONE; | 232 | return AP_SM_WAIT_NONE; |
| 212 | status = ap_sm_recv(aq); | 233 | status = ap_sm_recv(aq); |
| 234 | if (status.async) | ||
| 235 | return AP_SM_WAIT_NONE; | ||
| 213 | switch (status.response_code) { | 236 | switch (status.response_code) { |
| 214 | case AP_RESPONSE_NORMAL: | 237 | case AP_RESPONSE_NORMAL: |
| 215 | if (aq->queue_count > 0) { | 238 | if (aq->queue_count > 0) { |
| @@ -221,7 +244,7 @@ static enum ap_sm_wait ap_sm_read(struct ap_queue *aq) · 5 unmodified lines | |||
| 221 | case AP_RESPONSE_NO_PENDING_REPLY: | 244 | case AP_RESPONSE_NO_PENDING_REPLY: |
| 222 | if (aq->queue_count > 0) | 245 | if (aq->queue_count > 0) |
| 223 | return aq->interrupt ? | 246 | return aq->interrupt ? |
| 224 | AP_SM_WAIT_INTERRUPT : AP_SM_WAIT_TIMEOUT; | 247 | AP_SM_WAIT_INTERRUPT : AP_SM_WAIT_HIGH_TIMEOUT; |
| 225 | aq->sm_state = AP_SM_STATE_IDLE; | 248 | aq->sm_state = AP_SM_STATE_IDLE; |
| 226 | return AP_SM_WAIT_NONE; | 249 | return AP_SM_WAIT_NONE; |
| 227 | default: | 250 | default: |
| @@ -261,6 +284,8 @@ static enum ap_sm_wait ap_sm_write(struct ap_queue *aq) · 33 unmodified lines | |||
| 261 | status = __ap_send(qid, ap_msg->psmid, | 284 | status = __ap_send(qid, ap_msg->psmid, |
| 262 | ap_msg->msg, ap_msg->len, | 285 | ap_msg->msg, ap_msg->len, |
| 263 | ap_msg->flags & AP_MSG_FLAG_SPECIAL); | 286 | ap_msg->flags & AP_MSG_FLAG_SPECIAL); |
| 287 | if (status.async) | ||
| 288 | return AP_SM_WAIT_NONE; | ||
| 264 | switch (status.response_code) { | 289 | switch (status.response_code) { |
| 265 | case AP_RESPONSE_NORMAL: | 290 | case AP_RESPONSE_NORMAL: |
| 266 | aq->queue_count = max_t(int, 1, aq->queue_count + 1); | 291 | aq->queue_count = max_t(int, 1, aq->queue_count + 1); |
| @@ -277,10 +302,10 @@ static enum ap_sm_wait ap_sm_write(struct ap_queue *aq) · 10 unmodified lines | |||
| 277 | case AP_RESPONSE_Q_FULL: | 302 | case AP_RESPONSE_Q_FULL: |
| 278 | aq->sm_state = AP_SM_STATE_QUEUE_FULL; | 303 | aq->sm_state = AP_SM_STATE_QUEUE_FULL; |
| 279 | return aq->interrupt ? | 304 | return aq->interrupt ? |
| 280 | AP_SM_WAIT_INTERRUPT : AP_SM_WAIT_TIMEOUT; | 305 | AP_SM_WAIT_INTERRUPT : AP_SM_WAIT_HIGH_TIMEOUT; |
| 281 | case AP_RESPONSE_RESET_IN_PROGRESS: | 306 | case AP_RESPONSE_RESET_IN_PROGRESS: |
| 282 | aq->sm_state = AP_SM_STATE_RESET_WAIT; | 307 | aq->sm_state = AP_SM_STATE_RESET_WAIT; |
| 283 | return AP_SM_WAIT_TIMEOUT; | 308 | return AP_SM_WAIT_LOW_TIMEOUT; |
| 284 | case AP_RESPONSE_INVALID_DOMAIN: | 309 | case AP_RESPONSE_INVALID_DOMAIN: |
| 285 | AP_DBF_WARN("%s RESPONSE_INVALID_DOMAIN on NQAP\n", __func__); | 310 | AP_DBF_WARN("%s RESPONSE_INVALID_DOMAIN on NQAP\n", __func__); |
| 286 | fallthrough; | 311 | fallthrough; |
| @@ -322,13 +347,16 @@ static enum ap_sm_wait ap_sm_reset(struct ap_queue *aq) · 35 unmodified lines | |||
| 322 | { | 347 | { |
| 323 | struct ap_queue_status status; | 348 | struct ap_queue_status status; |
| 324 | 349 | ||
| 325 | status = ap_rapq(aq->qid); | 350 | status = ap_rapq(aq->qid, aq->rapq_fbit); |
| 351 | if (status.async) | ||
| 352 | return AP_SM_WAIT_NONE; | ||
| 326 | switch (status.response_code) { | 353 | switch (status.response_code) { |
| 327 | case AP_RESPONSE_NORMAL: | 354 | case AP_RESPONSE_NORMAL: |
| 328 | case AP_RESPONSE_RESET_IN_PROGRESS: | 355 | case AP_RESPONSE_RESET_IN_PROGRESS: |
| 329 | aq->sm_state = AP_SM_STATE_RESET_WAIT; | 356 | aq->sm_state = AP_SM_STATE_RESET_WAIT; |
| 330 | aq->interrupt = false; | 357 | aq->interrupt = false; |
| 331 | return AP_SM_WAIT_TIMEOUT; | 358 | aq->rapq_fbit = 0; |
| 359 | return AP_SM_WAIT_LOW_TIMEOUT; | ||
| 332 | default: | 360 | default: |
| 333 | aq->dev_state = AP_DEV_STATE_ERROR; | 361 | aq->dev_state = AP_DEV_STATE_ERROR; |
| 334 | aq->last_err_rc = status.response_code; | 362 | aq->last_err_rc = status.response_code; |
| @@ -368,7 +396,7 @@ static enum ap_sm_wait ap_sm_reset_wait(struct ap_queue *aq) · 33 unmodified lines | |||
| 368 | return AP_SM_WAIT_AGAIN; | 396 | return AP_SM_WAIT_AGAIN; |
| 369 | case AP_RESPONSE_BUSY: | 397 | case AP_RESPONSE_BUSY: |
| 370 | case AP_RESPONSE_RESET_IN_PROGRESS: | 398 | case AP_RESPONSE_RESET_IN_PROGRESS: |
| 371 | return AP_SM_WAIT_TIMEOUT; | 399 | return AP_SM_WAIT_LOW_TIMEOUT; |
| 372 | case AP_RESPONSE_Q_NOT_AVAIL: | 400 | case AP_RESPONSE_Q_NOT_AVAIL: |
| 373 | case AP_RESPONSE_DECONFIGURED: | 401 | case AP_RESPONSE_DECONFIGURED: |
| 374 | case AP_RESPONSE_CHECKSTOPPED: | 402 | case AP_RESPONSE_CHECKSTOPPED: |
| @@ -412,7 +440,7 @@ static enum ap_sm_wait ap_sm_setirq_wait(struct ap_queue *aq) · 37 unmodified lines | |||
| 412 | return AP_SM_WAIT_AGAIN; | 440 | return AP_SM_WAIT_AGAIN; |
| 413 | fallthrough; | 441 | fallthrough; |
| 414 | case AP_RESPONSE_NO_PENDING_REPLY: | 442 | case AP_RESPONSE_NO_PENDING_REPLY: |
| 415 | return AP_SM_WAIT_TIMEOUT; | 443 | return AP_SM_WAIT_LOW_TIMEOUT; |
| 416 | default: | 444 | default: |
| 417 | aq->dev_state = AP_DEV_STATE_ERROR; | 445 | aq->dev_state = AP_DEV_STATE_ERROR; |
| 418 | aq->last_err_rc = status.response_code; | 446 | aq->last_err_rc = status.response_code; |
| @@ -423,6 +451,59 @@ static enum ap_sm_wait ap_sm_setirq_wait(struct ap_queue *aq) · 4 unmodified lines | |||
| 423 | } | 451 | } |
| 424 | } | 452 | } |
| 425 | 453 | ||
| 454 | /** | ||
| 455 | * ap_sm_assoc_wait(): Test queue for completion of a pending | ||
| 456 | * association request. | ||
| 457 | * @aq: pointer to the AP queue | ||
| 458 | */ | ||
| 459 | static enum ap_sm_wait ap_sm_assoc_wait(struct ap_queue *aq) | ||
| 460 | { | ||
| 461 | struct ap_queue_status status; | ||
| 462 | struct ap_tapq_gr2 info; | ||
| 463 | |||
| 464 | status = ap_test_queue(aq->qid, 1, &info); | ||
| 465 | /* handle asynchronous error on this queue */ | ||
| 466 | if (status.async && status.response_code) { | ||
| 467 | aq->dev_state = AP_DEV_STATE_ERROR; | ||
| 468 | aq->last_err_rc = status.response_code; | ||
| 469 | AP_DBF_WARN("%s asynch RC 0x%02x on 0x%02x.%04x -> AP_DEV_STATE_ERROR\n", | ||
| 470 | __func__, status.response_code, | ||
| 471 | AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); | ||
| 472 | return AP_SM_WAIT_NONE; | ||
| 473 | } | ||
| 474 | if (status.response_code > AP_RESPONSE_BUSY) { | ||
| 475 | aq->dev_state = AP_DEV_STATE_ERROR; | ||
| 476 | aq->last_err_rc = status.response_code; | ||
| 477 | AP_DBF_WARN("%s RC 0x%02x on 0x%02x.%04x -> AP_DEV_STATE_ERROR\n", | ||
| 478 | __func__, status.response_code, | ||
| 479 | AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); | ||
| 480 | return AP_SM_WAIT_NONE; | ||
| 481 | } | ||
| 482 | |||
| 483 | /* check bs bits */ | ||
| 484 | switch (info.bs) { | ||
| 485 | case AP_BS_Q_USABLE: | ||
| 486 | /* association is through */ | ||
| 487 | aq->sm_state = AP_SM_STATE_IDLE; | ||
| 488 | AP_DBF_DBG("%s queue 0x%02x.%04x associated with %u\n", | ||
| 489 | __func__, AP_QID_CARD(aq->qid), | ||
| 490 | AP_QID_QUEUE(aq->qid), aq->assoc_idx); | ||
| 491 | return AP_SM_WAIT_NONE; | ||
| 492 | case AP_BS_Q_USABLE_NO_SECURE_KEY: | ||
| 493 | /* association still pending */ | ||
| 494 | return AP_SM_WAIT_LOW_TIMEOUT; | ||
| 495 | default: | ||
| 496 | /* reset from 'outside' happened or no idea at all */ | ||
| 497 | aq->assoc_idx = ASSOC_IDX_INVALID; | ||
| 498 | aq->dev_state = AP_DEV_STATE_ERROR; | ||
| 499 | aq->last_err_rc = status.response_code; | ||
| 500 | AP_DBF_WARN("%s bs 0x%02x on 0x%02x.%04x -> AP_DEV_STATE_ERROR\n", | ||
| 501 | __func__, info.bs, | ||
| 502 | AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); | ||
| 503 | return AP_SM_WAIT_NONE; | ||
| 504 | } | ||
| 505 | } | ||
| 506 | |||
| 426 | /* | 507 | /* |
| 427 | * AP state machine jump table | 508 | * AP state machine jump table |
| 428 | */ | 509 | */ |
| @@ -451,6 +532,10 @@ static ap_func_t *ap_jumptable[NR_AP_SM_STATES][NR_AP_SM_EVENTS] = { · 22 unmodified lines | |||
| 451 | [AP_SM_EVENT_POLL] = ap_sm_read, | 532 | [AP_SM_EVENT_POLL] = ap_sm_read, |
| 452 | [AP_SM_EVENT_TIMEOUT] = ap_sm_reset, | 533 | [AP_SM_EVENT_TIMEOUT] = ap_sm_reset, |
| 453 | }, | 534 | }, |
| 535 | [AP_SM_STATE_ASSOC_WAIT] = { | ||
| 536 | [AP_SM_EVENT_POLL] = ap_sm_assoc_wait, | ||
| 537 | [AP_SM_EVENT_TIMEOUT] = ap_sm_reset, | ||
| 538 | }, | ||
| 454 | }; | 539 | }; |
| 455 | 540 | ||
| 456 | enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event) | 541 | enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event) |
| @@ -490,9 +575,9 @@ static ssize_t request_count_show(struct device *dev, · 33 unmodified lines | |||
| 490 | spin_unlock_bh(&aq->lock); | 575 | spin_unlock_bh(&aq->lock); |
| 491 | 576 | ||
| 492 | if (valid) | 577 | if (valid) |
| 493 | return scnprintf(buf, PAGE_SIZE, "%llu\n", req_cnt); | 578 | return sysfs_emit(buf, "%llu\n", req_cnt); |
| 494 | else | 579 | else |
| 495 | return scnprintf(buf, PAGE_SIZE, "-\n"); | 580 | return sysfs_emit(buf, "-\n"); |
| 496 | } | 581 | } |
| 497 | 582 | ||
| 498 | static ssize_t request_count_store(struct device *dev, | 583 | static ssize_t request_count_store(struct device *dev, |
| @@ -520,7 +605,7 @@ static ssize_t requestq_count_show(struct device *dev, · 21 unmodified lines | |||
| 520 | if (aq->dev_state > AP_DEV_STATE_UNINITIATED) | 605 | if (aq->dev_state > AP_DEV_STATE_UNINITIATED) |
| 521 | reqq_cnt = aq->requestq_count; | 606 | reqq_cnt = aq->requestq_count; |
| 522 | spin_unlock_bh(&aq->lock); | 607 | spin_unlock_bh(&aq->lock); |
| 523 | return scnprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); | 608 | return sysfs_emit(buf, "%d\n", reqq_cnt); |
| 524 | } | 609 | } |
| 525 | 610 | ||
| 526 | static DEVICE_ATTR_RO(requestq_count); | 611 | static DEVICE_ATTR_RO(requestq_count); |
| @@ -535,7 +620,7 @@ static ssize_t pendingq_count_show(struct device *dev, · 8 unmodified lines | |||
| 535 | if (aq->dev_state > AP_DEV_STATE_UNINITIATED) | 620 | if (aq->dev_state > AP_DEV_STATE_UNINITIATED) |
| 536 | penq_cnt = aq->pendingq_count; | 621 | penq_cnt = aq->pendingq_count; |
| 537 | spin_unlock_bh(&aq->lock); | 622 | spin_unlock_bh(&aq->lock); |
| 538 | return scnprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); | 623 | return sysfs_emit(buf, "%d\n", penq_cnt); |
| 539 | } | 624 | } |
| 540 | 625 | ||
| 541 | static DEVICE_ATTR_RO(pendingq_count); | 626 | static DEVICE_ATTR_RO(pendingq_count); |
| @@ -550,14 +635,14 @@ static ssize_t reset_show(struct device *dev, · 8 unmodified lines | |||
| 550 | switch (aq->sm_state) { | 635 | switch (aq->sm_state) { |
| 551 | case AP_SM_STATE_RESET_START: | 636 | case AP_SM_STATE_RESET_START: |
| 552 | case AP_SM_STATE_RESET_WAIT: | 637 | case AP_SM_STATE_RESET_WAIT: |
| 553 | rc = scnprintf(buf, PAGE_SIZE, "Reset in progress.\n"); | 638 | rc = sysfs_emit(buf, "Reset in progress.\n"); |
| 554 | break; | 639 | break; |
| 555 | case AP_SM_STATE_WORKING: | 640 | case AP_SM_STATE_WORKING: |
| 556 | case AP_SM_STATE_QUEUE_FULL: | 641 | case AP_SM_STATE_QUEUE_FULL: |
| 557 | rc = scnprintf(buf, PAGE_SIZE, "Reset Timer armed.\n"); | 642 | rc = sysfs_emit(buf, "Reset Timer armed.\n"); |
| 558 | break; | 643 | break; |
| 559 | default: | 644 | default: |
| 560 | rc = scnprintf(buf, PAGE_SIZE, "No Reset Timer set.\n"); | 645 | rc = sysfs_emit(buf, "No Reset Timer set.\n"); |
| 561 | } | 646 | } |
| 562 | spin_unlock_bh(&aq->lock); | 647 | spin_unlock_bh(&aq->lock); |
| 563 | return rc; | 648 | return rc; |
| @@ -591,11 +676,11 @@ static ssize_t interrupt_show(struct device *dev, · 27 unmodified lines | |||
| 591 | 676 | ||
| 592 | spin_lock_bh(&aq->lock); | 677 | spin_lock_bh(&aq->lock); |
| 593 | if (aq->sm_state == AP_SM_STATE_SETIRQ_WAIT) | 678 | if (aq->sm_state == AP_SM_STATE_SETIRQ_WAIT) |
| 594 | rc = scnprintf(buf, PAGE_SIZE, "Enable Interrupt pending.\n"); | 679 | rc = sysfs_emit(buf, "Enable Interrupt pending.\n"); |
| 595 | else if (aq->interrupt) | 680 | else if (aq->interrupt) |
| 596 | rc = scnprintf(buf, PAGE_SIZE, "Interrupts enabled.\n"); | 681 | rc = sysfs_emit(buf, "Interrupts enabled.\n"); |
| 597 | else | 682 | else |
| 598 | rc = scnprintf(buf, PAGE_SIZE, "Interrupts disabled.\n"); | 683 | rc = sysfs_emit(buf, "Interrupts disabled.\n"); |
| 599 | spin_unlock_bh(&aq->lock); | 684 | spin_unlock_bh(&aq->lock); |
| 600 | return rc; | 685 | return rc; |
| 601 | } | 686 | } |
| @@ -609,7 +694,7 @@ static ssize_t config_show(struct device *dev, · 7 unmodified lines | |||
| 609 | int rc; | 694 | int rc; |
| 610 | 695 | ||
| 611 | spin_lock_bh(&aq->lock); | 696 | spin_lock_bh(&aq->lock); |
| 612 | rc = scnprintf(buf, PAGE_SIZE, "%d\n", aq->config ? 1 : 0); | 697 | rc = sysfs_emit(buf, "%d\n", aq->config ? 1 : 0); |
| 613 | spin_unlock_bh(&aq->lock); | 698 | spin_unlock_bh(&aq->lock); |
| 614 | return rc; | 699 | return rc; |
| 615 | } | 700 | } |
| @@ -623,13 +708,33 @@ static ssize_t chkstop_show(struct device *dev, · 7 unmodified lines | |||
| 623 | int rc; | 708 | int rc; |
| 624 | 709 | ||
| 625 | spin_lock_bh(&aq->lock); | 710 | spin_lock_bh(&aq->lock); |
| 626 | rc = scnprintf(buf, PAGE_SIZE, "%d\n", aq->chkstop ? 1 : 0); | 711 | rc = sysfs_emit(buf, "%d\n", aq->chkstop ? 1 : 0); |
| 627 | spin_unlock_bh(&aq->lock); | 712 | spin_unlock_bh(&aq->lock); |
| 628 | return rc; | 713 | return rc; |
| 629 | } | 714 | } |
| 630 | 715 | ||
| 631 | static DEVICE_ATTR_RO(chkstop); | 716 | static DEVICE_ATTR_RO(chkstop); |
| 632 | 717 | ||
| 718 | static ssize_t ap_functions_show(struct device *dev, | ||
| 719 | struct device_attribute *attr, char *buf) | ||
| 720 | { | ||
| 721 | struct ap_queue *aq = to_ap_queue(dev); | ||
| 722 | struct ap_queue_status status; | ||
| 723 | struct ap_tapq_gr2 info; | ||
| 724 | |||
| 725 | status = ap_test_queue(aq->qid, 1, &info); | ||
| 726 | if (status.response_code > AP_RESPONSE_BUSY) { | ||
| 727 | AP_DBF_DBG("%s RC 0x%02x on tapq(0x%02x.%04x)\n", | ||
| 728 | __func__, status.response_code, | ||
| 729 | AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); | ||
| 730 | return -EIO; | ||
| 731 | } | ||
| 732 | |||
| 733 | return sysfs_emit(buf, "0x%08X\n", info.fac); | ||
| 734 | } | ||
| 735 | |||
| 736 | static DEVICE_ATTR_RO(ap_functions); | ||
| 737 | |||
| 633 | #ifdef CONFIG_ZCRYPT_DEBUG | 738 | #ifdef CONFIG_ZCRYPT_DEBUG |
| 634 | static ssize_t states_show(struct device *dev, | 739 | static ssize_t states_show(struct device *dev, |
| 635 | struct device_attribute *attr, char *buf) | 740 | struct device_attribute *attr, char *buf) |
| @@ -641,50 +746,46 @@ static ssize_t states_show(struct device *dev, · 5 unmodified lines | |||
| 641 | /* queue device state */ | 746 | /* queue device state */ |
| 642 | switch (aq->dev_state) { | 747 | switch (aq->dev_state) { |
| 643 | case AP_DEV_STATE_UNINITIATED: | 748 | case AP_DEV_STATE_UNINITIATED: |
| 644 | rc = scnprintf(buf, PAGE_SIZE, "UNINITIATED\n"); | 749 | rc = sysfs_emit(buf, "UNINITIATED\n"); |
| 645 | break; | 750 | break; |
| 646 | case AP_DEV_STATE_OPERATING: | 751 | case AP_DEV_STATE_OPERATING: |
| 647 | rc = scnprintf(buf, PAGE_SIZE, "OPERATING"); | 752 | rc = sysfs_emit(buf, "OPERATING"); |
| 648 | break; | 753 | break; |
| 649 | case AP_DEV_STATE_SHUTDOWN: | 754 | case AP_DEV_STATE_SHUTDOWN: |
| 650 | rc = scnprintf(buf, PAGE_SIZE, "SHUTDOWN"); | 755 | rc = sysfs_emit(buf, "SHUTDOWN"); |
| 651 | break; | 756 | break; |
| 652 | case AP_DEV_STATE_ERROR: | 757 | case AP_DEV_STATE_ERROR: |
| 653 | rc = scnprintf(buf, PAGE_SIZE, "ERROR"); | 758 | rc = sysfs_emit(buf, "ERROR"); |
| 654 | break; | 759 | break; |
| 655 | default: | 760 | default: |
| 656 | rc = scnprintf(buf, PAGE_SIZE, "UNKNOWN"); | 761 | rc = sysfs_emit(buf, "UNKNOWN"); |
| 657 | } | 762 | } |
| 658 | /* state machine state */ | 763 | /* state machine state */ |
| 659 | if (aq->dev_state) { | 764 | if (aq->dev_state) { |
| 660 | switch (aq->sm_state) { | 765 | switch (aq->sm_state) { |
| 661 | case AP_SM_STATE_RESET_START: | 766 | case AP_SM_STATE_RESET_START: |
| 662 | rc += scnprintf(buf + rc, PAGE_SIZE - rc, | 767 | rc += sysfs_emit_at(buf, rc, " [RESET_START]\n"); |
| 663 | " [RESET_START]\n"); | ||
| 664 | break; | 768 | break; |
| 665 | case AP_SM_STATE_RESET_WAIT: | 769 | case AP_SM_STATE_RESET_WAIT: |
| 666 | rc += scnprintf(buf + rc, PAGE_SIZE - rc, | 770 | rc += sysfs_emit_at(buf, rc, " [RESET_WAIT]\n"); |
| 667 | " [RESET_WAIT]\n"); | ||
| 668 | break; | 771 | break; |
| 669 | case AP_SM_STATE_SETIRQ_WAIT: | 772 | case AP_SM_STATE_SETIRQ_WAIT: |
| 670 | rc += scnprintf(buf + rc, PAGE_SIZE - rc, | 773 | rc += sysfs_emit_at(buf, rc, " [SETIRQ_WAIT]\n"); |
| 671 | " [SETIRQ_WAIT]\n"); | ||
| 672 | break; | 774 | break; |
| 673 | case AP_SM_STATE_IDLE: | 775 | case AP_SM_STATE_IDLE: |
| 674 | rc += scnprintf(buf + rc, PAGE_SIZE - rc, | 776 | rc += sysfs_emit_at(buf, rc, " [IDLE]\n"); |
| 675 | " [IDLE]\n"); | ||
| 676 | break; | 777 | break; |
| 677 | case AP_SM_STATE_WORKING: | 778 | case AP_SM_STATE_WORKING: |
| 678 | rc += scnprintf(buf + rc, PAGE_SIZE - rc, | 779 | rc += sysfs_emit_at(buf, rc, " [WORKING]\n"); |
| 679 | " [WORKING]\n"); | ||
| 680 | break; | 780 | break; |
| 681 | case AP_SM_STATE_QUEUE_FULL: | 781 | case AP_SM_STATE_QUEUE_FULL: |
| 682 | rc += scnprintf(buf + rc, PAGE_SIZE - rc, | 782 | rc += sysfs_emit_at(buf, rc, " [FULL]\n"); |
| 683 | " [FULL]\n"); | 783 | break; |
| 784 | case AP_SM_STATE_ASSOC_WAIT: | ||
| 785 | rc += sysfs_emit_at(buf, rc, " [ASSOC_WAIT]\n"); | ||
| 684 | break; | 786 | break; |
| 685 | default: | 787 | default: |
| 686 | rc += scnprintf(buf + rc, PAGE_SIZE - rc, | 788 | rc += sysfs_emit_at(buf, rc, " [UNKNOWN]\n"); |
| 687 | " [UNKNOWN]\n"); | ||
| 688 | } | 789 | } |
| 689 | } | 790 | } |
| 690 | spin_unlock_bh(&aq->lock); | 791 | spin_unlock_bh(&aq->lock); |
| @@ -705,33 +806,33 @@ static ssize_t last_err_rc_show(struct device *dev, · 14 unmodified lines | |||
| 705 | 806 | ||
| 706 | switch (rc) { | 807 | switch (rc) { |
| 707 | case AP_RESPONSE_NORMAL: | 808 | case AP_RESPONSE_NORMAL: |
| 708 | return scnprintf(buf, PAGE_SIZE, "NORMAL\n"); | 809 | return sysfs_emit(buf, "NORMAL\n"); |
| 709 | case AP_RESPONSE_Q_NOT_AVAIL: | 810 | case AP_RESPONSE_Q_NOT_AVAIL: |
| 710 | return scnprintf(buf, PAGE_SIZE, "Q_NOT_AVAIL\n"); | 811 | return sysfs_emit(buf, "Q_NOT_AVAIL\n"); |
| 711 | case AP_RESPONSE_RESET_IN_PROGRESS: | 812 | case AP_RESPONSE_RESET_IN_PROGRESS: |
| 712 | return scnprintf(buf, PAGE_SIZE, "RESET_IN_PROGRESS\n"); | 813 | return sysfs_emit(buf, "RESET_IN_PROGRESS\n"); |
| 713 | case AP_RESPONSE_DECONFIGURED: | 814 | case AP_RESPONSE_DECONFIGURED: |
| 714 | return scnprintf(buf, PAGE_SIZE, "DECONFIGURED\n"); | 815 | return sysfs_emit(buf, "DECONFIGURED\n"); |
| 715 | case AP_RESPONSE_CHECKSTOPPED: | 816 | case AP_RESPONSE_CHECKSTOPPED: |
| 716 | return scnprintf(buf, PAGE_SIZE, "CHECKSTOPPED\n"); | 817 | return sysfs_emit(buf, "CHECKSTOPPED\n"); |
| 717 | case AP_RESPONSE_BUSY: | 818 | case AP_RESPONSE_BUSY: |
| 718 | return scnprintf(buf, PAGE_SIZE, "BUSY\n"); | 819 | return sysfs_emit(buf, "BUSY\n"); |
| 719 | case AP_RESPONSE_INVALID_ADDRESS: | 820 | case AP_RESPONSE_INVALID_ADDRESS: |
| 720 | return scnprintf(buf, PAGE_SIZE, "INVALID_ADDRESS\n"); | 821 | return sysfs_emit(buf, "INVALID_ADDRESS\n"); |
| 721 | case AP_RESPONSE_OTHERWISE_CHANGED: | 822 | case AP_RESPONSE_OTHERWISE_CHANGED: |
| 722 | return scnprintf(buf, PAGE_SIZE, "OTHERWISE_CHANGED\n"); | 823 | return sysfs_emit(buf, "OTHERWISE_CHANGED\n"); |
| 723 | case AP_RESPONSE_Q_FULL: | 824 | case AP_RESPONSE_Q_FULL: |
| 724 | return scnprintf(buf, PAGE_SIZE, "Q_FULL/NO_PENDING_REPLY\n"); | 825 | return sysfs_emit(buf, "Q_FULL/NO_PENDING_REPLY\n"); |
| 725 | case AP_RESPONSE_INDEX_TOO_BIG: | 826 | case AP_RESPONSE_INDEX_TOO_BIG: |
| 726 | return scnprintf(buf, PAGE_SIZE, "INDEX_TOO_BIG\n"); | 827 | return sysfs_emit(buf, "INDEX_TOO_BIG\n"); |
| 727 | case AP_RESPONSE_NO_FIRST_PART: | 828 | case AP_RESPONSE_NO_FIRST_PART: |
| 728 | return scnprintf(buf, PAGE_SIZE, "NO_FIRST_PART\n"); | 829 | return sysfs_emit(buf, "NO_FIRST_PART\n"); |
| 729 | case AP_RESPONSE_MESSAGE_TOO_BIG: | 830 | case AP_RESPONSE_MESSAGE_TOO_BIG: |
| 730 | return scnprintf(buf, PAGE_SIZE, "MESSAGE_TOO_BIG\n"); | 831 | return sysfs_emit(buf, "MESSAGE_TOO_BIG\n"); |
| 731 | case AP_RESPONSE_REQ_FAC_NOT_INST: | 832 | case AP_RESPONSE_REQ_FAC_NOT_INST: |
| 732 | return scnprintf(buf, PAGE_SIZE, "REQ_FAC_NOT_INST\n"); | 833 | return sysfs_emit(buf, "REQ_FAC_NOT_INST\n"); |
| 733 | default: | 834 | default: |
| 734 | return scnprintf(buf, PAGE_SIZE, "response code %d\n", rc); | 835 | return sysfs_emit(buf, "response code %d\n", rc); |
| 735 | } | 836 | } |
| 736 | } | 837 | } |
| 737 | static DEVICE_ATTR_RO(last_err_rc); | 838 | static DEVICE_ATTR_RO(last_err_rc); |
| @@ -745,6 +846,7 @@ static struct attribute *ap_queue_dev_attrs[] = { · 7 unmodified lines | |||
| 745 | &dev_attr_interrupt.attr, | 846 | &dev_attr_interrupt.attr, |
| 746 | &dev_attr_config.attr, | 847 | &dev_attr_config.attr, |
| 747 | &dev_attr_chkstop.attr, | 848 | &dev_attr_chkstop.attr, |
| 849 | &dev_attr_ap_functions.attr, | ||
| 748 | #ifdef CONFIG_ZCRYPT_DEBUG | 850 | #ifdef CONFIG_ZCRYPT_DEBUG |
| 749 | &dev_attr_states.attr, | 851 | &dev_attr_states.attr, |
| 750 | &dev_attr_last_err_rc.attr, | 852 | &dev_attr_last_err_rc.attr, |
| @@ -766,6 +868,186 @@ static struct device_type ap_queue_type = { · 15 unmodified lines | |||
| 766 | .groups = ap_queue_dev_attr_groups, | 868 | .groups = ap_queue_dev_attr_groups, |
| 767 | }; | 869 | }; |
| 768 | 870 | ||
| 871 | static ssize_t se_bind_show(struct device *dev, | ||
| 872 | struct device_attribute *attr, char *buf) | ||
| 873 | { | ||
| 874 | struct ap_queue *aq = to_ap_queue(dev); | ||
| 875 | struct ap_queue_status status; | ||
| 876 | struct ap_tapq_gr2 info; | ||
| 877 | |||
| 878 | if (!ap_q_supports_bind(aq)) | ||
| 879 | return sysfs_emit(buf, "-\n"); | ||
| 880 | |||
| 881 | status = ap_test_queue(aq->qid, 1, &info); | ||
| 882 | if (status.response_code > AP_RESPONSE_BUSY) { | ||
| 883 | AP_DBF_DBG("%s RC 0x%02x on tapq(0x%02x.%04x)\n", | ||
| 884 | __func__, status.response_code, | ||
| 885 | AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); | ||
| 886 | return -EIO; | ||
| 887 | } | ||
| 888 | switch (info.bs) { | ||
| 889 | case AP_BS_Q_USABLE: | ||
| 890 | case AP_BS_Q_USABLE_NO_SECURE_KEY: | ||
| 891 | return sysfs_emit(buf, "bound\n"); | ||
| 892 | default: | ||
| 893 | return sysfs_emit(buf, "unbound\n"); | ||
| 894 | } | ||
| 895 | } | ||
| 896 | |||
| 897 | static ssize_t se_bind_store(struct device *dev, | ||
| 898 | struct device_attribute *attr, | ||
| 899 | const char *buf, size_t count) | ||
| 900 | { | ||
| 901 | struct ap_queue *aq = to_ap_queue(dev); | ||
| 902 | struct ap_queue_status status; | ||
| 903 | bool value; | ||
| 904 | int rc; | ||
| 905 | |||
| 906 | if (!ap_q_supports_bind(aq)) | ||
| 907 | return -EINVAL; | ||
| 908 | |||
| 909 | /* only 0 (unbind) and 1 (bind) allowed */ | ||
| 910 | rc = kstrtobool(buf, &value); | ||
| 911 | if (rc) | ||
| 912 | return rc; | ||
| 913 | |||
| 914 | if (value) { | ||
| 915 | /* bind, do BAPQ */ | ||
| 916 | spin_lock_bh(&aq->lock); | ||
| 917 | if (aq->sm_state < AP_SM_STATE_IDLE) { | ||
| 918 | spin_unlock_bh(&aq->lock); | ||
| 919 | return -EBUSY; | ||
| 920 | } | ||
| 921 | status = ap_bapq(aq->qid); | ||
| 922 | spin_unlock_bh(&aq->lock); | ||
| 923 | if (status.response_code) { | ||
| 924 | AP_DBF_WARN("%s RC 0x%02x on bapq(0x%02x.%04x)\n", | ||
| 925 | __func__, status.response_code, | ||
| 926 | AP_QID_CARD(aq->qid), | ||
| 927 | AP_QID_QUEUE(aq->qid)); | ||
| 928 | return -EIO; | ||
| 929 | } | ||
| 930 | } else { | ||
| 931 | /* unbind, set F bit arg and trigger RAPQ */ | ||
| 932 | spin_lock_bh(&aq->lock); | ||
| 933 | __ap_flush_queue(aq); | ||
| 934 | aq->rapq_fbit = 1; | ||
| 935 | aq->assoc_idx = ASSOC_IDX_INVALID; | ||
| 936 | aq->sm_state = AP_SM_STATE_RESET_START; | ||
| 937 | ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL)); | ||
| 938 | spin_unlock_bh(&aq->lock); | ||
| 939 | } | ||
| 940 | |||
| 941 | return count; | ||
| 942 | } | ||
| 943 | |||
| 944 | static DEVICE_ATTR_RW(se_bind); | ||
| 945 | |||
| 946 | static ssize_t se_associate_show(struct device *dev, | ||
| 947 | struct device_attribute *attr, char *buf) | ||
| 948 | { | ||
| 949 | struct ap_queue *aq = to_ap_queue(dev); | ||
| 950 | struct ap_queue_status status; | ||
| 951 | struct ap_tapq_gr2 info; | ||
| 952 | |||
| 953 | if (!ap_q_supports_assoc(aq)) | ||
| 954 | return sysfs_emit(buf, "-\n"); | ||
| 955 | |||
| 956 | status = ap_test_queue(aq->qid, 1, &info); | ||
| 957 | if (status.response_code > AP_RESPONSE_BUSY) { | ||
| 958 | AP_DBF_DBG("%s RC 0x%02x on tapq(0x%02x.%04x)\n", | ||
| 959 | __func__, status.response_code, | ||
| 960 | AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); | ||
| 961 | return -EIO; | ||
| 962 | } | ||
| 963 | |||
| 964 | switch (info.bs) { | ||
| 965 | case AP_BS_Q_USABLE: | ||
| 966 | if (aq->assoc_idx == ASSOC_IDX_INVALID) { | ||
| 967 | AP_DBF_WARN("%s AP_BS_Q_USABLE but invalid assoc_idx\n", __func__); | ||
| 968 | return -EIO; | ||
| 969 | } | ||
| 970 | return sysfs_emit(buf, "associated %u\n", aq->assoc_idx); | ||
| 971 | case AP_BS_Q_USABLE_NO_SECURE_KEY: | ||
| 972 | if (aq->assoc_idx != ASSOC_IDX_INVALID) | ||
| 973 | return sysfs_emit(buf, "association pending\n"); | ||
| 974 | fallthrough; | ||
| 975 | default: | ||
| 976 | return sysfs_emit(buf, "unassociated\n"); | ||
| 977 | } | ||
| 978 | } | ||
| 979 | |||
| 980 | static ssize_t se_associate_store(struct device *dev, | ||
| 981 | struct device_attribute *attr, | ||
| 982 | const char *buf, size_t count) | ||
| 983 | { | ||
| 984 | struct ap_queue *aq = to_ap_queue(dev); | ||
| 985 | struct ap_queue_status status; | ||
| 986 | unsigned int value; | ||
| 987 | int rc; | ||
| 988 | |||
| 989 | if (!ap_q_supports_assoc(aq)) | ||
| 990 | return -EINVAL; | ||
| 991 | |||
| 992 | /* association index needs to be >= 0 */ | ||
| 993 | rc = kstrtouint(buf, 0, &value); | ||
| 994 | if (rc) | ||
| 995 | return rc; | ||
| 996 | if (value >= ASSOC_IDX_INVALID) | ||
| 997 | return -EINVAL; | ||
| 998 | |||
| 999 | spin_lock_bh(&aq->lock); | ||
| 1000 | |||
| 1001 | /* sm should be in idle state */ | ||
| 1002 | if (aq->sm_state != AP_SM_STATE_IDLE) { | ||
| 1003 | spin_unlock_bh(&aq->lock); | ||
| 1004 | return -EBUSY; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | /* already associated or association pending ? */ | ||
| 1008 | if (aq->assoc_idx != ASSOC_IDX_INVALID) { | ||
| 1009 | spin_unlock_bh(&aq->lock); | ||
| 1010 | return -EINVAL; | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | /* trigger the asynchronous association request */ | ||
| 1014 | status = ap_aapq(aq->qid, value); | ||
| 1015 | switch (status.response_code) { | ||
| 1016 | case AP_RESPONSE_NORMAL: | ||
| 1017 | case AP_RESPONSE_STATE_CHANGE_IN_PROGRESS: | ||
| 1018 | aq->sm_state = AP_SM_STATE_ASSOC_WAIT; | ||
| 1019 | aq->assoc_idx = value; | ||
| 1020 | ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL)); | ||
| 1021 | spin_unlock_bh(&aq->lock); | ||
| 1022 | break; | ||
| 1023 | default: | ||
| 1024 | spin_unlock_bh(&aq->lock); | ||
| 1025 | AP_DBF_WARN("%s RC 0x%02x on aapq(0x%02x.%04x)\n", | ||
| 1026 | __func__, status.response_code, | ||
| 1027 | AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); | ||
| 1028 | return -EIO; | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | return count; | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | static DEVICE_ATTR_RW(se_associate); | ||
| 1035 | |||
| 1036 | static struct attribute *ap_queue_dev_sb_attrs[] = { | ||
| 1037 | &dev_attr_se_bind.attr, | ||
| 1038 | &dev_attr_se_associate.attr, | ||
| 1039 | NULL | ||
| 1040 | }; | ||
| 1041 | |||
| 1042 | static struct attribute_group ap_queue_dev_sb_attr_group = { | ||
| 1043 | .attrs = ap_queue_dev_sb_attrs | ||
| 1044 | }; | ||
| 1045 | |||
| 1046 | static const struct attribute_group *ap_queue_dev_sb_attr_groups[] = { | ||
| 1047 | &ap_queue_dev_sb_attr_group, | ||
| 1048 | NULL | ||
| 1049 | }; | ||
| 1050 | |||
| 769 | static void ap_queue_device_release(struct device *dev) | 1051 | static void ap_queue_device_release(struct device *dev) |
| 770 | { | 1052 | { |
| 771 | struct ap_queue *aq = to_ap_queue(dev); | 1053 | struct ap_queue *aq = to_ap_queue(dev); |
| @@ -787,6 +1069,9 @@ struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type) · 15 unmodified lines | |||
| 787 | aq->ap_dev.device.release = ap_queue_device_release; | 1069 | aq->ap_dev.device.release = ap_queue_device_release; |
| 788 | aq->ap_dev.device.type = &ap_queue_type; | 1070 | aq->ap_dev.device.type = &ap_queue_type; |
| 789 | aq->ap_dev.device_type = device_type; | 1071 | aq->ap_dev.device_type = device_type; |
| 1072 | // add optional SE secure binding attributes group | ||
| 1073 | if (ap_sb_available() && is_prot_virt_guest()) | ||
| 1074 | aq->ap_dev.device.groups = ap_queue_dev_sb_attr_groups; | ||
| 790 | aq->qid = qid; | 1075 | aq->qid = qid; |
| 791 | aq->interrupt = false; | 1076 | aq->interrupt = false; |
| 792 | spin_lock_init(&aq->lock); | 1077 | spin_lock_init(&aq->lock); |
| @@ -922,7 +1207,7 @@ void ap_queue_remove(struct ap_queue *aq) · 129 unmodified lines | |||
| 922 | * to the initial value AP_DEV_STATE_UNINITIATED. | 1207 | * to the initial value AP_DEV_STATE_UNINITIATED. |
| 923 | */ | 1208 | */ |
| 924 | spin_lock_bh(&aq->lock); | 1209 | spin_lock_bh(&aq->lock); |
| 925 | ap_zapq(aq->qid); | 1210 | ap_zapq(aq->qid, 0); |
| 926 | aq->dev_state = AP_DEV_STATE_UNINITIATED; | 1211 | aq->dev_state = AP_DEV_STATE_UNINITIATED; |
| 927 | spin_unlock_bh(&aq->lock); | 1212 | spin_unlock_bh(&aq->lock); |
| 928 | } | 1213 | } |
| @@ -933,6 +1218,7 @@ void ap_queue_init_state(struct ap_queue *aq) · 4 unmodified lines | |||
| 933 | aq->dev_state = AP_DEV_STATE_OPERATING; | 1218 | aq->dev_state = AP_DEV_STATE_OPERATING; |
| 934 | aq->sm_state = AP_SM_STATE_RESET_START; | 1219 | aq->sm_state = AP_SM_STATE_RESET_START; |
| 935 | aq->last_err_rc = 0; | 1220 | aq->last_err_rc = 0; |
| 1221 | aq->assoc_idx = ASSOC_IDX_INVALID; | ||
| 936 | ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL)); | 1222 | ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL)); |
| 937 | spin_unlock_bh(&aq->lock); | 1223 | spin_unlock_bh(&aq->lock); |
| 938 | } | 1224 | } |
| @@ -60,14 +60,8 @@ static void vfio_ap_matrix_dev_release(struct device *dev) · 59 unmodified lines | |||
| 60 | kfree(matrix_dev); | 60 | kfree(matrix_dev); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | static int matrix_bus_match(struct device *dev, struct device_driver *drv) | ||
| 64 | { | ||
| 65 | return 1; | ||
| 66 | } | ||
| 67 | |||
| 68 | static struct bus_type matrix_bus = { | 63 | static struct bus_type matrix_bus = { |
| 69 | .name = "matrix", | 64 | .name = "matrix", |
| 70 | .match = &matrix_bus_match, | ||
| 71 | }; | 65 | }; |
| 72 | 66 | ||
| 73 | static struct device_driver matrix_driver = { | 67 | static struct device_driver matrix_driver = { |
| @@ -599,9 +599,9 @@ out_unlock: · 598 unmodified lines | |||
| 599 | static void vfio_ap_matrix_init(struct ap_config_info *info, | 599 | static void vfio_ap_matrix_init(struct ap_config_info *info, |
| 600 | struct ap_matrix *matrix) | 600 | struct ap_matrix *matrix) |
| 601 | { | 601 | { |
| 602 | matrix->apm_max = info->apxa ? info->Na : 63; | 602 | matrix->apm_max = info->apxa ? info->na : 63; |
| 603 | matrix->aqm_max = info->apxa ? info->Nd : 15; | 603 | matrix->aqm_max = info->apxa ? info->nd : 15; |
| 604 | matrix->adm_max = info->apxa ? info->Nd : 15; | 604 | matrix->adm_max = info->apxa ? info->nd : 15; |
| 605 | } | 605 | } |
| 606 | 606 | ||
| 607 | static void vfio_ap_mdev_update_guest_apcb(struct ap_matrix_mdev *matrix_mdev) | 607 | static void vfio_ap_mdev_update_guest_apcb(struct ap_matrix_mdev *matrix_mdev) |
| @@ -1657,7 +1657,7 @@ static int vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q) · 1049 unmodified lines | |||
| 1657 | if (!q) | 1657 | if (!q) |
| 1658 | return 0; | 1658 | return 0; |
| 1659 | retry_zapq: | 1659 | retry_zapq: |
| 1660 | status = ap_zapq(q->apqn); | 1660 | status = ap_zapq(q->apqn, 0); |
| 1661 | q->reset_rc = status.response_code; | 1661 | q->reset_rc = status.response_code; |
| 1662 | switch (status.response_code) { | 1662 | switch (status.response_code) { |
| 1663 | case AP_RESPONSE_NORMAL: | 1663 | case AP_RESPONSE_NORMAL: |
| @@ -2115,8 +2115,8 @@ static void vfio_ap_filter_apid_by_qtype(unsigned long *apm, unsigned long *aqm) · 451 unmodified lines | |||
| 2115 | { | 2115 | { |
| 2116 | bool apid_cleared; | 2116 | bool apid_cleared; |
| 2117 | struct ap_queue_status status; | 2117 | struct ap_queue_status status; |
| 2118 | unsigned long apid, apqi, info; | 2118 | unsigned long apid, apqi; |
| 2119 | int qtype, qtype_mask = 0xff000000; | 2119 | struct ap_tapq_gr2 info; |
| 2120 | 2120 | ||
| 2121 | for_each_set_bit_inv(apid, apm, AP_DEVICES) { | 2121 | for_each_set_bit_inv(apid, apm, AP_DEVICES) { |
| 2122 | apid_cleared = false; | 2122 | apid_cleared = false; |
| @@ -2133,15 +2133,13 @@ static void vfio_ap_filter_apid_by_qtype(unsigned long *apm, unsigned long *aqm) · 10 unmodified lines | |||
| 2133 | case AP_RESPONSE_DECONFIGURED: | 2133 | case AP_RESPONSE_DECONFIGURED: |
| 2134 | case AP_RESPONSE_CHECKSTOPPED: | 2134 | case AP_RESPONSE_CHECKSTOPPED: |
| 2135 | case AP_RESPONSE_BUSY: | 2135 | case AP_RESPONSE_BUSY: |
| 2136 | qtype = info & qtype_mask; | ||
| 2137 | |||
| 2138 | /* | 2136 | /* |
| 2139 | * The vfio_ap device driver only | 2137 | * The vfio_ap device driver only |
| 2140 | * supports CEX4 and newer adapters, so | 2138 | * supports CEX4 and newer adapters, so |
| 2141 | * remove the APID if the adapter is | 2139 | * remove the APID if the adapter is |
| 2142 | * older than a CEX4. | 2140 | * older than a CEX4. |
| 2143 | */ | 2141 | */ |
| 2144 | if (qtype < AP_DEVICE_TYPE_CEX4) { | 2142 | if (info.at < AP_DEVICE_TYPE_CEX4) { |
| 2145 | clear_bit_inv(apid, apm); | 2143 | clear_bit_inv(apid, apm); |
| 2146 | apid_cleared = true; | 2144 | apid_cleared = true; |
| 2147 | } | 2145 | } |
| @@ -159,25 +159,20 @@ static ssize_t ioctlmask_show(struct device *dev, · 158 unmodified lines | |||
| 159 | struct device_attribute *attr, | 159 | struct device_attribute *attr, |
| 160 | char *buf) | 160 | char *buf) |
| 161 | { | 161 | { |
| 162 | int i, rc; | ||
| 163 | struct zcdn_device *zcdndev = to_zcdn_dev(dev); | 162 | struct zcdn_device *zcdndev = to_zcdn_dev(dev); |
| 163 | int i, n; | ||
| 164 | 164 | ||
| 165 | if (mutex_lock_interruptible(&ap_perms_mutex)) | 165 | if (mutex_lock_interruptible(&ap_perms_mutex)) |
| 166 | return -ERESTARTSYS; | 166 | return -ERESTARTSYS; |
| 167 | 167 | ||
| 168 | buf[0] = '0'; | 168 | n = sysfs_emit(buf, "0x"); |
| 169 | buf[1] = 'x'; | ||
| 170 | for (i = 0; i < sizeof(zcdndev->perms.ioctlm) / sizeof(long); i++) | 169 | for (i = 0; i < sizeof(zcdndev->perms.ioctlm) / sizeof(long); i++) |
| 171 | snprintf(buf + 2 + 2 * i * sizeof(long), | 170 | n += sysfs_emit_at(buf, n, "%016lx", zcdndev->perms.ioctlm[i]); |
| 172 | PAGE_SIZE - 2 - 2 * i * sizeof(long), | 171 | n += sysfs_emit_at(buf, n, "\n"); |
| 173 | "%016lx", zcdndev->perms.ioctlm[i]); | ||
| 174 | buf[2 + 2 * i * sizeof(long)] = '\n'; | ||
| 175 | buf[2 + 2 * i * sizeof(long) + 1] = '\0'; | ||
| 176 | rc = 2 + 2 * i * sizeof(long) + 1; | ||
| 177 | 172 | ||
| 178 | mutex_unlock(&ap_perms_mutex); | 173 | mutex_unlock(&ap_perms_mutex); |
| 179 | 174 | ||
| 180 | return rc; | 175 | return n; |
| 181 | } | 176 | } |
| 182 | 177 | ||
| 183 | static ssize_t ioctlmask_store(struct device *dev, | 178 | static ssize_t ioctlmask_store(struct device *dev, |
| @@ -201,25 +196,20 @@ static ssize_t apmask_show(struct device *dev, · 17 unmodified lines | |||
| 201 | struct device_attribute *attr, | 196 | struct device_attribute *attr, |
| 202 | char *buf) | 197 | char *buf) |
| 203 | { | 198 | { |
| 204 | int i, rc; | ||
| 205 | struct zcdn_device *zcdndev = to_zcdn_dev(dev); | 199 | struct zcdn_device *zcdndev = to_zcdn_dev(dev); |
| 200 | int i, n; | ||
| 206 | 201 | ||
| 207 | if (mutex_lock_interruptible(&ap_perms_mutex)) | 202 | if (mutex_lock_interruptible(&ap_perms_mutex)) |
| 208 | return -ERESTARTSYS; | 203 | return -ERESTARTSYS; |
| 209 | 204 | ||
| 210 | buf[0] = '0'; | 205 | n = sysfs_emit(buf, "0x"); |
| 211 | buf[1] = 'x'; | ||
| 212 | for (i = 0; i < sizeof(zcdndev->perms.apm) / sizeof(long); i++) | 206 | for (i = 0; i < sizeof(zcdndev->perms.apm) / sizeof(long); i++) |
| 213 | snprintf(buf + 2 + 2 * i * sizeof(long), | 207 | n += sysfs_emit_at(buf, n, "%016lx", zcdndev->perms.apm[i]); |
| 214 | PAGE_SIZE - 2 - 2 * i * sizeof(long), | 208 | n += sysfs_emit_at(buf, n, "\n"); |
| 215 | "%016lx", zcdndev->perms.apm[i]); | ||
| 216 | buf[2 + 2 * i * sizeof(long)] = '\n'; | ||
| 217 | buf[2 + 2 * i * sizeof(long) + 1] = '\0'; | ||
| 218 | rc = 2 + 2 * i * sizeof(long) + 1; | ||
| 219 | 209 | ||
| 220 | mutex_unlock(&ap_perms_mutex); | 210 | mutex_unlock(&ap_perms_mutex); |
| 221 | 211 | ||
| 222 | return rc; | 212 | return n; |
| 223 | } | 213 | } |
| 224 | 214 | ||
| 225 | static ssize_t apmask_store(struct device *dev, | 215 | static ssize_t apmask_store(struct device *dev, |
| @@ -243,25 +233,20 @@ static ssize_t aqmask_show(struct device *dev, · 17 unmodified lines | |||
| 243 | struct device_attribute *attr, | 233 | struct device_attribute *attr, |
| 244 | char *buf) | 234 | char *buf) |
| 245 | { | 235 | { |
| 246 | int i, rc; | ||
| 247 | struct zcdn_device *zcdndev = to_zcdn_dev(dev); | 236 | struct zcdn_device *zcdndev = to_zcdn_dev(dev); |
| 237 | int i, n; | ||
| 248 | 238 | ||
| 249 | if (mutex_lock_interruptible(&ap_perms_mutex)) | 239 | if (mutex_lock_interruptible(&ap_perms_mutex)) |
| 250 | return -ERESTARTSYS; | 240 | return -ERESTARTSYS; |
| 251 | 241 | ||
| 252 | buf[0] = '0'; | 242 | n = sysfs_emit(buf, "0x"); |
| 253 | buf[1] = 'x'; | ||
| 254 | for (i = 0; i < sizeof(zcdndev->perms.aqm) / sizeof(long); i++) | 243 | for (i = 0; i < sizeof(zcdndev->perms.aqm) / sizeof(long); i++) |
| 255 | snprintf(buf + 2 + 2 * i * sizeof(long), | 244 | n += sysfs_emit_at(buf, n, "%016lx", zcdndev->perms.aqm[i]); |
| 256 | PAGE_SIZE - 2 - 2 * i * sizeof(long), | 245 | n += sysfs_emit_at(buf, n, "\n"); |
| 257 | "%016lx", zcdndev->perms.aqm[i]); | ||
| 258 | buf[2 + 2 * i * sizeof(long)] = '\n'; | ||
| 259 | buf[2 + 2 * i * sizeof(long) + 1] = '\0'; | ||
| 260 | rc = 2 + 2 * i * sizeof(long) + 1; | ||
| 261 | 246 | ||
| 262 | mutex_unlock(&ap_perms_mutex); | 247 | mutex_unlock(&ap_perms_mutex); |
| 263 | 248 | ||
| 264 | return rc; | 249 | return n; |
| 265 | } | 250 | } |
| 266 | 251 | ||
| 267 | static ssize_t aqmask_store(struct device *dev, | 252 | static ssize_t aqmask_store(struct device *dev, |
| @@ -285,25 +270,20 @@ static ssize_t admask_show(struct device *dev, · 17 unmodified lines | |||
| 285 | struct device_attribute *attr, | 270 | struct device_attribute *attr, |
| 286 | char *buf) | 271 | char *buf) |
| 287 | { | 272 | { |
| 288 | int i, rc; | ||
| 289 | struct zcdn_device *zcdndev = to_zcdn_dev(dev); | 273 | struct zcdn_device *zcdndev = to_zcdn_dev(dev); |
| 274 | int i, n; | ||
| 290 | 275 | ||
| 291 | if (mutex_lock_interruptible(&ap_perms_mutex)) | 276 | if (mutex_lock_interruptible(&ap_perms_mutex)) |
| 292 | return -ERESTARTSYS; | 277 | return -ERESTARTSYS; |
| 293 | 278 | ||
| 294 | buf[0] = '0'; | 279 | n = sysfs_emit(buf, "0x"); |
| 295 | buf[1] = 'x'; | ||
| 296 | for (i = 0; i < sizeof(zcdndev->perms.adm) / sizeof(long); i++) | 280 | for (i = 0; i < sizeof(zcdndev->perms.adm) / sizeof(long); i++) |
| 297 | snprintf(buf + 2 + 2 * i * sizeof(long), | 281 | n += sysfs_emit_at(buf, n, "%016lx", zcdndev->perms.adm[i]); |
| 298 | PAGE_SIZE - 2 - 2 * i * sizeof(long), | 282 | n += sysfs_emit_at(buf, n, "\n"); |
| 299 | "%016lx", zcdndev->perms.adm[i]); | ||
| 300 | buf[2 + 2 * i * sizeof(long)] = '\n'; | ||
| 301 | buf[2 + 2 * i * sizeof(long) + 1] = '\0'; | ||
| 302 | rc = 2 + 2 * i * sizeof(long) + 1; | ||
| 303 | 283 | ||
| 304 | mutex_unlock(&ap_perms_mutex); | 284 | mutex_unlock(&ap_perms_mutex); |
| 305 | 285 | ||
| 306 | return rc; | 286 | return n; |
| 307 | } | 287 | } |
| 308 | 288 | ||
| 309 | static ssize_t admask_store(struct device *dev, | 289 | static ssize_t admask_store(struct device *dev, |
| @@ -41,7 +41,7 @@ static ssize_t type_show(struct device *dev, · 40 unmodified lines | |||
| 41 | { | 41 | { |
| 42 | struct zcrypt_card *zc = dev_get_drvdata(dev); | 42 | struct zcrypt_card *zc = dev_get_drvdata(dev); |
| 43 | 43 | ||
| 44 | return scnprintf(buf, PAGE_SIZE, "%s\n", zc->type_string); | 44 | return sysfs_emit(buf, "%s\n", zc->type_string); |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | static DEVICE_ATTR_RO(type); | 47 | static DEVICE_ATTR_RO(type); |
| @@ -54,7 +54,7 @@ static ssize_t online_show(struct device *dev, · 6 unmodified lines | |||
| 54 | struct ap_card *ac = to_ap_card(dev); | 54 | struct ap_card *ac = to_ap_card(dev); |
| 55 | int online = ac->config && zc->online ? 1 : 0; | 55 | int online = ac->config && zc->online ? 1 : 0; |
| 56 | 56 | ||
| 57 | return scnprintf(buf, PAGE_SIZE, "%d\n", online); | 57 | return sysfs_emit(buf, "%d\n", online); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | static ssize_t online_store(struct device *dev, | 60 | static ssize_t online_store(struct device *dev, |
| @@ -118,7 +118,7 @@ static ssize_t load_show(struct device *dev, · 57 unmodified lines | |||
| 118 | { | 118 | { |
| 119 | struct zcrypt_card *zc = dev_get_drvdata(dev); | 119 | struct zcrypt_card *zc = dev_get_drvdata(dev); |
| 120 | 120 | ||
| 121 | return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&zc->load)); | 121 | return sysfs_emit(buf, "%d\n", atomic_read(&zc->load)); |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | static DEVICE_ATTR_RO(load); | 124 | static DEVICE_ATTR_RO(load); |
| @@ -89,10 +89,7 @@ struct cca_pvt_ext_crt_sec { · 88 unmodified lines | |||
| 89 | #define CCA_PVT_EXT_CRT_SEC_FMT_CL 0x40 | 89 | #define CCA_PVT_EXT_CRT_SEC_FMT_CL 0x40 |
| 90 | 90 | ||
| 91 | /** | 91 | /** |
| 92 | * Set up private key fields of a type6 MEX message. The _pad variant | 92 | * Set up private key fields of a type6 MEX message. |
| 93 | * strips leading zeroes from the b_key. | ||
| 94 | * Note that all numerics in the key token are big-endian, | ||
| 95 | * while the entries in the key block header are little-endian. | ||
| 96 | * | 93 | * |
| 97 | * @mex: pointer to user input data | 94 | * @mex: pointer to user input data |
| 98 | * @p: pointer to memory area for the key | 95 | * @p: pointer to memory area for the key |
| @@ -111,10 +108,9 @@ static inline int zcrypt_type6_mex_key_en(struct ica_rsa_modexpo *mex, void *p) · 12 unmodified lines | |||
| 111 | struct t6_keyblock_hdr t6_hdr; | 108 | struct t6_keyblock_hdr t6_hdr; |
| 112 | struct cca_token_hdr pubhdr; | 109 | struct cca_token_hdr pubhdr; |
| 113 | struct cca_public_sec pubsec; | 110 | struct cca_public_sec pubsec; |
| 114 | char exponent[0]; | 111 | char exponent[]; |
| 115 | } __packed *key = p; | 112 | } __packed *key = p; |
| 116 | unsigned char *temp; | 113 | unsigned char *ptr; |
| 117 | int i; | ||
| 118 | 114 | ||
| 119 | /* | 115 | /* |
| 120 | * The inputdatalength was a selection criteria in the dispatching | 116 | * The inputdatalength was a selection criteria in the dispatching |
| @@ -131,37 +127,29 @@ static inline int zcrypt_type6_mex_key_en(struct ica_rsa_modexpo *mex, void *p) · 10 unmodified lines | |||
| 131 | key->pubsec = static_pub_sec; | 127 | key->pubsec = static_pub_sec; |
| 132 | 128 | ||
| 133 | /* key parameter block */ | 129 | /* key parameter block */ |
| 134 | temp = key->exponent; | 130 | ptr = key->exponent; |
| 135 | if (copy_from_user(temp, mex->b_key, mex->inputdatalength)) | 131 | if (copy_from_user(ptr, mex->b_key, mex->inputdatalength)) |
| 136 | return -EFAULT; | 132 | return -EFAULT; |
| 137 | /* Strip leading zeroes from b_key. */ | 133 | ptr += mex->inputdatalength; |
| 138 | for (i = 0; i < mex->inputdatalength; i++) | ||
| 139 | if (temp[i]) | ||
| 140 | break; | ||
| 141 | if (i >= mex->inputdatalength) | ||
| 142 | return -EINVAL; | ||
| 143 | memmove(temp, temp + i, mex->inputdatalength - i); | ||
| 144 | temp += mex->inputdatalength - i; | ||
| 145 | /* modulus */ | 134 | /* modulus */ |
| 146 | if (copy_from_user(temp, mex->n_modulus, mex->inputdatalength)) | 135 | if (copy_from_user(ptr, mex->n_modulus, mex->inputdatalength)) |
| 147 | return -EFAULT; | 136 | return -EFAULT; |
| 148 | 137 | ||
| 149 | key->pubsec.modulus_bit_len = 8 * mex->inputdatalength; | 138 | key->pubsec.modulus_bit_len = 8 * mex->inputdatalength; |
| 150 | key->pubsec.modulus_byte_len = mex->inputdatalength; | 139 | key->pubsec.modulus_byte_len = mex->inputdatalength; |
| 151 | key->pubsec.exponent_len = mex->inputdatalength - i; | 140 | key->pubsec.exponent_len = mex->inputdatalength; |
| 152 | key->pubsec.section_length = sizeof(key->pubsec) + | 141 | key->pubsec.section_length = sizeof(key->pubsec) + |
| 153 | 2 * mex->inputdatalength - i; | 142 | 2 * mex->inputdatalength; |
| 154 | key->pubhdr.token_length = | 143 | key->pubhdr.token_length = |
| 155 | key->pubsec.section_length + sizeof(key->pubhdr); | 144 | key->pubsec.section_length + sizeof(key->pubhdr); |
| 156 | key->t6_hdr.ulen = key->pubhdr.token_length + 4; | 145 | key->t6_hdr.ulen = key->pubhdr.token_length + 4; |
| 157 | key->t6_hdr.blen = key->pubhdr.token_length + 6; | 146 | key->t6_hdr.blen = key->pubhdr.token_length + 6; |
| 158 | return sizeof(*key) + 2 * mex->inputdatalength - i; | 147 | |
| 148 | return sizeof(*key) + 2 * mex->inputdatalength; | ||
| 159 | } | 149 | } |
| 160 | 150 | ||
| 161 | /** | 151 | /** |
| 162 | * Set up private key fields of a type6 CRT message. | 152 | * Set up private key fields of a type6 CRT message. |
| 163 | * Note that all numerics in the key token are big-endian, | ||
| 164 | * while the entries in the key block header are little-endian. | ||
| 165 | * | 153 | * |
| 166 | * @mex: pointer to user input data | 154 | * @mex: pointer to user input data |
| 167 | * @p: pointer to memory area for the key | 155 | * @p: pointer to memory area for the key |
| @@ -180,7 +168,7 @@ static inline int zcrypt_type6_crt_key(struct ica_rsa_modexpo_crt *crt, void *p) · 12 unmodified lines | |||
| 180 | struct t6_keyblock_hdr t6_hdr; | 168 | struct t6_keyblock_hdr t6_hdr; |
| 181 | struct cca_token_hdr token; | 169 | struct cca_token_hdr token; |
| 182 | struct cca_pvt_ext_crt_sec pvt; | 170 | struct cca_pvt_ext_crt_sec pvt; |
| 183 | char key_parts[0]; | 171 | char key_parts[]; |
| 184 | } __packed *key = p; | 172 | } __packed *key = p; |
| 185 | struct cca_public_sec *pub; | 173 | struct cca_public_sec *pub; |
| 186 | int short_len, long_len, pad_len, key_len, size; | 174 | int short_len, long_len, pad_len, key_len, size; |
| @@ -242,6 +230,7 @@ static inline int zcrypt_type6_crt_key(struct ica_rsa_modexpo_crt *crt, void *p) · 55 unmodified lines | |||
| 242 | * used. | 230 | * used. |
| 243 | */ | 231 | */ |
| 244 | memcpy((char *)(pub + 1), pk_exponent, 3); | 232 | memcpy((char *)(pub + 1), pk_exponent, 3); |
| 233 | |||
| 245 | return size; | 234 | return size; |
| 246 | } | 235 | } |
| 247 | 236 | ||
| @@ -450,18 +450,18 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize, · 449 unmodified lines | |||
| 450 | char rule_array[8]; | 450 | char rule_array[8]; |
| 451 | struct lv1 { | 451 | struct lv1 { |
| 452 | u16 len; | 452 | u16 len; |
| 453 | u8 clrkey[0]; | 453 | u8 clrkey[]; |
| 454 | } lv1; | 454 | } lv1; |
| 455 | struct lv2 { | 455 | /* followed by struct lv2 */ |
| 456 | u16 len; | ||
| 457 | struct keyid { | ||
| 458 | u16 len; | ||
| 459 | u16 attr; | ||
| 460 | u8 data[SECKEYBLOBSIZE]; | ||
| 461 | } keyid; | ||
| 462 | } lv2; | ||
| 463 | } __packed * preqparm; | 456 | } __packed * preqparm; |
| 464 | struct lv2 *plv2; | 457 | struct lv2 { |
| 458 | u16 len; | ||
| 459 | struct keyid { | ||
| 460 | u16 len; | ||
| 461 | u16 attr; | ||
| 462 | u8 data[SECKEYBLOBSIZE]; | ||
| 463 | } keyid; | ||
| 464 | } __packed * plv2; | ||
| 465 | struct cmrepparm { | 465 | struct cmrepparm { |
| 466 | u8 subfunc_code[2]; | 466 | u8 subfunc_code[2]; |
| 467 | u16 rule_array_len; | 467 | u16 rule_array_len; |
| @@ -512,11 +512,11 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize, · 44 unmodified lines | |||
| 512 | } | 512 | } |
| 513 | preqparm->lv1.len = sizeof(struct lv1) + keysize; | 513 | preqparm->lv1.len = sizeof(struct lv1) + keysize; |
| 514 | memcpy(preqparm->lv1.clrkey, clrkey, keysize); | 514 | memcpy(preqparm->lv1.clrkey, clrkey, keysize); |
| 515 | plv2 = (struct lv2 *)(((u8 *)&preqparm->lv2) + keysize); | 515 | plv2 = (struct lv2 *)(((u8 *)preqparm) + sizeof(*preqparm) + keysize); |
| 516 | plv2->len = sizeof(struct lv2); | 516 | plv2->len = sizeof(struct lv2); |
| 517 | plv2->keyid.len = sizeof(struct keyid); | 517 | plv2->keyid.len = sizeof(struct keyid); |
| 518 | plv2->keyid.attr = 0x30; | 518 | plv2->keyid.attr = 0x30; |
| 519 | preqcblk->req_parml = sizeof(struct cmreqparm) + keysize; | 519 | preqcblk->req_parml = sizeof(*preqparm) + keysize + sizeof(*plv2); |
| 520 | 520 | ||
| 521 | /* fill xcrb struct */ | 521 | /* fill xcrb struct */ |
| 522 | prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); | 522 | prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); |
| @@ -761,22 +761,22 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags, · 238 unmodified lines | |||
| 761 | u16 key_name_2_len; | 761 | u16 key_name_2_len; |
| 762 | u16 user_data_1_len; | 762 | u16 user_data_1_len; |
| 763 | u16 user_data_2_len; | 763 | u16 user_data_2_len; |
| 764 | u8 key_name_1[0]; | 764 | /* u8 key_name_1[]; */ |
| 765 | u8 key_name_2[0]; | 765 | /* u8 key_name_2[]; */ |
| 766 | u8 user_data_1[0]; | 766 | /* u8 user_data_1[]; */ |
| 767 | u8 user_data_2[0]; | 767 | /* u8 user_data_2[]; */ |
| 768 | } vud; | 768 | } vud; |
| 769 | struct { | 769 | struct { |
| 770 | u16 len; | 770 | u16 len; |
| 771 | struct { | 771 | struct { |
| 772 | u16 len; | 772 | u16 len; |
| 773 | u16 flag; | 773 | u16 flag; |
| 774 | u8 kek_id_1[0]; | 774 | /* u8 kek_id_1[]; */ |
| 775 | } tlv1; | 775 | } tlv1; |
| 776 | struct { | 776 | struct { |
| 777 | u16 len; | 777 | u16 len; |
| 778 | u16 flag; | 778 | u16 flag; |
| 779 | u8 kek_id_2[0]; | 779 | /* u8 kek_id_2[]; */ |
| 780 | } tlv2; | 780 | } tlv2; |
| 781 | struct { | 781 | struct { |
| 782 | u16 len; | 782 | u16 len; |
| @@ -786,17 +786,17 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags, · 3 unmodified lines | |||
| 786 | struct { | 786 | struct { |
| 787 | u16 len; | 787 | u16 len; |
| 788 | u16 flag; | 788 | u16 flag; |
| 789 | u8 gen_key_id_1_label[0]; | 789 | /* u8 gen_key_id_1_label[]; */ |
| 790 | } tlv4; | 790 | } tlv4; |
| 791 | struct { | 791 | struct { |
| 792 | u16 len; | 792 | u16 len; |
| 793 | u16 flag; | 793 | u16 flag; |
| 794 | u8 gen_key_id_2[0]; | 794 | /* u8 gen_key_id_2[]; */ |
| 795 | } tlv5; | 795 | } tlv5; |
| 796 | struct { | 796 | struct { |
| 797 | u16 len; | 797 | u16 len; |
| 798 | u16 flag; | 798 | u16 flag; |
| 799 | u8 gen_key_id_2_label[0]; | 799 | /* u8 gen_key_id_2_label[]; */ |
| 800 | } tlv6; | 800 | } tlv6; |
| 801 | } kb; | 801 | } kb; |
| 802 | } __packed * preqparm; | 802 | } __packed * preqparm; |
| @@ -811,7 +811,7 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags, · 8 unmodified lines | |||
| 811 | struct { | 811 | struct { |
| 812 | u16 len; | 812 | u16 len; |
| 813 | u16 flag; | 813 | u16 flag; |
| 814 | u8 gen_key[0]; /* 120-136 bytes */ | 814 | u8 gen_key[]; /* 120-136 bytes */ |
| 815 | } tlv1; | 815 | } tlv1; |
| 816 | } kb; | 816 | } kb; |
| 817 | } __packed * prepparm; | 817 | } __packed * prepparm; |
| @@ -955,7 +955,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain, · 137 unmodified lines | |||
| 955 | struct rule_array_block { | 955 | struct rule_array_block { |
| 956 | u8 subfunc_code[2]; | 956 | u8 subfunc_code[2]; |
| 957 | u16 rule_array_len; | 957 | u16 rule_array_len; |
| 958 | char rule_array[0]; | 958 | char rule_array[]; |
| 959 | } __packed * preq_ra_block; | 959 | } __packed * preq_ra_block; |
| 960 | struct vud_block { | 960 | struct vud_block { |
| 961 | u16 len; | 961 | u16 len; |
| @@ -967,7 +967,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain, · 5 unmodified lines | |||
| 967 | struct { | 967 | struct { |
| 968 | u16 len; | 968 | u16 len; |
| 969 | u16 flag; /* 0x0063 */ | 969 | u16 flag; /* 0x0063 */ |
| 970 | u8 clr_key[0]; /* clear key value bytes */ | 970 | u8 clr_key[]; /* clear key value bytes */ |
| 971 | } tlv2; | 971 | } tlv2; |
| 972 | } __packed * preq_vud_block; | 972 | } __packed * preq_vud_block; |
| 973 | struct key_block { | 973 | struct key_block { |
| @@ -975,7 +975,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain, · 1 unmodified line | |||
| 975 | struct { | 975 | struct { |
| 976 | u16 len; | 976 | u16 len; |
| 977 | u16 flag; /* 0x0030 */ | 977 | u16 flag; /* 0x0030 */ |
| 978 | u8 key_token[0]; /* key skeleton */ | 978 | u8 key_token[]; /* key skeleton */ |
| 979 | } tlv1; | 979 | } tlv1; |
| 980 | } __packed * preq_key_block; | 980 | } __packed * preq_key_block; |
| 981 | struct iprepparm { | 981 | struct iprepparm { |
| @@ -989,7 +989,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain, · 7 unmodified lines | |||
| 989 | struct { | 989 | struct { |
| 990 | u16 len; | 990 | u16 len; |
| 991 | u16 flag; /* 0x0030 */ | 991 | u16 flag; /* 0x0030 */ |
| 992 | u8 key_token[0]; /* key token */ | 992 | u8 key_token[]; /* key token */ |
| 993 | } tlv1; | 993 | } tlv1; |
| 994 | } kb; | 994 | } kb; |
| 995 | } __packed * prepparm; | 995 | } __packed * prepparm; |
| @@ -1201,7 +1201,7 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey, · 205 unmodified lines | |||
| 1201 | u16 len; | 1201 | u16 len; |
| 1202 | u16 cca_key_token_len; | 1202 | u16 cca_key_token_len; |
| 1203 | u16 cca_key_token_flags; | 1203 | u16 cca_key_token_flags; |
| 1204 | u8 cca_key_token[0]; // 64 or more | 1204 | u8 cca_key_token[]; /* 64 or more */ |
| 1205 | } kb; | 1205 | } kb; |
| 1206 | } __packed * preqparm; | 1206 | } __packed * preqparm; |
| 1207 | struct aurepparm { | 1207 | struct aurepparm { |
| @@ -1370,7 +1370,7 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key, · 162 unmodified lines | |||
| 1370 | u16 len; | 1370 | u16 len; |
| 1371 | u16 cca_key_token_len; | 1371 | u16 cca_key_token_len; |
| 1372 | u16 cca_key_token_flags; | 1372 | u16 cca_key_token_flags; |
| 1373 | u8 cca_key_token[0]; | 1373 | u8 cca_key_token[]; |
| 1374 | } kb; | 1374 | } kb; |
| 1375 | } __packed * preqparm; | 1375 | } __packed * preqparm; |
| 1376 | struct aurepparm { | 1376 | struct aurepparm { |
| @@ -1387,17 +1387,15 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key, · 10 unmodified lines | |||
| 1387 | u8 form; | 1387 | u8 form; |
| 1388 | u8 pad1[3]; | 1388 | u8 pad1[3]; |
| 1389 | u16 keylen; | 1389 | u16 keylen; |
| 1390 | u8 key[0]; /* the key (keylen bytes) */ | 1390 | u8 key[]; /* the key (keylen bytes) */ |
| 1391 | u16 keyattrlen; | 1391 | /* u16 keyattrlen; */ |
| 1392 | u8 keyattr[32]; | 1392 | /* u8 keyattr[32]; */ |
| 1393 | u8 pad2[1]; | 1393 | /* u8 pad2[1]; */ |
| 1394 | u8 vptype; | 1394 | /* u8 vptype; */ |
| 1395 | u8 vp[32]; /* verification pattern */ | 1395 | /* u8 vp[32]; verification pattern */ |
| 1396 | } ckb; | 1396 | } ckb; |
| 1397 | } vud; | 1397 | } vud; |
| 1398 | struct { | 1398 | /* followed by a key block */ |
| 1399 | u16 len; | ||
| 1400 | } kb; | ||
| 1401 | } __packed * prepparm; | 1399 | } __packed * prepparm; |
| 1402 | int keylen = ((struct eccprivkeytoken *)key)->len; | 1400 | int keylen = ((struct eccprivkeytoken *)key)->len; |
| 1403 | 1401 | ||
| @@ -1525,7 +1523,7 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain, · 121 unmodified lines | |||
| 1525 | size_t parmbsize = sizeof(struct fqreqparm); | 1523 | size_t parmbsize = sizeof(struct fqreqparm); |
| 1526 | struct fqrepparm { | 1524 | struct fqrepparm { |
| 1527 | u8 subfunc_code[2]; | 1525 | u8 subfunc_code[2]; |
| 1528 | u8 lvdata[0]; | 1526 | u8 lvdata[]; |
| 1529 | } __packed * prepparm; | 1527 | } __packed * prepparm; |
| 1530 | 1528 | ||
| 1531 | /* get already prepared memory for 2 cprbs with param block each */ | 1529 | /* get already prepared memory for 2 cprbs with param block each */ |
| @@ -75,7 +75,7 @@ static ssize_t cca_serialnr_show(struct device *dev, · 74 unmodified lines | |||
| 75 | if (ap_domain_index >= 0) | 75 | if (ap_domain_index >= 0) |
| 76 | cca_get_info(ac->id, ap_domain_index, &ci, zc->online); | 76 | cca_get_info(ac->id, ap_domain_index, &ci, zc->online); |
| 77 | 77 | ||
| 78 | return scnprintf(buf, PAGE_SIZE, "%s\n", ci.serial); | 78 | return sysfs_emit(buf, "%s\n", ci.serial); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | static struct device_attribute dev_attr_cca_serialnr = | 81 | static struct device_attribute dev_attr_cca_serialnr = |
| @@ -110,51 +110,46 @@ static ssize_t cca_mkvps_show(struct device *dev, · 28 unmodified lines | |||
| 110 | &ci, zq->online); | 110 | &ci, zq->online); |
| 111 | 111 | ||
| 112 | if (ci.new_aes_mk_state >= '1' && ci.new_aes_mk_state <= '3') | 112 | if (ci.new_aes_mk_state >= '1' && ci.new_aes_mk_state <= '3') |
| 113 | n = scnprintf(buf, PAGE_SIZE, "AES NEW: %s 0x%016llx\n", | 113 | n = sysfs_emit(buf, "AES NEW: %s 0x%016llx\n", |
| 114 | new_state[ci.new_aes_mk_state - '1'], | 114 | new_state[ci.new_aes_mk_state - '1'], |
| 115 | ci.new_aes_mkvp); | 115 | ci.new_aes_mkvp); |
| 116 | else | 116 | else |
| 117 | n = scnprintf(buf, PAGE_SIZE, "AES NEW: - -\n"); | 117 | n = sysfs_emit(buf, "AES NEW: - -\n"); |
| 118 | 118 | ||
| 119 | if (ci.cur_aes_mk_state >= '1' && ci.cur_aes_mk_state <= '2') | 119 | if (ci.cur_aes_mk_state >= '1' && ci.cur_aes_mk_state <= '2') |
| 120 | n += scnprintf(buf + n, PAGE_SIZE - n, | 120 | n += sysfs_emit_at(buf, n, "AES CUR: %s 0x%016llx\n", |
| 121 | "AES CUR: %s 0x%016llx\n", | 121 | cao_state[ci.cur_aes_mk_state - '1'], |
| 122 | cao_state[ci.cur_aes_mk_state - '1'], | 122 | ci.cur_aes_mkvp); |
| 123 | ci.cur_aes_mkvp); | ||
| 124 | else | 123 | else |
| 125 | n += scnprintf(buf + n, PAGE_SIZE - n, "AES CUR: - -\n"); | 124 | n += sysfs_emit_at(buf, n, "AES CUR: - -\n"); |
| 126 | 125 | ||
| 127 | if (ci.old_aes_mk_state >= '1' && ci.old_aes_mk_state <= '2') | 126 | if (ci.old_aes_mk_state >= '1' && ci.old_aes_mk_state <= '2') |
| 128 | n += scnprintf(buf + n, PAGE_SIZE - n, | 127 | n += sysfs_emit_at(buf, n, "AES OLD: %s 0x%016llx\n", |
| 129 | "AES OLD: %s 0x%016llx\n", | 128 | cao_state[ci.old_aes_mk_state - '1'], |
| 130 | cao_state[ci.old_aes_mk_state - '1'], | 129 | ci.old_aes_mkvp); |
| 131 | ci.old_aes_mkvp); | ||
| 132 | else | 130 | else |
| 133 | n += scnprintf(buf + n, PAGE_SIZE - n, "AES OLD: - -\n"); | 131 | n += sysfs_emit_at(buf, n, "AES OLD: - -\n"); |
| 134 | 132 | ||
| 135 | if (ci.new_apka_mk_state >= '1' && ci.new_apka_mk_state <= '3') | 133 | if (ci.new_apka_mk_state >= '1' && ci.new_apka_mk_state <= '3') |
| 136 | n += scnprintf(buf + n, PAGE_SIZE - n, | 134 | n += sysfs_emit_at(buf, n, "APKA NEW: %s 0x%016llx\n", |
| 137 | "APKA NEW: %s 0x%016llx\n", | 135 | new_state[ci.new_apka_mk_state - '1'], |
| 138 | new_state[ci.new_apka_mk_state - '1'], | 136 | ci.new_apka_mkvp); |
| 139 | ci.new_apka_mkvp); | ||
| 140 | else | 137 | else |
| 141 | n += scnprintf(buf + n, PAGE_SIZE - n, "APKA NEW: - -\n"); | 138 | n += sysfs_emit_at(buf, n, "APKA NEW: - -\n"); |
| 142 | 139 | ||
| 143 | if (ci.cur_apka_mk_state >= '1' && ci.cur_apka_mk_state <= '2') | 140 | if (ci.cur_apka_mk_state >= '1' && ci.cur_apka_mk_state <= '2') |
| 144 | n += scnprintf(buf + n, PAGE_SIZE - n, | 141 | n += sysfs_emit_at(buf, n, "APKA CUR: %s 0x%016llx\n", |
| 145 | "APKA CUR: %s 0x%016llx\n", | 142 | cao_state[ci.cur_apka_mk_state - '1'], |
| 146 | cao_state[ci.cur_apka_mk_state - '1'], | 143 | ci.cur_apka_mkvp); |
| 147 | ci.cur_apka_mkvp); | ||
| 148 | else | 144 | else |
| 149 | n += scnprintf(buf + n, PAGE_SIZE - n, "APKA CUR: - -\n"); | 145 | n += sysfs_emit_at(buf, n, "APKA CUR: - -\n"); |
| 150 | 146 | ||
| 151 | if (ci.old_apka_mk_state >= '1' && ci.old_apka_mk_state <= '2') | 147 | if (ci.old_apka_mk_state >= '1' && ci.old_apka_mk_state <= '2') |
| 152 | n += scnprintf(buf + n, PAGE_SIZE - n, | 148 | n += sysfs_emit_at(buf, n, "APKA OLD: %s 0x%016llx\n", |
| 153 | "APKA OLD: %s 0x%016llx\n", | 149 | cao_state[ci.old_apka_mk_state - '1'], |
| 154 | cao_state[ci.old_apka_mk_state - '1'], | 150 | ci.old_apka_mkvp); |
| 155 | ci.old_apka_mkvp); | ||
| 156 | else | 151 | else |
| 157 | n += scnprintf(buf + n, PAGE_SIZE - n, "APKA OLD: - -\n"); | 152 | n += sysfs_emit_at(buf, n, "APKA OLD: - -\n"); |
| 158 | 153 | ||
| 159 | return n; | 154 | return n; |
| 160 | } | 155 | } |
| @@ -181,7 +176,7 @@ static const struct attribute_group cca_queue_attr_grp = { · 20 unmodified lines | |||
| 181 | static int zcrypt_cex2c_rng_supported(struct ap_queue *aq) | 176 | static int zcrypt_cex2c_rng_supported(struct ap_queue *aq) |
| 182 | { | 177 | { |
| 183 | struct ap_message ap_msg; | 178 | struct ap_message ap_msg; |
| 184 | unsigned long long psmid; | 179 | unsigned long psmid; |
| 185 | unsigned int domain; | 180 | unsigned int domain; |
| 186 | struct { | 181 | struct { |
| 187 | struct type86_hdr hdr; | 182 | struct type86_hdr hdr; |
| @@ -203,21 +198,22 @@ static int zcrypt_cex2c_rng_supported(struct ap_queue *aq) · 15 unmodified lines | |||
| 203 | ap_msg.msg = (void *)get_zeroed_page(GFP_KERNEL); | 198 | ap_msg.msg = (void *)get_zeroed_page(GFP_KERNEL); |
| 204 | if (!ap_msg.msg) | 199 | if (!ap_msg.msg) |
| 205 | return -ENOMEM; | 200 | return -ENOMEM; |
| 201 | ap_msg.bufsize = PAGE_SIZE; | ||
| 206 | 202 | ||
| 207 | rng_type6cprb_msgx(&ap_msg, 4, &domain); | 203 | rng_type6cprb_msgx(&ap_msg, 4, &domain); |
| 208 | 204 | ||
| 209 | msg = ap_msg.msg; | 205 | msg = ap_msg.msg; |
| 210 | msg->cprbx.domain = AP_QID_QUEUE(aq->qid); | 206 | msg->cprbx.domain = AP_QID_QUEUE(aq->qid); |
| 211 | 207 | ||
| 212 | rc = ap_send(aq->qid, 0x0102030405060708ULL, ap_msg.msg, ap_msg.len); | 208 | rc = ap_send(aq->qid, 0x0102030405060708UL, ap_msg.msg, ap_msg.len); |
| 213 | if (rc) | 209 | if (rc) |
| 214 | goto out_free; | 210 | goto out_free; |
| 215 | 211 | ||
| 216 | /* Wait for the test message to complete. */ | 212 | /* Wait for the test message to complete. */ |
| 217 | for (i = 0; i < 2 * HZ; i++) { | 213 | for (i = 0; i < 2 * HZ; i++) { |
| 218 | msleep(1000 / HZ); | 214 | msleep(1000 / HZ); |
| 219 | rc = ap_recv(aq->qid, &psmid, ap_msg.msg, 4096); | 215 | rc = ap_recv(aq->qid, &psmid, ap_msg.msg, ap_msg.bufsize); |
| 220 | if (rc == 0 && psmid == 0x0102030405060708ULL) | 216 | if (rc == 0 && psmid == 0x0102030405060708UL) |
| 221 | break; | 217 | break; |
| 222 | } | 218 | } |
| 223 | 219 | ||
| @@ -342,7 +338,7 @@ static int zcrypt_cex2c_queue_probe(struct ap_device *ap_dev) · 118 unmodified lines | |||
| 342 | zq->queue = aq; | 338 | zq->queue = aq; |
| 343 | zq->online = 1; | 339 | zq->online = 1; |
| 344 | atomic_set(&zq->load, 0); | 340 | atomic_set(&zq->load, 0); |
| 345 | ap_rapq(aq->qid); | 341 | ap_rapq(aq->qid, 0); |
| 346 | rc = zcrypt_cex2c_rng_supported(aq); | 342 | rc = zcrypt_cex2c_rng_supported(aq); |
| 347 | if (rc < 0) { | 343 | if (rc < 0) { |
| 348 | zcrypt_queue_free(zq); | 344 | zcrypt_queue_free(zq); |
| @@ -88,7 +88,7 @@ static ssize_t cca_serialnr_show(struct device *dev, · 87 unmodified lines | |||
| 88 | if (ap_domain_index >= 0) | 88 | if (ap_domain_index >= 0) |
| 89 | cca_get_info(ac->id, ap_domain_index, &ci, zc->online); | 89 | cca_get_info(ac->id, ap_domain_index, &ci, zc->online); |
| 90 | 90 | ||
| 91 | return scnprintf(buf, PAGE_SIZE, "%s\n", ci.serial); | 91 | return sysfs_emit(buf, "%s\n", ci.serial); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | static struct device_attribute dev_attr_cca_serialnr = | 94 | static struct device_attribute dev_attr_cca_serialnr = |
| @@ -123,79 +123,70 @@ static ssize_t cca_mkvps_show(struct device *dev, · 28 unmodified lines | |||
| 123 | &ci, zq->online); | 123 | &ci, zq->online); |
| 124 | 124 | ||
| 125 | if (ci.new_aes_mk_state >= '1' && ci.new_aes_mk_state <= '3') | 125 | if (ci.new_aes_mk_state >= '1' && ci.new_aes_mk_state <= '3') |
| 126 | n += scnprintf(buf + n, PAGE_SIZE, | 126 | n += sysfs_emit_at(buf, n, "AES NEW: %s 0x%016llx\n", |
| 127 | "AES NEW: %s 0x%016llx\n", | 127 | new_state[ci.new_aes_mk_state - '1'], |
| 128 | new_state[ci.new_aes_mk_state - '1'], | 128 | ci.new_aes_mkvp); |
| 129 | ci.new_aes_mkvp); | ||
| 130 | else | 129 | else |
| 131 | n += scnprintf(buf + n, PAGE_SIZE, "AES NEW: - -\n"); | 130 | n += sysfs_emit_at(buf, n, "AES NEW: - -\n"); |
| 132 | 131 | ||
| 133 | if (ci.cur_aes_mk_state >= '1' && ci.cur_aes_mk_state <= '2') | 132 | if (ci.cur_aes_mk_state >= '1' && ci.cur_aes_mk_state <= '2') |
| 134 | n += scnprintf(buf + n, PAGE_SIZE - n, | 133 | n += sysfs_emit_at(buf, n, "AES CUR: %s 0x%016llx\n", |
| 135 | "AES CUR: %s 0x%016llx\n", | 134 | cao_state[ci.cur_aes_mk_state - '1'], |
| 136 | cao_state[ci.cur_aes_mk_state - '1'], | 135 | ci.cur_aes_mkvp); |
| 137 | ci.cur_aes_mkvp); | ||
| 138 | else | 136 | else |
| 139 | n += scnprintf(buf + n, PAGE_SIZE - n, "AES CUR: - -\n"); | 137 | n += sysfs_emit_at(buf, n, "AES CUR: - -\n"); |
| 140 | 138 | ||
| 141 | if (ci.old_aes_mk_state >= '1' && ci.old_aes_mk_state <= '2') | 139 | if (ci.old_aes_mk_state >= '1' && ci.old_aes_mk_state <= '2') |
| 142 | n += scnprintf(buf + n, PAGE_SIZE - n, | 140 | n += sysfs_emit_at(buf, n, "AES OLD: %s 0x%016llx\n", |
| 143 | "AES OLD: %s 0x%016llx\n", | 141 | cao_state[ci.old_aes_mk_state - '1'], |
| 144 | cao_state[ci.old_aes_mk_state - '1'], | 142 | ci.old_aes_mkvp); |
| 145 | ci.old_aes_mkvp); | ||
| 146 | else | 143 | else |
| 147 | n += scnprintf(buf + n, PAGE_SIZE - n, "AES OLD: - -\n"); | 144 | n += sysfs_emit_at(buf, n, "AES OLD: - -\n"); |
| 148 | 145 | ||
| 149 | if (ci.new_apka_mk_state >= '1' && ci.new_apka_mk_state <= '3') | 146 | if (ci.new_apka_mk_state >= '1' && ci.new_apka_mk_state <= '3') |
| 150 | n += scnprintf(buf + n, PAGE_SIZE - n, | 147 | n += sysfs_emit_at(buf, n, "APKA NEW: %s 0x%016llx\n", |
| 151 | "APKA NEW: %s 0x%016llx\n", | 148 | new_state[ci.new_apka_mk_state - '1'], |
| 152 | new_state[ci.new_apka_mk_state - '1'], | 149 | ci.new_apka_mkvp); |
| 153 | ci.new_apka_mkvp); | ||
| 154 | else | 150 | else |
| 155 | n += scnprintf(buf + n, PAGE_SIZE - n, "APKA NEW: - -\n"); | 151 | n += sysfs_emit_at(buf, n, "APKA NEW: - -\n"); |
| 156 | 152 | ||
| 157 | if (ci.cur_apka_mk_state >= '1' && ci.cur_apka_mk_state <= '2') | 153 | if (ci.cur_apka_mk_state >= '1' && ci.cur_apka_mk_state <= '2') |
| 158 | n += scnprintf(buf + n, PAGE_SIZE - n, | 154 | n += sysfs_emit_at(buf, n, "APKA CUR: %s 0x%016llx\n", |
| 159 | "APKA CUR: %s 0x%016llx\n", | 155 | cao_state[ci.cur_apka_mk_state - '1'], |
| 160 | cao_state[ci.cur_apka_mk_state - '1'], | 156 | ci.cur_apka_mkvp); |
| 161 | ci.cur_apka_mkvp); | ||
| 162 | else | 157 | else |
| 163 | n += scnprintf(buf + n, PAGE_SIZE - n, "APKA CUR: - -\n"); | 158 | n += sysfs_emit_at(buf, n, "APKA CUR: - -\n"); |
| 164 | 159 | ||
| 165 | if (ci.old_apka_mk_state >= '1' && ci.old_apka_mk_state <= '2') | 160 | if (ci.old_apka_mk_state >= '1' && ci.old_apka_mk_state <= '2') |
| 166 | n += scnprintf(buf + n, PAGE_SIZE - n, | 161 | n += sysfs_emit_at(buf, n, "APKA OLD: %s 0x%016llx\n", |
| 167 | "APKA OLD: %s 0x%016llx\n", | 162 | cao_state[ci.old_apka_mk_state - '1'], |
| 168 | cao_state[ci.old_apka_mk_state - '1'], | 163 | ci.old_apka_mkvp); |
| 169 | ci.old_apka_mkvp); | ||
| 170 | else | 164 | else |
| 171 | n += scnprintf(buf + n, PAGE_SIZE - n, "APKA OLD: - -\n"); | 165 | n += sysfs_emit_at(buf, n, "APKA OLD: - -\n"); |
| 172 | 166 | ||
| 173 | if (ci.new_asym_mk_state >= '1' && ci.new_asym_mk_state <= '3') | 167 | if (ci.new_asym_mk_state >= '1' && ci.new_asym_mk_state <= '3') |
| 174 | n += scnprintf(buf + n, PAGE_SIZE, | 168 | n += sysfs_emit_at(buf, n, "ASYM NEW: %s 0x%016llx%016llx\n", |
| 175 | "ASYM NEW: %s 0x%016llx%016llx\n", | 169 | new_state[ci.new_asym_mk_state - '1'], |
| 176 | new_state[ci.new_asym_mk_state - '1'], | 170 | *((u64 *)(ci.new_asym_mkvp)), |
| 177 | *((u64 *)(ci.new_asym_mkvp)), | 171 | *((u64 *)(ci.new_asym_mkvp + sizeof(u64)))); |
| 178 | *((u64 *)(ci.new_asym_mkvp + sizeof(u64)))); | ||
| 179 | else | 172 | else |
| 180 | n += scnprintf(buf + n, PAGE_SIZE, "ASYM NEW: - -\n"); | 173 | n += sysfs_emit_at(buf, n, "ASYM NEW: - -\n"); |
| 181 | 174 | ||
| 182 | if (ci.cur_asym_mk_state >= '1' && ci.cur_asym_mk_state <= '2') | 175 | if (ci.cur_asym_mk_state >= '1' && ci.cur_asym_mk_state <= '2') |
| 183 | n += scnprintf(buf + n, PAGE_SIZE - n, | 176 | n += sysfs_emit_at(buf, n, "ASYM CUR: %s 0x%016llx%016llx\n", |
| 184 | "ASYM CUR: %s 0x%016llx%016llx\n", | 177 | cao_state[ci.cur_asym_mk_state - '1'], |
| 185 | cao_state[ci.cur_asym_mk_state - '1'], | 178 | *((u64 *)(ci.cur_asym_mkvp)), |
| 186 | *((u64 *)(ci.cur_asym_mkvp)), | 179 | *((u64 *)(ci.cur_asym_mkvp + sizeof(u64)))); |
| 187 | *((u64 *)(ci.cur_asym_mkvp + sizeof(u64)))); | ||
| 188 | else | 180 | else |
| 189 | n += scnprintf(buf + n, PAGE_SIZE - n, "ASYM CUR: - -\n"); | 181 | n += sysfs_emit_at(buf, n, "ASYM CUR: - -\n"); |
| 190 | 182 | ||
| 191 | if (ci.old_asym_mk_state >= '1' && ci.old_asym_mk_state <= '2') | 183 | if (ci.old_asym_mk_state >= '1' && ci.old_asym_mk_state <= '2') |
| 192 | n += scnprintf(buf + n, PAGE_SIZE - n, | 184 | n += sysfs_emit_at(buf, n, "ASYM OLD: %s 0x%016llx%016llx\n", |
| 193 | "ASYM OLD: %s 0x%016llx%016llx\n", | 185 | cao_state[ci.old_asym_mk_state - '1'], |
| 194 | cao_state[ci.old_asym_mk_state - '1'], | 186 | *((u64 *)(ci.old_asym_mkvp)), |
| 195 | *((u64 *)(ci.old_asym_mkvp)), | 187 | *((u64 *)(ci.old_asym_mkvp + sizeof(u64)))); |
| 196 | *((u64 *)(ci.old_asym_mkvp + sizeof(u64)))); | ||
| 197 | else | 188 | else |
| 198 | n += scnprintf(buf + n, PAGE_SIZE - n, "ASYM OLD: - -\n"); | 189 | n += sysfs_emit_at(buf, n, "ASYM OLD: - -\n"); |
| 199 | 190 | ||
| 200 | return n; | 191 | return n; |
| 201 | } | 192 | } |
| @@ -228,9 +219,9 @@ static ssize_t ep11_api_ordinalnr_show(struct device *dev, · 26 unmodified lines | |||
| 228 | ep11_get_card_info(ac->id, &ci, zc->online); | 219 | ep11_get_card_info(ac->id, &ci, zc->online); |
| 229 | 220 | ||
| 230 | if (ci.API_ord_nr > 0) | 221 | if (ci.API_ord_nr > 0) |
| 231 | return scnprintf(buf, PAGE_SIZE, "%u\n", ci.API_ord_nr); | 222 | return sysfs_emit(buf, "%u\n", ci.API_ord_nr); |
| 232 | else | 223 | else |
| 233 | return scnprintf(buf, PAGE_SIZE, "\n"); | 224 | return sysfs_emit(buf, "\n"); |
| 234 | } | 225 | } |
| 235 | 226 | ||
| 236 | static struct device_attribute dev_attr_ep11_api_ordinalnr = | 227 | static struct device_attribute dev_attr_ep11_api_ordinalnr = |
| @@ -249,11 +240,11 @@ static ssize_t ep11_fw_version_show(struct device *dev, · 12 unmodified lines | |||
| 249 | ep11_get_card_info(ac->id, &ci, zc->online); | 240 | ep11_get_card_info(ac->id, &ci, zc->online); |
| 250 | 241 | ||
| 251 | if (ci.FW_version > 0) | 242 | if (ci.FW_version > 0) |
| 252 | return scnprintf(buf, PAGE_SIZE, "%d.%d\n", | 243 | return sysfs_emit(buf, "%d.%d\n", |
| 253 | (int)(ci.FW_version >> 8), | 244 | (int)(ci.FW_version >> 8), |
| 254 | (int)(ci.FW_version & 0xFF)); | 245 | (int)(ci.FW_version & 0xFF)); |
| 255 | else | 246 | else |
| 256 | return scnprintf(buf, PAGE_SIZE, "\n"); | 247 | return sysfs_emit(buf, "\n"); |
| 257 | } | 248 | } |
| 258 | 249 | ||
| 259 | static struct device_attribute dev_attr_ep11_fw_version = | 250 | static struct device_attribute dev_attr_ep11_fw_version = |
| @@ -272,9 +263,9 @@ static ssize_t ep11_serialnr_show(struct device *dev, · 12 unmodified lines | |||
| 272 | ep11_get_card_info(ac->id, &ci, zc->online); | 263 | ep11_get_card_info(ac->id, &ci, zc->online); |
| 273 | 264 | ||
| 274 | if (ci.serial[0]) | 265 | if (ci.serial[0]) |
| 275 | return scnprintf(buf, PAGE_SIZE, "%16.16s\n", ci.serial); | 266 | return sysfs_emit(buf, "%16.16s\n", ci.serial); |
| 276 | else | 267 | else |
| 277 | return scnprintf(buf, PAGE_SIZE, "\n"); | 268 | return sysfs_emit(buf, "\n"); |
| 278 | } | 269 | } |
| 279 | 270 | ||
| 280 | static struct device_attribute dev_attr_ep11_serialnr = | 271 | static struct device_attribute dev_attr_ep11_serialnr = |
| @@ -309,11 +300,11 @@ static ssize_t ep11_card_op_modes_show(struct device *dev, · 28 unmodified lines | |||
| 309 | if (ci.op_mode & (1ULL << ep11_op_modes[i].mode_bit)) { | 300 | if (ci.op_mode & (1ULL << ep11_op_modes[i].mode_bit)) { |
| 310 | if (n > 0) | 301 | if (n > 0) |
| 311 | buf[n++] = ' '; | 302 | buf[n++] = ' '; |
| 312 | n += scnprintf(buf + n, PAGE_SIZE - n, | 303 | n += sysfs_emit_at(buf, n, "%s", |
| 313 | "%s", ep11_op_modes[i].mode_txt); | 304 | ep11_op_modes[i].mode_txt); |
| 314 | } | 305 | } |
| 315 | } | 306 | } |
| 316 | n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); | 307 | n += sysfs_emit_at(buf, n, "\n"); |
| 317 | 308 | ||
| 318 | return n; | 309 | return n; |
| 319 | } | 310 | } |
| @@ -356,29 +347,29 @@ static ssize_t ep11_mkvps_show(struct device *dev, · 36 unmodified lines | |||
| 356 | &di); | 347 | &di); |
| 357 | 348 | ||
| 358 | if (di.cur_wk_state == '0') { | 349 | if (di.cur_wk_state == '0') { |
| 359 | n = scnprintf(buf, PAGE_SIZE, "WK CUR: %s -\n", | 350 | n = sysfs_emit(buf, "WK CUR: %s -\n", |
| 360 | cwk_state[di.cur_wk_state - '0']); | 351 | cwk_state[di.cur_wk_state - '0']); |
| 361 | } else if (di.cur_wk_state == '1') { | 352 | } else if (di.cur_wk_state == '1') { |
| 362 | n = scnprintf(buf, PAGE_SIZE, "WK CUR: %s 0x", | 353 | n = sysfs_emit(buf, "WK CUR: %s 0x", |
| 363 | cwk_state[di.cur_wk_state - '0']); | 354 | cwk_state[di.cur_wk_state - '0']); |
| 364 | bin2hex(buf + n, di.cur_wkvp, sizeof(di.cur_wkvp)); | 355 | bin2hex(buf + n, di.cur_wkvp, sizeof(di.cur_wkvp)); |
| 365 | n += 2 * sizeof(di.cur_wkvp); | 356 | n += 2 * sizeof(di.cur_wkvp); |
| 366 | n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); | 357 | n += sysfs_emit_at(buf, n, "\n"); |
| 367 | } else { | 358 | } else { |
| 368 | n = scnprintf(buf, PAGE_SIZE, "WK CUR: - -\n"); | 359 | n = sysfs_emit(buf, "WK CUR: - -\n"); |
| 369 | } | 360 | } |
| 370 | 361 | ||
| 371 | if (di.new_wk_state == '0') { | 362 | if (di.new_wk_state == '0') { |
| 372 | n += scnprintf(buf + n, PAGE_SIZE - n, "WK NEW: %s -\n", | 363 | n += sysfs_emit_at(buf, n, "WK NEW: %s -\n", |
| 373 | nwk_state[di.new_wk_state - '0']); | 364 | nwk_state[di.new_wk_state - '0']); |
| 374 | } else if (di.new_wk_state >= '1' && di.new_wk_state <= '2') { | 365 | } else if (di.new_wk_state >= '1' && di.new_wk_state <= '2') { |
| 375 | n += scnprintf(buf + n, PAGE_SIZE - n, "WK NEW: %s 0x", | 366 | n += sysfs_emit_at(buf, n, "WK NEW: %s 0x", |
| 376 | nwk_state[di.new_wk_state - '0']); | 367 | nwk_state[di.new_wk_state - '0']); |
| 377 | bin2hex(buf + n, di.new_wkvp, sizeof(di.new_wkvp)); | 368 | bin2hex(buf + n, di.new_wkvp, sizeof(di.new_wkvp)); |
| 378 | n += 2 * sizeof(di.new_wkvp); | 369 | n += 2 * sizeof(di.new_wkvp); |
| 379 | n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); | 370 | n += sysfs_emit_at(buf, n, "\n"); |
| 380 | } else { | 371 | } else { |
| 381 | n += scnprintf(buf + n, PAGE_SIZE - n, "WK NEW: - -\n"); | 372 | n += sysfs_emit_at(buf, n, "WK NEW: - -\n"); |
| 382 | } | 373 | } |
| 383 | 374 | ||
| 384 | return n; | 375 | return n; |
| @@ -406,11 +397,11 @@ static ssize_t ep11_queue_op_modes_show(struct device *dev, · 21 unmodified lines | |||
| 406 | if (di.op_mode & (1ULL << ep11_op_modes[i].mode_bit)) { | 397 | if (di.op_mode & (1ULL << ep11_op_modes[i].mode_bit)) { |
| 407 | if (n > 0) | 398 | if (n > 0) |
| 408 | buf[n++] = ' '; | 399 | buf[n++] = ' '; |
| 409 | n += scnprintf(buf + n, PAGE_SIZE - n, | 400 | n += sysfs_emit_at(buf, n, "%s", |
| 410 | "%s", ep11_op_modes[i].mode_txt); | 401 | ep11_op_modes[i].mode_txt); |
| 411 | } | 402 | } |
| 412 | } | 403 | } |
| 413 | n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); | 404 | n += sysfs_emit_at(buf, n, "\n"); |
| 414 | 405 | ||
| 415 | return n; | 406 | return n; |
| 416 | } | 407 | } |
| @@ -1275,7 +1275,7 @@ int ep11_kblob2protkey(u16 card, u16 dom, const u8 *keyblob, size_t keybloblen, · 1274 unmodified lines | |||
| 1275 | u32 pkeybitsize; | 1275 | u32 pkeybitsize; |
| 1276 | u64 pkeysize; | 1276 | u64 pkeysize; |
| 1277 | u8 res2[8]; | 1277 | u8 res2[8]; |
| 1278 | u8 pkey[0]; | 1278 | u8 pkey[]; |
| 1279 | } __packed * wki; | 1279 | } __packed * wki; |
| 1280 | const u8 *key; | 1280 | const u8 *key; |
| 1281 | struct ep11kblob_header *hdr; | 1281 | struct ep11kblob_header *hdr; |
| @@ -441,14 +441,17 @@ static void zcrypt_cex2a_receive(struct ap_queue *aq, · 440 unmodified lines | |||
| 441 | t80h = reply->msg; | 441 | t80h = reply->msg; |
| 442 | if (t80h->type == TYPE80_RSP_CODE) { | 442 | if (t80h->type == TYPE80_RSP_CODE) { |
| 443 | len = t80h->len; | 443 | len = t80h->len; |
| 444 | if (len > reply->bufsize || len > msg->bufsize) { | 444 | if (len > reply->bufsize || len > msg->bufsize || |
| 445 | len != reply->len) { | ||
| 446 | ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n", __func__); | ||
| 445 | msg->rc = -EMSGSIZE; | 447 | msg->rc = -EMSGSIZE; |
| 446 | } else { | 448 | goto out; |
| 447 | memcpy(msg->msg, reply->msg, len); | ||
| 448 | msg->len = len; | ||
| 449 | } | 449 | } |
| 450 | memcpy(msg->msg, reply->msg, len); | ||
| 451 | msg->len = len; | ||
| 450 | } else { | 452 | } else { |
| 451 | memcpy(msg->msg, reply->msg, sizeof(error_reply)); | 453 | memcpy(msg->msg, reply->msg, sizeof(error_reply)); |
| 454 | msg->len = sizeof(error_reply); | ||
| 452 | } | 455 | } |
| 453 | out: | 456 | out: |
| 454 | complete((struct completion *)msg->private); | 457 | complete((struct completion *)msg->private); |
| @@ -476,7 +479,7 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_queue *zq, · 21 unmodified lines | |||
| 476 | if (!ap_msg->msg) | 479 | if (!ap_msg->msg) |
| 477 | return -ENOMEM; | 480 | return -ENOMEM; |
| 478 | ap_msg->receive = zcrypt_cex2a_receive; | 481 | ap_msg->receive = zcrypt_cex2a_receive; |
| 479 | ap_msg->psmid = (((unsigned long long)current->pid) << 32) + | 482 | ap_msg->psmid = (((unsigned long)current->pid) << 32) + |
| 480 | atomic_inc_return(&zcrypt_step); | 483 | atomic_inc_return(&zcrypt_step); |
| 481 | ap_msg->private = &work; | 484 | ap_msg->private = &work; |
| 482 | rc = ICAMEX_msg_to_type50MEX_msg(zq, ap_msg, mex); | 485 | rc = ICAMEX_msg_to_type50MEX_msg(zq, ap_msg, mex); |
| @@ -527,7 +530,7 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_queue *zq, · 44 unmodified lines | |||
| 527 | if (!ap_msg->msg) | 530 | if (!ap_msg->msg) |
| 528 | return -ENOMEM; | 531 | return -ENOMEM; |
| 529 | ap_msg->receive = zcrypt_cex2a_receive; | 532 | ap_msg->receive = zcrypt_cex2a_receive; |
| 530 | ap_msg->psmid = (((unsigned long long)current->pid) << 32) + | 533 | ap_msg->psmid = (((unsigned long)current->pid) << 32) + |
| 531 | atomic_inc_return(&zcrypt_step); | 534 | atomic_inc_return(&zcrypt_step); |
| 532 | ap_msg->private = &work; | 535 | ap_msg->private = &work; |
| 533 | rc = ICACRT_msg_to_type50CRT_msg(zq, ap_msg, crt); | 536 | rc = ICACRT_msg_to_type50CRT_msg(zq, ap_msg, crt); |
| @@ -208,7 +208,7 @@ static int icamex_msg_to_type6mex_msgx(struct zcrypt_queue *zq, · 207 unmodified lines | |||
| 208 | struct CPRBX cprbx; | 208 | struct CPRBX cprbx; |
| 209 | struct function_and_rules_block fr; | 209 | struct function_and_rules_block fr; |
| 210 | unsigned short length; | 210 | unsigned short length; |
| 211 | char text[0]; | 211 | char text[]; |
| 212 | } __packed * msg = ap_msg->msg; | 212 | } __packed * msg = ap_msg->msg; |
| 213 | int size; | 213 | int size; |
| 214 | 214 | ||
| @@ -278,7 +278,7 @@ static int icacrt_msg_to_type6crt_msgx(struct zcrypt_queue *zq, · 63 unmodified lines | |||
| 278 | struct CPRBX cprbx; | 278 | struct CPRBX cprbx; |
| 279 | struct function_and_rules_block fr; | 279 | struct function_and_rules_block fr; |
| 280 | unsigned short length; | 280 | unsigned short length; |
| 281 | char text[0]; | 281 | char text[]; |
| 282 | } __packed * msg = ap_msg->msg; | 282 | } __packed * msg = ap_msg->msg; |
| 283 | int size; | 283 | int size; |
| 284 | 284 | ||
| @@ -566,8 +566,8 @@ struct type86x_reply { · 281 unmodified lines | |||
| 566 | struct type86_fmt2_ext fmt2; | 566 | struct type86_fmt2_ext fmt2; |
| 567 | struct CPRBX cprbx; | 567 | struct CPRBX cprbx; |
| 568 | unsigned char pad[4]; /* 4 byte function code/rules block ? */ | 568 | unsigned char pad[4]; /* 4 byte function code/rules block ? */ |
| 569 | unsigned short length; | 569 | unsigned short length; /* length of data including length field size */ |
| 570 | char text[]; | 570 | char data[]; |
| 571 | } __packed; | 571 | } __packed; |
| 572 | 572 | ||
| 573 | struct type86_ep11_reply { | 573 | struct type86_ep11_reply { |
| @@ -581,45 +581,9 @@ static int convert_type86_ica(struct zcrypt_queue *zq, · 7 unmodified lines | |||
| 581 | char __user *outputdata, | 581 | char __user *outputdata, |
| 582 | unsigned int outputdatalength) | 582 | unsigned int outputdatalength) |
| 583 | { | 583 | { |
| 584 | static unsigned char static_pad[] = { | ||
| 585 | 0x00, 0x02, | ||
| 586 | 0x1B, 0x7B, 0x5D, 0xB5, 0x75, 0x01, 0x3D, 0xFD, | ||
| 587 | 0x8D, 0xD1, 0xC7, 0x03, 0x2D, 0x09, 0x23, 0x57, | ||
| 588 | 0x89, 0x49, 0xB9, 0x3F, 0xBB, 0x99, 0x41, 0x5B, | ||
| 589 | 0x75, 0x21, 0x7B, 0x9D, 0x3B, 0x6B, 0x51, 0x39, | ||
| 590 | 0xBB, 0x0D, 0x35, 0xB9, 0x89, 0x0F, 0x93, 0xA5, | ||
| 591 | 0x0B, 0x47, 0xF1, 0xD3, 0xBB, 0xCB, 0xF1, 0x9D, | ||
| 592 | 0x23, 0x73, 0x71, 0xFF, 0xF3, 0xF5, 0x45, 0xFB, | ||
| 593 | 0x61, 0x29, 0x23, 0xFD, 0xF1, 0x29, 0x3F, 0x7F, | ||
| 594 | 0x17, 0xB7, 0x1B, 0xA9, 0x19, 0xBD, 0x57, 0xA9, | ||
| 595 | 0xD7, 0x95, 0xA3, 0xCB, 0xED, 0x1D, 0xDB, 0x45, | ||
| 596 | 0x7D, 0x11, 0xD1, 0x51, 0x1B, 0xED, 0x71, 0xE9, | ||
| 597 | 0xB1, 0xD1, 0xAB, 0xAB, 0x21, 0x2B, 0x1B, 0x9F, | ||
| 598 | 0x3B, 0x9F, 0xF7, 0xF7, 0xBD, 0x63, 0xEB, 0xAD, | ||
| 599 | 0xDF, 0xB3, 0x6F, 0x5B, 0xDB, 0x8D, 0xA9, 0x5D, | ||
| 600 | 0xE3, 0x7D, 0x77, 0x49, 0x47, 0xF5, 0xA7, 0xFD, | ||
| 601 | 0xAB, 0x2F, 0x27, 0x35, 0x77, 0xD3, 0x49, 0xC9, | ||
| 602 | 0x09, 0xEB, 0xB1, 0xF9, 0xBF, 0x4B, 0xCB, 0x2B, | ||
| 603 | 0xEB, 0xEB, 0x05, 0xFF, 0x7D, 0xC7, 0x91, 0x8B, | ||
| 604 | 0x09, 0x83, 0xB9, 0xB9, 0x69, 0x33, 0x39, 0x6B, | ||
| 605 | 0x79, 0x75, 0x19, 0xBF, 0xBB, 0x07, 0x1D, 0xBD, | ||
| 606 | 0x29, 0xBF, 0x39, 0x95, 0x93, 0x1D, 0x35, 0xC7, | ||
| 607 | 0xC9, 0x4D, 0xE5, 0x97, 0x0B, 0x43, 0x9B, 0xF1, | ||
| 608 | 0x16, 0x93, 0x03, 0x1F, 0xA5, 0xFB, 0xDB, 0xF3, | ||
| 609 | 0x27, 0x4F, 0x27, 0x61, 0x05, 0x1F, 0xB9, 0x23, | ||
| 610 | 0x2F, 0xC3, 0x81, 0xA9, 0x23, 0x71, 0x55, 0x55, | ||
| 611 | 0xEB, 0xED, 0x41, 0xE5, 0xF3, 0x11, 0xF1, 0x43, | ||
| 612 | 0x69, 0x03, 0xBD, 0x0B, 0x37, 0x0F, 0x51, 0x8F, | ||
| 613 | 0x0B, 0xB5, 0x89, 0x5B, 0x67, 0xA9, 0xD9, 0x4F, | ||
| 614 | 0x01, 0xF9, 0x21, 0x77, 0x37, 0x73, 0x79, 0xC5, | ||
| 615 | 0x7F, 0x51, 0xC1, 0xCF, 0x97, 0xA1, 0x75, 0xAD, | ||
| 616 | 0x35, 0x9D, 0xD3, 0xD3, 0xA7, 0x9D, 0x5D, 0x41, | ||
| 617 | 0x6F, 0x65, 0x1B, 0xCF, 0xA9, 0x87, 0x91, 0x09 | ||
| 618 | }; | ||
| 619 | struct type86x_reply *msg = reply->msg; | 584 | struct type86x_reply *msg = reply->msg; |
| 620 | unsigned short service_rc, service_rs; | 585 | unsigned short service_rc, service_rs; |
| 621 | unsigned int reply_len, pad_len; | 586 | unsigned int data_len; |
| 622 | char *data; | ||
| 623 | 587 | ||
| 624 | service_rc = msg->cprbx.ccp_rtcode; | 588 | service_rc = msg->cprbx.ccp_rtcode; |
| 625 | if (unlikely(service_rc != 0)) { | 589 | if (unlikely(service_rc != 0)) { |
| @@ -647,32 +611,12 @@ static int convert_type86_ica(struct zcrypt_queue *zq, · 21 unmodified lines | |||
| 647 | ap_send_online_uevent(&zq->queue->ap_dev, zq->online); | 611 | ap_send_online_uevent(&zq->queue->ap_dev, zq->online); |
| 648 | return -EAGAIN; | 612 | return -EAGAIN; |
| 649 | } | 613 | } |
| 650 | data = msg->text; | 614 | data_len = msg->length - sizeof(msg->length); |
| 651 | reply_len = msg->length - 2; | 615 | if (data_len > outputdatalength) |
| 652 | if (reply_len > outputdatalength) | 616 | return -EMSGSIZE; |
| 653 | return -EINVAL; | 617 | |
| 654 | /* | ||
| 655 | * For all encipher requests, the length of the ciphertext (reply_len) | ||
| 656 | * will always equal the modulus length. For MEX decipher requests | ||
| 657 | * the output needs to get padded. Minimum pad size is 10. | ||
| 658 | * | ||
| 659 | * Currently, the cases where padding will be added is for: | ||
| 660 | * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support | ||
| 661 | * ZERO-PAD and CRT is only supported for PKD requests) | ||
| 662 | * - PCICC, always | ||
| 663 | */ | ||
| 664 | pad_len = outputdatalength - reply_len; | ||
| 665 | if (pad_len > 0) { | ||
| 666 | if (pad_len < 10) | ||
| 667 | return -EINVAL; | ||
| 668 | /* 'restore' padding left in the CEXXC card. */ | ||
| 669 | if (copy_to_user(outputdata, static_pad, pad_len - 1)) | ||
| 670 | return -EFAULT; | ||
| 671 | if (put_user(0, outputdata + pad_len - 1)) | ||
| 672 | return -EFAULT; | ||
| 673 | } | ||
| 674 | /* Copy the crypto response to user space. */ | 618 | /* Copy the crypto response to user space. */ |
| 675 | if (copy_to_user(outputdata + pad_len, data, reply_len)) | 619 | if (copy_to_user(outputdata, msg->data, data_len)) |
| 676 | return -EFAULT; | 620 | return -EFAULT; |
| 677 | return 0; | 621 | return 0; |
| 678 | } | 622 | } |
| @@ -926,8 +870,7 @@ static void zcrypt_msgtype6_receive(struct ap_queue *aq, · 247 unmodified lines | |||
| 926 | .type = TYPE82_RSP_CODE, | 870 | .type = TYPE82_RSP_CODE, |
| 927 | .reply_code = REP82_ERROR_MACHINE_FAILURE, | 871 | .reply_code = REP82_ERROR_MACHINE_FAILURE, |
| 928 | }; | 872 | }; |
| 929 | struct response_type *resp_type = | 873 | struct response_type *resp_type = msg->private; |
| 930 | (struct response_type *)msg->private; | ||
| 931 | struct type86x_reply *t86r; | 874 | struct type86x_reply *t86r; |
| 932 | int len; | 875 | int len; |
| 933 | 876 | ||
| @@ -939,28 +882,37 @@ static void zcrypt_msgtype6_receive(struct ap_queue *aq, · 5 unmodified lines | |||
| 939 | t86r->cprbx.cprb_ver_id == 0x02) { | 882 | t86r->cprbx.cprb_ver_id == 0x02) { |
| 940 | switch (resp_type->type) { | 883 | switch (resp_type->type) { |
| 941 | case CEXXC_RESPONSE_TYPE_ICA: | 884 | case CEXXC_RESPONSE_TYPE_ICA: |
| 942 | len = sizeof(struct type86x_reply) + t86r->length - 2; | 885 | len = sizeof(struct type86x_reply) + t86r->length; |
| 943 | if (len > reply->bufsize || len > msg->bufsize) { | 886 | if (len > reply->bufsize || len > msg->bufsize || |
| 887 | len != reply->len) { | ||
| 888 | ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n", __func__); | ||
| 944 | msg->rc = -EMSGSIZE; | 889 | msg->rc = -EMSGSIZE; |
| 945 | } else { | 890 | goto out; |
| 946 | memcpy(msg->msg, reply->msg, len); | ||
| 947 | msg->len = len; | ||
| 948 | } | 891 | } |
| 892 | memcpy(msg->msg, reply->msg, len); | ||
| 893 | msg->len = len; | ||
| 949 | break; | 894 | break; |
| 950 | case CEXXC_RESPONSE_TYPE_XCRB: | 895 | case CEXXC_RESPONSE_TYPE_XCRB: |
| 951 | len = t86r->fmt2.offset2 + t86r->fmt2.count2; | 896 | if (t86r->fmt2.count2) |
| 952 | if (len > reply->bufsize || len > msg->bufsize) { | 897 | len = t86r->fmt2.offset2 + t86r->fmt2.count2; |
| 898 | else | ||
| 899 | len = t86r->fmt2.offset1 + t86r->fmt2.count1; | ||
| 900 | if (len > reply->bufsize || len > msg->bufsize || | ||
| 901 | len != reply->len) { | ||
| 902 | ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n", __func__); | ||
| 953 | msg->rc = -EMSGSIZE; | 903 | msg->rc = -EMSGSIZE; |
| 954 | } else { | 904 | goto out; |
| 955 | memcpy(msg->msg, reply->msg, len); | ||
| 956 | msg->len = len; | ||
| 957 | } | 905 | } |
| 906 | memcpy(msg->msg, reply->msg, len); | ||
| 907 | msg->len = len; | ||
| 958 | break; | 908 | break; |
| 959 | default: | 909 | default: |
| 960 | memcpy(msg->msg, &error_reply, sizeof(error_reply)); | 910 | memcpy(msg->msg, &error_reply, sizeof(error_reply)); |
| 911 | msg->len = sizeof(error_reply); | ||
| 961 | } | 912 | } |
| 962 | } else { | 913 | } else { |
| 963 | memcpy(msg->msg, reply->msg, sizeof(error_reply)); | 914 | memcpy(msg->msg, reply->msg, sizeof(error_reply)); |
| 915 | msg->len = sizeof(error_reply); | ||
| 964 | } | 916 | } |
| 965 | out: | 917 | out: |
| 966 | complete(&resp_type->work); | 918 | complete(&resp_type->work); |
| @@ -982,8 +934,7 @@ static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq, · 15 unmodified lines | |||
| 982 | .type = TYPE82_RSP_CODE, | 934 | .type = TYPE82_RSP_CODE, |
| 983 | .reply_code = REP82_ERROR_MACHINE_FAILURE, | 935 | .reply_code = REP82_ERROR_MACHINE_FAILURE, |
| 984 | }; | 936 | }; |
| 985 | struct response_type *resp_type = | 937 | struct response_type *resp_type = msg->private; |
| 986 | (struct response_type *)msg->private; | ||
| 987 | struct type86_ep11_reply *t86r; | 938 | struct type86_ep11_reply *t86r; |
| 988 | int len; | 939 | int len; |
| 989 | 940 | ||
| @@ -996,18 +947,22 @@ static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq, · 6 unmodified lines | |||
| 996 | switch (resp_type->type) { | 947 | switch (resp_type->type) { |
| 997 | case CEXXC_RESPONSE_TYPE_EP11: | 948 | case CEXXC_RESPONSE_TYPE_EP11: |
| 998 | len = t86r->fmt2.offset1 + t86r->fmt2.count1; | 949 | len = t86r->fmt2.offset1 + t86r->fmt2.count1; |
| 999 | if (len > reply->bufsize || len > msg->bufsize) { | 950 | if (len > reply->bufsize || len > msg->bufsize || |
| 951 | len != reply->len) { | ||
| 952 | ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n", __func__); | ||
| 1000 | msg->rc = -EMSGSIZE; | 953 | msg->rc = -EMSGSIZE; |
| 1001 | } else { | 954 | goto out; |
| 1002 | memcpy(msg->msg, reply->msg, len); | ||
| 1003 | msg->len = len; | ||
| 1004 | } | 955 | } |
| 956 | memcpy(msg->msg, reply->msg, len); | ||
| 957 | msg->len = len; | ||
| 1005 | break; | 958 | break; |
| 1006 | default: | 959 | default: |
| 1007 | memcpy(msg->msg, &error_reply, sizeof(error_reply)); | 960 | memcpy(msg->msg, &error_reply, sizeof(error_reply)); |
| 961 | msg->len = sizeof(error_reply); | ||
| 1008 | } | 962 | } |
| 1009 | } else { | 963 | } else { |
| 1010 | memcpy(msg->msg, reply->msg, sizeof(error_reply)); | 964 | memcpy(msg->msg, reply->msg, sizeof(error_reply)); |
| 965 | msg->len = sizeof(error_reply); | ||
| 1011 | } | 966 | } |
| 1012 | out: | 967 | out: |
| 1013 | complete(&resp_type->work); | 968 | complete(&resp_type->work); |
| @@ -1036,7 +991,7 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq, · 22 unmodified lines | |||
| 1036 | return -ENOMEM; | 991 | return -ENOMEM; |
| 1037 | ap_msg->bufsize = PAGE_SIZE; | 992 | ap_msg->bufsize = PAGE_SIZE; |
| 1038 | ap_msg->receive = zcrypt_msgtype6_receive; | 993 | ap_msg->receive = zcrypt_msgtype6_receive; |
| 1039 | ap_msg->psmid = (((unsigned long long)current->pid) << 32) + | 994 | ap_msg->psmid = (((unsigned long)current->pid) << 32) + |
| 1040 | atomic_inc_return(&zcrypt_step); | 995 | atomic_inc_return(&zcrypt_step); |
| 1041 | ap_msg->private = &resp_type; | 996 | ap_msg->private = &resp_type; |
| 1042 | rc = icamex_msg_to_type6mex_msgx(zq, ap_msg, mex); | 997 | rc = icamex_msg_to_type6mex_msgx(zq, ap_msg, mex); |
| @@ -1086,7 +1041,7 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq, · 43 unmodified lines | |||
| 1086 | return -ENOMEM; | 1041 | return -ENOMEM; |
| 1087 | ap_msg->bufsize = PAGE_SIZE; | 1042 | ap_msg->bufsize = PAGE_SIZE; |
| 1088 | ap_msg->receive = zcrypt_msgtype6_receive; | 1043 | ap_msg->receive = zcrypt_msgtype6_receive; |
| 1089 | ap_msg->psmid = (((unsigned long long)current->pid) << 32) + | 1044 | ap_msg->psmid = (((unsigned long)current->pid) << 32) + |
| 1090 | atomic_inc_return(&zcrypt_step); | 1045 | atomic_inc_return(&zcrypt_step); |
| 1091 | ap_msg->private = &resp_type; | 1046 | ap_msg->private = &resp_type; |
| 1092 | rc = icacrt_msg_to_type6crt_msgx(zq, ap_msg, crt); | 1047 | rc = icacrt_msg_to_type6crt_msgx(zq, ap_msg, crt); |
| @@ -1137,7 +1092,7 @@ int prep_cca_ap_msg(bool userspace, struct ica_xcRB *xcrb, · 44 unmodified lines | |||
| 1137 | if (!ap_msg->msg) | 1092 | if (!ap_msg->msg) |
| 1138 | return -ENOMEM; | 1093 | return -ENOMEM; |
| 1139 | ap_msg->receive = zcrypt_msgtype6_receive; | 1094 | ap_msg->receive = zcrypt_msgtype6_receive; |
| 1140 | ap_msg->psmid = (((unsigned long long)current->pid) << 32) + | 1095 | ap_msg->psmid = (((unsigned long)current->pid) << 32) + |
| 1141 | atomic_inc_return(&zcrypt_step); | 1096 | atomic_inc_return(&zcrypt_step); |
| 1142 | ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL); | 1097 | ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL); |
| 1143 | if (!ap_msg->private) | 1098 | if (!ap_msg->private) |
| @@ -1157,7 +1112,7 @@ static long zcrypt_msgtype6_send_cprb(bool userspace, struct zcrypt_queue *zq, · 13 unmodified lines | |||
| 1157 | struct ap_message *ap_msg) | 1112 | struct ap_message *ap_msg) |
| 1158 | { | 1113 | { |
| 1159 | int rc; | 1114 | int rc; |
| 1160 | struct response_type *rtype = (struct response_type *)(ap_msg->private); | 1115 | struct response_type *rtype = ap_msg->private; |
| 1161 | struct { | 1116 | struct { |
| 1162 | struct type6_hdr hdr; | 1117 | struct type6_hdr hdr; |
| 1163 | struct CPRBX cprbx; | 1118 | struct CPRBX cprbx; |
| @@ -1218,7 +1173,7 @@ int prep_ep11_ap_msg(bool userspace, struct ep11_urb *xcrb, · 54 unmodified lines | |||
| 1218 | if (!ap_msg->msg) | 1173 | if (!ap_msg->msg) |
| 1219 | return -ENOMEM; | 1174 | return -ENOMEM; |
| 1220 | ap_msg->receive = zcrypt_msgtype6_receive_ep11; | 1175 | ap_msg->receive = zcrypt_msgtype6_receive_ep11; |
| 1221 | ap_msg->psmid = (((unsigned long long)current->pid) << 32) + | 1176 | ap_msg->psmid = (((unsigned long)current->pid) << 32) + |
| 1222 | atomic_inc_return(&zcrypt_step); | 1177 | atomic_inc_return(&zcrypt_step); |
| 1223 | ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL); | 1178 | ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL); |
| 1224 | if (!ap_msg->private) | 1179 | if (!ap_msg->private) |
| @@ -1240,7 +1195,7 @@ static long zcrypt_msgtype6_send_ep11_cprb(bool userspace, struct zcrypt_queue * · 15 unmodified lines | |||
| 1240 | { | 1195 | { |
| 1241 | int rc; | 1196 | int rc; |
| 1242 | unsigned int lfmt; | 1197 | unsigned int lfmt; |
| 1243 | struct response_type *rtype = (struct response_type *)(ap_msg->private); | 1198 | struct response_type *rtype = ap_msg->private; |
| 1244 | struct { | 1199 | struct { |
| 1245 | struct type6_hdr hdr; | 1200 | struct type6_hdr hdr; |
| 1246 | struct ep11_cprb cprbx; | 1201 | struct ep11_cprb cprbx; |
| @@ -1328,7 +1283,7 @@ int prep_rng_ap_msg(struct ap_message *ap_msg, int *func_code, · 81 unmodified lines | |||
| 1328 | if (!ap_msg->msg) | 1283 | if (!ap_msg->msg) |
| 1329 | return -ENOMEM; | 1284 | return -ENOMEM; |
| 1330 | ap_msg->receive = zcrypt_msgtype6_receive; | 1285 | ap_msg->receive = zcrypt_msgtype6_receive; |
| 1331 | ap_msg->psmid = (((unsigned long long)current->pid) << 32) + | 1286 | ap_msg->psmid = (((unsigned long)current->pid) << 32) + |
| 1332 | atomic_inc_return(&zcrypt_step); | 1287 | atomic_inc_return(&zcrypt_step); |
| 1333 | ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL); | 1288 | ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL); |
| 1334 | if (!ap_msg->private) | 1289 | if (!ap_msg->private) |
| @@ -1359,7 +1314,7 @@ static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq, · 24 unmodified lines | |||
| 1359 | short int verb_length; | 1314 | short int verb_length; |
| 1360 | short int key_length; | 1315 | short int key_length; |
| 1361 | } __packed * msg = ap_msg->msg; | 1316 | } __packed * msg = ap_msg->msg; |
| 1362 | struct response_type *rtype = (struct response_type *)(ap_msg->private); | 1317 | struct response_type *rtype = ap_msg->private; |
| 1363 | int rc; | 1318 | int rc; |
| 1364 | 1319 | ||
| 1365 | msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid); | 1320 | msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid); |
| @@ -44,7 +44,7 @@ static ssize_t online_show(struct device *dev, · 43 unmodified lines | |||
| 44 | struct ap_queue *aq = to_ap_queue(dev); | 44 | struct ap_queue *aq = to_ap_queue(dev); |
| 45 | int online = aq->config && zq->online ? 1 : 0; | 45 | int online = aq->config && zq->online ? 1 : 0; |
| 46 | 46 | ||
| 47 | return scnprintf(buf, PAGE_SIZE, "%d\n", online); | 47 | return sysfs_emit(buf, "%d\n", online); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | static ssize_t online_store(struct device *dev, | 50 | static ssize_t online_store(struct device *dev, |
| @@ -84,7 +84,7 @@ static ssize_t load_show(struct device *dev, · 33 unmodified lines | |||
| 84 | { | 84 | { |
| 85 | struct zcrypt_queue *zq = dev_get_drvdata(dev); | 85 | struct zcrypt_queue *zq = dev_get_drvdata(dev); |
| 86 | 86 | ||
| 87 | return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&zq->load)); | 87 | return sysfs_emit(buf, "%d\n", atomic_read(&zq->load)); |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | static DEVICE_ATTR_RO(load); | 90 | static DEVICE_ATTR_RO(load); |
| @@ -70,6 +70,18 @@ late_initcall(stackleak_sysctls_init); · 69 unmodified lines | |||
| 70 | #define skip_erasing() false | 70 | #define skip_erasing() false |
| 71 | #endif /* CONFIG_STACKLEAK_RUNTIME_DISABLE */ | 71 | #endif /* CONFIG_STACKLEAK_RUNTIME_DISABLE */ |
| 72 | 72 | ||
| 73 | #ifndef __stackleak_poison | ||
| 74 | static __always_inline void __stackleak_poison(unsigned long erase_low, | ||
| 75 | unsigned long erase_high, | ||
| 76 | unsigned long poison) | ||
| 77 | { | ||
| 78 | while (erase_low < erase_high) { | ||
| 79 | *(unsigned long *)erase_low = poison; | ||
| 80 | erase_low += sizeof(unsigned long); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | #endif | ||
| 84 | |||
| 73 | static __always_inline void __stackleak_erase(bool on_task_stack) | 85 | static __always_inline void __stackleak_erase(bool on_task_stack) |
| 74 | { | 86 | { |
| 75 | const unsigned long task_stack_low = stackleak_task_low_bound(current); | 87 | const unsigned long task_stack_low = stackleak_task_low_bound(current); |
| @@ -101,10 +113,7 @@ static __always_inline void __stackleak_erase(bool on_task_stack) · 25 unmodified lines | |||
| 101 | else | 113 | else |
| 102 | erase_high = task_stack_high; | 114 | erase_high = task_stack_high; |
| 103 | 115 | ||
| 104 | while (erase_low < erase_high) { | 116 | __stackleak_poison(erase_low, erase_high, STACKLEAK_POISON); |
| 105 | *(unsigned long *)erase_low = STACKLEAK_POISON; | ||
| 106 | erase_low += sizeof(unsigned long); | ||
| 107 | } | ||
| 108 | 117 | ||
| 109 | /* Reset the 'lowest_stack' value for the next syscall */ | 118 | /* Reset the 'lowest_stack' value for the next syscall */ |
| 110 | current->lowest_stack = task_stack_high; | 119 | current->lowest_stack = task_stack_high; |
| @@ -502,7 +502,7 @@ config SECTION_MISMATCH_WARN_ONLY · 501 unmodified lines | |||
| 502 | 502 | ||
| 503 | config DEBUG_FORCE_FUNCTION_ALIGN_64B | 503 | config DEBUG_FORCE_FUNCTION_ALIGN_64B |
| 504 | bool "Force all function address 64B aligned" | 504 | bool "Force all function address 64B aligned" |
| 505 | depends on EXPERT && (X86_64 || ARM64 || PPC32 || PPC64 || ARC) | 505 | depends on EXPERT && (X86_64 || ARM64 || PPC32 || PPC64 || ARC || S390) |
| 506 | select FUNCTION_ALIGNMENT_64B | 506 | select FUNCTION_ALIGNMENT_64B |
| 507 | help | 507 | help |
| 508 | There are cases that a commit from one domain changes the function | 508 | There are cases that a commit from one domain changes the function |