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.


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