]> rtime.felk.cvut.cz Git - jailhouse.git/blob - hypervisor/pci.c
core: Disable PCI devices on removal
[jailhouse.git] / hypervisor / pci.c
1 /*
2  * Jailhouse, a Linux-based partitioning hypervisor
3  *
4  * Copyright (c) Siemens AG, 2014
5  *
6  * Authors:
7  *  Ivan Kolchin <ivan.kolchin@siemens.com>
8  *  Jan Kiszka <jan.kiszka@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 <jailhouse/acpi.h>
15 #include <jailhouse/control.h>
16 #include <jailhouse/mmio.h>
17 #include <jailhouse/pci.h>
18 #include <jailhouse/printk.h>
19 #include <jailhouse/utils.h>
20
21 #define PCI_CONFIG_HEADER_SIZE          0x40
22
23 #define PCI_CFG_COMMAND                 0x04
24 # define PCI_CMD_INTX_OFF               (1 << 10)
25
26 struct acpi_mcfg_alloc {
27         u64 base_addr;
28         u16 segment_num;
29         u8 start_bus;
30         u8 end_bus;
31         u32 reserved;
32 } __attribute__((packed));
33
34 struct acpi_mcfg_table {
35         struct acpi_table_header header;
36         u8 reserved[8];
37         struct acpi_mcfg_alloc alloc_structs[];
38 } __attribute__((packed));
39
40 #define for_each_configured_pci_device(dev, cell)                       \
41         for ((dev) = (cell)->pci_devices;                               \
42              (dev) - (cell)->pci_devices < (cell)->config->num_pci_devices; \
43              (dev)++)
44
45 /* entry for PCI config space whitelist (granting access) */
46 struct pci_cfg_access {
47         u32 reg_num; /** Register number (4-byte aligned) */
48         u32 mask; /** Bit set: access allowed */
49 };
50
51 /* --- Whilelist for writing to PCI config space registers --- */
52 /* Type 1: Endpoints */
53 static const struct pci_cfg_access endpoint_write_access[] = {
54         { 0x04, 0xffffffff }, /* Command, Status */
55         { 0x0c, 0xff00ffff }, /* BIST, Latency Timer, Cacheline */
56         { 0x3c, 0x000000ff }, /* Int Line */
57 };
58 /* Type 2: Bridges */
59 static const struct pci_cfg_access bridge_write_access[] = {
60         { 0x04, 0xffffffff }, /* Command, Status */
61         { 0x0c, 0xff00ffff }, /* BIST, Latency Timer, Cacheline */
62         { 0x3c, 0xffff00ff }, /* Int Line, Bridge Control */
63 };
64
65 static void *pci_space;
66 static u64 pci_mmcfg_addr;
67 static u32 pci_mmcfg_size;
68 static u8 end_bus;
69
70 static void *pci_get_device_mmcfg_base(u16 bdf)
71 {
72         return pci_space + ((unsigned long)bdf << 12);
73 }
74
75 /**
76  * pci_read_config() - Read from PCI config space
77  * @bdf:        16-bit bus/device/function ID of target
78  * @address:    Config space access address
79  * @size:       Access size (1, 2 or 4 bytes)
80  *
81  * Return: read value
82  */
83 u32 pci_read_config(u16 bdf, u16 address, unsigned int size)
84 {
85         void *mmcfg_addr = pci_get_device_mmcfg_base(bdf) + address;
86
87         if (!pci_space || PCI_BUS(bdf) > end_bus)
88                 return arch_pci_read_config(bdf, address, size);
89
90         if (size == 1)
91                 return mmio_read8(mmcfg_addr);
92         else if (size == 2)
93                 return mmio_read16(mmcfg_addr);
94         else
95                 return mmio_read32(mmcfg_addr);
96 }
97
98 /**
99  * pci_write_config() - Write to PCI config space
100  * @bdf:        16-bit bus/device/function ID of target
101  * @address:    Config space access address
102  * @value:      Value to be written
103  * @size:       Access size (1, 2 or 4 bytes)
104  */
105 void pci_write_config(u16 bdf, u16 address, u32 value, unsigned int size)
106 {
107         void *mmcfg_addr = pci_get_device_mmcfg_base(bdf) + address;
108
109         if (!pci_space || PCI_BUS(bdf) > end_bus)
110                 return arch_pci_write_config(bdf, address, value, size);
111
112         if (size == 1)
113                 mmio_write8(mmcfg_addr, value);
114         else if (size == 2)
115                 mmio_write16(mmcfg_addr, value);
116         else
117                 mmio_write32(mmcfg_addr, value);
118 }
119
120 /**
121  * pci_get_assigned_device() - Look up device owned by a cell
122  * @cell:       Owning cell
123  * @bdf:        16-bit bus/device/function ID
124  *
125  * Return: Pointer to owned PCI device or NULL.
126  */
127 struct pci_device *pci_get_assigned_device(const struct cell *cell, u16 bdf)
128 {
129         const struct jailhouse_pci_device *dev_info =
130                 jailhouse_cell_pci_devices(cell->config);
131         u32 n;
132
133         /* We iterate over the static device information to increase cache
134          * locality. */
135         for (n = 0; n < cell->config->num_pci_devices; n++)
136                 if (dev_info[n].bdf == bdf)
137                         return cell->pci_devices[n].cell ?
138                                 &cell->pci_devices[n] : NULL;
139
140         return NULL;
141 }
142
143 /**
144  * pci_find_capability() - Look up capability at given config space address
145  * @device:     The device to be accessed
146  * @address:    Config space access address
147  *
148  * Return: Corresponding capability structure or NULL if none found.
149  */
150 static const struct jailhouse_pci_capability *
151 pci_find_capability(struct pci_device *device, u16 address)
152 {
153         const struct jailhouse_pci_capability *cap =
154                 jailhouse_cell_pci_caps(device->cell->config) +
155                 device->info->caps_start;
156         u32 n;
157
158         for (n = 0; n < device->info->num_caps; n++, cap++)
159                 if (cap->start <= address && cap->start + cap->len > address)
160                         return cap;
161
162         return NULL;
163 }
164
165 /**
166  * pci_cfg_read_moderate() - Moderate config space read access
167  * @device:     The device to be accessed; if NULL, access will be emulated,
168  *              returning a value of -1
169  * @address:    Config space address
170  * @size:       Access size (1, 2 or 4 bytes)
171  * @value:      Pointer to buffer to receive the emulated value if
172  *              PCI_ACCESS_DONE is returned
173  *
174  * Return: PCI_ACCESS_PERFORM or PCI_ACCESS_DONE.
175  */
176 enum pci_access pci_cfg_read_moderate(struct pci_device *device, u16 address,
177                                       unsigned int size, u32 *value)
178 {
179         const struct jailhouse_pci_capability *cap;
180
181         if (!device) {
182                 *value = -1;
183                 return PCI_ACCESS_DONE;
184         }
185
186         if (address < PCI_CONFIG_HEADER_SIZE)
187                 return PCI_ACCESS_PERFORM;
188
189         cap = pci_find_capability(device, address);
190         if (!cap)
191                 return PCI_ACCESS_PERFORM;
192
193         // TODO: Emulate MSI/MSI-X etc.
194
195         return PCI_ACCESS_PERFORM;
196 }
197
198 /**
199  * pci_cfg_write_moderate() - Moderate config space write access
200  * @device:     The device to be accessed; if NULL, access will be rejected
201  * @address:    Config space address
202  * @size:       Access size (1, 2 or 4 bytes)
203  * @value:      Value to be written
204  *
205  * Return: PCI_ACCESS_REJECT, PCI_ACCESS_PERFORM or PCI_ACCESS_DONE.
206  */
207 enum pci_access pci_cfg_write_moderate(struct pci_device *device, u16 address,
208                                        unsigned int size, u32 value)
209 {
210         const struct jailhouse_pci_capability *cap;
211         /* initialize list to work around wrong compiler warning */
212         const struct pci_cfg_access *list = NULL;
213         unsigned int n, bias_shift, len = 0;
214         u32 mask;
215
216         if (!device)
217                 return PCI_ACCESS_REJECT;
218
219         if (address < PCI_CONFIG_HEADER_SIZE) {
220                 if (device->info->type == JAILHOUSE_PCI_TYPE_DEVICE) {
221                         list = endpoint_write_access;
222                         len = ARRAY_SIZE(endpoint_write_access);
223                 } else if (device->info->type == JAILHOUSE_PCI_TYPE_BRIDGE) {
224                         list = bridge_write_access;
225                         len = ARRAY_SIZE(bridge_write_access);
226                 }
227
228                 bias_shift = (address & 0x003) * 8;
229                 mask = BYTE_MASK(size);
230
231                 for (n = 0; n < len; n++) {
232                         if (list[n].reg_num == (address & 0xffc) &&
233                             ((list[n].mask >> bias_shift) & mask) == mask)
234                                 return PCI_ACCESS_PERFORM;
235                 }
236
237                 return PCI_ACCESS_REJECT;
238         }
239
240         cap = pci_find_capability(device, address);
241         if (!cap || !(cap->flags & JAILHOUSE_PCICAPS_WRITE))
242                 return PCI_ACCESS_REJECT;
243
244         return PCI_ACCESS_PERFORM;
245 }
246
247 /**
248  * pci_init() - Initialization of PCI module
249  *
250  * Return: 0 - success, error code - if error.
251  */
252 int pci_init(void)
253 {
254         struct acpi_mcfg_table *mcfg;
255         int err;
256
257         err = pci_cell_init(&root_cell);
258         if (err)
259                 return err;
260
261         mcfg = (struct acpi_mcfg_table *)acpi_find_table("MCFG", NULL);
262         if (!mcfg)
263                 return 0;
264
265         if (mcfg->header.length !=
266             sizeof(struct acpi_mcfg_table) + sizeof(struct acpi_mcfg_alloc))
267                 return -EIO;
268
269         pci_mmcfg_addr = mcfg->alloc_structs[0].base_addr;
270         pci_mmcfg_size = (mcfg->alloc_structs[0].end_bus + 1) * 256 * 4096;
271         pci_space = page_alloc(&remap_pool, pci_mmcfg_size / PAGE_SIZE);
272         if (!pci_space)
273                 return -ENOMEM;
274
275         end_bus = mcfg->alloc_structs[0].end_bus;
276
277         return page_map_create(&hv_paging_structs,
278                                mcfg->alloc_structs[0].base_addr,
279                                pci_mmcfg_size, (unsigned long)pci_space,
280                                PAGE_DEFAULT_FLAGS | PAGE_FLAG_UNCACHED,
281                                PAGE_MAP_NON_COHERENT);
282 }
283
284 /**
285  * pci_mmio_access_handler() - Handler for MMIO-accesses to PCI config space
286  * @cell:       Request issuing cell
287  * @is_write:   True if write access
288  * @addr:       Address accessed
289  * @value:      Pointer to value for reading/writing
290  *
291  * Return: 1 if handled successfully, 0 if unhandled, -1 on access error
292  */
293 int pci_mmio_access_handler(const struct cell *cell, bool is_write,
294                             u64 addr, u32 *value)
295 {
296         u32 mmcfg_offset, reg_addr;
297         struct pci_device *device;
298         enum pci_access access;
299
300         if (!pci_space || addr < pci_mmcfg_addr ||
301             addr >= (pci_mmcfg_addr + pci_mmcfg_size - 4))
302                 return 0;
303
304         mmcfg_offset = addr - pci_mmcfg_addr;
305         reg_addr = mmcfg_offset & 0xfff;
306         device = pci_get_assigned_device(cell, mmcfg_offset >> 12);
307
308         if (is_write) {
309                 access = pci_cfg_write_moderate(device, reg_addr, 4, *value);
310                 if (access == PCI_ACCESS_REJECT)
311                         goto invalid_access;
312                 if (access == PCI_ACCESS_PERFORM)
313                         mmio_write32(pci_space + mmcfg_offset, *value);
314         } else {
315                 access = pci_cfg_read_moderate(device, reg_addr, 4, value);
316                 if (access == PCI_ACCESS_PERFORM)
317                         *value = mmio_read32(pci_space + mmcfg_offset);
318         }
319
320         return 1;
321
322 invalid_access:
323         panic_printk("FATAL: Invalid PCI MMCONFIG write, device %02x:%02x.%x, "
324                      "reg: %\n", PCI_BDF_PARAMS(mmcfg_offset >> 12), reg_addr);
325         return -1;
326
327 }
328
329 static int pci_add_device(struct cell *cell, struct pci_device *device)
330 {
331         printk("Adding PCI device %02x:%02x.%x to cell \"%s\"\n",
332                PCI_BDF_PARAMS(device->info->bdf), cell->config->name);
333         return arch_pci_add_device(cell, device);
334 }
335
336 static void pci_remove_device(struct pci_device *device)
337 {
338         printk("Removing PCI device %02x:%02x.%x from cell \"%s\"\n",
339                PCI_BDF_PARAMS(device->info->bdf), device->cell->config->name);
340         arch_pci_remove_device(device);
341         pci_write_config(device->info->bdf, PCI_CFG_COMMAND,
342                          PCI_CMD_INTX_OFF, 2);
343 }
344
345 int pci_cell_init(struct cell *cell)
346 {
347         unsigned long array_size = PAGE_ALIGN(cell->config->num_pci_devices *
348                                               sizeof(struct pci_device));
349         const struct jailhouse_pci_device *dev_infos =
350                 jailhouse_cell_pci_devices(cell->config);
351         struct pci_device *device, *root_device;
352         unsigned int ndev;
353         int err;
354
355         cell->pci_devices = page_alloc(&mem_pool, array_size / PAGE_SIZE);
356         if (!cell->pci_devices)
357                 return -ENOMEM;
358
359         /*
360          * We order device states in the same way as the static information
361          * so that we can use the index of the latter to find the former. For
362          * the other way around and for obtaining the owner cell, we use more
363          * handy pointers. The cell pointer also encodes active ownership.
364          */
365         for (ndev = 0; ndev < cell->config->num_pci_devices; ndev++) {
366                 device = &cell->pci_devices[ndev];
367                 device->info = &dev_infos[ndev];
368
369                 root_device = pci_get_assigned_device(&root_cell,
370                                                       dev_infos[ndev].bdf);
371                 if (root_device) {
372                         pci_remove_device(root_device);
373                         root_device->cell = NULL;
374                 }
375
376                 err = pci_add_device(cell, device);
377                 if (err) {
378                         pci_cell_exit(cell);
379                         return err;
380                 }
381
382                 device->cell = cell;
383         }
384
385         return 0;
386 }
387
388 static void pci_return_device_to_root_cell(struct pci_device *device)
389 {
390         struct pci_device *root_device;
391
392         for_each_configured_pci_device(root_device, &root_cell)
393                 if (root_device->info->domain == device->info->domain &&
394                     root_device->info->bdf == device->info->bdf) {
395                         if (pci_add_device(&root_cell, root_device) < 0)
396                                 printk("WARNING: Failed to re-assign PCI "
397                                        "device to root cell\n");
398                         else
399                                 root_device->cell = &root_cell;
400                         break;
401                 }
402 }
403
404 void pci_cell_exit(struct cell *cell)
405 {
406         unsigned long array_size = PAGE_ALIGN(cell->config->num_pci_devices *
407                                               sizeof(struct pci_device));
408         struct pci_device *device;
409
410         /*
411          * Do not destroy the root cell. We will shut down the complete
412          * hypervisor instead.
413          */
414         if (cell == &root_cell)
415                 return;
416
417         for_each_configured_pci_device(device, cell) {
418                 if (!device->cell)
419                         continue;
420                 pci_remove_device(device);
421                 pci_return_device_to_root_cell(device);
422         }
423
424         page_free(&mem_pool, cell->pci_devices, array_size / PAGE_SIZE);
425 }