Skip to content

Commit 1995a53

Browse files
committed
Merge tag 's390-6.7-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull more s390 updates from Vasily Gorbik: - Get rid of s390 specific use of two PTEs per 4KB page with complex half-used pages tracking. Using full 4KB pages for 2KB PTEs increases the memory footprint of page tables but drastically simplify mm code, removing a common blocker for common code changes and adaptations - Simplify and rework "cmma no-dat" handling. This is a follow up for recent fixes which prevent potential incorrect guest TLB flushes - Add perf user stack unwinding as well as USER_STACKTRACE support for user space built with -mbackchain compile option - Add few missing conversion from tlb_remove_table to tlb_remove_ptdesc - Fix crypto cards vanishing in a secure execution environment due to asynchronous errors - Avoid reporting crypto cards or queues in check-stop state as online - Fix null-ptr deference in AP bus code triggered by early config change via SCLP - Couple of stability improvements in AP queue interrupt handling * tag 's390-6.7-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: s390/mm: make pte_free_tlb() similar to pXd_free_tlb() s390/mm: use compound page order to distinguish page tables s390/mm: use full 4KB page for 2KB PTE s390/cmma: rework no-dat handling s390/cmma: move arch_set_page_dat() to header file s390/cmma: move set_page_stable() and friends to header file s390/cmma: move parsing of cmma kernel parameter to early boot code s390/cmma: cleanup inline assemblies s390/ap: fix vanishing crypto cards in SE environment s390/zcrypt: don't report online if card or queue is in check-stop state s390: add USER_STACKTRACE support s390/perf: implement perf_callchain_user() s390/ap: fix AP bus crash on early config change callback invocation s390/ap: re-enable interrupt for AP queues s390/ap: rework to use irq info from ap queue status s390/mm: add missing conversion to use ptdescs
2 parents 90450a0 + 02e790e commit 1995a53

25 files changed

+319
-537
lines changed

arch/s390/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ config S390
236236
select THREAD_INFO_IN_TASK
237237
select TRACE_IRQFLAGS_SUPPORT
238238
select TTY
239+
select USER_STACKTRACE_SUPPORT
239240
select VIRT_CPU_ACCOUNTING
240241
select ZONE_DMA
241242
# Note: keep the above list sorted alphabetically

arch/s390/boot/ipl_parm.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <linux/init.h>
44
#include <linux/ctype.h>
55
#include <linux/pgtable.h>
6+
#include <asm/page-states.h>
67
#include <asm/ebcdic.h>
78
#include <asm/sclp.h>
89
#include <asm/sections.h>
@@ -24,6 +25,7 @@ unsigned int __bootdata_preserved(zlib_dfltcc_support) = ZLIB_DFLTCC_FULL;
2425
struct ipl_parameter_block __bootdata_preserved(ipl_block);
2526
int __bootdata_preserved(ipl_block_valid);
2627
int __bootdata_preserved(__kaslr_enabled);
28+
int __bootdata_preserved(cmma_flag) = 1;
2729

2830
unsigned long vmalloc_size = VMALLOC_DEFAULT_SIZE;
2931
unsigned long memory_limit;
@@ -295,6 +297,12 @@ void parse_boot_command_line(void)
295297
if (!strcmp(param, "nokaslr"))
296298
__kaslr_enabled = 0;
297299

300+
if (!strcmp(param, "cmma")) {
301+
rc = kstrtobool(val, &enabled);
302+
if (!rc && !enabled)
303+
cmma_flag = 0;
304+
}
305+
298306
#if IS_ENABLED(CONFIG_KVM)
299307
if (!strcmp(param, "prot_virt")) {
300308
rc = kstrtobool(val, &enabled);

arch/s390/boot/startup.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: GPL-2.0
22
#include <linux/string.h>
33
#include <linux/elf.h>
4+
#include <asm/page-states.h>
45
#include <asm/boot_data.h>
56
#include <asm/sections.h>
67
#include <asm/maccess.h>
@@ -57,6 +58,48 @@ static void detect_facilities(void)
5758
machine.has_nx = 1;
5859
}
5960

61+
static int cmma_test_essa(void)
62+
{
63+
unsigned long reg1, reg2, tmp = 0;
64+
int rc = 1;
65+
psw_t old;
66+
67+
/* Test ESSA_GET_STATE */
68+
asm volatile(
69+
" mvc 0(16,%[psw_old]),0(%[psw_pgm])\n"
70+
" epsw %[reg1],%[reg2]\n"
71+
" st %[reg1],0(%[psw_pgm])\n"
72+
" st %[reg2],4(%[psw_pgm])\n"
73+
" larl %[reg1],1f\n"
74+
" stg %[reg1],8(%[psw_pgm])\n"
75+
" .insn rrf,0xb9ab0000,%[tmp],%[tmp],%[cmd],0\n"
76+
" la %[rc],0\n"
77+
"1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n"
78+
: [reg1] "=&d" (reg1),
79+
[reg2] "=&a" (reg2),
80+
[rc] "+&d" (rc),
81+
[tmp] "=&d" (tmp),
82+
"+Q" (S390_lowcore.program_new_psw),
83+
"=Q" (old)
84+
: [psw_old] "a" (&old),
85+
[psw_pgm] "a" (&S390_lowcore.program_new_psw),
86+
[cmd] "i" (ESSA_GET_STATE)
87+
: "cc", "memory");
88+
return rc;
89+
}
90+
91+
static void cmma_init(void)
92+
{
93+
if (!cmma_flag)
94+
return;
95+
if (cmma_test_essa()) {
96+
cmma_flag = 0;
97+
return;
98+
}
99+
if (test_facility(147))
100+
cmma_flag = 2;
101+
}
102+
60103
static void setup_lpp(void)
61104
{
62105
S390_lowcore.current_pid = 0;
@@ -306,6 +349,7 @@ void startup_kernel(void)
306349
setup_boot_command_line();
307350
parse_boot_command_line();
308351
detect_facilities();
352+
cmma_init();
309353
sanitize_prot_virt_host();
310354
max_physmem_end = detect_max_physmem_end();
311355
setup_ident_map_size(max_physmem_end);

arch/s390/boot/vmem.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <linux/sched/task.h>
33
#include <linux/pgtable.h>
44
#include <linux/kasan.h>
5+
#include <asm/page-states.h>
56
#include <asm/pgalloc.h>
67
#include <asm/facility.h>
78
#include <asm/sections.h>
@@ -70,6 +71,10 @@ static void kasan_populate_shadow(void)
7071
crst_table_init((unsigned long *)kasan_early_shadow_pud, pud_val(pud_z));
7172
crst_table_init((unsigned long *)kasan_early_shadow_pmd, pmd_val(pmd_z));
7273
memset64((u64 *)kasan_early_shadow_pte, pte_val(pte_z), PTRS_PER_PTE);
74+
__arch_set_page_dat(kasan_early_shadow_p4d, 1UL << CRST_ALLOC_ORDER);
75+
__arch_set_page_dat(kasan_early_shadow_pud, 1UL << CRST_ALLOC_ORDER);
76+
__arch_set_page_dat(kasan_early_shadow_pmd, 1UL << CRST_ALLOC_ORDER);
77+
__arch_set_page_dat(kasan_early_shadow_pte, 1);
7378

7479
/*
7580
* Current memory layout:
@@ -223,6 +228,7 @@ static void *boot_crst_alloc(unsigned long val)
223228

224229
table = (unsigned long *)physmem_alloc_top_down(RR_VMEM, size, size);
225230
crst_table_init(table, val);
231+
__arch_set_page_dat(table, 1UL << CRST_ALLOC_ORDER);
226232
return table;
227233
}
228234

@@ -238,6 +244,7 @@ static pte_t *boot_pte_alloc(void)
238244
if (!pte_leftover) {
239245
pte_leftover = (void *)physmem_alloc_top_down(RR_VMEM, PAGE_SIZE, PAGE_SIZE);
240246
pte = pte_leftover + _PAGE_TABLE_SIZE;
247+
__arch_set_page_dat(pte, 1);
241248
} else {
242249
pte = pte_leftover;
243250
pte_leftover = NULL;
@@ -418,6 +425,14 @@ void setup_vmem(unsigned long asce_limit)
418425
unsigned long asce_bits;
419426
int i;
420427

428+
/*
429+
* Mark whole memory as no-dat. This must be done before any
430+
* page tables are allocated, or kernel image builtin pages
431+
* are marked as dat tables.
432+
*/
433+
for_each_physmem_online_range(i, &start, &end)
434+
__arch_set_page_nodat((void *)start, (end - start) >> PAGE_SHIFT);
435+
421436
if (asce_limit == _REGION1_SIZE) {
422437
asce_type = _REGION2_ENTRY_EMPTY;
423438
asce_bits = _ASCE_TYPE_REGION2 | _ASCE_TABLE_LENGTH;
@@ -429,6 +444,8 @@ void setup_vmem(unsigned long asce_limit)
429444

430445
crst_table_init((unsigned long *)swapper_pg_dir, asce_type);
431446
crst_table_init((unsigned long *)invalid_pg_dir, _REGION3_ENTRY_EMPTY);
447+
__arch_set_page_dat((void *)swapper_pg_dir, 1UL << CRST_ALLOC_ORDER);
448+
__arch_set_page_dat((void *)invalid_pg_dir, 1UL << CRST_ALLOC_ORDER);
432449

433450
/*
434451
* To allow prefixing the lowcore must be mapped with 4KB pages.

arch/s390/include/asm/mmu.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ typedef struct {
1111
cpumask_t cpu_attach_mask;
1212
atomic_t flush_count;
1313
unsigned int flush_mm;
14-
struct list_head pgtable_list;
1514
struct list_head gmap_list;
1615
unsigned long gmap_asce;
1716
unsigned long asce;
@@ -39,7 +38,6 @@ typedef struct {
3938

4039
#define INIT_MM_CONTEXT(name) \
4140
.context.lock = __SPIN_LOCK_UNLOCKED(name.context.lock), \
42-
.context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list), \
4341
.context.gmap_list = LIST_HEAD_INIT(name.context.gmap_list),
4442

4543
#endif

arch/s390/include/asm/mmu_context.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ static inline int init_new_context(struct task_struct *tsk,
2222
unsigned long asce_type, init_entry;
2323

2424
spin_lock_init(&mm->context.lock);
25-
INIT_LIST_HEAD(&mm->context.pgtable_list);
2625
INIT_LIST_HEAD(&mm->context.gmap_list);
2726
cpumask_clear(&mm->context.cpu_attach_mask);
2827
atomic_set(&mm->context.flush_count, 0);

arch/s390/include/asm/page-states.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
#ifndef PAGE_STATES_H
88
#define PAGE_STATES_H
99

10+
#include <asm/sections.h>
11+
#include <asm/page.h>
12+
1013
#define ESSA_GET_STATE 0
1114
#define ESSA_SET_STABLE 1
1215
#define ESSA_SET_UNUSED 2
@@ -18,4 +21,60 @@
1821

1922
#define ESSA_MAX ESSA_SET_STABLE_NODAT
2023

24+
extern int __bootdata_preserved(cmma_flag);
25+
26+
static __always_inline unsigned long essa(unsigned long paddr, unsigned char cmd)
27+
{
28+
unsigned long rc;
29+
30+
asm volatile(
31+
" .insn rrf,0xb9ab0000,%[rc],%[paddr],%[cmd],0"
32+
: [rc] "=d" (rc)
33+
: [paddr] "d" (paddr),
34+
[cmd] "i" (cmd));
35+
return rc;
36+
}
37+
38+
static __always_inline void __set_page_state(void *addr, unsigned long num_pages, unsigned char cmd)
39+
{
40+
unsigned long paddr = __pa(addr) & PAGE_MASK;
41+
42+
while (num_pages--) {
43+
essa(paddr, cmd);
44+
paddr += PAGE_SIZE;
45+
}
46+
}
47+
48+
static inline void __set_page_unused(void *addr, unsigned long num_pages)
49+
{
50+
__set_page_state(addr, num_pages, ESSA_SET_UNUSED);
51+
}
52+
53+
static inline void __set_page_stable_dat(void *addr, unsigned long num_pages)
54+
{
55+
__set_page_state(addr, num_pages, ESSA_SET_STABLE);
56+
}
57+
58+
static inline void __set_page_stable_nodat(void *addr, unsigned long num_pages)
59+
{
60+
__set_page_state(addr, num_pages, ESSA_SET_STABLE_NODAT);
61+
}
62+
63+
static inline void __arch_set_page_nodat(void *addr, unsigned long num_pages)
64+
{
65+
if (!cmma_flag)
66+
return;
67+
if (cmma_flag < 2)
68+
__set_page_stable_dat(addr, num_pages);
69+
else
70+
__set_page_stable_nodat(addr, num_pages);
71+
}
72+
73+
static inline void __arch_set_page_dat(void *addr, unsigned long num_pages)
74+
{
75+
if (!cmma_flag)
76+
return;
77+
__set_page_stable_dat(addr, num_pages);
78+
}
79+
2180
#endif

arch/s390/include/asm/page.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ static inline int page_reset_referenced(unsigned long addr)
164164
struct page;
165165
void arch_free_page(struct page *page, int order);
166166
void arch_alloc_page(struct page *page, int order);
167-
void arch_set_page_dat(struct page *page, int order);
168167

169168
static inline int devmem_is_allowed(unsigned long pfn)
170169
{

arch/s390/include/asm/pgalloc.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ void crst_table_free(struct mm_struct *, unsigned long *);
2525
unsigned long *page_table_alloc(struct mm_struct *);
2626
struct page *page_table_alloc_pgste(struct mm_struct *mm);
2727
void page_table_free(struct mm_struct *, unsigned long *);
28-
void page_table_free_rcu(struct mmu_gather *, unsigned long *, unsigned long);
2928
void page_table_free_pgste(struct page *page);
3029
extern int page_table_allocate_pgste;
3130

arch/s390/include/asm/setup.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,6 @@ static inline void vmcp_cma_reserve(void) { }
125125

126126
void report_user_fault(struct pt_regs *regs, long signr, int is_mm_fault);
127127

128-
void cmma_init(void);
129-
void cmma_init_nodat(void);
130-
131128
extern void (*_machine_restart)(char *command);
132129
extern void (*_machine_halt)(void);
133130
extern void (*_machine_power_off)(void);

arch/s390/include/asm/stacktrace.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66
#include <linux/ptrace.h>
77
#include <asm/switch_to.h>
88

9+
struct stack_frame_user {
10+
unsigned long back_chain;
11+
unsigned long empty1[5];
12+
unsigned long gprs[10];
13+
unsigned long empty2[4];
14+
};
15+
916
enum stack_type {
1017
STACK_TYPE_UNKNOWN,
1118
STACK_TYPE_TASK,

arch/s390/include/asm/tlb.h

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,9 @@ static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
6969
tlb->mm->context.flush_mm = 1;
7070
tlb->freed_tables = 1;
7171
tlb->cleared_pmds = 1;
72-
/*
73-
* page_table_free_rcu takes care of the allocation bit masks
74-
* of the 2K table fragments in the 4K page table page,
75-
* then calls tlb_remove_table.
76-
*/
77-
page_table_free_rcu(tlb, (unsigned long *) pte, address);
72+
if (mm_alloc_pgste(tlb->mm))
73+
gmap_unlink(tlb->mm, (unsigned long *)pte, address);
74+
tlb_remove_ptdesc(tlb, pte);
7875
}
7976

8077
/*
@@ -112,7 +109,7 @@ static inline void p4d_free_tlb(struct mmu_gather *tlb, p4d_t *p4d,
112109
__tlb_adjust_range(tlb, address, PAGE_SIZE);
113110
tlb->mm->context.flush_mm = 1;
114111
tlb->freed_tables = 1;
115-
tlb_remove_table(tlb, p4d);
112+
tlb_remove_ptdesc(tlb, p4d);
116113
}
117114

118115
/*
@@ -130,7 +127,7 @@ static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,
130127
tlb->mm->context.flush_mm = 1;
131128
tlb->freed_tables = 1;
132129
tlb->cleared_p4ds = 1;
133-
tlb_remove_table(tlb, pud);
130+
tlb_remove_ptdesc(tlb, pud);
134131
}
135132

136133

arch/s390/kernel/early.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ decompressor_handled_param(vmalloc);
4646
decompressor_handled_param(dfltcc);
4747
decompressor_handled_param(facilities);
4848
decompressor_handled_param(nokaslr);
49+
decompressor_handled_param(cmma);
4950
#if IS_ENABLED(CONFIG_KVM)
5051
decompressor_handled_param(prot_virt);
5152
#endif

arch/s390/kernel/perf_event.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
#include <linux/export.h>
1616
#include <linux/seq_file.h>
1717
#include <linux/spinlock.h>
18+
#include <linux/uaccess.h>
19+
#include <linux/compat.h>
1820
#include <linux/sysfs.h>
21+
#include <asm/stacktrace.h>
1922
#include <asm/irq.h>
2023
#include <asm/cpu_mf.h>
2124
#include <asm/lowcore.h>
@@ -212,6 +215,44 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
212215
}
213216
}
214217

218+
void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
219+
struct pt_regs *regs)
220+
{
221+
struct stack_frame_user __user *sf;
222+
unsigned long ip, sp;
223+
bool first = true;
224+
225+
if (is_compat_task())
226+
return;
227+
perf_callchain_store(entry, instruction_pointer(regs));
228+
sf = (void __user *)user_stack_pointer(regs);
229+
pagefault_disable();
230+
while (entry->nr < entry->max_stack) {
231+
if (__get_user(sp, &sf->back_chain))
232+
break;
233+
if (__get_user(ip, &sf->gprs[8]))
234+
break;
235+
if (ip & 0x1) {
236+
/*
237+
* If the instruction address is invalid, and this
238+
* is the first stack frame, assume r14 has not
239+
* been written to the stack yet. Otherwise exit.
240+
*/
241+
if (first && !(regs->gprs[14] & 0x1))
242+
ip = regs->gprs[14];
243+
else
244+
break;
245+
}
246+
perf_callchain_store(entry, ip);
247+
/* Sanity check: ABI requires SP to be aligned 8 bytes. */
248+
if (!sp || sp & 0x7)
249+
break;
250+
sf = (void __user *)sp;
251+
first = false;
252+
}
253+
pagefault_enable();
254+
}
255+
215256
/* Perf definitions for PMU event attributes in sysfs */
216257
ssize_t cpumf_events_sysfs_show(struct device *dev,
217258
struct device_attribute *attr, char *page)

0 commit comments

Comments
 (0)