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.


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