VMMCP: start move to systems I can't use on my mac
[akaros.git] / tests / vmm / virtioconsole.c
1 #include <stdio.h> 
2 #include <pthread.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <fcntl.h>
6 #include <parlib/arch/arch.h>
7 #include <unistd.h>
8 #include <errno.h>
9 #include <dirent.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ros/syscall.h>
13 #include <sys/mman.h>
14 #include <vmm/virtio.h>
15
16 int *mmap_blob;
17 void *stack;
18 volatile int shared = 0;
19 int mcp = 1;
20 #define V(x, t) (*((volatile t*)(x)))
21 // NOTE: p is both our virtual and guest physical.
22 void *p;
23 int debug = 0;
24 struct virtqueue *head, *consin, *consout;
25 pthread_t *my_threads;
26 void **my_retvals;
27 int nr_threads = 2;
28         char *line, *consline, *outline;
29         struct scatterlist iov[32];
30         unsigned int inlen, outlen, conslen;
31         /* unlike Linux, this shared struct is for both host and guest. */
32 //      struct virtqueue *constoguest = 
33 //              vring_new_virtqueue(0, 512, 8192, 0, inpages, NULL, NULL, "test");
34 volatile int gaveit = 0, gotitback = 0;
35 struct virtqueue *guesttocons;
36         struct scatterlist out[] = { {NULL, sizeof(outline)}, };
37         struct scatterlist in[] = { {NULL, sizeof(line)}, };
38         int iter = 1;
39 volatile int done = 0;
40
41
42
43 static void *fail(void *arg)
44 {
45         uint16_t head = 0;
46
47         int i, j, ret;
48         for(i = 0; i < 8;) {
49                 /* guest: make a line available to host */
50                 if ((gotitback == gaveit) && (!virtqueue_add_inbuf_avail(guesttocons, in, 1, line, 0))) {
51                         gaveit++;
52                 }
53
54                 /* guest code. Get all your buffers back */
55                 char *cp = NULL;
56                 while ((cp = virtqueue_get_buf_used(guesttocons, &conslen))) {
57                         if (cp != line) {
58                                 gotitback++;
59                                 continue;
60                         }
61                         //fprintf(stderr, "guest: from host: %s\n", cp);
62                         /* guest: push some buffers into the channel for the host to use */
63                         /* can't use sprintf here ... */
64                         outline[0] = '0' + i;
65                         for(j = 0; line[j] != 0; j++)
66                                 outline[j+1] = line[j];
67                         j++;
68                         outline[j] = 0;
69                         
70 //                              sprintf(outline, "guest: outline %d:%s:\n", iter, line);
71                         ret = virtqueue_add_outbuf_avail(guesttocons, out, 1, outline, 0);
72                         i++;
73                 }
74         }
75
76         done = 1;
77         __asm__ __volatile__("vmcall");
78         __asm__ __volatile__("mov $0xdeadbeef, %rbx; mov 5, %rax\n");
79 }
80
81 unsigned long long *p512, *p1, *p2m;
82
83 void *talk_thread(void *arg)
84 {
85         fprintf(stderr, "talk thread ..\n");
86         uint16_t head;
87         int i;
88         int num;
89         for(num = 0; num < 8;) {
90                 /* host: use any buffers we should have been sent. */
91                 head = wait_for_vq_desc(guesttocons, iov, &outlen, &inlen);
92                 if (debug)
93                 printf("vq desc head %d, gaveit %d gotitback %d\n", head, gaveit, gotitback);
94                 for(i = 0; debug && i < outlen + inlen; i++)
95                         printf("v[%d/%d] v %p len %d\n", i, outlen + inlen, iov[i].v, iov[i].length);
96                 /* host: if we got an output buffer, just output it. */
97                 for(i = 0; i < outlen; i++) {
98                         num++;
99                         printf("Host:%s:\n", (char *)iov[i].v);
100                 }
101                 
102                 if (debug) printf("outlen is %d; inlen is %d\n", outlen, inlen);
103                 /* host: fill in the writeable buffers. */
104                 for (i = outlen; i < outlen + inlen; i++) {
105                         /* host: read a line. */
106                         memset(consline, 0, 128);
107                         if (1) {
108                                 if (fgets(consline, 4096-256, stdin) == NULL) {
109                                         exit(0);
110                                 } 
111                                 if (debug) printf("GOT A LINE:%s:\n", consline);
112                         } else {
113                                 sprintf(consline, "hi there. %d\n", i);
114                         }
115                         memmove(iov[i].v, consline, strlen(consline)+ 1);
116                         iov[i].length = strlen(consline) + 1;
117                 }
118                 
119                 /* host: now ack that we used them all. */
120                 add_used(guesttocons, head, outlen+inlen);
121         }
122         fprintf(stderr, "All done\n");
123         return NULL;
124 }
125
126 int main(int argc, char **argv)
127 {
128         int nr_gpcs = 1;
129         int fd = open("#cons/sysctl", O_RDWR), ret;
130         void * x;
131         static char cmd[512];
132         debug = argc > 1;
133         if (fd < 0) {
134                 perror("#cons/sysctl");
135                 exit(1);
136         }
137
138         if (ros_syscall(SYS_setup_vmm, nr_gpcs, 0, 0, 0, 0, 0) != nr_gpcs) {
139                 perror("Guest pcore setup failed");
140                 exit(1);
141         }
142         /* blob that is faulted in from the EPT first.  we need this to be in low
143          * memory (not above the normal mmap_break), so the EPT can look it up.
144          * Note that we won't get 4096.  The min is 1MB now, and ld is there. */
145         mmap_blob = mmap((int*)4096, PGSIZE, PROT_READ | PROT_WRITE,
146                          MAP_ANONYMOUS, -1, 0);
147         if (mmap_blob == MAP_FAILED) {
148                 perror("Unable to mmap");
149                 exit(1);
150         }
151
152         void *outpages;
153         outpages = mmap((int*)4096, 1048576, PROT_READ | PROT_WRITE,
154                          MAP_ANONYMOUS, -1, 0);
155         if (outpages == MAP_FAILED) {
156                 perror("Unable to mmap");
157                 exit(1);
158         }
159         line = outpages;
160         outline = outpages + 128;
161         consline = outpages + 256;
162         outpages += 4096;
163         stack = mmap((int*)4096, 8192, PROT_READ | PROT_WRITE,
164                          MAP_ANONYMOUS, -1, 0);
165         if (stack == MAP_FAILED) {
166                 perror("Unable to mmap");
167                 exit(1);
168         }
169
170         my_threads = calloc(sizeof(pthread_t) , nr_threads);
171         my_retvals = calloc(sizeof(void *) , nr_threads);
172         if (!(my_retvals && my_threads))
173                 perror("Init threads/malloc");
174
175         pthread_mcp_init();     /* gives us one vcore */
176         vcore_request(nr_threads - 1);  /* ghetto incremental interface */
177         for (int i = 0; i < nr_threads; i++) {
178                 x = __procinfo.vcoremap;
179                 fprintf(stderr, "%p\n", __procinfo.vcoremap);
180                 fprintf(stderr, "Vcore %d mapped to pcore %d\n", i,
181                            __procinfo.vcoremap[i].pcoreid);
182         }
183
184         guesttocons = vring_new_virtqueue(0, 512, 8192, 0, outpages, NULL, NULL, "test");
185         fprintf(stderr, "guesttocons is %p\n", guesttocons);
186         out[0].v = outline;
187         in[0].v = line;
188         if (mcp) {
189                 if (pthread_create(&my_threads[0], NULL, &talk_thread, NULL))
190                         perror("pth_create failed");
191 //      if (pthread_create(&my_threads[1], NULL, &fail, NULL))
192 //          perror("pth_create failed");
193         }
194         fprintf(stderr, "threads started\n");
195         
196         ret = syscall(33, 1);
197         if (ret < 0) {
198                 perror("vm setup");
199                 exit(1);
200         }
201         ret = posix_memalign((void **)&p512, 4096, 3 * 4096);
202         if (ret) {
203                 perror("ptp alloc");
204                 exit(1);
205         }
206         p1 = &p512[512];
207         p2m = &p512[1024];
208         p512[0] = (unsigned long long)p1 | 7;
209         p1[0] = /*0x87; */ (unsigned long long)p2m | 7;
210         p2m[0] = 0x87;
211         p2m[1] = 0x200000 | 0x87;
212         p2m[2] = 0x400000 | 0x87;
213         p2m[3] = 0x600000 | 0x87;
214         
215         fprintf(stderr, "p512 %p p512[0] is 0x%lx p1 %p p1[0] is 0x%x\n", p512, p512[0], p1,
216                p1[0]);
217         sprintf(cmd, "V 0x%x 0x%x 0x%x", (unsigned long long)fail,
218                 (unsigned long long)stack+8192, (unsigned long long)p512);
219         showscatterlist(in, 1);
220         showscatterlist(out, 1);
221         showvq(guesttocons);
222         //showdesc(guesttocons, 0);
223         if (debug)
224                 fprintf(stderr, "Writing command :%s:\n", cmd);
225         ret = write(fd, cmd, strlen(cmd));
226         if (ret != strlen(cmd)) {
227                 perror(cmd);
228         }
229         sprintf(cmd, "V 0 0 0");
230         while (! done) {
231                 if (debug)
232                         fprintf(stderr, "RESUME\n");
233                 ret = write(fd, cmd, strlen(cmd));
234                 if (ret != strlen(cmd)) {
235                         perror(cmd);
236                 }
237         }
238
239         if (debug)
240                 fprintf(stderr, "shared is %d\n", shared);
241
242         for (int i = 0; i < nr_threads - 1; i++) {
243                 int ret;
244                 if (pthread_join(my_threads[i], &my_retvals[i]))
245                         perror("pth_join failed");
246                 fprintf(stderr, "%d %d\n", i, ret);
247         }
248         
249         return 0;
250 }