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.


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