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.


2cd3745a1a2346631d66694c23a9d1757a8bd57f
[palacios.git] / palacios / src / devices / lnx_virtio_sym.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
25 #include <devices/pci.h>
26
27
28 #define SYM_MAGIC_PORT 20
29 #define SYM_SWAP_BASE_PORT 24
30 #define SYM_SWAP_SIZE_PORT 32
31
32
33 #define QUEUE_SIZE 128
34
35 struct sym_config {
36     uint32_t magic;
37     uint64_t swap_base;
38     uint32_t swap_size;
39 } __attribute__((packed));
40
41
42
43 struct virtio_sym_state {
44     struct sym_config sym_cfg;
45     struct virtio_config virtio_cfg;
46
47
48     struct vm_device * pci_bus;
49     struct pci_device * pci_dev;
50
51     struct virtio_queue queue[1];
52
53     struct virtio_queue * cur_queue;
54
55     int io_range_size;
56 };
57
58
59
60
61
62 static int virtio_reset(struct vm_device * dev) {
63     struct virtio_sym_state * virtio = (struct virtio_sym_state *)dev->private_data;
64
65     memset(virtio->queue, 0, sizeof(struct virtio_queue));
66
67     virtio->cur_queue = &(virtio->queue[0]);
68
69
70     virtio->virtio_cfg.status = 0;
71     virtio->virtio_cfg.pci_isr = 0;
72
73     virtio->queue[1].queue_size = QUEUE_SIZE;
74
75
76     memset(&(virtio->sym_cfg), 0, sizeof(struct sym_config));
77
78     return 0;
79 }
80
81
82 static int get_desc_count(struct virtio_queue * q, int index) {
83     struct vring_desc * tmp_desc = &(q->desc[index]);
84     int cnt = 1;
85     
86     while (tmp_desc->flags & VIRTIO_NEXT_FLAG) {
87         tmp_desc = &(q->desc[tmp_desc->next]);
88         cnt++;
89     }
90
91     return cnt;
92 }
93
94
95 static int handle_kick(struct vm_device * dev) {
96     struct virtio_sym_state * virtio = (struct virtio_sym_state *)dev->private_data;    
97     struct virtio_queue * q = virtio->cur_queue;
98
99     return -1;
100
101     PrintDebug("VIRTIO Symbiotic KICK: cur_index=%d (mod=%d), avail_index=%d\n", 
102                q->cur_avail_idx, q->cur_avail_idx % QUEUE_SIZE, q->avail->index);
103
104     while (q->cur_avail_idx < q->avail->index) {
105         struct vring_desc * tmp_desc = NULL;
106         uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % QUEUE_SIZE];
107         int desc_cnt = get_desc_count(q, desc_idx);
108         int i = 0;
109         uint32_t req_len = 0;
110
111
112         PrintDebug("Descriptor Count=%d, index=%d\n", desc_cnt, q->cur_avail_idx % QUEUE_SIZE);
113
114         for (i = 0; i < desc_cnt; i++) {
115             addr_t page_addr;
116             tmp_desc = &(q->desc[desc_idx]);
117             
118             PrintDebug("Header Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", 
119                        tmp_desc, 
120                        (void *)(addr_t)(tmp_desc->addr_gpa), tmp_desc->length, 
121                        tmp_desc->flags, tmp_desc->next);
122         
123
124             if (guest_pa_to_host_va(dev->vm, tmp_desc->addr_gpa, (addr_t *)&(page_addr)) == -1) {
125                 PrintError("Could not translate block header address\n");
126                 return -1;
127             }
128
129             /*      
130                if (handle_sym_op(dev, tmp_desc, buf_desc, status_desc) == -1) {
131                PrintError("Error handling symbiotic operation\n");
132                return -1;
133                }
134             */
135
136             PrintDebug("Symbiotic Device Currently Ignored\n");
137
138
139             req_len += tmp_desc->length;
140             desc_idx = tmp_desc->next;
141         }
142
143         q->used->ring[q->used->index % QUEUE_SIZE].id = q->avail->ring[q->cur_avail_idx % QUEUE_SIZE];
144         q->used->ring[q->used->index % QUEUE_SIZE].length = req_len; // What do we set this to????
145
146         q->used->index++;
147         q->cur_avail_idx++;
148     }
149
150     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
151         PrintDebug("Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
152         v3_pci_raise_irq(virtio->pci_bus, 0, virtio->pci_dev);
153         virtio->virtio_cfg.pci_isr = VIRTIO_ISR_ACTIVE;
154     }
155
156     return 0;
157 }
158
159
160 static int virtio_io_write(uint16_t port, void * src, uint_t length, void * private_data) {
161     struct vm_device * dev = (struct vm_device *)private_data;
162     struct virtio_sym_state * virtio = (struct virtio_sym_state *)dev->private_data;
163     int port_idx = port % virtio->io_range_size;
164
165
166 /*
167     PrintDebug("VIRTIO SYMBIOTIC Write for port %d (index=%d) len=%d, value=%x\n", 
168                port, port_idx,  length, *(uint32_t *)src);
169 */
170
171
172     switch (port_idx) {
173         case GUEST_FEATURES_PORT:
174             if (length != 4) {
175                 PrintError("Illegal write length for guest features\n");
176                 return -1;
177             }
178             
179             virtio->virtio_cfg.guest_features = *(uint32_t *)src;
180
181             break;
182         case VRING_PG_NUM_PORT:
183             if (length == 4) {
184                 addr_t pfn = *(uint32_t *)src;
185                 addr_t page_addr = (pfn << VIRTIO_PAGE_SHIFT);
186
187
188                 virtio->cur_queue->pfn = pfn;
189                 
190                 virtio->cur_queue->ring_desc_addr = page_addr ;
191                 virtio->cur_queue->ring_avail_addr = page_addr + (QUEUE_SIZE * sizeof(struct vring_desc));
192                 virtio->cur_queue->ring_used_addr = ( virtio->cur_queue->ring_avail_addr + \
193                                                  sizeof(struct vring_avail)    + \
194                                                  (QUEUE_SIZE * sizeof(uint16_t)));
195                 
196                 // round up to next page boundary.
197                 virtio->cur_queue->ring_used_addr = (virtio->cur_queue->ring_used_addr + 0xfff) & ~0xfff;
198
199                 if (guest_pa_to_host_va(dev->vm, virtio->cur_queue->ring_desc_addr, (addr_t *)&(virtio->cur_queue->desc)) == -1) {
200                     PrintError("Could not translate ring descriptor address\n");
201                     return -1;
202                 }
203
204
205                 if (guest_pa_to_host_va(dev->vm, virtio->cur_queue->ring_avail_addr, (addr_t *)&(virtio->cur_queue->avail)) == -1) {
206                     PrintError("Could not translate ring available address\n");
207                     return -1;
208                 }
209
210
211                 if (guest_pa_to_host_va(dev->vm, virtio->cur_queue->ring_used_addr, (addr_t *)&(virtio->cur_queue->used)) == -1) {
212                     PrintError("Could not translate ring used address\n");
213                     return -1;
214                 }
215
216                 PrintDebug("RingDesc_addr=%p, Avail_addr=%p, Used_addr=%p\n",
217                            (void *)(virtio->cur_queue->ring_desc_addr),
218                            (void *)(virtio->cur_queue->ring_avail_addr),
219                            (void *)(virtio->cur_queue->ring_used_addr));
220
221                 PrintDebug("RingDesc=%p, Avail=%p, Used=%p\n", 
222                            virtio->cur_queue->desc, virtio->cur_queue->avail, virtio->cur_queue->used);
223
224             } else {
225                 PrintError("Illegal write length for page frame number\n");
226                 return -1;
227             }
228             break;
229         case VRING_Q_SEL_PORT:
230             virtio->virtio_cfg.vring_queue_selector = *(uint16_t *)src;
231
232             if (virtio->virtio_cfg.vring_queue_selector > 0) {
233                 PrintError("Virtio Symbiotic device has not qeueues. Selected %d\n", 
234                            virtio->virtio_cfg.vring_queue_selector);
235                 return -1;
236             }
237             
238             virtio->cur_queue = &(virtio->queue[virtio->virtio_cfg.vring_queue_selector]);
239
240             break;
241         case VRING_Q_NOTIFY_PORT:
242             PrintDebug("Handling Kick\n");
243             if (handle_kick(dev) == -1) {
244                 PrintError("Could not handle Symbiotic Notification\n");
245                 return -1;
246             }
247             break;
248         case VIRTIO_STATUS_PORT:
249             virtio->virtio_cfg.status = *(uint8_t *)src;
250
251             if (virtio->virtio_cfg.status == 0) {
252                 PrintDebug("Resetting device\n");
253                 virtio_reset(dev);
254             }
255
256             break;
257
258         case VIRTIO_ISR_PORT:
259             virtio->virtio_cfg.pci_isr = *(uint8_t *)src;
260             break;
261         default:
262             return -1;
263             break;
264     }
265
266     return length;
267 }
268
269
270 static int virtio_io_read(uint16_t port, void * dst, uint_t length, void * private_data) {
271     struct vm_device * dev = (struct vm_device *)private_data;
272     struct virtio_sym_state * virtio = (struct virtio_sym_state *)dev->private_data;
273     int port_idx = port % virtio->io_range_size;
274
275 /*
276     PrintDebug("VIRTIO SYMBIOTIC Read  for port %d (index =%d), length=%d\n", 
277                port, port_idx, length);
278 */
279     switch (port_idx) {
280         case HOST_FEATURES_PORT:
281             if (length != 4) {
282                 PrintError("Illegal read length for host features\n");
283                 return -1;
284             }
285
286             *(uint32_t *)dst = virtio->virtio_cfg.host_features;
287         
288             break;
289         case VRING_PG_NUM_PORT:
290             if (length != 4) {
291                 PrintError("Illegal read length for page frame number\n");
292                 return -1;
293             }
294
295             *(uint32_t *)dst = virtio->cur_queue->pfn;
296
297             break;
298         case VRING_SIZE_PORT:
299             if (length != 2) {
300                 PrintError("Illegal read length for vring size\n");
301                 return -1;
302             }
303                 
304             *(uint16_t *)dst = virtio->cur_queue->queue_size;
305
306             break;
307
308         case VIRTIO_STATUS_PORT:
309             if (length != 1) {
310                 PrintError("Illegal read length for status\n");
311                 return -1;
312             }
313
314             *(uint8_t *)dst = virtio->virtio_cfg.status;
315             break;
316
317         case VIRTIO_ISR_PORT:
318             *(uint8_t *)dst = virtio->virtio_cfg.pci_isr;
319             virtio->virtio_cfg.pci_isr = 0;
320             v3_pci_lower_irq(virtio->pci_bus, 0, virtio->pci_dev);
321             break;
322
323         default:
324             if ( (port_idx >= sizeof(struct virtio_config)) && 
325                  (port_idx < (sizeof(struct virtio_config) + sizeof(struct sym_config))) ) {
326                 int cfg_offset = port_idx - sizeof(struct virtio_config);
327                 uint8_t * cfg_ptr = (uint8_t *)&(virtio->sym_cfg);
328
329                 memcpy(dst, cfg_ptr + cfg_offset, length);
330                 
331             } else {
332                 PrintError("Read of Unhandled Virtio Read\n");
333                 return -1;
334             }
335           
336             break;
337     }
338
339     return length;
340 }
341
342
343
344    
345
346 static struct v3_device_ops dev_ops = {
347     .free = NULL,
348     .reset = NULL,
349     .start = NULL,
350     .stop = NULL,
351 };
352
353
354
355
356 static int virtio_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
357     struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
358     struct virtio_sym_state * virtio_state = NULL;
359     struct pci_device * pci_dev = NULL;
360     char * name = v3_cfg_val(cfg, "name");
361
362     PrintDebug("Initializing VIRTIO Symbiotic device\n");
363
364     if (pci_bus == NULL) {
365         PrintError("VirtIO devices require a PCI Bus");
366         return -1;
367     }
368
369     
370     virtio_state  = (struct virtio_sym_state *)V3_Malloc(sizeof(struct virtio_sym_state));
371     memset(virtio_state, 0, sizeof(struct virtio_sym_state));
372
373
374     struct vm_device * dev = v3_allocate_device(name, &dev_ops, virtio_state);
375     if (v3_attach_device(vm, dev) == -1) {
376         PrintError("Could not attach device %s\n", name);
377         return -1;
378     }
379
380
381     // PCI initialization
382     {
383         struct v3_pci_bar bars[6];
384         int num_ports = sizeof(struct virtio_config) + sizeof(struct sym_config);
385         int tmp_ports = num_ports;
386         int i;
387
388
389
390         // This gets the number of ports, rounded up to a power of 2
391         virtio_state->io_range_size = 1; // must be a power of 2
392
393         while (tmp_ports > 0) {
394             tmp_ports >>= 1;
395             virtio_state->io_range_size <<= 1;
396         }
397         
398         // this is to account for any low order bits being set in num_ports
399         // if there are none, then num_ports was already a power of 2 so we shift right to reset it
400         if ((num_ports & ((virtio_state->io_range_size >> 1) - 1)) == 0) {
401             virtio_state->io_range_size >>= 1;
402         }
403
404
405         for (i = 0; i < 6; i++) {
406             bars[i].type = PCI_BAR_NONE;
407         }
408
409         bars[0].type = PCI_BAR_IO;
410         bars[0].default_base_port = -1;
411         bars[0].num_ports = virtio_state->io_range_size;
412
413         bars[0].io_read = virtio_io_read;
414         bars[0].io_write = virtio_io_write;
415         bars[0].private_data = dev;
416
417         pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
418                                          0, PCI_AUTO_DEV_NUM, 0,
419                                          "LNX_VIRTIO_SYM", bars,
420                                          NULL, NULL, NULL, dev);
421
422         if (!pci_dev) {
423             PrintError("Could not register PCI Device\n");
424             return -1;
425         }
426         
427         pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
428         pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
429         
430
431         pci_dev->config_header.device_id = VIRTIO_SYMBIOTIC_DEV_ID;
432         pci_dev->config_header.class = PCI_CLASS_MEMORY;
433         pci_dev->config_header.subclass = PCI_MEM_SUBCLASS_RAM;
434     
435         pci_dev->config_header.subsystem_id = VIRTIO_SYMBIOTIC_SUBDEVICE_ID;
436
437
438         pci_dev->config_header.intr_pin = 1;
439
440         pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
441
442
443         virtio_state->pci_dev = pci_dev;
444         virtio_state->pci_bus = pci_bus;
445     }
446
447     virtio_reset(dev);
448
449
450     return 0;
451 }
452
453
454 device_register("LNX_VIRTIO_SYM", virtio_init)