return 0;
}
+/*
+ * cpreg_values are sorted in ascending order by KVM register ID
+ * (see kvm_arm_init_cpreg_list). This allows us to cheaply find
+ * the storage for a KVM register by ID with a binary search.
+ */
+static uint64_t *kvm_arm_get_cpreg_ptr(ARMCPU *cpu, uint64_t regidx)
+{
+ uint64_t *res;
+
+ res = bsearch(®idx, cpu->cpreg_indexes, cpu->cpreg_array_len,
+ sizeof(uint64_t), compare_u64);
+ assert(res);
+
+ return &cpu->cpreg_values[res - cpu->cpreg_indexes];
+}
+
/* Initialize the ARMCPU cpreg list according to the kernel's
* definition of what CPU registers it knows about (and throw away
* the previous TCG-created cpreg list).
return ok;
}
+void kvm_arm_cpu_pre_save(ARMCPU *cpu)
+{
+ /* KVM virtual time adjustment */
+ if (cpu->kvm_vtime_dirty) {
+ *kvm_arm_get_cpreg_ptr(cpu, KVM_REG_ARM_TIMER_CNT) = cpu->kvm_vtime;
+ }
+}
+
+void kvm_arm_cpu_post_load(ARMCPU *cpu)
+{
+ /* KVM virtual time adjustment */
+ if (cpu->kvm_adjvtime) {
+ cpu->kvm_vtime = *kvm_arm_get_cpreg_ptr(cpu, KVM_REG_ARM_TIMER_CNT);
+ cpu->kvm_vtime_dirty = true;
+ }
+}
+
void kvm_arm_reset_vcpu(ARMCPU *cpu)
{
int ret;
return 0;
}
+void kvm_arm_get_virtual_time(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ struct kvm_one_reg reg = {
+ .id = KVM_REG_ARM_TIMER_CNT,
+ .addr = (uintptr_t)&cpu->kvm_vtime,
+ };
+ int ret;
+
+ if (cpu->kvm_vtime_dirty) {
+ return;
+ }
+
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
+ if (ret) {
+ error_report("Failed to get KVM_REG_ARM_TIMER_CNT");
+ abort();
+ }
+
+ cpu->kvm_vtime_dirty = true;
+}
+
+void kvm_arm_put_virtual_time(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ struct kvm_one_reg reg = {
+ .id = KVM_REG_ARM_TIMER_CNT,
+ .addr = (uintptr_t)&cpu->kvm_vtime,
+ };
+ int ret;
+
+ if (!cpu->kvm_vtime_dirty) {
+ return;
+ }
+
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
+ if (ret) {
+ error_report("Failed to set KVM_REG_ARM_TIMER_CNT");
+ abort();
+ }
+
+ cpu->kvm_vtime_dirty = false;
+}
+
int kvm_put_vcpu_events(ARMCPU *cpu)
{
CPUARMState *env = &cpu->env;
return MEMTXATTRS_UNSPECIFIED;
}
+void kvm_arm_vm_state_change(void *opaque, int running, RunState state)
+{
+ CPUState *cs = opaque;
+ ARMCPU *cpu = ARM_CPU(cs);
+
+ if (running) {
+ if (cpu->kvm_adjvtime) {
+ kvm_arm_put_virtual_time(cs);
+ }
+ } else {
+ if (cpu->kvm_adjvtime) {
+ kvm_arm_get_virtual_time(cs);
+ }
+ }
+}
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
{
bool write_kvmstate_to_list(ARMCPU *cpu);
/**
+ * kvm_arm_cpu_pre_save:
+ * @cpu: ARMCPU
+ *
+ * Called after write_kvmstate_to_list() from cpu_pre_save() to update
+ * the cpreg list with KVM CPU state.
+ */
+void kvm_arm_cpu_pre_save(ARMCPU *cpu);
+
+/**
+ * kvm_arm_cpu_post_load:
+ * @cpu: ARMCPU
+ *
+ * Called from cpu_post_load() to update KVM CPU state from the cpreg list.
+ */
+void kvm_arm_cpu_post_load(ARMCPU *cpu);
+
+/**
* kvm_arm_reset_vcpu:
* @cpu: ARMCPU
*
*/
int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu);
+/**
+ * kvm_arm_get_virtual_time:
+ * @cs: CPUState
+ *
+ * Gets the VCPU's virtual counter and stores it in the KVM CPU state.
+ */
+void kvm_arm_get_virtual_time(CPUState *cs);
+
+/**
+ * kvm_arm_put_virtual_time:
+ * @cs: CPUState
+ *
+ * Sets the VCPU's virtual counter to the value stored in the KVM CPU state.
+ */
+void kvm_arm_put_virtual_time(CPUState *cs);
+
+void kvm_arm_vm_state_change(void *opaque, int running, RunState state);
+
int kvm_arm_vgic_probe(void);
void kvm_arm_pmu_set_irq(CPUState *cs, int irq);
static inline void kvm_arm_pmu_init(CPUState *cs) {}
static inline void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map) {}
+
+static inline void kvm_arm_get_virtual_time(CPUState *cs) {}
+static inline void kvm_arm_put_virtual_time(CPUState *cs) {}
#endif
static inline const char *gic_class_name(void)