2 * Jailhouse, a Linux-based partitioning hypervisor
4 * Copyright (c) Siemens AG, 2014
7 * Ivan Kolchin <ivan.kolchin@siemens.com>
8 * Jan Kiszka <jan.kiszka@siemens.com>
10 * This work is licensed under the terms of the GNU GPL, version 2. See
11 * the COPYING file in the top-level directory.
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>
20 #define PCI_CONFIG_HEADER_SIZE 0x40
22 #define PCI_CFG_COMMAND 0x04
23 # define PCI_CMD_INTX_OFF (1 << 10)
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; \
30 /* entry for PCI config space whitelist (granting access) */
31 struct pci_cfg_access {
32 u32 reg_num; /** Register number (4-byte aligned) */
33 u32 mask; /** Bit set: access allowed */
36 /* --- Whilelist for writing to PCI config space registers --- */
37 /* Type 1: Endpoints */
38 static const struct pci_cfg_access endpoint_write_access[] = {
39 { 0x04, 0xffffffff }, /* Command, Status */
40 { 0x0c, 0xff00ffff }, /* BIST, Latency Timer, Cacheline */
41 { 0x3c, 0x000000ff }, /* Int Line */
44 static const struct pci_cfg_access bridge_write_access[] = {
45 { 0x04, 0xffffffff }, /* Command, Status */
46 { 0x0c, 0xff00ffff }, /* BIST, Latency Timer, Cacheline */
47 { 0x3c, 0xffff00ff }, /* Int Line, Bridge Control */
50 static void *pci_space;
51 static u64 mmcfg_start, mmcfg_end;
54 static void *pci_get_device_mmcfg_base(u16 bdf)
56 return pci_space + ((unsigned long)bdf << 12);
60 * pci_read_config() - Read from PCI config space
61 * @bdf: 16-bit bus/device/function ID of target
62 * @address: Config space access address
63 * @size: Access size (1, 2 or 4 bytes)
67 u32 pci_read_config(u16 bdf, u16 address, unsigned int size)
69 void *mmcfg_addr = pci_get_device_mmcfg_base(bdf) + address;
71 if (!pci_space || PCI_BUS(bdf) > end_bus)
72 return arch_pci_read_config(bdf, address, size);
75 return mmio_read8(mmcfg_addr);
77 return mmio_read16(mmcfg_addr);
79 return mmio_read32(mmcfg_addr);
83 * pci_write_config() - Write to PCI config space
84 * @bdf: 16-bit bus/device/function ID of target
85 * @address: Config space access address
86 * @value: Value to be written
87 * @size: Access size (1, 2 or 4 bytes)
89 void pci_write_config(u16 bdf, u16 address, u32 value, unsigned int size)
91 void *mmcfg_addr = pci_get_device_mmcfg_base(bdf) + address;
93 if (!pci_space || PCI_BUS(bdf) > end_bus)
94 return arch_pci_write_config(bdf, address, value, size);
97 mmio_write8(mmcfg_addr, value);
99 mmio_write16(mmcfg_addr, value);
101 mmio_write32(mmcfg_addr, value);
105 * pci_get_assigned_device() - Look up device owned by a cell
107 * @bdf: 16-bit bus/device/function ID
109 * Return: Pointer to owned PCI device or NULL.
111 struct pci_device *pci_get_assigned_device(const struct cell *cell, u16 bdf)
113 const struct jailhouse_pci_device *dev_info =
114 jailhouse_cell_pci_devices(cell->config);
117 /* We iterate over the static device information to increase cache
119 for (n = 0; n < cell->config->num_pci_devices; n++)
120 if (dev_info[n].bdf == bdf)
121 return cell->pci_devices[n].cell ?
122 &cell->pci_devices[n] : NULL;
128 * pci_find_capability() - Look up capability at given config space address
129 * @device: The device to be accessed
130 * @address: Config space access address
132 * Return: Corresponding capability structure or NULL if none found.
134 static const struct jailhouse_pci_capability *
135 pci_find_capability(struct pci_device *device, u16 address)
137 const struct jailhouse_pci_capability *cap =
138 jailhouse_cell_pci_caps(device->cell->config) +
139 device->info->caps_start;
142 for (n = 0; n < device->info->num_caps; n++, cap++)
143 if (cap->start <= address && cap->start + cap->len > address)
150 * pci_cfg_read_moderate() - Moderate config space read access
151 * @device: The device to be accessed; if NULL, access will be emulated,
152 * returning a value of -1
153 * @address: Config space address
154 * @size: Access size (1, 2 or 4 bytes)
155 * @value: Pointer to buffer to receive the emulated value if
156 * PCI_ACCESS_DONE is returned
158 * Return: PCI_ACCESS_PERFORM or PCI_ACCESS_DONE.
160 enum pci_access pci_cfg_read_moderate(struct pci_device *device, u16 address,
161 unsigned int size, u32 *value)
163 const struct jailhouse_pci_capability *cap;
167 return PCI_ACCESS_DONE;
170 if (address < PCI_CONFIG_HEADER_SIZE)
171 return PCI_ACCESS_PERFORM;
173 cap = pci_find_capability(device, address);
175 return PCI_ACCESS_PERFORM;
177 // TODO: Emulate MSI/MSI-X etc.
179 return PCI_ACCESS_PERFORM;
183 * pci_cfg_write_moderate() - Moderate config space write access
184 * @device: The device to be accessed; if NULL, access will be rejected
185 * @address: Config space address
186 * @size: Access size (1, 2 or 4 bytes)
187 * @value: Value to be written
189 * Return: PCI_ACCESS_REJECT, PCI_ACCESS_PERFORM or PCI_ACCESS_DONE.
191 enum pci_access pci_cfg_write_moderate(struct pci_device *device, u16 address,
192 unsigned int size, u32 value)
194 const struct jailhouse_pci_capability *cap;
195 /* initialize list to work around wrong compiler warning */
196 const struct pci_cfg_access *list = NULL;
197 unsigned int n, bias_shift, len = 0;
201 return PCI_ACCESS_REJECT;
203 if (address < PCI_CONFIG_HEADER_SIZE) {
204 if (device->info->type == JAILHOUSE_PCI_TYPE_DEVICE) {
205 list = endpoint_write_access;
206 len = ARRAY_SIZE(endpoint_write_access);
207 } else if (device->info->type == JAILHOUSE_PCI_TYPE_BRIDGE) {
208 list = bridge_write_access;
209 len = ARRAY_SIZE(bridge_write_access);
212 bias_shift = (address & 0x003) * 8;
213 mask = BYTE_MASK(size);
215 for (n = 0; n < len; n++) {
216 if (list[n].reg_num == (address & 0xffc) &&
217 ((list[n].mask >> bias_shift) & mask) == mask)
218 return PCI_ACCESS_PERFORM;
221 return PCI_ACCESS_REJECT;
224 cap = pci_find_capability(device, address);
225 if (!cap || !(cap->flags & JAILHOUSE_PCICAPS_WRITE))
226 return PCI_ACCESS_REJECT;
228 return PCI_ACCESS_PERFORM;
232 * pci_init() - Initialization of PCI module
234 * Return: 0 - success, error code - if error.
238 unsigned int mmcfg_size;
241 err = pci_cell_init(&root_cell);
245 mmcfg_start = system_config->platform_info.x86.mmconfig_base;
246 if (mmcfg_start == 0)
249 end_bus = system_config->platform_info.x86.mmconfig_end_bus;
250 mmcfg_size = (end_bus + 1) * 256 * 4096;
251 mmcfg_end = mmcfg_start + mmcfg_size - 4;
253 pci_space = page_alloc(&remap_pool, mmcfg_size / PAGE_SIZE);
257 return page_map_create(&hv_paging_structs, mmcfg_start, mmcfg_size,
258 (unsigned long)pci_space,
259 PAGE_DEFAULT_FLAGS | PAGE_FLAG_UNCACHED,
260 PAGE_MAP_NON_COHERENT);
264 * pci_mmio_access_handler() - Handler for MMIO-accesses to PCI config space
265 * @cell: Request issuing cell
266 * @is_write: True if write access
267 * @addr: Address accessed
268 * @value: Pointer to value for reading/writing
270 * Return: 1 if handled successfully, 0 if unhandled, -1 on access error
272 int pci_mmio_access_handler(const struct cell *cell, bool is_write,
273 u64 addr, u32 *value)
275 u32 mmcfg_offset, reg_addr;
276 struct pci_device *device;
277 enum pci_access access;
279 if (!pci_space || addr < mmcfg_start || addr > mmcfg_end)
282 mmcfg_offset = addr - mmcfg_start;
283 reg_addr = mmcfg_offset & 0xfff;
284 /* access must be DWORD-aligned */
288 device = pci_get_assigned_device(cell, mmcfg_offset >> 12);
291 access = pci_cfg_write_moderate(device, reg_addr, 4, *value);
292 if (access == PCI_ACCESS_REJECT)
294 if (access == PCI_ACCESS_PERFORM)
295 mmio_write32(pci_space + mmcfg_offset, *value);
297 access = pci_cfg_read_moderate(device, reg_addr, 4, value);
298 if (access == PCI_ACCESS_PERFORM)
299 *value = mmio_read32(pci_space + mmcfg_offset);
305 panic_printk("FATAL: Invalid PCI MMCONFIG write, device %02x:%02x.%x, "
306 "reg: %\n", PCI_BDF_PARAMS(mmcfg_offset >> 12), reg_addr);
311 static int pci_add_device(struct cell *cell, struct pci_device *device)
313 printk("Adding PCI device %02x:%02x.%x to cell \"%s\"\n",
314 PCI_BDF_PARAMS(device->info->bdf), cell->config->name);
315 return arch_pci_add_device(cell, device);
318 static void pci_remove_device(struct pci_device *device)
320 printk("Removing PCI device %02x:%02x.%x from cell \"%s\"\n",
321 PCI_BDF_PARAMS(device->info->bdf), device->cell->config->name);
322 arch_pci_remove_device(device);
323 pci_write_config(device->info->bdf, PCI_CFG_COMMAND,
324 PCI_CMD_INTX_OFF, 2);
327 int pci_cell_init(struct cell *cell)
329 unsigned long array_size = PAGE_ALIGN(cell->config->num_pci_devices *
330 sizeof(struct pci_device));
331 const struct jailhouse_pci_device *dev_infos =
332 jailhouse_cell_pci_devices(cell->config);
333 struct pci_device *device, *root_device;
337 cell->pci_devices = page_alloc(&mem_pool, array_size / PAGE_SIZE);
338 if (!cell->pci_devices)
342 * We order device states in the same way as the static information
343 * so that we can use the index of the latter to find the former. For
344 * the other way around and for obtaining the owner cell, we use more
345 * handy pointers. The cell pointer also encodes active ownership.
347 for (ndev = 0; ndev < cell->config->num_pci_devices; ndev++) {
348 device = &cell->pci_devices[ndev];
349 device->info = &dev_infos[ndev];
351 root_device = pci_get_assigned_device(&root_cell,
352 dev_infos[ndev].bdf);
354 pci_remove_device(root_device);
355 root_device->cell = NULL;
358 err = pci_add_device(cell, device);
370 static void pci_return_device_to_root_cell(struct pci_device *device)
372 struct pci_device *root_device;
374 for_each_configured_pci_device(root_device, &root_cell)
375 if (root_device->info->domain == device->info->domain &&
376 root_device->info->bdf == device->info->bdf) {
377 if (pci_add_device(&root_cell, root_device) < 0)
378 printk("WARNING: Failed to re-assign PCI "
379 "device to root cell\n");
381 root_device->cell = &root_cell;
386 void pci_cell_exit(struct cell *cell)
388 unsigned long array_size = PAGE_ALIGN(cell->config->num_pci_devices *
389 sizeof(struct pci_device));
390 struct pci_device *device;
393 * Do not destroy the root cell. We will shut down the complete
394 * hypervisor instead.
396 if (cell == &root_cell)
399 for_each_configured_pci_device(device, cell) {
402 pci_remove_device(device);
403 pci_return_device_to_root_cell(device);
406 page_free(&mem_pool, cell->pci_devices, array_size / PAGE_SIZE);