1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2012-2015 - ARM Ltd 4 * Author: Marc Zyngier <marc.zyngier@arm.com> 5 */ 6 7 #include <clocksource/arm_arch_timer.h> 8 #include <linux/compiler.h> 9 #include <linux/kvm_host.h> 10 11 #include <asm/kvm_hyp.h> 12 #include <asm/kvm_mmu.h> 13 14 #include <nvhe/pkvm.h> 15 16 static u32 timer_freq; 17 __kvm_timer_set_cntvoff(u64 cntvoff)18void __kvm_timer_set_cntvoff(u64 cntvoff) 19 { 20 write_sysreg(cntvoff, cntvoff_el2); 21 } 22 23 /* 24 * Should only be called on non-VHE or hVHE setups. 25 * VHE systems use EL2 timers and configure EL1 timers in kvm_timer_init_vhe(). 26 */ __timer_disable_traps(struct kvm_vcpu * vcpu)27void __timer_disable_traps(struct kvm_vcpu *vcpu) 28 { 29 u64 val, shift = 0; 30 31 if (has_hvhe()) 32 shift = 10; 33 34 /* Allow physical timer/counter access for the host */ 35 val = read_sysreg(cnthctl_el2); 36 val |= (CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN) << shift; 37 write_sysreg(val, cnthctl_el2); 38 } 39 40 /* 41 * Should only be called on non-VHE or hVHE setups. 42 * VHE systems use EL2 timers and configure EL1 timers in kvm_timer_init_vhe(). 43 */ __timer_enable_traps(struct kvm_vcpu * vcpu)44void __timer_enable_traps(struct kvm_vcpu *vcpu) 45 { 46 u64 clr = 0, set = 0; 47 48 /* 49 * Disallow physical timer access for the guest 50 * Physical counter access is allowed if no offset is enforced 51 * or running protected (we don't offset anything in this case). 52 */ 53 clr = CNTHCTL_EL1PCEN; 54 if (is_protected_kvm_enabled() || 55 !kern_hyp_va(vcpu->kvm)->arch.timer_data.poffset) 56 set |= CNTHCTL_EL1PCTEN; 57 else 58 clr |= CNTHCTL_EL1PCTEN; 59 60 if (has_hvhe()) { 61 clr <<= 10; 62 set <<= 10; 63 } 64 65 sysreg_clear_set(cnthctl_el2, clr, set); 66 } 67 pkvm_ticks_get(void)68static u64 pkvm_ticks_get(void) 69 { 70 return __arch_counter_get_cntvct(); 71 } 72 73 #define SEC_TO_US 1000000 74 pkvm_timer_init(void)75int pkvm_timer_init(void) 76 { 77 timer_freq = read_sysreg(cntfrq_el0); 78 /* 79 * TODO: The highest privileged level is supposed to initialize this 80 * register. But on some systems (which?), this information is only 81 * contained in the device-tree, so we'll need to find it out some other 82 * way. 83 */ 84 if (!timer_freq || timer_freq < SEC_TO_US) 85 return -ENODEV; 86 return 0; 87 } 88 89 #define pkvm_time_us_to_ticks(us) ((u64)(us) * timer_freq / SEC_TO_US) 90 pkvm_udelay(unsigned long usecs)91void pkvm_udelay(unsigned long usecs) 92 { 93 u64 ticks = pkvm_time_us_to_ticks(usecs); 94 u64 start = pkvm_ticks_get(); 95 96 while (true) { 97 u64 cur = pkvm_ticks_get(); 98 99 if ((cur - start) >= ticks || cur < start) 100 break; 101 /* TODO wfe */ 102 cpu_relax(); 103 } 104 } 105