1 #include "kvm/virtio-rng.h"
3 #include "kvm/virtio-pci-dev.h"
5 #include "kvm/virtio.h"
8 #include "kvm/threadpool.h"
9 #include "kvm/guest_compat.h"
10 #include "kvm/virtio-pci.h"
12 #include <linux/virtio_ring.h>
13 #include <linux/virtio_rng.h>
15 #include <linux/list.h>
17 #include <sys/types.h>
20 #include <linux/kernel.h>
22 #define NUM_VIRT_QUEUES 1
23 #define VIRTIO_RNG_QUEUE_SIZE 128
26 struct virt_queue
*vq
;
28 struct thread_pool__job job_id
;
32 struct list_head list
;
33 struct virtio_pci vpci
;
39 struct virt_queue vqs
[NUM_VIRT_QUEUES
];
40 struct rng_dev_job jobs
[NUM_VIRT_QUEUES
];
43 static LIST_HEAD(rdevs
);
45 static void set_config(struct kvm
*kvm
, void *dev
, u8 data
, u32 offset
)
50 static u8
get_config(struct kvm
*kvm
, void *dev
, u32 offset
)
56 static u32
get_host_features(struct kvm
*kvm
, void *dev
)
62 static void set_guest_features(struct kvm
*kvm
, void *dev
, u32 features
)
67 static bool virtio_rng_do_io_request(struct kvm
*kvm
, struct rng_dev
*rdev
, struct virt_queue
*queue
)
69 struct iovec iov
[VIRTIO_RNG_QUEUE_SIZE
];
73 head
= virt_queue__get_iov(queue
, iov
, &out
, &in
, kvm
);
74 len
= readv(rdev
->fd
, iov
, in
);
76 virt_queue__set_used_elem(queue
, head
, len
);
81 static void virtio_rng_do_io(struct kvm
*kvm
, void *param
)
83 struct rng_dev_job
*job
= param
;
84 struct virt_queue
*vq
= job
->vq
;
85 struct rng_dev
*rdev
= job
->rdev
;
87 while (virt_queue__available(vq
))
88 virtio_rng_do_io_request(kvm
, rdev
, vq
);
90 virtio_pci__signal_vq(kvm
, &rdev
->vpci
, vq
- rdev
->vqs
);
93 static int init_vq(struct kvm
*kvm
, void *dev
, u32 vq
, u32 pfn
)
95 struct rng_dev
*rdev
= dev
;
96 struct virt_queue
*queue
;
97 struct rng_dev_job
*job
;
100 compat__remove_message(rdev
->compat_id
);
102 queue
= &rdev
->vqs
[vq
];
104 p
= guest_pfn_to_host(kvm
, queue
->pfn
);
106 job
= &rdev
->jobs
[vq
];
108 vring_init(&queue
->vring
, VIRTIO_RNG_QUEUE_SIZE
, p
, VIRTIO_PCI_VRING_ALIGN
);
110 *job
= (struct rng_dev_job
) {
115 thread_pool__init_job(&job
->job_id
, kvm
, virtio_rng_do_io
, job
);
120 static int notify_vq(struct kvm
*kvm
, void *dev
, u32 vq
)
122 struct rng_dev
*rdev
= dev
;
124 thread_pool__do_job(&rdev
->jobs
[vq
].job_id
);
129 static int get_pfn_vq(struct kvm
*kvm
, void *dev
, u32 vq
)
131 struct rng_dev
*rdev
= dev
;
133 return rdev
->vqs
[vq
].pfn
;
136 static int get_size_vq(struct kvm
*kvm
, void *dev
, u32 vq
)
138 return VIRTIO_RNG_QUEUE_SIZE
;
141 void virtio_rng__init(struct kvm
*kvm
)
143 struct rng_dev
*rdev
;
145 rdev
= malloc(sizeof(*rdev
));
149 rdev
->fd
= open("/dev/urandom", O_RDONLY
);
151 die("Failed initializing RNG");
153 virtio_pci__init(kvm
, &rdev
->vpci
, rdev
, PCI_DEVICE_ID_VIRTIO_RNG
, VIRTIO_ID_RNG
);
154 rdev
->vpci
.ops
= (struct virtio_pci_ops
) {
155 .set_config
= set_config
,
156 .get_config
= get_config
,
157 .get_host_features
= get_host_features
,
158 .set_guest_features
= set_guest_features
,
160 .notify_vq
= notify_vq
,
161 .get_pfn_vq
= get_pfn_vq
,
162 .get_size_vq
= get_size_vq
,
165 list_add_tail(&rdev
->list
, &rdevs
);
167 rdev
->compat_id
= compat__add_message("virtio-rng device was not detected",
168 "While you have requested a virtio-rng device, "
169 "the guest kernel didn't seem to detect it.\n"
170 "Please make sure that the kernel was compiled"
171 "with CONFIG_HW_RANDOM_VIRTIO.");
174 void virtio_rng__delete_all(struct kvm
*kvm
)
176 while (!list_empty(&rdevs
)) {
177 struct rng_dev
*rdev
;
179 rdev
= list_first_entry(&rdevs
, struct rng_dev
, list
);
180 list_del(&rdev
->list
);