]> rtime.felk.cvut.cz Git - jailhouse.git/blob - hypervisor/pci.c
core: Virtualize legacy MSI for interrupt remapping support
[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/control.h>
15 #include <jailhouse/mmio.h>
16 #include <jailhouse/pci.h>
17 #include <jailhouse/printk.h>
18 #include <jailhouse/utils.h>
19
20 #define PCI_CONFIG_HEADER_SIZE          0x40
21
22 #define PCI_CAP_MSI                     0x05
23 #define PCI_CAP_MSIX                    0x11
24
25 #define for_each_configured_pci_device(dev, cell)                       \
26         for ((dev) = (cell)->pci_devices;                               \
27              (dev) - (cell)->pci_devices < (cell)->config->num_pci_devices; \
28              (dev)++)
29
30 #define for_each_pci_cap(cap, dev, counter)                             \
31         for ((cap) = jailhouse_cell_pci_caps((dev)->cell->config) +     \
32                 (dev)->info->caps_start, (counter) = 0;                 \
33              (counter) < (dev)->info->num_caps;                         \
34              (cap)++, (counter)++)
35
36 /* entry for PCI config space whitelist (granting access) */
37 struct pci_cfg_access {
38         u32 reg_num; /** Register number (4-byte aligned) */
39         u32 mask; /** Bit set: access allowed */
40 };
41
42 /* --- Whilelist for writing to PCI config space registers --- */
43 /* Type 1: Endpoints */
44 static const struct pci_cfg_access endpoint_write_access[] = {
45         { 0x04, 0xffffffff }, /* Command, Status */
46         { 0x0c, 0xff00ffff }, /* BIST, Latency Timer, Cacheline */
47         { 0x3c, 0x000000ff }, /* Int Line */
48 };
49 /* Type 2: Bridges */
50 static const struct pci_cfg_access bridge_write_access[] = {
51         { 0x04, 0xffffffff }, /* Command, Status */
52         { 0x0c, 0xff00ffff }, /* BIST, Latency Timer, Cacheline */
53         { 0x3c, 0xffff00ff }, /* Int Line, Bridge Control */
54 };
55
56 static void *pci_space;
57 static u64 mmcfg_start, mmcfg_end;
58 static u8 end_bus;
59
60 static void *pci_get_device_mmcfg_base(u16 bdf)
61 {
62         return pci_space + ((unsigned long)bdf << 12);
63 }
64
65 /**
66  * pci_read_config() - Read from PCI config space
67  * @bdf:        16-bit bus/device/function ID of target
68  * @address:    Config space access address
69  * @size:       Access size (1, 2 or 4 bytes)
70  *
71  * Return: read value
72  */
73 u32 pci_read_config(u16 bdf, u16 address, unsigned int size)
74 {
75         void *mmcfg_addr = pci_get_device_mmcfg_base(bdf) + address;
76
77         if (!pci_space || PCI_BUS(bdf) > end_bus)
78                 return arch_pci_read_config(bdf, address, size);
79
80         if (size == 1)
81                 return mmio_read8(mmcfg_addr);
82         else if (size == 2)
83                 return mmio_read16(mmcfg_addr);
84         else
85                 return mmio_read32(mmcfg_addr);
86 }
87
88 /**
89  * pci_write_config() - Write to PCI config space
90  * @bdf:        16-bit bus/device/function ID of target
91  * @address:    Config space access address
92  * @value:      Value to be written
93  * @size:       Access size (1, 2 or 4 bytes)
94  */
95 void pci_write_config(u16 bdf, u16 address, u32 value, unsigned int size)
96 {
97         void *mmcfg_addr = pci_get_device_mmcfg_base(bdf) + address;
98
99         if (!pci_space || PCI_BUS(bdf) > end_bus)
100                 return arch_pci_write_config(bdf, address, value, size);
101
102         if (size == 1)
103                 mmio_write8(mmcfg_addr, value);
104         else if (size == 2)
105                 mmio_write16(mmcfg_addr, value);
106         else
107                 mmio_write32(mmcfg_addr, value);
108 }
109
110 /**
111  * pci_get_assigned_device() - Look up device owned by a cell
112  * @cell:       Owning cell
113  * @bdf:        16-bit bus/device/function ID
114  *
115  * Return: Pointer to owned PCI device or NULL.
116  */
117 struct pci_device *pci_get_assigned_device(const struct cell *cell, u16 bdf)
118 {
119         const struct jailhouse_pci_device *dev_info =
120                 jailhouse_cell_pci_devices(cell->config);
121         u32 n;
122
123         /* We iterate over the static device information to increase cache
124          * locality. */
125         for (n = 0; n < cell->config->num_pci_devices; n++)
126                 if (dev_info[n].bdf == bdf)
127                         return cell->pci_devices[n].cell ?
128                                 &cell->pci_devices[n] : NULL;
129
130         return NULL;
131 }
132
133 /**
134  * pci_find_capability() - Look up capability at given config space address
135  * @device:     The device to be accessed
136  * @address:    Config space access address
137  *
138  * Return: Corresponding capability structure or NULL if none found.
139  */
140 static const struct jailhouse_pci_capability *
141 pci_find_capability(struct pci_device *device, u16 address)
142 {
143         const struct jailhouse_pci_capability *cap =
144                 jailhouse_cell_pci_caps(device->cell->config) +
145                 device->info->caps_start;
146         u32 n;
147
148         for (n = 0; n < device->info->num_caps; n++, cap++)
149                 if (cap->start <= address && cap->start + cap->len > address)
150                         return cap;
151
152         return NULL;
153 }
154
155 /**
156  * pci_cfg_read_moderate() - Moderate config space read access
157  * @device:     The device to be accessed; if NULL, access will be emulated,
158  *              returning a value of -1
159  * @address:    Config space address
160  * @size:       Access size (1, 2 or 4 bytes)
161  * @value:      Pointer to buffer to receive the emulated value if
162  *              PCI_ACCESS_DONE is returned
163  *
164  * Return: PCI_ACCESS_PERFORM or PCI_ACCESS_DONE.
165  */
166 enum pci_access pci_cfg_read_moderate(struct pci_device *device, u16 address,
167                                       unsigned int size, u32 *value)
168 {
169         const struct jailhouse_pci_capability *cap;
170         unsigned int cap_offs;
171
172         if (!device) {
173                 *value = -1;
174                 return PCI_ACCESS_DONE;
175         }
176
177         if (address < PCI_CONFIG_HEADER_SIZE)
178                 return PCI_ACCESS_PERFORM;
179
180         cap = pci_find_capability(device, address);
181         if (!cap)
182                 return PCI_ACCESS_PERFORM;
183
184         cap_offs = address - cap->start;
185         if (cap->id == PCI_CAP_MSI && cap_offs >= 4 &&
186             (cap_offs < 10 || (device->info->msi_64bits && cap_offs < 14))) {
187                 *value = device->msi_registers.raw[cap_offs / 4] >>
188                         ((cap_offs % 4) * 8);
189                 return PCI_ACCESS_DONE;
190         }
191
192         return PCI_ACCESS_PERFORM;
193 }
194
195 /**
196  * pci_cfg_write_moderate() - Moderate config space write access
197  * @device:     The device to be accessed; if NULL, access will be rejected
198  * @address:    Config space address
199  * @size:       Access size (1, 2 or 4 bytes)
200  * @value:      Value to be written
201  *
202  * Return: PCI_ACCESS_REJECT, PCI_ACCESS_PERFORM or PCI_ACCESS_DONE.
203  */
204 enum pci_access pci_cfg_write_moderate(struct pci_device *device, u16 address,
205                                        unsigned int size, u32 value)
206 {
207         const struct jailhouse_pci_capability *cap;
208         /* initialize list to work around wrong compiler warning */
209         const struct pci_cfg_access *list = NULL;
210         unsigned int bias_shift = (address % 4) * 8;
211         unsigned int n, cap_offs, len = 0;
212         u32 mask = BYTE_MASK(size);
213
214         if (!device)
215                 return PCI_ACCESS_REJECT;
216
217         if (address < PCI_CONFIG_HEADER_SIZE) {
218                 if (device->info->type == JAILHOUSE_PCI_TYPE_DEVICE) {
219                         list = endpoint_write_access;
220                         len = ARRAY_SIZE(endpoint_write_access);
221                 } else if (device->info->type == JAILHOUSE_PCI_TYPE_BRIDGE) {
222                         list = bridge_write_access;
223                         len = ARRAY_SIZE(bridge_write_access);
224                 }
225
226                 for (n = 0; n < len; n++) {
227                         if (list[n].reg_num == (address & 0xffc) &&
228                             ((list[n].mask >> bias_shift) & mask) == mask)
229                                 return PCI_ACCESS_PERFORM;
230                 }
231
232                 return PCI_ACCESS_REJECT;
233         }
234
235         cap = pci_find_capability(device, address);
236         if (!cap || !(cap->flags & JAILHOUSE_PCICAPS_WRITE))
237                 return PCI_ACCESS_REJECT;
238
239         cap_offs = address - cap->start;
240         if (cap->id == PCI_CAP_MSI &&
241             (cap_offs < 10 || (device->info->msi_64bits && cap_offs < 14))) {
242                 value <<= bias_shift;
243                 mask <<= bias_shift;
244                 device->msi_registers.raw[cap_offs / 4] &= ~mask;
245                 device->msi_registers.raw[cap_offs / 4] |= value;
246
247                 if (pci_update_msi(device, cap) < 0)
248                         return PCI_ACCESS_REJECT;
249
250                 /*
251                  * Address and data words are emulated, the control word is
252                  * written as-is.
253                  */
254                 if (cap_offs >= 4)
255                         return PCI_ACCESS_DONE;
256         }
257
258         return PCI_ACCESS_PERFORM;
259 }
260
261 /**
262  * pci_init() - Initialization of PCI module
263  *
264  * Return: 0 - success, error code - if error.
265  */
266 int pci_init(void)
267 {
268         unsigned int mmcfg_size;
269         int err;
270
271         err = pci_cell_init(&root_cell);
272         if (err)
273                 return err;
274
275         mmcfg_start = system_config->platform_info.x86.mmconfig_base;
276         if (mmcfg_start == 0)
277                 return 0;
278
279         end_bus = system_config->platform_info.x86.mmconfig_end_bus;
280         mmcfg_size = (end_bus + 1) * 256 * 4096;
281         mmcfg_end = mmcfg_start + mmcfg_size - 4;
282
283         pci_space = page_alloc(&remap_pool, mmcfg_size / PAGE_SIZE);
284         if (!pci_space)
285                 return -ENOMEM;
286
287         return page_map_create(&hv_paging_structs, mmcfg_start, mmcfg_size,
288                                (unsigned long)pci_space,
289                                PAGE_DEFAULT_FLAGS | PAGE_FLAG_UNCACHED,
290                                PAGE_MAP_NON_COHERENT);
291 }
292
293 /**
294  * pci_mmio_access_handler() - Handler for MMIO-accesses to PCI config space
295  * @cell:       Request issuing cell
296  * @is_write:   True if write access
297  * @addr:       Address accessed
298  * @value:      Pointer to value for reading/writing
299  *
300  * Return: 1 if handled successfully, 0 if unhandled, -1 on access error
301  */
302 int pci_mmio_access_handler(const struct cell *cell, bool is_write,
303                             u64 addr, u32 *value)
304 {
305         u32 mmcfg_offset, reg_addr;
306         struct pci_device *device;
307         enum pci_access access;
308
309         if (!pci_space || addr < mmcfg_start || addr > mmcfg_end)
310                 return 0;
311
312         mmcfg_offset = addr - mmcfg_start;
313         reg_addr = mmcfg_offset & 0xfff;
314         /* access must be DWORD-aligned */
315         if (reg_addr & 0x3)
316                 goto invalid_access;
317
318         device = pci_get_assigned_device(cell, mmcfg_offset >> 12);
319
320         if (is_write) {
321                 access = pci_cfg_write_moderate(device, reg_addr, 4, *value);
322                 if (access == PCI_ACCESS_REJECT)
323                         goto invalid_access;
324                 if (access == PCI_ACCESS_PERFORM)
325                         mmio_write32(pci_space + mmcfg_offset, *value);
326         } else {
327                 access = pci_cfg_read_moderate(device, reg_addr, 4, value);
328                 if (access == PCI_ACCESS_PERFORM)
329                         *value = mmio_read32(pci_space + mmcfg_offset);
330         }
331
332         return 1;
333
334 invalid_access:
335         panic_printk("FATAL: Invalid PCI MMCONFIG write, device %02x:%02x.%x, "
336                      "reg: %\n", PCI_BDF_PARAMS(mmcfg_offset >> 12), reg_addr);
337         return -1;
338
339 }
340
341 unsigned int pci_enabled_msi_vectors(struct pci_device *device)
342 {
343         return device->msi_registers.msg32.enable ?
344                 1 << device->msi_registers.msg32.mme : 0;
345 }
346
347 static void pci_save_msi(struct pci_device *device,
348                          const struct jailhouse_pci_capability *cap)
349 {
350         u16 bdf = device->info->bdf;
351         unsigned int n;
352
353         for (n = 0; n < (device->info->msi_64bits ? 4 : 3); n++)
354                 device->msi_registers.raw[n] =
355                         pci_read_config(bdf, cap->start + n * 4, 4);
356 }
357
358 static void pci_restore_msi(struct pci_device *device,
359                             const struct jailhouse_pci_capability *cap)
360 {
361         unsigned int n;
362
363         for (n = 1; n < (device->info->msi_64bits ? 4 : 3); n++)
364                 pci_write_config(device->info->bdf, cap->start + n * 4,
365                                  device->msi_registers.raw[n], 4);
366 }
367
368 /**
369  * pci_prepare_handover() - Prepare the handover of PCI devices to Jailhouse or
370  *                          back to Linux
371  */
372 void pci_prepare_handover(void)
373 {
374         const struct jailhouse_pci_capability *cap;
375         struct pci_device *device;
376         unsigned int n;
377
378         if (!root_cell.pci_devices)
379                 return;
380
381         for_each_configured_pci_device(device, &root_cell) {
382                 if (device->cell)
383                         for_each_pci_cap(cap, device, n)
384                                 if (cap->id == PCI_CAP_MSI)
385                                         pci_suppress_msi(device, cap);
386                                 // TODO: MSI-X
387         }
388 }
389
390 static int pci_add_device(struct cell *cell, struct pci_device *device)
391 {
392         printk("Adding PCI device %02x:%02x.%x to cell \"%s\"\n",
393                PCI_BDF_PARAMS(device->info->bdf), cell->config->name);
394         return arch_pci_add_device(cell, device);
395 }
396
397 static void pci_remove_device(struct pci_device *device)
398 {
399         printk("Removing PCI device %02x:%02x.%x from cell \"%s\"\n",
400                PCI_BDF_PARAMS(device->info->bdf), device->cell->config->name);
401         arch_pci_remove_device(device);
402         pci_write_config(device->info->bdf, PCI_CFG_COMMAND,
403                          PCI_CMD_INTX_OFF, 2);
404 }
405
406 int pci_cell_init(struct cell *cell)
407 {
408         unsigned long array_size = PAGE_ALIGN(cell->config->num_pci_devices *
409                                               sizeof(struct pci_device));
410         const struct jailhouse_pci_device *dev_infos =
411                 jailhouse_cell_pci_devices(cell->config);
412         const struct jailhouse_pci_capability *cap;
413         struct pci_device *device, *root_device;
414         unsigned int ndev, ncap;
415         int err;
416
417         cell->pci_devices = page_alloc(&mem_pool, array_size / PAGE_SIZE);
418         if (!cell->pci_devices)
419                 return -ENOMEM;
420
421         /*
422          * We order device states in the same way as the static information
423          * so that we can use the index of the latter to find the former. For
424          * the other way around and for obtaining the owner cell, we use more
425          * handy pointers. The cell pointer also encodes active ownership.
426          */
427         for (ndev = 0; ndev < cell->config->num_pci_devices; ndev++) {
428                 device = &cell->pci_devices[ndev];
429                 device->info = &dev_infos[ndev];
430
431                 root_device = pci_get_assigned_device(&root_cell,
432                                                       dev_infos[ndev].bdf);
433                 if (root_device) {
434                         pci_remove_device(root_device);
435                         root_device->cell = NULL;
436                 }
437
438                 err = pci_add_device(cell, device);
439                 if (err) {
440                         pci_cell_exit(cell);
441                         return err;
442                 }
443
444                 device->cell = cell;
445
446                 for_each_pci_cap(cap, device, ncap)
447                         if (cap->id == PCI_CAP_MSI)
448                                 pci_save_msi(device, cap);
449                         else if (cap->id == PCI_CAP_MSIX)
450                                 // TODO: Handle
451                                 printk("MSI-X left out @%02x:%02x.%x!\n",
452                                        PCI_BDF_PARAMS(device->info->bdf));
453         }
454
455         if (cell == &root_cell)
456                 pci_prepare_handover();
457
458         return 0;
459 }
460
461 static void pci_return_device_to_root_cell(struct pci_device *device)
462 {
463         struct pci_device *root_device;
464
465         for_each_configured_pci_device(root_device, &root_cell)
466                 if (root_device->info->domain == device->info->domain &&
467                     root_device->info->bdf == device->info->bdf) {
468                         if (pci_add_device(&root_cell, root_device) < 0)
469                                 printk("WARNING: Failed to re-assign PCI "
470                                        "device to root cell\n");
471                         else
472                                 root_device->cell = &root_cell;
473                         break;
474                 }
475 }
476
477 void pci_cell_exit(struct cell *cell)
478 {
479         unsigned long array_size = PAGE_ALIGN(cell->config->num_pci_devices *
480                                               sizeof(struct pci_device));
481         struct pci_device *device;
482
483         /*
484          * Do not destroy the root cell. We will shut down the complete
485          * hypervisor instead.
486          */
487         if (cell == &root_cell)
488                 return;
489
490         for_each_configured_pci_device(device, cell)
491                 if (device->cell) {
492                         pci_remove_device(device);
493                         pci_return_device_to_root_cell(device);
494                 }
495
496         page_free(&mem_pool, cell->pci_devices, array_size / PAGE_SIZE);
497 }
498
499 void pci_config_commit(struct cell *cell_added_removed)
500 {
501         const struct jailhouse_pci_capability *cap;
502         struct pci_device *device;
503         unsigned int n;
504         int err = 0;
505
506         if (!cell_added_removed)
507                 return;
508
509         for_each_configured_pci_device(device, &root_cell)
510                 if (device->cell)
511                         for_each_pci_cap(cap, device, n) {
512                                 if (cap->id == PCI_CAP_MSI)
513                                         err = pci_update_msi(device, cap);
514                                 // TODO: MSI-X
515                                 if (err)
516                                         goto error;
517                         }
518         return;
519
520 error:
521         panic_printk("FATAL: Unsupported MSI/MSI-X state, device %02x:%02x.%x,"
522                      " cap %d\n", PCI_BDF_PARAMS(device->info->bdf), cap->id);
523         panic_stop(NULL);
524 }
525
526 void pci_shutdown(void)
527 {
528         const struct jailhouse_pci_capability *cap;
529         struct pci_device *device;
530         unsigned int n;
531
532         if (!root_cell.pci_devices)
533                 return;
534
535         for_each_configured_pci_device(device, &root_cell)
536                 if (device->cell)
537                         for_each_pci_cap(cap, device, n)
538                                 if (cap->id == PCI_CAP_MSI)
539                                         pci_restore_msi(device, cap);
540                                 // TODO: MSI-X
541 }