xen_pt.h (10479B)
1#ifndef XEN_PT_H 2#define XEN_PT_H 3 4#include "hw/xen/xen_common.h" 5#include "hw/pci/pci.h" 6#include "xen-host-pci-device.h" 7#include "qom/object.h" 8 9bool xen_igd_gfx_pt_enabled(void); 10void xen_igd_gfx_pt_set(bool value, Error **errp); 11 12void xen_pt_log(const PCIDevice *d, const char *f, ...) GCC_FMT_ATTR(2, 3); 13 14#define XEN_PT_ERR(d, _f, _a...) xen_pt_log(d, "%s: Error: "_f, __func__, ##_a) 15 16#ifdef XEN_PT_LOGGING_ENABLED 17# define XEN_PT_LOG(d, _f, _a...) xen_pt_log(d, "%s: " _f, __func__, ##_a) 18# define XEN_PT_WARN(d, _f, _a...) \ 19 xen_pt_log(d, "%s: Warning: "_f, __func__, ##_a) 20#else 21# define XEN_PT_LOG(d, _f, _a...) 22# define XEN_PT_WARN(d, _f, _a...) 23#endif 24 25#ifdef XEN_PT_DEBUG_PCI_CONFIG_ACCESS 26# define XEN_PT_LOG_CONFIG(d, addr, val, len) \ 27 xen_pt_log(d, "%s: address=0x%04x val=0x%08x len=%d\n", \ 28 __func__, addr, val, len) 29#else 30# define XEN_PT_LOG_CONFIG(d, addr, val, len) 31#endif 32 33 34/* Helper */ 35#define XEN_PFN(x) ((x) >> XC_PAGE_SHIFT) 36 37typedef const struct XenPTRegInfo XenPTRegInfo; 38typedef struct XenPTReg XenPTReg; 39 40 41#define TYPE_XEN_PT_DEVICE "xen-pci-passthrough" 42OBJECT_DECLARE_SIMPLE_TYPE(XenPCIPassthroughState, XEN_PT_DEVICE) 43 44uint32_t igd_read_opregion(XenPCIPassthroughState *s); 45void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val); 46 47/* function type for config reg */ 48typedef int (*xen_pt_conf_reg_init) 49 (XenPCIPassthroughState *, XenPTRegInfo *, uint32_t real_offset, 50 uint32_t *data); 51typedef int (*xen_pt_conf_dword_write) 52 (XenPCIPassthroughState *, XenPTReg *cfg_entry, 53 uint32_t *val, uint32_t dev_value, uint32_t valid_mask); 54typedef int (*xen_pt_conf_word_write) 55 (XenPCIPassthroughState *, XenPTReg *cfg_entry, 56 uint16_t *val, uint16_t dev_value, uint16_t valid_mask); 57typedef int (*xen_pt_conf_byte_write) 58 (XenPCIPassthroughState *, XenPTReg *cfg_entry, 59 uint8_t *val, uint8_t dev_value, uint8_t valid_mask); 60typedef int (*xen_pt_conf_dword_read) 61 (XenPCIPassthroughState *, XenPTReg *cfg_entry, 62 uint32_t *val, uint32_t valid_mask); 63typedef int (*xen_pt_conf_word_read) 64 (XenPCIPassthroughState *, XenPTReg *cfg_entry, 65 uint16_t *val, uint16_t valid_mask); 66typedef int (*xen_pt_conf_byte_read) 67 (XenPCIPassthroughState *, XenPTReg *cfg_entry, 68 uint8_t *val, uint8_t valid_mask); 69 70#define XEN_PT_BAR_ALLF 0xFFFFFFFF 71#define XEN_PT_BAR_UNMAPPED (-1) 72 73#define XEN_PCI_CAP_MAX 48 74 75#define XEN_PCI_INTEL_OPREGION 0xfc 76 77typedef enum { 78 XEN_PT_GRP_TYPE_HARDWIRED = 0, /* 0 Hardwired reg group */ 79 XEN_PT_GRP_TYPE_EMU, /* emul reg group */ 80} XenPTRegisterGroupType; 81 82typedef enum { 83 XEN_PT_BAR_FLAG_MEM = 0, /* Memory type BAR */ 84 XEN_PT_BAR_FLAG_IO, /* I/O type BAR */ 85 XEN_PT_BAR_FLAG_UPPER, /* upper 64bit BAR */ 86 XEN_PT_BAR_FLAG_UNUSED, /* unused BAR */ 87} XenPTBarFlag; 88 89 90typedef struct XenPTRegion { 91 /* BAR flag */ 92 XenPTBarFlag bar_flag; 93 /* Translation of the emulated address */ 94 union { 95 uint64_t maddr; 96 uint64_t pio_base; 97 uint64_t u; 98 } access; 99} XenPTRegion; 100 101/* XenPTRegInfo declaration 102 * - only for emulated register (either a part or whole bit). 103 * - for passthrough register that need special behavior (like interacting with 104 * other component), set emu_mask to all 0 and specify r/w func properly. 105 * - do NOT use ALL F for init_val, otherwise the tbl will not be registered. 106 */ 107 108/* emulated register information */ 109struct XenPTRegInfo { 110 uint32_t offset; 111 uint32_t size; 112 uint32_t init_val; 113 /* reg reserved field mask (ON:reserved, OFF:defined) */ 114 uint32_t res_mask; 115 /* reg read only field mask (ON:RO/ROS, OFF:other) */ 116 uint32_t ro_mask; 117 /* reg read/write-1-clear field mask (ON:RW1C/RW1CS, OFF:other) */ 118 uint32_t rw1c_mask; 119 /* reg emulate field mask (ON:emu, OFF:passthrough) */ 120 uint32_t emu_mask; 121 xen_pt_conf_reg_init init; 122 /* read/write function pointer 123 * for double_word/word/byte size */ 124 union { 125 struct { 126 xen_pt_conf_dword_write write; 127 xen_pt_conf_dword_read read; 128 } dw; 129 struct { 130 xen_pt_conf_word_write write; 131 xen_pt_conf_word_read read; 132 } w; 133 struct { 134 xen_pt_conf_byte_write write; 135 xen_pt_conf_byte_read read; 136 } b; 137 } u; 138}; 139 140/* emulated register management */ 141struct XenPTReg { 142 QLIST_ENTRY(XenPTReg) entries; 143 XenPTRegInfo *reg; 144 union { 145 uint8_t *byte; 146 uint16_t *half_word; 147 uint32_t *word; 148 } ptr; /* pointer to dev.config. */ 149}; 150 151typedef const struct XenPTRegGroupInfo XenPTRegGroupInfo; 152 153/* emul reg group size initialize method */ 154typedef int (*xen_pt_reg_size_init_fn) 155 (XenPCIPassthroughState *, XenPTRegGroupInfo *, 156 uint32_t base_offset, uint8_t *size); 157 158/* emulated register group information */ 159struct XenPTRegGroupInfo { 160 uint8_t grp_id; 161 XenPTRegisterGroupType grp_type; 162 uint8_t grp_size; 163 xen_pt_reg_size_init_fn size_init; 164 XenPTRegInfo *emu_regs; 165}; 166 167/* emul register group management table */ 168typedef struct XenPTRegGroup { 169 QLIST_ENTRY(XenPTRegGroup) entries; 170 XenPTRegGroupInfo *reg_grp; 171 uint32_t base_offset; 172 uint8_t size; 173 QLIST_HEAD(, XenPTReg) reg_tbl_list; 174} XenPTRegGroup; 175 176 177#define XEN_PT_UNASSIGNED_PIRQ (-1) 178typedef struct XenPTMSI { 179 uint16_t flags; 180 uint32_t addr_lo; /* guest message address */ 181 uint32_t addr_hi; /* guest message upper address */ 182 uint16_t data; /* guest message data */ 183 uint32_t ctrl_offset; /* saved control offset */ 184 uint32_t mask; /* guest mask bits */ 185 int pirq; /* guest pirq corresponding */ 186 bool initialized; /* when guest MSI is initialized */ 187 bool mapped; /* when pirq is mapped */ 188} XenPTMSI; 189 190typedef struct XenPTMSIXEntry { 191 int pirq; 192 uint64_t addr; 193 uint32_t data; 194 uint32_t latch[4]; 195 bool updated; /* indicate whether MSI ADDR or DATA is updated */ 196} XenPTMSIXEntry; 197typedef struct XenPTMSIX { 198 uint32_t ctrl_offset; 199 bool enabled; 200 bool maskall; 201 int total_entries; 202 int bar_index; 203 uint64_t table_base; 204 uint32_t table_offset_adjust; /* page align mmap */ 205 uint64_t mmio_base_addr; 206 MemoryRegion mmio; 207 void *phys_iomem_base; 208 XenPTMSIXEntry msix_entry[]; 209} XenPTMSIX; 210 211struct XenPCIPassthroughState { 212 PCIDevice dev; 213 214 PCIHostDeviceAddress hostaddr; 215 bool is_virtfn; 216 bool permissive; 217 bool permissive_warned; 218 XenHostPCIDevice real_device; 219 XenPTRegion bases[PCI_NUM_REGIONS]; /* Access regions */ 220 QLIST_HEAD(, XenPTRegGroup) reg_grps; 221 222 uint32_t machine_irq; 223 224 XenPTMSI *msi; 225 XenPTMSIX *msix; 226 227 MemoryRegion bar[PCI_NUM_REGIONS - 1]; 228 MemoryRegion rom; 229 230 MemoryListener memory_listener; 231 MemoryListener io_listener; 232 bool listener_set; 233}; 234 235void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp); 236void xen_pt_config_delete(XenPCIPassthroughState *s); 237XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address); 238XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address); 239int xen_pt_bar_offset_to_index(uint32_t offset); 240 241static inline pcibus_t xen_pt_get_emul_size(XenPTBarFlag flag, pcibus_t r_size) 242{ 243 /* align resource size (memory type only) */ 244 if (flag == XEN_PT_BAR_FLAG_MEM) { 245 return (r_size + XC_PAGE_SIZE - 1) & XC_PAGE_MASK; 246 } else { 247 return r_size; 248 } 249} 250 251/* INTx */ 252/* The PCI Local Bus Specification, Rev. 3.0, 253 * Section 6.2.4 Miscellaneous Registers, pp 223 254 * outlines 5 valid values for the interrupt pin (intx). 255 * 0: For devices (or device functions) that don't use an interrupt in 256 * 1: INTA# 257 * 2: INTB# 258 * 3: INTC# 259 * 4: INTD# 260 * 261 * Xen uses the following 4 values for intx 262 * 0: INTA# 263 * 1: INTB# 264 * 2: INTC# 265 * 3: INTD# 266 * 267 * Observing that these list of values are not the same, xen_pt_pci_read_intx() 268 * uses the following mapping from hw to xen values. 269 * This seems to reflect the current usage within Xen. 270 * 271 * PCI hardware | Xen | Notes 272 * ----------------+-----+---------------------------------------------------- 273 * 0 | 0 | No interrupt 274 * 1 | 0 | INTA# 275 * 2 | 1 | INTB# 276 * 3 | 2 | INTC# 277 * 4 | 3 | INTD# 278 * any other value | 0 | This should never happen, log error message 279 */ 280 281static inline uint8_t xen_pt_pci_read_intx(XenPCIPassthroughState *s) 282{ 283 uint8_t v = 0; 284 xen_host_pci_get_byte(&s->real_device, PCI_INTERRUPT_PIN, &v); 285 return v; 286} 287 288static inline uint8_t xen_pt_pci_intx(XenPCIPassthroughState *s) 289{ 290 uint8_t r_val = xen_pt_pci_read_intx(s); 291 292 XEN_PT_LOG(&s->dev, "intx=%i\n", r_val); 293 if (r_val < 1 || r_val > 4) { 294 XEN_PT_LOG(&s->dev, "Interrupt pin read from hardware is out of range:" 295 " value=%i, acceptable range is 1 - 4\n", r_val); 296 r_val = 0; 297 } else { 298 /* Note that if s.real_device.config_fd is closed we make 0xff. */ 299 r_val -= 1; 300 } 301 302 return r_val; 303} 304 305/* MSI/MSI-X */ 306int xen_pt_msi_setup(XenPCIPassthroughState *s); 307int xen_pt_msi_update(XenPCIPassthroughState *d); 308void xen_pt_msi_disable(XenPCIPassthroughState *s); 309 310int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base); 311void xen_pt_msix_delete(XenPCIPassthroughState *s); 312void xen_pt_msix_unmap(XenPCIPassthroughState *s); 313int xen_pt_msix_update(XenPCIPassthroughState *s); 314int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index); 315void xen_pt_msix_disable(XenPCIPassthroughState *s); 316 317static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar) 318{ 319 return s->msix && s->msix->bar_index == bar; 320} 321 322extern void *pci_assign_dev_load_option_rom(PCIDevice *dev, 323 int *size, 324 unsigned int domain, 325 unsigned int bus, unsigned int slot, 326 unsigned int function); 327static inline bool is_igd_vga_passthrough(XenHostPCIDevice *dev) 328{ 329 return (xen_igd_gfx_pt_enabled() 330 && ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA)); 331} 332int xen_pt_register_vga_regions(XenHostPCIDevice *dev); 333int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev); 334void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev, 335 Error **errp); 336#endif /* XEN_PT_H */