Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


HVM capability enhancement: asynchronous upcalls to ROS userspace
[palacios.git] / guest / linux / hvm-ros / v3_hvm_ros_user.c
1 /*
2   Copyright (c) 2015 Peter Dinda
3 */
4
5 #include <sys/syscall.h>
6 #include <unistd.h>
7 #include <stdint.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11
12 #include <sys/mman.h>
13
14 #include "v3_hvm_ros_user.h"
15
16
17 #define DEBUG_OUTPUT 0
18 #define INFO_OUTPUT 0
19
20 #if DEBUG_OUTPUT
21 #define DEBUG(...) fprintf(stderr,__VA_ARGS__)
22 #else
23 #define DEBUG(...)
24 #endif
25
26 #if INFO_OUTPUT
27 #define INFO(...) fprintf(stdout,__VA_ARGS__)
28 #else
29 #define INFO(...)
30 #endif
31
32
33
34 typedef unsigned char uchar_t;
35
36 #define rdtscll(val)                                    \
37     do {                                                \
38         uint64_t tsc;                                   \
39         uint32_t a, d;                                  \
40         asm volatile("rdtsc" : "=a" (a), "=d" (d));     \
41         *(uint32_t *)&(tsc) = a;                        \
42         *(uint32_t *)(((uchar_t *)&tsc) + 4) = d;       \
43         val = tsc;                                      \
44     } while (0)                                 
45
46
47 /*
48   This convention match the definition in palacios/include/palacios/vmm_hvm.h
49
50   Calling convention:
51
52 64 bit:
53   rax = hcall number
54   rbx = 0x6464646464646464...
55   rcx = 1st arg
56   rdx = 2nd arg
57   rsi = 3rd arg
58   rdi = 4th arg
59   r8  = 5th arg
60   r9  = 6th arg
61   r10 = 7th arg
62   r11 = 8th arg
63
64 32 bit:
65   eax = hcall number
66   ebx = 0x32323232
67   arguments on stack in C order (first argument is TOS)
68      arguments are also 32 bit
69 */
70 #define HCALL64(rc,id,a,b,c,d,e,f,g,h)                \
71   asm volatile ("movq %1, %%rax; "                    \
72                 "pushq %%rbx; "                       \
73                 "movq $0x6464646464646464, %%rbx; "   \
74                 "movq %2, %%rcx; "                    \
75                 "movq %3, %%rdx; "                    \
76                 "movq %4, %%rsi; "                    \
77                 "movq %5, %%rdi; "                    \
78                 "movq %6, %%r8 ; "                    \
79                 "movq %7, %%r9 ; "                    \
80                 "movq %8, %%r10; "                    \
81                 "movq %9, %%r11; "                    \
82                 "vmmcall ;       "                    \
83                 "movq %%rax, %0; "                    \
84                 "popq %%rbx; "                        \
85                 : "=m"(rc)                            \
86                 : "m"(id),                            \
87                   "m"(a), "m"(b), "m"(c), "m"(d),     \
88                   "m"(e), "m"(f), "m"(g), "m"(h)      \
89                 : "%rax","%rcx","%rdx","%rsi","%rdi", \
90                   "%r8","%r9","%r10","%r11"           \
91                 )
92
93 #define HCALL32(rc,id,a,b,c,d,e,f,g,h)                \
94   asm volatile ("movl %1, %%eax; "                    \
95                 "pushl %%ebx; "                       \
96                 "movl $0x32323232, %%ebx; "           \
97                 "pushl %9;"                           \
98                 "pushl %8;"                           \
99                 "pushl %7;"                           \
100                 "pushl %6;"                           \
101                 "pushl %5;"                           \
102                 "pushl %4;"                           \
103                 "pushl %3;"                           \
104                 "pushl %2;"                           \
105                 "vmmcall ;       "                    \
106                 "movl %%eax, %0; "                    \
107                 "addl $32, %%esp; "                   \
108                 "popl %%ebx; "                        \
109                 : "=r"(rc)                            \
110                 : "m"(id),                            \
111                   "m"(a), "m"(b), "m"(c), "m"(d),     \
112                 "m"(e), "m"(f), "m"(g), "m"(h)        \
113                 : "%eax"                              \
114                 )
115
116 #ifdef __x86_64__
117 #define HCALL(rc,id,a,b,c,d,e,f,g,h)  HCALL64(rc,id,a,b,c,d,e,f,g,h)
118 #else
119 #define HCALL(rc,id,a,b,c,d,e,f,g,h)  HCALL32(rc,id,a,b,c,d,e,f,g,h)   
120 #endif
121
122
123 /* This must match the definition in palacios/include/palacios/vmm_hvm.h" */
124 struct v3_ros_event {
125     enum { ROS_NONE=0, ROS_PAGE_FAULT=1, ROS_SYSCALL=2 } event_type;
126     uint64_t       last_ros_event_result; // valid when ROS_NONE
127     union {
128         struct {   // valid when ROS_PAGE_FAULT
129             uint64_t rip;
130             uint64_t cr2;
131             enum {ROS_READ, ROS_WRITE} action;
132         } page_fault;
133         struct { // valid when ROS_SYSCALL
134             uint64_t args[8];
135         } syscall;
136     };
137 };
138
139
140 int v3_hvm_ros_user_init()
141 {
142     // currently nothing to do
143     return 0;
144 }
145
146 int v3_hvm_ros_user_deinit()
147 {
148     // currently nothing to do
149     return 0;
150 }
151
152 static void handle_ros_event(struct v3_ros_event *event)
153 {
154     unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
155     char t;
156
157     switch (event->event_type) { 
158         case ROS_PAGE_FAULT: 
159             // force the ros kernel to the PTE
160             if (event->page_fault.action==ROS_READ) { 
161                 DEBUG("Handling page fault read for %p\n", (volatile char*)(event->page_fault.cr2));
162                 t=*(volatile char*)(event->page_fault.cr2);
163                 t=t; // avoid wanting for this throwaway
164             } else if (event->page_fault.action==ROS_WRITE) { 
165                 DEBUG("Handling page fault writefor %p\n", (volatile char*)(event->page_fault.cr2));
166                 *(volatile char*)(event->page_fault.cr2) = *(volatile char *)(event->page_fault.cr2);
167             } else {
168                 INFO("Huh?\n");
169             }
170             DEBUG("Done - doing hypercall\n");
171             num = 0xf00d;
172             a1 = 0x1f;
173             a2 = 0; // success
174             HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
175             // completed
176             DEBUG("Completed.\n");
177
178             break;
179             
180         case ROS_SYSCALL:
181             DEBUG("Doing system call: syscall(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
182                     event->syscall.args[0],
183                     event->syscall.args[1],
184                     event->syscall.args[2],
185                     event->syscall.args[3],
186                     event->syscall.args[4],
187                     event->syscall.args[5],
188                     event->syscall.args[6],
189                     event->syscall.args[7]);
190
191             rc = syscall(event->syscall.args[0],
192                          event->syscall.args[1],
193                          event->syscall.args[2],
194                          event->syscall.args[3],
195                          event->syscall.args[4],
196                          event->syscall.args[5],
197                          event->syscall.args[6],
198                          event->syscall.args[7]);
199
200             if ((int)rc<0) {
201                 DEBUG("syscall failed");
202             }
203
204             DEBUG("Return = 0x%llx, doing hypercall\n", rc);
205             num = 0xf00d;
206             a1 = 0x1f;
207             a2 = rc;
208             HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
209             DEBUG("Completed\n");
210
211             break;
212         default:
213             DEBUG( "Unknown ROS event 0x%x\n", event->event_type);
214             break;
215     }
216 }
217     
218     
219
220 static void wait_for_completion()
221 {
222   unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
223   struct v3_ros_event event;
224
225   memset(&event, 1, sizeof(event));
226
227   rc = 1;
228
229   while (rc) { 
230     num = 0xf00d;
231     a1 = 0xf;
232     a2 = (unsigned long long) &event;
233     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
234     if (rc) { 
235         //      usleep(100);
236         if (event.event_type != ROS_NONE) { 
237             handle_ros_event(&event);
238         }
239     }
240   }
241 }
242
243
244 int v3_hvm_ros_install_hrt_image(void *image, uint64_t size)
245 {
246     unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
247     unsigned long long i;
248     volatile long long sum=0;
249
250     num = 0xf00d;
251     a1 = 0x8; // install image
252     a2 = (unsigned long long) image;
253     a3 = size;
254
255     // touch the whoel image to make it has ptes
256     for (i=0;i<size;i++) { 
257         sum+=((char*)image)[i];
258     }
259
260     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
261
262     if (rc) { 
263         return -1;
264     } else {
265         return 0;
266     }
267 }
268
269 int v3_hvm_ros_reset(reset_type what)
270 {
271     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
272     unsigned long long rc;
273     
274     num=0xf00d;
275     switch (what) { 
276         case RESET_ROS:
277             a1 = 0x1;
278             break;
279         case RESET_HRT:
280             a1 = 0x2;
281             break;
282         case RESET_BOTH:
283             a1 = 0x3;
284             break;
285     }
286     
287     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
288     
289     if (rc) {
290         INFO("Error in request to reset rc=0x%llx\n",rc);
291         return -1;
292     } else {
293         // no waiting for completion here
294         return 0;
295     }
296 }
297
298
299 int v3_hvm_ros_merge_address_spaces()
300 {
301     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
302     unsigned long long rc;
303
304     num=0xf00d;
305     a1 = 0x30; // merge address spaces
306     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
307     if (rc) {
308       INFO("Error in request to merge address spaces rc=0x%llx\n",rc);
309       return -1;
310     } else {
311       wait_for_completion();
312       return 0;
313     }
314 }
315
316 int v3_hvm_ros_unmerge_address_spaces()
317 {
318     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
319     unsigned long long rc;
320
321     num=0xf00d;
322     a1 = 0x31; // merge address spaces
323     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
324     if (rc) {
325       INFO("Error in request to unmerge address spaces rc=0x%llx\n",rc);
326       return -1;
327     } else {
328       wait_for_completion();
329       return 0;
330     }
331 }
332
333
334 int v3_hvm_ros_invoke_hrt_async(void *buf, int par)
335 {
336     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
337     unsigned long long rc;
338
339     num=0xf00d;
340     if (par) { 
341         a1 = 0x21; // issue "function" in parallel
342     } else {
343         a1 = 0x20; // issue "function" sequentially
344     }
345     a2 = (unsigned long long) buf;
346     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
347     if (rc) { 
348         INFO("Error in request to launch %s function rc=0x%llx\n", par ? "parallel" : "", rc);
349         return -1;
350     } else {
351         wait_for_completion();
352         return 0;
353     }
354 }
355
356
357
358
359
360 /*
361   Synchronous operation model 
362
363   On ROS:
364
365   [0] => issue count
366   [1] => completion count
367   [2] => function call ptr
368
369   1. merge
370   2. indicate this is the address for sync
371   3. ++[0]
372   4. wait for [1] to match
373   5. goto 3
374
375   On HRT:
376
377   1. merge
378   2. cnt=1;
379   3. wait for [0] to get to cnt
380   4. exec
381   5. ++[1]   ++cnt
382   6. goto 3
383 */
384
385 static volatile unsigned long long sync_proto[3]={0,0,0};
386
387
388 static void wait_for_sync()
389 {
390   unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
391   struct v3_ros_event event;
392
393   memset(&event, 1, sizeof(event));
394   
395   rc = 1;
396
397   while (rc!=4) { 
398     num = 0xf00d;
399     a1 = 0xf;
400     a2 = (unsigned long long) &event;
401     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
402     if (rc!=4) { 
403         //      usleep(100);
404         if (event.event_type != ROS_NONE) { 
405             handle_ros_event(&event);
406         }
407     }
408   }
409 }
410
411
412 int v3_hvm_ros_synchronize()
413 {
414     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
415     unsigned long long rc;
416
417     // make sure this address is touched, then zero
418     sync_proto[0]=sync_proto[1]=sync_proto[2]=1;
419     sync_proto[0]=sync_proto[1]=sync_proto[2]=0;
420
421     num=0xf00d;
422     a1 = 0x28; // issue sync request setup
423     a2 = (unsigned long long) sync_proto;
424     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
425     
426     if (rc) { 
427         INFO("Synchronize call failed with rc=0x%llx\n",rc);
428         return -1;
429     } else {
430         wait_for_sync();
431         return 0;
432     }
433 }
434
435
436 int v3_hvm_ros_desynchronize()
437 {
438     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
439     unsigned long long rc;
440
441     num=0xf00d;
442     a1 = 0x29; // issue sync request teardown
443     a2 = (unsigned long long) sync_proto;
444     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
445
446     if (rc) { 
447         INFO("Desynchronize call failed with rc=0x%llx\n",rc);
448         return -1;
449     } else {
450         wait_for_completion();
451         return 0;
452     }
453 }
454
455 #define HOW_OFTEN 1000000
456
457 int v3_hvm_ros_invoke_hrt_sync(void *buf, int ros)
458 {
459     int i;
460     sync_proto[2]=(unsigned long long)buf;
461     sync_proto[0]++;
462
463     i=0;
464     while (sync_proto[1] != sync_proto[0]) {
465         i++;
466         if (ros && (!i%HOW_OFTEN)) { 
467             unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
468             struct v3_ros_event event;
469
470             memset(&event, 1, sizeof(event));
471
472             num = 0xf00d;
473             a1 = 0xf;
474             a2 = (unsigned long long) &event;
475             HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
476             if (event.event_type != ROS_NONE) { 
477                 handle_ros_event(&event);
478             }
479         }
480     }   
481     return 0;
482 }
483
484 extern void *__v3_hvm_ros_signal_handler_stub;
485
486 void (*__v3_hvm_ros_signal_handler)(uint64_t) = 0;
487 static void *__v3_hvm_ros_signal_handler_stack = 0;
488 static uint64_t __v3_hvm_ros_signal_handler_stack_size=0;
489
490 int v3_hvm_ros_register_signal(void (*h)(uint64_t), void *stack, uint64_t stack_size )
491 {
492     unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
493
494     if (mlock(stack,stack_size)) { 
495         INFO("Can't pin stack - proceeding\n");
496     }
497
498     // clear it and touch it
499     memset(stack,0,stack_size);
500
501     __v3_hvm_ros_signal_handler_stack = stack;
502     __v3_hvm_ros_signal_handler_stack_size = stack_size;
503     __v3_hvm_ros_signal_handler = h;
504
505     // Attempt to install
506     
507     num = 0xf00d;
508     a1 = 0x40;
509     a2 = (unsigned long long) &__v3_hvm_ros_signal_handler_stub;
510     a3 = (unsigned long long) stack + stack_size - 8; // put us at the top of the stack
511
512     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
513     if (rc) {
514         INFO("Failed to install HVM signal handler\n");
515         return -1;
516     } 
517
518     return 0;
519 }
520
521 int v3_hvm_ros_unregister_signal()
522 {
523     unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
524
525     // an unregister boils down to setting handler to null
526     num = 0xf00d;
527     a1 = 0x40;
528     a2 = (unsigned long long) 0;
529     a3 = (unsigned long long) 0; 
530
531     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
532
533     if (rc) {
534         INFO("Failed to uninstall HVM signal handler\n");
535     } 
536
537     // and now do user space cleanup
538
539     __v3_hvm_ros_signal_handler = 0;
540
541     if (__v3_hvm_ros_signal_handler_stack) { 
542         munlock(__v3_hvm_ros_signal_handler_stack,__v3_hvm_ros_signal_handler_stack_size);
543         __v3_hvm_ros_signal_handler_stack = 0;
544         __v3_hvm_ros_signal_handler_stack_size = 0;
545     }
546     
547     if (rc) { 
548         return -1;
549     } else {
550         return 0;
551     }
552 }
553
554
555 int  v3_hvm_hrt_signal_ros(uint64_t code)
556 {
557     unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
558
559     num = 0xf00d;
560     a1 = 0x41;
561     a2 = (unsigned long long) code;
562
563     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
564
565     return rc ? -1 : rc;
566
567 }