mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
KVM/ARM updates for 4.13
- vcpu request overhaul - allow timer and PMU to have their interrupt number selected from userspace - workaround for Cavium erratum 30115 - handling of memory poisonning - the usual crop of fixes and cleanups -----BEGIN PGP SIGNATURE----- iQJJBAABCAAzFiEEn9UcU+C1Yxj9lZw9I9DQutE9ekMFAllWCM0VHG1hcmMuenlu Z2llckBhcm0uY29tAAoJECPQ0LrRPXpDjJ0QAI16x6+trKhH31lTSYekYfqm4hZ2 Fp7IbALW9KNCaY35tZov2Zuh99qGRduxTh7ewqhKpON8kkU+UKj0F7zH22+vfN4m yas/+uNr8R9VLyvea4ysPsgx8Q8v1Ix9setohHYNZIL9/klVqtaHpYvArHVF/mzq p2j/NxRS2dlp9r2TtoMRMhA05u6r0wolhUuh+z9v2ipib0gfOBIG24jsqCTEcD9n 5A/cVd+ztYshkrV95h3y9peahwt3zOA4QBGzrQ2K25jp0s54nqhmC7JTNSa8dtar YGW2MuAMoIFTwCFAlpwCzrwpOJFzF3Q6A8bOxei2fjclzjPMgT1xQxuhOoe4ntFa lTPxSHalm5W6dFTW90YSo2DBcPe+N7sQkhjR0cCeY3GYsOFhXMLTlOl5Pt1YK1or +3FAI74tFRKvVmb9mhZeGTvuzhDgRvtf3Qq5rjwlGzKc2BBOEgtMyj/Wgwo4N6Dz IjOnoRaUGELoBCWoTorMxLpsPBdPVSUxNyJTdAhqZ/ZtT1xqjhFNLZcrVWmOTzDM 1cav+jZkla4sLmJSNDD54aCSvvtPHis0nZn9PRlh12xgOyYiAVx4K++MNuWP0P37 hbh1gbPT+FcoVxPurUsX/pjNlTucPZcBwFytZDQlpwtPBpEFzJiImLYe/PldRb0f 9WQOH1Y1+q14MF+N =6hNK -----END PGP SIGNATURE----- Merge tag 'kvmarm-for-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD KVM/ARM updates for 4.13 - vcpu request overhaul - allow timer and PMU to have their interrupt number selected from userspace - workaround for Cavium erratum 30115 - handling of memory poisonning - the usual crop of fixes and cleanups Conflicts: arch/s390/include/asm/kvm_host.h
This commit is contained in:
commit
04a7ea04d5
59 changed files with 2077 additions and 326 deletions
|
|
@ -60,7 +60,7 @@ static const unsigned short cc_map[16] = {
|
|||
/*
|
||||
* Check if a trapped instruction should have been executed or not.
|
||||
*/
|
||||
bool kvm_condition_valid32(const struct kvm_vcpu *vcpu)
|
||||
bool __hyp_text kvm_condition_valid32(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long cpsr;
|
||||
u32 cpsr_cond;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/kvm_host.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <clocksource/arm_arch_timer.h>
|
||||
#include <asm/arch_timer.h>
|
||||
|
|
@ -35,6 +36,16 @@ static struct timecounter *timecounter;
|
|||
static unsigned int host_vtimer_irq;
|
||||
static u32 host_vtimer_irq_flags;
|
||||
|
||||
static const struct kvm_irq_level default_ptimer_irq = {
|
||||
.irq = 30,
|
||||
.level = 1,
|
||||
};
|
||||
|
||||
static const struct kvm_irq_level default_vtimer_irq = {
|
||||
.irq = 27,
|
||||
.level = 1,
|
||||
};
|
||||
|
||||
void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu_vtimer(vcpu)->active_cleared_last = false;
|
||||
|
|
@ -95,7 +106,7 @@ static void kvm_timer_inject_irq_work(struct work_struct *work)
|
|||
* If the vcpu is blocked we want to wake it up so that it will see
|
||||
* the timer has expired when entering the guest.
|
||||
*/
|
||||
kvm_vcpu_kick(vcpu);
|
||||
kvm_vcpu_wake_up(vcpu);
|
||||
}
|
||||
|
||||
static u64 kvm_timer_compute_delta(struct arch_timer_context *timer_ctx)
|
||||
|
|
@ -215,7 +226,8 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
|
|||
if (likely(irqchip_in_kernel(vcpu->kvm))) {
|
||||
ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
|
||||
timer_ctx->irq.irq,
|
||||
timer_ctx->irq.level);
|
||||
timer_ctx->irq.level,
|
||||
timer_ctx);
|
||||
WARN_ON(ret);
|
||||
}
|
||||
}
|
||||
|
|
@ -445,22 +457,11 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
|
|||
kvm_timer_update_state(vcpu);
|
||||
}
|
||||
|
||||
int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
|
||||
const struct kvm_irq_level *virt_irq,
|
||||
const struct kvm_irq_level *phys_irq)
|
||||
int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
|
||||
struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
|
||||
|
||||
/*
|
||||
* The vcpu timer irq number cannot be determined in
|
||||
* kvm_timer_vcpu_init() because it is called much before
|
||||
* kvm_vcpu_set_target(). To handle this, we determine
|
||||
* vcpu timer irq number when the vcpu is reset.
|
||||
*/
|
||||
vtimer->irq.irq = virt_irq->irq;
|
||||
ptimer->irq.irq = phys_irq->irq;
|
||||
|
||||
/*
|
||||
* The bits in CNTV_CTL are architecturally reset to UNKNOWN for ARMv8
|
||||
* and to 0 for ARMv7. We provide an implementation that always
|
||||
|
|
@ -496,6 +497,8 @@ static void update_vtimer_cntvoff(struct kvm_vcpu *vcpu, u64 cntvoff)
|
|||
void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
|
||||
struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
|
||||
struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
|
||||
|
||||
/* Synchronize cntvoff across all vtimers of a VM. */
|
||||
update_vtimer_cntvoff(vcpu, kvm_phys_timer_read());
|
||||
|
|
@ -504,6 +507,9 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
|
|||
INIT_WORK(&timer->expired, kvm_timer_inject_irq_work);
|
||||
hrtimer_init(&timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
|
||||
timer->timer.function = kvm_timer_expire;
|
||||
|
||||
vtimer->irq.irq = default_vtimer_irq.irq;
|
||||
ptimer->irq.irq = default_ptimer_irq.irq;
|
||||
}
|
||||
|
||||
static void kvm_timer_init_interrupt(void *info)
|
||||
|
|
@ -613,6 +619,30 @@ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
|
|||
kvm_vgic_unmap_phys_irq(vcpu, vtimer->irq.irq);
|
||||
}
|
||||
|
||||
static bool timer_irqs_are_valid(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int vtimer_irq, ptimer_irq;
|
||||
int i, ret;
|
||||
|
||||
vtimer_irq = vcpu_vtimer(vcpu)->irq.irq;
|
||||
ret = kvm_vgic_set_owner(vcpu, vtimer_irq, vcpu_vtimer(vcpu));
|
||||
if (ret)
|
||||
return false;
|
||||
|
||||
ptimer_irq = vcpu_ptimer(vcpu)->irq.irq;
|
||||
ret = kvm_vgic_set_owner(vcpu, ptimer_irq, vcpu_ptimer(vcpu));
|
||||
if (ret)
|
||||
return false;
|
||||
|
||||
kvm_for_each_vcpu(i, vcpu, vcpu->kvm) {
|
||||
if (vcpu_vtimer(vcpu)->irq.irq != vtimer_irq ||
|
||||
vcpu_ptimer(vcpu)->irq.irq != ptimer_irq)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int kvm_timer_enable(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
|
||||
|
|
@ -632,6 +662,11 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
|
|||
if (!vgic_initialized(vcpu->kvm))
|
||||
return -ENODEV;
|
||||
|
||||
if (!timer_irqs_are_valid(vcpu)) {
|
||||
kvm_debug("incorrectly configured timer irqs\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the physical IRQ number corresponding to the host_vtimer_irq
|
||||
*/
|
||||
|
|
@ -681,3 +716,79 @@ void kvm_timer_init_vhe(void)
|
|||
val |= (CNTHCTL_EL1PCTEN << cnthctl_shift);
|
||||
write_sysreg(val, cnthctl_el2);
|
||||
}
|
||||
|
||||
static void set_timer_irqs(struct kvm *kvm, int vtimer_irq, int ptimer_irq)
|
||||
{
|
||||
struct kvm_vcpu *vcpu;
|
||||
int i;
|
||||
|
||||
kvm_for_each_vcpu(i, vcpu, kvm) {
|
||||
vcpu_vtimer(vcpu)->irq.irq = vtimer_irq;
|
||||
vcpu_ptimer(vcpu)->irq.irq = ptimer_irq;
|
||||
}
|
||||
}
|
||||
|
||||
int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
|
||||
{
|
||||
int __user *uaddr = (int __user *)(long)attr->addr;
|
||||
struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
|
||||
struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
|
||||
int irq;
|
||||
|
||||
if (!irqchip_in_kernel(vcpu->kvm))
|
||||
return -EINVAL;
|
||||
|
||||
if (get_user(irq, uaddr))
|
||||
return -EFAULT;
|
||||
|
||||
if (!(irq_is_ppi(irq)))
|
||||
return -EINVAL;
|
||||
|
||||
if (vcpu->arch.timer_cpu.enabled)
|
||||
return -EBUSY;
|
||||
|
||||
switch (attr->attr) {
|
||||
case KVM_ARM_VCPU_TIMER_IRQ_VTIMER:
|
||||
set_timer_irqs(vcpu->kvm, irq, ptimer->irq.irq);
|
||||
break;
|
||||
case KVM_ARM_VCPU_TIMER_IRQ_PTIMER:
|
||||
set_timer_irqs(vcpu->kvm, vtimer->irq.irq, irq);
|
||||
break;
|
||||
default:
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arm_timer_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
|
||||
{
|
||||
int __user *uaddr = (int __user *)(long)attr->addr;
|
||||
struct arch_timer_context *timer;
|
||||
int irq;
|
||||
|
||||
switch (attr->attr) {
|
||||
case KVM_ARM_VCPU_TIMER_IRQ_VTIMER:
|
||||
timer = vcpu_vtimer(vcpu);
|
||||
break;
|
||||
case KVM_ARM_VCPU_TIMER_IRQ_PTIMER:
|
||||
timer = vcpu_ptimer(vcpu);
|
||||
break;
|
||||
default:
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
irq = timer->irq.irq;
|
||||
return put_user(irq, uaddr);
|
||||
}
|
||||
|
||||
int kvm_arm_timer_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
|
||||
{
|
||||
switch (attr->attr) {
|
||||
case KVM_ARM_VCPU_TIMER_IRQ_VTIMER:
|
||||
case KVM_ARM_VCPU_TIMER_IRQ_PTIMER:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENXIO;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -368,6 +368,13 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
|
|||
kvm_timer_vcpu_put(vcpu);
|
||||
}
|
||||
|
||||
static void vcpu_power_off(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu->arch.power_off = true;
|
||||
kvm_make_request(KVM_REQ_SLEEP, vcpu);
|
||||
kvm_vcpu_kick(vcpu);
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
|
||||
struct kvm_mp_state *mp_state)
|
||||
{
|
||||
|
|
@ -387,7 +394,7 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
|
|||
vcpu->arch.power_off = false;
|
||||
break;
|
||||
case KVM_MP_STATE_STOPPED:
|
||||
vcpu->arch.power_off = true;
|
||||
vcpu_power_off(vcpu);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
|
@ -520,6 +527,10 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
|
|||
}
|
||||
|
||||
ret = kvm_timer_enable(vcpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = kvm_arm_pmu_v3_enable(vcpu);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -536,21 +547,7 @@ void kvm_arm_halt_guest(struct kvm *kvm)
|
|||
|
||||
kvm_for_each_vcpu(i, vcpu, kvm)
|
||||
vcpu->arch.pause = true;
|
||||
kvm_make_all_cpus_request(kvm, KVM_REQ_VCPU_EXIT);
|
||||
}
|
||||
|
||||
void kvm_arm_halt_vcpu(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu->arch.pause = true;
|
||||
kvm_vcpu_kick(vcpu);
|
||||
}
|
||||
|
||||
void kvm_arm_resume_vcpu(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct swait_queue_head *wq = kvm_arch_vcpu_wq(vcpu);
|
||||
|
||||
vcpu->arch.pause = false;
|
||||
swake_up(wq);
|
||||
kvm_make_all_cpus_request(kvm, KVM_REQ_SLEEP);
|
||||
}
|
||||
|
||||
void kvm_arm_resume_guest(struct kvm *kvm)
|
||||
|
|
@ -558,16 +555,23 @@ void kvm_arm_resume_guest(struct kvm *kvm)
|
|||
int i;
|
||||
struct kvm_vcpu *vcpu;
|
||||
|
||||
kvm_for_each_vcpu(i, vcpu, kvm)
|
||||
kvm_arm_resume_vcpu(vcpu);
|
||||
kvm_for_each_vcpu(i, vcpu, kvm) {
|
||||
vcpu->arch.pause = false;
|
||||
swake_up(kvm_arch_vcpu_wq(vcpu));
|
||||
}
|
||||
}
|
||||
|
||||
static void vcpu_sleep(struct kvm_vcpu *vcpu)
|
||||
static void vcpu_req_sleep(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct swait_queue_head *wq = kvm_arch_vcpu_wq(vcpu);
|
||||
|
||||
swait_event_interruptible(*wq, ((!vcpu->arch.power_off) &&
|
||||
(!vcpu->arch.pause)));
|
||||
|
||||
if (vcpu->arch.power_off || vcpu->arch.pause) {
|
||||
/* Awaken to handle a signal, request we sleep again later. */
|
||||
kvm_make_request(KVM_REQ_SLEEP, vcpu);
|
||||
}
|
||||
}
|
||||
|
||||
static int kvm_vcpu_initialized(struct kvm_vcpu *vcpu)
|
||||
|
|
@ -575,6 +579,20 @@ static int kvm_vcpu_initialized(struct kvm_vcpu *vcpu)
|
|||
return vcpu->arch.target >= 0;
|
||||
}
|
||||
|
||||
static void check_vcpu_requests(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_request_pending(vcpu)) {
|
||||
if (kvm_check_request(KVM_REQ_SLEEP, vcpu))
|
||||
vcpu_req_sleep(vcpu);
|
||||
|
||||
/*
|
||||
* Clear IRQ_PENDING requests that were made to guarantee
|
||||
* that a VCPU sees new virtual interrupts.
|
||||
*/
|
||||
kvm_check_request(KVM_REQ_IRQ_PENDING, vcpu);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code
|
||||
* @vcpu: The VCPU pointer
|
||||
|
|
@ -620,8 +638,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
|
||||
update_vttbr(vcpu->kvm);
|
||||
|
||||
if (vcpu->arch.power_off || vcpu->arch.pause)
|
||||
vcpu_sleep(vcpu);
|
||||
check_vcpu_requests(vcpu);
|
||||
|
||||
/*
|
||||
* Preparing the interrupts to be injected also
|
||||
|
|
@ -650,8 +667,17 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
run->exit_reason = KVM_EXIT_INTR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure we set mode to IN_GUEST_MODE after we disable
|
||||
* interrupts and before the final VCPU requests check.
|
||||
* See the comment in kvm_vcpu_exiting_guest_mode() and
|
||||
* Documentation/virtual/kvm/vcpu-requests.rst
|
||||
*/
|
||||
smp_store_mb(vcpu->mode, IN_GUEST_MODE);
|
||||
|
||||
if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
|
||||
vcpu->arch.power_off || vcpu->arch.pause) {
|
||||
kvm_request_pending(vcpu)) {
|
||||
vcpu->mode = OUTSIDE_GUEST_MODE;
|
||||
local_irq_enable();
|
||||
kvm_pmu_sync_hwstate(vcpu);
|
||||
kvm_timer_sync_hwstate(vcpu);
|
||||
|
|
@ -667,7 +693,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
*/
|
||||
trace_kvm_entry(*vcpu_pc(vcpu));
|
||||
guest_enter_irqoff();
|
||||
vcpu->mode = IN_GUEST_MODE;
|
||||
|
||||
ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
|
||||
|
||||
|
|
@ -756,6 +781,7 @@ static int vcpu_interrupt_line(struct kvm_vcpu *vcpu, int number, bool level)
|
|||
* trigger a world-switch round on the running physical CPU to set the
|
||||
* virtual IRQ/FIQ fields in the HCR appropriately.
|
||||
*/
|
||||
kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
|
||||
kvm_vcpu_kick(vcpu);
|
||||
|
||||
return 0;
|
||||
|
|
@ -806,7 +832,7 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
|
|||
if (irq_num < VGIC_NR_SGIS || irq_num >= VGIC_NR_PRIVATE_IRQS)
|
||||
return -EINVAL;
|
||||
|
||||
return kvm_vgic_inject_irq(kvm, vcpu->vcpu_id, irq_num, level);
|
||||
return kvm_vgic_inject_irq(kvm, vcpu->vcpu_id, irq_num, level, NULL);
|
||||
case KVM_ARM_IRQ_TYPE_SPI:
|
||||
if (!irqchip_in_kernel(kvm))
|
||||
return -ENXIO;
|
||||
|
|
@ -814,7 +840,7 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
|
|||
if (irq_num < VGIC_NR_PRIVATE_IRQS)
|
||||
return -EINVAL;
|
||||
|
||||
return kvm_vgic_inject_irq(kvm, 0, irq_num, level);
|
||||
return kvm_vgic_inject_irq(kvm, 0, irq_num, level, NULL);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
|
@ -884,7 +910,7 @@ static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu,
|
|||
* Handle the "start in power-off" case.
|
||||
*/
|
||||
if (test_bit(KVM_ARM_VCPU_POWER_OFF, vcpu->arch.features))
|
||||
vcpu->arch.power_off = true;
|
||||
vcpu_power_off(vcpu);
|
||||
else
|
||||
vcpu->arch.power_off = false;
|
||||
|
||||
|
|
@ -1115,9 +1141,6 @@ static void cpu_init_hyp_mode(void *dummy)
|
|||
__cpu_init_hyp_mode(pgd_ptr, hyp_stack_ptr, vector_ptr);
|
||||
__cpu_init_stage2();
|
||||
|
||||
if (is_kernel_in_hyp_mode())
|
||||
kvm_timer_init_vhe();
|
||||
|
||||
kvm_arm_init_debug();
|
||||
}
|
||||
|
||||
|
|
@ -1137,6 +1160,7 @@ static void cpu_hyp_reinit(void)
|
|||
* event was cancelled before the CPU was reset.
|
||||
*/
|
||||
__cpu_init_stage2();
|
||||
kvm_timer_init_vhe();
|
||||
} else {
|
||||
cpu_init_hyp_mode(NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,10 +19,12 @@
|
|||
#include <linux/irqchip/arm-gic-v3.h>
|
||||
#include <linux/kvm_host.h>
|
||||
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/kvm_hyp.h>
|
||||
|
||||
#define vtr_to_max_lr_idx(v) ((v) & 0xf)
|
||||
#define vtr_to_nr_pre_bits(v) (((u32)(v) >> 26) + 1)
|
||||
#define vtr_to_nr_pre_bits(v) ((((u32)(v) >> 26) & 7) + 1)
|
||||
#define vtr_to_nr_apr_regs(v) (1 << (vtr_to_nr_pre_bits(v) - 5))
|
||||
|
||||
static u64 __hyp_text __gic_v3_get_lr(unsigned int lr)
|
||||
{
|
||||
|
|
@ -118,6 +120,90 @@ static void __hyp_text __gic_v3_set_lr(u64 val, int lr)
|
|||
}
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_write_ap0rn(u32 val, int n)
|
||||
{
|
||||
switch (n) {
|
||||
case 0:
|
||||
write_gicreg(val, ICH_AP0R0_EL2);
|
||||
break;
|
||||
case 1:
|
||||
write_gicreg(val, ICH_AP0R1_EL2);
|
||||
break;
|
||||
case 2:
|
||||
write_gicreg(val, ICH_AP0R2_EL2);
|
||||
break;
|
||||
case 3:
|
||||
write_gicreg(val, ICH_AP0R3_EL2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_write_ap1rn(u32 val, int n)
|
||||
{
|
||||
switch (n) {
|
||||
case 0:
|
||||
write_gicreg(val, ICH_AP1R0_EL2);
|
||||
break;
|
||||
case 1:
|
||||
write_gicreg(val, ICH_AP1R1_EL2);
|
||||
break;
|
||||
case 2:
|
||||
write_gicreg(val, ICH_AP1R2_EL2);
|
||||
break;
|
||||
case 3:
|
||||
write_gicreg(val, ICH_AP1R3_EL2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 __hyp_text __vgic_v3_read_ap0rn(int n)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
switch (n) {
|
||||
case 0:
|
||||
val = read_gicreg(ICH_AP0R0_EL2);
|
||||
break;
|
||||
case 1:
|
||||
val = read_gicreg(ICH_AP0R1_EL2);
|
||||
break;
|
||||
case 2:
|
||||
val = read_gicreg(ICH_AP0R2_EL2);
|
||||
break;
|
||||
case 3:
|
||||
val = read_gicreg(ICH_AP0R3_EL2);
|
||||
break;
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static u32 __hyp_text __vgic_v3_read_ap1rn(int n)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
switch (n) {
|
||||
case 0:
|
||||
val = read_gicreg(ICH_AP1R0_EL2);
|
||||
break;
|
||||
case 1:
|
||||
val = read_gicreg(ICH_AP1R1_EL2);
|
||||
break;
|
||||
case 2:
|
||||
val = read_gicreg(ICH_AP1R2_EL2);
|
||||
break;
|
||||
case 3:
|
||||
val = read_gicreg(ICH_AP1R3_EL2);
|
||||
break;
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
|
|
@ -154,24 +240,27 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
|
|||
|
||||
switch (nr_pre_bits) {
|
||||
case 7:
|
||||
cpu_if->vgic_ap0r[3] = read_gicreg(ICH_AP0R3_EL2);
|
||||
cpu_if->vgic_ap0r[2] = read_gicreg(ICH_AP0R2_EL2);
|
||||
cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3);
|
||||
cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2);
|
||||
case 6:
|
||||
cpu_if->vgic_ap0r[1] = read_gicreg(ICH_AP0R1_EL2);
|
||||
cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1);
|
||||
default:
|
||||
cpu_if->vgic_ap0r[0] = read_gicreg(ICH_AP0R0_EL2);
|
||||
cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0);
|
||||
}
|
||||
|
||||
switch (nr_pre_bits) {
|
||||
case 7:
|
||||
cpu_if->vgic_ap1r[3] = read_gicreg(ICH_AP1R3_EL2);
|
||||
cpu_if->vgic_ap1r[2] = read_gicreg(ICH_AP1R2_EL2);
|
||||
cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3);
|
||||
cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2);
|
||||
case 6:
|
||||
cpu_if->vgic_ap1r[1] = read_gicreg(ICH_AP1R1_EL2);
|
||||
cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1);
|
||||
default:
|
||||
cpu_if->vgic_ap1r[0] = read_gicreg(ICH_AP1R0_EL2);
|
||||
cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
|
||||
}
|
||||
} else {
|
||||
if (static_branch_unlikely(&vgic_v3_cpuif_trap))
|
||||
write_gicreg(0, ICH_HCR_EL2);
|
||||
|
||||
cpu_if->vgic_elrsr = 0xffff;
|
||||
cpu_if->vgic_ap0r[0] = 0;
|
||||
cpu_if->vgic_ap0r[1] = 0;
|
||||
|
|
@ -224,26 +313,34 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
|
|||
|
||||
switch (nr_pre_bits) {
|
||||
case 7:
|
||||
write_gicreg(cpu_if->vgic_ap0r[3], ICH_AP0R3_EL2);
|
||||
write_gicreg(cpu_if->vgic_ap0r[2], ICH_AP0R2_EL2);
|
||||
__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3);
|
||||
__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2);
|
||||
case 6:
|
||||
write_gicreg(cpu_if->vgic_ap0r[1], ICH_AP0R1_EL2);
|
||||
__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1);
|
||||
default:
|
||||
write_gicreg(cpu_if->vgic_ap0r[0], ICH_AP0R0_EL2);
|
||||
__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0);
|
||||
}
|
||||
|
||||
switch (nr_pre_bits) {
|
||||
case 7:
|
||||
write_gicreg(cpu_if->vgic_ap1r[3], ICH_AP1R3_EL2);
|
||||
write_gicreg(cpu_if->vgic_ap1r[2], ICH_AP1R2_EL2);
|
||||
__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3);
|
||||
__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2);
|
||||
case 6:
|
||||
write_gicreg(cpu_if->vgic_ap1r[1], ICH_AP1R1_EL2);
|
||||
__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1);
|
||||
default:
|
||||
write_gicreg(cpu_if->vgic_ap1r[0], ICH_AP1R0_EL2);
|
||||
__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < used_lrs; i++)
|
||||
__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
|
||||
} else {
|
||||
/*
|
||||
* If we need to trap system registers, we must write
|
||||
* ICH_HCR_EL2 anyway, even if no interrupts are being
|
||||
* injected,
|
||||
*/
|
||||
if (static_branch_unlikely(&vgic_v3_cpuif_trap))
|
||||
write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -287,3 +384,697 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
|
|||
{
|
||||
write_gicreg(vmcr, ICH_VMCR_EL2);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARM64
|
||||
|
||||
static int __hyp_text __vgic_v3_bpr_min(void)
|
||||
{
|
||||
/* See Pseudocode for VPriorityGroup */
|
||||
return 8 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
|
||||
}
|
||||
|
||||
static int __hyp_text __vgic_v3_get_group(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u32 esr = kvm_vcpu_get_hsr(vcpu);
|
||||
u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
|
||||
|
||||
return crm != 8;
|
||||
}
|
||||
|
||||
#define GICv3_IDLE_PRIORITY 0xff
|
||||
|
||||
static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
|
||||
u32 vmcr,
|
||||
u64 *lr_val)
|
||||
{
|
||||
unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
|
||||
u8 priority = GICv3_IDLE_PRIORITY;
|
||||
int i, lr = -1;
|
||||
|
||||
for (i = 0; i < used_lrs; i++) {
|
||||
u64 val = __gic_v3_get_lr(i);
|
||||
u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
|
||||
|
||||
/* Not pending in the state? */
|
||||
if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT)
|
||||
continue;
|
||||
|
||||
/* Group-0 interrupt, but Group-0 disabled? */
|
||||
if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK))
|
||||
continue;
|
||||
|
||||
/* Group-1 interrupt, but Group-1 disabled? */
|
||||
if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK))
|
||||
continue;
|
||||
|
||||
/* Not the highest priority? */
|
||||
if (lr_prio >= priority)
|
||||
continue;
|
||||
|
||||
/* This is a candidate */
|
||||
priority = lr_prio;
|
||||
*lr_val = val;
|
||||
lr = i;
|
||||
}
|
||||
|
||||
if (lr == -1)
|
||||
*lr_val = ICC_IAR1_EL1_SPURIOUS;
|
||||
|
||||
return lr;
|
||||
}
|
||||
|
||||
static int __hyp_text __vgic_v3_find_active_lr(struct kvm_vcpu *vcpu,
|
||||
int intid, u64 *lr_val)
|
||||
{
|
||||
unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < used_lrs; i++) {
|
||||
u64 val = __gic_v3_get_lr(i);
|
||||
|
||||
if ((val & ICH_LR_VIRTUAL_ID_MASK) == intid &&
|
||||
(val & ICH_LR_ACTIVE_BIT)) {
|
||||
*lr_val = val;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
*lr_val = ICC_IAR1_EL1_SPURIOUS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int __hyp_text __vgic_v3_get_highest_active_priority(void)
|
||||
{
|
||||
u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
|
||||
u32 hap = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_apr_regs; i++) {
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* The ICH_AP0Rn_EL2 and ICH_AP1Rn_EL2 registers
|
||||
* contain the active priority levels for this VCPU
|
||||
* for the maximum number of supported priority
|
||||
* levels, and we return the full priority level only
|
||||
* if the BPR is programmed to its minimum, otherwise
|
||||
* we return a combination of the priority level and
|
||||
* subpriority, as determined by the setting of the
|
||||
* BPR, but without the full subpriority.
|
||||
*/
|
||||
val = __vgic_v3_read_ap0rn(i);
|
||||
val |= __vgic_v3_read_ap1rn(i);
|
||||
if (!val) {
|
||||
hap += 32;
|
||||
continue;
|
||||
}
|
||||
|
||||
return (hap + __ffs(val)) << __vgic_v3_bpr_min();
|
||||
}
|
||||
|
||||
return GICv3_IDLE_PRIORITY;
|
||||
}
|
||||
|
||||
static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
|
||||
{
|
||||
return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
|
||||
}
|
||||
|
||||
static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
|
||||
{
|
||||
unsigned int bpr;
|
||||
|
||||
if (vmcr & ICH_VMCR_CBPR_MASK) {
|
||||
bpr = __vgic_v3_get_bpr0(vmcr);
|
||||
if (bpr < 7)
|
||||
bpr++;
|
||||
} else {
|
||||
bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
|
||||
}
|
||||
|
||||
return bpr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a priority to a preemption level, taking the relevant BPR
|
||||
* into account by zeroing the sub-priority bits.
|
||||
*/
|
||||
static u8 __hyp_text __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp)
|
||||
{
|
||||
unsigned int bpr;
|
||||
|
||||
if (!grp)
|
||||
bpr = __vgic_v3_get_bpr0(vmcr) + 1;
|
||||
else
|
||||
bpr = __vgic_v3_get_bpr1(vmcr);
|
||||
|
||||
return pri & (GENMASK(7, 0) << bpr);
|
||||
}
|
||||
|
||||
/*
|
||||
* The priority value is independent of any of the BPR values, so we
|
||||
* normalize it using the minumal BPR value. This guarantees that no
|
||||
* matter what the guest does with its BPR, we can always set/get the
|
||||
* same value of a priority.
|
||||
*/
|
||||
static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
|
||||
{
|
||||
u8 pre, ap;
|
||||
u32 val;
|
||||
int apr;
|
||||
|
||||
pre = __vgic_v3_pri_to_pre(pri, vmcr, grp);
|
||||
ap = pre >> __vgic_v3_bpr_min();
|
||||
apr = ap / 32;
|
||||
|
||||
if (!grp) {
|
||||
val = __vgic_v3_read_ap0rn(apr);
|
||||
__vgic_v3_write_ap0rn(val | BIT(ap % 32), apr);
|
||||
} else {
|
||||
val = __vgic_v3_read_ap1rn(apr);
|
||||
__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
|
||||
}
|
||||
}
|
||||
|
||||
static int __hyp_text __vgic_v3_clear_highest_active_priority(void)
|
||||
{
|
||||
u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
|
||||
u32 hap = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_apr_regs; i++) {
|
||||
u32 ap0, ap1;
|
||||
int c0, c1;
|
||||
|
||||
ap0 = __vgic_v3_read_ap0rn(i);
|
||||
ap1 = __vgic_v3_read_ap1rn(i);
|
||||
if (!ap0 && !ap1) {
|
||||
hap += 32;
|
||||
continue;
|
||||
}
|
||||
|
||||
c0 = ap0 ? __ffs(ap0) : 32;
|
||||
c1 = ap1 ? __ffs(ap1) : 32;
|
||||
|
||||
/* Always clear the LSB, which is the highest priority */
|
||||
if (c0 < c1) {
|
||||
ap0 &= ~BIT(c0);
|
||||
__vgic_v3_write_ap0rn(ap0, i);
|
||||
hap += c0;
|
||||
} else {
|
||||
ap1 &= ~BIT(c1);
|
||||
__vgic_v3_write_ap1rn(ap1, i);
|
||||
hap += c1;
|
||||
}
|
||||
|
||||
/* Rescale to 8 bits of priority */
|
||||
return hap << __vgic_v3_bpr_min();
|
||||
}
|
||||
|
||||
return GICv3_IDLE_PRIORITY;
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
|
||||
{
|
||||
u64 lr_val;
|
||||
u8 lr_prio, pmr;
|
||||
int lr, grp;
|
||||
|
||||
grp = __vgic_v3_get_group(vcpu);
|
||||
|
||||
lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
|
||||
if (lr < 0)
|
||||
goto spurious;
|
||||
|
||||
if (grp != !!(lr_val & ICH_LR_GROUP))
|
||||
goto spurious;
|
||||
|
||||
pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
|
||||
lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
|
||||
if (pmr <= lr_prio)
|
||||
goto spurious;
|
||||
|
||||
if (__vgic_v3_get_highest_active_priority() <= __vgic_v3_pri_to_pre(lr_prio, vmcr, grp))
|
||||
goto spurious;
|
||||
|
||||
lr_val &= ~ICH_LR_STATE;
|
||||
/* No active state for LPIs */
|
||||
if ((lr_val & ICH_LR_VIRTUAL_ID_MASK) <= VGIC_MAX_SPI)
|
||||
lr_val |= ICH_LR_ACTIVE_BIT;
|
||||
__gic_v3_set_lr(lr_val, lr);
|
||||
__vgic_v3_set_active_priority(lr_prio, vmcr, grp);
|
||||
vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
|
||||
return;
|
||||
|
||||
spurious:
|
||||
vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_clear_active_lr(int lr, u64 lr_val)
|
||||
{
|
||||
lr_val &= ~ICH_LR_ACTIVE_BIT;
|
||||
if (lr_val & ICH_LR_HW) {
|
||||
u32 pid;
|
||||
|
||||
pid = (lr_val & ICH_LR_PHYS_ID_MASK) >> ICH_LR_PHYS_ID_SHIFT;
|
||||
gic_write_dir(pid);
|
||||
}
|
||||
|
||||
__gic_v3_set_lr(lr_val, lr);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_bump_eoicount(void)
|
||||
{
|
||||
u32 hcr;
|
||||
|
||||
hcr = read_gicreg(ICH_HCR_EL2);
|
||||
hcr += 1 << ICH_HCR_EOIcount_SHIFT;
|
||||
write_gicreg(hcr, ICH_HCR_EL2);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_write_dir(struct kvm_vcpu *vcpu,
|
||||
u32 vmcr, int rt)
|
||||
{
|
||||
u32 vid = vcpu_get_reg(vcpu, rt);
|
||||
u64 lr_val;
|
||||
int lr;
|
||||
|
||||
/* EOImode == 0, nothing to be done here */
|
||||
if (!(vmcr & ICH_VMCR_EOIM_MASK))
|
||||
return;
|
||||
|
||||
/* No deactivate to be performed on an LPI */
|
||||
if (vid >= VGIC_MIN_LPI)
|
||||
return;
|
||||
|
||||
lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val);
|
||||
if (lr == -1) {
|
||||
__vgic_v3_bump_eoicount();
|
||||
return;
|
||||
}
|
||||
|
||||
__vgic_v3_clear_active_lr(lr, lr_val);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
|
||||
{
|
||||
u32 vid = vcpu_get_reg(vcpu, rt);
|
||||
u64 lr_val;
|
||||
u8 lr_prio, act_prio;
|
||||
int lr, grp;
|
||||
|
||||
grp = __vgic_v3_get_group(vcpu);
|
||||
|
||||
/* Drop priority in any case */
|
||||
act_prio = __vgic_v3_clear_highest_active_priority();
|
||||
|
||||
/* If EOIing an LPI, no deactivate to be performed */
|
||||
if (vid >= VGIC_MIN_LPI)
|
||||
return;
|
||||
|
||||
/* EOImode == 1, nothing to be done here */
|
||||
if (vmcr & ICH_VMCR_EOIM_MASK)
|
||||
return;
|
||||
|
||||
lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val);
|
||||
if (lr == -1) {
|
||||
__vgic_v3_bump_eoicount();
|
||||
return;
|
||||
}
|
||||
|
||||
lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
|
||||
|
||||
/* If priorities or group do not match, the guest has fscked-up. */
|
||||
if (grp != !!(lr_val & ICH_LR_GROUP) ||
|
||||
__vgic_v3_pri_to_pre(lr_prio, vmcr, grp) != act_prio)
|
||||
return;
|
||||
|
||||
/* Let's now perform the deactivation */
|
||||
__vgic_v3_clear_active_lr(lr, lr_val);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_read_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
|
||||
{
|
||||
vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG0_MASK));
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
|
||||
{
|
||||
vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_write_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
|
||||
{
|
||||
u64 val = vcpu_get_reg(vcpu, rt);
|
||||
|
||||
if (val & 1)
|
||||
vmcr |= ICH_VMCR_ENG0_MASK;
|
||||
else
|
||||
vmcr &= ~ICH_VMCR_ENG0_MASK;
|
||||
|
||||
__vgic_v3_write_vmcr(vmcr);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
|
||||
{
|
||||
u64 val = vcpu_get_reg(vcpu, rt);
|
||||
|
||||
if (val & 1)
|
||||
vmcr |= ICH_VMCR_ENG1_MASK;
|
||||
else
|
||||
vmcr &= ~ICH_VMCR_ENG1_MASK;
|
||||
|
||||
__vgic_v3_write_vmcr(vmcr);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_read_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
|
||||
{
|
||||
vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr0(vmcr));
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
|
||||
{
|
||||
vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
|
||||
{
|
||||
u64 val = vcpu_get_reg(vcpu, rt);
|
||||
u8 bpr_min = __vgic_v3_bpr_min() - 1;
|
||||
|
||||
/* Enforce BPR limiting */
|
||||
if (val < bpr_min)
|
||||
val = bpr_min;
|
||||
|
||||
val <<= ICH_VMCR_BPR0_SHIFT;
|
||||
val &= ICH_VMCR_BPR0_MASK;
|
||||
vmcr &= ~ICH_VMCR_BPR0_MASK;
|
||||
vmcr |= val;
|
||||
|
||||
__vgic_v3_write_vmcr(vmcr);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
|
||||
{
|
||||
u64 val = vcpu_get_reg(vcpu, rt);
|
||||
u8 bpr_min = __vgic_v3_bpr_min();
|
||||
|
||||
if (vmcr & ICH_VMCR_CBPR_MASK)
|
||||
return;
|
||||
|
||||
/* Enforce BPR limiting */
|
||||
if (val < bpr_min)
|
||||
val = bpr_min;
|
||||
|
||||
val <<= ICH_VMCR_BPR1_SHIFT;
|
||||
val &= ICH_VMCR_BPR1_MASK;
|
||||
vmcr &= ~ICH_VMCR_BPR1_MASK;
|
||||
vmcr |= val;
|
||||
|
||||
__vgic_v3_write_vmcr(vmcr);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_read_apxrn(struct kvm_vcpu *vcpu, int rt, int n)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (!__vgic_v3_get_group(vcpu))
|
||||
val = __vgic_v3_read_ap0rn(n);
|
||||
else
|
||||
val = __vgic_v3_read_ap1rn(n);
|
||||
|
||||
vcpu_set_reg(vcpu, rt, val);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_write_apxrn(struct kvm_vcpu *vcpu, int rt, int n)
|
||||
{
|
||||
u32 val = vcpu_get_reg(vcpu, rt);
|
||||
|
||||
if (!__vgic_v3_get_group(vcpu))
|
||||
__vgic_v3_write_ap0rn(val, n);
|
||||
else
|
||||
__vgic_v3_write_ap1rn(val, n);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_read_apxr0(struct kvm_vcpu *vcpu,
|
||||
u32 vmcr, int rt)
|
||||
{
|
||||
__vgic_v3_read_apxrn(vcpu, rt, 0);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_read_apxr1(struct kvm_vcpu *vcpu,
|
||||
u32 vmcr, int rt)
|
||||
{
|
||||
__vgic_v3_read_apxrn(vcpu, rt, 1);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_read_apxr2(struct kvm_vcpu *vcpu,
|
||||
u32 vmcr, int rt)
|
||||
{
|
||||
__vgic_v3_read_apxrn(vcpu, rt, 2);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_read_apxr3(struct kvm_vcpu *vcpu,
|
||||
u32 vmcr, int rt)
|
||||
{
|
||||
__vgic_v3_read_apxrn(vcpu, rt, 3);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_write_apxr0(struct kvm_vcpu *vcpu,
|
||||
u32 vmcr, int rt)
|
||||
{
|
||||
__vgic_v3_write_apxrn(vcpu, rt, 0);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_write_apxr1(struct kvm_vcpu *vcpu,
|
||||
u32 vmcr, int rt)
|
||||
{
|
||||
__vgic_v3_write_apxrn(vcpu, rt, 1);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_write_apxr2(struct kvm_vcpu *vcpu,
|
||||
u32 vmcr, int rt)
|
||||
{
|
||||
__vgic_v3_write_apxrn(vcpu, rt, 2);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu,
|
||||
u32 vmcr, int rt)
|
||||
{
|
||||
__vgic_v3_write_apxrn(vcpu, rt, 3);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
|
||||
u32 vmcr, int rt)
|
||||
{
|
||||
u64 lr_val;
|
||||
int lr, lr_grp, grp;
|
||||
|
||||
grp = __vgic_v3_get_group(vcpu);
|
||||
|
||||
lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
|
||||
if (lr == -1)
|
||||
goto spurious;
|
||||
|
||||
lr_grp = !!(lr_val & ICH_LR_GROUP);
|
||||
if (lr_grp != grp)
|
||||
lr_val = ICC_IAR1_EL1_SPURIOUS;
|
||||
|
||||
spurious:
|
||||
vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_read_pmr(struct kvm_vcpu *vcpu,
|
||||
u32 vmcr, int rt)
|
||||
{
|
||||
vmcr &= ICH_VMCR_PMR_MASK;
|
||||
vmcr >>= ICH_VMCR_PMR_SHIFT;
|
||||
vcpu_set_reg(vcpu, rt, vmcr);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_write_pmr(struct kvm_vcpu *vcpu,
|
||||
u32 vmcr, int rt)
|
||||
{
|
||||
u32 val = vcpu_get_reg(vcpu, rt);
|
||||
|
||||
val <<= ICH_VMCR_PMR_SHIFT;
|
||||
val &= ICH_VMCR_PMR_MASK;
|
||||
vmcr &= ~ICH_VMCR_PMR_MASK;
|
||||
vmcr |= val;
|
||||
|
||||
write_gicreg(vmcr, ICH_VMCR_EL2);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_read_rpr(struct kvm_vcpu *vcpu,
|
||||
u32 vmcr, int rt)
|
||||
{
|
||||
u32 val = __vgic_v3_get_highest_active_priority();
|
||||
vcpu_set_reg(vcpu, rt, val);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_read_ctlr(struct kvm_vcpu *vcpu,
|
||||
u32 vmcr, int rt)
|
||||
{
|
||||
u32 vtr, val;
|
||||
|
||||
vtr = read_gicreg(ICH_VTR_EL2);
|
||||
/* PRIbits */
|
||||
val = ((vtr >> 29) & 7) << ICC_CTLR_EL1_PRI_BITS_SHIFT;
|
||||
/* IDbits */
|
||||
val |= ((vtr >> 23) & 7) << ICC_CTLR_EL1_ID_BITS_SHIFT;
|
||||
/* SEIS */
|
||||
val |= ((vtr >> 22) & 1) << ICC_CTLR_EL1_SEIS_SHIFT;
|
||||
/* A3V */
|
||||
val |= ((vtr >> 21) & 1) << ICC_CTLR_EL1_A3V_SHIFT;
|
||||
/* EOImode */
|
||||
val |= ((vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT) << ICC_CTLR_EL1_EOImode_SHIFT;
|
||||
/* CBPR */
|
||||
val |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
|
||||
|
||||
vcpu_set_reg(vcpu, rt, val);
|
||||
}
|
||||
|
||||
static void __hyp_text __vgic_v3_write_ctlr(struct kvm_vcpu *vcpu,
|
||||
u32 vmcr, int rt)
|
||||
{
|
||||
u32 val = vcpu_get_reg(vcpu, rt);
|
||||
|
||||
if (val & ICC_CTLR_EL1_CBPR_MASK)
|
||||
vmcr |= ICH_VMCR_CBPR_MASK;
|
||||
else
|
||||
vmcr &= ~ICH_VMCR_CBPR_MASK;
|
||||
|
||||
if (val & ICC_CTLR_EL1_EOImode_MASK)
|
||||
vmcr |= ICH_VMCR_EOIM_MASK;
|
||||
else
|
||||
vmcr &= ~ICH_VMCR_EOIM_MASK;
|
||||
|
||||
write_gicreg(vmcr, ICH_VMCR_EL2);
|
||||
}
|
||||
|
||||
int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int rt;
|
||||
u32 esr;
|
||||
u32 vmcr;
|
||||
void (*fn)(struct kvm_vcpu *, u32, int);
|
||||
bool is_read;
|
||||
u32 sysreg;
|
||||
|
||||
esr = kvm_vcpu_get_hsr(vcpu);
|
||||
if (vcpu_mode_is_32bit(vcpu)) {
|
||||
if (!kvm_condition_valid(vcpu))
|
||||
return 1;
|
||||
|
||||
sysreg = esr_cp15_to_sysreg(esr);
|
||||
} else {
|
||||
sysreg = esr_sys64_to_sysreg(esr);
|
||||
}
|
||||
|
||||
is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
|
||||
|
||||
switch (sysreg) {
|
||||
case SYS_ICC_IAR0_EL1:
|
||||
case SYS_ICC_IAR1_EL1:
|
||||
if (unlikely(!is_read))
|
||||
return 0;
|
||||
fn = __vgic_v3_read_iar;
|
||||
break;
|
||||
case SYS_ICC_EOIR0_EL1:
|
||||
case SYS_ICC_EOIR1_EL1:
|
||||
if (unlikely(is_read))
|
||||
return 0;
|
||||
fn = __vgic_v3_write_eoir;
|
||||
break;
|
||||
case SYS_ICC_IGRPEN1_EL1:
|
||||
if (is_read)
|
||||
fn = __vgic_v3_read_igrpen1;
|
||||
else
|
||||
fn = __vgic_v3_write_igrpen1;
|
||||
break;
|
||||
case SYS_ICC_BPR1_EL1:
|
||||
if (is_read)
|
||||
fn = __vgic_v3_read_bpr1;
|
||||
else
|
||||
fn = __vgic_v3_write_bpr1;
|
||||
break;
|
||||
case SYS_ICC_AP0Rn_EL1(0):
|
||||
case SYS_ICC_AP1Rn_EL1(0):
|
||||
if (is_read)
|
||||
fn = __vgic_v3_read_apxr0;
|
||||
else
|
||||
fn = __vgic_v3_write_apxr0;
|
||||
break;
|
||||
case SYS_ICC_AP0Rn_EL1(1):
|
||||
case SYS_ICC_AP1Rn_EL1(1):
|
||||
if (is_read)
|
||||
fn = __vgic_v3_read_apxr1;
|
||||
else
|
||||
fn = __vgic_v3_write_apxr1;
|
||||
break;
|
||||
case SYS_ICC_AP0Rn_EL1(2):
|
||||
case SYS_ICC_AP1Rn_EL1(2):
|
||||
if (is_read)
|
||||
fn = __vgic_v3_read_apxr2;
|
||||
else
|
||||
fn = __vgic_v3_write_apxr2;
|
||||
break;
|
||||
case SYS_ICC_AP0Rn_EL1(3):
|
||||
case SYS_ICC_AP1Rn_EL1(3):
|
||||
if (is_read)
|
||||
fn = __vgic_v3_read_apxr3;
|
||||
else
|
||||
fn = __vgic_v3_write_apxr3;
|
||||
break;
|
||||
case SYS_ICC_HPPIR0_EL1:
|
||||
case SYS_ICC_HPPIR1_EL1:
|
||||
if (unlikely(!is_read))
|
||||
return 0;
|
||||
fn = __vgic_v3_read_hppir;
|
||||
break;
|
||||
case SYS_ICC_IGRPEN0_EL1:
|
||||
if (is_read)
|
||||
fn = __vgic_v3_read_igrpen0;
|
||||
else
|
||||
fn = __vgic_v3_write_igrpen0;
|
||||
break;
|
||||
case SYS_ICC_BPR0_EL1:
|
||||
if (is_read)
|
||||
fn = __vgic_v3_read_bpr0;
|
||||
else
|
||||
fn = __vgic_v3_write_bpr0;
|
||||
break;
|
||||
case SYS_ICC_DIR_EL1:
|
||||
if (unlikely(is_read))
|
||||
return 0;
|
||||
fn = __vgic_v3_write_dir;
|
||||
break;
|
||||
case SYS_ICC_RPR_EL1:
|
||||
if (unlikely(!is_read))
|
||||
return 0;
|
||||
fn = __vgic_v3_read_rpr;
|
||||
break;
|
||||
case SYS_ICC_CTLR_EL1:
|
||||
if (is_read)
|
||||
fn = __vgic_v3_read_ctlr;
|
||||
else
|
||||
fn = __vgic_v3_write_ctlr;
|
||||
break;
|
||||
case SYS_ICC_PMR_EL1:
|
||||
if (is_read)
|
||||
fn = __vgic_v3_read_pmr;
|
||||
else
|
||||
fn = __vgic_v3_write_pmr;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
vmcr = __vgic_v3_read_vmcr();
|
||||
rt = kvm_vcpu_sys_get_rt(vcpu);
|
||||
fn(vcpu, vmcr, rt);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/kvm_host.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <trace/events/kvm.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
|
@ -879,6 +880,9 @@ static pmd_t *stage2_get_pmd(struct kvm *kvm, struct kvm_mmu_memory_cache *cache
|
|||
pmd_t *pmd;
|
||||
|
||||
pud = stage2_get_pud(kvm, cache, addr);
|
||||
if (!pud)
|
||||
return NULL;
|
||||
|
||||
if (stage2_pud_none(*pud)) {
|
||||
if (!cache)
|
||||
return NULL;
|
||||
|
|
@ -1258,6 +1262,24 @@ static void coherent_cache_guest_page(struct kvm_vcpu *vcpu, kvm_pfn_t pfn,
|
|||
__coherent_cache_guest_page(vcpu, pfn, size);
|
||||
}
|
||||
|
||||
static void kvm_send_hwpoison_signal(unsigned long address,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
siginfo_t info;
|
||||
|
||||
info.si_signo = SIGBUS;
|
||||
info.si_errno = 0;
|
||||
info.si_code = BUS_MCEERR_AR;
|
||||
info.si_addr = (void __user *)address;
|
||||
|
||||
if (is_vm_hugetlb_page(vma))
|
||||
info.si_addr_lsb = huge_page_shift(hstate_vma(vma));
|
||||
else
|
||||
info.si_addr_lsb = PAGE_SHIFT;
|
||||
|
||||
send_sig_info(SIGBUS, &info, current);
|
||||
}
|
||||
|
||||
static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
struct kvm_memory_slot *memslot, unsigned long hva,
|
||||
unsigned long fault_status)
|
||||
|
|
@ -1327,6 +1349,10 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
|||
smp_rmb();
|
||||
|
||||
pfn = gfn_to_pfn_prot(kvm, gfn, write_fault, &writable);
|
||||
if (pfn == KVM_PFN_ERR_HWPOISON) {
|
||||
kvm_send_hwpoison_signal(hva, vma);
|
||||
return 0;
|
||||
}
|
||||
if (is_error_noslot_pfn(pfn))
|
||||
return -EFAULT;
|
||||
|
||||
|
|
|
|||
|
|
@ -203,6 +203,24 @@ static u64 kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
|
|||
return reg;
|
||||
}
|
||||
|
||||
static void kvm_pmu_check_overflow(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_pmu *pmu = &vcpu->arch.pmu;
|
||||
bool overflow = !!kvm_pmu_overflow_status(vcpu);
|
||||
|
||||
if (pmu->irq_level == overflow)
|
||||
return;
|
||||
|
||||
pmu->irq_level = overflow;
|
||||
|
||||
if (likely(irqchip_in_kernel(vcpu->kvm))) {
|
||||
int ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
|
||||
pmu->irq_num, overflow,
|
||||
&vcpu->arch.pmu);
|
||||
WARN_ON(ret);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_pmu_overflow_set - set PMU overflow interrupt
|
||||
* @vcpu: The vcpu pointer
|
||||
|
|
@ -210,37 +228,18 @@ static u64 kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
|
|||
*/
|
||||
void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val)
|
||||
{
|
||||
u64 reg;
|
||||
|
||||
if (val == 0)
|
||||
return;
|
||||
|
||||
vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= val;
|
||||
reg = kvm_pmu_overflow_status(vcpu);
|
||||
if (reg != 0)
|
||||
kvm_vcpu_kick(vcpu);
|
||||
kvm_pmu_check_overflow(vcpu);
|
||||
}
|
||||
|
||||
static void kvm_pmu_update_state(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_pmu *pmu = &vcpu->arch.pmu;
|
||||
bool overflow;
|
||||
|
||||
if (!kvm_arm_pmu_v3_ready(vcpu))
|
||||
return;
|
||||
|
||||
overflow = !!kvm_pmu_overflow_status(vcpu);
|
||||
if (pmu->irq_level == overflow)
|
||||
return;
|
||||
|
||||
pmu->irq_level = overflow;
|
||||
|
||||
if (likely(irqchip_in_kernel(vcpu->kvm))) {
|
||||
int ret;
|
||||
ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
|
||||
pmu->irq_num, overflow);
|
||||
WARN_ON(ret);
|
||||
}
|
||||
kvm_pmu_check_overflow(vcpu);
|
||||
}
|
||||
|
||||
bool kvm_pmu_should_notify_user(struct kvm_vcpu *vcpu)
|
||||
|
|
@ -451,25 +450,32 @@ bool kvm_arm_support_pmu_v3(void)
|
|||
return (perf_num_counters() > 0);
|
||||
}
|
||||
|
||||
static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
|
||||
int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (!kvm_arm_support_pmu_v3())
|
||||
return -ENODEV;
|
||||
if (!vcpu->arch.pmu.created)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* We currently require an in-kernel VGIC to use the PMU emulation,
|
||||
* because we do not support forwarding PMU overflow interrupts to
|
||||
* userspace yet.
|
||||
* A valid interrupt configuration for the PMU is either to have a
|
||||
* properly configured interrupt number and using an in-kernel
|
||||
* irqchip, or to not have an in-kernel GIC and not set an IRQ.
|
||||
*/
|
||||
if (!irqchip_in_kernel(vcpu->kvm) || !vgic_initialized(vcpu->kvm))
|
||||
return -ENODEV;
|
||||
if (irqchip_in_kernel(vcpu->kvm)) {
|
||||
int irq = vcpu->arch.pmu.irq_num;
|
||||
if (!kvm_arm_pmu_irq_initialized(vcpu))
|
||||
return -EINVAL;
|
||||
|
||||
if (!test_bit(KVM_ARM_VCPU_PMU_V3, vcpu->arch.features) ||
|
||||
!kvm_arm_pmu_irq_initialized(vcpu))
|
||||
return -ENXIO;
|
||||
|
||||
if (kvm_arm_pmu_v3_ready(vcpu))
|
||||
return -EBUSY;
|
||||
/*
|
||||
* If we are using an in-kernel vgic, at this point we know
|
||||
* the vgic will be initialized, so we can check the PMU irq
|
||||
* number against the dimensions of the vgic and make sure
|
||||
* it's valid.
|
||||
*/
|
||||
if (!irq_is_ppi(irq) && !vgic_valid_spi(vcpu->kvm, irq))
|
||||
return -EINVAL;
|
||||
} else if (kvm_arm_pmu_irq_initialized(vcpu)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
kvm_pmu_vcpu_reset(vcpu);
|
||||
vcpu->arch.pmu.ready = true;
|
||||
|
|
@ -477,7 +483,40 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define irq_is_ppi(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
|
||||
static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (!kvm_arm_support_pmu_v3())
|
||||
return -ENODEV;
|
||||
|
||||
if (!test_bit(KVM_ARM_VCPU_PMU_V3, vcpu->arch.features))
|
||||
return -ENXIO;
|
||||
|
||||
if (vcpu->arch.pmu.created)
|
||||
return -EBUSY;
|
||||
|
||||
if (irqchip_in_kernel(vcpu->kvm)) {
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If using the PMU with an in-kernel virtual GIC
|
||||
* implementation, we require the GIC to be already
|
||||
* initialized when initializing the PMU.
|
||||
*/
|
||||
if (!vgic_initialized(vcpu->kvm))
|
||||
return -ENODEV;
|
||||
|
||||
if (!kvm_arm_pmu_irq_initialized(vcpu))
|
||||
return -ENXIO;
|
||||
|
||||
ret = kvm_vgic_set_owner(vcpu, vcpu->arch.pmu.irq_num,
|
||||
&vcpu->arch.pmu);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
vcpu->arch.pmu.created = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For one VM the interrupt type must be same for each vcpu.
|
||||
|
|
@ -512,6 +551,9 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
|
|||
int __user *uaddr = (int __user *)(long)attr->addr;
|
||||
int irq;
|
||||
|
||||
if (!irqchip_in_kernel(vcpu->kvm))
|
||||
return -EINVAL;
|
||||
|
||||
if (!test_bit(KVM_ARM_VCPU_PMU_V3, vcpu->arch.features))
|
||||
return -ENODEV;
|
||||
|
||||
|
|
@ -519,7 +561,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
|
|||
return -EFAULT;
|
||||
|
||||
/* The PMU overflow interrupt can be a PPI or a valid SPI. */
|
||||
if (!(irq_is_ppi(irq) || vgic_valid_spi(vcpu->kvm, irq)))
|
||||
if (!(irq_is_ppi(irq) || irq_is_spi(irq)))
|
||||
return -EINVAL;
|
||||
|
||||
if (!pmu_irq_is_valid(vcpu->kvm, irq))
|
||||
|
|
@ -546,6 +588,9 @@ int kvm_arm_pmu_v3_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
|
|||
int __user *uaddr = (int __user *)(long)attr->addr;
|
||||
int irq;
|
||||
|
||||
if (!irqchip_in_kernel(vcpu->kvm))
|
||||
return -EINVAL;
|
||||
|
||||
if (!test_bit(KVM_ARM_VCPU_PMU_V3, vcpu->arch.features))
|
||||
return -ENODEV;
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ static unsigned long kvm_psci_vcpu_suspend(struct kvm_vcpu *vcpu)
|
|||
* for KVM will preserve the register state.
|
||||
*/
|
||||
kvm_vcpu_block(vcpu);
|
||||
kvm_clear_request(KVM_REQ_UNHALT, vcpu);
|
||||
|
||||
return PSCI_RET_SUCCESS;
|
||||
}
|
||||
|
|
@ -64,6 +65,8 @@ static unsigned long kvm_psci_vcpu_suspend(struct kvm_vcpu *vcpu)
|
|||
static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu->arch.power_off = true;
|
||||
kvm_make_request(KVM_REQ_SLEEP, vcpu);
|
||||
kvm_vcpu_kick(vcpu);
|
||||
}
|
||||
|
||||
static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
|
||||
|
|
@ -178,10 +181,9 @@ static void kvm_prepare_system_event(struct kvm_vcpu *vcpu, u32 type)
|
|||
* after this call is handled and before the VCPUs have been
|
||||
* re-initialized.
|
||||
*/
|
||||
kvm_for_each_vcpu(i, tmp, vcpu->kvm) {
|
||||
kvm_for_each_vcpu(i, tmp, vcpu->kvm)
|
||||
tmp->arch.power_off = true;
|
||||
kvm_vcpu_kick(tmp);
|
||||
}
|
||||
kvm_make_all_cpus_request(vcpu->kvm, KVM_REQ_SLEEP);
|
||||
|
||||
memset(&vcpu->run->system_event, 0, sizeof(vcpu->run->system_event));
|
||||
vcpu->run->system_event.type = type;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ static int vgic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e,
|
|||
|
||||
if (!vgic_valid_spi(kvm, spi_id))
|
||||
return -EINVAL;
|
||||
return kvm_vgic_inject_irq(kvm, 0, spi_id, level);
|
||||
return kvm_vgic_inject_irq(kvm, 0, spi_id, level, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -226,7 +226,13 @@ static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
|
|||
|
||||
switch (addr & 0xff) {
|
||||
case GIC_CPU_CTRL:
|
||||
val = vmcr.ctlr;
|
||||
val = vmcr.grpen0 << GIC_CPU_CTRL_EnableGrp0_SHIFT;
|
||||
val |= vmcr.grpen1 << GIC_CPU_CTRL_EnableGrp1_SHIFT;
|
||||
val |= vmcr.ackctl << GIC_CPU_CTRL_AckCtl_SHIFT;
|
||||
val |= vmcr.fiqen << GIC_CPU_CTRL_FIQEn_SHIFT;
|
||||
val |= vmcr.cbpr << GIC_CPU_CTRL_CBPR_SHIFT;
|
||||
val |= vmcr.eoim << GIC_CPU_CTRL_EOImodeNS_SHIFT;
|
||||
|
||||
break;
|
||||
case GIC_CPU_PRIMASK:
|
||||
/*
|
||||
|
|
@ -267,7 +273,13 @@ static void vgic_mmio_write_vcpuif(struct kvm_vcpu *vcpu,
|
|||
|
||||
switch (addr & 0xff) {
|
||||
case GIC_CPU_CTRL:
|
||||
vmcr.ctlr = val;
|
||||
vmcr.grpen0 = !!(val & GIC_CPU_CTRL_EnableGrp0);
|
||||
vmcr.grpen1 = !!(val & GIC_CPU_CTRL_EnableGrp1);
|
||||
vmcr.ackctl = !!(val & GIC_CPU_CTRL_AckCtl);
|
||||
vmcr.fiqen = !!(val & GIC_CPU_CTRL_FIQEn);
|
||||
vmcr.cbpr = !!(val & GIC_CPU_CTRL_CBPR);
|
||||
vmcr.eoim = !!(val & GIC_CPU_CTRL_EOImodeNS);
|
||||
|
||||
break;
|
||||
case GIC_CPU_PRIMASK:
|
||||
/*
|
||||
|
|
@ -296,34 +308,36 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
|
|||
vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12,
|
||||
VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
|
||||
vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
|
||||
vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
|
||||
VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
|
||||
vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
|
||||
vgic_mmio_read_enable, vgic_mmio_write_senable, NULL, NULL, 1,
|
||||
VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
|
||||
vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
|
||||
vgic_mmio_read_enable, vgic_mmio_write_cenable, NULL, NULL, 1,
|
||||
VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
|
||||
vgic_mmio_read_pending, vgic_mmio_write_spending, 1,
|
||||
vgic_mmio_read_pending, vgic_mmio_write_spending, NULL, NULL, 1,
|
||||
VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
|
||||
vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
|
||||
vgic_mmio_read_pending, vgic_mmio_write_cpending, NULL, NULL, 1,
|
||||
VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
|
||||
vgic_mmio_read_active, vgic_mmio_write_sactive, 1,
|
||||
vgic_mmio_read_active, vgic_mmio_write_sactive,
|
||||
NULL, vgic_mmio_uaccess_write_sactive, 1,
|
||||
VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
|
||||
vgic_mmio_read_active, vgic_mmio_write_cactive, 1,
|
||||
vgic_mmio_read_active, vgic_mmio_write_cactive,
|
||||
NULL, vgic_mmio_uaccess_write_cactive, 1,
|
||||
VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
|
||||
vgic_mmio_read_priority, vgic_mmio_write_priority, 8,
|
||||
VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
|
||||
vgic_mmio_read_priority, vgic_mmio_write_priority, NULL, NULL,
|
||||
8, VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
|
||||
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
|
||||
vgic_mmio_read_target, vgic_mmio_write_target, 8,
|
||||
vgic_mmio_read_target, vgic_mmio_write_target, NULL, NULL, 8,
|
||||
VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
|
||||
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
|
||||
vgic_mmio_read_config, vgic_mmio_write_config, 2,
|
||||
vgic_mmio_read_config, vgic_mmio_write_config, NULL, NULL, 2,
|
||||
VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
|
||||
vgic_mmio_read_raz, vgic_mmio_write_sgir, 4,
|
||||
|
|
|
|||
|
|
@ -456,11 +456,13 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
|
|||
vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
|
||||
VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
|
||||
vgic_mmio_read_active, vgic_mmio_write_sactive, NULL, NULL, 1,
|
||||
vgic_mmio_read_active, vgic_mmio_write_sactive,
|
||||
NULL, vgic_mmio_uaccess_write_sactive, 1,
|
||||
VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
|
||||
vgic_mmio_read_active, vgic_mmio_write_cactive, NULL, NULL, 1,
|
||||
VGIC_ACCESS_32bit),
|
||||
vgic_mmio_read_active, vgic_mmio_write_cactive,
|
||||
NULL, vgic_mmio_uaccess_write_cactive,
|
||||
1, VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
|
||||
vgic_mmio_read_priority, vgic_mmio_write_priority, NULL, NULL,
|
||||
8, VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
|
||||
|
|
@ -526,12 +528,14 @@ static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
|
|||
vgic_mmio_read_pending, vgic_mmio_write_cpending,
|
||||
vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
|
||||
VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
|
||||
vgic_mmio_read_active, vgic_mmio_write_sactive, 4,
|
||||
VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
|
||||
vgic_mmio_read_active, vgic_mmio_write_cactive, 4,
|
||||
VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ISACTIVER0,
|
||||
vgic_mmio_read_active, vgic_mmio_write_sactive,
|
||||
NULL, vgic_mmio_uaccess_write_sactive,
|
||||
4, VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ICACTIVER0,
|
||||
vgic_mmio_read_active, vgic_mmio_write_cactive,
|
||||
NULL, vgic_mmio_uaccess_write_cactive,
|
||||
4, VGIC_ACCESS_32bit),
|
||||
REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
|
||||
vgic_mmio_read_priority, vgic_mmio_write_priority, 32,
|
||||
VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
|
||||
|
|
|
|||
|
|
@ -231,40 +231,72 @@ static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
|
|||
* be migrated while we don't hold the IRQ locks and we don't want to be
|
||||
* chasing moving targets.
|
||||
*
|
||||
* For private interrupts, we only have to make sure the single and only VCPU
|
||||
* that can potentially queue the IRQ is stopped.
|
||||
* For private interrupts we don't have to do anything because userspace
|
||||
* accesses to the VGIC state already require all VCPUs to be stopped, and
|
||||
* only the VCPU itself can modify its private interrupts active state, which
|
||||
* guarantees that the VCPU is not running.
|
||||
*/
|
||||
static void vgic_change_active_prepare(struct kvm_vcpu *vcpu, u32 intid)
|
||||
{
|
||||
if (intid < VGIC_NR_PRIVATE_IRQS)
|
||||
kvm_arm_halt_vcpu(vcpu);
|
||||
else
|
||||
if (intid > VGIC_NR_PRIVATE_IRQS)
|
||||
kvm_arm_halt_guest(vcpu->kvm);
|
||||
}
|
||||
|
||||
/* See vgic_change_active_prepare */
|
||||
static void vgic_change_active_finish(struct kvm_vcpu *vcpu, u32 intid)
|
||||
{
|
||||
if (intid < VGIC_NR_PRIVATE_IRQS)
|
||||
kvm_arm_resume_vcpu(vcpu);
|
||||
else
|
||||
if (intid > VGIC_NR_PRIVATE_IRQS)
|
||||
kvm_arm_resume_guest(vcpu->kvm);
|
||||
}
|
||||
|
||||
static void __vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
{
|
||||
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
|
||||
int i;
|
||||
|
||||
for_each_set_bit(i, &val, len * 8) {
|
||||
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
|
||||
vgic_mmio_change_active(vcpu, irq, false);
|
||||
vgic_put_irq(vcpu->kvm, irq);
|
||||
}
|
||||
}
|
||||
|
||||
void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
{
|
||||
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
|
||||
|
||||
mutex_lock(&vcpu->kvm->lock);
|
||||
vgic_change_active_prepare(vcpu, intid);
|
||||
|
||||
__vgic_mmio_write_cactive(vcpu, addr, len, val);
|
||||
|
||||
vgic_change_active_finish(vcpu, intid);
|
||||
mutex_unlock(&vcpu->kvm->lock);
|
||||
}
|
||||
|
||||
void vgic_mmio_uaccess_write_cactive(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
{
|
||||
__vgic_mmio_write_cactive(vcpu, addr, len, val);
|
||||
}
|
||||
|
||||
static void __vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
{
|
||||
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
|
||||
int i;
|
||||
|
||||
vgic_change_active_prepare(vcpu, intid);
|
||||
for_each_set_bit(i, &val, len * 8) {
|
||||
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
|
||||
vgic_mmio_change_active(vcpu, irq, false);
|
||||
vgic_mmio_change_active(vcpu, irq, true);
|
||||
vgic_put_irq(vcpu->kvm, irq);
|
||||
}
|
||||
vgic_change_active_finish(vcpu, intid);
|
||||
}
|
||||
|
||||
void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
|
||||
|
|
@ -272,15 +304,21 @@ void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
|
|||
unsigned long val)
|
||||
{
|
||||
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
|
||||
int i;
|
||||
|
||||
mutex_lock(&vcpu->kvm->lock);
|
||||
vgic_change_active_prepare(vcpu, intid);
|
||||
for_each_set_bit(i, &val, len * 8) {
|
||||
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
|
||||
vgic_mmio_change_active(vcpu, irq, true);
|
||||
vgic_put_irq(vcpu->kvm, irq);
|
||||
}
|
||||
|
||||
__vgic_mmio_write_sactive(vcpu, addr, len, val);
|
||||
|
||||
vgic_change_active_finish(vcpu, intid);
|
||||
mutex_unlock(&vcpu->kvm->lock);
|
||||
}
|
||||
|
||||
void vgic_mmio_uaccess_write_sactive(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
{
|
||||
__vgic_mmio_write_sactive(vcpu, addr, len, val);
|
||||
}
|
||||
|
||||
unsigned long vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ extern struct kvm_io_device_ops kvm_io_gic_ops;
|
|||
* The _WITH_LENGTH version instantiates registers with a fixed length
|
||||
* and is mutually exclusive with the _PER_IRQ version.
|
||||
*/
|
||||
#define REGISTER_DESC_WITH_BITS_PER_IRQ(off, rd, wr, bpi, acc) \
|
||||
#define REGISTER_DESC_WITH_BITS_PER_IRQ(off, rd, wr, ur, uw, bpi, acc) \
|
||||
{ \
|
||||
.reg_offset = off, \
|
||||
.bits_per_irq = bpi, \
|
||||
|
|
@ -83,6 +83,8 @@ extern struct kvm_io_device_ops kvm_io_gic_ops;
|
|||
.access_flags = acc, \
|
||||
.read = rd, \
|
||||
.write = wr, \
|
||||
.uaccess_read = ur, \
|
||||
.uaccess_write = uw, \
|
||||
}
|
||||
|
||||
#define REGISTER_DESC_WITH_LENGTH(off, rd, wr, length, acc) \
|
||||
|
|
@ -165,6 +167,14 @@ void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
|
|||
gpa_t addr, unsigned int len,
|
||||
unsigned long val);
|
||||
|
||||
void vgic_mmio_uaccess_write_cactive(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val);
|
||||
|
||||
void vgic_mmio_uaccess_write_sactive(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val);
|
||||
|
||||
unsigned long vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len);
|
||||
|
||||
|
|
|
|||
|
|
@ -177,7 +177,18 @@ void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
|
|||
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
|
||||
u32 vmcr;
|
||||
|
||||
vmcr = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
|
||||
vmcr = (vmcrp->grpen0 << GICH_VMCR_ENABLE_GRP0_SHIFT) &
|
||||
GICH_VMCR_ENABLE_GRP0_MASK;
|
||||
vmcr |= (vmcrp->grpen1 << GICH_VMCR_ENABLE_GRP1_SHIFT) &
|
||||
GICH_VMCR_ENABLE_GRP1_MASK;
|
||||
vmcr |= (vmcrp->ackctl << GICH_VMCR_ACK_CTL_SHIFT) &
|
||||
GICH_VMCR_ACK_CTL_MASK;
|
||||
vmcr |= (vmcrp->fiqen << GICH_VMCR_FIQ_EN_SHIFT) &
|
||||
GICH_VMCR_FIQ_EN_MASK;
|
||||
vmcr |= (vmcrp->cbpr << GICH_VMCR_CBPR_SHIFT) &
|
||||
GICH_VMCR_CBPR_MASK;
|
||||
vmcr |= (vmcrp->eoim << GICH_VMCR_EOI_MODE_SHIFT) &
|
||||
GICH_VMCR_EOI_MODE_MASK;
|
||||
vmcr |= (vmcrp->abpr << GICH_VMCR_ALIAS_BINPOINT_SHIFT) &
|
||||
GICH_VMCR_ALIAS_BINPOINT_MASK;
|
||||
vmcr |= (vmcrp->bpr << GICH_VMCR_BINPOINT_SHIFT) &
|
||||
|
|
@ -195,8 +206,19 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
|
|||
|
||||
vmcr = cpu_if->vgic_vmcr;
|
||||
|
||||
vmcrp->ctlr = (vmcr & GICH_VMCR_CTRL_MASK) >>
|
||||
GICH_VMCR_CTRL_SHIFT;
|
||||
vmcrp->grpen0 = (vmcr & GICH_VMCR_ENABLE_GRP0_MASK) >>
|
||||
GICH_VMCR_ENABLE_GRP0_SHIFT;
|
||||
vmcrp->grpen1 = (vmcr & GICH_VMCR_ENABLE_GRP1_MASK) >>
|
||||
GICH_VMCR_ENABLE_GRP1_SHIFT;
|
||||
vmcrp->ackctl = (vmcr & GICH_VMCR_ACK_CTL_MASK) >>
|
||||
GICH_VMCR_ACK_CTL_SHIFT;
|
||||
vmcrp->fiqen = (vmcr & GICH_VMCR_FIQ_EN_MASK) >>
|
||||
GICH_VMCR_FIQ_EN_SHIFT;
|
||||
vmcrp->cbpr = (vmcr & GICH_VMCR_CBPR_MASK) >>
|
||||
GICH_VMCR_CBPR_SHIFT;
|
||||
vmcrp->eoim = (vmcr & GICH_VMCR_EOI_MODE_MASK) >>
|
||||
GICH_VMCR_EOI_MODE_SHIFT;
|
||||
|
||||
vmcrp->abpr = (vmcr & GICH_VMCR_ALIAS_BINPOINT_MASK) >>
|
||||
GICH_VMCR_ALIAS_BINPOINT_SHIFT;
|
||||
vmcrp->bpr = (vmcr & GICH_VMCR_BINPOINT_MASK) >>
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@
|
|||
|
||||
#include "vgic.h"
|
||||
|
||||
static bool group0_trap;
|
||||
static bool group1_trap;
|
||||
static bool common_trap;
|
||||
|
||||
void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
|
|
@ -159,15 +163,24 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
|
|||
void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
|
||||
{
|
||||
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
u32 model = vcpu->kvm->arch.vgic.vgic_model;
|
||||
u32 vmcr;
|
||||
|
||||
/*
|
||||
* Ignore the FIQen bit, because GIC emulation always implies
|
||||
* SRE=1 which means the vFIQEn bit is also RES1.
|
||||
*/
|
||||
vmcr = ((vmcrp->ctlr >> ICC_CTLR_EL1_EOImode_SHIFT) <<
|
||||
ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;
|
||||
vmcr |= (vmcrp->ctlr << ICH_VMCR_CBPR_SHIFT) & ICH_VMCR_CBPR_MASK;
|
||||
if (model == KVM_DEV_TYPE_ARM_VGIC_V2) {
|
||||
vmcr = (vmcrp->ackctl << ICH_VMCR_ACK_CTL_SHIFT) &
|
||||
ICH_VMCR_ACK_CTL_MASK;
|
||||
vmcr |= (vmcrp->fiqen << ICH_VMCR_FIQ_EN_SHIFT) &
|
||||
ICH_VMCR_FIQ_EN_MASK;
|
||||
} else {
|
||||
/*
|
||||
* When emulating GICv3 on GICv3 with SRE=1 on the
|
||||
* VFIQEn bit is RES1 and the VAckCtl bit is RES0.
|
||||
*/
|
||||
vmcr = ICH_VMCR_FIQ_EN_MASK;
|
||||
}
|
||||
|
||||
vmcr |= (vmcrp->cbpr << ICH_VMCR_CBPR_SHIFT) & ICH_VMCR_CBPR_MASK;
|
||||
vmcr |= (vmcrp->eoim << ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;
|
||||
vmcr |= (vmcrp->abpr << ICH_VMCR_BPR1_SHIFT) & ICH_VMCR_BPR1_MASK;
|
||||
vmcr |= (vmcrp->bpr << ICH_VMCR_BPR0_SHIFT) & ICH_VMCR_BPR0_MASK;
|
||||
vmcr |= (vmcrp->pmr << ICH_VMCR_PMR_SHIFT) & ICH_VMCR_PMR_MASK;
|
||||
|
|
@ -180,17 +193,27 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
|
|||
void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
|
||||
{
|
||||
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
u32 model = vcpu->kvm->arch.vgic.vgic_model;
|
||||
u32 vmcr;
|
||||
|
||||
vmcr = cpu_if->vgic_vmcr;
|
||||
|
||||
/*
|
||||
* Ignore the FIQen bit, because GIC emulation always implies
|
||||
* SRE=1 which means the vFIQEn bit is also RES1.
|
||||
*/
|
||||
vmcrp->ctlr = ((vmcr >> ICH_VMCR_EOIM_SHIFT) <<
|
||||
ICC_CTLR_EL1_EOImode_SHIFT) & ICC_CTLR_EL1_EOImode_MASK;
|
||||
vmcrp->ctlr |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
|
||||
if (model == KVM_DEV_TYPE_ARM_VGIC_V2) {
|
||||
vmcrp->ackctl = (vmcr & ICH_VMCR_ACK_CTL_MASK) >>
|
||||
ICH_VMCR_ACK_CTL_SHIFT;
|
||||
vmcrp->fiqen = (vmcr & ICH_VMCR_FIQ_EN_MASK) >>
|
||||
ICH_VMCR_FIQ_EN_SHIFT;
|
||||
} else {
|
||||
/*
|
||||
* When emulating GICv3 on GICv3 with SRE=1 on the
|
||||
* VFIQEn bit is RES1 and the VAckCtl bit is RES0.
|
||||
*/
|
||||
vmcrp->fiqen = 1;
|
||||
vmcrp->ackctl = 0;
|
||||
}
|
||||
|
||||
vmcrp->cbpr = (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
|
||||
vmcrp->eoim = (vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT;
|
||||
vmcrp->abpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
|
||||
vmcrp->bpr = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
|
||||
vmcrp->pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
|
||||
|
|
@ -239,6 +262,12 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
|
|||
|
||||
/* Get the show on the road... */
|
||||
vgic_v3->vgic_hcr = ICH_HCR_EN;
|
||||
if (group0_trap)
|
||||
vgic_v3->vgic_hcr |= ICH_HCR_TALL0;
|
||||
if (group1_trap)
|
||||
vgic_v3->vgic_hcr |= ICH_HCR_TALL1;
|
||||
if (common_trap)
|
||||
vgic_v3->vgic_hcr |= ICH_HCR_TC;
|
||||
}
|
||||
|
||||
int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
|
||||
|
|
@ -410,6 +439,26 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
|
||||
|
||||
static int __init early_group0_trap_cfg(char *buf)
|
||||
{
|
||||
return strtobool(buf, &group0_trap);
|
||||
}
|
||||
early_param("kvm-arm.vgic_v3_group0_trap", early_group0_trap_cfg);
|
||||
|
||||
static int __init early_group1_trap_cfg(char *buf)
|
||||
{
|
||||
return strtobool(buf, &group1_trap);
|
||||
}
|
||||
early_param("kvm-arm.vgic_v3_group1_trap", early_group1_trap_cfg);
|
||||
|
||||
static int __init early_common_trap_cfg(char *buf)
|
||||
{
|
||||
return strtobool(buf, &common_trap);
|
||||
}
|
||||
early_param("kvm-arm.vgic_v3_common_trap", early_common_trap_cfg);
|
||||
|
||||
/**
|
||||
* vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
|
||||
* @node: pointer to the DT node
|
||||
|
|
@ -461,6 +510,21 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
|
|||
if (kvm_vgic_global_state.vcpu_base == 0)
|
||||
kvm_info("disabling GICv2 emulation\n");
|
||||
|
||||
#ifdef CONFIG_ARM64
|
||||
if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_30115)) {
|
||||
group0_trap = true;
|
||||
group1_trap = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (group0_trap || group1_trap || common_trap) {
|
||||
kvm_info("GICv3 sysreg trapping enabled ([%s%s%s], reduced performance)\n",
|
||||
group0_trap ? "G0" : "",
|
||||
group1_trap ? "G1" : "",
|
||||
common_trap ? "C" : "");
|
||||
static_branch_enable(&vgic_v3_cpuif_trap);
|
||||
}
|
||||
|
||||
kvm_vgic_global_state.vctrl_base = NULL;
|
||||
kvm_vgic_global_state.type = VGIC_V3;
|
||||
kvm_vgic_global_state.max_gic_vcpus = VGIC_V3_MAX_CPUS;
|
||||
|
|
|
|||
|
|
@ -35,11 +35,12 @@ struct vgic_global kvm_vgic_global_state __ro_after_init = {
|
|||
|
||||
/*
|
||||
* Locking order is always:
|
||||
* its->cmd_lock (mutex)
|
||||
* its->its_lock (mutex)
|
||||
* vgic_cpu->ap_list_lock
|
||||
* kvm->lpi_list_lock
|
||||
* vgic_irq->irq_lock
|
||||
* kvm->lock (mutex)
|
||||
* its->cmd_lock (mutex)
|
||||
* its->its_lock (mutex)
|
||||
* vgic_cpu->ap_list_lock
|
||||
* kvm->lpi_list_lock
|
||||
* vgic_irq->irq_lock
|
||||
*
|
||||
* If you need to take multiple locks, always take the upper lock first,
|
||||
* then the lower ones, e.g. first take the its_lock, then the irq_lock.
|
||||
|
|
@ -234,10 +235,14 @@ static void vgic_sort_ap_list(struct kvm_vcpu *vcpu)
|
|||
|
||||
/*
|
||||
* Only valid injection if changing level for level-triggered IRQs or for a
|
||||
* rising edge.
|
||||
* rising edge, and in-kernel connected IRQ lines can only be controlled by
|
||||
* their owner.
|
||||
*/
|
||||
static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
|
||||
static bool vgic_validate_injection(struct vgic_irq *irq, bool level, void *owner)
|
||||
{
|
||||
if (irq->owner != owner)
|
||||
return false;
|
||||
|
||||
switch (irq->config) {
|
||||
case VGIC_CONFIG_LEVEL:
|
||||
return irq->line_level != level;
|
||||
|
|
@ -285,8 +290,10 @@ retry:
|
|||
* won't see this one until it exits for some other
|
||||
* reason.
|
||||
*/
|
||||
if (vcpu)
|
||||
if (vcpu) {
|
||||
kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
|
||||
kvm_vcpu_kick(vcpu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -332,6 +339,7 @@ retry:
|
|||
spin_unlock(&irq->irq_lock);
|
||||
spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
|
||||
|
||||
kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
|
||||
kvm_vcpu_kick(vcpu);
|
||||
|
||||
return true;
|
||||
|
|
@ -346,13 +354,16 @@ retry:
|
|||
* false: to ignore the call
|
||||
* Level-sensitive true: raise the input signal
|
||||
* false: lower the input signal
|
||||
* @owner: The opaque pointer to the owner of the IRQ being raised to verify
|
||||
* that the caller is allowed to inject this IRQ. Userspace
|
||||
* injections will have owner == NULL.
|
||||
*
|
||||
* The VGIC is not concerned with devices being active-LOW or active-HIGH for
|
||||
* level-sensitive interrupts. You can think of the level parameter as 1
|
||||
* being HIGH and 0 being LOW and all devices being active-HIGH.
|
||||
*/
|
||||
int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
|
||||
bool level)
|
||||
bool level, void *owner)
|
||||
{
|
||||
struct kvm_vcpu *vcpu;
|
||||
struct vgic_irq *irq;
|
||||
|
|
@ -374,7 +385,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
|
|||
|
||||
spin_lock(&irq->irq_lock);
|
||||
|
||||
if (!vgic_validate_injection(irq, level)) {
|
||||
if (!vgic_validate_injection(irq, level, owner)) {
|
||||
/* Nothing to see here, move along... */
|
||||
spin_unlock(&irq->irq_lock);
|
||||
vgic_put_irq(kvm, irq);
|
||||
|
|
@ -430,6 +441,39 @@ int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_vgic_set_owner - Set the owner of an interrupt for a VM
|
||||
*
|
||||
* @vcpu: Pointer to the VCPU (used for PPIs)
|
||||
* @intid: The virtual INTID identifying the interrupt (PPI or SPI)
|
||||
* @owner: Opaque pointer to the owner
|
||||
*
|
||||
* Returns 0 if intid is not already used by another in-kernel device and the
|
||||
* owner is set, otherwise returns an error code.
|
||||
*/
|
||||
int kvm_vgic_set_owner(struct kvm_vcpu *vcpu, unsigned int intid, void *owner)
|
||||
{
|
||||
struct vgic_irq *irq;
|
||||
int ret = 0;
|
||||
|
||||
if (!vgic_initialized(vcpu->kvm))
|
||||
return -EAGAIN;
|
||||
|
||||
/* SGIs and LPIs cannot be wired up to any device */
|
||||
if (!irq_is_ppi(intid) && !vgic_valid_spi(vcpu->kvm, intid))
|
||||
return -EINVAL;
|
||||
|
||||
irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
|
||||
spin_lock(&irq->irq_lock);
|
||||
if (irq->owner && irq->owner != owner)
|
||||
ret = -EEXIST;
|
||||
else
|
||||
irq->owner = owner;
|
||||
spin_unlock(&irq->irq_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* vgic_prune_ap_list - Remove non-relevant interrupts from the list
|
||||
*
|
||||
|
|
@ -721,8 +765,10 @@ void vgic_kick_vcpus(struct kvm *kvm)
|
|||
* a good kick...
|
||||
*/
|
||||
kvm_for_each_vcpu(c, vcpu, kvm) {
|
||||
if (kvm_vgic_vcpu_pending_irq(vcpu))
|
||||
if (kvm_vgic_vcpu_pending_irq(vcpu)) {
|
||||
kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
|
||||
kvm_vcpu_kick(vcpu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -111,14 +111,18 @@ static inline bool irq_is_pending(struct vgic_irq *irq)
|
|||
* registers regardless of the hardware backed GIC used.
|
||||
*/
|
||||
struct vgic_vmcr {
|
||||
u32 ctlr;
|
||||
u32 grpen0;
|
||||
u32 grpen1;
|
||||
|
||||
u32 ackctl;
|
||||
u32 fiqen;
|
||||
u32 cbpr;
|
||||
u32 eoim;
|
||||
|
||||
u32 abpr;
|
||||
u32 bpr;
|
||||
u32 pmr; /* Priority mask field in the GICC_PMR and
|
||||
* ICC_PMR_EL1 priority field format */
|
||||
/* Below member variable are valid only for GICv3 */
|
||||
u32 grpen0;
|
||||
u32 grpen1;
|
||||
};
|
||||
|
||||
struct vgic_reg_attr {
|
||||
|
|
|
|||
Loading…
Reference in a new issue