debuggers.hg

view unmodified_drivers/linux-2.6/platform-pci/platform-pci.c @ 22855:1d1eec7e1fb4

xl: Perform minimal validation of virtual disk file while parsing config file

This patch performs some very basic validation on the virtual disk
file passed through the config file. This validation ensures that we
don't go too far with the initialization like spawn qemu and more
while there could be some potentially fundamental issues.

[ Patch fixed up to work with PHYSTYPE_EMPTY 22808:6ec61438713a -iwj ]

Signed-off-by: Kamala Narasimhan <kamala.narasimhan@citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
Committed-by: Ian Jackson <ian.jackson@eu.citrix.com>
author Kamala Narasimhan <kamala.narasimhan@gmail.com>
date Tue Jan 25 18:09:49 2011 +0000 (2011-01-25)
parents 7bc5e072d986
children
line source
1 /******************************************************************************
2 * platform-pci.c
3 *
4 * Xen platform PCI device driver
5 * Copyright (c) 2005, Intel Corporation.
6 * Copyright (c) 2007, XenSource Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place - Suite 330, Boston, MA 02111-1307 USA.
20 *
21 */
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/sched.h>
26 #include <linux/errno.h>
27 #include <linux/pci.h>
28 #include <linux/init.h>
29 #include <linux/version.h>
30 #include <linux/interrupt.h>
31 #include <linux/vmalloc.h>
32 #include <linux/mm.h>
33 #include <asm/system.h>
34 #include <asm/io.h>
35 #include <asm/irq.h>
36 #include <asm/uaccess.h>
37 #include <asm/hypervisor.h>
38 #include <asm/pgtable.h>
39 #include <xen/interface/memory.h>
40 #include <xen/interface/hvm/params.h>
41 #include <xen/features.h>
42 #include <xen/evtchn.h>
43 #ifdef __ia64__
44 #include <asm/xen/xencomm.h>
45 #endif
47 #include "platform-pci.h"
49 #ifdef HAVE_XEN_PLATFORM_COMPAT_H
50 #include <xen/platform-compat.h>
51 #endif
53 #define DRV_NAME "xen-platform-pci"
54 #define DRV_VERSION "0.10"
55 #define DRV_RELDATE "03/03/2005"
57 static int max_hypercall_stub_pages, nr_hypercall_stub_pages;
58 char *hypercall_stubs;
59 EXPORT_SYMBOL(hypercall_stubs);
61 MODULE_AUTHOR("ssmith@xensource.com");
62 MODULE_DESCRIPTION("Xen platform PCI device");
63 MODULE_LICENSE("GPL");
65 /* NB. [aux-]ide-disks options do not unplug IDE CD-ROM drives. */
66 /* NB. aux-ide-disks is equiv to ide-disks except ignores primary master. */
67 static char *dev_unplug;
68 module_param(dev_unplug, charp, 0644);
69 MODULE_PARM_DESC(dev_unplug, "Emulated devices to unplug: "
70 "[all,][ide-disks,][aux-ide-disks,][nics]\n");
72 struct pci_dev *xen_platform_pdev;
74 static unsigned long shared_info_frame;
75 static uint64_t callback_via;
77 static int __devinit init_xen_info(void)
78 {
79 struct xen_add_to_physmap xatp;
80 extern void *shared_info_area;
82 #ifdef __ia64__
83 xencomm_initialize();
84 #endif
86 setup_xen_features();
88 shared_info_frame = alloc_xen_mmio(PAGE_SIZE) >> PAGE_SHIFT;
89 xatp.domid = DOMID_SELF;
90 xatp.idx = 0;
91 xatp.space = XENMAPSPACE_shared_info;
92 xatp.gpfn = shared_info_frame;
93 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
94 BUG();
96 shared_info_area =
97 ioremap(shared_info_frame << PAGE_SHIFT, PAGE_SIZE);
98 if (shared_info_area == NULL)
99 panic("can't map shared info\n");
101 return 0;
102 }
104 static unsigned long platform_mmio;
105 static unsigned long platform_mmio_alloc;
106 static unsigned long platform_mmiolen;
108 unsigned long alloc_xen_mmio(unsigned long len)
109 {
110 unsigned long addr;
112 addr = platform_mmio + platform_mmio_alloc;
113 platform_mmio_alloc += len;
114 BUG_ON(platform_mmio_alloc > platform_mmiolen);
116 return addr;
117 }
119 #ifndef __ia64__
121 static uint32_t xen_cpuid_base(void)
122 {
123 uint32_t base, eax, ebx, ecx, edx;
124 char signature[13];
126 for (base = 0x40000000; base < 0x40010000; base += 0x100) {
127 cpuid(base, &eax, &ebx, &ecx, &edx);
128 *(uint32_t*)(signature + 0) = ebx;
129 *(uint32_t*)(signature + 4) = ecx;
130 *(uint32_t*)(signature + 8) = edx;
131 signature[12] = 0;
133 if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2))
134 return base;
135 }
137 return 0;
138 }
140 static int init_hypercall_stubs(void)
141 {
142 uint32_t eax, ebx, ecx, edx, pages, msr, i, base;
144 base = xen_cpuid_base();
145 if (base == 0) {
146 printk(KERN_WARNING
147 "Detected Xen platform device but not Xen VMM?\n");
148 return -EINVAL;
149 }
151 cpuid(base + 1, &eax, &ebx, &ecx, &edx);
153 printk(KERN_INFO "Xen version %d.%d.\n", eax >> 16, eax & 0xffff);
155 /*
156 * Find largest supported number of hypercall pages.
157 * We'll create as many as possible up to this number.
158 */
159 cpuid(base + 2, &pages, &msr, &ecx, &edx);
161 /*
162 * Use __vmalloc() because vmalloc_exec() is not an exported symbol.
163 * PAGE_KERNEL_EXEC also is not exported, hence we use PAGE_KERNEL.
164 * hypercall_stubs = vmalloc_exec(pages * PAGE_SIZE);
165 */
166 while (pages > 0) {
167 hypercall_stubs = __vmalloc(
168 pages * PAGE_SIZE,
169 GFP_KERNEL | __GFP_HIGHMEM,
170 __pgprot(__PAGE_KERNEL & ~_PAGE_NX));
171 if (hypercall_stubs != NULL)
172 break;
173 pages--; /* vmalloc failed: try one fewer pages */
174 }
176 if (hypercall_stubs == NULL)
177 return -ENOMEM;
179 for (i = 0; i < pages; i++) {
180 unsigned long pfn;
181 pfn = vmalloc_to_pfn((char *)hypercall_stubs + i*PAGE_SIZE);
182 wrmsrl(msr, ((u64)pfn << PAGE_SHIFT) + i);
183 }
185 nr_hypercall_stub_pages = pages;
186 max_hypercall_stub_pages = pages;
188 printk(KERN_INFO "Hypercall area is %u pages.\n", pages);
190 return 0;
191 }
193 static void resume_hypercall_stubs(void)
194 {
195 uint32_t base, ecx, edx, pages, msr, i;
197 base = xen_cpuid_base();
198 BUG_ON(base == 0);
200 cpuid(base + 2, &pages, &msr, &ecx, &edx);
202 if (pages > max_hypercall_stub_pages)
203 pages = max_hypercall_stub_pages;
205 for (i = 0; i < pages; i++) {
206 unsigned long pfn;
207 pfn = vmalloc_to_pfn((char *)hypercall_stubs + i*PAGE_SIZE);
208 wrmsrl(msr, ((u64)pfn << PAGE_SHIFT) + i);
209 }
211 nr_hypercall_stub_pages = pages;
212 }
214 #else /* __ia64__ */
216 #define init_hypercall_stubs() (0)
217 #define resume_hypercall_stubs() ((void)0)
219 #endif
221 static uint64_t get_callback_via(struct pci_dev *pdev)
222 {
223 u8 pin;
224 int irq;
226 #ifdef __ia64__
227 for (irq = 0; irq < 16; irq++) {
228 if (isa_irq_to_vector(irq) == pdev->irq)
229 return irq; /* ISA IRQ */
230 }
231 #else /* !__ia64__ */
232 irq = pdev->irq;
233 if (irq < 16)
234 return irq; /* ISA IRQ */
235 #endif
237 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
238 pin = pdev->pin;
239 #else
240 pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin);
241 #endif
243 /* We don't know the GSI. Specify the PCI INTx line instead. */
244 return (((uint64_t)0x01 << 56) | /* PCI INTx identifier */
245 ((uint64_t)pci_domain_nr(pdev->bus) << 32) |
246 ((uint64_t)pdev->bus->number << 16) |
247 ((uint64_t)(pdev->devfn & 0xff) << 8) |
248 ((uint64_t)(pin - 1) & 3));
249 }
251 static int set_callback_via(uint64_t via)
252 {
253 struct xen_hvm_param a;
255 a.domid = DOMID_SELF;
256 a.index = HVM_PARAM_CALLBACK_IRQ;
257 a.value = via;
258 return HYPERVISOR_hvm_op(HVMOP_set_param, &a);
259 }
261 int xen_irq_init(struct pci_dev *pdev);
262 int xenbus_init(void);
263 int xen_reboot_init(void);
264 int xen_panic_handler_init(void);
265 int gnttab_init(void);
267 #define XEN_IOPORT_BASE 0x10
269 #define XEN_IOPORT_PLATFLAGS (XEN_IOPORT_BASE + 0) /* 1 byte access (R/W) */
270 #define XEN_IOPORT_MAGIC (XEN_IOPORT_BASE + 0) /* 2 byte access (R) */
271 #define XEN_IOPORT_UNPLUG (XEN_IOPORT_BASE + 0) /* 2 byte access (W) */
272 #define XEN_IOPORT_DRVVER (XEN_IOPORT_BASE + 0) /* 4 byte access (W) */
274 #define XEN_IOPORT_SYSLOG (XEN_IOPORT_BASE + 2) /* 1 byte access (W) */
275 #define XEN_IOPORT_PROTOVER (XEN_IOPORT_BASE + 2) /* 1 byte access (R) */
276 #define XEN_IOPORT_PRODNUM (XEN_IOPORT_BASE + 2) /* 2 byte access (W) */
278 #define XEN_IOPORT_MAGIC_VAL 0x49d2
279 #define XEN_IOPORT_LINUX_PRODNUM 0xffff /* NB: register a proper one */
280 #define XEN_IOPORT_LINUX_DRVVER ((LINUX_VERSION_CODE << 8) + 0x0)
282 #define UNPLUG_ALL_IDE_DISKS 1
283 #define UNPLUG_ALL_NICS 2
284 #define UNPLUG_AUX_IDE_DISKS 4
285 #define UNPLUG_ALL 7
287 static int check_platform_magic(struct device *dev, long ioaddr, long iolen)
288 {
289 short magic, unplug = 0;
290 char protocol, *p, *q, *err;
292 for (p = dev_unplug; p; p = q) {
293 q = strchr(dev_unplug, ',');
294 if (q)
295 *q++ = '\0';
296 if (!strcmp(p, "all"))
297 unplug |= UNPLUG_ALL;
298 else if (!strcmp(p, "ide-disks"))
299 unplug |= UNPLUG_ALL_IDE_DISKS;
300 else if (!strcmp(p, "aux-ide-disks"))
301 unplug |= UNPLUG_AUX_IDE_DISKS;
302 else if (!strcmp(p, "nics"))
303 unplug |= UNPLUG_ALL_NICS;
304 else
305 dev_warn(dev, "unrecognised option '%s' "
306 "in module parameter 'dev_unplug'\n", p);
307 }
309 if (iolen < 0x16) {
310 err = "backend too old";
311 goto no_dev;
312 }
314 magic = inw(XEN_IOPORT_MAGIC);
316 if (magic != XEN_IOPORT_MAGIC_VAL) {
317 err = "unrecognised magic value";
318 goto no_dev;
319 }
321 protocol = inb(XEN_IOPORT_PROTOVER);
323 dev_info(dev, "I/O protocol version %d\n", protocol);
325 switch (protocol) {
326 case 1:
327 outw(XEN_IOPORT_LINUX_PRODNUM, XEN_IOPORT_PRODNUM);
328 outl(XEN_IOPORT_LINUX_DRVVER, XEN_IOPORT_DRVVER);
329 if (inw(XEN_IOPORT_MAGIC) != XEN_IOPORT_MAGIC_VAL) {
330 dev_err(dev, "blacklisted by host\n");
331 return -ENODEV;
332 }
333 /* Fall through */
334 case 0:
335 outw(unplug, XEN_IOPORT_UNPLUG);
336 break;
337 default:
338 err = "unknown I/O protocol version";
339 goto no_dev;
340 }
342 return 0;
344 no_dev:
345 dev_warn(dev, "failed backend handshake: %s\n", err);
346 if (!unplug)
347 return 0;
348 dev_err(dev, "failed to execute specified dev_unplug options!\n");
349 return -ENODEV;
350 }
352 static int __devinit platform_pci_init(struct pci_dev *pdev,
353 const struct pci_device_id *ent)
354 {
355 int i, ret;
356 long ioaddr, iolen;
357 long mmio_addr, mmio_len;
359 if (xen_platform_pdev)
360 return -EBUSY;
361 xen_platform_pdev = pdev;
363 i = pci_enable_device(pdev);
364 if (i)
365 return i;
367 ioaddr = pci_resource_start(pdev, 0);
368 iolen = pci_resource_len(pdev, 0);
370 mmio_addr = pci_resource_start(pdev, 1);
371 mmio_len = pci_resource_len(pdev, 1);
373 callback_via = get_callback_via(pdev);
375 if (mmio_addr == 0 || ioaddr == 0 || callback_via == 0) {
376 printk(KERN_WARNING DRV_NAME ":no resources found\n");
377 return -ENOENT;
378 }
380 ret = pci_request_region(pdev, 1, DRV_NAME);
381 if (ret < 0)
382 return ret;
384 ret = pci_request_region(pdev, 0, DRV_NAME);
385 if (ret < 0)
386 goto mem_out;
388 platform_mmio = mmio_addr;
389 platform_mmiolen = mmio_len;
391 ret = init_hypercall_stubs();
392 if (ret < 0)
393 goto out;
395 ret = check_platform_magic(&pdev->dev, ioaddr, iolen);
396 if (ret < 0)
397 goto out;
399 if ((ret = init_xen_info()))
400 goto out;
402 if ((ret = gnttab_init()))
403 goto out;
405 if ((ret = xen_irq_init(pdev)))
406 goto out;
408 if ((ret = set_callback_via(callback_via)))
409 goto out;
411 if ((ret = xenbus_init()))
412 goto out;
414 if ((ret = xen_reboot_init()))
415 goto out;
417 if ((ret = xen_panic_handler_init()))
418 goto out;
420 out:
421 if (ret) {
422 pci_release_region(pdev, 0);
423 mem_out:
424 pci_release_region(pdev, 1);
425 }
427 return ret;
428 }
430 #define XEN_PLATFORM_VENDOR_ID 0x5853
431 #define XEN_PLATFORM_DEVICE_ID 0x0001
432 static struct pci_device_id platform_pci_tbl[] __devinitdata = {
433 {XEN_PLATFORM_VENDOR_ID, XEN_PLATFORM_DEVICE_ID,
434 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
435 /* Continue to recognise the old ID for now */
436 {0xfffd, 0x0101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
437 {0,}
438 };
440 MODULE_DEVICE_TABLE(pci, platform_pci_tbl);
442 static struct pci_driver platform_driver = {
443 name: DRV_NAME,
444 probe: platform_pci_init,
445 id_table: platform_pci_tbl,
446 };
448 static int pci_device_registered;
450 void platform_pci_resume(void)
451 {
452 struct xen_add_to_physmap xatp;
454 resume_hypercall_stubs();
456 xatp.domid = DOMID_SELF;
457 xatp.idx = 0;
458 xatp.space = XENMAPSPACE_shared_info;
459 xatp.gpfn = shared_info_frame;
460 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
461 BUG();
463 if (set_callback_via(callback_via))
464 printk("platform_pci_resume failure!\n");
465 }
467 static int __init platform_pci_module_init(void)
468 {
469 int rc;
471 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
472 rc = pci_module_init(&platform_driver);
473 #else
474 rc = pci_register_driver(&platform_driver);
475 #endif
476 if (rc) {
477 printk(KERN_INFO DRV_NAME
478 ": No platform pci device model found\n");
479 return rc;
480 }
482 pci_device_registered = 1;
483 return 0;
484 }
486 module_init(platform_pci_module_init);