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.


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