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.


Added missing HVM reset function to Linux library...
[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 int v3_hvm_ros_reset(reset_type what)
243 {
244     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
245     unsigned long long rc;
246     
247     num=0xf00d;
248     switch (what) { 
249         case RESET_ROS:
250             a1 = 0x1;
251             break;
252         case RESET_HRT:
253             a1 = 0x2;
254             break;
255         case RESET_BOTH:
256             a1 = 0x3;
257             break;
258     }
259     
260     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
261     
262     if (rc) {
263         INFO("Error in request to reset rc=0x%llx\n",rc);
264         return -1;
265     } else {
266         // no waiting for completion here
267         return 0;
268     }
269 }
270
271
272 int v3_hvm_ros_merge_address_spaces()
273 {
274     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
275     unsigned long long rc;
276
277     num=0xf00d;
278     a1 = 0x30; // merge address spaces
279     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
280     if (rc) {
281       INFO("Error in request to merge address spaces rc=0x%llx\n",rc);
282       return -1;
283     } else {
284       wait_for_completion();
285       return 0;
286     }
287 }
288
289 int v3_hvm_ros_unmerge_address_spaces()
290 {
291     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
292     unsigned long long rc;
293
294     num=0xf00d;
295     a1 = 0x31; // merge address spaces
296     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
297     if (rc) {
298       INFO("Error in request to unmerge address spaces rc=0x%llx\n",rc);
299       return -1;
300     } else {
301       wait_for_completion();
302       return 0;
303     }
304 }
305
306
307 int v3_hvm_ros_invoke_hrt_async(void *buf, int par)
308 {
309     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
310     unsigned long long rc;
311
312     num=0xf00d;
313     if (par) { 
314         a1 = 0x21; // issue "function" in parallel
315     } else {
316         a1 = 0x20; // issue "function" sequentially
317     }
318     a2 = (unsigned long long) buf;
319     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
320     if (rc) { 
321         INFO("Error in request to launch %s function rc=0x%llx\n", par ? "parallel" : "", rc);
322         return -1;
323     } else {
324         wait_for_completion();
325         return 0;
326     }
327 }
328
329
330
331
332
333 /*
334   Synchronous operation model 
335
336   On ROS:
337
338   [0] => issue count
339   [1] => completion count
340   [2] => function call ptr
341
342   1. merge
343   2. indicate this is the address for sync
344   3. ++[0]
345   4. wait for [1] to match
346   5. goto 3
347
348   On HRT:
349
350   1. merge
351   2. cnt=1;
352   3. wait for [0] to get to cnt
353   4. exec
354   5. ++[1]   ++cnt
355   6. goto 3
356 */
357
358 static volatile unsigned long long sync_proto[3]={0,0,0};
359
360
361 static void wait_for_sync()
362 {
363   unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
364   struct v3_ros_event event;
365
366   memset(&event, 1, sizeof(event));
367   
368   rc = 1;
369
370   while (rc!=4) { 
371     num = 0xf00d;
372     a1 = 0xf;
373     a2 = (unsigned long long) &event;
374     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
375     if (rc!=4) { 
376         //      usleep(100);
377         if (event.event_type != ROS_NONE) { 
378             handle_ros_event(&event);
379         }
380     }
381   }
382 }
383
384
385 int v3_hvm_ros_synchronize()
386 {
387     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
388     unsigned long long rc;
389
390     // make sure this address is touched, then zero
391     sync_proto[0]=sync_proto[1]=sync_proto[2]=1;
392     sync_proto[0]=sync_proto[1]=sync_proto[2]=0;
393
394     num=0xf00d;
395     a1 = 0x28; // issue sync request setup
396     a2 = (unsigned long long) sync_proto;
397     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
398     
399     if (rc) { 
400         INFO("Synchronize call failed with rc=0x%llx\n",rc);
401         return -1;
402     } else {
403         wait_for_sync();
404         return 0;
405     }
406 }
407
408
409 int v3_hvm_ros_desynchronize()
410 {
411     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
412     unsigned long long rc;
413
414     num=0xf00d;
415     a1 = 0x29; // issue sync request teardown
416     a2 = (unsigned long long) sync_proto;
417     HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
418
419     if (rc) { 
420         INFO("Desynchronize call failed with rc=0x%llx\n",rc);
421         return -1;
422     } else {
423         wait_for_completion();
424         return 0;
425     }
426 }
427
428 #define HOW_OFTEN 1000000
429
430 int v3_hvm_ros_invoke_hrt_sync(void *buf, int ros)
431 {
432     int i;
433     sync_proto[2]=(unsigned long long)buf;
434     sync_proto[0]++;
435
436     i=0;
437     while (sync_proto[1] != sync_proto[0]) {
438         i++;
439         if (ros && (!i%HOW_OFTEN)) { 
440             unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
441             struct v3_ros_event event;
442
443             memset(&event, 1, sizeof(event));
444
445             num = 0xf00d;
446             a1 = 0xf;
447             a2 = (unsigned long long) &event;
448             HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
449             if (event.event_type != ROS_NONE) { 
450                 handle_ros_event(&event);
451             }
452         }
453     }   
454     return 0;
455 }
456