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.


d3bae18d1e28591585078a0963f7d218e632bae9
[palacios.git] / palacios / src / devices / lnx_virtio_symmod.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_dev_mgr.h>
22 #include <palacios/vm_guest_mem.h>
23 #include <devices/lnx_virtio_pci.h>
24 #include <palacios/vmm_symmod.h>
25
26 #include <devices/pci.h>
27
28
29 #define QUEUE_SIZE 128
30 #define NUM_QUEUES 2
31
32 struct sym_config {
33 } __attribute__((packed));
34
35
36
37 struct virtio_sym_state {
38     struct sym_config sym_cfg;
39     struct virtio_config virtio_cfg;
40
41
42     struct vm_device * pci_bus;
43     struct pci_device * pci_dev;
44
45
46 #define NOTIFY_QUEUE 0
47 #define LOADER_QUEUE 1
48     struct virtio_queue queue[NUM_QUEUES];
49
50     struct virtio_queue * cur_queue;
51
52     int notifier_active;
53
54     int io_range_size;
55 };
56
57
58
59 // structure of the symmod notifier ring structures
60 struct symmod_hdr {
61     uint32_t num_bytes;
62     char name[32];
63 } __attribute__((packed));
64
65
66 static int virtio_reset(struct virtio_sym_state * virtio) {
67
68     memset(virtio->queue, 0, sizeof(struct virtio_queue) * 2);
69
70     virtio->cur_queue = &(virtio->queue[0]);
71
72     virtio->virtio_cfg.status = 0;
73     virtio->virtio_cfg.pci_isr = 0;
74
75     virtio->queue[0].queue_size = QUEUE_SIZE;
76     virtio->queue[1].queue_size = QUEUE_SIZE;
77
78
79     memset(&(virtio->sym_cfg), 0, sizeof(struct sym_config));
80
81     return 0;
82 }
83
84
85
86 static int get_desc_count(struct virtio_queue * q, int index) {
87     struct vring_desc * tmp_desc = &(q->desc[index]);
88     int cnt = 1;
89     
90     while (tmp_desc->flags & VIRTIO_NEXT_FLAG) {
91         tmp_desc = &(q->desc[tmp_desc->next]);
92         cnt++;
93     }
94
95     return cnt;
96 }
97
98
99
100
101 static int handle_xfer_kick(struct guest_info * core, struct virtio_sym_state * sym_state) {
102     struct virtio_queue * q = sym_state->cur_queue;
103     
104     PrintDebug("SYMMOD: VIRTIO SYMMOD Kick on loader queue\n");
105
106     while (q->cur_avail_idx < q->avail->index) {
107         struct vring_desc * hdr_desc = NULL;
108         struct vring_desc * buf_desc = NULL;
109         struct vring_desc * status_desc = NULL;
110         uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % QUEUE_SIZE];
111         uint16_t desc_cnt = get_desc_count(q, desc_idx);
112         struct symmod_hdr * hdr = NULL;
113         int i;
114         uint32_t xfer_len = 0;
115         uint8_t status = 0;
116         uint8_t * status_ptr = NULL;
117         struct v3_sym_module * module = NULL;
118         uint32_t offset = 0;
119
120
121         PrintDebug("Descriptor Count=%d, index=%d\n", desc_cnt, q->cur_avail_idx % QUEUE_SIZE);
122
123         if (desc_cnt < 3) {
124             PrintError("Symmod loads must include at least 3 descriptors (cnt=%d)\n", desc_cnt);
125             return -1;
126         }
127         
128         hdr_desc = &(q->desc[desc_idx]);
129
130         if (guest_pa_to_host_va(core, hdr_desc->addr_gpa, (addr_t *)&hdr) == -1) {
131             PrintError("Could not translate SYMMOD header address\n");
132             return -1;
133         }
134
135         desc_idx = hdr_desc->next;
136
137         module = v3_get_sym_module(core->vm_info, hdr->name);
138
139         for (i = 0; i < desc_cnt - 2; i++) {
140             uint8_t tmp_status = 0;
141             uint8_t * buf = NULL;
142
143             buf_desc = &(q->desc[desc_idx]);
144
145             if (guest_pa_to_host_va(core, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) {
146                 PrintError("Could not translate buffer address\n");
147                 return -1;
148             }
149
150             memcpy(buf, module->start_addr + offset, buf_desc->length);
151             PrintDebug("Copying module to virtio buffers: SRC=%p, DST=%p, len=%d\n",
152                        (void *)(module->start_addr + offset), (void *)buf, buf_desc->length);
153
154             if (tmp_status != 0) {
155                 PrintError("Error loading module segment\n");
156                 status = tmp_status;
157             }
158
159
160             offset += buf_desc->length;
161             xfer_len += buf_desc->length;
162             desc_idx = buf_desc->next;
163         }
164
165         status_desc = &(q->desc[desc_idx]);
166
167         if (guest_pa_to_host_va(core, status_desc->addr_gpa, (addr_t *)&status_ptr) == -1) {
168             PrintError("SYMMOD Error could not translate status address\n");
169             return -1;
170         }
171
172         xfer_len += status_desc->length;
173         *status_ptr = status;
174
175         PrintDebug("Transferred %d bytes (xfer_len)\n", xfer_len);
176         q->used->ring[q->used->index % QUEUE_SIZE].id = q->avail->ring[q->cur_avail_idx % QUEUE_SIZE];
177         q->used->ring[q->used->index % QUEUE_SIZE].length = xfer_len; // set to total inbound xfer length
178
179         q->used->index++;
180         q->cur_avail_idx++;
181     }
182
183
184     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
185         PrintDebug("Raising IRQ %d\n",  sym_state->pci_dev->config_header.intr_line);
186         v3_pci_raise_irq(sym_state->pci_bus, 0, sym_state->pci_dev);
187         sym_state->virtio_cfg.pci_isr = 1;
188     }
189
190
191     return 0;
192 }
193
194
195 static int virtio_io_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * private_data) {
196     struct virtio_sym_state * sym_state = (struct virtio_sym_state *)private_data;
197     int port_idx = port % sym_state->io_range_size;
198
199
200     PrintDebug("SYMMOD: VIRTIO SYMMOD Write for port %d len=%d, value=%x\n", 
201                port, length, *(uint32_t *)src);
202     PrintDebug("SYMMOD: port idx=%d\n", port_idx);
203
204
205     switch (port_idx) {
206         case GUEST_FEATURES_PORT:
207             if (length != 4) {
208                 PrintError("Illegal write length for guest features\n");
209                 return -1;
210             }
211             
212             sym_state->virtio_cfg.guest_features = *(uint32_t *)src;
213
214             break;
215         case VRING_PG_NUM_PORT:
216             if (length == 4) {
217                 addr_t pfn = *(uint32_t *)src;
218                 addr_t page_addr = (pfn << VIRTIO_PAGE_SHIFT);
219
220                 sym_state->cur_queue->pfn = pfn;
221                 
222                 sym_state->cur_queue->ring_desc_addr = page_addr ;
223                 sym_state->cur_queue->ring_avail_addr = page_addr + (QUEUE_SIZE * sizeof(struct vring_desc));
224                 sym_state->cur_queue->ring_used_addr = ( sym_state->cur_queue->ring_avail_addr + \
225                                                  sizeof(struct vring_avail)    + \
226                                                  (QUEUE_SIZE * sizeof(uint16_t)));
227                 
228                 // round up to next page boundary.
229                 sym_state->cur_queue->ring_used_addr = (sym_state->cur_queue->ring_used_addr + 0xfff) & ~0xfff;
230
231                 if (guest_pa_to_host_va(core, sym_state->cur_queue->ring_desc_addr, (addr_t *)&(sym_state->cur_queue->desc)) == -1) {
232                     PrintError("Could not translate ring descriptor address\n");
233                     return -1;
234                 }
235
236
237                 if (guest_pa_to_host_va(core, sym_state->cur_queue->ring_avail_addr, (addr_t *)&(sym_state->cur_queue->avail)) == -1) {
238                     PrintError("Could not translate ring available address\n");
239                     return -1;
240                 }
241
242
243                 if (guest_pa_to_host_va(core, sym_state->cur_queue->ring_used_addr, (addr_t *)&(sym_state->cur_queue->used)) == -1) {
244                     PrintError("Could not translate ring used address\n");
245                     return -1;
246                 }
247
248                 PrintDebug("SYMMOD: RingDesc_addr=%p, Avail_addr=%p, Used_addr=%p\n",
249                            (void *)(sym_state->cur_queue->ring_desc_addr),
250                            (void *)(sym_state->cur_queue->ring_avail_addr),
251                            (void *)(sym_state->cur_queue->ring_used_addr));
252
253                 PrintDebug("SYMMOD: RingDesc=%p, Avail=%p, Used=%p\n", 
254                            sym_state->cur_queue->desc, sym_state->cur_queue->avail, sym_state->cur_queue->used);
255
256             } else {
257                 PrintError("Illegal write length for page frame number\n");
258                 return -1;
259             }
260             break;
261         case VRING_Q_SEL_PORT:
262             sym_state->virtio_cfg.vring_queue_selector = *(uint16_t *)src;
263
264             if (sym_state->virtio_cfg.vring_queue_selector > NUM_QUEUES) {
265                 PrintError("Virtio Symbiotic device has no qeueues. Selected %d\n", 
266                            sym_state->virtio_cfg.vring_queue_selector);
267                 return -1;
268             }
269             
270             sym_state->cur_queue = &(sym_state->queue[sym_state->virtio_cfg.vring_queue_selector]);
271
272             break;
273         case VRING_Q_NOTIFY_PORT: {
274             uint16_t queue_idx = *(uint16_t *)src;
275
276             PrintDebug("SYMMOD: Handling Kick\n");
277
278             if (queue_idx == 0) {
279                 sym_state->notifier_active = 1;
280
281             } else if (queue_idx == 1) {
282                 if (handle_xfer_kick(core, sym_state) == -1) {
283                     PrintError("Could not handle Symbiotic Notification\n");
284                     return -1;
285                 }
286             } else {
287                 PrintError("Kick on invalid queue (%d)\n", queue_idx);
288                 return -1;
289             }
290
291             break;
292         }
293         case VIRTIO_STATUS_PORT:
294             sym_state->virtio_cfg.status = *(uint8_t *)src;
295
296             if (sym_state->virtio_cfg.status == 0) {
297                 PrintDebug("SYMMOD: Resetting device\n");
298                 virtio_reset(sym_state);
299             }
300
301             break;
302
303         case VIRTIO_ISR_PORT:
304             sym_state->virtio_cfg.pci_isr = *(uint8_t *)src;
305             break;
306         default:
307             return -1;
308             break;
309     }
310
311     return length;
312 }
313
314
315 static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * private_data) {
316
317     struct virtio_sym_state * sym_state = (struct virtio_sym_state *)private_data;
318     int port_idx = port % sym_state->io_range_size;
319
320 /*
321     PrintDebug("SYMMOD: VIRTIO SYMBIOTIC Read  for port %d (index =%d), length=%d\n", 
322                port, port_idx, length);
323 */
324     switch (port_idx) {
325         case HOST_FEATURES_PORT:
326             if (length != 4) {
327                 PrintError("Illegal read length for host features\n");
328                 return -1;
329             }
330
331             *(uint32_t *)dst = sym_state->virtio_cfg.host_features;
332         
333             break;
334         case VRING_PG_NUM_PORT:
335             if (length != 4) {
336                 PrintError("Illegal read length for page frame number\n");
337                 return -1;
338             }
339
340             *(uint32_t *)dst = sym_state->cur_queue->pfn;
341
342             break;
343         case VRING_SIZE_PORT:
344             if (length != 2) {
345                 PrintError("Illegal read length for vring size\n");
346                 return -1;
347             }
348                 
349             *(uint16_t *)dst = sym_state->cur_queue->queue_size;
350
351             break;
352
353         case VIRTIO_STATUS_PORT:
354             if (length != 1) {
355                 PrintError("Illegal read length for status\n");
356                 return -1;
357             }
358
359             *(uint8_t *)dst = sym_state->virtio_cfg.status;
360             break;
361
362         case VIRTIO_ISR_PORT:
363             *(uint8_t *)dst = sym_state->virtio_cfg.pci_isr;
364             sym_state->virtio_cfg.pci_isr = 0;
365             v3_pci_lower_irq(sym_state->pci_bus, 0, sym_state->pci_dev);
366             break;
367
368         default:
369             if ( (port_idx >= sizeof(struct virtio_config)) && 
370                  (port_idx < (sizeof(struct virtio_config) + sizeof(struct sym_config))) ) {
371                 int cfg_offset = port_idx - sizeof(struct virtio_config);
372                 uint8_t * cfg_ptr = (uint8_t *)&(sym_state->sym_cfg);
373
374                 memcpy(dst, cfg_ptr + cfg_offset, length);
375                 
376             } else {
377                 PrintError("Read of Unhandled Virtio Read\n");
378                 return -1;
379             }
380           
381             break;
382     }
383
384     return length;
385 }
386
387
388
389
390 static int virtio_load_module(struct v3_vm_info * vm, char * name, int mod_size, void * priv_data) {
391     struct virtio_sym_state * virtio = (struct virtio_sym_state *)priv_data;
392     //   struct virtio_queue * q = virtio->cur_queue;
393     struct virtio_queue * q = &(virtio->queue[NOTIFY_QUEUE]);
394
395     if (strlen(name) >= 32) {
396         PrintError("Module name is too long... (%d bytes) limit is 32\n", (uint32_t)strlen(name));
397         return -1;
398     }
399
400     PrintDebug("SYMMOD: VIRTIO SYMMOD Loader: Loading Module (size=%d)\n", mod_size);
401
402     //queue is not set yet
403     if (q->ring_avail_addr == 0) {
404         PrintError("Queue is not set\n");
405         return -1;
406     }
407
408     
409     if (q->cur_avail_idx < q->avail->index) {
410         uint16_t notifier_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
411         struct symmod_hdr * notifier = NULL;
412         struct vring_desc * notifier_desc = NULL;
413
414         PrintDebug("SYMMOD: Descriptor index=%d\n", q->cur_avail_idx % q->queue_size);
415
416         notifier_desc = &(q->desc[notifier_idx]);
417
418         PrintDebug("SYMMOD: Notifier Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", notifier_desc, 
419                    (void *)(notifier_desc->addr_gpa), notifier_desc->length, notifier_desc->flags, notifier_desc->next);        
420
421         if (guest_pa_to_host_va(&(vm->cores[0]), notifier_desc->addr_gpa, (addr_t *)&(notifier)) == -1) {
422             PrintError("Could not translate receive buffer address\n");
423             return -1;
424         }
425
426         // clear the notifier
427         memset(notifier, 0, sizeof(struct symmod_hdr));
428
429         // set the module name
430         memcpy(notifier->name, name, strlen(name));
431
432         // set module length
433         notifier->num_bytes = mod_size;
434
435         
436         q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
437
438         q->used->ring[q->used->index % q->queue_size].length = sizeof(struct symmod_hdr);
439
440         q->used->index++;
441         q->cur_avail_idx++;
442     }
443
444     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
445         PrintDebug("SYMMOD: Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
446         v3_pci_raise_irq(virtio->pci_bus, 0, virtio->pci_dev);
447         virtio->virtio_cfg.pci_isr = 0x1;
448     }
449
450
451     return 0;
452 }
453
454
455
456
457 static struct v3_device_ops dev_ops = {
458     .free = NULL,
459     .reset = NULL,
460     .start = NULL,
461     .stop = NULL,
462 };
463
464
465
466 static struct v3_symmod_loader_ops loader_ops = {
467     .load_module = virtio_load_module,
468 };
469
470
471 static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
472     struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
473     struct virtio_sym_state * virtio_state = NULL;
474     struct pci_device * pci_dev = NULL;
475     char * name = v3_cfg_val(cfg, "name");
476
477     PrintDebug("SYMMOD: Initializing VIRTIO Symbiotic Module device\n");
478
479     if (pci_bus == NULL) {
480         PrintError("VirtIO devices require a PCI Bus");
481         return -1;
482     }
483     
484     virtio_state  = (struct virtio_sym_state *)V3_Malloc(sizeof(struct virtio_sym_state));
485     memset(virtio_state, 0, sizeof(struct virtio_sym_state));
486
487     struct vm_device * dev = v3_allocate_device(name, &dev_ops, virtio_state);
488
489     if (v3_attach_device(vm, dev) == -1) {
490         PrintError("Could not attach device %s\n", name);
491         return -1;
492     }
493
494
495     // PCI initialization
496     {
497         struct v3_pci_bar bars[6];
498         int num_ports = sizeof(struct virtio_config) + sizeof(struct sym_config);
499         int tmp_ports = num_ports;
500         int i;
501
502
503         // This gets the number of ports, rounded up to a power of 2
504         virtio_state->io_range_size = 1; // must be a power of 2
505
506         while (tmp_ports > 0) {
507             tmp_ports >>= 1;
508             virtio_state->io_range_size <<= 1;
509         }
510         
511         // this is to account for any low order bits being set in num_ports
512         // if there are none, then num_ports was already a power of 2 so we shift right to reset it
513         if ((num_ports & ((virtio_state->io_range_size >> 1) - 1)) == 0) {
514             virtio_state->io_range_size >>= 1;
515         }
516
517
518         for (i = 0; i < 6; i++) {
519             bars[i].type = PCI_BAR_NONE;
520         }
521
522         bars[0].type = PCI_BAR_IO;
523         bars[0].default_base_port = -1;
524         bars[0].num_ports = virtio_state->io_range_size;
525
526         bars[0].io_read = virtio_io_read;
527         bars[0].io_write = virtio_io_write;
528         bars[0].private_data = virtio_state;
529
530         pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
531                                          0, PCI_AUTO_DEV_NUM, 0,
532                                          "LNX_VIRTIO_SYMMOD", bars,
533                                          NULL, NULL, NULL, virtio_state);
534
535         if (!pci_dev) {
536             PrintError("Could not register PCI Device\n");
537             return -1;
538         }
539         
540         pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
541         pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
542         
543
544         pci_dev->config_header.device_id = VIRTIO_SYMMOD_DEV_ID;
545         pci_dev->config_header.class = PCI_CLASS_MEMORY;
546         pci_dev->config_header.subclass = PCI_MEM_SUBCLASS_RAM;
547     
548         pci_dev->config_header.subsystem_id = VIRTIO_SYMMOD_SUBDEVICE_ID;
549
550
551         pci_dev->config_header.intr_pin = 1;
552
553         pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
554
555
556         virtio_state->pci_dev = pci_dev;
557         virtio_state->pci_bus = pci_bus;
558     }
559
560     virtio_reset(virtio_state);
561
562     v3_set_symmod_loader(vm, &loader_ops, virtio_state);
563
564     return 0;
565 }
566
567
568 device_register("LNX_VIRTIO_SYMMOD", virtio_init)