cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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 */