Basic init of the virtio_mmio region
[akaros.git] / tests / vmm / vmrunkernel.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 <parlib/ros_debug.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <dirent.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ros/syscall.h>
14 #include <sys/mman.h>
15 #include <vmm/coreboot_tables.h>
16 #include <ros/vmm.h>
17 #include <vmm/virtio_mmio.h>
18 #include <vmm/virtio_ids.h>
19
20 /* this test will run the "kernel" in the negative address space. We hope. */
21 int *mmap_blob;
22 unsigned long long stack[1024];
23 volatile int shared = 0;
24 int mcp = 1;
25 #define V(x, t) (*((volatile t*)(x)))
26
27 #define MiB 0x100000u
28 #define GiB (1u<<30)
29 #define VIRTIOBASE (15*MiB)
30 #define GKERNBASE (16*MiB)
31 #define KERNSIZE (128*MiB+GKERNBASE)
32 uint8_t _kernel[KERNSIZE];
33
34 unsigned long long *p512, *p1, *p2m;
35
36 void *talk_thread(void *arg)
37 {
38         printf("talk thread ..\n");
39         for(; V(&shared, int) < 32; ){
40                 if (V(&shared, int) & 1) {
41                         printf("shared %d\n", V(&shared, int) );
42                         V(&shared, int) = V(&shared, int) + 1;
43                 }
44                 cpu_relax();
45         }
46         printf("All done, read %d\n", *mmap_blob);
47         return NULL;
48 }
49
50 pthread_t *my_threads;
51 void **my_retvals;
52 int nr_threads = 2;
53
54 static void setupconsole(uint32_t *v)
55 {
56         // try to make linux happy.
57         // this is not really endian safe but ... well ... WE'RE ON THE SAME MACHINE
58         v[VIRTIO_MMIO_MAGIC_VALUE/4] = ('v' | 'i' << 8 | 'r' << 16 | 't' << 24);
59         v[VIRTIO_MMIO_VERSION] = 35;
60         v[VIRTIO_MMIO_DEVICE_ID] = VIRTIO_ID_CONSOLE;
61 }
62 int main(int argc, char **argv)
63 {
64         int amt;
65         int vmmflags = VMM_VMCALL_PRINTF;
66         uint64_t entry = 0x1000000, kerneladdress = 0x1000000;
67         int nr_gpcs = 1;
68         int fd = open("#cons/sysctl", O_RDWR), ret;
69         void * x;
70         int kfd = -1;
71         static char cmd[512];
72         void *coreboot_tables = (void *) 0x1165000;
73         /* kernel has to be in the range VIRTIOBASE to KERNSIZE+GKERNBASE for now. */
74         // mmap is not working for us at present.
75         if ((uint64_t)_kernel > VIRTIOBASE) {
76                 printf("kernel array @%p is above , VIRTIOBASE@%p sucks\n", _kernel, VIRTIOBASE);
77                 exit(1);
78         }
79         memset(_kernel, 0, sizeof(_kernel));
80
81         if (fd < 0) {
82                 perror("#cons/sysctl");
83                 exit(1);
84         }
85         argc--,argv++;
86         // switches ...
87         // Sorry, I don't much like the gnu opt parsing code.
88         while (1) {
89                 if (*argv[0] != '-')
90                         break;
91                 switch(argv[0][1]) {
92                 case 'n':
93                         vmmflags &= ~VMM_VMCALL_PRINTF;
94                         break;
95                 default:
96                         printf("BMAFR\n");
97                         break;
98                 }
99                 argc--,argv++;
100         }
101         if (argc < 1) {
102                 fprintf(stderr, "Usage: %s vmimage [-n (no vmcall printf)] [coreboot_tables [loadaddress [entrypoint]]]\n", argv[0]);
103                 exit(1);
104         }
105         if (argc > 1)
106                 coreboot_tables = (void *) strtoull(argv[1], 0, 0);
107         if (argc > 2)
108                 kerneladdress = strtoull(argv[2], 0, 0);
109         if (argc > 3)
110                 entry = strtoull(argv[3], 0, 0);
111         kfd = open(argv[0], O_RDONLY);
112         if (kfd < 0) {
113                 perror(argv[0]);
114                 exit(1);
115         }
116         // read in the kernel.
117         x = (void *)kerneladdress;
118         for(;;) {
119                 amt = read(kfd, x, 1048576);
120                 if (amt < 0) {
121                         perror("read");
122                         exit(1);
123                 }
124                 if (amt == 0) {
125                         break;
126                 }
127                 x += amt;
128         }
129         fprintf(stderr, "Read in %d bytes\n", x-kerneladdress);
130
131         fprintf(stderr, "Run with %d cores and vmmflags 0x%x\n", nr_gpcs, vmmflags);
132         if (ros_syscall(SYS_setup_vmm, nr_gpcs, vmmflags, 0, 0, 0, 0) != nr_gpcs) {
133                 perror("Guest pcore setup failed");
134                 exit(1);
135         }
136         /* blob that is faulted in from the EPT first.  we need this to be in low
137          * memory (not above the normal mmap_break), so the EPT can look it up.
138          * Note that we won't get 4096.  The min is 1MB now, and ld is there. */
139         mmap_blob = mmap((int*)4096, PGSIZE, PROT_READ | PROT_WRITE,
140                          MAP_ANONYMOUS, -1, 0);
141         if (mmap_blob == MAP_FAILED) {
142                 perror("Unable to mmap");
143                 exit(1);
144         }
145
146         mcp = 0; //argc - 1;
147         if (mcp) {
148                 my_threads = malloc(sizeof(pthread_t) * nr_threads);
149                 my_retvals = malloc(sizeof(void*) * nr_threads);
150                 if (!(my_retvals && my_threads))
151                         perror("Init threads/malloc");
152
153                 pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
154                 pthread_need_tls(FALSE);
155                 pthread_mcp_init();                                     /* gives us one vcore */
156                 vcore_request(nr_threads - 1);          /* ghetto incremental interface */
157                 for (int i = 0; i < nr_threads; i++) {
158                         x = __procinfo.vcoremap;
159                         printf("%p\n", __procinfo.vcoremap);
160                         printf("Vcore %d mapped to pcore %d\n", i,
161                                 __procinfo.vcoremap[i].pcoreid);
162                 }
163         }
164
165         if (mcp) {
166                 if (pthread_create(&my_threads[0], NULL, &talk_thread, NULL))
167                         perror("pth_create failed");
168 //              if (pthread_create(&my_threads[1], NULL, &fail, NULL))
169 //                      perror("pth_create failed");
170         }
171         printf("threads started\n");
172
173         if (0) for (int i = 0; i < nr_threads-1; i++) {
174                 int ret;
175                 if (pthread_join(my_threads[i], &my_retvals[i]))
176                         perror("pth_join failed");
177                 printf("%d %d\n", i, ret);
178         }
179         
180
181         ret = syscall(33, 1);
182         if (ret < 0) {
183                 perror("vm setup");
184                 exit(1);
185         }
186         ret = posix_memalign((void **)&p512, 4096, 3*4096);
187         printf("memalign is %p\n", p512);
188         if (ret) {
189                 perror("ptp alloc");
190                 exit(1);
191         }
192         p1 = &p512[512];
193         p2m = &p512[1024];
194         uint64_t kernbase = 0; //0xffffffff80000000;
195         uint64_t highkernbase = 0xffffffff80000000;
196         p512[PML4(kernbase)] = (unsigned long long)p1 | 7;
197         p1[PML3(kernbase)] = /*0x87; */(unsigned long long)p2m | 7;
198         p512[PML4(highkernbase)] = (unsigned long long)p1 | 7;
199         p1[PML3(highkernbase)] = /*0x87; */(unsigned long long)p2m | 7;
200 #define _2MiB (0x200000)
201         int i;
202         for (i = 0; i < 512; i++) {
203                 p2m[PML2(kernbase + i * _2MiB)] = 0x87 | i * _2MiB;
204         }
205
206         kernbase >>= (0+12);
207         kernbase <<= (0 + 12);
208         uint8_t *kernel = (void *)GKERNBASE;
209         write_coreboot_table(coreboot_tables, ((void *)VIRTIOBASE) /*kernel*/, KERNSIZE + 1048576);
210         hexdump(stdout, coreboot_tables, 128);
211         setupconsole((void *)VIRTIOBASE);
212         hexdump(stdout, (void *)VIRTIOBASE, 128);
213         printf("kernbase for pml4 is 0x%llx and entry is %llx\n", kernbase, entry);
214         printf("p512 %p p512[0] is 0x%lx p1 %p p1[0] is 0x%x\n", p512, p512[0], p1, p1[0]);
215         sprintf(cmd, "V 0x%llx 0x%llx 0x%llx", entry, (unsigned long long) &stack[1024], (unsigned long long) p512);
216         printf("Writing command :%s:\n", cmd);
217         ret = write(fd, cmd, strlen(cmd));
218         if (ret != strlen(cmd)) {
219                 perror(cmd);
220         }
221         sprintf(cmd, "V 0 0 0");
222         while (1) {
223                 int c;
224                 printf("RESUME?\n");
225                 c = getchar();
226                 if (c == 'q')
227                         break;
228                 ret = write(fd, cmd, strlen(cmd));
229                 if (ret != strlen(cmd)) {
230                         perror(cmd);
231                 }
232         }
233         hexdump(stdout, (void *)VIRTIOBASE, 128);
234         printf("shared is %d, blob is %d\n", shared, *mmap_blob);
235
236         return 0;
237 }