Skip to content

event synchronization

Mathieu Tarral edited this page Jan 12, 2017 · 2 revisions

This page describe how events are reported to the userland component.

First the nitro struct in the kvm_vcpu has 2 synchronization variables :

struct nitro_vcpu{
  struct completion k_wait_cv;
  struct semaphore n_wait_sem;
  struct event event;
};

When a vcpu is created, the struct will be initialized in this way

void nitro_create_vcpu_hook(struct kvm_vcpu *vcpu){
  vcpu->nitro.event.present = false;
  init_completion(&(vcpu->nitro.k_wait_cv));
  sema_init(&(vcpu->nitro.n_wait_sem),0);
}

Then, when the traps are set

    if (enabled)
    {
        kvm->nitro.traps |= NITRO_TRAP_SYSCALL;
        init_completion(&vcpu->nitro.k_wait_cv);
    }
    else
    {
        kvm->nitro.traps &= ~(NITRO_TRAP_SYSCALL);
        complete_all(&(vcpu->nitro.k_wait_cv));
    }

When a syscall is trapped, in x86.c:vcpu_run

if(vcpu->nitro.event.present)
    nitro_report_event(vcpu);

and nitro_report_event

void nitro_report_event(struct kvm_vcpu *vcpu){
  nitro_wait(vcpu);
  vcpu->nitro.event.present = false;
}

nitro_wait like the name suggests, wait for the userland to pick the event with get_event.

  • up(&(vcpu->nitro.n_wait_sem)); : unlocks the semaphore n_wait_sem, allowing the nitro_main.c:nitro_report_event code to continue and load the event
  • wait_for_completion_interruptible_timeout : waits for userland to call continue_vm
void nitro_wait(struct kvm_vcpu *vcpu){
  long rv;
  
  up(&(vcpu->nitro.n_wait_sem));
  rv = wait_for_completion_interruptible_timeout(&(vcpu->nitro.k_wait_cv),msecs_to_jiffies(30000));
  
  if (rv == 0)
    printk(KERN_INFO "nitro: %s: wait timed out\n",__FUNCTION__);
  else if (rv < 0)
    printk(KERN_INFO "nitro: %s: wait interrupted\n",__FUNCTION__);
  
  return;
}
int nitro_ioctl_get_event(struct kvm_vcpu *vcpu, struct event *ev){
  int rv;
  
  rv = down_interruptible(&(vcpu->nitro.n_wait_sem));
  
  if (rv == 0) {
	  ev->direction = vcpu->nitro.event.direction;
	  ev->type = vcpu->nitro.event.type;
  }
  
  return rv;
}
int nitro_ioctl_continue(struct kvm_vcpu *vcpu){

  //if no waiters
  if(completion_done(&(vcpu->nitro.k_wait_cv)))
    return -1;
  
  complete(&(vcpu->nitro.k_wait_cv));
  return 0;
}
Clone this wiki locally