]> rtime.felk.cvut.cz Git - jailhouse.git/blob - driver/pci.c
driver: Improve input validation to make code scanners happier
[jailhouse.git] / driver / pci.c
1 /*
2  * Jailhouse, a Linux-based partitioning hypervisor
3  *
4  * Copyright (c) Siemens AG, 2014-2015
5  *
6  * Authors:
7  *  Jan Kiszka <jan.kiszka@siemens.com>
8  *  Henning Schild <henning.schild@siemens.com>
9  *
10  * This work is licensed under the terms of the GNU GPL, version 2.  See
11  * the COPYING file in the top-level directory.
12  */
13
14 #include <linux/pci.h>
15
16 #include "pci.h"
17
18 static void jailhouse_pci_add_device(const struct jailhouse_pci_device *dev)
19 {
20         int num;
21         struct pci_bus *bus;
22
23         bus = pci_find_bus(dev->domain, PCI_BUS_NUM(dev->bdf));
24         if (bus) {
25                 num = pci_scan_slot(bus, dev->bdf & 0xff);
26                 if (num) {
27                         pci_lock_rescan_remove();
28                         pci_bus_assign_resources(bus);
29                         pci_bus_add_devices(bus);
30                         pci_unlock_rescan_remove();
31                 }
32         }
33 }
34
35 static void jailhouse_pci_remove_device(const struct jailhouse_pci_device *dev)
36 {
37         struct pci_dev *l_dev;
38
39         l_dev = pci_get_bus_and_slot(PCI_BUS_NUM(dev->bdf), dev->bdf & 0xff);
40         if (l_dev)
41                 pci_stop_and_remove_bus_device_locked(l_dev);
42 }
43
44 void jailhouse_pci_do_all_devices(struct cell *cell, unsigned int type,
45                                   unsigned int action)
46 {
47         unsigned int n;
48         const struct jailhouse_pci_device *dev;
49
50         dev = cell->pci_devices;
51         for (n = cell->num_pci_devices; n > 0; n--) {
52                 if (dev->type == type) {
53                         if (action == JAILHOUSE_PCI_ACTION_ADD)
54                                 jailhouse_pci_add_device(dev);
55                         else if (action == JAILHOUSE_PCI_ACTION_DEL)
56                                 jailhouse_pci_remove_device(dev);
57                 }
58                 dev++;
59         }
60 }
61
62 int jailhouse_pci_cell_setup(struct cell *cell,
63                              const struct jailhouse_cell_desc *cell_desc)
64 {
65         if (cell_desc->num_pci_devices == 0)
66                 /* cell is zero-initialized, no need to set pci fields */
67                 return 0;
68
69         if (cell_desc->num_pci_devices >=
70             ULONG_MAX / sizeof(struct jailhouse_pci_device))
71                 return -EINVAL;
72
73         cell->num_pci_devices = cell_desc->num_pci_devices;
74         cell->pci_devices = vmalloc(sizeof(struct jailhouse_pci_device) *
75                                     cell->num_pci_devices);
76         if (!cell->pci_devices)
77                 return -ENOMEM;
78
79         memcpy(cell->pci_devices,
80                jailhouse_cell_pci_devices(cell_desc),
81                sizeof(struct jailhouse_pci_device) * cell->num_pci_devices);
82
83         return 0;
84 }
85
86 void jailhouse_pci_cell_cleanup(struct cell *cell)
87 {
88         vfree(cell->pci_devices);
89 }