/* callback, runs in vcore context. this sets up our initial context. once we * become runnable again, we'll run the first bits of the vm ctx. after that, * our context will be stopped and started and will just run whatever the guest * VM wants. we'll never come back to this code or to run_vm(). */ static void __build_vm_ctx_cb(struct uthread *uth, void *arg) { struct pthread_tcb *pthread = (struct pthread_tcb*)uth; struct vmctl *vmctl = (struct vmctl*)arg; struct vm_trapframe *vm_tf; __pthread_generic_yield(pthread); pthread->state = PTH_BLK_YIELDING; memset(&uth->u_ctx, 0, sizeof(struct user_context)); uth->u_ctx.type = ROS_VM_CTX; vm_tf = &uth->u_ctx.tf.vm_tf; vm_tf->tf_guest_pcoreid = 0; /* assuming only 1 guest core */ copy_vmctl_to_vmtf(vmctl, vm_tf); /* other HW/GP regs are 0, which should be fine. the FP state is still * whatever we were running before, though this is pretty much unnecessary. * we mostly don't want crazy crap in the uth->as, and a non-current_uthread * VM ctx is supposed to have something in their FP state (like HW ctxs). */ save_fp_state(&uth->as); uth->flags |= UTHREAD_FPSAVED | UTHREAD_SAVED; uthread_runnable(uth); }
static void __futex_block(struct uthread *uthread, void *arg) { pthread_t pthread = (pthread_t)uthread; struct futex_element *e = (struct futex_element*)arg; __pthread_generic_yield(pthread); pthread->state = PTH_BLK_MUTEX; e->pthread = pthread; }
static void vmm_thread_refl_fault(struct uthread *uth, struct user_context *ctx) { struct pthread_tcb *pthread = (struct pthread_tcb*)uth; /* Hack to call the original pth 2LS op */ if (!ctx->type == ROS_VM_CTX) { old_thread_refl(uth, ctx); return; } __pthread_generic_yield(pthread); /* normally we'd handle the vmexit here. to work within the existing * framework, we just wake the controller thread. It'll look at our ctx * then make us runnable again */ pthread->state = PTH_BLK_MUTEX; uth_mutex_unlock(the_ball); /* wake the run_vmthread */ }