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/acpi.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 struct acpi_mcfg_alloc {
28 } __attribute__((packed));
30 struct acpi_mcfg_table {
31 struct acpi_table_header header;
33 struct acpi_mcfg_alloc alloc_structs[];
34 } __attribute__((packed));
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 */
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 */
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 */
56 static void *pci_space;
57 static u64 pci_mmcfg_addr;
58 static u32 pci_mmcfg_size;
61 static void *pci_get_device_mmcfg_base(u16 bdf)
63 return pci_space + ((unsigned long)bdf << 12);
67 * pci_read_config() - Read from PCI config space
68 * @bdf: 16-bit bus/device/function ID of target
69 * @address: Config space access address
70 * @size: Access size (1, 2 or 4 bytes)
74 u32 pci_read_config(u16 bdf, u16 address, unsigned int size)
76 void *mmcfg_addr = pci_get_device_mmcfg_base(bdf) + address;
78 if (!pci_space || PCI_BUS(bdf) > end_bus)
79 return arch_pci_read_config(bdf, address, size);
82 return mmio_read8(mmcfg_addr);
84 return mmio_read16(mmcfg_addr);
86 return mmio_read32(mmcfg_addr);
90 * pci_write_config() - Write to PCI config space
91 * @bdf: 16-bit bus/device/function ID of target
92 * @address: Config space access address
93 * @value: Value to be written
94 * @size: Access size (1, 2 or 4 bytes)
96 void pci_write_config(u16 bdf, u16 address, u32 value, unsigned int size)
98 void *mmcfg_addr = pci_get_device_mmcfg_base(bdf) + address;
100 if (!pci_space || PCI_BUS(bdf) > end_bus)
101 return arch_pci_write_config(bdf, address, value, size);
104 mmio_write8(mmcfg_addr, value);
106 mmio_write16(mmcfg_addr, value);
108 mmio_write32(mmcfg_addr, value);
112 * pci_get_assigned_device() - Look up device owned by a cell
114 * @bdf: 16-bit bus/device/function ID
116 * Return: Valid pointer - owns, NULL - doesn't own.
118 const struct jailhouse_pci_device *
119 pci_get_assigned_device(const struct cell *cell, u16 bdf)
121 const struct jailhouse_pci_device *device =
122 jailhouse_cell_pci_devices(cell->config);
125 for (n = 0; n < cell->config->num_pci_devices; n++)
126 if (device[n].bdf == bdf)
133 * pci_find_capability() - Look up capability at given config space address
134 * @cell: Device owning cell
135 * @device: The device to be accessed
136 * @address: Config space access address
138 * Return: Corresponding capability structure or NULL if none found.
140 static const struct jailhouse_pci_capability *
141 pci_find_capability(const struct cell *cell,
142 const struct jailhouse_pci_device *device, u16 address)
144 const struct jailhouse_pci_capability *cap =
145 jailhouse_cell_pci_caps(cell->config) + device->caps_start;
148 for (n = 0; n < device->num_caps; n++, cap++)
149 if (cap->start <= address && cap->start + cap->len > address)
156 * pci_cfg_read_moderate() - Moderate config space read access
157 * @cell: Request issuing cell
158 * @device: The device to be accessed; if NULL, access will be emulated,
159 * returning a value of -1
160 * @address: Config space address
161 * @size: Access size (1, 2 or 4 bytes)
162 * @value: Pointer to buffer to receive the emulated value if
163 * PCI_ACCESS_EMULATE is returned
165 * Return: PCI_ACCESS_PERFORM or PCI_ACCESS_EMULATE.
168 pci_cfg_read_moderate(const struct cell *cell,
169 const struct jailhouse_pci_device *device, u16 address,
170 unsigned int size, u32 *value)
172 const struct jailhouse_pci_capability *cap;
176 return PCI_ACCESS_EMULATE;
179 if (address < PCI_CONFIG_HEADER_SIZE)
180 return PCI_ACCESS_PERFORM;
182 cap = pci_find_capability(cell, device, address);
184 return PCI_ACCESS_PERFORM;
186 // TODO: Emulate MSI/MSI-X etc.
188 return PCI_ACCESS_PERFORM;
192 * pci_cfg_write_moderate() - Moderate config space write access
193 * @cell: Request issuing cell
194 * @device: The device to be accessed; if NULL, access will be rejected
195 * @address: Config space address
196 * @size: Access size (1, 2 or 4 bytes)
197 * @value: Value to be written
199 * Return: PCI_ACCESS_REJECT, PCI_ACCESS_PERFORM or PCI_ACCESS_EMULATE.
202 pci_cfg_write_moderate(const struct cell *cell,
203 const struct jailhouse_pci_device *device, u16 address,
204 unsigned int size, u32 value)
206 const struct jailhouse_pci_capability *cap;
207 /* initialize list to work around wrong compiler warning */
208 const struct pci_cfg_access *list = NULL;
209 unsigned int n, bias_shift, len = 0;
213 return PCI_ACCESS_REJECT;
215 if (address < PCI_CONFIG_HEADER_SIZE) {
216 if (device->type == JAILHOUSE_PCI_TYPE_DEVICE) {
217 list = endpoint_write_access;
218 len = ARRAY_SIZE(endpoint_write_access);
219 } else if (device->type == JAILHOUSE_PCI_TYPE_BRIDGE) {
220 list = bridge_write_access;
221 len = ARRAY_SIZE(bridge_write_access);
224 bias_shift = (address & 0x003) * 8;
225 mask = BYTE_MASK(size);
227 for (n = 0; n < len; n++) {
228 if (list[n].reg_num == (address & 0xffc) &&
229 ((list[n].mask >> bias_shift) & mask) == mask)
230 return PCI_ACCESS_PERFORM;
233 return PCI_ACCESS_REJECT;
236 cap = pci_find_capability(cell, device, address);
237 if (!cap || !(cap->flags & JAILHOUSE_PCICAPS_WRITE))
238 return PCI_ACCESS_REJECT;
240 return PCI_ACCESS_PERFORM;
244 * pci_init() - Initialization of PCI module
246 * Return: 0 - success, error code - if error.
250 struct acpi_mcfg_table *mcfg;
252 mcfg = (struct acpi_mcfg_table *)acpi_find_table("MCFG", NULL);
256 if (mcfg->header.length !=
257 sizeof(struct acpi_mcfg_table) + sizeof(struct acpi_mcfg_alloc))
260 pci_mmcfg_addr = mcfg->alloc_structs[0].base_addr;
261 pci_mmcfg_size = (mcfg->alloc_structs[0].end_bus + 1) * 256 * 4096;
262 pci_space = page_alloc(&remap_pool, pci_mmcfg_size / PAGE_SIZE);
266 end_bus = mcfg->alloc_structs[0].end_bus;
268 return page_map_create(&hv_paging_structs,
269 mcfg->alloc_structs[0].base_addr,
270 pci_mmcfg_size, (unsigned long)pci_space,
271 PAGE_DEFAULT_FLAGS | PAGE_FLAG_UNCACHED,
272 PAGE_MAP_NON_COHERENT);
276 * pci_mmio_access_handler() - Handler for MMIO-accesses to PCI config space
277 * @cell: Request issuing cell
278 * @is_write: True if write access
279 * @addr: Address accessed
280 * @value: Pointer to value for reading/writing
282 * Return: 1 if handled successfully, 0 if unhandled, -1 on access error
284 int pci_mmio_access_handler(const struct cell *cell, bool is_write,
285 u64 addr, u32 *value)
287 const struct jailhouse_pci_device *device;
288 u32 mmcfg_offset, reg_addr;
289 enum pci_access access;
291 if (!pci_space || addr < pci_mmcfg_addr ||
292 addr >= (pci_mmcfg_addr + pci_mmcfg_size - 4))
295 mmcfg_offset = addr - pci_mmcfg_addr;
296 reg_addr = mmcfg_offset & 0xfff;
297 device = pci_get_assigned_device(cell, mmcfg_offset >> 12);
300 access = pci_cfg_write_moderate(cell, device, reg_addr, 4,
302 if (access == PCI_ACCESS_REJECT)
304 mmio_write32(pci_space + mmcfg_offset, *value);
306 access = pci_cfg_read_moderate(cell, device, reg_addr, 4,
308 if (access == PCI_ACCESS_PERFORM)
309 *value = mmio_read32(pci_space + mmcfg_offset);
315 panic_printk("FATAL: Invalid PCI MMCONFIG write, device %02x:%02x.%x, "
316 "reg: %\n", PCI_BDF_PARAMS(mmcfg_offset >> 12), reg_addr);