X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=guest%2Flinux%2Fhvm-ros%2Fv3_hvm_ros_user.c;h=9928ba97fbd102b59c64edbb7bf47f422c39d6c6;hb=15b65ca6d546fbd03cdd7ae72830555e0263e538;hp=345f8cb719d61442e2fb4933a9e40a6c6a1c0064;hpb=d13fa71cb7a372c39ea92aaa69d74d63d9e0ed8e;p=palacios.git diff --git a/guest/linux/hvm-ros/v3_hvm_ros_user.c b/guest/linux/hvm-ros/v3_hvm_ros_user.c index 345f8cb..9928ba9 100644 --- a/guest/linux/hvm-ros/v3_hvm_ros_user.c +++ b/guest/linux/hvm-ros/v3_hvm_ros_user.c @@ -2,28 +2,34 @@ Copyright (c) 2015 Peter Dinda */ -#include #include #include #include #include +#include +#include #include +#include #include "v3_hvm_ros_user.h" -#define DEBUG_OUTPUT 0 -#define INFO_OUTPUT 0 +#define HRT_FAIL_VEC 0x1d + +static FILE *log = NULL; + -#if DEBUG_OUTPUT -#define DEBUG(...) fprintf(stderr,__VA_ARGS__) +#if DEBUG_ENABLE==1 +#define DEBUG(fmt, args...) if (log) { fprintf(log, "DEBUG: " fmt, ##args); } #else #define DEBUG(...) #endif -#if INFO_OUTPUT -#define INFO(...) fprintf(stdout,__VA_ARGS__) +#if INFO_ENABLE==1 +#define INFO(fmt, args...) if (log) { fprintf(log, fmt, ##args); } + fprintf(stdout, fmt, ##args); \ + } #else #define INFO(...) #endif @@ -118,10 +124,37 @@ typedef unsigned char uchar_t; #define HCALL(rc,id,a,b,c,d,e,f,g,h) HCALL32(rc,id,a,b,c,d,e,f,g,h) #endif +static inline uint64_t +Syscall (uint64_t num, + uint64_t a1, + uint64_t a2, + uint64_t a3, + uint64_t a4, + uint64_t a5, + uint64_t a6) +{ + uint64_t rc; + + __asm__ __volatile__ ("movq %1, %%rax; " + "movq %2, %%rdi; " + "movq %3, %%rsi; " + "movq %4, %%rdx; " + "movq %5, %%r10; " + "movq %6, %%r8; " + "movq %7, %%r9; " + "syscall; " + "movq %%rax, %0; " + : "=m"(rc) + : "m"(num), "m"(a1), "m"(a2), "m"(a3), "m"(a4), "m"(a5), "m"(a6) + : "%rax", "%rdi", "%rcx", "%rsi", "%rdx", "%r10", "%r8", "%r9", "%r11", "memory"); + + return rc; +} + /* This must match the definition in palacios/include/palacios/vmm_hvm.h" */ struct v3_ros_event { - enum { ROS_NONE=0, ROS_PAGE_FAULT=1, ROS_SYSCALL=2 } event_type; + enum { ROS_NONE=0, ROS_PAGE_FAULT=1, ROS_SYSCALL=2, HRT_EXCEPTION=3, HRT_THREAD_EXIT=4, ROS_DONE=5} event_type; uint64_t last_ros_event_result; // valid when ROS_NONE union { struct { // valid when ROS_PAGE_FAULT @@ -132,23 +165,130 @@ struct v3_ros_event { struct { // valid when ROS_SYSCALL uint64_t args[8]; } syscall; + struct { // valid when HRT_EXCEPTION + uint64_t rip; + uint64_t vector; + } excp; + struct { // valid when HRT_THREAD_EXIT + uint64_t nktid; + } thread_exit; }; }; int v3_hvm_ros_user_init() { - // currently nothing to do + log = stderr; + return 0; +} + + +int v3_hvm_ros_user_set_log(FILE *l) +{ + log = l; return 0; } int v3_hvm_ros_user_deinit() { - // currently nothing to do + log = NULL; + return 0; +} + + +int v3_hvm_handle_ros_event_nohcall(struct v3_ros_event *event) +{ + uint64_t rc; + char t; + + switch (event->event_type) { + case ROS_PAGE_FAULT: + // force the ros kernel to the PTE + if (event->page_fault.action==ROS_READ) { + DEBUG("EVENT [PF READ] : %p\n", (volatile char*)(event->page_fault.cr2)); + t=*(volatile char*)(event->page_fault.cr2); + t=t; // avoid wanting for this throwaway + } else if (event->page_fault.action==ROS_WRITE) { + DEBUG("EVENT [PF WRITE] : %p\n", (volatile char*)(event->page_fault.cr2)); + + // stash the old contents + char tmp = *((volatile char *)event->page_fault.cr2); + + // force a write + *((volatile char*)event->page_fault.cr2) = 0xa; + + // put the old value back + *((volatile char*)event->page_fault.cr2) = tmp; + + } else { + INFO("Huh?\n"); + } + + DEBUG("Done."); + event->last_ros_event_result = 0; + //event->event_type = ROS_DONE; + event->event_type = ROS_NONE; + // completed + DEBUG("[OK]\n"); + + break; + + case ROS_SYSCALL: + DEBUG("EVENT [SYSCALL] : syscall(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", + event->syscall.args[0], + event->syscall.args[1], + event->syscall.args[2], + event->syscall.args[3], + event->syscall.args[4], + event->syscall.args[5], + event->syscall.args[6], + event->syscall.args[7]); + + rc = Syscall(event->syscall.args[0], + event->syscall.args[1], + event->syscall.args[2], + event->syscall.args[3], + event->syscall.args[4], + event->syscall.args[5], + event->syscall.args[6]); + + if ((long int)rc<0) { + DEBUG("Syscall (num=0x%llx) failed (rc=0x%llx)\n", (unsigned long long)event->syscall.args[0], (unsigned long long)rc); + } + + DEBUG("Return = 0x%lx...", rc); + event->last_ros_event_result = rc; + //event->event_type = ROS_DONE; + event->event_type = ROS_NONE; + DEBUG("[OK]\n"); + + break; + + case HRT_EXCEPTION: + DEBUG("EVENT [EXCEPTION] : (tid=%lx) at %p vector=0x%lx...", syscall(SYS_gettid), (void*)event->excp.rip, event->excp.vector); + if (event->excp.vector == HRT_FAIL_VEC) { + INFO("HRT execution failed due to exception in HRT\n"); + } else { + INFO("HRT execution failed due to exception in ROS (vec=0x%lx)\n", event->excp.vector); + } + + event->last_ros_event_result = 0; + //event->event_type = ROS_DONE; + event->event_type = ROS_NONE; + DEBUG("[OK]\n"); + exit(EXIT_FAILURE); + break; + + default: + DEBUG( "Unknown ROS event 0x%x\n", event->event_type); + break; + } + return 0; } -static void handle_ros_event(struct v3_ros_event *event) + +int v3_hvm_handle_ros_event(struct v3_ros_event *event) { unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0; char t; @@ -161,60 +301,105 @@ static void handle_ros_event(struct v3_ros_event *event) t=*(volatile char*)(event->page_fault.cr2); t=t; // avoid wanting for this throwaway } else if (event->page_fault.action==ROS_WRITE) { - DEBUG("Handling page fault writefor %p\n", (volatile char*)(event->page_fault.cr2)); - *(volatile char*)(event->page_fault.cr2) = *(volatile char *)(event->page_fault.cr2); + DEBUG("Handling page fault write for %p\n", (volatile char*)(event->page_fault.cr2)); + + // stash the old contents + char tmp = *((volatile char *)event->page_fault.cr2); + + // force a write + *((volatile char*)event->page_fault.cr2) = 0xa; + + // put the old value back + *((volatile char*)event->page_fault.cr2) = tmp; + } else { INFO("Huh?\n"); } - DEBUG("Done - doing hypercall\n"); + + DEBUG("Done - doing hypercall..."); num = 0xf00d; a1 = 0x1f; a2 = 0; // success HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8); // completed - DEBUG("Completed.\n"); - + DEBUG("[OK]\n"); + break; case ROS_SYSCALL: DEBUG("Doing system call: syscall(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", - event->syscall.args[0], - event->syscall.args[1], - event->syscall.args[2], - event->syscall.args[3], - event->syscall.args[4], - event->syscall.args[5], - event->syscall.args[6], - event->syscall.args[7]); - - rc = syscall(event->syscall.args[0], + event->syscall.args[0], + event->syscall.args[1], + event->syscall.args[2], + event->syscall.args[3], + event->syscall.args[4], + event->syscall.args[5], + event->syscall.args[6], + event->syscall.args[7]); + + rc = Syscall(event->syscall.args[0], event->syscall.args[1], event->syscall.args[2], event->syscall.args[3], event->syscall.args[4], event->syscall.args[5], - event->syscall.args[6], - event->syscall.args[7]); - - if ((int)rc<0) { - DEBUG("syscall failed"); + event->syscall.args[6]); + + if ((long int)rc<0) { + DEBUG("Syscall (num=0x%llx) failed (rc=0x%llx)\n", (unsigned long long)event->syscall.args[0], (unsigned long long)rc); } - - DEBUG("Return = 0x%llx, doing hypercall\n", rc); + + DEBUG("Return = 0x%llx, doing hypercall...", rc); num = 0xf00d; a1 = 0x1f; a2 = rc; HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8); - DEBUG("Completed\n"); + DEBUG("[OK]\n"); + + break; + case HRT_EXCEPTION: + DEBUG("Handling exception (tid=%lx) at %p vector=0x%lx...", syscall(SYS_gettid), (void*)event->excp.rip, event->excp.vector); + if (event->excp.vector == HRT_FAIL_VEC) { + INFO("HRT execution failed due to exception in HRT\n"); + } else { + INFO("HRT execution failed due to exception in ROS (vec=0x%lx)\n", event->excp.vector); + } + + num = 0xf00d; + a1 = 0x1f; + a2 = rc; + HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8); + DEBUG("[OK]\n"); + exit(EXIT_FAILURE); break; + default: DEBUG( "Unknown ROS event 0x%x\n", event->event_type); break; } + + return 0; } + +static void wait_for_merge_completion() +{ + unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0; + struct v3_ros_event event; + memset(&event, 1, sizeof(event)); + rc = 1; + + while (rc) { + num = 0xf00d; + a1 = 0xf; + a2 = (unsigned long long) &event; + HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8); + } + +} + static void wait_for_completion() { @@ -233,7 +418,7 @@ static void wait_for_completion() if (rc) { // usleep(100); if (event.event_type != ROS_NONE) { - handle_ros_event(&event); + v3_hvm_handle_ros_event(&event); } } } @@ -307,7 +492,7 @@ int v3_hvm_ros_merge_address_spaces() INFO("Error in request to merge address spaces rc=0x%llx\n",rc); return -1; } else { - wait_for_completion(); + wait_for_merge_completion(); return 0; } } @@ -330,6 +515,44 @@ int v3_hvm_ros_unmerge_address_spaces() } +int v3_hvm_ros_mirror_gdt(uint64_t fsbase, uint64_t cpu) +{ + unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0; + unsigned long long rc; + + num=0xf00d; + a1 = 0x51; // mirror the ROS FS and GS on the HRT side + a2 = fsbase; + a3 = cpu; + HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8); + if (rc) { + INFO("Error in request to mirror GDT (rc=0x%llx)\n", rc); + return -1; + } else { + wait_for_completion(); + return 0; + } + +} + +int v3_hvm_ros_unmirror_gdt() +{ + unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0; + unsigned long long rc; + + num=0xf00d; + a1 = 0x53; // unmirror GDT and the rest + HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8); + if (rc) { + INFO("Error in request to unmirror GDT (rc=0x%llx)\n", rc); + return -1; + } else { + wait_for_completion(); + return 0; + } +} + + int v3_hvm_ros_invoke_hrt_async(void *buf, int par) { unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0; @@ -352,6 +575,22 @@ int v3_hvm_ros_invoke_hrt_async(void *buf, int par) } } +int v3_hvm_ros_invoke_hrt_async_nowait(void *buf, int par) +{ + unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0; + unsigned long long rc; + + num=0xf00d; + if (par) { + a1 = 0x21; // issue "function" in parallel + } else { + a1 = 0x20; // issue "function" sequentially + } + a2 = (unsigned long long) buf; + HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8); + return 0; +} + @@ -401,7 +640,7 @@ static void wait_for_sync() if (rc!=4) { // usleep(100); if (event.event_type != ROS_NONE) { - handle_ros_event(&event); + v3_hvm_handle_ros_event(&event); } } } @@ -473,10 +712,96 @@ int v3_hvm_ros_invoke_hrt_sync(void *buf, int ros) a2 = (unsigned long long) &event; HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8); if (event.event_type != ROS_NONE) { - handle_ros_event(&event); + v3_hvm_handle_ros_event(&event); } } } return 0; } +extern void *__v3_hvm_ros_signal_handler_stub; + +void (*__v3_hvm_ros_signal_handler)(uint64_t) = 0; +static void *__v3_hvm_ros_signal_handler_stack = 0; +static uint64_t __v3_hvm_ros_signal_handler_stack_size=0; + +int v3_hvm_ros_register_signal(void (*h)(uint64_t), void *stack, uint64_t stack_size) +{ + unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0; + + if (mlock(stack,stack_size)) { + INFO("Can't pin stack - proceeding\n"); + } + + // clear it and touch it + memset(stack,0,stack_size); + + __v3_hvm_ros_signal_handler_stack = stack; + __v3_hvm_ros_signal_handler_stack_size = stack_size; + __v3_hvm_ros_signal_handler = h; + + // Attempt to install + + num = 0xf00d; + a1 = 0x40; + a2 = (unsigned long long) &__v3_hvm_ros_signal_handler_stub; + a3 = (unsigned long long) stack + stack_size - 16; // put us at the top of the stack, and 16 byte aligned + + HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8); + if (rc) { + INFO("Failed to install HVM signal handler\n"); + return -1; + } + + return 0; +} + +int v3_hvm_ros_unregister_signal() +{ + unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0; + + // an unregister boils down to setting handler to null + num = 0xf00d; + a1 = 0x40; + a2 = (unsigned long long) 0; + a3 = (unsigned long long) 0; + + HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8); + + if (rc) { + INFO("Failed to uninstall HVM signal handler\n"); + } + + // and now do user space cleanup + + __v3_hvm_ros_signal_handler = 0; + + if (__v3_hvm_ros_signal_handler_stack) { + munlock(__v3_hvm_ros_signal_handler_stack,__v3_hvm_ros_signal_handler_stack_size); + __v3_hvm_ros_signal_handler_stack = 0; + __v3_hvm_ros_signal_handler_stack_size = 0; + } + + if (rc) { + return -1; + } else { + return 0; + } +} + + +int v3_hvm_hrt_signal_ros(uint64_t code) +{ + unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0; + + num = 0xf00d; + a1 = 0x41; + a2 = (unsigned long long) code; + + HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8); + + return rc ? -1 : rc; + +} + +