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 if (!name)
267 return NULL;
268
269
270 if (index >= ldev->desc->num_vq)
271 return ERR_PTR(-ENOENT);
272
273 lvq = kmalloc(sizeof(*lvq), GFP_KERNEL);
274 if (!lvq)
275 return ERR_PTR(-ENOMEM);
276
277
278
279
280
281
282 memcpy(&lvq->config, lg_vq(ldev->desc)+index, sizeof(lvq->config));
283
284 printk("Mapping virtqueue %i addr %lx\n", index,
285 (unsigned long)lvq->config.pfn << PAGE_SHIFT);
286
287 lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT,
288 DIV_ROUND_UP(vring_size(lvq->config.num,
289 LGUEST_VRING_ALIGN),
290 PAGE_SIZE));
291 if (!lvq->pages) {
292 err = -ENOMEM;
293 goto free_lvq;
294 }
295
296
297
298
299
300
301
302 vq = vring_new_virtqueue(index, lvq->config.num, LGUEST_VRING_ALIGN, vdev,
303 true, lvq->pages, lg_notify, callback, name);
304 if (!vq) {
305 err = -ENOMEM;
306 goto unmap;
307 }
308
309
310 err = lguest_setup_irq(lvq->config.irq);
311 if (err)
312 goto destroy_vring;
313
314
315
316
317
318
319
320
321
322 err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED,
323 dev_name(&vdev->dev), vq);
324 if (err)
325 goto free_desc;
326
327
328
329
330
331 vq->priv = lvq;
332 return vq;
333
334free_desc:
335 irq_free_desc(lvq->config.irq);
336destroy_vring:
337 vring_del_virtqueue(vq);
338unmap:
339 lguest_unmap(lvq->pages);
340free_lvq:
341 kfree(lvq);
342 return ERR_PTR(err);
343}
344
345
346
347static void lg_del_vq(struct virtqueue *vq)
348{
349 struct lguest_vq_info *lvq = vq->priv;
350
351
352 free_irq(lvq->config.irq, vq);
353
354 vring_del_virtqueue(vq);
355
356 lguest_unmap(lvq->pages);
357
358 kfree(lvq);
359}
360
361static void lg_del_vqs(struct virtio_device *vdev)
362{
363 struct virtqueue *vq, *n;
364
365 list_for_each_entry_safe(vq, n, &vdev->vqs, list)
366 lg_del_vq(vq);
367}
368
369static int lg_find_vqs(struct virtio_device *vdev, unsigned nvqs,
370 struct virtqueue *vqs[],
371 vq_callback_t *callbacks[],
372 const char *names[])
373{
374 struct lguest_device *ldev = to_lgdev(vdev);
375 int i;
376
377
378 if (nvqs > ldev->desc->num_vq)
379 return -ENOENT;
380
381 for (i = 0; i < nvqs; ++i) {
382 vqs[i] = lg_find_vq(vdev, i, callbacks[i], names[i]);
383 if (IS_ERR(vqs[i]))
384 goto error;
385 }
386 return 0;
387
388error:
389 lg_del_vqs(vdev);
390 return PTR_ERR(vqs[i]);
391}
392
393static const char *lg_bus_name(struct virtio_device *vdev)
394{
395 return "";
396}
397
398
399static const struct virtio_config_ops lguest_config_ops = {
400 .get_features = lg_get_features,
401 .finalize_features = lg_finalize_features,
402 .get = lg_get,
403 .set = lg_set,
404 .get_status = lg_get_status,
405 .set_status = lg_set_status,
406 .reset = lg_reset,
407 .find_vqs = lg_find_vqs,
408 .del_vqs = lg_del_vqs,
409 .bus_name = lg_bus_name,
410};
411
412
413
414
415
416static struct device *lguest_root;
417
418
419
420
421
422
423
424
425
426
427
428
429
430static void add_lguest_device(struct lguest_device_desc *d,
431 unsigned int offset)
432{
433 struct lguest_device *ldev;
434
435
436 ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
437 if (!ldev) {
438 printk(KERN_EMERG "Cannot allocate lguest dev %u type %u\n",
439 offset, d->type);
440 return;
441 }
442
443
444 ldev->vdev.dev.parent = lguest_root;
445
446
447
448
449
450 ldev->vdev.id.device = d->type;
451
452
453
454
455 ldev->vdev.config = &lguest_config_ops;
456
457 ldev->desc = d;
458
459
460
461
462
463
464 if (register_virtio_device(&ldev->vdev) != 0) {
465 printk(KERN_ERR "Failed to register lguest dev %u type %u\n",
466 offset, d->type);
467 kfree(ldev);
468 }
469}
470
471
472
473
474
475static void scan_devices(void)
476{
477 unsigned int i;
478 struct lguest_device_desc *d;
479
480
481 for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
482 d = lguest_devices + i;
483
484
485 if (d->type == 0)
486 break;
487
488 printk("Device at %i has size %u\n", i, desc_size(d));
489 add_lguest_device(d, i);
490 }
491}
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507static int __init lguest_devices_init(void)
508{
509 if (strcmp(pv_info.name, "lguest") != 0)
510 return 0;
511
512 lguest_root = root_device_register("lguest");
513 if (IS_ERR(lguest_root))
514 panic("Could not register lguest root");
515
516
517 lguest_devices = lguest_map(max_pfn<<PAGE_SHIFT, 1);
518
519 scan_devices();
520 return 0;
521}
522
523postcore_initcall(lguest_devices_init);
524
525
526
527
528
529
530
531
532
533
534
535