mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 02:09:42 +00:00
![Bob Haarman](/assets/img/avatar_default.png)
commitd8ad6d39c3
upstream. 'jiffies' and 'jiffies_64' are meant to alias (two different symbols that share the same address). Most architectures make the symbols alias to the same address via a linker script assignment in their arch/<arch>/kernel/vmlinux.lds.S: jiffies = jiffies_64; which is effectively a definition of jiffies. jiffies and jiffies_64 are both forward declared for all architectures in include/linux/jiffies.h. jiffies_64 is defined in kernel/time/timer.c. x86_64 was peculiar in that it wasn't doing the above linker script assignment, but rather was: 1. defining jiffies in arch/x86/kernel/time.c instead via the linker script. 2. overriding the symbol jiffies_64 from kernel/time/timer.c in arch/x86/kernel/vmlinux.lds.s via 'jiffies_64 = jiffies;'. As Fangrui notes: In LLD, symbol assignments in linker scripts override definitions in object files. GNU ld appears to have the same behavior. It would probably make sense for LLD to error "duplicate symbol" but GNU ld is unlikely to adopt for compatibility reasons. This results in an ODR violation (UB), which seems to have survived thus far. Where it becomes harmful is when; 1. -fno-semantic-interposition is used: As Fangrui notes: Clang after LLVM commit 5b22bcc2b70d ("[X86][ELF] Prefer to lower MC_GlobalAddress operands to .Lfoo$local") defaults to -fno-semantic-interposition similar semantics which help -fpic/-fPIC code avoid GOT/PLT when the referenced symbol is defined within the same translation unit. Unlike GCC -fno-semantic-interposition, Clang emits such relocations referencing local symbols for non-pic code as well. This causes references to jiffies to refer to '.Ljiffies$local' when jiffies is defined in the same translation unit. Likewise, references to jiffies_64 become references to '.Ljiffies_64$local' in translation units that define jiffies_64. Because these differ from the names used in the linker script, they will not be rewritten to alias one another. 2. Full LTO Full LTO effectively treats all source files as one translation unit, causing these local references to be produced everywhere. When the linker processes the linker script, there are no longer any references to jiffies_64' anywhere to replace with 'jiffies'. And thus '.Ljiffies$local' and '.Ljiffies_64$local' no longer alias at all. In the process of porting patches enabling Full LTO from arm64 to x86_64, spooky bugs have been observed where the kernel appeared to boot, but init doesn't get scheduled. Avoid the ODR violation by matching other architectures and define jiffies only by linker script. For -fno-semantic-interposition + Full LTO, there is no longer a global definition of jiffies for the compiler to produce a local symbol which the linker script won't ensure aliases to jiffies_64. Fixes:40747ffa5a
("asmlinkage: Make jiffies visible") Reported-by: Nathan Chancellor <natechancellor@gmail.com> Reported-by: Alistair Delva <adelva@google.com> Debugged-by: Nick Desaulniers <ndesaulniers@google.com> Debugged-by: Sami Tolvanen <samitolvanen@google.com> Suggested-by: Fangrui Song <maskray@google.com> Signed-off-by: Bob Haarman <inglorion@google.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Sedat Dilek <sedat.dilek@gmail.com> # build+boot on Reviewed-by: Andi Kleen <ak@linux.intel.com> Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com> Cc: stable@vger.kernel.org Link: https://github.com/ClangBuiltLinux/linux/issues/852 Link: https://lkml.kernel.org/r/20200602193100.229287-1-inglorion@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
135 lines
3.1 KiB
C
135 lines
3.1 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 1991,1992,1995 Linus Torvalds
|
|
* Copyright (c) 1994 Alan Modra
|
|
* Copyright (c) 1995 Markus Kuhn
|
|
* Copyright (c) 1996 Ingo Molnar
|
|
* Copyright (c) 1998 Andrea Arcangeli
|
|
* Copyright (c) 2002,2006 Vojtech Pavlik
|
|
* Copyright (c) 2003 Andi Kleen
|
|
*
|
|
*/
|
|
|
|
#include <linux/clocksource.h>
|
|
#include <linux/clockchips.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/i8253.h>
|
|
#include <linux/time.h>
|
|
#include <linux/export.h>
|
|
|
|
#include <asm/vsyscall.h>
|
|
#include <asm/x86_init.h>
|
|
#include <asm/i8259.h>
|
|
#include <asm/timer.h>
|
|
#include <asm/hpet.h>
|
|
#include <asm/time.h>
|
|
|
|
unsigned long profile_pc(struct pt_regs *regs)
|
|
{
|
|
unsigned long pc = instruction_pointer(regs);
|
|
|
|
if (!user_mode(regs) && in_lock_functions(pc)) {
|
|
#ifdef CONFIG_FRAME_POINTER
|
|
return *(unsigned long *)(regs->bp + sizeof(long));
|
|
#else
|
|
unsigned long *sp = (unsigned long *)regs->sp;
|
|
/*
|
|
* Return address is either directly at stack pointer
|
|
* or above a saved flags. Eflags has bits 22-31 zero,
|
|
* kernel addresses don't.
|
|
*/
|
|
if (sp[0] >> 22)
|
|
return sp[0];
|
|
if (sp[1] >> 22)
|
|
return sp[1];
|
|
#endif
|
|
}
|
|
return pc;
|
|
}
|
|
EXPORT_SYMBOL(profile_pc);
|
|
|
|
/*
|
|
* Default timer interrupt handler for PIT/HPET
|
|
*/
|
|
static irqreturn_t timer_interrupt(int irq, void *dev_id)
|
|
{
|
|
global_clock_event->event_handler(global_clock_event);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static struct irqaction irq0 = {
|
|
.handler = timer_interrupt,
|
|
.flags = IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
|
|
.name = "timer"
|
|
};
|
|
|
|
static void __init setup_default_timer_irq(void)
|
|
{
|
|
/*
|
|
* Unconditionally register the legacy timer; even without legacy
|
|
* PIC/PIT we need this for the HPET0 in legacy replacement mode.
|
|
*/
|
|
if (setup_irq(0, &irq0))
|
|
pr_info("Failed to register legacy timer interrupt\n");
|
|
}
|
|
|
|
/* Default timer init function */
|
|
void __init hpet_time_init(void)
|
|
{
|
|
if (!hpet_enable()) {
|
|
if (!pit_timer_init())
|
|
return;
|
|
}
|
|
|
|
setup_default_timer_irq();
|
|
}
|
|
|
|
static __init void x86_late_time_init(void)
|
|
{
|
|
/*
|
|
* Before PIT/HPET init, select the interrupt mode. This is required
|
|
* to make the decision whether PIT should be initialized correct.
|
|
*/
|
|
x86_init.irqs.intr_mode_select();
|
|
|
|
/* Setup the legacy timers */
|
|
x86_init.timers.timer_init();
|
|
|
|
/*
|
|
* After PIT/HPET timers init, set up the final interrupt mode for
|
|
* delivering IRQs.
|
|
*/
|
|
x86_init.irqs.intr_mode_init();
|
|
tsc_init();
|
|
}
|
|
|
|
/*
|
|
* Initialize TSC and delay the periodic timer init to
|
|
* late x86_late_time_init() so ioremap works.
|
|
*/
|
|
void __init time_init(void)
|
|
{
|
|
late_time_init = x86_late_time_init;
|
|
}
|
|
|
|
/*
|
|
* Sanity check the vdso related archdata content.
|
|
*/
|
|
void clocksource_arch_init(struct clocksource *cs)
|
|
{
|
|
if (cs->archdata.vclock_mode == VCLOCK_NONE)
|
|
return;
|
|
|
|
if (cs->archdata.vclock_mode > VCLOCK_MAX) {
|
|
pr_warn("clocksource %s registered with invalid vclock_mode %d. Disabling vclock.\n",
|
|
cs->name, cs->archdata.vclock_mode);
|
|
cs->archdata.vclock_mode = VCLOCK_NONE;
|
|
}
|
|
|
|
if (cs->mask != CLOCKSOURCE_MASK(64)) {
|
|
pr_warn("clocksource %s registered with invalid mask %016llx. Disabling vclock.\n",
|
|
cs->name, cs->mask);
|
|
cs->archdata.vclock_mode = VCLOCK_NONE;
|
|
}
|
|
}
|