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.


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