2 * Jailhouse, a Linux-based partitioning hypervisor
4 * Copyright (c) Siemens AG, 2014
7 * Ivan Kolchin <ivan.kolchin@siemens.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
13 #include <jailhouse/acpi.h>
14 #include <jailhouse/pci.h>
15 #include <jailhouse/printk.h>
16 #include <jailhouse/utils.h>
18 struct acpi_mcfg_alloc {
24 } __attribute__((packed));
26 struct acpi_mcfg_table {
27 struct acpi_table_header header;
29 struct acpi_mcfg_alloc alloc_structs[];
30 } __attribute__((packed));
32 /* entry for PCI config space whitelist (granting access) */
33 struct pci_cfg_access {
34 u32 reg_num; /** Register number (4-byte aligned) */
35 u32 mask; /** Bit set: access allowed */
38 /* --- Whilelist for writing to PCI config space registers --- */
39 /* Type 1: Endpoints */
40 static const struct pci_cfg_access endpoint_write_access[] = {
41 { 0x04, 0xffffffff }, /* Command, Status */
42 { 0x0c, 0xff000000 }, /* BIST */
43 { 0x3c, 0x000000ff }, /* Int Line */
46 static const struct pci_cfg_access bridge_write_access[] = {
47 { 0x04, 0xffffffff }, /* Command, Status */
48 { 0x0c, 0xff000000 }, /* BIST */
49 { 0x3c, 0xffff00ff }, /* Int Line, Bridge Control */
52 static void *pci_space;
53 static u64 pci_mmcfg_addr;
54 static u32 pci_mmcfg_size;
57 * pci_get_assigned_device() - Look up device owned by a cell
59 * @bdf: 16-bit bus/device/function ID
61 * Return: Valid pointer - owns, NULL - doesn't own.
63 const struct jailhouse_pci_device *
64 pci_get_assigned_device(const struct cell *cell, u16 bdf)
66 const struct jailhouse_pci_device *device =
67 jailhouse_cell_pci_devices(cell->config);
70 for (n = 0; n < cell->config->num_pci_devices; n++)
71 if (((device[n].bus << 8) | device[n].devfn) == bdf)
78 * pci_cfg_write_allowed() - Check general config space write permission
79 * @type: JAILHOUSE_PCI_TYPE_DEVICE or JAILHOUSE_PCI_TYPE_BRIDGE
80 * @reg_num: Register number (4-byte aligned)
81 * @bias: Bias from register base address in bytes
82 * @size: Access size (1, 2 or 4 bytes)
84 * Return: True if writing is allowed, false otherwise.
86 bool pci_cfg_write_allowed(u32 type, u8 reg_num, unsigned int reg_bias,
89 /* initialize list to work around wrong compiler warning */
90 const struct pci_cfg_access *list = NULL;
91 unsigned int n, len = 0;
93 if (type == JAILHOUSE_PCI_TYPE_DEVICE) {
94 list = endpoint_write_access;
95 len = ARRAY_SIZE(endpoint_write_access);
96 } else if (type == JAILHOUSE_PCI_TYPE_BRIDGE) {
97 list = bridge_write_access;
98 len = ARRAY_SIZE(bridge_write_access);
101 for (n = 0; n < len; n++)
102 if (list[n].reg_num == reg_num)
103 return ((list[n].mask >> (reg_bias * 8)) &
104 BYTE_MASK(size)) == BYTE_MASK(size);
110 * pci_init() - Initialization of PCI module
112 * Return: 0 - success, error code - if error.
116 struct acpi_mcfg_table *mcfg;
118 mcfg = (struct acpi_mcfg_table *)acpi_find_table("MCFG", NULL);
122 if (mcfg->header.length !=
123 sizeof(struct acpi_mcfg_table) + sizeof(struct acpi_mcfg_alloc))
126 pci_mmcfg_addr = mcfg->alloc_structs[0].base_addr;
127 pci_mmcfg_size = (mcfg->alloc_structs[0].end_bus -
128 mcfg->alloc_structs[0].start_bus) * 256 * 4096;
129 pci_space = page_alloc(&remap_pool, pci_mmcfg_size / PAGE_SIZE);
131 page_map_create(&hv_paging_structs,
132 mcfg->alloc_structs[0].base_addr,
133 pci_mmcfg_size, (unsigned long)pci_space,
134 PAGE_DEFAULT_FLAGS | PAGE_FLAG_UNCACHED,
135 PAGE_MAP_NON_COHERENT);
141 * pci_mmio_access_handler() - Handler for MMIO-accesses to PCI config space
142 * @cell: Request issuing cell
143 * @is_write: True if write access
144 * @addr: Address accessed
145 * @value: Value to write (for write operations only)
147 * Return: 1 if handled successfully, 0 if unhandled, -1 on access error
149 int pci_mmio_access_handler(struct registers *guest_regs,
150 const struct cell *cell, bool is_write,
153 const struct jailhouse_pci_device *device;
158 if (addr < pci_mmcfg_addr ||
159 addr >= (pci_mmcfg_addr + pci_mmcfg_size - 4))
162 mmcfg_offset = addr - pci_mmcfg_addr;
163 reg_bias = mmcfg_offset % 4;
164 reg_num = mmcfg_offset & 0xfff;
165 device = pci_get_assigned_device(cell, mmcfg_offset >> 12);
171 if (reg_num < PCI_CONFIG_HEADER_SIZE)
172 if (pci_cfg_write_allowed(device->type,
173 (reg_num - reg_bias),
175 *(volatile u32 *)(pci_space + mmcfg_offset) =
176 ((u64 *)guest_regs)[reg];
179 ((u64 *)guest_regs)[reg] =
180 *(volatile u32 *)(pci_space + mmcfg_offset);
182 ((u64 *)guest_regs)[reg] = BYTE_MASK(4);