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.


integrated new configuration system
[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, v3_cfg_tree_t * cfg) {
355     struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
356     struct virtio_sym_state * virtio_state = NULL;
357     struct pci_device * pci_dev = NULL;
358     char * name = v3_cfg_val(cfg, "name");
359
360     PrintDebug("Initializing VIRTIO Symbiotic device\n");
361
362     if (pci_bus == NULL) {
363         PrintError("VirtIO devices require a PCI Bus");
364         return -1;
365     }
366
367     
368     virtio_state  = (struct virtio_sym_state *)V3_Malloc(sizeof(struct virtio_sym_state));
369     memset(virtio_state, 0, sizeof(struct virtio_sym_state));
370
371
372     struct vm_device * dev = v3_allocate_device(name, &dev_ops, virtio_state);
373     if (v3_attach_device(vm, dev) == -1) {
374         PrintError("Could not attach device %s\n", name);
375         return -1;
376     }
377
378
379     // PCI initialization
380     {
381         struct v3_pci_bar bars[6];
382         int num_ports = sizeof(struct virtio_config) + sizeof(struct sym_config);
383         int tmp_ports = num_ports;
384         int i;
385
386
387
388         // This gets the number of ports, rounded up to a power of 2
389         virtio_state->io_range_size = 1; // must be a power of 2
390
391         while (tmp_ports > 0) {
392             tmp_ports >>= 1;
393             virtio_state->io_range_size <<= 1;
394         }
395         
396         // this is to account for any low order bits being set in num_ports
397         // if there are none, then num_ports was already a power of 2 so we shift right to reset it
398         if ((num_ports & ((virtio_state->io_range_size >> 1) - 1)) == 0) {
399             virtio_state->io_range_size >>= 1;
400         }
401
402
403         for (i = 0; i < 6; i++) {
404             bars[i].type = PCI_BAR_NONE;
405         }
406
407         bars[0].type = PCI_BAR_IO;
408         bars[0].default_base_port = -1;
409         bars[0].num_ports = virtio_state->io_range_size;
410
411         bars[0].io_read = virtio_io_read;
412         bars[0].io_write = virtio_io_write;
413         bars[0].private_data = dev;
414
415         pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
416                                          0, PCI_AUTO_DEV_NUM, 0,
417                                          "LNX_VIRTIO_SYM", bars,
418                                          NULL, NULL, NULL, dev);
419
420         if (!pci_dev) {
421             PrintError("Could not register PCI Device\n");
422             return -1;
423         }
424         
425         pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
426         pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
427         
428
429         pci_dev->config_header.device_id = VIRTIO_SYMBIOTIC_DEV_ID;
430         pci_dev->config_header.class = PCI_CLASS_MEMORY;
431         pci_dev->config_header.subclass = PCI_MEM_SUBCLASS_RAM;
432     
433         pci_dev->config_header.subsystem_id = VIRTIO_SYMBIOTIC_SUBDEVICE_ID;
434
435
436         pci_dev->config_header.intr_pin = 1;
437
438         pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
439
440
441         virtio_state->pci_dev = pci_dev;
442         virtio_state->pci_bus = pci_bus;
443     }
444
445     virtio_reset(dev);
446
447
448     return 0;
449 }
450
451
452 device_register("LNX_VIRTIO_SYM", virtio_init)