On 06/19/2012 01:05 AM, Christoffer Dall wrote:
>> Premature, but this is sad. I suggest you split vmid generation from
>> next available vmid. This allows you to make the generation counter
>> atomic so it may be read outside the lock.
>>
>> You can do
>>
>> if (likely(kvm->arch.vmd_gen) == atomic_read(&kvm_vmid_gen)))
>> return;
>>
>> spin_lock(...
>>
>
> I knew you were going to say something here :), please take a look at
> this and see if you agree:
It looks reasonable wrt locking.
> +
> + /* First user of a new VMID generation? */
> + if (unlikely(kvm_next_vmid == 0)) {
> + atomic64_inc(&kvm_vmid_gen);
> + kvm_next_vmid = 1;
> +
> + /* This does nothing on UP */
> + smp_call_function(reset_vm_context, NULL, 1);
Does this imply a memory barrier? If not, smp_mb__after_atomic_inc().
> +
> + /*
> + * On SMP we know no other CPUs can use this CPU's or
> + * each other's VMID since the kvm_vmid_lock blocks
> + * them from reentry to the guest.
> + */
> +
> + reset_vm_context(NULL);
These two lines can be folded as on_each_cpu().
Don't you have a race here where you can increment the generation just
before guest entry?
cpu0 cpu1
(vmid=0, gen=1) (gen=0)
-------------------------- ----------------------
gen == global_gen, return
gen != global_gen
increment global_gen
smp_call_function
reset_vm_context
vmid=0
enter with vmid=0 enter with vmid=0
You must recheck gen after disabling interrupts to ensure global_gen
didn't bump after update_vttbr but before entry. x86 has a lot of this,
see vcpu_enter_guest() and vcpu->requests (doesn't apply directly to
your case but may come in useful later).
>
>>> +
>>> +/**
>>> + * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest
>>> code
>>> + * @vcpu: The VCPU pointer
>>> + * @run: The kvm_run structure pointer used for userspace state
>>> exchange
>>> + *
>>> + * This function is called through the VCPU_RUN ioctl called from user
>>> space. It
>>> + * will execute VM code in a loop until the time slice for the process is
>>> used
>>> + * or some emulation is needed from user space in which case the function
>>> will
>>> + * return with return value 0 and with the kvm_run structure filled in
>>> with the
>>> + * required data for the requested emulation.
>>> + */
>>> int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>>> {
>>> - return -EINVAL;
>>> + int ret = 0;
>>> + sigset_t sigsaved;
>>> +
>>> + if (vcpu->sigset_active)
>>> + sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
>>> +
>>> + run->exit_reason = KVM_EXIT_UNKNOWN;
>>> + while (run->exit_reason == KVM_EXIT_UNKNOWN) {
>>
>> It's not a good idea to read stuff from run unless it's part of the ABI,
>> since userspace can play with it while you're reading it. It's harmless
>> here but in other places it can lead to a vulnerability.
>>
>
> ok, so in this case, userspace can 'suppress' an MMIO or interrupt
> window operation.
>
> I can change to keep some local variable to maintain the state and
> have some API convention for emulation functions, if you feel strongly
> about it, but otherwise it feels to me like the code will be more
> complicated. Do you have other ideas?
x86 uses:
0 - return to userspace (run prepared)
1 - return to guest (run untouched)
-ESOMETHING - return to userspace
as return values from handlers and for locals (usually named 'r').
--
error compiling committee.c: too many arguments to function
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html