mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-31 08:28:13 +00:00
1462eb381b
In order to allow objtool to make sense of all the various paravirt functions, it needs to either parse whole pv_ops[] tables, or observe individual assignments in the form: bf87: 48 c7 05 00 00 00 00 00 00 00 00 movq $0x0,0x0(%rip) bf92 <xen_init_spinlocks+0x5f> bf8a: R_X86_64_PC32 pv_ops+0x268 As is, xen_cpu_ops[] is at offset +0 in pv_ops[] and could thus be parsed as a 'normal' pv_ops[] table, however xen_irq_ops[] and xen_mmu_ops[] are not. Worse, both the latter two are compiled into the individual assignment for by current GCC, but that's not something one can rely on. Therefore, convert all three into full pv_ops[] tables. This has the benefit of not needing to teach objtool about the offsets and resulting in more conservative code-gen. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Juergen Gross <jgross@suse.com> Link: https://lore.kernel.org/r/20210624095149.057262522@infradead.org
113 lines
2.7 KiB
C
113 lines
2.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include <linux/hardirq.h>
|
|
|
|
#include <asm/x86_init.h>
|
|
|
|
#include <xen/interface/xen.h>
|
|
#include <xen/interface/sched.h>
|
|
#include <xen/interface/vcpu.h>
|
|
#include <xen/features.h>
|
|
#include <xen/events.h>
|
|
|
|
#include <asm/xen/hypercall.h>
|
|
#include <asm/xen/hypervisor.h>
|
|
|
|
#include "xen-ops.h"
|
|
|
|
/*
|
|
* Force a proper event-channel callback from Xen after clearing the
|
|
* callback mask. We do this in a very simple manner, by making a call
|
|
* down into Xen. The pending flag will be checked by Xen on return.
|
|
*/
|
|
noinstr void xen_force_evtchn_callback(void)
|
|
{
|
|
(void)HYPERVISOR_xen_version(0, NULL);
|
|
}
|
|
|
|
asmlinkage __visible noinstr unsigned long xen_save_fl(void)
|
|
{
|
|
struct vcpu_info *vcpu;
|
|
unsigned long flags;
|
|
|
|
vcpu = this_cpu_read(xen_vcpu);
|
|
|
|
/* flag has opposite sense of mask */
|
|
flags = !vcpu->evtchn_upcall_mask;
|
|
|
|
/* convert to IF type flag
|
|
-0 -> 0x00000000
|
|
-1 -> 0xffffffff
|
|
*/
|
|
return (-flags) & X86_EFLAGS_IF;
|
|
}
|
|
__PV_CALLEE_SAVE_REGS_THUNK(xen_save_fl, ".noinstr.text");
|
|
|
|
asmlinkage __visible noinstr void xen_irq_disable(void)
|
|
{
|
|
/* There's a one instruction preempt window here. We need to
|
|
make sure we're don't switch CPUs between getting the vcpu
|
|
pointer and updating the mask. */
|
|
preempt_disable();
|
|
this_cpu_read(xen_vcpu)->evtchn_upcall_mask = 1;
|
|
preempt_enable_no_resched();
|
|
}
|
|
__PV_CALLEE_SAVE_REGS_THUNK(xen_irq_disable, ".noinstr.text");
|
|
|
|
asmlinkage __visible noinstr void xen_irq_enable(void)
|
|
{
|
|
struct vcpu_info *vcpu;
|
|
|
|
/*
|
|
* We may be preempted as soon as vcpu->evtchn_upcall_mask is
|
|
* cleared, so disable preemption to ensure we check for
|
|
* events on the VCPU we are still running on.
|
|
*/
|
|
preempt_disable();
|
|
|
|
vcpu = this_cpu_read(xen_vcpu);
|
|
vcpu->evtchn_upcall_mask = 0;
|
|
|
|
/* Doesn't matter if we get preempted here, because any
|
|
pending event will get dealt with anyway. */
|
|
|
|
barrier(); /* unmask then check (avoid races) */
|
|
if (unlikely(vcpu->evtchn_upcall_pending))
|
|
xen_force_evtchn_callback();
|
|
|
|
preempt_enable();
|
|
}
|
|
__PV_CALLEE_SAVE_REGS_THUNK(xen_irq_enable, ".noinstr.text");
|
|
|
|
static void xen_safe_halt(void)
|
|
{
|
|
/* Blocking includes an implicit local_irq_enable(). */
|
|
if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0)
|
|
BUG();
|
|
}
|
|
|
|
static void xen_halt(void)
|
|
{
|
|
if (irqs_disabled())
|
|
HYPERVISOR_vcpu_op(VCPUOP_down,
|
|
xen_vcpu_nr(smp_processor_id()), NULL);
|
|
else
|
|
xen_safe_halt();
|
|
}
|
|
|
|
static const typeof(pv_ops) xen_irq_ops __initconst = {
|
|
.irq = {
|
|
|
|
.save_fl = PV_CALLEE_SAVE(xen_save_fl),
|
|
.irq_disable = PV_CALLEE_SAVE(xen_irq_disable),
|
|
.irq_enable = PV_CALLEE_SAVE(xen_irq_enable),
|
|
|
|
.safe_halt = xen_safe_halt,
|
|
.halt = xen_halt,
|
|
},
|
|
};
|
|
|
|
void __init xen_init_irq_ops(void)
|
|
{
|
|
pv_ops.irq = xen_irq_ops.irq;
|
|
x86_init.irqs.intr_init = xen_init_IRQ;
|
|
}
|