mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
The basic idea is to have __WARN_printf() be a vararg function such
that the compiler can do the optimal calling convention for us. This
function body will be a #UD and then set up a va_list in the exception
from pt_regs.
But because the trap will be in a called function, the bug_entry must
be passed in. Have that be the first argument, with the format tucked
away inside the bug_entry.
The comments should clarify the real fun details.
The big downside is that all WARNs will now show:
RIP: 0010:__WARN_trap:+0
One possible solution is to simply discard the top frame when
unwinding. A follow up patch takes care of this slightly differently
by abusing the x86 static_call implementation.
This changes (with the next patches):
WARN_ONCE(preempt_count() != 2*PREEMPT_DISABLE_OFFSET,
"corrupted preempt_count: %s/%d/0x%x\n",
from:
cmpl $2, %ecx #, _7
jne .L1472
...
.L1472:
cmpb $0, __already_done.11(%rip)
je .L1513
...
.L1513
movb $1, __already_done.11(%rip)
movl 1424(%r14), %edx # _15->pid, _15->pid
leaq 1912(%r14), %rsi #, _17
movq $.LC43, %rdi #,
call __warn_printk #
ud2
.pushsection __bug_table,"aw"
2:
.long 1b - . # bug_entry::bug_addr
.long .LC1 - . # bug_entry::file
.word 5093 # bug_entry::line
.word 2313 # bug_entry::flags
.org 2b + 12
.popsection
.pushsection .discard.annotate_insn,"M", @progbits, 8
.long 1b - .
.long 8 # ANNOTYPE_REACHABLE
.popsection
into:
cmpl $2, %ecx #, _7
jne .L1442 #,
...
.L1442:
lea (2f)(%rip), %rdi
1:
.pushsection __bug_table,"aw"
2:
.long 1b - . # bug_entry::bug_addr
.long .LC43 - . # bug_entry::format
.long .LC1 - . # bug_entry::file
.word 5093 # bug_entry::line
.word 2323 # bug_entry::flags
.org 2b + 16
.popsection
movl 1424(%r14), %edx # _19->pid, _19->pid
leaq 1912(%r14), %rsi #, _13
ud1 (%edx), %rdi
Notably, by pushing everything into the exception handler it can take
care of the ONCE thing.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20251110115758.213813530@infradead.org
79 lines
2.1 KiB
ArmAsm
79 lines
2.1 KiB
ArmAsm
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Common place for both 32- and 64-bit entry routines.
|
|
*/
|
|
|
|
#include <linux/export.h>
|
|
#include <linux/linkage.h>
|
|
#include <linux/objtool.h>
|
|
#include <asm/msr-index.h>
|
|
#include <asm/unwind_hints.h>
|
|
#include <asm/segment.h>
|
|
#include <asm/cache.h>
|
|
#include <asm/cpufeatures.h>
|
|
#include <asm/nospec-branch.h>
|
|
|
|
#include "calling.h"
|
|
|
|
.pushsection .noinstr.text, "ax"
|
|
|
|
/* Clobbers AX, CX, DX */
|
|
SYM_FUNC_START(write_ibpb)
|
|
ANNOTATE_NOENDBR
|
|
movl $MSR_IA32_PRED_CMD, %ecx
|
|
movl _ASM_RIP(x86_pred_cmd), %eax
|
|
xorl %edx, %edx
|
|
wrmsr
|
|
|
|
/* Make sure IBPB clears return stack preductions too. */
|
|
FILL_RETURN_BUFFER %rax, RSB_CLEAR_LOOPS, X86_BUG_IBPB_NO_RET
|
|
RET
|
|
SYM_FUNC_END(write_ibpb)
|
|
/* For KVM */
|
|
EXPORT_SYMBOL_GPL(write_ibpb);
|
|
|
|
SYM_FUNC_START(__WARN_trap)
|
|
ANNOTATE_NOENDBR
|
|
ANNOTATE_REACHABLE
|
|
ud1 (%edx), %_ASM_ARG1
|
|
RET
|
|
SYM_FUNC_END(__WARN_trap)
|
|
EXPORT_SYMBOL(__WARN_trap)
|
|
|
|
.popsection
|
|
|
|
/*
|
|
* Define the VERW operand that is disguised as entry code so that
|
|
* it can be referenced with KPTI enabled. This ensures VERW can be
|
|
* used late in exit-to-user path after page tables are switched.
|
|
*/
|
|
.pushsection .entry.text, "ax"
|
|
|
|
.align L1_CACHE_BYTES, 0xcc
|
|
SYM_CODE_START_NOALIGN(x86_verw_sel)
|
|
UNWIND_HINT_UNDEFINED
|
|
ANNOTATE_NOENDBR
|
|
.word __KERNEL_DS
|
|
.align L1_CACHE_BYTES, 0xcc
|
|
SYM_CODE_END(x86_verw_sel);
|
|
/* For KVM */
|
|
EXPORT_SYMBOL_GPL(x86_verw_sel);
|
|
|
|
.popsection
|
|
|
|
THUNK warn_thunk_thunk, __warn_thunk
|
|
|
|
/*
|
|
* Clang's implementation of TLS stack cookies requires the variable in
|
|
* question to be a TLS variable. If the variable happens to be defined as an
|
|
* ordinary variable with external linkage in the same compilation unit (which
|
|
* amounts to the whole of vmlinux with LTO enabled), Clang will drop the
|
|
* segment register prefix from the references, resulting in broken code. Work
|
|
* around this by avoiding the symbol used in -mstack-protector-guard-symbol=
|
|
* entirely in the C code, and use an alias emitted by the linker script
|
|
* instead.
|
|
*/
|
|
#if defined(CONFIG_STACKPROTECTOR) && defined(CONFIG_SMP)
|
|
EXPORT_SYMBOL(__ref_stack_chk_guard);
|
|
#endif
|