linux-headers/arch/e2k/include/asm/kvm/guest/system.h

228 lines
7.0 KiB
C

/*
* KVM guest processor and processes support
*
* Copyright (C) 2014 MCST
*/
#ifndef _E2K_KVM_GUEST_SYSTEM_H_
#define _E2K_KVM_GUEST_SYSTEM_H_
#ifndef __ASSEMBLY__
#include <linux/types.h>
#include <asm/kvm/cpu_regs_access.h>
/*
* Guest kernel case assumption is that the host emulates hardware updates
* of CPU registers state on trap or system call, in particular PSR state.
* Hardware disables interrupt masks and switch interrupts control to PSR,
* so host sets VCPU registers (copy into memory) in same state.
* Trap handler should switch interrupts control from PSR to UPSR
* previously it should set UPSR to initial state for kernel with disabled
* interrupts (so UPSR disable interrupts)
* If trap occurs on guest kernel, then interrupts should be enabled
* and control should be under UPSR. So do not restore control under PSR and
* restore only UPSR state.
* Guest kernel cannot use 'done' instruction and restore PSR state
* saved into CR1.lo register, it should be done by host.
*/
#define KVM_INIT_KERNEL_UPSR_REG(irq_en, nmirq_dis) \
({ \
e2k_upsr_t __upsr_val; \
\
__upsr_val = nmirq_dis ? E2K_KERNEL_INITIAL_UPSR_WITH_DISABLED_NMI \
: \
E2K_KERNEL_INITIAL_UPSR; \
KVM_WRITE_UPSR_REG_VALUE(__upsr_val.UPSR_reg); \
})
#define BOOT_KVM_INIT_KERNEL_UPSR_REG(irq_en, nmirq_dis) \
({ \
e2k_upsr_t __upsr_val; \
\
__upsr_val = nmirq_dis ? E2K_KERNEL_INITIAL_UPSR_WITH_DISABLED_NMI \
: \
E2K_KERNEL_INITIAL_UPSR; \
BOOT_KVM_WRITE_UPSR_REG_VALUE(__upsr_val.UPSR_reg); \
})
#define KVM_INIT_USER_UPSR_REG() \
KVM_WRITE_UPSR_REG_VALUE(E2K_USER_INITIAL_UPSR.UPSR_reg)
#define KVM_INIT_USER_PSR() \
KVM_ATOMIC_WRITE_PSR_REG_VALUE(E2K_USER_INITIAL_PSR.PSR_reg, \
false) /* IRQs under UPSR */
#define KVM_DO_SAVE_PSR_REG(psr_reg) \
(psr_reg.PSR_reg = KVM_READ_PSR_REG_VALUE())
#define KVM_DO_SAVE_UPSR_REG(upsr_reg) \
(upsr_reg.UPSR_reg = KVM_READ_UPSR_REG_VALUE())
#define KVM_DO_SAVE_PSR_UPSR_REGS(psr_reg, upsr_reg, under_upsr) \
({ \
KVM_DO_SAVE_PSR_REG((psr_reg)); \
KVM_DO_SAVE_UPSR_REG((upsr_reg)); \
under_upsr = kvm_get_vcpu_state()->irqs_under_upsr; \
})
#define KVM_DO_RESTORE_PSR_REG(psr_reg) \
(KVM_WRITE_PSR_REG_VALUE(psr_reg.PSR_reg))
#define KVM_DO_RESTORE_UPSR_REG(upsr_reg) \
(KVM_WRITE_UPSR_REG_VALUE(upsr_reg.UPSR_reg))
#define KVM_SWITCH_IRQ_TO_UPSR(disable_sge) \
KVM_WRITE_PSR_REG_VALUE(AW(E2K_KERNEL_PSR_ENABLED))
#define BOOT_KVM_SWITCH_IRQ_TO_UPSR() \
BOOT_KVM_WRITE_PSR_REG_VALUE(AW(E2K_KERNEL_PSR_ENABLED))
#define KVM_DO_RETURN_IRQ_TO_PSR(under_upsr, disable_sge) \
KVM_ATOMIC_WRITE_PSR_REG_VALUE(AW(E2K_KERNEL_PSR_DISABLED), under_upsr)
#define KVM_RETURN_IRQ_TO_PSR(under_upsr) \
KVM_DO_RETURN_IRQ_TO_PSR(under_upsr, false)
#define KVM_SET_USER_INITIAL_UPSR(upsr) \
({ \
KVM_RETURN_IRQ_TO_PSR(false); \
KVM_WRITE_UPSR_REG(upsr); \
})
#define KVM_CHECK_IRQ_UNDER_PSR(psr_reg, under_upsr) \
({ \
if (psr_reg.PSR_ie || psr_reg.PSR_uie || !psr_reg.PSR_pm) { \
pr_err("#U1 PSR 0x%x under upsr %d\n", \
psr_reg.PSR_reg, under_upsr); \
psr_reg.PSR_ie = 0; \
psr_reg.PSR_uie = 0; \
psr_reg.PSR_pm = 1; \
WARN_ON(true); \
} \
if (under_upsr) { \
pr_err("#U2 PSR 0x%x under upsr %d\n", \
psr_reg.PSR_reg, under_upsr); \
kvm_get_vcpu_state()->irqs_under_upsr = false; \
WARN_ON(true); \
} \
})
#define KVM_CHECK_IRQ_UNDER_UPSR(psr_reg, upsr_reg, under_upsr, has_irqs) \
({ \
if (psr_reg.PSR_ie || !psr_reg.PSR_pm || \
!psr_reg.PSR_uie && under_upsr) { \
pr_err("#K1 PSR 0x%x UPSR 0x%x under upsr %d\n", \
psr_reg.PSR_reg, upsr_reg.UPSR_reg, \
under_upsr); \
psr_reg.PSR_ie = 0; \
psr_reg.PSR_pm = 1; \
if (under_upsr) \
psr_reg.PSR_uie = 1; \
KVM_WRITE_PSR_REG_VALUE(psr_reg.PSR_reg); \
WARN_ON(true); \
} \
if (psr_reg.PSR_uie && !under_upsr) { \
E2K_LMS_HALT_OK; \
pr_err("#K2 PSR 0x%x UPSR 0x%x under upsr %d\n", \
psr_reg.PSR_reg, upsr_reg.UPSR_reg, \
under_upsr); \
kvm_get_vcpu_state()->irqs_under_upsr = true; \
WARN_ON(true); \
} \
if (!upsr_reg.UPSR_ie && under_upsr && has_irqs) { \
pr_err("#K3 PSR 0x%x UPSR 0x%x under upsr %d " \
"has IRQs %d\n", \
psr_reg.PSR_reg, upsr_reg.UPSR_reg, \
under_upsr, has_irqs); \
upsr_reg.UPSR_ie = 1; \
KVM_WRITE_UPSR_REG_VALUE(upsr_reg.UPSR_reg); \
WARN_ON(true); \
} \
})
#define KVM_CHECK_IRQ_STATE(psr_reg, upsr_reg, under_upsr, \
has_irqs, user_mode) \
do { \
if (user_mode) { \
KVM_CHECK_IRQ_UNDER_PSR(psr_reg, under_upsr); \
} else { \
KVM_CHECK_IRQ_UNDER_UPSR(psr_reg, upsr_reg, \
under_upsr, has_irqs); \
} \
} while (false)
#define KVM_RETURN_TO_KERNEL_UPSR(upsr_reg) \
({ \
if (IS_HV_GM()) { \
e2k_cr1_lo_t cr1_lo; \
unsigned psr; \
\
cr1_lo = NATIVE_NV_READ_CR1_LO_REG(); \
psr = cr1_lo.CR1_lo_psr; \
KVM_WRITE_SW_PSR_REG_VALUE(psr); \
NATIVE_RETURN_IRQ_TO_PSR(); \
} else { \
KVM_RETURN_IRQ_TO_PSR(true); \
} \
KVM_DO_RESTORE_UPSR_REG(upsr_reg); \
})
#define KVM_RETURN_TO_INIT_USER_UPSR() \
({ \
KVM_INIT_USER_PSR(); \
KVM_INIT_USER_UPSR_REG(); \
})
#define KVM_SWITCH_TO_KERNEL_UPSR(psr_reg, upsr_reg, under_upsr, \
irq_en, nmirq_dis) \
({ \
KVM_DO_SAVE_PSR_UPSR_REGS(psr_reg, upsr_reg, under_upsr); \
KVM_DO_SWITCH_TO_KERNEL_UPSR(irq_en, nmirq_dis); \
kvm_get_vcpu_state()->irqs_under_upsr = true; \
})
#define KVM_DO_SWITCH_TO_KERNEL_UPSR(irq_en, nmirq_dis) \
PREFIX_DO_SWITCH_TO_KERNEL_UPSR(KVM, kvm, \
irq_en, nmirq_dis)
#define KVM_RETURN_TO_USER_UPSR(upsr_reg, under_upsr) \
({ \
KVM_RETURN_IRQ_TO_PSR(under_upsr); \
KVM_DO_RESTORE_UPSR_REG(upsr_reg); \
})
#define KVM_SET_KERNEL_UPSR_WITH_DISABLED_NMI() \
PREFIX_SET_KERNEL_UPSR_WITH_DISABLED_NMI(KVM)
#define KVM_SET_KERNEL_UPSR(disable_sge) \
PREFIX_SET_KERNEL_UPSR(KVM, disable_sge)
#define BOOT_KVM_SET_KERNEL_UPSR() \
BOOT_PREFIX_SET_KERNEL_UPSR(KVM)
#define kvm_psr_and_upsr_irqs_disabled() \
({ \
e2k_psr_t psr; \
e2k_upsr_t upsr; \
bool under_upsr; \
\
KVM_DO_SAVE_PSR_UPSR_REGS(psr, upsr, under_upsr); \
psr_and_upsr_irqs_disabled_flags(psr.PSR_reg, upsr.UPSR_reg); \
})
extern void *kvm_nested_kernel_return_address(int n);
#ifdef CONFIG_KVM_GUEST_KERNEL
/* it is pure guest kernel (not paravirtualized) */
#define INIT_KERNEL_UPSR_REG(irq_en, nmirq_dis) \
KVM_INIT_KERNEL_UPSR_REG(irq_en, nmirq_dis)
#define SET_KERNEL_UPSR(disable_sge) \
KVM_SET_KERNEL_UPSR(disable_sge)
#define BOOT_SET_KERNEL_UPSR() \
BOOT_KVM_SET_KERNEL_UPSR()
#define SET_KERNEL_UPSR_WITH_DISABLED_NMI() \
KVM_SET_KERNEL_UPSR_WITH_DISABLED_NMI()
#define RETURN_TO_KERNEL_UPSR(upsr_reg) \
KVM_RETURN_TO_KERNEL_UPSR(upsr_reg)
static inline void *
nested_kernel_return_address(int n)
{
return kvm_nested_kernel_return_address(n);
}
#endif /* CONFIG_KVM_GUEST_KERNEL */
#endif /* ! __ASSEMBLY__ */
#endif /* _E2K_KVM_GUEST_SYSTEM_H_ */