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.


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