6 #include <parlib/arch/arch.h>
7 #include <parlib/ros_debug.h>
13 #include <ros/syscall.h>
15 #include <vmm/coreboot_tables.h>
17 #include <vmm/virtio.h>
18 #include <vmm/virtio_mmio.h>
19 #include <vmm/virtio_ids.h>
21 /* this test will run the "kernel" in the negative address space. We hope. */
23 unsigned long long stack[1024];
24 volatile int shared = 0;
25 volatile int quit = 0;
30 #define VIRTIOBASE (15*MiB)
31 #define GKERNBASE (16*MiB)
32 #define KERNSIZE (128*MiB+GKERNBASE)
33 uint8_t _kernel[KERNSIZE];
35 unsigned long long *p512, *p1, *p2m;
37 pthread_t *my_threads;
40 char *line, *consline, *outline;
41 struct scatterlist iov[32];
42 unsigned int inlen, outlen, conslen;
43 /* unlike Linux, this shared struct is for both host and guest. */
44 // struct virtqueue *constoguest =
45 // vring_new_virtqueue(0, 512, 8192, 0, inpages, NULL, NULL, "test");
46 volatile int gaveit = 0, gotitback = 0;
47 struct virtqueue *guesttocons;
48 struct scatterlist out[] = { {NULL, sizeof(outline)}, };
49 struct scatterlist in[] = { {NULL, sizeof(line)}, };
51 static inline uint32_t read32(const volatile void *addr)
53 return *(const volatile uint32_t *)addr;
56 static inline void write32(volatile void *addr, uint32_t value)
58 *(volatile uint32_t *)addr = value;
61 void dumpvirtio_mmio(FILE *f, void *v)
63 fprintf(f, "VIRTIO_MMIO_MAGIC_VALUE: 0x%x\n", read32(v+VIRTIO_MMIO_MAGIC_VALUE));
64 fprintf(f, "VIRTIO_MMIO_VERSION: 0x%x\n", read32(v+VIRTIO_MMIO_VERSION));
65 fprintf(f, "VIRTIO_MMIO_DEVICE_ID: 0x%x\n", read32(v+VIRTIO_MMIO_DEVICE_ID));
66 fprintf(f, "VIRTIO_MMIO_VENDOR_ID: 0x%x\n", read32(v+VIRTIO_MMIO_VENDOR_ID));
67 fprintf(f, "VIRTIO_MMIO_DEVICE_FEATURES: 0x%x\n", read32(v+VIRTIO_MMIO_DEVICE_FEATURES));
68 fprintf(f, "VIRTIO_MMIO_DEVICE_FEATURES_SEL: 0x%x\n", read32(v+VIRTIO_MMIO_DEVICE_FEATURES_SEL));
69 fprintf(f, "VIRTIO_MMIO_DRIVER_FEATURES: 0x%x\n", read32(v+VIRTIO_MMIO_DRIVER_FEATURES));
70 fprintf(f, "VIRTIO_MMIO_DRIVER_FEATURES_SEL: 0x%x\n", read32(v+VIRTIO_MMIO_DRIVER_FEATURES_SEL));
71 fprintf(f, "VIRTIO_MMIO_GUEST_PAGE_SIZE: 0x%x\n", read32(v+VIRTIO_MMIO_GUEST_PAGE_SIZE));
72 fprintf(f, "VIRTIO_MMIO_QUEUE_SEL: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_SEL));
73 fprintf(f, "VIRTIO_MMIO_QUEUE_NUM_MAX: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_NUM_MAX));
74 fprintf(f, "VIRTIO_MMIO_QUEUE_NUM: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_NUM));
75 fprintf(f, "VIRTIO_MMIO_QUEUE_ALIGN: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_ALIGN));
76 fprintf(f, "VIRTIO_MMIO_QUEUE_PFN: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_PFN));
77 fprintf(f, "VIRTIO_MMIO_QUEUE_READY: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_READY));
78 fprintf(f, "VIRTIO_MMIO_QUEUE_NOTIFY: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_NOTIFY));
79 fprintf(f, "VIRTIO_MMIO_INTERRUPT_STATUS: 0x%x\n", read32(v+VIRTIO_MMIO_INTERRUPT_STATUS));
80 fprintf(f, "VIRTIO_MMIO_INTERRUPT_ACK: 0x%x\n", read32(v+VIRTIO_MMIO_INTERRUPT_ACK));
81 fprintf(f, "VIRTIO_MMIO_STATUS: 0x%x\n", read32(v+VIRTIO_MMIO_STATUS));
82 fprintf(f, "VIRTIO_MMIO_QUEUE_DESC_LOW: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_DESC_LOW));
83 fprintf(f, "VIRTIO_MMIO_QUEUE_DESC_HIGH: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_DESC_HIGH));
84 fprintf(f, "VIRTIO_MMIO_QUEUE_AVAIL_LOW: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_AVAIL_LOW));
85 fprintf(f, "VIRTIO_MMIO_QUEUE_AVAIL_HIGH: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_AVAIL_HIGH));
86 fprintf(f, "VIRTIO_MMIO_QUEUE_USED_LOW: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_USED_LOW));
87 fprintf(f, "VIRTIO_MMIO_QUEUE_USED_HIGH: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_USED_HIGH));
88 fprintf(f, "VIRTIO_MMIO_CONFIG_GENERATION: 0x%x\n", read32(v+VIRTIO_MMIO_CONFIG_GENERATION));
90 static void setupconsole(void *v)
92 // try to make linux happy.
93 // this is not really endian safe but ... well ... WE'RE ON THE SAME MACHINE
94 write32(v+VIRTIO_MMIO_MAGIC_VALUE, ('v' | 'i' << 8 | 'r' << 16 | 't' << 24));
95 // no constant for this is defined anywhere. It's just 1.
96 write32(v+VIRTIO_MMIO_VERSION, 1);
97 write32(v+VIRTIO_MMIO_DEVICE_ID, VIRTIO_ID_CONSOLE);
98 write32(v+VIRTIO_MMIO_QUEUE_NUM_MAX, 1);
99 write32(v+VIRTIO_MMIO_QUEUE_PFN, 0);
108 void *talk_thread(void *arg)
110 struct ttargs *a = arg;
112 fprintf(stderr, "talk thread ..\n");
118 printf("Sleep 15 seconds\n");
120 printf("----------------------- TT a %p\n", a);
121 printf("talk thread ttargs %x v %x\n", a, v);
123 if (debug) printf("Spin on console being read, print num queues, halt\n");
124 while ((vv = read32(v+VIRTIO_MMIO_DRIVER_FEATURES)) == 0) {
125 printf("no ready ... \n");
127 dumpvirtio_mmio(stdout, v);
129 printf("sleep 1 second\n");
132 if (debug)printf("vv %x, set selector %x\n", vv, read32(v + VIRTIO_MMIO_DRIVER_FEATURES_SEL));
133 if (debug) printf("loop forever");
136 for(num = 0;;num++) {
137 /* host: use any buffers we should have been sent. */
138 head = wait_for_vq_desc(guesttocons, iov, &outlen, &inlen);
140 printf("vq desc head %d, gaveit %d gotitback %d\n", head, gaveit, gotitback);
141 for(i = 0; debug && i < outlen + inlen; i++)
142 printf("v[%d/%d] v %p len %d\n", i, outlen + inlen, iov[i].v, iov[i].length);
143 /* host: if we got an output buffer, just output it. */
144 for(i = 0; i < outlen; i++) {
146 printf("Host:%s:\n", (char *)iov[i].v);
150 printf("outlen is %d; inlen is %d\n", outlen, inlen);
151 /* host: fill in the writeable buffers. */
152 for (i = outlen; i < outlen + inlen; i++) {
153 /* host: read a line. */
154 memset(consline, 0, 128);
156 if (fgets(consline, 4096-256, stdin) == NULL) {
159 if (debug) printf("GOT A LINE:%s:\n", consline);
161 sprintf(consline, "hi there. %d\n", i);
163 memmove(iov[i].v, consline, strlen(consline)+ 1);
164 iov[i].length = strlen(consline) + 1;
166 if (debug) printf("call add_used\n");
167 /* host: now ack that we used them all. */
168 add_used(guesttocons, head, outlen+inlen);
169 if (debug) printf("DONE call add_used\n");
171 fprintf(stderr, "All done\n");
178 int main(int argc, char **argv)
182 int vmmflags = VMM_VMCALL_PRINTF;
183 uint64_t entry = 0x1000000, kerneladdress = 0x1000000;
185 int fd = open("#c/vmctl", O_RDWR), ret;
188 static char cmd[512];
189 void *coreboot_tables = (void *) 0x1165000;
190 /* kernel has to be in the range VIRTIOBASE to KERNSIZE+GKERNBASE for now. */
191 // mmap is not working for us at present.
192 if ((uint64_t)_kernel > VIRTIOBASE) {
193 printf("kernel array @%p is above , VIRTIOBASE@%p sucks\n", _kernel, VIRTIOBASE);
196 memset(_kernel, 0, sizeof(_kernel));
199 perror("#cons/sysctl");
204 // Sorry, I don't much like the gnu opt parsing code.
210 vmmflags &= ~VMM_VMCALL_PRINTF;
219 fprintf(stderr, "Usage: %s vmimage [-n (no vmcall printf)] [coreboot_tables [loadaddress [entrypoint]]]\n", argv[0]);
223 coreboot_tables = (void *) strtoull(argv[1], 0, 0);
225 kerneladdress = strtoull(argv[2], 0, 0);
227 entry = strtoull(argv[3], 0, 0);
228 kfd = open(argv[0], O_RDONLY);
233 // read in the kernel.
234 x = (void *)kerneladdress;
236 amt = read(kfd, x, 1048576);
246 fprintf(stderr, "Read in %d bytes\n", x-kerneladdress);
248 fprintf(stderr, "Run with %d cores and vmmflags 0x%x\n", nr_gpcs, vmmflags);
249 if (ros_syscall(SYS_setup_vmm, nr_gpcs, vmmflags, 0, 0, 0, 0) != nr_gpcs) {
250 perror("Guest pcore setup failed");
253 /* blob that is faulted in from the EPT first. we need this to be in low
254 * memory (not above the normal mmap_break), so the EPT can look it up.
255 * Note that we won't get 4096. The min is 1MB now, and ld is there. */
256 mmap_blob = mmap((int*)4096, PGSIZE, PROT_READ | PROT_WRITE,
257 MAP_ANONYMOUS, -1, 0);
258 if (mmap_blob == MAP_FAILED) {
259 perror("Unable to mmap");
265 my_threads = malloc(sizeof(pthread_t) * nr_threads);
266 my_retvals = malloc(sizeof(void*) * nr_threads);
267 if (!(my_retvals && my_threads))
268 perror("Init threads/malloc");
270 pthread_can_vcore_request(FALSE); /* 2LS won't manage vcores */
271 pthread_need_tls(FALSE);
272 pthread_mcp_init(); /* gives us one vcore */
273 vcore_request(nr_threads - 1); /* ghetto incremental interface */
274 for (int i = 0; i < nr_threads; i++) {
275 x = __procinfo.vcoremap;
276 printf("%p\n", __procinfo.vcoremap);
277 printf("Vcore %d mapped to pcore %d\n", i,
278 __procinfo.vcoremap[i].pcoreid);
282 t.virtio = (void *)VIRTIOBASE;
284 ret = syscall(33, 1);
289 ret = posix_memalign((void **)&p512, 4096, 3*4096);
290 printf("memalign is %p\n", p512);
297 uint64_t kernbase = 0; //0xffffffff80000000;
298 uint64_t highkernbase = 0xffffffff80000000;
299 p512[PML4(kernbase)] = (unsigned long long)p1 | 7;
300 p1[PML3(kernbase)] = /*0x87; */(unsigned long long)p2m | 7;
301 p512[PML4(highkernbase)] = (unsigned long long)p1 | 7;
302 p1[PML3(highkernbase)] = /*0x87; */(unsigned long long)p2m | 7;
303 #define _2MiB (0x200000)
305 for (i = 0; i < 512; i++) {
306 p2m[PML2(kernbase + i * _2MiB)] = 0x87 | i * _2MiB;
310 kernbase <<= (0 + 12);
311 uint8_t *kernel = (void *)GKERNBASE;
312 write_coreboot_table(coreboot_tables, ((void *)VIRTIOBASE) /*kernel*/, KERNSIZE + 1048576);
313 hexdump(stdout, coreboot_tables, 512);
314 setupconsole((void *)VIRTIOBASE);
315 hexdump(stdout, (void *)VIRTIOBASE, 128);
316 printf("kernbase for pml4 is 0x%llx and entry is %llx\n", kernbase, entry);
317 printf("p512 %p p512[0] is 0x%lx p1 %p p1[0] is 0x%x\n", p512, p512[0], p1, p1[0]);
318 vmctl.command = REG_RSP_RIP_CR3;
319 vmctl.cr3 = (uint64_t) p512;
320 vmctl.regs.tf_rip = entry;
321 vmctl.regs.tf_rsp = (uint64_t) &stack[1024];
323 if (pthread_create(&my_threads[0], NULL, &talk_thread, &t))
324 perror("pth_create failed");
326 printf("threads started\n");
327 printf("Writing command :%s:\n", cmd);
329 ret = write(fd, &vmctl, sizeof(vmctl));
330 if (ret != sizeof(vmctl)) {
333 vmctl.command = RESUME;
340 ret = write(fd, &vmctl, sizeof(vmctl));
341 if (ret != sizeof(vmctl)) {
344 printf("RIP %p\n", vmctl.regs.tf_rip);
346 dumpvirtio_mmio(stdout, (void *)VIRTIOBASE);
347 printf("shared is %d, blob is %d\n", shared, *mmap_blob);
350 for (int i = 0; i < nr_threads-1; i++) {
352 if (pthread_join(my_threads[i], &my_retvals[i]))
353 perror("pth_join failed");
354 printf("%d %d\n", i, ret);