📄 pass-through.c
字号:
/* * Copyright (c) 2007, Neocleus Corporation. * Copyright (c) 2007, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. * * Alex Novik <alex@neocleus.com> * Allen Kay <allen.m.kay@intel.com> * Guy Zana <guy@neocleus.com> * * This file implements direct PCI assignment to a HVM guest */#include "vl.h"#include "pass-through.h"#include "pci/header.h"#include "pci/pci.h"#include "pt-msi.h"extern FILE *logfile;struct php_dev { struct pt_dev *pt_dev; uint8_t valid; uint8_t r_bus; uint8_t r_dev; uint8_t r_func;};struct dpci_infos { struct php_dev php_devs[PHP_SLOT_LEN]; PCIBus *e_bus; struct pci_access *pci_access;} dpci_infos;/* prototype */static uint32_t pt_common_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset);static uint32_t pt_ptr_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset);static uint32_t pt_status_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset);static uint32_t pt_irqpin_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset);static uint32_t pt_bar_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset);static uint32_t pt_linkctrl2_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset);static uint32_t pt_msgctrl_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset);static uint32_t pt_msgaddr32_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset);static uint32_t pt_msgaddr64_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset);static uint32_t pt_msgdata_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset);static uint32_t pt_msixctrl_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset);static uint8_t pt_reg_grp_size_init(struct pt_dev *ptdev, struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset);static uint8_t pt_msi_size_init(struct pt_dev *ptdev, struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset);static uint8_t pt_msix_size_init(struct pt_dev *ptdev, struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset);static uint8_t pt_vendor_size_init(struct pt_dev *ptdev, struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset);static int pt_byte_reg_read(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint8_t *valueu, uint8_t valid_mask);static int pt_word_reg_read(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint16_t *value, uint16_t valid_mask);static int pt_long_reg_read(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint32_t *value, uint32_t valid_mask);static int pt_bar_reg_read(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint32_t *value, uint32_t valid_mask);static int pt_byte_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint8_t *value, uint8_t dev_value, uint8_t valid_mask);static int pt_word_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint16_t *value, uint16_t dev_value, uint16_t valid_mask);static int pt_long_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint32_t *value, uint32_t dev_value, uint32_t valid_mask);static int pt_cmd_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint16_t *value, uint16_t dev_value, uint16_t valid_mask);static int pt_bar_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint32_t *value, uint32_t dev_value, uint32_t valid_mask);static int pt_exp_rom_bar_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint32_t *value, uint32_t dev_value, uint32_t valid_mask);static int pt_pmcsr_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint16_t *value, uint16_t dev_value, uint16_t valid_mask);static int pt_devctrl_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint16_t *value, uint16_t dev_value, uint16_t valid_mask);static int pt_linkctrl_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint16_t *value, uint16_t dev_value, uint16_t valid_mask);static int pt_devctrl2_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint16_t *value, uint16_t dev_value, uint16_t valid_mask);static int pt_linkctrl2_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint16_t *value, uint16_t dev_value, uint16_t valid_mask);static int pt_msgctrl_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint16_t *value, uint16_t dev_value, uint16_t valid_mask);static int pt_msgaddr32_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint32_t *value, uint32_t dev_value, uint32_t valid_mask);static int pt_msgaddr64_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint32_t *value, uint32_t dev_value, uint32_t valid_mask);static int pt_msgdata_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint16_t *value, uint16_t dev_value, uint16_t valid_mask);static int pt_msixctrl_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint16_t *value, uint16_t dev_value, uint16_t valid_mask);/* pt_reg_info_tbl declaration * - only for emulated register (either a part or whole bit). * - for passthrough register that need special behavior (like interacting with * other component), set emu_mask to all 0 and specify r/w func properly. * - do NOT use ALL F for init_val, otherwise the tbl will not be registered. */ /* Header Type0 reg static infomation table */static struct pt_reg_info_tbl pt_emu_reg_header0_tbl[] = { /* Command reg */ { .offset = PCI_COMMAND, .size = 2, .init_val = 0x0000, .ro_mask = 0xF880, .emu_mask = 0x0340, .init = pt_common_reg_init, .u.w.read = pt_word_reg_read, .u.w.write = pt_cmd_reg_write, }, /* Capabilities Pointer reg */ { .offset = PCI_CAPABILITY_LIST, .size = 1, .init_val = 0x00, .ro_mask = 0xFF, .emu_mask = 0xFF, .init = pt_ptr_reg_init, .u.b.read = pt_byte_reg_read, .u.b.write = pt_byte_reg_write, }, /* Status reg */ /* use emulated Cap Ptr value to initialize, * so need to be declared after Cap Ptr reg */ { .offset = PCI_STATUS, .size = 2, .init_val = 0x0000, .ro_mask = 0x06FF, .emu_mask = 0x0010, .init = pt_status_reg_init, .u.w.read = pt_word_reg_read, .u.w.write = pt_word_reg_write, }, /* Cache Line Size reg */ { .offset = PCI_CACHE_LINE_SIZE, .size = 1, .init_val = 0x00, .ro_mask = 0x00, .emu_mask = 0xFF, .init = pt_common_reg_init, .u.b.read = pt_byte_reg_read, .u.b.write = pt_byte_reg_write, }, /* Latency Timer reg */ { .offset = PCI_LATENCY_TIMER, .size = 1, .init_val = 0x00, .ro_mask = 0x00, .emu_mask = 0xFF, .init = pt_common_reg_init, .u.b.read = pt_byte_reg_read, .u.b.write = pt_byte_reg_write, }, /* Header Type reg */ { .offset = PCI_HEADER_TYPE, .size = 1, .init_val = 0x00, .ro_mask = 0xFF, .emu_mask = 0x80, .init = pt_common_reg_init, .u.b.read = pt_byte_reg_read, .u.b.write = pt_byte_reg_write, }, /* Interrupt Line reg */ { .offset = PCI_INTERRUPT_LINE, .size = 1, .init_val = 0x00, .ro_mask = 0x00, .emu_mask = 0xFF, .init = pt_common_reg_init, .u.b.read = pt_byte_reg_read, .u.b.write = pt_byte_reg_write, }, /* Interrupt Pin reg */ { .offset = PCI_INTERRUPT_PIN, .size = 1, .init_val = 0x00, .ro_mask = 0xFF, .emu_mask = 0xFF, .init = pt_irqpin_reg_init, .u.b.read = pt_byte_reg_read, .u.b.write = pt_byte_reg_write, }, /* BAR 0 reg */ /* mask of BAR need to be decided later, depends on IO/MEM type */ { .offset = PCI_BASE_ADDRESS_0, .size = 4, .init_val = 0x00000000, .init = pt_bar_reg_init, .u.dw.read = pt_bar_reg_read, .u.dw.write = pt_bar_reg_write, }, /* BAR 1 reg */ { .offset = PCI_BASE_ADDRESS_1, .size = 4, .init_val = 0x00000000, .init = pt_bar_reg_init, .u.dw.read = pt_bar_reg_read, .u.dw.write = pt_bar_reg_write, }, /* BAR 2 reg */ { .offset = PCI_BASE_ADDRESS_2, .size = 4, .init_val = 0x00000000, .init = pt_bar_reg_init, .u.dw.read = pt_bar_reg_read, .u.dw.write = pt_bar_reg_write, }, /* BAR 3 reg */ { .offset = PCI_BASE_ADDRESS_3, .size = 4, .init_val = 0x00000000, .init = pt_bar_reg_init, .u.dw.read = pt_bar_reg_read, .u.dw.write = pt_bar_reg_write, }, /* BAR 4 reg */ { .offset = PCI_BASE_ADDRESS_4, .size = 4, .init_val = 0x00000000, .init = pt_bar_reg_init, .u.dw.read = pt_bar_reg_read, .u.dw.write = pt_bar_reg_write, }, /* BAR 5 reg */ { .offset = PCI_BASE_ADDRESS_5, .size = 4, .init_val = 0x00000000, .init = pt_bar_reg_init, .u.dw.read = pt_bar_reg_read, .u.dw.write = pt_bar_reg_write, }, /* Expansion ROM BAR reg */ { .offset = PCI_ROM_ADDRESS, .size = 4, .init_val = 0x00000000, .ro_mask = 0x000007FE, .emu_mask = 0xFFFFF800, .init = pt_bar_reg_init, .u.dw.read = pt_long_reg_read, .u.dw.write = pt_exp_rom_bar_reg_write, }, { .size = 0, }, };/* Power Management Capability reg static infomation table */static struct pt_reg_info_tbl pt_emu_reg_pm_tbl[] = { /* Next Pointer reg */ { .offset = PCI_CAP_LIST_NEXT, .size = 1, .init_val = 0x00, .ro_mask = 0xFF, .emu_mask = 0xFF, .init = pt_ptr_reg_init, .u.b.read = pt_byte_reg_read, .u.b.write = pt_byte_reg_write, }, /* Power Management Capabilities reg */ { .offset = PCI_CAP_FLAGS, .size = 2, .init_val = 0x0000, .ro_mask = 0xFFFF, .emu_mask = 0xFFE8, .init = pt_common_reg_init, .u.w.read = pt_word_reg_read, .u.w.write = pt_word_reg_write, }, /* PCI Power Management Control/Status reg */ { .offset = PCI_PM_CTRL, .size = 2, .init_val = 0x0008, .ro_mask = 0x60FC, .emu_mask = 0xFF0B, .init = pt_common_reg_init, .u.w.read = pt_word_reg_read, .u.w.write = pt_pmcsr_reg_write, }, /* Data reg */ { .offset = PCI_PM_DATA_REGISTER, .size = 1, .init_val = 0x00, .ro_mask = 0xFF, .emu_mask = 0xFF, .init = pt_common_reg_init, .u.b.read = pt_byte_reg_read, .u.b.write = pt_byte_reg_write, }, { .size = 0, }, };/* Vital Product Data Capability Structure reg static infomation table */static struct pt_reg_info_tbl pt_emu_reg_vpd_tbl[] = { /* Next Pointer reg */ { .offset = PCI_CAP_LIST_NEXT, .size = 1, .init_val = 0x00, .ro_mask = 0xFF, .emu_mask = 0xFF, .init = pt_ptr_reg_init, .u.b.read = pt_byte_reg_read, .u.b.write = pt_byte_reg_write, }, { .size = 0, }, };/* Vendor Specific Capability Structure reg static infomation table */static struct pt_reg_info_tbl pt_emu_reg_vendor_tbl[] = { /* Next Pointer reg */ { .offset = PCI_CAP_LIST_NEXT, .size = 1, .init_val = 0x00, .ro_mask = 0xFF, .emu_mask = 0xFF, .init = pt_ptr_reg_init, .u.b.read = pt_byte_reg_read, .u.b.write = pt_byte_reg_write, }, { .size = 0, }, };/* PCI Express Capability Structure reg static infomation table */static struct pt_reg_info_tbl pt_emu_reg_pcie_tbl[] = { /* Next Pointer reg */ { .offset = PCI_CAP_LIST_NEXT, .size = 1, .init_val = 0x00, .ro_mask = 0xFF, .emu_mask = 0xFF, .init = pt_ptr_reg_init, .u.b.read = pt_byte_reg_read, .u.b.write = pt_byte_reg_write, }, /* Device Capabilities reg */ { .offset = PCI_EXP_DEVCAP, .size = 4, .init_val = 0x00000000, .ro_mask = 0x1FFCFFFF, .emu_mask = 0x10000000, .init = pt_common_reg_init, .u.dw.read = pt_long_reg_read, .u.dw.write = pt_long_reg_write, }, /* Device Control reg */ { .offset = PCI_EXP_DEVCTL, .size = 2, .init_val = 0x2810, .ro_mask = 0x0000, .emu_mask = 0xFFFF,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -