1
2
3
4
5
6
7
8
9
10#include <linux/init.h>
11#include <linux/bootmem.h>
12#include <linux/lguest_launcher.h>
13#include <linux/virtio.h>
14#include <linux/virtio_config.h>
15#include <linux/interrupt.h>
16#include <linux/virtio_ring.h>
17#include <linux/err.h>
18#include <linux/export.h>
19#include <linux/slab.h>
20#include <asm/io.h>
21#include <asm/paravirt.h>
22#include <asm/lguest_hcall.h>
23
24
25static void *lguest_devices;
26
27
28
29
30
31static inline void *lguest_map(unsigned long phys_addr, unsigned long pages)
32{
33 return (__force void *)ioremap_cache(phys_addr, PAGE_SIZE*pages);
34}
35
36static inline void lguest_unmap(void *addr)
37{
38 iounmap((__force void __iomem *)addr);
39}
40
41
42
43
44
45struct lguest_device {
46 struct virtio_device vdev;
47
48
49 struct lguest_device_desc *desc;
50};
51
52
53
54
55
56
57#define to_lgdev(vd) container_of(vd, struct lguest_device, vdev)
58
59
60
61
62
63
64
65
66
67
68
69
70static struct lguest_vqconfig *lg_vq(const struct lguest_device_desc *desc)
71{
72 return (void *)(desc + 1);
73}
74
75
76static u8 *lg_features(const struct lguest_device_desc *desc)
77{
78 return (void *)(lg_vq(desc) + desc->num_vq);
79}
80
81
82static u8 *lg_config(const struct lguest_device_desc *desc)
83{
84 return lg_features(desc) + desc->feature_len * 2;
85}
86
87
88static unsigned desc_size(const struct lguest_device_desc *desc)
89{
90 return sizeof(*desc)
91 + desc->num_vq * sizeof(struct lguest_vqconfig)
92 + desc->feature_len * 2
93 + desc->config_len;
94}
95
96
97static u32 lg_get_features(struct virtio_device *vdev)
98{
99 unsigned int i;
100 u32 features = 0;
101 struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
102 u8 *in_features = lg_features(desc);
103
104
105 for (i = 0; i < min(desc->feature_len * 8, 32); i++)
106 if (in_features[i / 8] & (1 << (i % 8)))
107 features |= (1 << i);
108
109 return features;
110}
111
112
113
114
115
116static void status_notify(struct virtio_device *vdev)
117{
118 unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
119
120 hcall(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset, 0, 0, 0);
121}
122
123
124
125
126
127
128
129static void lg_finalize_features(struct virtio_device *vdev)
130{
131 unsigned int i, bits;
132 struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
133
134 u8 *out_features = lg_features(desc) + desc->feature_len;
135
136
137 vring_transport_features(vdev);
138
139
140
141
142
143
144 memset(out_features, 0, desc->feature_len);
145 bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
146 for (i = 0; i < bits; i++) {
147 if (test_bit(i, vdev->features))
148 out_features[i / 8] |= (1 << (i % 8));
149 }
150
151
152 status_notify(vdev);
153}
154
155
156static void lg_get(struct virtio_device *vdev, unsigned int offset,
157 void *buf, unsigned len)
158{
159 struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
160
161
162 BUG_ON(offset + len > desc->config_len);
163 memcpy(buf, lg_config(desc) + offset, len);
164}
165
166
167static void lg_set(struct virtio_device *vdev, unsigned int offset,
168 const void *buf, unsigned len)
169{
170 struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
171
172
173 BUG_ON(offset + len > desc->config_len);
174 memcpy(lg_config(desc) + offset, buf, len);
175}
176
177
178
179
180
181static u8 lg_get_status(struct virtio_device *vdev)
182{
183 return to_lgdev(vdev)->desc->status;
184}
185
186static void lg_set_status(struct virtio_device *vdev, u8 status)
187{
188 BUG_ON(!status);
189 to_lgdev(vdev)->desc->status = status;
190
191
192 if (status & VIRTIO_CONFIG_S_FAILED)
193 status_notify(vdev);
194}
195
196static void lg_reset(struct virtio_device *vdev)
197{
198
199 to_lgdev(vdev)->desc->status = 0;
200 status_notify(vdev);
201}
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219struct lguest_vq_info {
220
221 struct lguest_vqconfig config;
222
223
224 void *pages;
225};
226
227
228
229
230
231
232static void lg_notify(struct virtqueue *vq)
233{
234
235
236
237
238 struct lguest_vq_info *lvq = vq->priv;
239
240 hcall(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT, 0, 0, 0);
241}
242
243
244extern int lguest_setup_irq(unsigned int irq);
245
246
247
248
249
250
251
252
253
254
255
256static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
257 unsigned index,
258 void (*callback)(struct virtqueue *vq),
259 const char *name)
260{
261 struct lguest_device *ldev = to_lgdev(vdev);
262 struct lguest_vq_info *lvq;
263 struct virtqueue *vq;
264 int err;
265
266
267 if (index >= ldev->desc->num_vq)
268 return ERR_PTR(-ENOENT);
269
270 lvq = kmalloc(sizeof(*lvq), GFP_KERNEL);
271 if (!lvq)
272 return ERR_PTR(-ENOMEM);
273
274
275
276
277
278
279 memcpy(&lvq->config, lg_vq(ldev->desc)+index, sizeof(lvq->config));
280
281 printk("Mapping virtqueue %i addr %lx\n", index,
282 (unsigned long)lvq->config.pfn << PAGE_SHIFT);
283
284 lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT,
285 DIV_ROUND_UP(vring_size(lvq->config.num,
286 LGUEST_VRING_ALIGN),
287 PAGE_SIZE));
288 if (!lvq->pages) {
289 err = -ENOMEM;
290 goto free_lvq;
291 }
292
293
294
295
296
297
298
299 vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN, vdev,
300 true, lvq->pages, lg_notify, callback, name);
301 if (!vq) {
302 err = -ENOMEM;
303 goto unmap;
304 }
305
306
307 err = lguest_setup_irq(lvq->config.irq);
308 if (err)
309 goto destroy_vring;
310
311
312
313
314
315
316
317
318
319 err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED,
320 dev_name(&vdev->dev), vq);
321 if (err)
322 goto free_desc;
323
324
325
326
327
328 vq->priv = lvq;
329 return vq;
330
331free_desc:
332 irq_free_desc(lvq->config.irq);
333destroy_vring:
334 vring_del_virtqueue(vq);
335unmap:
336 lguest_unmap(lvq->pages);
337free_lvq:
338 kfree(lvq);
339 return ERR_PTR(err);
340}
341
342
343
344static void lg_del_vq(struct virtqueue *vq)
345{
346 struct lguest_vq_info *lvq = vq->priv;
347
348
349 free_irq(lvq->config.irq, vq);
350
351 vring_del_virtqueue(vq);
352
353 lguest_unmap(lvq->pages);
354
355 kfree(lvq);
356}
357
358static void lg_del_vqs(struct virtio_device *vdev)
359{
360 struct virtqueue *vq, *n;
361
362 list_for_each_entry_safe(vq, n, &vdev->vqs, list)
363 lg_del_vq(vq);
364}
365
366static int lg_find_vqs(struct virtio_device *vdev, unsigned nvqs,
367 struct virtqueue *vqs[],
368 vq_callback_t *callbacks[],
369 const char *names[])
370{
371 struct lguest_device *ldev = to_lgdev(vdev);
372 int i;
373
374
375 if (nvqs > ldev->desc->num_vq)
376 return -ENOENT;
377
378 for (i = 0; i < nvqs; ++i) {
379 vqs[i] = lg_find_vq(vdev, i, callbacks[i], names[i]);
380 if (IS_ERR(vqs[i]))
381 goto error;
382 }
383 return 0;
384
385error:
386 lg_del_vqs(vdev);
387 return PTR_ERR(vqs[i]);
388}
389
390static const char *lg_bus_name(struct virtio_device *vdev)
391{
392 return "";
393}
394
395
396static struct virtio_config_ops lguest_config_ops = {
397 .get_features = lg_get_features,
398 .finalize_features = lg_finalize_features,
399 .get = lg_get,
400 .set = lg_set,
401 .get_status = lg_get_status,
402 .set_status = lg_set_status,
403 .reset = lg_reset,
404 .find_vqs = lg_find_vqs,
405 .del_vqs = lg_del_vqs,
406 .bus_name = lg_bus_name,
407};
408
409
410
411
412
413static struct device *lguest_root;
414
415
416
417
418
419
420
421
422
423
424
425
426
427static void add_lguest_device(struct lguest_device_desc *d,
428 unsigned int offset)
429{
430 struct lguest_device *ldev;
431
432
433 ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
434 if (!ldev) {
435 printk(KERN_EMERG "Cannot allocate lguest dev %u type %u\n",
436 offset, d->type);
437 return;
438 }
439
440
441 ldev->vdev.dev.parent = lguest_root;
442
443
444
445
446
447 ldev->vdev.id.device = d->type;
448
449
450
451
452 ldev->vdev.config = &lguest_config_ops;
453
454 ldev->desc = d;
455
456
457
458
459
460
461 if (register_virtio_device(&ldev->vdev) != 0) {
462 printk(KERN_ERR "Failed to register lguest dev %u type %u\n",
463 offset, d->type);
464 kfree(ldev);
465 }
466}
467
468
469
470
471
472static void scan_devices(void)
473{
474 unsigned int i;
475 struct lguest_device_desc *d;
476
477
478 for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
479 d = lguest_devices + i;
480
481
482 if (d->type == 0)
483 break;
484
485 printk("Device at %i has size %u\n", i, desc_size(d));
486 add_lguest_device(d, i);
487 }
488}
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504static int __init lguest_devices_init(void)
505{
506 if (strcmp(pv_info.name, "lguest") != 0)
507 return 0;
508
509 lguest_root = root_device_register("lguest");
510 if (IS_ERR(lguest_root))
511 panic("Could not register lguest root");
512
513
514 lguest_devices = lguest_map(max_pfn<<PAGE_SHIFT, 1);
515
516 scan_devices();
517 return 0;
518}
519
520postcore_initcall(lguest_devices_init);
521
522
523
524
525
526
527
528
529
530
531
532