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.


807f68d42f413fd407807bbe705f124685841c34
[palacios.git] / palacios / src / devices / lnx_virtio_balloon.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 <devices/lnx_virtio_pci.h>
23 #include <palacios/vm_guest_mem.h>
24
25 #include <devices/pci.h>
26
27
28 #define BLN_REQUESTED_PORT     20
29 #define BLN_ALLOCATED_PORT     28
30
31
32 #define PAGE_SIZE 4096
33
34 #define BALLOON_HCALL 0xba00
35
36 struct balloon_config {
37     uint32_t requested_pages;
38     uint32_t allocated_pages;
39 } __attribute__((packed));
40
41
42
43 /* How this works:
44  * A ballooning request is made by specifying the new memory size of the guest. The guest 
45  * will then shrink the amount of of memory it uses to target. The target size is stored in the 
46  * Virtio PCI configuration space in the requested pages field. The device raises its irq, to notify the guest
47  * 
48  * The guest might not be able to shrink to target, so it stores the size it was able to shrink to 
49  * into the allocate_pages field of the pci configuration space.
50  * 
51  * When the guest frees pages it writes the addresses to the deflation queue (the 2nd one), and does a kick.
52  * When pages are given back to the host they are fed in via the inflation queue (the 1st one), and raises an irq.
53  */
54
55
56 #define QUEUE_SIZE 128
57
58 /* Host Feature flags */
59 #define VIRTIO_NOTIFY_HOST       0x01     
60
61
62
63
64
65 struct virtio_balloon_state {
66     struct balloon_config balloon_cfg;
67     struct virtio_config virtio_cfg;
68
69     struct vm_device * pci_bus;
70     struct pci_device * pci_dev;
71     
72     struct virtio_queue queue[2];
73
74
75     struct virtio_queue * cur_queue;
76
77     int io_range_size;
78 };
79
80
81 static int virtio_free(struct vm_device * dev) {
82     return -1;
83 }
84
85 static int virtio_reset(struct vm_device * dev) {
86     struct virtio_balloon_state * virtio = (struct virtio_balloon_state *)dev->private_data;
87
88     memset(virtio->queue, 0, sizeof(struct virtio_queue) * 2);
89
90     virtio->cur_queue = &(virtio->queue[0]);
91
92
93     virtio->virtio_cfg.status = 0;
94     virtio->virtio_cfg.pci_isr = 0;
95
96
97     /* Balloon configuration */
98     virtio->virtio_cfg.host_features = VIRTIO_NOTIFY_HOST;
99
100     // Virtio Balloon uses two queues
101     virtio->queue[0].queue_size = QUEUE_SIZE;
102     virtio->queue[1].queue_size = QUEUE_SIZE;
103
104
105     memset(&(virtio->balloon_cfg), 0, sizeof(struct balloon_config));
106
107     return 0;
108 }
109
110
111
112
113 static int handle_kick(struct vm_device * dev) {
114     struct virtio_balloon_state * virtio = (struct virtio_balloon_state *)dev->private_data;    
115     struct virtio_queue * q = virtio->cur_queue;
116
117     PrintDebug("VIRTIO KICK: cur_index=%d, avail_index=%d\n", q->cur_avail_idx, q->avail->index);
118
119     while (q->cur_avail_idx < q->avail->index) {
120         struct vring_desc * hdr_desc = NULL;
121         struct vring_desc * buf_desc = NULL;
122         struct vring_desc * status_desc = NULL;
123         uint16_t chain_idx = q->avail->ring[q->cur_avail_idx];
124         uint32_t req_len = 0;
125         int chained = 1;
126
127         PrintDebug("chained=%d, Chain Index=%d\n", chained, chain_idx);
128
129         while (chained) {
130             hdr_desc = &(q->desc[chain_idx]);
131             
132             PrintDebug("Header Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", hdr_desc, 
133                        (void *)(hdr_desc->addr_gpa), hdr_desc->length, hdr_desc->flags, hdr_desc->next);
134         
135             if (!(hdr_desc->flags & VIRTIO_NEXT_FLAG)) {
136                 PrintError("Balloon operations must chain a buffer descriptor\n");
137                 return -1;
138             }
139
140             buf_desc = &(q->desc[hdr_desc->next]);
141             
142             PrintDebug("Buffer Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", buf_desc, 
143                        (void *)(buf_desc->addr_gpa), buf_desc->length, buf_desc->flags, buf_desc->next);
144             
145             if (!(buf_desc->flags & VIRTIO_NEXT_FLAG)) {
146                 PrintError("Balloon operatoins must chain a status descriptor\n");
147                 return -1;
148             }
149             
150             status_desc = &(q->desc[buf_desc->next]);
151
152             // We detect whether we are chained here...
153             if (status_desc->flags & VIRTIO_NEXT_FLAG) {
154                 chained = 1;
155                 chain_idx = status_desc->next; 
156             } else {
157                 chained = 0;
158             }
159
160             PrintDebug("Status Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", status_desc, 
161                        (void *)(status_desc->addr_gpa), status_desc->length, status_desc->flags, status_desc->next);
162             
163
164             /*      
165                if (handle_balloon_op(dev, hdr_desc, buf_desc, status_desc) == -1) {
166                PrintError("Error handling balloon operation\n");
167                return -1;
168                }
169             */
170
171             PrintDebug("Guest Balloon Currently Ignored\n");
172             PrintDebug("\t Requested=%d, Allocated=%d\n", virtio->balloon_cfg.requested_pages, virtio->balloon_cfg.allocated_pages);
173
174
175             req_len += (buf_desc->length + status_desc->length);
176         }
177
178         q->used->ring[q->used->index].id = q->avail->ring[q->cur_avail_idx];
179         q->used->ring[q->used->index].length = req_len; // What do we set this to????
180
181         q->used->index = (q->used->index + 1) % (QUEUE_SIZE * sizeof(struct vring_desc));;
182
183
184         q->cur_avail_idx = (q->cur_avail_idx + 1) % (QUEUE_SIZE * sizeof(struct vring_desc));
185     }
186
187     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
188         PrintDebug("Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
189         v3_pci_raise_irq(virtio->pci_bus, 0, virtio->pci_dev);
190         virtio->virtio_cfg.pci_isr = 1;
191     }
192
193     return 0;
194 }
195
196 static int virtio_io_write(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
197     struct virtio_balloon_state * virtio = (struct virtio_balloon_state *)dev->private_data;
198     int port_idx = port % virtio->io_range_size;
199
200
201     PrintDebug("VIRTIO BALLOON Write for port %d (index=%d) len=%d, value=%x\n", 
202                port, port_idx,  length, *(uint32_t *)src);
203
204
205
206     switch (port_idx) {
207         case GUEST_FEATURES_PORT:
208             if (length != 4) {
209                 PrintError("Illegal write length for guest features\n");
210                 return -1;
211             }
212             
213             virtio->virtio_cfg.guest_features = *(uint32_t *)src;
214
215             break;
216         case VRING_PG_NUM_PORT:
217             if (length == 4) {
218                 addr_t pfn = *(uint32_t *)src;
219                 addr_t page_addr = (pfn << VIRTIO_PAGE_SHIFT);
220
221
222                 virtio->cur_queue->pfn = pfn;
223                 
224                 virtio->cur_queue->ring_desc_addr = page_addr ;
225                 virtio->cur_queue->ring_avail_addr = page_addr + (QUEUE_SIZE * sizeof(struct vring_desc));
226                 virtio->cur_queue->ring_used_addr = ( virtio->cur_queue->ring_avail_addr + \
227                                                  sizeof(struct vring_avail)    + \
228                                                  (QUEUE_SIZE * sizeof(uint16_t)));
229                 
230                 // round up to next page boundary.
231                 virtio->cur_queue->ring_used_addr = (virtio->cur_queue->ring_used_addr + 0xfff) & ~0xfff;
232
233                 if (guest_pa_to_host_va(dev->vm, virtio->cur_queue->ring_desc_addr, (addr_t *)&(virtio->cur_queue->desc)) == -1) {
234                     PrintError("Could not translate ring descriptor address\n");
235                     return -1;
236                 }
237
238
239                 if (guest_pa_to_host_va(dev->vm, virtio->cur_queue->ring_avail_addr, (addr_t *)&(virtio->cur_queue->avail)) == -1) {
240                     PrintError("Could not translate ring available address\n");
241                     return -1;
242                 }
243
244
245                 if (guest_pa_to_host_va(dev->vm, virtio->cur_queue->ring_used_addr, (addr_t *)&(virtio->cur_queue->used)) == -1) {
246                     PrintError("Could not translate ring used address\n");
247                     return -1;
248                 }
249
250                 PrintDebug("RingDesc_addr=%p, Avail_addr=%p, Used_addr=%p\n",
251                            (void *)(virtio->cur_queue->ring_desc_addr),
252                            (void *)(virtio->cur_queue->ring_avail_addr),
253                            (void *)(virtio->cur_queue->ring_used_addr));
254
255                 PrintDebug("RingDesc=%p, Avail=%p, Used=%p\n", 
256                            virtio->cur_queue->desc, virtio->cur_queue->avail, virtio->cur_queue->used);
257
258             } else {
259                 PrintError("Illegal write length for page frame number\n");
260                 return -1;
261             }
262             break;
263         case VRING_Q_SEL_PORT:
264             virtio->virtio_cfg.vring_queue_selector = *(uint16_t *)src;
265
266             if (virtio->virtio_cfg.vring_queue_selector > 1) {
267                 PrintError("Virtio Balloon device only uses 2 queue, selected %d\n", 
268                            virtio->virtio_cfg.vring_queue_selector);
269                 return -1;
270             }
271             
272             virtio->cur_queue = &(virtio->queue[virtio->virtio_cfg.vring_queue_selector]);
273
274             break;
275         case VRING_Q_NOTIFY_PORT:
276             PrintDebug("Handling Kick\n");
277             if (handle_kick(dev) == -1) {
278                 PrintError("Could not handle Balloon Notification\n");
279                 return -1;
280             }
281             break;
282         case VIRTIO_STATUS_PORT:
283             virtio->virtio_cfg.status = *(uint8_t *)src;
284
285             if (virtio->virtio_cfg.status == 0) {
286                 PrintDebug("Resetting device\n");
287                 virtio_reset(dev);
288             }
289
290             break;
291
292         case VIRTIO_ISR_PORT:
293             virtio->virtio_cfg.pci_isr = *(uint8_t *)src;
294             break;
295         default:
296             return -1;
297             break;
298     }
299
300     return length;
301 }
302
303
304 static int virtio_io_read(uint16_t port, void * dst, uint_t length, struct vm_device * dev) {
305     struct virtio_balloon_state * virtio = (struct virtio_balloon_state *)dev->private_data;
306     int port_idx = port % virtio->io_range_size;
307
308
309     PrintDebug("VIRTIO BALLOON Read  for port %d (index =%d), length=%d\n", 
310                port, port_idx, length);
311
312     switch (port_idx) {
313         case HOST_FEATURES_PORT:
314             if (length != 4) {
315                 PrintError("Illegal read length for host features\n");
316                 return -1;
317             }
318
319             *(uint32_t *)dst = virtio->virtio_cfg.host_features;
320         
321             break;
322         case VRING_PG_NUM_PORT:
323             if (length != 4) {
324                 PrintError("Illegal read length for page frame number\n");
325                 return -1;
326             }
327
328             *(uint32_t *)dst = virtio->cur_queue->pfn;
329
330             break;
331         case VRING_SIZE_PORT:
332             if (length != 2) {
333                 PrintError("Illegal read length for vring size\n");
334                 return -1;
335             }
336                 
337             *(uint16_t *)dst = virtio->cur_queue->queue_size;
338
339             break;
340
341         case VIRTIO_STATUS_PORT:
342             if (length != 1) {
343                 PrintError("Illegal read length for status\n");
344                 return -1;
345             }
346
347             *(uint8_t *)dst = virtio->virtio_cfg.status;
348             break;
349
350         case VIRTIO_ISR_PORT:
351             *(uint8_t *)dst = virtio->virtio_cfg.pci_isr;
352             virtio->virtio_cfg.pci_isr = 0;
353             v3_pci_lower_irq(virtio->pci_bus, 0, virtio->pci_dev);
354             break;
355
356         default:
357             if ( (port_idx >= sizeof(struct virtio_config)) && 
358                  (port_idx < (sizeof(struct virtio_config) + sizeof(struct balloon_config))) ) {
359
360                 uint8_t * cfg_ptr = (uint8_t *)&(virtio->balloon_cfg);
361                 memcpy(dst, cfg_ptr, length);
362                 
363             } else {
364                 PrintError("Read of Unhandled Virtio Read\n");
365                 return -1;
366             }
367           
368             break;
369     }
370
371     return length;
372 }
373
374
375
376
377 static struct v3_device_ops dev_ops = {
378     .free = virtio_free,
379     .reset = NULL,
380     .start = NULL,
381     .stop = NULL,
382 };
383
384
385 static int set_size(struct vm_device * dev, addr_t size) {
386     struct virtio_balloon_state * virtio = (struct virtio_balloon_state *)dev->private_data;
387
388     virtio->balloon_cfg.requested_pages = size / PAGE_SIZE; // number of pages
389     v3_pci_raise_irq(virtio->pci_bus, 0, virtio->pci_dev);
390     
391     return 0;
392 }
393
394
395 static int handle_hcall(struct guest_info * info, uint_t hcall_id, void * priv_data) {
396     struct vm_device * dev = (struct vm_device *)priv_data;
397     int tgt_size = info->vm_regs.rcx;
398
399     
400     return set_size(dev, tgt_size);
401 }
402
403
404
405
406
407 static int virtio_init(struct guest_info * vm, void * cfg_data) {
408     struct vm_device * pci_bus = v3_find_dev(vm, (char *)cfg_data);
409     struct virtio_balloon_state * virtio_state = NULL;
410     struct pci_device * pci_dev = NULL;
411
412     PrintDebug("Initializing VIRTIO Balloon device\n");
413
414     if (pci_bus == NULL) {
415         PrintError("VirtIO devices require a PCI Bus");
416         return -1;
417     }
418
419     
420     virtio_state  = (struct virtio_balloon_state *)V3_Malloc(sizeof(struct virtio_balloon_state));
421     memset(virtio_state, 0, sizeof(struct virtio_balloon_state));
422
423
424     struct vm_device * dev = v3_allocate_device("LNX_VIRTIO_BALLOON", &dev_ops, virtio_state);
425     if (v3_attach_device(vm, dev) == -1) {
426         PrintError("Could not attach device %s\n", "LNX_VIRTIO_BALLOON");
427         return -1;
428     }
429
430
431
432
433     // PCI initialization
434     {
435         struct v3_pci_bar bars[6];
436         int num_ports = sizeof(struct virtio_config) + sizeof(struct balloon_config);
437         int tmp_ports = num_ports;
438         int i;
439
440
441
442         // This gets the number of ports, rounded up to a power of 2
443         virtio_state->io_range_size = 1; // must be a power of 2
444
445         while (tmp_ports > 0) {
446             tmp_ports >>= 1;
447             virtio_state->io_range_size <<= 1;
448         }
449         
450         // this is to account for any low order bits being set in num_ports
451         // if there are none, then num_ports was already a power of 2 so we shift right to reset it
452         if ((num_ports & ((virtio_state->io_range_size >> 1) - 1)) == 0) {
453             virtio_state->io_range_size >>= 1;
454         }
455
456
457         for (i = 0; i < 6; i++) {
458             bars[i].type = PCI_BAR_NONE;
459         }
460
461         bars[0].type = PCI_BAR_IO;
462         bars[0].default_base_port = -1;
463         bars[0].num_ports = virtio_state->io_range_size;
464
465         bars[0].io_read = virtio_io_read;
466         bars[0].io_write = virtio_io_write;
467
468         pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
469                                          0, PCI_AUTO_DEV_NUM, 0,
470                                          "LNX_VIRTIO_BALLOON", bars,
471                                          NULL, NULL, NULL, dev);
472
473         if (!pci_dev) {
474             PrintError("Could not register PCI Device\n");
475             return -1;
476         }
477         
478         pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
479         pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
480         
481
482         pci_dev->config_header.device_id = VIRTIO_BALLOON_DEV_ID;
483         pci_dev->config_header.class = PCI_CLASS_MEMORY;
484         pci_dev->config_header.subclass = PCI_MEM_SUBCLASS_RAM;
485     
486         pci_dev->config_header.subsystem_id = VIRTIO_BALLOON_SUBDEVICE_ID;
487
488
489         pci_dev->config_header.intr_pin = 1;
490
491         pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
492
493
494         virtio_state->pci_dev = pci_dev;
495         virtio_state->pci_bus = pci_bus;
496     }
497
498     virtio_reset(dev);
499
500     v3_register_hypercall(vm, BALLOON_HCALL, handle_hcall, dev);
501
502     return 0;
503 }
504
505
506 device_register("LNX_VIRTIO_BALLOON", virtio_init)