blob: 489d72d9e9fd2db05d107022ba0765d3a1753e22 [file] [log] [blame]
/* Copyright (c) 2017 Google Inc.
* Barret Rhoden <brho@cs.berkeley.edu>
* See LICENSE for details.
*
* vthread_test: mostly create/join/vmcalls */
#include <vmm/vmm.h>
#include <vmm/vthread.h>
#include <parlib/stdio.h>
#include <parlib/uthread.h>
enum {
MY_VMCALL_TEST1 = VTH_VMCALL_NEXT,
MY_VMCALL_TEST2,
};
/* Here's how you can make your own vmcalls and still use the vth vmcalls for
* the stuff you don't want to reimplement. */
static bool extended_handle_vmcall(struct guest_thread *gth,
struct vm_trapframe *vm_tf)
{
switch (vm_tf->tf_rax) {
case MY_VMCALL_TEST1:
goto out_ok;
}
return vth_handle_vmcall(gth, vm_tf);
out_ok:
vm_tf->tf_rip += 3;
return TRUE;
};
static struct virtual_machine vm = {.vmcall = extended_handle_vmcall,
.mtx = UTH_MUTEX_INIT};
static void thread_entry(void *arg)
{
const char nums[] = "123456789";
for (int i = 0; i < sizeof(nums); i++)
vmcall(VTH_VMCALL_PRINTC, nums[i]);
vmcall(MY_VMCALL_TEST1);
vmcall(VTH_VMCALL_EXIT, arg, 0, 0, 0);
}
int main(int argc, char **argv)
{
#define NR_VTHS 5
struct vthread *vths[NR_VTHS];
void *retvals[NR_VTHS];
/* Tests multiple threads at once */
for (long i = 0; i < NR_VTHS; i++)
vths[i] = vthread_create(&vm, thread_entry, (void*)i);
for (long i = 0; i < NR_VTHS; i++) {
vthread_join(vths[i], &retvals[i]);
assert(retvals[i] == (void*)i);
}
/* Tests reuse / GPC leakage */
for (long i = 0; i < NR_VTHS * 2; i++) {
vths[0] = vthread_create(&vm, thread_entry, (void*)i);
vthread_join(vths[0], &retvals[0]);
assert(retvals[0] == (void*)i);
}
assert(vm.nr_gpcs == NR_VTHS);
return 0;
}