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.


Linux guest user library and test application for ROS<->HRT interaction in an HVM
[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
13 #include "v3_hvm_ros_user.h"
14
15
16 #define DEBUG_OUTPUT 0
17 #define INFO_OUTPUT 0
18
19 #if DEBUG_OUTPUT
20 #define DEBUG(...) fprintf(stderr,__VA_ARGS__)
21 #else
22 #define DEBUG(...)
23 #endif
24
25 #if INFO_OUTPUT
26 #define INFO(...) fprintf(stdout,__VA_ARGS__)
27 #else
28 #define INFO(...)
29 #endif
30
31
32
33 typedef unsigned char uchar_t;
34
35 #define rdtscll(val)                                    \
36     do {                                                \
37         uint64_t tsc;                                   \
38         uint32_t a, d;                                  \
39         asm volatile("rdtsc" : "=a" (a), "=d" (d));     \
40         *(uint32_t *)&(tsc) = a;                        \
41         *(uint32_t *)(((uchar_t *)&tsc) + 4) = d;       \
42         val = tsc;                                      \
43     } while (0)                                 
44
45
46 /*
47   This convention match the definition in palacios/include/palacios/vmm_hvm.h
48
49   Calling convention:
50
51 64 bit:
52   rax = hcall number
53   rbx = 0x6464646464646464...
54   rcx = 1st arg
55   rdx = 2nd arg
56   rsi = 3rd arg
57   rdi = 4th arg
58   r8  = 5th arg
59   r9  = 6th arg
60   r10 = 7th arg
61   r11 = 8th arg
62
63 32 bit:
64   eax = hcall number
65   ebx = 0x32323232
66   arguments on stack in C order (first argument is TOS)
67      arguments are also 32 bit
68 */
69 #define HCALL64(rc,id,a,b,c,d,e,f,g,h)                \
70   asm volatile ("movq %1, %%rax; "                    \
71                 "pushq %%rbx; "                       \
72                 "movq $0x6464646464646464, %%rbx; "   \
73                 "movq %2, %%rcx; "                    \
74                 "movq %3, %%rdx; "                    \
75                 "movq %4, %%rsi; "                    \
76                 "movq %5, %%rdi; "                    \
77                 "movq %6, %%r8 ; "                    \
78                 "movq %7, %%r9 ; "                    \
79                 "movq %8, %%r10; "                    \
80                 "movq %9, %%r11; "                    \
81                 "vmmcall ;       "                    \
82                 "movq %%rax, %0; "                    \
83                 "popq %%rbx; "                        \
84                 : "=m"(rc)                            \
85                 : "m"(id),                            \
86                   "m"(a), "m"(b), "m"(c), "m"(d),     \
87                   "m"(e), "m"(f), "m"(g), "m"(h)      \
88                 : "%rax","%rcx","%rdx","%rsi","%rdi", \
89                   "%r8","%r9","%r10","%r11"           \
90                 )
91
92 #define HCALL32(rc,id,a,b,c,d,e,f,g,h)                \
93   asm volatile ("movl %1, %%eax; "                    \
94                 "pushl %%ebx; "                       \
95                 "movl $0x32323232, %%ebx; "           \
96                 "pushl %9;"                           \
97                 "pushl %8;"                           \
98                 "pushl %7;"                           \
99                 "pushl %6;"                           \
100                 "pushl %5;"                           \
101                 "pushl %4;"                           \
102                 "pushl %3;"                           \
103                 "pushl %2;"                           \
104                 "vmmcall ;       "                    \
105                 "movl %%eax, %0; "                    \
106                 "addl $32, %%esp; "                   \
107                 "popl %%ebx; "                        \
108                 : "=r"(rc)                            \
109                 : "m"(id),                            \
110                   "m"(a), "m"(b), "m"(c), "m"(d),     \
111                 "m"(e), "m"(f), "m"(g), "m"(h)        \
112                 : "%eax"                              \
113                 )
114
115 #ifdef __x86_64__
116 #define HCALL(rc,id,a,b,c,d,e,f,g,h)  HCALL64(rc,id,a,b,c,d,e,f,g,h)
117 #else
118 #define HCALL(rc,id,a,b,c,d,e,f,g,h)  HCALL32(rc,id,a,b,c,d,e,f,g,h)   
119 #endif
120
121
122 /* This must match the definition in palacios/include/palacios/vmm_hvm.h" */
123 struct v3_ros_event {
124     enum { ROS_NONE=0, ROS_PAGE_FAULT=1, ROS_SYSCALL=2 } event_type;
125     uint64_t       last_ros_event_result; // valid when ROS_NONE
126     union {
127         struct {   // valid when ROS_PAGE_FAULT
128             uint64_t rip;
129             uint64_t cr2;
130             enum {ROS_READ, ROS_WRITE} action;
131         } page_fault;
132         struct { // valid when ROS_SYSCALL
133             uint64_t args[8];
134         } syscall;
135     };
136 };
137
138
139 int v3_hvm_ros_user_init()
140 {
141     // currently nothing to do
142     return 0;
143 }
144
145 int v3_hvm_ros_user_deinit()
146 {
147     // currently nothing to do
148     return 0;
149 }
150
151 static void handle_ros_event(struct v3_ros_event *event)
152 {
153     unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
154     char t;
155
156     switch (event->event_type) { 
157         case ROS_PAGE_FAULT: 
158             // force the ros kernel to the PTE
159             if (event->page_fault.action==ROS_READ) { 
160                 DEBUG("Handling page fault read for %p\n", (volatile char*)(event->page_fault.cr2));
161                 t=*(volatile char*)(event->page_fault.cr2);
162                 t=t; // avoid wanting for this throwaway
163             } else if (event->page_fault.action==ROS_WRITE) { 
164                 DEBUG("Handling page fault writefor %p\n", (volatile char*)(event->page_fault.cr2));
165                 *(volatile char*)(event->page_fault.cr2) = *(volatile char *)(event->page_fault.cr2);
166             } else {
167                 INFO("Huh?\n");
168             }
169             DEBUG("Done - doing hypercall\n");
170             num = 0xf00d;
171             a1 = 0x1f;
172             a2 = 0; // success
173             HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
174             // completed
175             DEBUG("Completed.\n");
176
177             break;
178             
179         case ROS_SYSCALL:
180             DEBUG("Doing system call: syscall(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
181                     event->syscall.args[0],
182                     event->syscall.args[1],
183                     event->syscall.args[2],
184                     event->syscall.args[3],
185                     event->syscall.args[4],
186                     event->syscall.args[5],
187                     event->syscall.args[6],
188                     event->syscall.args[7]);
189
190             rc = syscall(event->syscall.args[0],
191                          event->syscall.args[1],
192                          event->syscall.args[2],
193                          event->syscall.args[3],
194                          event->syscall.args[4],
195                          event->syscall.args[5],
196                          event->syscall.args[6],
197                          event->syscall.args[7]);
198
199             if ((int)rc<0) {
200                 DEBUG("syscall failed");
201             }
202
203             DEBUG("Return = 0x%llx, doing hypercall\n", rc);
204             num = 0xf00d;
205             a1 = 0x1f;
206             a2 = rc;
207             HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
208             DEBUG("Completed\n");
209
210             break;
211         default:
212             DEBUG( "Unknown ROS event 0x%x\n", event->event_type);
213             break;
214     }
215 }
216     
217     
218
219 static void wait_for_completion()
220 {
221   unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
222   struct v3_ros_event event;
223
224   memset(&event, 1, sizeof(event));
225
226   rc = 1;
227
228   while (rc) { 
229     num = 0xf00d;
230     a1 = 0xf;
231     a2 = (unsigned long long) &event;
232     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
233     if (rc) { 
234         //      usleep(100);
235         if (event.event_type != ROS_NONE) { 
236             handle_ros_event(&event);
237         }
238     }
239   }
240 }
241
242
243 int v3_hvm_ros_merge_address_spaces()
244 {
245     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
246     unsigned long long rc;
247
248     num=0xf00d;
249     a1 = 0x30; // merge address spaces
250     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
251     if (rc) {
252       INFO("Error in request to merge address spaces rc=0x%llx\n",rc);
253       return -1;
254     } else {
255       wait_for_completion();
256       return 0;
257     }
258 }
259
260 int v3_hvm_ros_unmerge_address_spaces()
261 {
262     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
263     unsigned long long rc;
264
265     num=0xf00d;
266     a1 = 0x31; // merge address spaces
267     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
268     if (rc) {
269       INFO("Error in request to unmerge address spaces rc=0x%llx\n",rc);
270       return -1;
271     } else {
272       wait_for_completion();
273       return 0;
274     }
275 }
276
277
278 int v3_hvm_ros_invoke_hrt_async(void *buf, int par)
279 {
280     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
281     unsigned long long rc;
282
283     num=0xf00d;
284     if (par) { 
285         a1 = 0x21; // issue "function" in parallel
286     } else {
287         a1 = 0x20; // issue "function" sequentially
288     }
289     a2 = (unsigned long long) buf;
290     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
291     if (rc) { 
292         INFO("Error in request to launch %s function rc=0x%llx\n", par ? "parallel" : "", rc);
293         return -1;
294     } else {
295         wait_for_completion();
296         return 0;
297     }
298 }
299
300
301
302
303
304 /*
305   Synchronous operation model 
306
307   On ROS:
308
309   [0] => issue count
310   [1] => completion count
311   [2] => function call ptr
312
313   1. merge
314   2. indicate this is the address for sync
315   3. ++[0]
316   4. wait for [1] to match
317   5. goto 3
318
319   On HRT:
320
321   1. merge
322   2. cnt=1;
323   3. wait for [0] to get to cnt
324   4. exec
325   5. ++[1]   ++cnt
326   6. goto 3
327 */
328
329 static volatile unsigned long long sync_proto[3]={0,0,0};
330
331
332 static void wait_for_sync()
333 {
334   unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
335   struct v3_ros_event event;
336
337   memset(&event, 1, sizeof(event));
338   
339   rc = 1;
340
341   while (rc!=4) { 
342     num = 0xf00d;
343     a1 = 0xf;
344     a2 = (unsigned long long) &event;
345     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
346     if (rc!=4) { 
347         //      usleep(100);
348         if (event.event_type != ROS_NONE) { 
349             handle_ros_event(&event);
350         }
351     }
352   }
353 }
354
355
356 int v3_hvm_ros_synchronize()
357 {
358     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
359     unsigned long long rc;
360
361     // make sure this address is touched, then zero
362     sync_proto[0]=sync_proto[1]=sync_proto[2]=1;
363     sync_proto[0]=sync_proto[1]=sync_proto[2]=0;
364
365     num=0xf00d;
366     a1 = 0x28; // issue sync request setup
367     a2 = (unsigned long long) sync_proto;
368     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
369     
370     if (rc) { 
371         INFO("Synchronize call failed with rc=0x%llx\n",rc);
372         return -1;
373     } else {
374         wait_for_sync();
375         return 0;
376     }
377 }
378
379
380 int v3_hvm_ros_desynchronize()
381 {
382     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
383     unsigned long long rc;
384
385     num=0xf00d;
386     a1 = 0x29; // issue sync request teardown
387     a2 = (unsigned long long) sync_proto;
388     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
389
390     if (rc) { 
391         INFO("Desynchronize call failed with rc=0x%llx\n",rc);
392         return -1;
393     } else {
394         wait_for_completion();
395         return 0;
396     }
397 }
398
399 #define HOW_OFTEN 1000000
400
401 int v3_hvm_ros_invoke_hrt_sync(void *buf, int ros)
402 {
403     int i;
404     sync_proto[2]=(unsigned long long)buf;
405     sync_proto[0]++;
406
407     i=0;
408     while (sync_proto[1] != sync_proto[0]) {
409         i++;
410         if (ros && (!i%HOW_OFTEN)) { 
411             unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
412             struct v3_ros_event event;
413
414             memset(&event, 1, sizeof(event));
415
416             num = 0xf00d;
417             a1 = 0xf;
418             a2 = (unsigned long long) &event;
419             HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
420             if (event.event_type != ROS_NONE) { 
421                 handle_ros_event(&event);
422             }
423         }
424     }   
425     return 0;
426 }
427