Blame view
drivers/lguest/lguest_device.c
15.6 KB
2e04ef769 lguest: fix comme... |
1 2 |
/*P:050 * Lguest guests use a very simple method to describe devices. It's a |
a6bd8e130 lguest: comment d... |
3 |
* series of device descriptors contained just above the top of normal Guest |
19f1537b7 Lguest support fo... |
4 5 6 7 |
* memory. * * We use the standard "virtio" device infrastructure, which provides us with a * console, a network and a block driver. Each one expects some configuration |
2e04ef769 lguest: fix comme... |
8 9 |
* information and a "virtqueue" or two to send and receive data. :*/ |
19f1537b7 Lguest support fo... |
10 11 12 13 14 15 16 17 |
#include <linux/init.h> #include <linux/bootmem.h> #include <linux/lguest_launcher.h> #include <linux/virtio.h> #include <linux/virtio_config.h> #include <linux/interrupt.h> #include <linux/virtio_ring.h> #include <linux/err.h> |
39a0e33da lguest: add expor... |
18 |
#include <linux/export.h> |
5a0e3ad6a include cleanup: ... |
19 |
#include <linux/slab.h> |
19f1537b7 Lguest support fo... |
20 21 22 23 24 25 |
#include <asm/io.h> #include <asm/paravirt.h> #include <asm/lguest_hcall.h> /* The pointer to our (page) of device descriptions. */ static void *lguest_devices; |
2e04ef769 lguest: fix comme... |
26 27 28 29 |
/* * For Guests, device memory can be used as normal memory, so we cast away the * __iomem to quieten sparse. */ |
19f1537b7 Lguest support fo... |
30 31 |
static inline void *lguest_map(unsigned long phys_addr, unsigned long pages) { |
e27810f11 lguest: use iorem... |
32 |
return (__force void *)ioremap_cache(phys_addr, PAGE_SIZE*pages); |
19f1537b7 Lguest support fo... |
33 34 35 36 37 38 |
} static inline void lguest_unmap(void *addr) { iounmap((__force void __iomem *)addr); } |
2e04ef769 lguest: fix comme... |
39 40 41 42 |
/*D:100 * Each lguest device is just a virtio device plus a pointer to its entry * in the lguest_devices page. */ |
19f1537b7 Lguest support fo... |
43 44 45 46 47 48 |
struct lguest_device { struct virtio_device vdev; /* The entry in the lguest_devices page for this device. */ struct lguest_device_desc *desc; }; |
2e04ef769 lguest: fix comme... |
49 50 |
/* * Since the virtio infrastructure hands us a pointer to the virtio_device all |
19f1537b7 Lguest support fo... |
51 |
* the time, it helps to have a curt macro to get a pointer to the struct |
2e04ef769 lguest: fix comme... |
52 53 |
* lguest_device it's enclosed in. */ |
25478445c Fix container_of(... |
54 |
#define to_lgdev(vd) container_of(vd, struct lguest_device, vdev) |
19f1537b7 Lguest support fo... |
55 56 57 58 |
/*D:130 * Device configurations * |
a586d4f60 virtio: simplify ... |
59 |
* The configuration information for a device consists of one or more |
a6bd8e130 lguest: comment d... |
60 |
* virtqueues, a feature bitmap, and some configuration bytes. The |
6e5aa7efb virtio: reset fun... |
61 |
* configuration bytes don't really matter to us: the Launcher sets them up, and |
a586d4f60 virtio: simplify ... |
62 |
* the driver will look at them during setup. |
19f1537b7 Lguest support fo... |
63 |
* |
a586d4f60 virtio: simplify ... |
64 |
* A convenient routine to return the device's virtqueue config array: |
2e04ef769 lguest: fix comme... |
65 66 |
* immediately after the descriptor. */ |
a586d4f60 virtio: simplify ... |
67 68 69 70 |
static struct lguest_vqconfig *lg_vq(const struct lguest_device_desc *desc) { return (void *)(desc + 1); } |
19f1537b7 Lguest support fo... |
71 |
|
a586d4f60 virtio: simplify ... |
72 73 74 75 76 |
/* The features come immediately after the virtqueues. */ static u8 *lg_features(const struct lguest_device_desc *desc) { return (void *)(lg_vq(desc) + desc->num_vq); } |
19f1537b7 Lguest support fo... |
77 |
|
a586d4f60 virtio: simplify ... |
78 79 |
/* The config space comes after the two feature bitmasks. */ static u8 *lg_config(const struct lguest_device_desc *desc) |
19f1537b7 Lguest support fo... |
80 |
{ |
a586d4f60 virtio: simplify ... |
81 82 |
return lg_features(desc) + desc->feature_len * 2; } |
19f1537b7 Lguest support fo... |
83 |
|
a586d4f60 virtio: simplify ... |
84 85 86 87 88 89 90 91 |
/* The total size of the config page used by this device (incl. desc) */ static unsigned desc_size(const struct lguest_device_desc *desc) { return sizeof(*desc) + desc->num_vq * sizeof(struct lguest_vqconfig) + desc->feature_len * 2 + desc->config_len; } |
c45a6816c virtio: explicit ... |
92 93 |
/* This gets the device's feature bits. */ static u32 lg_get_features(struct virtio_device *vdev) |
a586d4f60 virtio: simplify ... |
94 |
{ |
c45a6816c virtio: explicit ... |
95 96 |
unsigned int i; u32 features = 0; |
a586d4f60 virtio: simplify ... |
97 |
struct lguest_device_desc *desc = to_lgdev(vdev)->desc; |
c45a6816c virtio: explicit ... |
98 99 100 101 102 103 104 105 106 |
u8 *in_features = lg_features(desc); /* We do this the slow but generic way. */ for (i = 0; i < min(desc->feature_len * 8, 32); i++) if (in_features[i / 8] & (1 << (i % 8))) features |= (1 << i); return features; } |
2e04ef769 lguest: fix comme... |
107 |
/* |
3c3ed482d lguest: Simplify ... |
108 109 110 111 112 113 114 115 116 117 118 |
* To notify on reset or feature finalization, we (ab)use the NOTIFY * hypercall, with the descriptor address of the device. */ static void status_notify(struct virtio_device *vdev) { unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices; hcall(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset, 0, 0, 0); } /* |
2e04ef769 lguest: fix comme... |
119 120 121 122 123 |
* The virtio core takes the features the Host offers, and copies the ones * supported by the driver into the vdev->features array. Once that's all * sorted out, this routine is called so we can tell the Host which features we * understand and accept. */ |
c624896e4 virtio: Rename se... |
124 |
static void lg_finalize_features(struct virtio_device *vdev) |
c45a6816c virtio: explicit ... |
125 |
{ |
c624896e4 virtio: Rename se... |
126 |
unsigned int i, bits; |
c45a6816c virtio: explicit ... |
127 128 129 |
struct lguest_device_desc *desc = to_lgdev(vdev)->desc; /* Second half of bitmap is features we accept. */ u8 *out_features = lg_features(desc) + desc->feature_len; |
e34f87256 virtio: Add trans... |
130 131 |
/* Give virtio_ring a chance to accept features. */ vring_transport_features(vdev); |
2e04ef769 lguest: fix comme... |
132 133 134 135 136 |
/* * The vdev->feature array is a Linux bitmask: this isn't the same as a * the simple array of bits used by lguest devices for features. So we * do this slow, manual conversion which is completely general. */ |
c45a6816c virtio: explicit ... |
137 |
memset(out_features, 0, desc->feature_len); |
c624896e4 virtio: Rename se... |
138 139 140 |
bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8; for (i = 0; i < bits; i++) { if (test_bit(i, vdev->features)) |
c45a6816c virtio: explicit ... |
141 142 |
out_features[i / 8] |= (1 << (i % 8)); } |
3c3ed482d lguest: Simplify ... |
143 144 145 |
/* Tell Host we've finished with this device's feature negotiation */ status_notify(vdev); |
19f1537b7 Lguest support fo... |
146 147 148 |
} /* Once they've found a field, getting a copy of it is easy. */ |
a586d4f60 virtio: simplify ... |
149 |
static void lg_get(struct virtio_device *vdev, unsigned int offset, |
19f1537b7 Lguest support fo... |
150 151 |
void *buf, unsigned len) { |
a586d4f60 virtio: simplify ... |
152 153 154 155 156 |
struct lguest_device_desc *desc = to_lgdev(vdev)->desc; /* Check they didn't ask for more than the length of the config! */ BUG_ON(offset + len > desc->config_len); memcpy(buf, lg_config(desc) + offset, len); |
19f1537b7 Lguest support fo... |
157 158 159 |
} /* Setting the contents is also trivial. */ |
a586d4f60 virtio: simplify ... |
160 |
static void lg_set(struct virtio_device *vdev, unsigned int offset, |
19f1537b7 Lguest support fo... |
161 162 |
const void *buf, unsigned len) { |
a586d4f60 virtio: simplify ... |
163 164 165 166 167 |
struct lguest_device_desc *desc = to_lgdev(vdev)->desc; /* Check they didn't ask for more than the length of the config! */ BUG_ON(offset + len > desc->config_len); memcpy(lg_config(desc) + offset, buf, len); |
19f1537b7 Lguest support fo... |
168 |
} |
2e04ef769 lguest: fix comme... |
169 170 171 172 |
/* * The operations to get and set the status word just access the status field * of the device descriptor. */ |
19f1537b7 Lguest support fo... |
173 174 175 176 177 178 179 |
static u8 lg_get_status(struct virtio_device *vdev) { return to_lgdev(vdev)->desc->status; } static void lg_set_status(struct virtio_device *vdev, u8 status) { |
6e5aa7efb virtio: reset fun... |
180 |
BUG_ON(!status); |
3c3ed482d lguest: Simplify ... |
181 182 183 184 185 |
to_lgdev(vdev)->desc->status = status; /* Tell Host immediately if we failed. */ if (status & VIRTIO_CONFIG_S_FAILED) status_notify(vdev); |
19f1537b7 Lguest support fo... |
186 |
} |
6e5aa7efb virtio: reset fun... |
187 188 |
static void lg_reset(struct virtio_device *vdev) { |
3c3ed482d lguest: Simplify ... |
189 190 191 |
/* 0 status means "reset" */ to_lgdev(vdev)->desc->status = 0; status_notify(vdev); |
6e5aa7efb virtio: reset fun... |
192 |
} |
19f1537b7 Lguest support fo... |
193 194 195 196 197 198 |
/* * Virtqueues * * The other piece of infrastructure virtio needs is a "virtqueue": a way of * the Guest device registering buffers for the other side to read from or * write into (ie. send and receive buffers). Each device can have multiple |
e1e72965e lguest: documenta... |
199 200 |
* virtqueues: for example the console driver uses one queue for sending and * another for receiving. |
19f1537b7 Lguest support fo... |
201 202 203 204 205 206 207 208 |
* * Fortunately for us, a very fast shared-memory-plus-descriptors virtqueue * already exists in virtio_ring.c. We just need to connect it up. * * We start with the information we need to keep about each virtqueue. */ /*D:140 This is the information we remember about each virtqueue. */ |
1842f23c0 lguest and virtio... |
209 |
struct lguest_vq_info { |
19f1537b7 Lguest support fo... |
210 211 212 213 214 215 |
/* A copy of the information contained in the device config. */ struct lguest_vqconfig config; /* The address where we mapped the virtio ring, so we can unmap it. */ void *pages; }; |
2e04ef769 lguest: fix comme... |
216 217 |
/* * When the virtio_ring code wants to prod the Host, it calls us here and we |
a6bd8e130 lguest: comment d... |
218 |
* make a hypercall. We hand the physical address of the virtqueue so the Host |
2e04ef769 lguest: fix comme... |
219 220 |
* knows which virtqueue we're talking about. */ |
19f1537b7 Lguest support fo... |
221 222 |
static void lg_notify(struct virtqueue *vq) { |
2e04ef769 lguest: fix comme... |
223 224 225 226 |
/* * We store our virtqueue information in the "priv" pointer of the * virtqueue structure. */ |
19f1537b7 Lguest support fo... |
227 |
struct lguest_vq_info *lvq = vq->priv; |
091ebf07a lguest: stop usin... |
228 |
hcall(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT, 0, 0, 0); |
19f1537b7 Lguest support fo... |
229 |
} |
6db6a5f3a lguest: fix for C... |
230 |
/* An extern declaration inside a C file is bad form. Don't do it. */ |
b6c96c021 lguest: Make sure... |
231 |
extern int lguest_setup_irq(unsigned int irq); |
6db6a5f3a lguest: fix for C... |
232 |
|
2e04ef769 lguest: fix comme... |
233 |
/* |
a91d74a3c lguest: update co... |
234 |
* This routine finds the Nth virtqueue described in the configuration of |
19f1537b7 Lguest support fo... |
235 236 237 238 |
* this device and sets it up. * * This is kind of an ugly duckling. It'd be nicer to have a standard * representation of a virtqueue in the configuration space, but it seems that |
e1e72965e lguest: documenta... |
239 |
* everyone wants to do it differently. The KVM coders want the Guest to |
19f1537b7 Lguest support fo... |
240 241 |
* allocate its own pages and tell the Host where they are, but for lguest it's * simpler for the Host to simply tell us where the pages are. |
2e04ef769 lguest: fix comme... |
242 |
*/ |
19f1537b7 Lguest support fo... |
243 |
static struct virtqueue *lg_find_vq(struct virtio_device *vdev, |
a586d4f60 virtio: simplify ... |
244 |
unsigned index, |
9499f5e7e virtio: add names... |
245 246 |
void (*callback)(struct virtqueue *vq), const char *name) |
19f1537b7 Lguest support fo... |
247 |
{ |
a586d4f60 virtio: simplify ... |
248 |
struct lguest_device *ldev = to_lgdev(vdev); |
19f1537b7 Lguest support fo... |
249 250 |
struct lguest_vq_info *lvq; struct virtqueue *vq; |
19f1537b7 Lguest support fo... |
251 |
int err; |
a586d4f60 virtio: simplify ... |
252 253 |
/* We must have this many virtqueues. */ if (index >= ldev->desc->num_vq) |
19f1537b7 Lguest support fo... |
254 255 256 257 258 |
return ERR_PTR(-ENOENT); lvq = kmalloc(sizeof(*lvq), GFP_KERNEL); if (!lvq) return ERR_PTR(-ENOMEM); |
2e04ef769 lguest: fix comme... |
259 260 |
/* * Make a copy of the "struct lguest_vqconfig" entry, which sits after |
a586d4f60 virtio: simplify ... |
261 |
* the descriptor. We need a copy because the config space might not |
2e04ef769 lguest: fix comme... |
262 263 |
* be aligned correctly. */ |
a586d4f60 virtio: simplify ... |
264 |
memcpy(&lvq->config, lg_vq(ldev->desc)+index, sizeof(lvq->config)); |
19f1537b7 Lguest support fo... |
265 |
|
a586d4f60 virtio: simplify ... |
266 267 268 |
printk("Mapping virtqueue %i addr %lx ", index, (unsigned long)lvq->config.pfn << PAGE_SHIFT); |
19f1537b7 Lguest support fo... |
269 270 |
/* Figure out how many pages the ring will take, and map that memory */ lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT, |
42b36cc0c virtio: Force use... |
271 |
DIV_ROUND_UP(vring_size(lvq->config.num, |
2966af73e virtio: use LGUES... |
272 |
LGUEST_VRING_ALIGN), |
19f1537b7 Lguest support fo... |
273 274 275 276 277 |
PAGE_SIZE)); if (!lvq->pages) { err = -ENOMEM; goto free_lvq; } |
2e04ef769 lguest: fix comme... |
278 279 |
/* * OK, tell virtio_ring.c to set up a virtqueue now we know its size |
7b21e34fd virtio: harsher b... |
280 281 282 |
* and we've got a pointer to its pages. Note that we set weak_barriers * to 'true': the host just a(nother) SMP CPU, so we only need inter-cpu * barriers. |
2e04ef769 lguest: fix comme... |
283 |
*/ |
7b21e34fd virtio: harsher b... |
284 285 |
vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN, vdev, true, lvq->pages, lg_notify, callback, name); |
19f1537b7 Lguest support fo... |
286 287 288 289 |
if (!vq) { err = -ENOMEM; goto unmap; } |
6db6a5f3a lguest: fix for C... |
290 |
/* Make sure the interrupt is allocated. */ |
b6c96c021 lguest: Make sure... |
291 292 293 |
err = lguest_setup_irq(lvq->config.irq); if (err) goto destroy_vring; |
6db6a5f3a lguest: fix for C... |
294 |
|
2e04ef769 lguest: fix comme... |
295 296 297 298 299 |
/* * Tell the interrupt for this virtqueue to go to the virtio_ring * interrupt handler. * * FIXME: We used to have a flag for the Host to tell us we could use |
19f1537b7 Lguest support fo... |
300 |
* the interrupt as a source of randomness: it'd be nice to have that |
2e04ef769 lguest: fix comme... |
301 302 |
* back. */ |
19f1537b7 Lguest support fo... |
303 |
err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED, |
bda53cd51 lguest: struct de... |
304 |
dev_name(&vdev->dev), vq); |
19f1537b7 Lguest support fo... |
305 |
if (err) |
b6c96c021 lguest: Make sure... |
306 |
goto free_desc; |
19f1537b7 Lguest support fo... |
307 |
|
2e04ef769 lguest: fix comme... |
308 309 310 311 |
/* * Last of all we hook up our 'struct lguest_vq_info" to the * virtqueue's priv pointer. */ |
19f1537b7 Lguest support fo... |
312 313 |
vq->priv = lvq; return vq; |
b6c96c021 lguest: Make sure... |
314 315 |
free_desc: irq_free_desc(lvq->config.irq); |
19f1537b7 Lguest support fo... |
316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
destroy_vring: vring_del_virtqueue(vq); unmap: lguest_unmap(lvq->pages); free_lvq: kfree(lvq); return ERR_PTR(err); } /*:*/ /* Cleaning up a virtqueue is easy */ static void lg_del_vq(struct virtqueue *vq) { struct lguest_vq_info *lvq = vq->priv; |
74b2553f1 virtio: fix modul... |
330 331 |
/* Release the interrupt */ free_irq(lvq->config.irq, vq); |
19f1537b7 Lguest support fo... |
332 333 334 335 336 337 338 |
/* Tell virtio_ring.c to free the virtqueue. */ vring_del_virtqueue(vq); /* Unmap the pages containing the ring. */ lguest_unmap(lvq->pages); /* Free our own queue information. */ kfree(lvq); } |
d2a7ddda9 virtio: find_vqs/... |
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 |
static void lg_del_vqs(struct virtio_device *vdev) { struct virtqueue *vq, *n; list_for_each_entry_safe(vq, n, &vdev->vqs, list) lg_del_vq(vq); } static int lg_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], const char *names[]) { struct lguest_device *ldev = to_lgdev(vdev); int i; /* We must have this many virtqueues. */ if (nvqs > ldev->desc->num_vq) return -ENOENT; for (i = 0; i < nvqs; ++i) { vqs[i] = lg_find_vq(vdev, i, callbacks[i], names[i]); if (IS_ERR(vqs[i])) goto error; } return 0; error: lg_del_vqs(vdev); return PTR_ERR(vqs[i]); } |
66846048f enable virtio_net... |
370 371 372 373 |
static const char *lg_bus_name(struct virtio_device *vdev) { return ""; } |
19f1537b7 Lguest support fo... |
374 375 |
/* The ops structure which hooks everything together. */ static struct virtio_config_ops lguest_config_ops = { |
c45a6816c virtio: explicit ... |
376 |
.get_features = lg_get_features, |
c624896e4 virtio: Rename se... |
377 |
.finalize_features = lg_finalize_features, |
19f1537b7 Lguest support fo... |
378 379 380 381 |
.get = lg_get, .set = lg_set, .get_status = lg_get_status, .set_status = lg_set_status, |
6e5aa7efb virtio: reset fun... |
382 |
.reset = lg_reset, |
d2a7ddda9 virtio: find_vqs/... |
383 384 |
.find_vqs = lg_find_vqs, .del_vqs = lg_del_vqs, |
66846048f enable virtio_net... |
385 |
.bus_name = lg_bus_name, |
19f1537b7 Lguest support fo... |
386 |
}; |
2e04ef769 lguest: fix comme... |
387 388 389 390 |
/* * The root device for the lguest virtio devices. This makes them appear as * /sys/devices/lguest/0,1,2 not /sys/devices/0,1,2. */ |
ff8561c4a lguest: do not st... |
391 |
static struct device *lguest_root; |
19f1537b7 Lguest support fo... |
392 |
|
2e04ef769 lguest: fix comme... |
393 394 |
/*D:120 * This is the core of the lguest bus: actually adding a new device. |
19f1537b7 Lguest support fo... |
395 396 397 398 399 400 401 |
* It's a separate function because it's neater that way, and because an * earlier version of the code supported hotplug and unplug. They were removed * early on because they were never used. * * As Andrew Tridgell says, "Untested code is buggy code". * * It's worth reading this carefully: we start with a pointer to the new device |
b769f5790 virtio: set devic... |
402 |
* descriptor in the "lguest_devices" page, and the offset into the device |
2e04ef769 lguest: fix comme... |
403 404 |
* descriptor page so we can uniquely identify it if things go badly wrong. */ |
b769f5790 virtio: set devic... |
405 406 |
static void add_lguest_device(struct lguest_device_desc *d, unsigned int offset) |
19f1537b7 Lguest support fo... |
407 408 |
{ struct lguest_device *ldev; |
2e04ef769 lguest: fix comme... |
409 |
/* Start with zeroed memory; Linux's device layer counts on it. */ |
19f1537b7 Lguest support fo... |
410 411 |
ldev = kzalloc(sizeof(*ldev), GFP_KERNEL); if (!ldev) { |
b769f5790 virtio: set devic... |
412 413 414 |
printk(KERN_EMERG "Cannot allocate lguest dev %u type %u ", offset, d->type); |
19f1537b7 Lguest support fo... |
415 416 417 418 |
return; } /* This devices' parent is the lguest/ dir. */ |
ff8561c4a lguest: do not st... |
419 |
ldev->vdev.dev.parent = lguest_root; |
a91d74a3c lguest: update co... |
420 421 422 423 424 |
/* * The device type comes straight from the descriptor. There's also a * device vendor field in the virtio_device struct, which we leave as * 0. */ |
19f1537b7 Lguest support fo... |
425 |
ldev->vdev.id.device = d->type; |
2e04ef769 lguest: fix comme... |
426 427 428 429 |
/* * We have a simple set of routines for querying the device's * configuration information and setting its status. */ |
19f1537b7 Lguest support fo... |
430 431 432 |
ldev->vdev.config = &lguest_config_ops; /* And we remember the device's descriptor for lguest_config_ops. */ ldev->desc = d; |
2e04ef769 lguest: fix comme... |
433 434 |
/* * register_virtio_device() sets up the generic fields for the struct |
19f1537b7 Lguest support fo... |
435 |
* virtio_device and calls device_register(). This makes the bus |
2e04ef769 lguest: fix comme... |
436 437 |
* infrastructure look for a matching driver. */ |
19f1537b7 Lguest support fo... |
438 |
if (register_virtio_device(&ldev->vdev) != 0) { |
b769f5790 virtio: set devic... |
439 440 441 |
printk(KERN_ERR "Failed to register lguest dev %u type %u ", offset, d->type); |
19f1537b7 Lguest support fo... |
442 443 444 |
kfree(ldev); } } |
2e04ef769 lguest: fix comme... |
445 446 447 448 |
/*D:110 * scan_devices() simply iterates through the device page. The type 0 is * reserved to mean "end of devices". */ |
19f1537b7 Lguest support fo... |
449 450 451 452 453 454 |
static void scan_devices(void) { unsigned int i; struct lguest_device_desc *d; /* We start at the page beginning, and skip over each entry. */ |
a586d4f60 virtio: simplify ... |
455 |
for (i = 0; i < PAGE_SIZE; i += desc_size(d)) { |
19f1537b7 Lguest support fo... |
456 457 458 459 460 |
d = lguest_devices + i; /* Once we hit a zero, stop. */ if (d->type == 0) break; |
a586d4f60 virtio: simplify ... |
461 462 |
printk("Device at %i has size %u ", i, desc_size(d)); |
b769f5790 virtio: set devic... |
463 |
add_lguest_device(d, i); |
19f1537b7 Lguest support fo... |
464 465 |
} } |
2e04ef769 lguest: fix comme... |
466 467 |
/*D:105 * Fairly early in boot, lguest_devices_init() is called to set up the |
19f1537b7 Lguest support fo... |
468 469 470 471 472 473 474 475 476 477 |
* lguest device infrastructure. We check that we are a Guest by checking * pv_info.name: there are other ways of checking, but this seems most * obvious to me. * * So we can access the "struct lguest_device_desc"s easily, we map that memory * and store the pointer in the global "lguest_devices". Then we register a * root device from which all our devices will hang (this seems to be the * correct sysfs incantation). * * Finally we call scan_devices() which adds all the devices found in the |
2e04ef769 lguest: fix comme... |
478 479 |
* lguest_devices page. */ |
19f1537b7 Lguest support fo... |
480 481 482 483 |
static int __init lguest_devices_init(void) { if (strcmp(pv_info.name, "lguest") != 0) return 0; |
ff8561c4a lguest: do not st... |
484 485 |
lguest_root = root_device_register("lguest"); if (IS_ERR(lguest_root)) |
19f1537b7 Lguest support fo... |
486 487 488 489 490 491 492 493 494 495 |
panic("Could not register lguest root"); /* Devices are in a single page above top of "normal" mem */ lguest_devices = lguest_map(max_pfn<<PAGE_SHIFT, 1); scan_devices(); return 0; } /* We do this after core stuff, but before the drivers. */ postcore_initcall(lguest_devices_init); |
2e04ef769 lguest: fix comme... |
496 497 |
/*D:150 * At this point in the journey we used to now wade through the lguest |
19f1537b7 Lguest support fo... |
498 499 500 501 502 503 |
* devices themselves: net, block and console. Since they're all now virtio * devices rather than lguest-specific, I've decided to ignore them. Mostly, * they're kind of boring. But this does mean you'll never experience the * thrill of reading the forbidden love scene buried deep in the block driver. * * "make Launcher" beckons, where we answer questions like "Where do Guests |
2e04ef769 lguest: fix comme... |
504 505 |
* come from?", and "What do you do when someone asks for optimization?". */ |