symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/virtio-balloon.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * Virtio Block Device
       
     3  *
       
     4  * Copyright IBM, Corp. 2008
       
     5  *
       
     6  * Authors:
       
     7  *  Anthony Liguori   <aliguori@us.ibm.com>
       
     8  *
       
     9  * This work is licensed under the terms of the GNU GPL, version 2.  See
       
    10  * the COPYING file in the top-level directory.
       
    11  *
       
    12  */
       
    13 
       
    14 #include "qemu-common.h"
       
    15 #include "virtio.h"
       
    16 #include "pc.h"
       
    17 #include "sysemu.h"
       
    18 #include "cpu.h"
       
    19 #include "balloon.h"
       
    20 #include "virtio-balloon.h"
       
    21 #include "kvm.h"
       
    22 
       
    23 #if defined(__linux__)
       
    24 #include <sys/mman.h>
       
    25 #endif
       
    26 
       
    27 typedef struct VirtIOBalloon
       
    28 {
       
    29     VirtIODevice vdev;
       
    30     VirtQueue *ivq, *dvq;
       
    31     uint32_t num_pages;
       
    32     uint32_t actual;
       
    33 } VirtIOBalloon;
       
    34 
       
    35 static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev)
       
    36 {
       
    37     return (VirtIOBalloon *)vdev;
       
    38 }
       
    39 
       
    40 static void balloon_page(void *addr, int deflate)
       
    41 {
       
    42 #if defined(__linux__)
       
    43     if (!kvm_enabled() || kvm_has_sync_mmu())
       
    44         madvise(addr, TARGET_PAGE_SIZE,
       
    45                 deflate ? MADV_WILLNEED : MADV_DONTNEED);
       
    46 #endif
       
    47 }
       
    48 
       
    49 /* FIXME: once we do a virtio refactoring, this will get subsumed into common
       
    50  * code */
       
    51 static size_t memcpy_from_iovector(void *data, size_t offset, size_t size,
       
    52                                    struct iovec *iov, int iovlen)
       
    53 {
       
    54     int i;
       
    55     uint8_t *ptr = data;
       
    56     size_t iov_off = 0;
       
    57     size_t data_off = 0;
       
    58 
       
    59     for (i = 0; i < iovlen && size; i++) {
       
    60         if (offset < (iov_off + iov[i].iov_len)) {
       
    61             size_t len = MIN((iov_off + iov[i].iov_len) - offset , size);
       
    62 
       
    63             memcpy(ptr + data_off, iov[i].iov_base + (offset - iov_off), len);
       
    64 
       
    65             data_off += len;
       
    66             offset += len;
       
    67             size -= len;
       
    68         }
       
    69 
       
    70         iov_off += iov[i].iov_len;
       
    71     }
       
    72 
       
    73     return data_off;
       
    74 }
       
    75 
       
    76 static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
       
    77 {
       
    78     VirtIOBalloon *s = to_virtio_balloon(vdev);
       
    79     VirtQueueElement elem;
       
    80 
       
    81     while (virtqueue_pop(vq, &elem)) {
       
    82         size_t offset = 0;
       
    83         uint32_t pfn;
       
    84 
       
    85         while (memcpy_from_iovector(&pfn, offset, 4,
       
    86                                     elem.out_sg, elem.out_num) == 4) {
       
    87             ram_addr_t pa;
       
    88             ram_addr_t addr;
       
    89 
       
    90             pa = (ram_addr_t)ldl_p(&pfn) << VIRTIO_BALLOON_PFN_SHIFT;
       
    91             offset += 4;
       
    92 
       
    93             addr = cpu_get_physical_page_desc(pa);
       
    94             if ((addr & ~TARGET_PAGE_MASK) != IO_MEM_RAM)
       
    95                 continue;
       
    96 
       
    97             balloon_page(host_ram_addr(addr), !!(vq == s->dvq));
       
    98         }
       
    99 
       
   100         virtqueue_push(vq, &elem, offset);
       
   101         virtio_notify(vdev, vq);
       
   102     }
       
   103 }
       
   104 
       
   105 static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
       
   106 {
       
   107     VirtIOBalloon *dev = to_virtio_balloon(vdev);
       
   108     struct virtio_balloon_config config;
       
   109 
       
   110     config.num_pages = cpu_to_le32(dev->num_pages);
       
   111     config.actual = cpu_to_le32(dev->actual);
       
   112 
       
   113     memcpy(config_data, &config, 8);
       
   114 }
       
   115 
       
   116 static void virtio_balloon_set_config(VirtIODevice *vdev,
       
   117                                       const uint8_t *config_data)
       
   118 {
       
   119     VirtIOBalloon *dev = to_virtio_balloon(vdev);
       
   120     struct virtio_balloon_config config;
       
   121     memcpy(&config, config_data, 8);
       
   122     dev->actual = config.actual;
       
   123 }
       
   124 
       
   125 static uint32_t virtio_balloon_get_features(VirtIODevice *vdev)
       
   126 {
       
   127     return 0;
       
   128 }
       
   129 
       
   130 static ram_addr_t virtio_balloon_to_target(void *opaque, ram_addr_t target)
       
   131 {
       
   132     VirtIOBalloon *dev = opaque;
       
   133 
       
   134     if (target > ram_size)
       
   135         target = ram_size;
       
   136 
       
   137     if (target) {
       
   138         dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
       
   139         virtio_notify_config(&dev->vdev);
       
   140     }
       
   141 
       
   142     return ram_size - (dev->actual << VIRTIO_BALLOON_PFN_SHIFT);
       
   143 }
       
   144 
       
   145 static void virtio_balloon_save(QEMUFile *f, void *opaque)
       
   146 {
       
   147     VirtIOBalloon *s = opaque;
       
   148 
       
   149     virtio_save(&s->vdev, f);
       
   150 
       
   151     qemu_put_be32(f, s->num_pages);
       
   152     qemu_put_be32(f, s->actual);
       
   153 }
       
   154 
       
   155 static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
       
   156 {
       
   157     VirtIOBalloon *s = opaque;
       
   158 
       
   159     if (version_id != 1)
       
   160         return -EINVAL;
       
   161 
       
   162     virtio_load(&s->vdev, f);
       
   163 
       
   164     s->num_pages = qemu_get_be32(f);
       
   165     s->actual = qemu_get_be32(f);
       
   166 
       
   167     return 0;
       
   168 }
       
   169 
       
   170 void virtio_balloon_init(VirtIOBindFn bind, void *bind_arg)
       
   171 {
       
   172     VirtIOBalloon *s;
       
   173 
       
   174     s = (VirtIOBalloon *)bind(bind_arg, "virtio-balloon",
       
   175                               0, VIRTIO_ID_BALLOON,
       
   176                               8, sizeof(VirtIOBalloon));
       
   177     if (s == NULL)
       
   178         return;
       
   179 
       
   180     s->vdev.get_config = virtio_balloon_get_config;
       
   181     s->vdev.set_config = virtio_balloon_set_config;
       
   182     s->vdev.get_features = virtio_balloon_get_features;
       
   183 
       
   184     s->ivq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
       
   185     s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
       
   186 
       
   187     qemu_add_balloon_handler(virtio_balloon_to_target, s);
       
   188 
       
   189     register_savevm("virtio-balloon", -1, 1, virtio_balloon_save, virtio_balloon_load, s);
       
   190 }