Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64: KVM: allow export and import of generic timer regs

For correct guest suspend/resume behaviour we need to ensure we include
the generic timer registers for 64 bit guests. As CONFIG_KVM_ARM_TIMER is
always set for arm64 we don't need to worry about null implementations.
However I have re-jigged the kvm_arm_timer_set/get_reg declarations to
be in the common include/kvm/arm_arch_timer.h headers.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

authored by

Alex Bennée and committed by
Christoffer Dall
1df08ba0 efd48cea

+81 -14
-3
arch/arm/include/asm/kvm_host.h
··· 228 228 int kvm_perf_init(void); 229 229 int kvm_perf_teardown(void); 230 230 231 - u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid); 232 - int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value); 233 - 234 231 #endif /* __ARM_KVM_HOST_H__ */
-10
arch/arm/kvm/guest.c
··· 124 124 return false; 125 125 } 126 126 127 - int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value) 128 - { 129 - return 0; 130 - } 131 - 132 - u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid) 133 - { 134 - return 0; 135 - } 136 - 137 127 #else 138 128 139 129 #define NUM_TIMER_REGS 3
+67 -1
arch/arm64/kvm/guest.c
··· 136 136 } 137 137 138 138 /** 139 + * ARM64 versions of the TIMER registers, always available on arm64 140 + */ 141 + 142 + #define NUM_TIMER_REGS 3 143 + 144 + static bool is_timer_reg(u64 index) 145 + { 146 + switch (index) { 147 + case KVM_REG_ARM_TIMER_CTL: 148 + case KVM_REG_ARM_TIMER_CNT: 149 + case KVM_REG_ARM_TIMER_CVAL: 150 + return true; 151 + } 152 + return false; 153 + } 154 + 155 + static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) 156 + { 157 + if (put_user(KVM_REG_ARM_TIMER_CTL, uindices)) 158 + return -EFAULT; 159 + uindices++; 160 + if (put_user(KVM_REG_ARM_TIMER_CNT, uindices)) 161 + return -EFAULT; 162 + uindices++; 163 + if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices)) 164 + return -EFAULT; 165 + 166 + return 0; 167 + } 168 + 169 + static int set_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 170 + { 171 + void __user *uaddr = (void __user *)(long)reg->addr; 172 + u64 val; 173 + int ret; 174 + 175 + ret = copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)); 176 + if (ret != 0) 177 + return ret; 178 + 179 + return kvm_arm_timer_set_reg(vcpu, reg->id, val); 180 + } 181 + 182 + static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 183 + { 184 + void __user *uaddr = (void __user *)(long)reg->addr; 185 + u64 val; 186 + 187 + val = kvm_arm_timer_get_reg(vcpu, reg->id); 188 + return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)); 189 + } 190 + 191 + /** 139 192 * kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG 140 193 * 141 194 * This is for all registers. 142 195 */ 143 196 unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu) 144 197 { 145 - return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu); 198 + return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu) 199 + + NUM_TIMER_REGS; 146 200 } 147 201 148 202 /** ··· 208 154 { 209 155 unsigned int i; 210 156 const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE; 157 + int ret; 211 158 212 159 for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) { 213 160 if (put_user(core_reg | i, uindices)) 214 161 return -EFAULT; 215 162 uindices++; 216 163 } 164 + 165 + ret = copy_timer_indices(vcpu, uindices); 166 + if (ret) 167 + return ret; 168 + uindices += NUM_TIMER_REGS; 217 169 218 170 return kvm_arm_copy_sys_reg_indices(vcpu, uindices); 219 171 } ··· 234 174 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) 235 175 return get_core_reg(vcpu, reg); 236 176 177 + if (is_timer_reg(reg->id)) 178 + return get_timer_reg(vcpu, reg); 179 + 237 180 return kvm_arm_sys_reg_get_reg(vcpu, reg); 238 181 } 239 182 ··· 249 186 /* Register group 16 means we set a core register. */ 250 187 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) 251 188 return set_core_reg(vcpu, reg); 189 + 190 + if (is_timer_reg(reg->id)) 191 + return set_timer_reg(vcpu, reg); 252 192 253 193 return kvm_arm_sys_reg_set_reg(vcpu, reg); 254 194 }
+14
include/kvm/arm_arch_timer.h
··· 67 67 void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu); 68 68 void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu); 69 69 void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu); 70 + 71 + u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid); 72 + int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value); 73 + 70 74 #else 71 75 static inline int kvm_timer_hyp_init(void) 72 76 { ··· 88 84 static inline void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu) {} 89 85 static inline void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu) {} 90 86 static inline void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu) {} 87 + 88 + static inline int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value) 89 + { 90 + return 0; 91 + } 92 + 93 + static inline u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid) 94 + { 95 + return 0; 96 + } 91 97 #endif 92 98 93 99 #endif