2 Copyright (c) 2015 Peter Dinda
15 #include "v3_hvm_ros_user.h"
18 #define HRT_FAIL_VEC 0x1d
20 static FILE *log = NULL;
24 #define DEBUG(fmt, args...) if (log) { fprintf(log, "DEBUG: " fmt, ##args); }
30 #define INFO(fmt, args...) if (log) { fprintf(log, fmt, ##args); }
31 fprintf(stdout, fmt, ##args); \
39 typedef unsigned char uchar_t;
41 #define rdtscll(val) \
45 asm volatile("rdtsc" : "=a" (a), "=d" (d)); \
46 *(uint32_t *)&(tsc) = a; \
47 *(uint32_t *)(((uchar_t *)&tsc) + 4) = d; \
53 This convention match the definition in palacios/include/palacios/vmm_hvm.h
59 rbx = 0x6464646464646464...
72 arguments on stack in C order (first argument is TOS)
73 arguments are also 32 bit
75 #define HCALL64(rc,id,a,b,c,d,e,f,g,h) \
76 asm volatile ("movq %1, %%rax; " \
78 "movq $0x6464646464646464, %%rbx; " \
92 "m"(a), "m"(b), "m"(c), "m"(d), \
93 "m"(e), "m"(f), "m"(g), "m"(h) \
94 : "%rax","%rcx","%rdx","%rsi","%rdi", \
95 "%r8","%r9","%r10","%r11" \
98 #define HCALL32(rc,id,a,b,c,d,e,f,g,h) \
99 asm volatile ("movl %1, %%eax; " \
101 "movl $0x32323232, %%ebx; " \
112 "addl $32, %%esp; " \
116 "m"(a), "m"(b), "m"(c), "m"(d), \
117 "m"(e), "m"(f), "m"(g), "m"(h) \
122 #define HCALL(rc,id,a,b,c,d,e,f,g,h) HCALL64(rc,id,a,b,c,d,e,f,g,h)
124 #define HCALL(rc,id,a,b,c,d,e,f,g,h) HCALL32(rc,id,a,b,c,d,e,f,g,h)
127 static inline uint64_t
128 Syscall (uint64_t num,
138 __asm__ __volatile__ ("movq %1, %%rax; "
148 : "m"(num), "m"(a1), "m"(a2), "m"(a3), "m"(a4), "m"(a5), "m"(a6)
149 : "%rax", "%rdi", "%rcx", "%rsi", "%rdx", "%r10", "%r8", "%r9", "%r11", "memory");
155 /* This must match the definition in palacios/include/palacios/vmm_hvm.h" */
156 struct v3_ros_event {
157 enum { ROS_NONE=0, ROS_PAGE_FAULT=1, ROS_SYSCALL=2, HRT_EXCEPTION=3, HRT_THREAD_EXIT=4, ROS_DONE=5} event_type;
158 uint64_t last_ros_event_result; // valid when ROS_NONE
160 struct { // valid when ROS_PAGE_FAULT
163 enum {ROS_READ, ROS_WRITE} action;
165 struct { // valid when ROS_SYSCALL
168 struct { // valid when HRT_EXCEPTION
172 struct { // valid when HRT_THREAD_EXIT
179 int v3_hvm_ros_user_init()
186 int v3_hvm_ros_user_set_log(FILE *l)
192 int v3_hvm_ros_user_deinit()
199 int v3_hvm_handle_ros_event_nohcall(struct v3_ros_event *event)
204 switch (event->event_type) {
206 // force the ros kernel to the PTE
207 if (event->page_fault.action==ROS_READ) {
208 DEBUG("EVENT [PF READ] : %p\n", (volatile char*)(event->page_fault.cr2));
209 t=*(volatile char*)(event->page_fault.cr2);
210 t=t; // avoid wanting for this throwaway
211 } else if (event->page_fault.action==ROS_WRITE) {
212 DEBUG("EVENT [PF WRITE] : %p\n", (volatile char*)(event->page_fault.cr2));
214 // stash the old contents
215 char tmp = *((volatile char *)event->page_fault.cr2);
218 *((volatile char*)event->page_fault.cr2) = 0xa;
220 // put the old value back
221 *((volatile char*)event->page_fault.cr2) = tmp;
228 event->last_ros_event_result = 0;
229 //event->event_type = ROS_DONE;
230 event->event_type = ROS_NONE;
237 DEBUG("EVENT [SYSCALL] : syscall(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
238 event->syscall.args[0],
239 event->syscall.args[1],
240 event->syscall.args[2],
241 event->syscall.args[3],
242 event->syscall.args[4],
243 event->syscall.args[5],
244 event->syscall.args[6],
245 event->syscall.args[7]);
247 rc = Syscall(event->syscall.args[0],
248 event->syscall.args[1],
249 event->syscall.args[2],
250 event->syscall.args[3],
251 event->syscall.args[4],
252 event->syscall.args[5],
253 event->syscall.args[6]);
255 if ((long int)rc<0) {
256 DEBUG("Syscall (num=0x%llx) failed (rc=0x%llx)\n", (unsigned long long)event->syscall.args[0], (unsigned long long)rc);
259 DEBUG("Return = 0x%lx...", rc);
260 event->last_ros_event_result = rc;
261 //event->event_type = ROS_DONE;
262 event->event_type = ROS_NONE;
268 DEBUG("EVENT [EXCEPTION] : (tid=%lx) at %p vector=0x%lx...", syscall(SYS_gettid), (void*)event->excp.rip, event->excp.vector);
269 if (event->excp.vector == HRT_FAIL_VEC) {
270 INFO("HRT execution failed due to exception in HRT\n");
272 INFO("HRT execution failed due to exception in ROS (vec=0x%lx)\n", event->excp.vector);
275 event->last_ros_event_result = 0;
276 //event->event_type = ROS_DONE;
277 event->event_type = ROS_NONE;
283 DEBUG( "Unknown ROS event 0x%x\n", event->event_type);
291 int v3_hvm_handle_ros_event(struct v3_ros_event *event)
293 unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
296 switch (event->event_type) {
298 // force the ros kernel to the PTE
299 if (event->page_fault.action==ROS_READ) {
300 DEBUG("Handling page fault read for %p\n", (volatile char*)(event->page_fault.cr2));
301 t=*(volatile char*)(event->page_fault.cr2);
302 t=t; // avoid wanting for this throwaway
303 } else if (event->page_fault.action==ROS_WRITE) {
304 DEBUG("Handling page fault write for %p\n", (volatile char*)(event->page_fault.cr2));
306 // stash the old contents
307 char tmp = *((volatile char *)event->page_fault.cr2);
310 *((volatile char*)event->page_fault.cr2) = 0xa;
312 // put the old value back
313 *((volatile char*)event->page_fault.cr2) = tmp;
319 DEBUG("Done - doing hypercall...");
323 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
330 DEBUG("Doing system call: syscall(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
331 event->syscall.args[0],
332 event->syscall.args[1],
333 event->syscall.args[2],
334 event->syscall.args[3],
335 event->syscall.args[4],
336 event->syscall.args[5],
337 event->syscall.args[6],
338 event->syscall.args[7]);
340 rc = Syscall(event->syscall.args[0],
341 event->syscall.args[1],
342 event->syscall.args[2],
343 event->syscall.args[3],
344 event->syscall.args[4],
345 event->syscall.args[5],
346 event->syscall.args[6]);
348 if ((long int)rc<0) {
349 DEBUG("Syscall (num=0x%llx) failed (rc=0x%llx)\n", (unsigned long long)event->syscall.args[0], (unsigned long long)rc);
352 DEBUG("Return = 0x%llx, doing hypercall...", rc);
356 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
362 DEBUG("Handling exception (tid=%lx) at %p vector=0x%lx...", syscall(SYS_gettid), (void*)event->excp.rip, event->excp.vector);
363 if (event->excp.vector == HRT_FAIL_VEC) {
364 INFO("HRT execution failed due to exception in HRT\n");
366 INFO("HRT execution failed due to exception in ROS (vec=0x%lx)\n", event->excp.vector);
372 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
378 DEBUG( "Unknown ROS event 0x%x\n", event->event_type);
385 static void wait_for_merge_completion()
387 unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
388 struct v3_ros_event event;
390 memset(&event, 1, sizeof(event));
397 a2 = (unsigned long long) &event;
398 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
404 static void wait_for_completion()
406 unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
407 struct v3_ros_event event;
409 memset(&event, 1, sizeof(event));
416 a2 = (unsigned long long) &event;
417 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
420 if (event.event_type != ROS_NONE) {
421 v3_hvm_handle_ros_event(&event);
428 int v3_hvm_ros_install_hrt_image(void *image, uint64_t size)
430 unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
431 unsigned long long i;
432 volatile long long sum=0;
435 a1 = 0x8; // install image
436 a2 = (unsigned long long) image;
439 // touch the whoel image to make it has ptes
440 for (i=0;i<size;i++) {
441 sum+=((char*)image)[i];
444 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
453 int v3_hvm_ros_reset(reset_type what)
455 unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
456 unsigned long long rc;
471 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
474 INFO("Error in request to reset rc=0x%llx\n",rc);
477 // no waiting for completion here
483 int v3_hvm_ros_merge_address_spaces()
485 unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
486 unsigned long long rc;
489 a1 = 0x30; // merge address spaces
490 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
492 INFO("Error in request to merge address spaces rc=0x%llx\n",rc);
495 wait_for_merge_completion();
500 int v3_hvm_ros_unmerge_address_spaces()
502 unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
503 unsigned long long rc;
506 a1 = 0x31; // merge address spaces
507 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
509 INFO("Error in request to unmerge address spaces rc=0x%llx\n",rc);
512 wait_for_completion();
518 int v3_hvm_ros_mirror_gdt(uint64_t fsbase, uint64_t cpu)
520 unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
521 unsigned long long rc;
524 a1 = 0x51; // mirror the ROS FS and GS on the HRT side
527 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
529 INFO("Error in request to mirror GDT (rc=0x%llx)\n", rc);
532 wait_for_completion();
538 int v3_hvm_ros_unmirror_gdt()
540 unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
541 unsigned long long rc;
544 a1 = 0x53; // unmirror GDT and the rest
545 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
547 INFO("Error in request to unmirror GDT (rc=0x%llx)\n", rc);
550 wait_for_completion();
556 int v3_hvm_ros_invoke_hrt_async(void *buf, int par)
558 unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
559 unsigned long long rc;
563 a1 = 0x21; // issue "function" in parallel
565 a1 = 0x20; // issue "function" sequentially
567 a2 = (unsigned long long) buf;
568 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
570 INFO("Error in request to launch %s function rc=0x%llx\n", par ? "parallel" : "", rc);
573 wait_for_completion();
578 int v3_hvm_ros_invoke_hrt_async_nowait(void *buf, int par)
580 unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
581 unsigned long long rc;
585 a1 = 0x21; // issue "function" in parallel
587 a1 = 0x20; // issue "function" sequentially
589 a2 = (unsigned long long) buf;
590 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
599 Synchronous operation model
604 [1] => completion count
605 [2] => function call ptr
608 2. indicate this is the address for sync
610 4. wait for [1] to match
617 3. wait for [0] to get to cnt
623 static volatile unsigned long long sync_proto[3]={0,0,0};
626 static void wait_for_sync()
628 unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
629 struct v3_ros_event event;
631 memset(&event, 1, sizeof(event));
638 a2 = (unsigned long long) &event;
639 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
642 if (event.event_type != ROS_NONE) {
643 v3_hvm_handle_ros_event(&event);
650 int v3_hvm_ros_synchronize()
652 unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
653 unsigned long long rc;
655 // make sure this address is touched, then zero
656 sync_proto[0]=sync_proto[1]=sync_proto[2]=1;
657 sync_proto[0]=sync_proto[1]=sync_proto[2]=0;
660 a1 = 0x28; // issue sync request setup
661 a2 = (unsigned long long) sync_proto;
662 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
665 INFO("Synchronize call failed with rc=0x%llx\n",rc);
674 int v3_hvm_ros_desynchronize()
676 unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
677 unsigned long long rc;
680 a1 = 0x29; // issue sync request teardown
681 a2 = (unsigned long long) sync_proto;
682 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
685 INFO("Desynchronize call failed with rc=0x%llx\n",rc);
688 wait_for_completion();
693 #define HOW_OFTEN 1000000
695 int v3_hvm_ros_invoke_hrt_sync(void *buf, int ros)
698 sync_proto[2]=(unsigned long long)buf;
702 while (sync_proto[1] != sync_proto[0]) {
704 if (ros && (!i%HOW_OFTEN)) {
705 unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
706 struct v3_ros_event event;
708 memset(&event, 1, sizeof(event));
712 a2 = (unsigned long long) &event;
713 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
714 if (event.event_type != ROS_NONE) {
715 v3_hvm_handle_ros_event(&event);
722 extern void *__v3_hvm_ros_signal_handler_stub;
724 void (*__v3_hvm_ros_signal_handler)(uint64_t) = 0;
725 static void *__v3_hvm_ros_signal_handler_stack = 0;
726 static uint64_t __v3_hvm_ros_signal_handler_stack_size=0;
728 int v3_hvm_ros_register_signal(void (*h)(uint64_t), void *stack, uint64_t stack_size)
730 unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
732 if (mlock(stack,stack_size)) {
733 INFO("Can't pin stack - proceeding\n");
736 // clear it and touch it
737 memset(stack,0,stack_size);
739 __v3_hvm_ros_signal_handler_stack = stack;
740 __v3_hvm_ros_signal_handler_stack_size = stack_size;
741 __v3_hvm_ros_signal_handler = h;
743 // Attempt to install
747 a2 = (unsigned long long) &__v3_hvm_ros_signal_handler_stub;
748 a3 = (unsigned long long) stack + stack_size - 16; // put us at the top of the stack, and 16 byte aligned
750 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
752 INFO("Failed to install HVM signal handler\n");
759 int v3_hvm_ros_unregister_signal()
761 unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
763 // an unregister boils down to setting handler to null
766 a2 = (unsigned long long) 0;
767 a3 = (unsigned long long) 0;
769 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
772 INFO("Failed to uninstall HVM signal handler\n");
775 // and now do user space cleanup
777 __v3_hvm_ros_signal_handler = 0;
779 if (__v3_hvm_ros_signal_handler_stack) {
780 munlock(__v3_hvm_ros_signal_handler_stack,__v3_hvm_ros_signal_handler_stack_size);
781 __v3_hvm_ros_signal_handler_stack = 0;
782 __v3_hvm_ros_signal_handler_stack_size = 0;
793 int v3_hvm_hrt_signal_ros(uint64_t code)
795 unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
799 a2 = (unsigned long long) code;
801 HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);