diff options
Diffstat (limited to 'arch/arm64/kvm/reset.c')
-rw-r--r-- | arch/arm64/kvm/reset.c | 50 |
1 files changed, 48 insertions, 2 deletions
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index b72a3dd56204..f16a5f8ff2b4 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <asm/kvm_arm.h> | 32 | #include <asm/kvm_arm.h> |
33 | #include <asm/kvm_asm.h> | 33 | #include <asm/kvm_asm.h> |
34 | #include <asm/kvm_coproc.h> | 34 | #include <asm/kvm_coproc.h> |
35 | #include <asm/kvm_emulate.h> | ||
35 | #include <asm/kvm_mmu.h> | 36 | #include <asm/kvm_mmu.h> |
36 | 37 | ||
37 | /* Maximum phys_shift supported for any VM on this host */ | 38 | /* Maximum phys_shift supported for any VM on this host */ |
@@ -105,16 +106,33 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext) | |||
105 | * This function finds the right table above and sets the registers on | 106 | * This function finds the right table above and sets the registers on |
106 | * the virtual CPU struct to their architecturally defined reset | 107 | * the virtual CPU struct to their architecturally defined reset |
107 | * values. | 108 | * values. |
109 | * | ||
110 | * Note: This function can be called from two paths: The KVM_ARM_VCPU_INIT | ||
111 | * ioctl or as part of handling a request issued by another VCPU in the PSCI | ||
112 | * handling code. In the first case, the VCPU will not be loaded, and in the | ||
113 | * second case the VCPU will be loaded. Because this function operates purely | ||
114 | * on the memory-backed valus of system registers, we want to do a full put if | ||
115 | * we were loaded (handling a request) and load the values back at the end of | ||
116 | * the function. Otherwise we leave the state alone. In both cases, we | ||
117 | * disable preemption around the vcpu reset as we would otherwise race with | ||
118 | * preempt notifiers which also call put/load. | ||
108 | */ | 119 | */ |
109 | int kvm_reset_vcpu(struct kvm_vcpu *vcpu) | 120 | int kvm_reset_vcpu(struct kvm_vcpu *vcpu) |
110 | { | 121 | { |
111 | const struct kvm_regs *cpu_reset; | 122 | const struct kvm_regs *cpu_reset; |
123 | int ret = -EINVAL; | ||
124 | bool loaded; | ||
125 | |||
126 | preempt_disable(); | ||
127 | loaded = (vcpu->cpu != -1); | ||
128 | if (loaded) | ||
129 | kvm_arch_vcpu_put(vcpu); | ||
112 | 130 | ||
113 | switch (vcpu->arch.target) { | 131 | switch (vcpu->arch.target) { |
114 | default: | 132 | default: |
115 | if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) { | 133 | if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) { |
116 | if (!cpu_has_32bit_el1()) | 134 | if (!cpu_has_32bit_el1()) |
117 | return -EINVAL; | 135 | goto out; |
118 | cpu_reset = &default_regs_reset32; | 136 | cpu_reset = &default_regs_reset32; |
119 | } else { | 137 | } else { |
120 | cpu_reset = &default_regs_reset; | 138 | cpu_reset = &default_regs_reset; |
@@ -129,6 +147,29 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) | |||
129 | /* Reset system registers */ | 147 | /* Reset system registers */ |
130 | kvm_reset_sys_regs(vcpu); | 148 | kvm_reset_sys_regs(vcpu); |
131 | 149 | ||
150 | /* | ||
151 | * Additional reset state handling that PSCI may have imposed on us. | ||
152 | * Must be done after all the sys_reg reset. | ||
153 | */ | ||
154 | if (vcpu->arch.reset_state.reset) { | ||
155 | unsigned long target_pc = vcpu->arch.reset_state.pc; | ||
156 | |||
157 | /* Gracefully handle Thumb2 entry point */ | ||
158 | if (vcpu_mode_is_32bit(vcpu) && (target_pc & 1)) { | ||
159 | target_pc &= ~1UL; | ||
160 | vcpu_set_thumb(vcpu); | ||
161 | } | ||
162 | |||
163 | /* Propagate caller endianness */ | ||
164 | if (vcpu->arch.reset_state.be) | ||
165 | kvm_vcpu_set_be(vcpu); | ||
166 | |||
167 | *vcpu_pc(vcpu) = target_pc; | ||
168 | vcpu_set_reg(vcpu, 0, vcpu->arch.reset_state.r0); | ||
169 | |||
170 | vcpu->arch.reset_state.reset = false; | ||
171 | } | ||
172 | |||
132 | /* Reset PMU */ | 173 | /* Reset PMU */ |
133 | kvm_pmu_vcpu_reset(vcpu); | 174 | kvm_pmu_vcpu_reset(vcpu); |
134 | 175 | ||
@@ -137,7 +178,12 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) | |||
137 | vcpu->arch.workaround_flags |= VCPU_WORKAROUND_2_FLAG; | 178 | vcpu->arch.workaround_flags |= VCPU_WORKAROUND_2_FLAG; |
138 | 179 | ||
139 | /* Reset timer */ | 180 | /* Reset timer */ |
140 | return kvm_timer_vcpu_reset(vcpu); | 181 | ret = kvm_timer_vcpu_reset(vcpu); |
182 | out: | ||
183 | if (loaded) | ||
184 | kvm_arch_vcpu_load(vcpu, smp_processor_id()); | ||
185 | preempt_enable(); | ||
186 | return ret; | ||
141 | } | 187 | } |
142 | 188 | ||
143 | void kvm_set_ipa_limit(void) | 189 | void kvm_set_ipa_limit(void) |