Skip to content

Commit d768bd8

Browse files
author
Martin Schwidefsky
committed
s390: add options to change branch prediction behaviour for the kernel
Add the PPA instruction to the system entry and exit path to switch the kernel to a different branch prediction behaviour. The instructions are added via CPU alternatives and can be disabled with the "nospec" or the "nobp=0" kernel parameter. If the default behaviour selected with CONFIG_KERNEL_NOBP is set to "n" then the "nobp=1" parameter can be used to enable the changed kernel branch prediction. Acked-by: Cornelia Huck <[email protected]> Signed-off-by: Martin Schwidefsky <[email protected]>
1 parent cf14899 commit d768bd8

File tree

7 files changed

+94
-0
lines changed

7 files changed

+94
-0
lines changed

arch/s390/Kconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,23 @@ config ARCH_RANDOM
540540

541541
If unsure, say Y.
542542

543+
config KERNEL_NOBP
544+
def_bool n
545+
prompt "Enable modified branch prediction for the kernel by default"
546+
help
547+
If this option is selected the kernel will switch to a modified
548+
branch prediction mode if the firmware interface is available.
549+
The modified branch prediction mode improves the behaviour in
550+
regard to speculative execution.
551+
552+
With the option enabled the kernel parameter "nobp=0" or "nospec"
553+
can be used to run the kernel in the normal branch prediction mode.
554+
555+
With the option disabled the modified branch prediction mode is
556+
enabled with the "nobp=1" kernel parameter.
557+
558+
If unsure, say N.
559+
543560
endmenu
544561

545562
menu "Memory setup"

arch/s390/include/asm/processor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ void cpu_detect_mhz_feature(void);
9191
extern const struct seq_operations cpuinfo_op;
9292
extern int sysctl_ieee_emulation_warnings;
9393
extern void execve_tail(void);
94+
extern void __bpon(void);
9495

9596
/*
9697
* User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit.

arch/s390/kernel/alternative.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,29 @@ static int __init disable_alternative_instructions(char *str)
1515

1616
early_param("noaltinstr", disable_alternative_instructions);
1717

18+
static int __init nobp_setup_early(char *str)
19+
{
20+
bool enabled;
21+
int rc;
22+
23+
rc = kstrtobool(str, &enabled);
24+
if (rc)
25+
return rc;
26+
if (enabled && test_facility(82))
27+
__set_facility(82, S390_lowcore.alt_stfle_fac_list);
28+
else
29+
__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
30+
return 0;
31+
}
32+
early_param("nobp", nobp_setup_early);
33+
34+
static int __init nospec_setup_early(char *str)
35+
{
36+
__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
37+
return 0;
38+
}
39+
early_param("nospec", nospec_setup_early);
40+
1841
struct brcl_insn {
1942
u16 opc;
2043
s32 disp;

arch/s390/kernel/early.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ static noinline __init void setup_facility_list(void)
196196
memcpy(S390_lowcore.alt_stfle_fac_list,
197197
S390_lowcore.stfle_fac_list,
198198
sizeof(S390_lowcore.alt_stfle_fac_list));
199+
if (!IS_ENABLED(CONFIG_KERNEL_NOBP))
200+
__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
199201
}
200202

201203
static __init void detect_diag9c(void)

arch/s390/kernel/entry.S

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,34 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART)
159159
tm off+\addr, \mask
160160
.endm
161161

162+
.macro BPOFF
163+
.pushsection .altinstr_replacement, "ax"
164+
660: .long 0xb2e8c000
165+
.popsection
166+
661: .long 0x47000000
167+
.pushsection .altinstructions, "a"
168+
.long 661b - .
169+
.long 660b - .
170+
.word 82
171+
.byte 4
172+
.byte 4
173+
.popsection
174+
.endm
175+
176+
.macro BPON
177+
.pushsection .altinstr_replacement, "ax"
178+
662: .long 0xb2e8d000
179+
.popsection
180+
663: .long 0x47000000
181+
.pushsection .altinstructions, "a"
182+
.long 663b - .
183+
.long 662b - .
184+
.word 82
185+
.byte 4
186+
.byte 4
187+
.popsection
188+
.endm
189+
162190
.section .kprobes.text, "ax"
163191
.Ldummy:
164192
/*
@@ -171,6 +199,11 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART)
171199
*/
172200
nop 0
173201

202+
ENTRY(__bpon)
203+
.globl __bpon
204+
BPON
205+
br %r14
206+
174207
/*
175208
* Scheduler resume function, called by switch_to
176209
* gpr2 = (task_struct *) prev
@@ -226,8 +259,11 @@ ENTRY(sie64a)
226259
jnz .Lsie_skip
227260
TSTMSK __LC_CPU_FLAGS,_CIF_FPU
228261
jo .Lsie_skip # exit if fp/vx regs changed
262+
BPON
229263
.Lsie_entry:
230264
sie 0(%r14)
265+
.Lsie_exit:
266+
BPOFF
231267
.Lsie_skip:
232268
ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE
233269
lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
@@ -279,6 +315,7 @@ ENTRY(system_call)
279315
stpt __LC_SYNC_ENTER_TIMER
280316
.Lsysc_stmg:
281317
stmg %r8,%r15,__LC_SAVE_AREA_SYNC
318+
BPOFF
282319
lg %r12,__LC_CURRENT
283320
lghi %r13,__TASK_thread
284321
lghi %r14,_PIF_SYSCALL
@@ -325,6 +362,7 @@ ENTRY(system_call)
325362
jnz .Lsysc_work # check for work
326363
TSTMSK __LC_CPU_FLAGS,_CIF_WORK
327364
jnz .Lsysc_work
365+
BPON
328366
.Lsysc_restore:
329367
lg %r14,__LC_VDSO_PER_CPU
330368
lmg %r0,%r10,__PT_R0(%r11)
@@ -530,6 +568,7 @@ ENTRY(kernel_thread_starter)
530568

531569
ENTRY(pgm_check_handler)
532570
stpt __LC_SYNC_ENTER_TIMER
571+
BPOFF
533572
stmg %r8,%r15,__LC_SAVE_AREA_SYNC
534573
lg %r10,__LC_LAST_BREAK
535574
lg %r12,__LC_CURRENT
@@ -637,6 +676,7 @@ ENTRY(pgm_check_handler)
637676
ENTRY(io_int_handler)
638677
STCK __LC_INT_CLOCK
639678
stpt __LC_ASYNC_ENTER_TIMER
679+
BPOFF
640680
stmg %r8,%r15,__LC_SAVE_AREA_ASYNC
641681
lg %r12,__LC_CURRENT
642682
larl %r13,cleanup_critical
@@ -687,9 +727,13 @@ ENTRY(io_int_handler)
687727
lg %r14,__LC_VDSO_PER_CPU
688728
lmg %r0,%r10,__PT_R0(%r11)
689729
mvc __LC_RETURN_PSW(16),__PT_PSW(%r11)
730+
tm __PT_PSW+1(%r11),0x01 # returning to user ?
731+
jno .Lio_exit_kernel
732+
BPON
690733
.Lio_exit_timer:
691734
stpt __LC_EXIT_TIMER
692735
mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
736+
.Lio_exit_kernel:
693737
lmg %r11,%r15,__PT_R11(%r11)
694738
lpswe __LC_RETURN_PSW
695739
.Lio_done:
@@ -860,6 +904,7 @@ ENTRY(io_int_handler)
860904
ENTRY(ext_int_handler)
861905
STCK __LC_INT_CLOCK
862906
stpt __LC_ASYNC_ENTER_TIMER
907+
BPOFF
863908
stmg %r8,%r15,__LC_SAVE_AREA_ASYNC
864909
lg %r12,__LC_CURRENT
865910
larl %r13,cleanup_critical
@@ -908,6 +953,7 @@ ENTRY(psw_idle)
908953
.Lpsw_idle_stcctm:
909954
#endif
910955
oi __LC_CPU_FLAGS+7,_CIF_ENABLED_WAIT
956+
BPON
911957
STCK __CLOCK_IDLE_ENTER(%r2)
912958
stpt __TIMER_IDLE_ENTER(%r2)
913959
.Lpsw_idle_lpsw:
@@ -1008,6 +1054,7 @@ load_fpu_regs:
10081054
*/
10091055
ENTRY(mcck_int_handler)
10101056
STCK __LC_MCCK_CLOCK
1057+
BPOFF
10111058
la %r1,4095 # validate r1
10121059
spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # validate cpu timer
10131060
sckc __LC_CLOCK_COMPARATOR # validate comparator
@@ -1118,6 +1165,7 @@ ENTRY(mcck_int_handler)
11181165
mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW
11191166
tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
11201167
jno 0f
1168+
BPON
11211169
stpt __LC_EXIT_TIMER
11221170
mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
11231171
0: lmg %r11,%r15,__PT_R11(%r11)

arch/s390/kernel/ipl.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,7 @@ static struct kset *ipl_kset;
543543

544544
static void __ipl_run(void *unused)
545545
{
546+
__bpon();
546547
diag308(DIAG308_LOAD_CLEAR, NULL);
547548
if (MACHINE_IS_VM)
548549
__cpcmd("IPL", NULL, 0, NULL);

arch/s390/kernel/smp.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *),
319319
mem_assign_absolute(lc->restart_fn, (unsigned long) func);
320320
mem_assign_absolute(lc->restart_data, (unsigned long) data);
321321
mem_assign_absolute(lc->restart_source, source_cpu);
322+
__bpon();
322323
asm volatile(
323324
"0: sigp 0,%0,%2 # sigp restart to target cpu\n"
324325
" brc 2,0b # busy, try again\n"
@@ -903,6 +904,7 @@ void __cpu_die(unsigned int cpu)
903904
void __noreturn cpu_die(void)
904905
{
905906
idle_task_exit();
907+
__bpon();
906908
pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0);
907909
for (;;) ;
908910
}

0 commit comments

Comments
 (0)