| /* Copyright (c) 2016 Google Inc. |
| * Barret Rhoden <brho@cs.berkeley.edu> |
| * See LICENSE for details. |
| * |
| * Helper functions for virtual machines */ |
| |
| #include <vmm/vmm.h> |
| #include <errno.h> |
| #include <parlib/bitmask.h> |
| #include <parlib/uthread.h> |
| #include <sys/syscall.h> |
| |
| /* Sends an interrupt with @vector to guest pcore @gpcoreid. Returns 0 on |
| * success, -1 with errstr set o/w. */ |
| int vmm_interrupt_guest(struct virtual_machine *vm, unsigned int gpcoreid, |
| unsigned int vector) |
| { |
| struct guest_thread *gth; |
| struct vmm_gpcore_init *gpci; |
| |
| if (gpcoreid >= vm->nr_gpcs) { |
| werrstr("Guest pcoreid %d out of range (%d gpcs)", gpcoreid, |
| vm->nr_gpcs); |
| return -1; |
| } |
| gth = gpcid_to_gth(vm, gpcoreid); |
| gpci = gth_to_gpci(gth); |
| /* The OUTSTANDING_NOTIF bit (256) is one greater than the last valid |
| * descriptor */ |
| if (vector >= VMX_POSTED_OUTSTANDING_NOTIF) { |
| werrstr("Interrupt vector %d too high (max %d)", vector, |
| VMX_POSTED_OUTSTANDING_NOTIF - 1); |
| return -1; |
| } |
| /* Syncing with halting guest threads. The Mutex protects changes to |
| * the posted irq descriptor. */ |
| uth_mutex_lock(gth->halt_mtx); |
| SET_BITMASK_BIT_ATOMIC(gpci->posted_irq_desc, vector); |
| /* Atomic op provides the mb() btw writing the vector and mucking with |
| * OUTSTANDING_NOTIF. |
| * |
| * If we set notif, it's on us to inject the IRQ. Either way, notif |
| * will be set and we must kick the CV, unconditionally. */ |
| if (!GET_BITMASK_BIT(gpci->posted_irq_desc, |
| VMX_POSTED_OUTSTANDING_NOTIF)) { |
| SET_BITMASK_BIT_ATOMIC(gpci->posted_irq_desc, |
| VMX_POSTED_OUTSTANDING_NOTIF); |
| ros_syscall(SYS_vmm_poke_guest, gpcoreid, 0, 0, 0, 0, 0); |
| } |
| uth_cond_var_signal(gth->halt_cv); |
| uth_mutex_unlock(gth->halt_mtx); |
| return 0; |
| } |