4df05f3619
Since the IDT is referenced from a fixmap, make sure it is page aligned. Merge with 32-bit one, since it was already aligned to deal with F00F bug. Since bss is cleared before IDT setup, it can live there. This also moves the other *_idt_table variables into common locations. This avoids the risk of the IDT ever being moved in the bss and having the mapping be offset, resulting in calling incorrect handlers. In the current upstream kernel this is not a manifested bug, but heavily patched kernels (such as those using the PaX patch series) did encounter this bug. The tables other than idt_table technically do not need to be page aligned, at least not at the current time, but using a common declaration avoids mistakes. On 64 bits the table is exactly one page long, anyway. Signed-off-by: Kees Cook <keescook@chromium.org> Link: http://lkml.kernel.org/r/20130716183441.GA14232@www.outflux.net Reported-by: PaX Team <pageexec@gmail.com> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
59 lines
1.3 KiB
C
59 lines
1.3 KiB
C
/*
|
|
* Code for supporting irq vector tracepoints.
|
|
*
|
|
* Copyright (C) 2013 Seiji Aguchi <seiji.aguchi@hds.com>
|
|
*
|
|
*/
|
|
#include <asm/hw_irq.h>
|
|
#include <asm/desc.h>
|
|
#include <linux/atomic.h>
|
|
|
|
atomic_t trace_idt_ctr = ATOMIC_INIT(0);
|
|
struct desc_ptr trace_idt_descr = { NR_VECTORS * 16 - 1,
|
|
(unsigned long) trace_idt_table };
|
|
|
|
/* No need to be aligned, but done to keep all IDTs defined the same way. */
|
|
gate_desc trace_idt_table[NR_VECTORS] __page_aligned_bss;
|
|
|
|
static int trace_irq_vector_refcount;
|
|
static DEFINE_MUTEX(irq_vector_mutex);
|
|
|
|
static void set_trace_idt_ctr(int val)
|
|
{
|
|
atomic_set(&trace_idt_ctr, val);
|
|
/* Ensure the trace_idt_ctr is set before sending IPI */
|
|
wmb();
|
|
}
|
|
|
|
static void switch_idt(void *arg)
|
|
{
|
|
unsigned long flags;
|
|
|
|
local_irq_save(flags);
|
|
load_current_idt();
|
|
local_irq_restore(flags);
|
|
}
|
|
|
|
void trace_irq_vector_regfunc(void)
|
|
{
|
|
mutex_lock(&irq_vector_mutex);
|
|
if (!trace_irq_vector_refcount) {
|
|
set_trace_idt_ctr(1);
|
|
smp_call_function(switch_idt, NULL, 0);
|
|
switch_idt(NULL);
|
|
}
|
|
trace_irq_vector_refcount++;
|
|
mutex_unlock(&irq_vector_mutex);
|
|
}
|
|
|
|
void trace_irq_vector_unregfunc(void)
|
|
{
|
|
mutex_lock(&irq_vector_mutex);
|
|
trace_irq_vector_refcount--;
|
|
if (!trace_irq_vector_refcount) {
|
|
set_trace_idt_ctr(0);
|
|
smp_call_function(switch_idt, NULL, 0);
|
|
switch_idt(NULL);
|
|
}
|
|
mutex_unlock(&irq_vector_mutex);
|
|
}
|