qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

xen_pt.h (10617B)


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