powerpc/security: Allow for processors that flush the link stack using the special bcctr

If both count cache and link stack are to be flushed, and can be flushed
with the special bcctr, patch that in directly to the flush/branch nop
site.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200609070610.846703-7-npiggin@gmail.com
This commit is contained in:
Nicholas Piggin 2020-06-09 17:06:09 +10:00 committed by Michael Ellerman
parent 70d7cdaf05
commit 4d24e21cc6
2 changed files with 21 additions and 8 deletions

View File

@ -63,6 +63,8 @@ static inline bool security_ftr_enabled(u64 feature)
// bcctr 2,0,0 triggers a hardware assisted count cache flush // bcctr 2,0,0 triggers a hardware assisted count cache flush
#define SEC_FTR_BCCTR_FLUSH_ASSIST 0x0000000000000800ull #define SEC_FTR_BCCTR_FLUSH_ASSIST 0x0000000000000800ull
// bcctr 2,0,0 triggers a hardware assisted link stack flush
#define SEC_FTR_BCCTR_LINK_FLUSH_ASSIST 0x0000000000002000ull
// Features indicating need for Spectre/Meltdown mitigations // Features indicating need for Spectre/Meltdown mitigations

View File

@ -219,24 +219,25 @@ ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, c
if (ccd) if (ccd)
seq_buf_printf(&s, "Indirect branch cache disabled"); seq_buf_printf(&s, "Indirect branch cache disabled");
if (link_stack_flush_type == BRANCH_CACHE_FLUSH_SW)
seq_buf_printf(&s, ", Software link stack flush");
} else if (count_cache_flush_type != BRANCH_CACHE_FLUSH_NONE) { } else if (count_cache_flush_type != BRANCH_CACHE_FLUSH_NONE) {
seq_buf_printf(&s, "Mitigation: Software count cache flush"); seq_buf_printf(&s, "Mitigation: Software count cache flush");
if (count_cache_flush_type == BRANCH_CACHE_FLUSH_HW) if (count_cache_flush_type == BRANCH_CACHE_FLUSH_HW)
seq_buf_printf(&s, " (hardware accelerated)"); seq_buf_printf(&s, " (hardware accelerated)");
if (link_stack_flush_type == BRANCH_CACHE_FLUSH_SW)
seq_buf_printf(&s, ", Software link stack flush");
} else if (btb_flush_enabled) { } else if (btb_flush_enabled) {
seq_buf_printf(&s, "Mitigation: Branch predictor state flush"); seq_buf_printf(&s, "Mitigation: Branch predictor state flush");
} else { } else {
seq_buf_printf(&s, "Vulnerable"); seq_buf_printf(&s, "Vulnerable");
} }
if (bcs || ccd || count_cache_flush_type != BRANCH_CACHE_FLUSH_NONE) {
if (link_stack_flush_type != BRANCH_CACHE_FLUSH_NONE)
seq_buf_printf(&s, ", Software link stack flush");
if (link_stack_flush_type == BRANCH_CACHE_FLUSH_HW)
seq_buf_printf(&s, " (hardware accelerated)");
}
seq_buf_printf(&s, "\n"); seq_buf_printf(&s, "\n");
return s.len; return s.len;
@ -435,6 +436,7 @@ static void update_branch_cache_flush(void)
patch_instruction_site(&patch__call_kvm_flush_link_stack, patch_instruction_site(&patch__call_kvm_flush_link_stack,
ppc_inst(PPC_INST_NOP)); ppc_inst(PPC_INST_NOP));
} else { } else {
// Could use HW flush, but that could also flush count cache
patch_branch_site(&patch__call_kvm_flush_link_stack, patch_branch_site(&patch__call_kvm_flush_link_stack,
(u64)&kvm_flush_link_stack, BRANCH_SET_LINK); (u64)&kvm_flush_link_stack, BRANCH_SET_LINK);
} }
@ -445,6 +447,10 @@ static void update_branch_cache_flush(void)
link_stack_flush_type == BRANCH_CACHE_FLUSH_NONE) { link_stack_flush_type == BRANCH_CACHE_FLUSH_NONE) {
patch_instruction_site(&patch__call_flush_branch_caches, patch_instruction_site(&patch__call_flush_branch_caches,
ppc_inst(PPC_INST_NOP)); ppc_inst(PPC_INST_NOP));
} else if (count_cache_flush_type == BRANCH_CACHE_FLUSH_HW &&
link_stack_flush_type == BRANCH_CACHE_FLUSH_HW) {
patch_instruction_site(&patch__call_flush_branch_caches,
ppc_inst(PPC_INST_BCCTR_FLUSH));
} else { } else {
patch_branch_site(&patch__call_flush_branch_caches, patch_branch_site(&patch__call_flush_branch_caches,
(u64)&flush_branch_caches, BRANCH_SET_LINK); (u64)&flush_branch_caches, BRANCH_SET_LINK);
@ -485,8 +491,13 @@ static void toggle_branch_cache_flush(bool enable)
pr_info("link-stack-flush: flush disabled.\n"); pr_info("link-stack-flush: flush disabled.\n");
} else { } else {
link_stack_flush_type = BRANCH_CACHE_FLUSH_SW; if (security_ftr_enabled(SEC_FTR_BCCTR_LINK_FLUSH_ASSIST)) {
pr_info("link-stack-flush: software flush enabled.\n"); link_stack_flush_type = BRANCH_CACHE_FLUSH_HW;
pr_info("link-stack-flush: hardware flush enabled.\n");
} else {
link_stack_flush_type = BRANCH_CACHE_FLUSH_SW;
pr_info("link-stack-flush: software flush enabled.\n");
}
} }
update_branch_cache_flush(); update_branch_cache_flush();