WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] ioemu: Support more Capability Structures

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] ioemu: Support more Capability Structures (including MSI/MSI-X)
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Fri, 04 Jul 2008 08:00:15 -0700
Delivery-date: Fri, 04 Jul 2008 08:01:42 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1215168861 -3600
# Node ID 9cf72db44ee968de1c4a51de1e9aa91c841b6e6b
# Parent  1db0b09b290eef393df17f3502ea27324fe403aa
ioemu: Support more Capability Structures (including MSI/MSI-X)
       and Device Specific Registers for pt device.

I implemented following Capability Structures and Device Specific
Registers.
    * Configuration Header Type 0
        -> emulation.
           "emulation" does not mean no accessing real I/O device.
           Access real I/O device, but guest value and real value
           might be different.
    * MSI Capability Structure
        -> emulation.
           Behavior is not changed from existed implementation in
           pt-msi.c, although code is changed.
    * MSI-X Capability Structure
        -> emulation.
           Behavior is not changed from existed implementation in
           pt-msi.c, although code is changed.
    * PCI Express Capability Structure
        -> emulation.
    * PCI Power Management Capability Structure
        -> emulation.
    * Vital Product Data Capability Structure
        -> emulation.
           Emulated register is only  Next Capability Pointer
    Register.
           All other registers are passthrough.
    * Vendor Specific Capability Structure
        -> emulation
           Emulated register is only  Next Capability Pointer
    Register.
           All other registers are passthrough.
    * Device Specific Register (exclude capability structures)
        -> passthrough.
           The device drivers in guest domain are allowed to access
           Device Specific Register. So various I/O device will work.

I assigned following device to guest domain, and they worked fine.
    - PCIe NIC (MSI)
    - PCI NIC (MSI)
    - UHCI (INTx interrupt)
    - IDE Controller (INTx interrupt)

Signed-off-by: Yuji Shimada <shimada-yxb@xxxxxxxxxxxxxxx>
---
 tools/ioemu/hw/pass-through.c | 2354 ++++++++++++++++++++++++++++++++++++++++--
 tools/ioemu/hw/pass-through.h |  175 ++-
 tools/ioemu/hw/pci.c          |   31 
 tools/ioemu/hw/pt-msi.c       |  565 ----------
 tools/ioemu/hw/pt-msi.h       |   17 
 tools/ioemu/vl.h              |    2 
 6 files changed, 2491 insertions(+), 653 deletions(-)

diff -r 1db0b09b290e -r 9cf72db44ee9 tools/ioemu/hw/pass-through.c
--- a/tools/ioemu/hw/pass-through.c     Fri Jul 04 11:51:59 2008 +0100
+++ b/tools/ioemu/hw/pass-through.c     Fri Jul 04 11:54:21 2008 +0100
@@ -46,6 +46,629 @@ struct dpci_infos {
 
 } 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);
+
+/* 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,
+        .init       = pt_common_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_devctrl_reg_write,
+    },
+    /* Link Control reg */
+    {
+        .offset     = PCI_EXP_LNKCTL,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0x0000,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_common_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_linkctrl_reg_write,
+    },
+    /* Device Control 2 reg */
+    {
+        .offset     = 0x28,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0x0000,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_common_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_devctrl2_reg_write,
+    },
+    /* Link Control 2 reg */
+    {
+        .offset     = 0x30,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0x0000,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_linkctrl2_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_linkctrl2_reg_write,
+    },
+    {
+        .size = 0,
+    }, 
+};
+
+/* MSI Capability Structure reg static infomation table */
+static struct pt_reg_info_tbl pt_emu_reg_msi_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,
+    },
+    /* Message Control reg */
+    {
+        .offset     = PCI_MSI_FLAGS, // 2
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0x018E,
+        .emu_mask   = 0xFFFE,
+        .init       = pt_msgctrl_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_msgctrl_reg_write,
+    },
+    /* Message Address reg */
+    {
+        .offset     = PCI_MSI_ADDRESS_LO, // 4
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .ro_mask    = 0x00000FF0,    /* bit 4~11 is reserved for MSI in x86 */
+        .emu_mask   = 0xFFFFFFFF,
+        .init       = pt_msgaddr32_reg_init,
+        .u.dw.read  = pt_long_reg_read,
+        .u.dw.write = pt_msgaddr32_reg_write,
+    },
+    /* Message Upper Address reg (if PCI_MSI_FLAGS_64BIT set) */
+    {
+        .offset     = PCI_MSI_ADDRESS_HI, // 8
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .ro_mask    = 0x00000000,
+        .emu_mask   = 0xFFFFFFFF,
+        .init       = pt_msgaddr64_reg_init,
+        .u.dw.read  = pt_long_reg_read,
+        .u.dw.write = pt_msgaddr64_reg_write,
+    },
+    /* Message Data reg (16 bits of data for 32-bit devices) */
+    {
+        .offset     = PCI_MSI_DATA_32, // 8
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0x3800,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_msgdata_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_msgdata_reg_write,
+    },
+    /* Message Data reg (16 bits of data for 64-bit devices) */
+    {
+        .offset     = PCI_MSI_DATA_64, // 12
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0x3800,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_msgdata_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_msgdata_reg_write,
+    },
+    {
+        .size = 0,
+    }, 
+};
+
+/* MSI-X Capability Structure reg static infomation table */
+static struct pt_reg_info_tbl pt_emu_reg_msix_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,
+    },
+    /* Message Control reg */
+    {
+        .offset     = PCI_MSI_FLAGS, // 2
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0x3FFF,
+        .emu_mask   = 0x0000,
+        .init       = pt_msixctrl_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_msixctrl_reg_write,
+    },
+    {
+        .size = 0,
+    }, 
+};
+
+/* emul reg group static infomation table */
+static const struct pt_reg_grp_info_tbl pt_emu_reg_grp_tbl[] = {
+    /* Header Type0 reg group */
+    {
+        .grp_id     = 0xFF,
+        .grp_type   = GRP_TYPE_EMU,
+        .grp_size   = 0x40,
+        .size_init  = pt_reg_grp_size_init,
+        .emu_reg_tbl= pt_emu_reg_header0_tbl,
+    },
+    /* PCI PowerManagement Capability reg group */
+    {
+        .grp_id     = PCI_CAP_ID_PM,
+        .grp_type   = GRP_TYPE_EMU,
+        .grp_size   = PCI_PM_SIZEOF,
+        .size_init  = pt_reg_grp_size_init,
+        .emu_reg_tbl= pt_emu_reg_pm_tbl,
+    },
+    /* AGP Capability Structure reg group */
+    {
+        .grp_id     = PCI_CAP_ID_AGP,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x30,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* Vital Product Data Capability Structure reg group */
+    {
+        .grp_id     = PCI_CAP_ID_VPD,
+        .grp_type   = GRP_TYPE_EMU,
+        .grp_size   = 0x08,
+        .size_init  = pt_reg_grp_size_init,
+        .emu_reg_tbl= pt_emu_reg_vpd_tbl,
+    },
+    /* Slot Identification reg group */
+    {
+        .grp_id     = PCI_CAP_ID_SLOTID,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x04,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* MSI Capability Structure reg group */
+    {
+        .grp_id     = PCI_CAP_ID_MSI,
+        .grp_type   = GRP_TYPE_EMU,
+        .grp_size   = 0xFF,
+        .size_init  = pt_msi_size_init,
+        .emu_reg_tbl= pt_emu_reg_msi_tbl,
+    },
+    /* PCI-X Capabilities List Item reg group */
+    {
+        .grp_id     = PCI_CAP_ID_PCIX,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x18,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* Vendor Specific Capability Structure reg group */
+    {
+        .grp_id     = PCI_CAP_ID_VNDR,
+        .grp_type   = GRP_TYPE_EMU,
+        .grp_size   = 0xFF,
+        .size_init  = pt_vendor_size_init,
+        .emu_reg_tbl= pt_emu_reg_vendor_tbl,
+    },
+    /* SHPC Capability List Item reg group */
+    {
+        .grp_id     = PCI_CAP_ID_HOTPLUG,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x08,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* Subsystem ID and Subsystem Vendor ID Capability List Item reg group */
+    {
+        .grp_id     = PCI_CAP_ID_SSVID,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x08,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* AGP 8x Capability Structure reg group */
+    {
+        .grp_id     = PCI_CAP_ID_AGP3,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x30,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* PCI Express Capability Structure reg group */
+    {
+        .grp_id     = PCI_CAP_ID_EXP,
+        .grp_type   = GRP_TYPE_EMU,
+        .grp_size   = 0x3C,
+        .size_init  = pt_reg_grp_size_init,
+        .emu_reg_tbl= pt_emu_reg_pcie_tbl,
+    },
+    /* MSI-X Capability Structure reg group */
+    {
+        .grp_id     = PCI_CAP_ID_MSIX,
+        .grp_type   = GRP_TYPE_EMU,
+        .grp_size   = 0x0C,
+        .size_init  = pt_msix_size_init,
+        .emu_reg_tbl= pt_emu_reg_msix_tbl,
+    },
+    {
+        .grp_size = 0,
+    }, 
+};
+
 static int token_value(char *token)
 {
     return strtol(token, NULL, 16);
@@ -197,8 +820,9 @@ void pt_iomem_map(PCIDevice *d, int i, u
     assigned_device->bases[i].e_physbase = e_phys;
     assigned_device->bases[i].e_size= e_size;
 
-    PT_LOG("e_phys=%08x maddr=%08x type=%d len=%08x index=%d\n",
-        e_phys, assigned_device->bases[i].access.maddr, type, e_size, i);
+    PT_LOG("e_phys=%08x maddr=%lx type=%d len=%d index=%d first_map=%d\n",
+        e_phys, assigned_device->bases[i].access.maddr, 
+        type, e_size, i, first_map);
 
     if ( e_size == 0 )
         return;
@@ -219,18 +843,25 @@ void pt_iomem_map(PCIDevice *d, int i, u
         }
     }
 
-    /* Create new mapping */
-    ret = xc_domain_memory_mapping(xc_handle, domid,
-            assigned_device->bases[i].e_physbase >> XC_PAGE_SHIFT,
-            assigned_device->bases[i].access.maddr >> XC_PAGE_SHIFT,
-            (e_size+XC_PAGE_SIZE-1) >> XC_PAGE_SHIFT,
-            DPCI_ADD_MAPPING);
-    if ( ret != 0 )
-        PT_LOG("Error: create new mapping failed!\n");
-
-    ret = remove_msix_mapping(assigned_device, i);
-    if ( ret != 0 )
-        PT_LOG("Error: remove MSX-X mmio mapping failed!\n");
+    /* map only valid guest address (include 0) */
+    if (e_phys != -1)
+    {
+        /* Create new mapping */
+        ret = xc_domain_memory_mapping(xc_handle, domid,
+                assigned_device->bases[i].e_physbase >> XC_PAGE_SHIFT,
+                assigned_device->bases[i].access.maddr >> XC_PAGE_SHIFT,
+                (e_size+XC_PAGE_SIZE-1) >> XC_PAGE_SHIFT,
+                DPCI_ADD_MAPPING);
+
+        if ( ret != 0 )
+        {
+            PT_LOG("Error: create new mapping failed!\n");
+        }
+        
+        ret = remove_msix_mapping(assigned_device, i);
+        if ( ret != 0 )
+            PT_LOG("Error: remove MSX-X mmio mapping failed!\n");
+    }
 }
 
 /* Being called each time a pio region has been updated */
@@ -245,9 +876,9 @@ void pt_ioport_map(PCIDevice *d, int i,
     assigned_device->bases[i].e_physbase = e_phys;
     assigned_device->bases[i].e_size= e_size;
 
-    PT_LOG("e_phys=%04x pio_base=%04x len=%04x index=%d\n",
+    PT_LOG("e_phys=%04x pio_base=%04x len=%d index=%d first_map=%d\n",
         (uint16_t)e_phys, (uint16_t)assigned_device->bases[i].access.pio_base,
-        (uint16_t)e_size, i);
+        (uint16_t)e_size, i, first_map);
 
     if ( e_size == 0 )
         return;
@@ -265,13 +896,86 @@ void pt_ioport_map(PCIDevice *d, int i,
         }
     }
 
-    /* Create new mapping */
-    ret = xc_domain_ioport_mapping(xc_handle, domid, e_phys,
-                assigned_device->bases[i].access.pio_base, e_size,
-                DPCI_ADD_MAPPING);
-    if ( ret != 0 )
-        PT_LOG("Error: create new mapping failed!\n");
-
+    /* map only valid guest address (include 0) */
+    if (e_phys != -1)
+    {
+        /* Create new mapping */
+        ret = xc_domain_ioport_mapping(xc_handle, domid, e_phys,
+                    assigned_device->bases[i].access.pio_base, e_size,
+                    DPCI_ADD_MAPPING);
+        if ( ret != 0 )
+        {
+            PT_LOG("Error: create new mapping failed!\n");
+        }
+    }
+}
+
+/* find emulate register group entry */
+struct pt_reg_grp_tbl* pt_find_reg_grp(
+        struct pt_dev *ptdev, uint32_t address)
+{
+    struct pt_reg_grp_tbl* reg_grp_entry = NULL;
+
+    /* find register group entry */
+    for (reg_grp_entry = ptdev->reg_grp_tbl_head.lh_first; reg_grp_entry;
+        reg_grp_entry = reg_grp_entry->entries.le_next)
+    {
+        /* check address */
+        if ((reg_grp_entry->base_offset <= address) &&
+            ((reg_grp_entry->base_offset + reg_grp_entry->size) > address))
+            goto out;
+    }
+    /* group entry not found */
+    reg_grp_entry = NULL;
+
+out:
+    return reg_grp_entry;
+}
+
+/* find emulate register entry */
+struct pt_reg_tbl* pt_find_reg(
+        struct pt_reg_grp_tbl* reg_grp, uint32_t address)
+{
+    struct pt_reg_tbl* reg_entry = NULL;
+    struct pt_reg_info_tbl* reg = NULL;
+    uint32_t real_offset = 0;
+
+    /* find register entry */
+    for (reg_entry = reg_grp->reg_tbl_head.lh_first; reg_entry;
+        reg_entry = reg_entry->entries.le_next)
+    {
+        reg = reg_entry->reg;
+        real_offset = (reg_grp->base_offset + reg->offset);
+        /* check address */
+        if ((real_offset <= address) && ((real_offset + reg->size) > address))
+            goto out;
+    }
+    /* register entry not found */
+    reg_entry = NULL;
+
+out:
+    return reg_entry;
+}
+
+/* get BAR index */
+static int pt_bar_offset_to_index(uint32_t offset)
+{
+    int index = 0;
+
+    /* check Exp ROM BAR */
+    if (offset == PCI_ROM_ADDRESS)
+    {
+        index = PCI_ROM_SLOT;
+        goto out;
+    }
+
+    /* calculate BAR index */
+    index = ((offset - PCI_BASE_ADDRESS_0) >> 2);
+    if (index >= PCI_NUM_REGIONS)
+        index = -1;
+
+out:
+    return index;
 }
 
 static void pt_pci_write_config(PCIDevice *d, uint32_t address, uint32_t val,
@@ -279,60 +983,258 @@ static void pt_pci_write_config(PCIDevic
 {
     struct pt_dev *assigned_device = (struct pt_dev *)d;
     struct pci_dev *pci_dev = assigned_device->pci_dev;
-
-#ifdef PT_DEBUG_PCI_CONFIG_ACCESS
-    PT_LOG("(%x.%x): address=%04x val=0x%08x len=%d\n",
-       (d->devfn >> 3) & 0x1F, (d->devfn & 0x7), address, val, len);
-#endif
-
-    /* Pre-write hooking */
-    switch ( address ) {
-    case 0x0C ... 0x3F:
-        pci_default_write_config(d, address, val, len);
-        return;
-    }
-
-    if ( pt_msi_write(assigned_device, address, val, len) )
-        return;
-
-    if ( pt_msix_write(assigned_device, address, val, len) )
-        return;
-
-    /* PCI config pass-through */
-    if (address == 0x4) {
-        switch (len){
-        case 1:
-            pci_write_byte(pci_dev, address, val);
-            break;
-        case 2:
-            pci_write_word(pci_dev, address, val);
-            break;
-        case 4:
-            pci_write_long(pci_dev, address, val);
-            break;
-        }
-    }
-
-    if (address == 0x4) {
-        /* Post-write hooking */
-        pci_default_write_config(d, address, val, len);
-    }
+    struct pt_reg_grp_tbl *reg_grp_entry = NULL;
+    struct pt_reg_grp_info_tbl *reg_grp = NULL;
+    struct pt_reg_tbl *reg_entry = NULL;
+    struct pt_reg_info_tbl *reg = NULL;
+    uint32_t find_addr = address;
+    uint32_t real_offset = 0;
+    uint32_t valid_mask = 0xFFFFFFFF;
+    uint32_t read_val = 0;
+    uint8_t *ptr_val = NULL;
+    int emul_len = 0;
+    int index = 0;
+    int ret = 0;
+
+    PT_LOG("write(%x.%x): address=%04x val=0x%08x len=%d\n",
+        (d->devfn >> 3) & 0x1F, (d->devfn & 0x7), address, val, len);
+
+    /* check offset range */
+    if (address >= 0xFF)
+    {
+        PT_LOG("Failed to write register with offset exceeding FFh. "
+            "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n",
+            pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
+            address, len);
+        goto exit;
+    }
+
+    /* check write size */
+    if ((len != 1) && (len != 2) && (len != 4))
+    {
+        PT_LOG("Failed to write register with invalid access length. "
+            "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n",
+            pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
+            address, len);
+        goto exit;
+    }
+
+    /* check offset alignment */
+    if (address & (len-1))
+    {
+        PT_LOG("Failed to write register with invalid access size alignment. "
+            "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n",
+            pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
+            address, len);
+        goto exit;
+    }
+
+    /* check unused BAR register */
+    index = pt_bar_offset_to_index(address);
+    if ((index >= 0) && (val > 0 && val < PT_BAR_ALLF) &&
+        (assigned_device->bases[index].bar_flag == PT_BAR_FLAG_UNUSED))
+    {
+        PT_LOG("Guest attempt to set address to unused Base Address Register. "
+            "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n",
+            pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), 
+            (d->devfn & 0x7), address, len);
+    }
+
+    /* find register group entry */
+    reg_grp_entry = pt_find_reg_grp(assigned_device, address);
+    if (reg_grp_entry)
+    {
+        reg_grp = reg_grp_entry->reg_grp;
+        /* check 0 Hardwired register group */
+        if (reg_grp->grp_type == GRP_TYPE_HARDWIRED)
+        {
+            /* ignore silently */
+            PT_LOG("Access to 0 Hardwired register.\n");
+            goto exit;
+        }
+    }
+
+    /* read I/O device register value */
+    switch (len) {
+    case 1:
+        read_val = pci_read_byte(pci_dev, address);
+        break;
+    case 2:
+        read_val = pci_read_word(pci_dev, address);
+        break;
+    case 4:
+        read_val = pci_read_long(pci_dev, address);
+        break;
+    }
+
+    /* check libpci error */
+    valid_mask = (0xFFFFFFFF >> ((4 - len) << 3));
+    if ((read_val & valid_mask) == valid_mask)
+    {
+        PT_LOG("libpci read error. No emulation. "
+            "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n",
+            pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
+            address, len);
+        goto exit;
+    }
+    
+    /* pass directly to libpci for passthrough type register group */
+    if (reg_grp_entry == NULL)
+        goto out;
+
+    /* adjust the write value to appropriate CFC-CFF window */
+    val <<= ((address & 3) << 3);
+    emul_len = len;
+
+    /* loop Guest request size */
+    while (0 < emul_len)
+    {
+        /* find register entry to be emulated */
+        reg_entry = pt_find_reg(reg_grp_entry, find_addr);
+        if (reg_entry)
+        {
+            reg = reg_entry->reg;
+            real_offset = (reg_grp_entry->base_offset + reg->offset);
+            valid_mask = (0xFFFFFFFF >> ((4 - emul_len) << 3));
+            valid_mask <<= ((find_addr - real_offset) << 3);
+            ptr_val = ((uint8_t *)&val + (real_offset & 3));
+
+            /* do emulation depend on register size */
+            switch (reg->size) {
+            case 1:
+                /* emulate write to byte register */
+                if (reg->u.b.write)
+                    ret = reg->u.b.write(assigned_device, reg_entry,
+                               (uint8_t *)ptr_val, 
+                               (uint8_t)(read_val >> ((real_offset & 3) << 3)),
+                               (uint8_t)valid_mask);
+                break;
+            case 2:
+                /* emulate write to word register */
+                if (reg->u.w.write)
+                    ret = reg->u.w.write(assigned_device, reg_entry,
+                               (uint16_t *)ptr_val, 
+                               (uint16_t)(read_val >> ((real_offset & 3) << 
3)),
+                               (uint16_t)valid_mask);
+                break;
+            case 4:
+                /* emulate write to double word register */
+                if (reg->u.dw.write)
+                    ret = reg->u.dw.write(assigned_device, reg_entry,
+                               (uint32_t *)ptr_val, 
+                               (uint32_t)(read_val >> ((real_offset & 3) << 
3)),
+                               (uint32_t)valid_mask);
+                break;
+            }
+
+            /* write emulation error */
+            if (ret < 0)
+            {
+                /* exit I/O emulator */
+                PT_LOG("I/O emulator exit()\n");
+                exit(1);
+            }
+
+            /* calculate next address to find */
+            emul_len -= reg->size;
+            if (emul_len > 0)
+                find_addr = real_offset + reg->size;
+        }
+        else
+        {
+            /* nothing to do with passthrough type register, 
+             * continue to find next byte 
+             */
+            emul_len--;
+            find_addr++;
+        }
+    }
+    
+    /* need to shift back before passing them to libpci */
+    val >>= ((address & 3) << 3);
+
+out:
+    switch (len){
+    case 1:
+        pci_write_byte(pci_dev, address, val);
+        break;
+    case 2:
+        pci_write_word(pci_dev, address, val);
+        break;
+    case 4:
+        pci_write_long(pci_dev, address, val);
+        break;
+    }
+
+exit:
+    return;
 }
 
 static uint32_t pt_pci_read_config(PCIDevice *d, uint32_t address, int len)
 {
     struct pt_dev *assigned_device = (struct pt_dev *)d;
     struct pci_dev *pci_dev = assigned_device->pci_dev;
-    uint32_t val = 0xFF;
-
-    /* Pre-hooking */
-    switch ( address ) {
-    case 0x0C ... 0x3F:
-        val = pci_default_read_config(d, address, len);
+    uint32_t val = 0xFFFFFFFF;
+    struct pt_reg_grp_tbl *reg_grp_entry = NULL;
+    struct pt_reg_grp_info_tbl *reg_grp = NULL;
+    struct pt_reg_tbl *reg_entry = NULL;
+    struct pt_reg_info_tbl *reg = NULL;
+    uint32_t find_addr = address;
+    uint32_t real_offset = 0;
+    uint32_t valid_mask = 0xFFFFFFFF;
+    uint8_t *ptr_val = NULL;
+    int emul_len = 0;
+    int ret = 0;
+
+    PT_LOG("read(%x.%x): address=%04x len=%d\n",
+        (d->devfn >> 3) & 0x1F, (d->devfn & 0x7), address, len);
+
+    /* check offset range */
+    if (address >= 0xFF)
+    {
+        PT_LOG("Failed to read register with offset exceeding FFh. "
+            "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n",
+            pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
+            address, len);
         goto exit;
     }
 
-    switch ( len ) {
+    /* check read size */
+    if ((len != 1) && (len != 2) && (len != 4))
+    {
+        PT_LOG("Failed to read register with invalid access length. "
+            "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n",
+            pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
+            address, len);
+        goto exit;
+    }
+
+    /* check offset alignment */
+    if (address & (len-1))
+    {
+        PT_LOG("Failed to read register with invalid access size alignment. "
+            "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n",
+            pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
+            address, len);
+        goto exit;
+    }
+
+    /* find register group entry */
+    reg_grp_entry = pt_find_reg_grp(assigned_device, address);
+    if (reg_grp_entry)
+    {
+        reg_grp = reg_grp_entry->reg_grp;
+        /* check 0 Hardwired register group */
+        if (reg_grp->grp_type == GRP_TYPE_HARDWIRED)
+        {
+            /* no need to emulate, just return 0 */
+            val = 0;
+            goto exit;
+        }
+    }
+
+    /* read I/O device register value */
+    switch (len) {
     case 1:
         val = pci_read_byte(pci_dev, address);
         break;
@@ -344,15 +1246,92 @@ static uint32_t pt_pci_read_config(PCIDe
         break;
     }
 
-    pt_msi_read(assigned_device, address, len, &val);
-    pt_msix_read(assigned_device, address, len, &val);
+    /* check libpci error */
+    valid_mask = (0xFFFFFFFF >> ((4 - len) << 3));
+    if ((val & valid_mask) == valid_mask)
+    {
+        PT_LOG("libpci read error. No emulation. "
+            "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n",
+            pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
+            address, len);
+        goto exit;
+    }
+
+    /* just return the I/O device register value for 
+     * passthrough type register group 
+     */
+    if (reg_grp_entry == NULL)
+        goto exit;
+
+    /* adjust the read value to appropriate CFC-CFF window */
+    val <<= ((address & 3) << 3);
+    emul_len = len;
+
+    /* loop Guest request size */
+    while (0 < emul_len)
+    {
+        /* find register entry to be emulated */
+        reg_entry = pt_find_reg(reg_grp_entry, find_addr);
+        if (reg_entry)
+        {
+            reg = reg_entry->reg;
+            real_offset = (reg_grp_entry->base_offset + reg->offset);
+            valid_mask = (0xFFFFFFFF >> ((4 - emul_len) << 3));
+            valid_mask <<= ((find_addr - real_offset) << 3);
+            ptr_val = ((uint8_t *)&val + (real_offset & 3));
+
+            /* do emulation depend on register size */
+            switch (reg->size) {
+            case 1:
+                /* emulate read to byte register */
+                if (reg->u.b.read)
+                    ret = reg->u.b.read(assigned_device, reg_entry,
+                                        (uint8_t *)ptr_val, 
+                                        (uint8_t)valid_mask);
+                break;
+            case 2:
+                /* emulate read to word register */
+                if (reg->u.w.read)
+                    ret = reg->u.w.read(assigned_device, reg_entry,
+                                        (uint16_t *)ptr_val, 
+                                        (uint16_t)valid_mask);
+                break;
+            case 4:
+                /* emulate read to double word register */
+                if (reg->u.dw.read)
+                    ret = reg->u.dw.read(assigned_device, reg_entry,
+                                        (uint32_t *)ptr_val, 
+                                        (uint32_t)valid_mask);
+                break;
+            }
+
+            /* read emulation error */
+            if (ret < 0)
+            {
+                /* exit I/O emulator */
+                PT_LOG("I/O emulator exit()\n");
+                exit(1);
+            }
+
+            /* calculate next address to find */
+            emul_len -= reg->size;
+            if (emul_len > 0)
+                find_addr = real_offset + reg->size;
+        }
+        else
+        {
+            /* nothing to do with passthrough type register, 
+             * continue to find next byte 
+             */
+            emul_len--;
+            find_addr++;
+        }
+    }
+    
+    /* need to shift back before returning them to pci bus emulator */
+    val >>= ((address & 3) << 3);
+
 exit:
-
-#ifdef PT_DEBUG_PCI_CONFIG_ACCESS
-    PT_LOG("(%x.%x): address=%04x val=0x%08x len=%d\n",
-       (d->devfn >> 3) & 0x1F, (d->devfn & 0x7), address, val, len);
-#endif
-
     return val;
 }
 
@@ -488,11 +1467,1211 @@ uint8_t find_cap_offset(struct pci_dev *
     return 0;
 }
 
+/* parse BAR */
+static int pt_bar_reg_parse(
+        struct pt_dev *ptdev, struct pt_reg_info_tbl *reg)
+{
+    PCIDevice *d = &ptdev->dev;
+    struct pt_region *region = NULL;
+    PCIIORegion *r;
+    uint32_t bar_64 = (reg->offset - 4);
+    int bar_flag = PT_BAR_FLAG_UNUSED;
+    int index = 0;
+    int i;
+
+    /* set again the BAR config because it has been overwritten
+     * by pci_register_io_region()
+     */
+    for (i=reg->offset; i<(reg->offset + 4); i++)
+        d->config[i] = pci_read_byte(ptdev->pci_dev, i);
+
+    /* check 64bit BAR */
+    index = pt_bar_offset_to_index(reg->offset);
+    if ((index > 0) && (index < PCI_ROM_SLOT) &&
+        (d->config[bar_64] & PCI_BASE_ADDRESS_MEM_TYPE_64))
+    {
+        region = &ptdev->bases[index-1];
+        if (region->bar_flag != PT_BAR_FLAG_UPPER)
+        {
+            bar_flag = PT_BAR_FLAG_UPPER;
+            goto out;
+        }
+    }
+
+    /* check unused BAR */
+    r = &d->io_regions[index];
+    if (!r->size)
+        goto out;
+
+    /* check BAR I/O indicator */
+    if (d->config[reg->offset] & PCI_BASE_ADDRESS_SPACE_IO)
+        bar_flag = PT_BAR_FLAG_IO;
+    else
+        bar_flag = PT_BAR_FLAG_MEM;
+
+out:
+    return bar_flag;
+}
+
+/* mapping BAR */
+static void pt_bar_mapping(struct pt_dev *ptdev, int io_enable, int mem_enable)
+{
+    PCIDevice *dev = (PCIDevice *)&ptdev->dev;
+    PCIIORegion *r;
+    struct pt_region *base = NULL;
+    uint32_t r_size = 0;
+    int ret = 0;
+    int i;
+
+    for (i=0; i<PCI_NUM_REGIONS; i++)
+    {
+        r = &dev->io_regions[i];
+
+        /* check valid region */
+        if (!r->size)
+            continue;
+
+        base = &ptdev->bases[i];
+        /* skip unused BAR or upper 64bit BAR */
+        if ((base->bar_flag == PT_BAR_FLAG_UNUSED) || 
+           (base->bar_flag == PT_BAR_FLAG_UPPER))
+               continue;
+
+        /* clear region address in case I/O Space or Memory Space disable */
+        if (((base->bar_flag == PT_BAR_FLAG_IO) && !io_enable ) ||
+            ((base->bar_flag == PT_BAR_FLAG_MEM) && !mem_enable ))
+            r->addr = -1;
+
+        /* prevent guest software mapping memory resource to 00000000h */
+        if ((base->bar_flag == PT_BAR_FLAG_MEM) && (r->addr == 0))
+            r->addr = -1;
+
+        /* align resource size (memory type only) */
+        r_size = r->size;
+        PT_GET_EMUL_SIZE(base->bar_flag, r_size);
+
+        /* check overlapped address */
+        ret = pt_chk_bar_overlap(dev->bus, dev->devfn, r->addr, r_size);
+        if (ret > 0)
+            PT_LOG("Base Address[%d] is overlapped. "
+                "[Address:%08xh][Size:%04xh]\n", i, r->addr, r_size);
+
+        /* check whether we need to update the mapping or not */
+        if (r->addr != ptdev->bases[i].e_physbase)
+        {
+            /* mapping BAR */
+            r->map_func((PCIDevice *)ptdev, i, r->addr, 
+                         r_size, r->type);
+        }
+    }
+
+    return;
+}
+
+/* initialize emulate register */
+static int pt_config_reg_init(struct pt_dev *ptdev,
+        struct pt_reg_grp_tbl *reg_grp,
+        struct pt_reg_info_tbl *reg)
+{
+    struct pt_reg_tbl *reg_entry;
+    uint32_t data = 0;
+    int err = 0;
+
+    /* allocate register entry */
+    reg_entry = qemu_mallocz(sizeof(struct pt_reg_tbl));
+    if (reg_entry == NULL)
+    {
+        PT_LOG("Failed to allocate memory.\n");
+        err = -1;
+        goto out;
+    }
+
+    /* initialize register entry */
+    reg_entry->reg = reg;
+    reg_entry->data = 0;
+
+    if (reg->init)
+    {
+        /* initialize emulate register */
+        data = reg->init(ptdev, reg_entry->reg,
+                        (reg_grp->base_offset + reg->offset));
+        if (data == PT_INVALID_REG)
+        {
+            /* free unused BAR register entry */
+            free(reg_entry);
+            goto out;
+        }
+        /* set register value */
+        reg_entry->data = data;
+    }
+    /* list add register entry */
+    QEMU_LIST_INSERT_HEAD(&reg_grp->reg_tbl_head, reg_entry, entries);
+
+out:
+    return err;
+}
+
+/* initialize emulate register group */
+static int pt_config_init(struct pt_dev *ptdev)
+{
+    struct pt_reg_grp_tbl *reg_grp_entry = NULL;
+    struct pt_reg_info_tbl *reg_tbl = NULL;
+    uint32_t reg_grp_offset = 0;
+    int i, j, err = 0;
+
+    /* initialize register group list */
+    QEMU_LIST_INIT(&ptdev->reg_grp_tbl_head);
+
+    /* initialize register group */
+    for (i=0; pt_emu_reg_grp_tbl[i].grp_size != 0; i++)
+    {
+        if (pt_emu_reg_grp_tbl[i].grp_id != 0xFF)
+        {
+            reg_grp_offset = (uint32_t)find_cap_offset(ptdev->pci_dev, 
+                                 pt_emu_reg_grp_tbl[i].grp_id);
+            if (!reg_grp_offset) 
+                continue;
+        }
+
+        /* allocate register group table */
+        reg_grp_entry = qemu_mallocz(sizeof(struct pt_reg_grp_tbl));
+        if (reg_grp_entry == NULL)
+        {
+            PT_LOG("Failed to allocate memory.\n");
+            err = -1;
+            goto out;
+        }
+
+        /* initialize register group entry */
+        QEMU_LIST_INIT(&reg_grp_entry->reg_tbl_head);
+
+        /* need to declare here, to enable searching Cap Ptr reg 
+         * (which is in the same reg group) when initializing Status reg 
+         */
+        QEMU_LIST_INSERT_HEAD(&ptdev->reg_grp_tbl_head, reg_grp_entry, 
entries);
+
+        reg_grp_entry->base_offset = reg_grp_offset;
+        reg_grp_entry->reg_grp = 
+                (struct pt_reg_grp_info_tbl*)&pt_emu_reg_grp_tbl[i];
+        if (pt_emu_reg_grp_tbl[i].size_init)
+        {
+            /* get register group size */
+            reg_grp_entry->size = pt_emu_reg_grp_tbl[i].size_init(ptdev,
+                                      reg_grp_entry->reg_grp, 
+                                      reg_grp_offset);
+        }
+
+        if (pt_emu_reg_grp_tbl[i].grp_type == GRP_TYPE_EMU)
+        {
+            if (pt_emu_reg_grp_tbl[i].emu_reg_tbl)
+            {
+                reg_tbl = pt_emu_reg_grp_tbl[i].emu_reg_tbl;
+                /* initialize capability register */
+                for (j=0; reg_tbl->size != 0; j++, reg_tbl++)
+                {
+                    /* initialize capability register */
+                    err = pt_config_reg_init(ptdev, reg_grp_entry, reg_tbl);
+                    if (err < 0)
+                        goto out;
+                }
+            }
+        }
+        reg_grp_offset = 0;
+    }
+
+out:
+    return err;
+}
+
+/* initialize common register value */
+static uint32_t pt_common_reg_init(struct pt_dev *ptdev,
+        struct pt_reg_info_tbl *reg, uint32_t real_offset)
+{
+    return reg->init_val;
+}
+
+/* initialize Capabilities Pointer or Next Pointer register */
+static uint32_t pt_ptr_reg_init(struct pt_dev *ptdev,
+        struct pt_reg_info_tbl *reg, uint32_t real_offset)
+{
+    uint32_t reg_field = (uint32_t)ptdev->dev.config[real_offset];
+    int i;
+
+    /* find capability offset */
+    while (reg_field)
+    {
+        for (i=0; pt_emu_reg_grp_tbl[i].grp_size != 0; i++)
+        {
+            /* check whether the next capability 
+             * should be exported to guest or not 
+             */
+            if (pt_emu_reg_grp_tbl[i].grp_id == ptdev->dev.config[reg_field])
+            {
+                if (pt_emu_reg_grp_tbl[i].grp_type == GRP_TYPE_EMU)
+                    goto out;
+                /* ignore the 0 hardwired capability, find next one */
+                break;
+            }
+        }
+        /* next capability */
+        reg_field = (uint32_t)ptdev->dev.config[reg_field + 1];
+    }
+
+out:
+    return reg_field;
+}
+
+/* initialize Status register */
+static uint32_t pt_status_reg_init(struct pt_dev *ptdev,
+        struct pt_reg_info_tbl *reg, uint32_t real_offset)
+{
+    struct pt_reg_grp_tbl *reg_grp_entry = NULL;
+    struct pt_reg_tbl *reg_entry = NULL;
+    int reg_field = 0;
+
+    /* find Header register group */
+    reg_grp_entry = pt_find_reg_grp(ptdev, PCI_CAPABILITY_LIST);
+    if (reg_grp_entry)
+    {
+        /* find Capabilities Pointer register */
+        reg_entry = pt_find_reg(reg_grp_entry, PCI_CAPABILITY_LIST);
+        if (reg_entry)
+        {
+            /* check Capabilities Pointer register */
+            if (reg_entry->data)
+                reg_field |= PCI_STATUS_CAP_LIST;
+            else
+                reg_field &= ~PCI_STATUS_CAP_LIST;
+        }
+        else
+        {
+            /* exit I/O emulator */
+            PT_LOG("I/O emulator exit()\n");
+            exit(1);
+        }
+    }
+    else
+    {
+        /* exit I/O emulator */
+        PT_LOG("I/O emulator exit()\n");
+        exit(1);
+    }
+
+    return reg_field;
+}
+
+/* initialize Interrupt Pin register */
+static uint32_t pt_irqpin_reg_init(struct pt_dev *ptdev,
+        struct pt_reg_info_tbl *reg, uint32_t real_offset)
+{
+    int reg_field = 0;
+
+    /* set Interrupt Pin register to use INTA# if it has */
+    if (ptdev->dev.config[real_offset])
+        reg_field = 0x01;
+
+    return reg_field;
+}
+
+/* initialize BAR */
+static uint32_t pt_bar_reg_init(struct pt_dev *ptdev,
+        struct pt_reg_info_tbl *reg, uint32_t real_offset)
+{
+    int reg_field = 0;
+    int index;
+
+    /* get BAR index */
+    index = pt_bar_offset_to_index(reg->offset);
+    if (index < 0)
+    {
+        /* exit I/O emulator */
+        PT_LOG("I/O emulator exit()\n");
+        exit(1);
+    }
+
+    /* set initial guest physical base address to -1 */
+    ptdev->bases[index].e_physbase = -1;
+
+    /* set BAR flag */
+    ptdev->bases[index].bar_flag = pt_bar_reg_parse(ptdev, reg);
+    if (ptdev->bases[index].bar_flag == PT_BAR_FLAG_UNUSED)
+        reg_field = PT_INVALID_REG;
+
+    return reg_field;
+}
+
+/* initialize Link Control 2 register */
+static uint32_t pt_linkctrl2_reg_init(struct pt_dev *ptdev,
+        struct pt_reg_info_tbl *reg, uint32_t real_offset)
+{
+    int reg_field = 0;
+
+    /* set Supported Link Speed */
+    reg_field |= 
+        (0x0F & 
+         ptdev->dev.config[(real_offset - reg->offset) + PCI_EXP_LNKCAP]);
+
+    return reg_field;
+}
+
+/* initialize Message Control register */
+static uint32_t pt_msgctrl_reg_init(struct pt_dev *ptdev,
+        struct pt_reg_info_tbl *reg, uint32_t real_offset)
+{
+    PCIDevice *d = (struct PCIDevice *)ptdev;
+    struct pci_dev *pdev = ptdev->pci_dev;
+    uint32_t reg_field = 0;
+    
+    /* use I/O device register's value as initial value */
+    reg_field |= *((uint16_t*)(d->config + real_offset));
+    
+    if (reg_field & PCI_MSI_FLAGS_ENABLE)
+    {
+        PT_LOG("MSI enabled already, disable first\n");
+        pci_write_word(pdev, real_offset, reg_field & ~PCI_MSI_FLAGS_ENABLE);
+    }
+    ptdev->msi->flags |= (reg_field | MSI_FLAG_UNINIT);
+    
+    /* All register is 0 after reset, except first 4 byte */
+    reg_field &= reg->ro_mask;
+    
+    return reg_field;
+}
+
+/* initialize Message Address register */
+static uint32_t pt_msgaddr32_reg_init(struct pt_dev *ptdev,
+        struct pt_reg_info_tbl *reg, uint32_t real_offset)
+{
+    PCIDevice *d = (struct PCIDevice *)ptdev;
+    uint32_t reg_field = 0;
+    
+    /* use I/O device register's value as initial value */
+    reg_field |= *((uint32_t*)(d->config + real_offset));
+    
+    return reg_field;
+}
+
+/* initialize Message Upper Address register */
+static uint32_t pt_msgaddr64_reg_init(struct pt_dev *ptdev,
+        struct pt_reg_info_tbl *reg, uint32_t real_offset)
+{
+    PCIDevice *d = (struct PCIDevice *)ptdev;
+    uint32_t reg_field = 0;
+    
+    /* no need to initialize in case of 32 bit type */
+    if (!(ptdev->msi->flags & PCI_MSI_FLAGS_64BIT))
+        return PT_INVALID_REG;
+    
+    /* use I/O device register's value as initial value */
+    reg_field |= *((uint32_t*)(d->config + real_offset));
+    
+    return reg_field;
+}
+
+/* this function will be called twice (for 32 bit and 64 bit type) */
+/* initialize Message Data register */
+static uint32_t pt_msgdata_reg_init(struct pt_dev *ptdev,
+        struct pt_reg_info_tbl *reg, uint32_t real_offset)
+{
+    PCIDevice *d = (struct PCIDevice *)ptdev;
+    uint32_t flags = ptdev->msi->flags;
+    uint32_t offset = reg->offset;
+    
+    /* check the offset whether matches the type or not */
+    if (((offset == PCI_MSI_DATA_64) &&  (flags & PCI_MSI_FLAGS_64BIT)) ||
+        ((offset == PCI_MSI_DATA_32) && !(flags & PCI_MSI_FLAGS_64BIT)))
+        return *((uint16_t*)(d->config + real_offset));
+    else
+        return PT_INVALID_REG;
+}
+
+/* initialize Message Control register for MSI-X */
+static uint32_t pt_msixctrl_reg_init(struct pt_dev *ptdev,
+        struct pt_reg_info_tbl *reg, uint32_t real_offset)
+{
+    PCIDevice *d = (struct PCIDevice *)ptdev;
+    struct pci_dev *pdev = ptdev->pci_dev;
+    uint16_t reg_field = 0;
+    
+    /* use I/O device register's value as initial value */
+    reg_field |= *((uint16_t*)(d->config + real_offset));
+    
+    if (reg_field & PCI_MSIX_ENABLE)
+    {
+        PT_LOG("MSIX enabled already, disable first\n");
+        pci_write_word(pdev, real_offset, reg_field & ~PCI_MSIX_ENABLE);
+        reg_field &= ~(PCI_MSIX_ENABLE | PCI_MSIX_MASK);
+    }
+    
+    return reg_field;
+}
+
+/* get register group size */
+static uint8_t pt_reg_grp_size_init(struct pt_dev *ptdev,
+        struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset)
+{
+    return grp_reg->grp_size;
+}
+
+/* get MSI Capability Structure register group size */
+static uint8_t pt_msi_size_init(struct pt_dev *ptdev,
+        struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset)
+{
+    PCIDevice *d = &ptdev->dev;
+    uint16_t msg_ctrl = 0;
+    uint8_t msi_size = 0xa;
+
+    msg_ctrl = *((uint16_t*)(d->config + (base_offset + PCI_MSI_FLAGS)));
+
+    /* check 64 bit address capable & Per-vector masking capable */
+    if (msg_ctrl & PCI_MSI_FLAGS_64BIT)
+        msi_size += 4;
+    if (msg_ctrl & PCI_MSI_FLAGS_MASK_BIT)
+        msi_size += 10;
+
+    ptdev->msi = malloc(sizeof(struct pt_msi_info));
+    if ( !ptdev->msi )
+    {
+        PT_LOG("error allocation pt_msi_info\n");
+        /* exit I/O emulator */
+        PT_LOG("I/O emulator exit()\n");
+        exit(1);
+    }
+    memset(ptdev->msi, 0, sizeof(struct pt_msi_info));
+    
+    return msi_size;
+}
+
+/* get MSI-X Capability Structure register group size */
+static uint8_t pt_msix_size_init(struct pt_dev *ptdev,
+        struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset)
+{
+    int ret = 0;
+
+    ret = pt_msix_init(ptdev, base_offset);
+
+    if (ret == -1)
+    {
+        /* exit I/O emulator */
+        PT_LOG("I/O emulator exit()\n");
+        exit(1);
+    }
+
+    return grp_reg->grp_size;
+}
+
+/* get Vendor Specific Capability Structure register group size */
+static uint8_t pt_vendor_size_init(struct pt_dev *ptdev,
+        struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset)
+{
+    return ptdev->dev.config[base_offset + 0x02];
+}
+
+/* read byte size emulate register */
+static int pt_byte_reg_read(struct pt_dev *ptdev,
+        struct pt_reg_tbl *cfg_entry,
+        uint8_t *value, uint8_t valid_mask)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint8_t valid_emu_mask = 0;
+
+    /* emulate byte register */
+    valid_emu_mask = reg->emu_mask & valid_mask;
+    *value = ((*value & ~valid_emu_mask) | 
+              (cfg_entry->data & valid_emu_mask));
+
+    return 0;
+}
+
+/* read word size emulate register */
+static int pt_word_reg_read(struct pt_dev *ptdev,
+        struct pt_reg_tbl *cfg_entry,
+        uint16_t *value, uint16_t valid_mask)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint16_t valid_emu_mask = 0;
+
+    /* emulate word register */
+    valid_emu_mask = reg->emu_mask & valid_mask;
+    *value = ((*value & ~valid_emu_mask) | 
+              (cfg_entry->data & valid_emu_mask));
+
+    return 0;
+}
+
+/* read long size emulate register */
+static int pt_long_reg_read(struct pt_dev *ptdev,
+        struct pt_reg_tbl *cfg_entry,
+        uint32_t *value, uint32_t valid_mask)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint32_t valid_emu_mask = 0;
+
+    /* emulate long register */
+    valid_emu_mask = reg->emu_mask & valid_mask;
+    *value = ((*value & ~valid_emu_mask) | 
+              (cfg_entry->data & valid_emu_mask));
+
+   return 0;
+}
+
+/* read BAR */
+static int pt_bar_reg_read(struct pt_dev *ptdev,
+        struct pt_reg_tbl *cfg_entry,
+        uint32_t *value, uint32_t valid_mask)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint32_t valid_emu_mask = 0;
+    uint32_t bar_emu_mask = 0;
+    int index;
+
+    /* get BAR index */
+    index = pt_bar_offset_to_index(reg->offset);
+    if (index < 0)
+    {
+        /* exit I/O emulator */
+        PT_LOG("I/O emulator exit()\n");
+        exit(1);
+    }
+
+    /* set emulate mask depend on BAR flag */
+    switch (ptdev->bases[index].bar_flag)
+    {
+    case PT_BAR_FLAG_MEM:
+        bar_emu_mask = PT_BAR_MEM_EMU_MASK;
+        break;
+    case PT_BAR_FLAG_IO:
+        bar_emu_mask = PT_BAR_IO_EMU_MASK;
+        break;
+    case PT_BAR_FLAG_UPPER:
+        *value = 0;
+        goto out;
+    default:
+        break;
+    }
+
+    /* emulate BAR */
+    valid_emu_mask = bar_emu_mask & valid_mask;
+    *value = ((*value & ~valid_emu_mask) | 
+              (cfg_entry->data & valid_emu_mask));
+
+out:
+   return 0;
+}
+
+/* write byte size emulate register */
+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)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint8_t writable_mask = 0;
+    uint8_t throughable_mask = 0;
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = ((*value & writable_mask) |
+                       (cfg_entry->data & ~writable_mask));
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = ((*value & throughable_mask) |
+              (dev_value & ~throughable_mask));
+
+    return 0;
+}
+
+/* write word size emulate register */
+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)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = ((*value & writable_mask) |
+                       (cfg_entry->data & ~writable_mask));
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = ((*value & throughable_mask) |
+              (dev_value & ~throughable_mask));
+
+    return 0;
+}
+
+/* write long size emulate register */
+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)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint32_t writable_mask = 0;
+    uint32_t throughable_mask = 0;
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = ((*value & writable_mask) |
+                       (cfg_entry->data & ~writable_mask));
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = ((*value & throughable_mask) |
+              (dev_value & ~throughable_mask));
+
+    return 0;
+}
+
+/* write Command register */
+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)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    uint16_t wr_value = *value;
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = ((*value & writable_mask) |
+                       (cfg_entry->data & ~writable_mask));
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = ((*value & throughable_mask) | (dev_value & ~throughable_mask));
+
+    /* mapping BAR */
+    pt_bar_mapping(ptdev, wr_value & PCI_COMMAND_IO, 
+                          wr_value & PCI_COMMAND_MEMORY);
+
+    return 0;
+}
+
+/* write BAR */
+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)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    struct pt_reg_grp_tbl *reg_grp_entry = NULL;
+    struct pt_reg_tbl *reg_entry = NULL;
+    struct pt_region *base = NULL;
+    PCIDevice *d = (PCIDevice *)&ptdev->dev;
+    PCIIORegion *r;
+    uint32_t writable_mask = 0;
+    uint32_t throughable_mask = 0;
+    uint32_t bar_emu_mask = 0;
+    uint32_t bar_ro_mask = 0;
+    uint32_t new_addr, last_addr;
+    uint32_t prev_offset;
+    uint32_t r_size = 0;
+    int index = 0;
+
+   /* get BAR index */
+    index = pt_bar_offset_to_index(reg->offset);
+    if (index < 0)
+    {
+        /* exit I/O emulator */
+        PT_LOG("I/O emulator exit()\n");
+        exit(1);
+    }
+
+    r = &d->io_regions[index];
+    r_size = r->size;
+    base = &ptdev->bases[index];
+    /* align resource size (memory type only) */
+    PT_GET_EMUL_SIZE(base->bar_flag, r_size);
+
+    /* check guest write value */
+    if (*value == PT_BAR_ALLF)
+    {
+        /* set register with resource size alligned to page size */
+        cfg_entry->data = ~(r_size - 1);
+        /* avoid writing ALL F to I/O device register */
+        *value = dev_value;
+    }
+    else
+    {
+        /* set emulate mask and read-only mask depend on BAR flag */
+        switch (ptdev->bases[index].bar_flag)
+        {
+        case PT_BAR_FLAG_MEM:
+            bar_emu_mask = PT_BAR_MEM_EMU_MASK;
+            bar_ro_mask = PT_BAR_MEM_RO_MASK;
+            break;
+        case PT_BAR_FLAG_IO:
+            new_addr = *value;
+            last_addr = new_addr + r_size - 1;
+            /* check 64K range */
+            if (last_addr <= new_addr || !new_addr || last_addr >= 0x10000)
+            {
+                PT_LOG("Guest attempt to set Base Address over the 64KB. "
+                    "[%02x:%02x.%x][Offset:%02xh][Range:%08xh-%08xh]\n",
+                    pci_bus_num(d->bus), 
+                    ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
+                    reg->offset, new_addr, last_addr);
+                /* just remove mapping */
+                r->addr = -1;
+                goto exit;
+            }
+            bar_emu_mask = PT_BAR_IO_EMU_MASK;
+            bar_ro_mask = PT_BAR_IO_RO_MASK;
+            break;
+        case PT_BAR_FLAG_UPPER:
+            if (*value)
+            {
+                PT_LOG("Guest attempt to set high MMIO Base Address. "
+                   "Ignore mapping. "
+                   "[%02x:%02x.%x][Offset:%02xh][High Address:%08xh]\n",
+                    pci_bus_num(d->bus), 
+                    ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
+                    reg->offset, *value);
+                /* clear lower address */
+                d->io_regions[index-1].addr = -1;
+            }
+            else
+            {
+                /* find lower 32bit BAR */
+                prev_offset = (reg->offset - 4);
+                reg_grp_entry = pt_find_reg_grp(ptdev, prev_offset);
+                if (reg_grp_entry)
+                {
+                    reg_entry = pt_find_reg(reg_grp_entry, prev_offset);
+                    if (reg_entry)
+                        /* restore lower address */
+                        d->io_regions[index-1].addr = reg_entry->data;
+                    else
+                        return -1;
+                }
+                else
+                    return -1;
+            }
+            cfg_entry->data = 0;
+            r->addr = -1;
+            goto exit;
+        }
+
+        /* modify emulate register */
+        writable_mask = bar_emu_mask & ~bar_ro_mask & valid_mask;
+        cfg_entry->data = ((*value & writable_mask) |
+                           (cfg_entry->data & ~writable_mask));
+        /* update the corresponding virtual region address */
+        r->addr = cfg_entry->data;
+
+        /* create value for writing to I/O device register */
+        throughable_mask = ~bar_emu_mask & valid_mask;
+        *value = ((*value & throughable_mask) |
+                  (dev_value & ~throughable_mask));
+    }
+
+exit:
+    return 0;
+}
+
+/* write Exp ROM BAR */
+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)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    struct pt_region *base = NULL;
+    PCIDevice *d = (PCIDevice *)&ptdev->dev;
+    PCIIORegion *r;
+    uint32_t writable_mask = 0;
+    uint32_t throughable_mask = 0;
+    uint32_t r_size = 0;
+
+    r = &d->io_regions[PCI_ROM_SLOT];
+    r_size = r->size;
+    base = &ptdev->bases[PCI_ROM_SLOT];
+    /* align memory type resource size */
+    PT_GET_EMUL_SIZE(base->bar_flag, r_size);
+
+    /* check guest write value */
+    if (*value == PT_BAR_ALLF)
+    {
+        /* set register with resource size alligned to page size */
+        cfg_entry->data = ~(r_size - 1);
+        /* avoid writing ALL F to I/O device register */
+        *value = dev_value;
+    }
+    else
+    {
+        /* modify emulate register */
+        writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+        cfg_entry->data = ((*value & writable_mask) |
+                           (cfg_entry->data & ~writable_mask));
+        /* update the corresponding virtual region address */
+        r->addr = cfg_entry->data;
+
+        /* create value for writing to I/O device register */
+        throughable_mask = ~reg->emu_mask & valid_mask;
+        *value = ((*value & throughable_mask) |
+                  (dev_value & ~throughable_mask));
+    }
+
+    return 0;
+}
+
+/* write Power Management Control/Status register */
+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)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    uint16_t pmcsr_mask = (PCI_PM_CTRL_PME_ENABLE | 
+                           PCI_PM_CTRL_DATA_SEL_MASK |
+                           PCI_PM_CTRL_PME_STATUS);
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask & ~pmcsr_mask;
+    /* ignore it when the requested state neither D3 nor D0 */
+    if (((*value & PCI_PM_CTRL_STATE_MASK) != PCI_PM_CTRL_STATE_MASK) &&
+        ((*value & PCI_PM_CTRL_STATE_MASK) != 0))
+        writable_mask &= ~PCI_PM_CTRL_STATE_MASK;
+
+    cfg_entry->data = ((*value & writable_mask) |
+                       (cfg_entry->data & ~writable_mask));
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = ((*value & throughable_mask) |
+              (dev_value & ~throughable_mask));
+
+    return 0;
+}
+
+/* write Device Control register */
+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)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    uint16_t devctrl_mask = (PCI_EXP_DEVCTL_AUX_PME | 0x8000);
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask & ~devctrl_mask;
+    cfg_entry->data = ((*value & writable_mask) |
+                       (cfg_entry->data & ~writable_mask));
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = ((*value & throughable_mask) |
+              (dev_value & ~throughable_mask));
+
+    return 0;
+}
+
+/* write Link Control register */
+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)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    uint16_t linkctrl_mask = (PCI_EXP_LNKCTL_ASPM | 0x04 |
+                              PCI_EXP_LNKCTL_DISABLE |
+                              PCI_EXP_LNKCTL_RETRAIN | 
+                              0x0400 | 0x0800 | 0xF000);
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask & 
~linkctrl_mask;
+    cfg_entry->data = ((*value & writable_mask) |
+                       (cfg_entry->data & ~writable_mask));
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = ((*value & throughable_mask) |
+              (dev_value & ~throughable_mask));
+
+    return 0;
+}
+
+/* write Device Control2 register */
+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)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    uint16_t devctrl2_mask = 0xFFE0;
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask & 
~devctrl2_mask;
+    cfg_entry->data = ((*value & writable_mask) |
+                       (cfg_entry->data & ~writable_mask));
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = ((*value & throughable_mask) |
+              (dev_value & ~throughable_mask));
+
+    return 0;
+}
+
+/* write Link Control2 register */
+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)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    uint16_t linkctrl2_mask = (0x0040 | 0xE000);
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask & 
+                    ~linkctrl2_mask;
+    cfg_entry->data = ((*value & writable_mask) |
+                       (cfg_entry->data & ~writable_mask));
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = ((*value & throughable_mask) |
+              (dev_value & ~throughable_mask));
+
+    return 0;
+}
+
+/* write Message Control register */
+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)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    uint16_t old_ctrl = cfg_entry->data;
+    PCIDevice *pd = (PCIDevice *)ptdev;
+
+    PT_LOG("[before] dev_val:%xh wr_val:%xh\n", dev_value, *value);
+
+    /* Currently no support for multi-vector */
+    if ((*value & PCI_MSI_FLAGS_QSIZE) != 0x0)
+        PT_LOG("try to set more than 1 vector ctrl %x\n", *value);
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = ((*value & writable_mask) |
+                       (cfg_entry->data & ~writable_mask));
+    /* update the msi_info too */
+    ptdev->msi->flags |= cfg_entry->data & 
+        ~(MSI_FLAG_UNINIT | PT_MSI_MAPPED | PCI_MSI_FLAGS_ENABLE);
+
+    PT_LOG("old_ctrl:%04xh new_ctrl:%04xh\n", old_ctrl, cfg_entry->data);
+    
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = ((*value & throughable_mask) | (dev_value & ~throughable_mask));
+
+    /* update MSI */
+    if (*value & PCI_MSI_FLAGS_ENABLE)
+    {
+        /* setup MSI pirq for the first time */
+        if (ptdev->msi->flags & MSI_FLAG_UNINIT)
+        {
+            /* Init physical one */
+            PT_LOG("setup msi for dev %x\n", pd->devfn);
+            if (pt_msi_setup(ptdev))
+            {
+                PT_LOG("pt_msi_setup error!!!\n");
+                return -1;
+            }
+            pt_msi_update(ptdev);
+
+            ptdev->msi->flags &= ~MSI_FLAG_UNINIT;
+            ptdev->msi->flags |= PT_MSI_MAPPED;
+        }
+        ptdev->msi->flags |= PCI_MSI_FLAGS_ENABLE;
+    }
+    else
+        ptdev->msi->flags &= ~PCI_MSI_FLAGS_ENABLE;
+
+    PT_LOG("[after] wr_val:%xh\n", *value);
+
+    return 0;
+}
+
+/* write Message Address register */
+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)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint32_t writable_mask = 0;
+    uint32_t throughable_mask = 0;
+    uint32_t old_addr = cfg_entry->data;
+
+    PT_LOG("[before] dev_val:%xh wr_val:%xh\n", dev_value, *value);
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = ((*value & writable_mask) |
+                       (cfg_entry->data & ~writable_mask));
+    /* update the msi_info too */
+    ptdev->msi->addr_lo = cfg_entry->data;
+    
+    PT_LOG("old_addr_lo:%08xh new_addr_lo:%08xh\n", old_addr, cfg_entry->data);
+    
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = ((*value & throughable_mask) | (dev_value & ~throughable_mask));
+
+    /* update MSI */
+    if (cfg_entry->data != old_addr)
+    {
+        if (ptdev->msi->flags & PCI_MSI_FLAGS_ENABLE)
+            pt_msi_update(ptdev);
+    }
+
+    PT_LOG("[after] wr_val:%xh\n", *value);
+
+    return 0;
+}
+
+/* write Message Upper Address register */
+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)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint32_t writable_mask = 0;
+    uint32_t throughable_mask = 0;
+    uint32_t old_addr = cfg_entry->data;
+
+    PT_LOG("[before] dev_val:%xh wr_val:%xh\n", dev_value, *value);
+
+    /* check whether the type is 64 bit or not */
+    if (!(ptdev->msi->flags & PCI_MSI_FLAGS_64BIT))
+    {
+        /* exit I/O emulator */
+        PT_LOG("why comes to Upper Address without 64 bit support??\n");
+        return -1;
+    }
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = ((*value & writable_mask) |
+                       (cfg_entry->data & ~writable_mask));
+    /* update the msi_info too */
+    ptdev->msi->addr_hi = cfg_entry->data;
+    
+    PT_LOG("old_addr_hi:%08xh new_addr_hi:%08xh\n", old_addr, cfg_entry->data);
+    
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = ((*value & throughable_mask) | (dev_value & ~throughable_mask));
+
+    /* update MSI */
+    if (cfg_entry->data != old_addr)
+    {
+        if (ptdev->msi->flags & PCI_MSI_FLAGS_ENABLE)
+            pt_msi_update(ptdev);
+    }
+
+    PT_LOG("[after] wr_val:%xh\n", *value);
+
+    return 0;
+}
+
+/* this function will be called twice (for 32 bit and 64 bit type) */
+/* write Message Data register */
+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)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    uint16_t old_data = cfg_entry->data;
+    uint32_t flags = ptdev->msi->flags;
+    uint32_t offset = reg->offset;
+
+    PT_LOG("[before] dev_val:%xh wr_val:%xh\n", dev_value, *value);
+
+    /* check the offset whether matches the type or not */
+    if (!((offset == PCI_MSI_DATA_64) &&  (flags & PCI_MSI_FLAGS_64BIT)) &&
+        !((offset == PCI_MSI_DATA_32) && !(flags & PCI_MSI_FLAGS_64BIT)))
+    {
+        /* exit I/O emulator */
+        PT_LOG("Error: the offset is not match with the 32/64 bit type!!\n");
+        return -1;
+    }
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = ((*value & writable_mask) |
+                       (cfg_entry->data & ~writable_mask));
+    /* update the msi_info too */
+    ptdev->msi->data = cfg_entry->data;
+
+    PT_LOG("old_data:%04xh new_data:%04xh\n", old_data, cfg_entry->data);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = ((*value & throughable_mask) | (dev_value & ~throughable_mask));
+
+    /* update MSI */
+    if (cfg_entry->data != old_data)
+    {
+        if (flags & PCI_MSI_FLAGS_ENABLE)
+            pt_msi_update(ptdev);
+    }
+
+    PT_LOG("[after] wr_val:%xh\n", *value);
+
+    return 0;
+}
+
+/* write Message Control register for MSI-X */
+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)
+{
+    struct pt_reg_info_tbl *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    uint16_t old_ctrl = cfg_entry->data;
+
+    PT_LOG("[before] dev_val:%xh wr_val:%xh\n", dev_value, *value);
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = ((*value & writable_mask) |
+                       (cfg_entry->data & ~writable_mask));
+
+    PT_LOG("old_ctrl:%04xh new_ctrl:%04xh\n", old_ctrl, cfg_entry->data);
+    
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = ((*value & throughable_mask) | (dev_value & ~throughable_mask));
+
+    /* update MSI-X */
+    if ((*value & PCI_MSIX_ENABLE) && !(*value & PCI_MSIX_MASK))
+        pt_msix_update(ptdev);
+
+    ptdev->msix->enabled = !!(*value & PCI_MSIX_ENABLE);
+
+    PT_LOG("[after] wr_val:%xh\n", *value);
+
+    return 0;
+}
+
 struct pt_dev * register_real_device(PCIBus *e_bus,
         const char *e_dev_name, int e_devfn, uint8_t r_bus, uint8_t r_dev,
         uint8_t r_func, uint32_t machine_irq, struct pci_access *pci_access)
 {
-    int rc = -1, i, pos;
+    int rc = -1, i;
     struct pt_dev *assigned_device = NULL;
     struct pci_dev *pci_dev;
     uint8_t e_device, e_intx;
@@ -540,7 +2719,6 @@ struct pt_dev * register_real_device(PCI
         dpci_infos.php_devs[PCI_TO_PHP_SLOT(free_pci_slot)].pt_dev = 
assigned_device;
 
     assigned_device->pci_dev = pci_dev;
-
 
     /* Assign device */
     machine_bdf.reg = 0;
@@ -555,18 +2733,22 @@ struct pt_dev * register_real_device(PCI
     for ( i = 0; i < PCI_CONFIG_SIZE; i++ )
         assigned_device->dev.config[i] = pci_read_byte(pci_dev, i);
 
-    if ( (pos = find_cap_offset(pci_dev, PCI_CAP_ID_MSI)) )
-        pt_msi_init(assigned_device, pos);
-
-    if ( (pos = find_cap_offset(pci_dev, PCI_CAP_ID_MSIX)) )
-        pt_msix_init(assigned_device, pos);
-
     /* Handle real device's MMIO/PIO BARs */
     pt_register_regions(assigned_device);
 
+    /* reinitialize each config register to be emulated */
+    rc = pt_config_init(assigned_device);
+    if ( rc < 0 ) {
+        return NULL;
+    }
+
     /* Bind interrupt */
+    if (!assigned_device->dev.config[0x3d])
+        goto out;
+
     e_device = (assigned_device->dev.devfn >> 3) & 0x1f;
-    e_intx = assigned_device->dev.config[0x3d]-1;
+    /* fix virtual interrupt pin to INTA# */
+    e_intx = 0;
 
     if ( PT_MACHINE_IRQ_AUTO == machine_irq )
     {
@@ -603,6 +2785,7 @@ struct pt_dev * register_real_device(PCI
             *(uint16_t *)(&assigned_device->dev.config[0x04]));
     }
 
+out:
     PT_LOG("Real physical device %02x:%02x.%x registered successfuly!\n", 
         r_bus, r_dev, r_func);
 
@@ -756,3 +2939,4 @@ int pt_init(PCIBus *e_bus, char *direct_
     /* Success */
     return 0;
 }
+
diff -r 1db0b09b290e -r 9cf72db44ee9 tools/ioemu/hw/pass-through.h
--- a/tools/ioemu/hw/pass-through.h     Fri Jul 04 11:51:59 2008 +0100
+++ b/tools/ioemu/hw/pass-through.h     Fri Jul 04 11:54:21 2008 +0100
@@ -21,6 +21,7 @@
 #include "vl.h"
 #include "pci/header.h"
 #include "pci/pci.h"
+#include "audio/sys-queue.h"
 
 /* Log acesss */
 #define PT_LOGGING_ENABLED
@@ -42,6 +43,40 @@
 #define PCI_EXP_DEVCAP_FLR      (1 << 28)
 #define PCI_EXP_DEVCTL_FLR      (1 << 15)
 #define PCI_BAR_ENTRIES         (6)
+
+/* because the current version of libpci (2.2.0) doesn't define these ID,
+ * so we define Capability ID here.
+ */
+/* SHPC Capability List Item reg group */
+#define PCI_CAP_ID_HOTPLUG      0x0C
+/* Subsystem ID and Subsystem Vendor ID Capability List Item reg group */
+#define PCI_CAP_ID_SSVID        0x0D
+/* interrupt masking & reporting supported */
+#define PCI_MSI_FLAGS_MASK_BIT  0x0100
+
+#define PT_INVALID_REG          0xFFFFFFFF      /* invalid register value */
+#define PT_BAR_ALLF             0xFFFFFFFF      /* BAR ALLF value */
+#define PT_BAR_MEM_RO_MASK      0x0000000F      /* BAR ReadOnly mask(Memory) */
+#define PT_BAR_MEM_EMU_MASK     0xFFFFFFF0      /* BAR emul mask(Memory) */
+#define PT_BAR_IO_RO_MASK       0x00000003      /* BAR ReadOnly mask(I/O) */
+#define PT_BAR_IO_EMU_MASK      0xFFFFFFFC      /* BAR emul mask(I/O) */
+enum {
+    PT_BAR_FLAG_MEM = 0,                        /* Memory type BAR */
+    PT_BAR_FLAG_IO,                             /* I/O type BAR */
+    PT_BAR_FLAG_UPPER,                          /* upper 64bit BAR */
+    PT_BAR_FLAG_UNUSED,                         /* unused BAR */
+};
+enum {
+    GRP_TYPE_HARDWIRED = 0,                     /* 0 Hardwired reg group */
+    GRP_TYPE_EMU,                               /* emul reg group */
+};
+
+#define PT_GET_EMUL_SIZE(flag, r_size) do { \
+    if (flag == PT_BAR_FLAG_MEM) {\
+        r_size = (((r_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)); \
+    }\
+} while(0)
+
 
 struct pt_region {
     /* Virtual phys base & size */
@@ -49,30 +84,32 @@ struct pt_region {
     uint32_t e_size;
     /* Index of region in qemu */
     uint32_t memory_index;
+    /* BAR flag */
+    uint32_t bar_flag;
     /* Translation of the emulated address */
     union {
-        uint32_t maddr;
-        uint32_t pio_base;
-        uint32_t u;
+        uint64_t maddr;
+        uint64_t pio_base;
+        uint64_t u;
     } access;
 };
 
 struct pt_msi_info {
     uint32_t flags;
-    int offset;
-    int size;
-    int pirq;  /* guest pirq corresponding */
+    int pirq;          /* guest pirq corresponding */
+    uint32_t addr_lo;  /* guest message address */
+    uint32_t addr_hi;  /* guest message upper address */
+    uint16_t data;     /* guest message data */
 };
 
 struct msix_entry_info {
-    int pirq;   /* -1 means unmapped */
-    int flags;  /* flags indicting whether MSI ADDR or DATA is updated */
+    int pirq;          /* -1 means unmapped */
+    int flags;         /* flags indicting whether MSI ADDR or DATA is updated 
*/
     uint32_t io_mem[4];
 };
 
 struct pt_msix_info {
     int enabled;
-    int offset;
     int total_entries;
     int bar_index;
     uint32_t table_off;
@@ -89,8 +126,10 @@ struct pt_msix_info {
 */
 struct pt_dev {
     PCIDevice dev;
-    struct pci_dev *pci_dev;                     /* libpci struct */
+    struct pci_dev *pci_dev;                    /* libpci struct */
     struct pt_region bases[PCI_NUM_REGIONS];    /* Access regions */
+    QEMU_LIST_HEAD (reg_grp_tbl_listhead, pt_reg_grp_tbl) reg_grp_tbl_head;
+                                                /* emul reg group list */
     struct pt_msi_info *msi;                    /* MSI virtualization */
     struct pt_msix_info *msix;                  /* MSI-X virtualization */
 };
@@ -113,5 +152,121 @@ struct pci_config_cf8 {
 
 int pt_init(PCIBus * e_bus, char * direct_pci);
 
+/* emul reg group management table */
+struct pt_reg_grp_tbl {
+    /* emul reg group list */
+    QEMU_LIST_ENTRY (pt_reg_grp_tbl) entries;
+    /* emul reg group info table */
+    struct pt_reg_grp_info_tbl *reg_grp;
+    /* emul reg group base offset */
+    uint32_t base_offset;
+    /* emul reg group size */
+    uint8_t size;
+    /* emul reg management table list */
+    QEMU_LIST_HEAD (reg_tbl_listhead, pt_reg_tbl) reg_tbl_head;
+};
+
+/* emul reg group size initialize method */
+typedef uint8_t (*pt_reg_size_init) (struct pt_dev *ptdev, 
+                                     struct pt_reg_grp_info_tbl *grp_reg, 
+                                     uint32_t base_offset);
+/* emul reg group infomation table */
+struct pt_reg_grp_info_tbl {
+    /* emul reg group ID */
+    uint8_t grp_id;
+    /* emul reg group type */
+    uint8_t grp_type;
+    /* emul reg group size */
+    uint8_t grp_size;
+    /* emul reg get size method */
+    pt_reg_size_init size_init;
+    /* emul reg info table */
+    struct pt_reg_info_tbl *emu_reg_tbl;
+};
+
+/* emul reg management table */
+struct pt_reg_tbl {
+    /* emul reg table list */
+    QEMU_LIST_ENTRY (pt_reg_tbl) entries;
+    /* emul reg info table */
+    struct pt_reg_info_tbl *reg;
+    /* emul reg value */
+    uint32_t data;
+};
+
+/* emul reg initialize method */
+typedef uint32_t (*conf_reg_init) (struct pt_dev *ptdev, 
+                                   struct pt_reg_info_tbl *reg, 
+                                   uint32_t real_offset);
+/* emul reg long write method */
+typedef int (*conf_dword_write) (struct pt_dev *ptdev,
+                                 struct pt_reg_tbl *cfg_entry, 
+                                 uint32_t *value, 
+                                 uint32_t dev_value,
+                                 uint32_t valid_mask);
+/* emul reg word write method */
+typedef int (*conf_word_write) (struct pt_dev *ptdev,
+                                struct pt_reg_tbl *cfg_entry, 
+                                uint16_t *value, 
+                                uint16_t dev_value,
+                                uint16_t valid_mask);
+/* emul reg byte write method */
+typedef int (*conf_byte_write) (struct pt_dev *ptdev,
+                                struct pt_reg_tbl *cfg_entry, 
+                                uint8_t *value, 
+                                uint8_t dev_value,
+                                uint8_t valid_mask);
+/* emul reg long read methods */
+typedef int (*conf_dword_read) (struct pt_dev *ptdev,
+                                struct pt_reg_tbl *cfg_entry, 
+                                uint32_t *value,
+                                uint32_t valid_mask);
+/* emul reg word read method */
+typedef int (*conf_word_read) (struct pt_dev *ptdev,
+                               struct pt_reg_tbl *cfg_entry, 
+                               uint16_t *value,
+                               uint16_t valid_mask);
+/* emul reg byte read method */
+typedef int (*conf_byte_read) (struct pt_dev *ptdev,
+                               struct pt_reg_tbl *cfg_entry, 
+                               uint8_t *value,
+                               uint8_t valid_mask);
+
+/* emul reg infomation table */
+struct pt_reg_info_tbl {
+    /* reg relative offset */
+    uint32_t offset;
+    /* reg size */
+    uint32_t size;
+    /* reg initial value */
+    uint32_t init_val;
+    /* reg read only field mask (ON:RO/ROS, OFF:other) */
+    uint32_t ro_mask;
+    /* reg emulate field mask (ON:emu, OFF:passthrough) */
+    uint32_t emu_mask;
+    /* emul reg initialize method */
+    conf_reg_init init;
+    union {
+        struct {
+            /* emul reg long write method */
+            conf_dword_write write;
+            /* emul reg long read method */
+            conf_dword_read read;
+        } dw;
+        struct {
+            /* emul reg word write method */
+            conf_word_write write;
+            /* emul reg word read method */
+            conf_word_read read;
+        } w;
+        struct {
+            /* emul reg byte write method */
+            conf_byte_write write;
+            /* emul reg byte read method */
+            conf_byte_read read;
+        } b;
+    } u;
+};
+
 #endif /* __PASSTHROUGH_H__ */
 
diff -r 1db0b09b290e -r 9cf72db44ee9 tools/ioemu/hw/pci.c
--- a/tools/ioemu/hw/pci.c      Fri Jul 04 11:51:59 2008 +0100
+++ b/tools/ioemu/hw/pci.c      Fri Jul 04 11:54:21 2008 +0100
@@ -641,3 +641,34 @@ PCIBus *pci_bridge_init(PCIBus *bus, int
     s->bus = pci_register_secondary_bus(&s->dev, map_irq);
     return s->bus;
 }
+
+int pt_chk_bar_overlap(PCIBus *bus, int devfn, uint32_t addr, uint32_t size)
+{
+    PCIDevice *devices = (PCIDevice *)bus->devices;
+    PCIIORegion *r;
+    int ret = 0;
+    int i, j;
+
+    /* check Overlapped to Base Address */
+    for (i=0; i<256; i++, devices++)
+    {
+        if ((devices == NULL) || (devices->devfn == devfn))
+            continue;
+
+        for (j=0; j<PCI_NUM_REGIONS; j++)
+        {
+            r = &devices->io_regions[j];
+            if ((addr < (r->addr + r->size)) && ((addr + size) > r->addr))
+            {
+                printf("Overlapped to device[%02x:%02x.%x] region:%d addr:%08x"
+                    " size:%08x\n", bus->bus_num, (devices->devfn >> 3) & 0x1F,
+                    (devices->devfn & 0x7), j, r->addr, r->size);
+                ret = 1;
+                goto out;
+            }
+        }
+    }
+
+out:
+    return ret;
+}
diff -r 1db0b09b290e -r 9cf72db44ee9 tools/ioemu/hw/pt-msi.c
--- a/tools/ioemu/hw/pt-msi.c   Fri Jul 04 11:51:59 2008 +0100
+++ b/tools/ioemu/hw/pt-msi.c   Fri Jul 04 11:54:21 2008 +0100
@@ -23,60 +23,11 @@
 #include <sys/mman.h>
 
 /* MSI virtuailization functions */
-#define PT_MSI_CTRL_WR_MASK_HI      (0x1)
-#define PT_MSI_CTRL_WR_MASK_LO      (0x8E)
-#define PT_MSI_DATA_WR_MASK         (0x38)
-int pt_msi_init(struct pt_dev *dev, int pos)
-{
-    uint8_t id;
-    uint16_t flags;
-    struct pci_dev *pd = dev->pci_dev;
-    PCIDevice *d = (struct PCIDevice *)dev;
-
-    id = pci_read_byte(pd, pos + PCI_CAP_LIST_ID);
-
-    if ( id != PCI_CAP_ID_MSI )
-    {
-        PT_LOG("pt_msi_init: error id %x pos %x\n", id, pos);
-        return -1;
-    }
-
-    dev->msi = malloc(sizeof(struct pt_msi_info));
-    if ( !dev->msi )
-    {
-        PT_LOG("pt_msi_init: error allocation pt_msi_info\n");
-        return -1;
-    }
-    memset(dev->msi, 0, sizeof(struct pt_msi_info));
-
-    dev->msi->offset = pos;
-    dev->msi->size = 0xa;
-
-    flags = pci_read_byte(pd, pos + PCI_MSI_FLAGS);
-    if ( flags & PCI_MSI_FLAGS_ENABLE )
-    {
-        PT_LOG("pt_msi_init: MSI enabled already, disable first\n");
-        pci_write_byte(pd, pos + PCI_MSI_FLAGS, flags & ~PCI_MSI_FLAGS_ENABLE);
-    }
-    dev->msi->flags |= (flags | MSI_FLAG_UNINIT);
-
-    if ( flags & PCI_MSI_FLAGS_64BIT )
-        dev->msi->size += 4;
-    if ( flags & PCI_MSI_FLAGS_PVMASK )
-        dev->msi->size += 10;
-
-    /* All register is 0 after reset, except first 4 byte */
-    *(uint32_t *)(&d->config[pos]) = pci_read_long(pd, pos);
-    d->config[pos + 2] &=  PT_MSI_CTRL_WR_MASK_LO;
-    d->config[pos + 3] &=  PT_MSI_CTRL_WR_MASK_HI;
-
-    return 0;
-}
 
 /*
  * setup physical msi, but didn't enable it
  */
-static int pt_msi_setup(struct pt_dev *dev)
+int pt_msi_setup(struct pt_dev *dev)
 {
     int pirq = -1;
 
@@ -107,56 +58,7 @@ static int pt_msi_setup(struct pt_dev *d
     return 0;
 }
 
-/*
- * caller should make sure mask is supported
- */
-static uint32_t get_msi_gmask(struct pt_dev *d)
-{
-    struct PCIDevice *pd = (struct PCIDevice *)d;
-
-    if ( d->msi->flags & PCI_MSI_FLAGS_64BIT )
-        return *(uint32_t *)(pd->config + d->msi->offset + 0xc);
-    else
-        return *(uint32_t *)(pd->config + d->msi->offset + 0x10);
-
-}
-
-static uint16_t get_msi_gdata(struct pt_dev *d)
-{
-    struct PCIDevice *pd = (struct PCIDevice *)d;
-
-    if ( d->msi->flags & PCI_MSI_FLAGS_64BIT )
-        return *(uint16_t *)(pd->config + d->msi->offset + PCI_MSI_DATA_64);
-    else
-        return *(uint16_t *)(pd->config + d->msi->offset + PCI_MSI_DATA_32);
-}
-
-static uint64_t get_msi_gaddr(struct pt_dev *d)
-{
-    struct PCIDevice *pd = (struct PCIDevice *)d;
-    uint32_t addr_hi;
-    uint64_t addr = 0;
-
-    addr =(uint64_t)(*(uint32_t *)(pd->config +
-                     d->msi->offset + PCI_MSI_ADDRESS_LO));
-
-    if ( d->msi->flags & PCI_MSI_FLAGS_64BIT )
-    {
-        addr_hi = *(uint32_t *)(pd->config + d->msi->offset
-                                + PCI_MSI_ADDRESS_HI);
-        addr |= (uint64_t)addr_hi << 32;
-    }
-    return addr;
-}
-
-static uint8_t get_msi_gctrl(struct pt_dev *d)
-{
-    struct PCIDevice *pd = (struct PCIDevice *)d;
-
-    return  *(uint8_t *)(pd->config + d->msi->offset + PCI_MSI_FLAGS);
-}
-
-static uint32_t __get_msi_gflags(uint32_t data, uint64_t addr)
+uint32_t __get_msi_gflags(uint32_t data, uint64_t addr)
 {
     uint32_t result = 0;
     int rh, dm, dest_id, deliv_mode, trig_mode;
@@ -174,320 +76,27 @@ static uint32_t __get_msi_gflags(uint32_
     return result;
 }
 
-static uint32_t get_msi_gflags(struct pt_dev *d)
-{
-    uint16_t data = get_msi_gdata(d);
-    uint64_t addr = get_msi_gaddr(d);
-
-    return __get_msi_gflags(data, addr);
-}
-
-/*
- * This may be arch different
- */
-static inline uint8_t get_msi_gvec(struct pt_dev *d)
-{
-    return get_msi_gdata(d) & 0xff;
-}
-
 /*
  * Update msi mapping, usually called when MSI enabled,
  * except the first time
  */
-static int pt_msi_update(struct pt_dev *d)
-{
-    PT_LOG("now update msi with pirq %x gvec %x\n",
-            d->msi->pirq, get_msi_gvec(d));
-    return xc_domain_update_msi_irq(xc_handle, domid, get_msi_gvec(d),
-                                     d->msi->pirq, get_msi_gflags(d));
-}
-
-static int pt_msi_enable(struct pt_dev *d, int enable)
-{
-    uint16_t ctrl;
-    struct pci_dev *pd = d->pci_dev;
-
-    if ( !pd )
-        return -1;
-
-    ctrl = pci_read_word(pd, d->msi->offset + PCI_MSI_FLAGS);
-
-    if ( enable )
-        ctrl |= PCI_MSI_FLAGS_ENABLE;
-    else
-        ctrl &= ~PCI_MSI_FLAGS_ENABLE;
-
-    pci_write_word(pd, d->msi->offset + PCI_MSI_FLAGS, ctrl);
-    return 0;
-}
-
-static int pt_msi_control_update(struct pt_dev *d, uint16_t old_ctrl)
-{
-    uint16_t new_ctrl;
-    PCIDevice *pd = (PCIDevice *)d;
-
-    new_ctrl = get_msi_gctrl(d);
-
-    PT_LOG("old_ctrl %x new_Ctrl %x\n", old_ctrl, new_ctrl);
-
-    if ( new_ctrl & PCI_MSI_FLAGS_ENABLE )
-    {
-        if ( d->msi->flags & MSI_FLAG_UNINIT )
-        {
-            /* Init physical one */
-            PT_LOG("setup msi for dev %x\n", pd->devfn);
-            if ( pt_msi_setup(d) )
-            {
-                PT_LOG("pt_msi_setup error!!!\n");
-                return -1;
-            }
-            pt_msi_update(d);
-
-            d->msi->flags &= ~MSI_FLAG_UNINIT;
-            d->msi->flags |= PT_MSI_MAPPED;
-
-            /* Enable physical MSI only after bind */
-            pt_msi_enable(d, 1);
-        }
-        else if ( !(old_ctrl & PCI_MSI_FLAGS_ENABLE) )
-            pt_msi_enable(d, 1);
-    }
-    else if ( old_ctrl & PCI_MSI_FLAGS_ENABLE )
-        pt_msi_enable(d, 0);
-
-    /* Currently no support for multi-vector */
-    if ( (new_ctrl & PCI_MSI_FLAGS_QSIZE) != 0x0 )
-        PT_LOG("try to set more than 1 vector ctrl %x\n", new_ctrl);
-
-    return 0;
-}
-
-static int
-pt_msi_map_update(struct pt_dev *d, uint32_t old_data, uint64_t old_addr)
-{
-    uint32_t data;
-    uint64_t addr;
-
-    data = get_msi_gdata(d);
-    addr = get_msi_gaddr(d);
-
-    PT_LOG("old_data %x old_addr %lx data %x addr %lx\n",
-            old_data, old_addr, data, addr);
-
-    if ( data != old_data || addr != old_addr )
-        if ( get_msi_gctrl(d) & PCI_MSI_FLAGS_ENABLE )
-            pt_msi_update(d);
-
-    return 0;
-}
-
-static int pt_msi_mask_update(struct pt_dev *d, uint32_t old_mask)
-{
-    struct pci_dev *pd = d->pci_dev;
-    uint32_t mask;
-    int offset;
-
-    if ( !(d->msi->flags & PCI_MSI_FLAGS_PVMASK) )
-        return -1;
-
-    mask = get_msi_gmask(d);
-
-    if ( d->msi->flags & PCI_MSI_FLAGS_64BIT )
-        offset = d->msi->offset + 0xc;
-    else
-        offset = d->msi->offset + 0x10;
-
-    if ( old_mask != mask )
-        pci_write_long(pd, offset, mask);
-
-    return 0;
-}
-
-#define ACCESSED_DATA 0x2
-#define ACCESSED_MASK 0x4
-#define ACCESSED_ADDR 0x8
-#define ACCESSED_CTRL 0x10
-
-int pt_msi_write(struct pt_dev *d, uint32_t addr, uint32_t val, uint32_t len)
-{
-    struct pci_dev *pd;
-    int i, cur = addr;
-    uint8_t value, flags = 0;
-    uint16_t old_ctrl = 0, old_data = 0;
-    uint32_t old_mask = 0;
-    uint64_t old_addr = 0;
-    PCIDevice *dev = (PCIDevice *)d;
-    int can_write = 1;
-
-    if ( !d || !d->msi )
-        return 0;
-
-    if ( (addr >= (d->msi->offset + d->msi->size) ) ||
-         (addr + len) < d->msi->offset)
-        return 0;
-
-    PT_LOG("addr %x val %x len %x offset %x size %x\n",
-            addr, val, len, d->msi->offset, d->msi->size);
-
-    pd = d->pci_dev;
-    old_ctrl = get_msi_gctrl(d);
-    old_addr = get_msi_gaddr(d);
-    old_data = get_msi_gdata(d);
-
-    if ( d->msi->flags & PCI_MSI_FLAGS_PVMASK )
-        old_mask = get_msi_gmask(d);
-
-    for ( i = 0; i < len; i++, cur++ )
-    {
-        int off;
-        uint8_t orig_value;
-
-        if ( cur < d->msi->offset )
-            continue;
-        else if ( cur >= (d->msi->offset + d->msi->size) )
-            break;
-
-        off = cur - d->msi->offset;
-        value = (val >> (i * 8)) & 0xff;
-
-        switch ( off )
-        {
-            case 0x0 ... 0x1:
-                can_write = 0;
-                break;
-            case 0x2:
-            case 0x3:
-                flags |= ACCESSED_CTRL;
-
-                orig_value = pci_read_byte(pd, d->msi->offset + off);
-
-                orig_value &= (off == 2) ? PT_MSI_CTRL_WR_MASK_LO:
-                                      PT_MSI_CTRL_WR_MASK_HI;
-
-                orig_value |= value & ( (off == 2) ? ~PT_MSI_CTRL_WR_MASK_LO:
-                                              ~PT_MSI_CTRL_WR_MASK_HI);
-                value = orig_value;
-                break;
-            case 0x4 ... 0x7:
-                flags |= ACCESSED_ADDR;
-                /* bit 4 ~ 11 is reserved for MSI in x86 */
-                if ( off == 0x4 )
-                    value &= 0x0f;
-                if ( off == 0x5 )
-                    value &= 0xf0;
-                break;
-            case 0x8 ... 0xb:
-                if ( d->msi->flags & PCI_MSI_FLAGS_64BIT )
-                {
-                    /* Up 32bit is reserved in x86 */
-                    flags |= ACCESSED_ADDR;
-                    if ( value )
-                        PT_LOG("Write up32 addr with %x \n", value);
-                }
-                else
-                {
-                    if ( off == 0xa || off == 0xb )
-                        can_write = 0;
-                    else
-                        flags |= ACCESSED_DATA;
-                    if ( off == 0x9 )
-                        value &= ~PT_MSI_DATA_WR_MASK;
-                }
-                break;
-            case 0xc ... 0xf:
-                if ( d->msi->flags & PCI_MSI_FLAGS_64BIT )
-                {
-                    if ( off == 0xe || off == 0xf )
-                        can_write = 0;
-                    else
-                    {
-                        flags |= ACCESSED_DATA;
-                        if (off == 0xd)
-                            value &= ~PT_MSI_DATA_WR_MASK;
-                    }
-                }
-                else
-                {
-                    if ( d->msi->flags & PCI_MSI_FLAGS_PVMASK )
-                        flags |= ACCESSED_MASK;
-                    else
-                        PT_LOG("why comes to MASK without mask support??\n");
-                }
-                break;
-            case 0x10 ... 0x13:
-                if ( d->msi->flags & PCI_MSI_FLAGS_64BIT )
-                {
-                    if ( d->msi->flags & PCI_MSI_FLAGS_PVMASK )
-                        flags |= ACCESSED_MASK;
-                    else
-                        PT_LOG("why comes to MASK without mask support??\n");
-                }
-                else
-                    can_write = 0;
-                break;
-            case 0x14 ... 0x18:
-                can_write = 0;
-                break;
-            default:
-                PT_LOG("Non MSI register!!!\n");
-                break;
-        }
-
-        if ( can_write )
-            dev->config[cur] = value;
-    }
-
-    if ( flags & ACCESSED_DATA || flags & ACCESSED_ADDR )
-        pt_msi_map_update(d, old_data, old_addr);
-
-    if ( flags & ACCESSED_MASK )
-        pt_msi_mask_update(d, old_mask);
-
-    /* This will enable physical one, do it in last step */
-    if ( flags & ACCESSED_CTRL )
-        pt_msi_control_update(d, old_ctrl);
-
-    return 1;
-}
-
-int pt_msi_read(struct pt_dev *d, int addr, int len, uint32_t *val)
-{
-    int e_addr = addr, e_len = len, offset = 0, i;
-    uint8_t e_val = 0;
-    PCIDevice *pd = (PCIDevice *)d;
-
-    if ( !d || !d->msi )
-        return 0;
-
-    if ( (addr > (d->msi->offset + d->msi->size) ) ||
-         (addr + len) <= d->msi->offset )
-        return 0;
-
-    PT_LOG("pt_msi_read addr %x len %x val %x offset %x size %x\n",
-            addr, len, *val, d->msi->offset, d->msi->size);
-
-    if ( (addr + len ) > (d->msi->offset + d->msi->size) )
-        e_len -= addr + len - d->msi->offset - d->msi->size;
-
-    if ( addr < d->msi->offset )
-    {
-        e_addr = d->msi->offset;
-        offset = d->msi->offset - addr;
-        e_len -= offset;
-    }
-
-    for ( i = 0; i < e_len; i++ )
-    {
-        e_val = *(uint8_t *)(&pd->config[e_addr] + i);
-        *val &= ~(0xff << ( (offset + i) * 8));
-        *val |= (e_val << ( (offset + i) * 8));
-    }
-
-    return e_len;
+int pt_msi_update(struct pt_dev *d)
+{
+    uint8_t gvec = 0;
+    uint32_t gflags = 0;
+    uint64_t addr = 0;
+    
+    /* get vector, address, flags info, etc. */
+    gvec = d->msi->data & 0xFF;
+    addr = (uint64_t)d->msi->addr_hi << 32 | d->msi->addr_lo;
+    gflags = __get_msi_gflags(d->msi->data, addr);
+    
+    PT_LOG("now update msi with pirq %x gvec %x\n", d->msi->pirq, gvec);
+    return xc_domain_update_msi_irq(xc_handle, domid, gvec,
+                                     d->msi->pirq, gflags);
 }
 
 /* MSI-X virtulization functions */
-#define PT_MSIX_CTRL_WR_MASK_HI      (0xC0)
 static void mask_physical_msix_entry(struct pt_dev *dev, int entry_nr, int 
mask)
 {
     void *phys_off;
@@ -538,7 +147,7 @@ static int pt_msix_update_one(struct pt_
     return 0;
 }
 
-static int pt_msix_update(struct pt_dev *dev)
+int pt_msix_update(struct pt_dev *dev)
 {
     struct pt_msix_info *msix = dev->msix;
     int i;
@@ -671,7 +280,7 @@ int pt_msix_init(struct pt_dev *dev, int
 int pt_msix_init(struct pt_dev *dev, int pos)
 {
     uint8_t id;
-    uint16_t flags, control;
+    uint16_t control;
     int i, total_entries, table_off, bar_index;
     uint64_t bar_base;
     struct pci_dev *pd = dev->pci_dev;
@@ -698,21 +307,11 @@ int pt_msix_init(struct pt_dev *dev, int
     memset(dev->msix, 0, sizeof(struct pt_msix_info)
                          + total_entries*sizeof(struct msix_entry_info));
     dev->msix->total_entries = total_entries;
-    dev->msix->offset = pos;
     for ( i = 0; i < total_entries; i++ )
         dev->msix->msix_entry[i].pirq = -1;
 
     dev->msix->mmio_index =
         cpu_register_io_memory(0, pci_msix_read, pci_msix_write, dev);
-
-    flags = pci_read_word(pd, pos + PCI_MSI_FLAGS);
-    if ( flags & PCI_MSIX_ENABLE )
-    {
-        PT_LOG("MSIX enabled already, disable first\n");
-        pci_write_word(pd, pos + PCI_MSI_FLAGS, flags & ~PCI_MSIX_ENABLE);
-        *(uint16_t *)&dev->dev.config[pos + PCI_MSI_FLAGS]
-            = flags & ~(PCI_MSIX_ENABLE | PCI_MSIX_MASK);
-    }
 
     table_off = pci_read_long(pd, pos + PCI_MSIX_TABLE);
     bar_index = dev->msix->bar_index = table_off & PCI_MSIX_BIR;
@@ -733,131 +332,3 @@ int pt_msix_init(struct pt_dev *dev, int
            (unsigned long)dev->msix->phys_iomem_base);
     return 0;
 }
-
-static int pt_msix_enable(struct pt_dev *d, int enable)
-{
-    uint16_t ctrl;
-    struct pci_dev *pd = d->pci_dev;
-
-    if ( !pd )
-        return -1;
-
-    ctrl = pci_read_word(pd, d->msix->offset + PCI_MSI_FLAGS);
-    if ( enable )
-        ctrl |= PCI_MSIX_ENABLE;
-    else
-        ctrl &= ~PCI_MSIX_ENABLE;
-    pci_write_word(pd, d->msix->offset + PCI_MSI_FLAGS, ctrl);
-    d->msix->enabled = !!enable;
-
-    return 0;
-}
-
-static int pt_msix_func_mask(struct pt_dev *d, int mask)
-{
-    uint16_t ctrl;
-    struct pci_dev *pd = d->pci_dev;
-
-    if ( !pd )
-        return -1;
-
-    ctrl = pci_read_word(pd, d->msix->offset + PCI_MSI_FLAGS);
-
-    if ( mask )
-        ctrl |= PCI_MSIX_MASK;
-    else
-        ctrl &= ~PCI_MSIX_MASK;
-
-    pci_write_word(pd, d->msix->offset + PCI_MSI_FLAGS, ctrl);
-    return 0;
-}
-
-static int pt_msix_control_update(struct pt_dev *d)
-{
-    PCIDevice *pd = (PCIDevice *)d;
-    uint16_t ctrl = *(uint16_t *)(&pd->config[d->msix->offset + 2]);
-
-    if ( ctrl & PCI_MSIX_ENABLE && !(ctrl & PCI_MSIX_MASK ) )
-        pt_msix_update(d);
-
-    pt_msix_func_mask(d, ctrl & PCI_MSIX_MASK);
-    pt_msix_enable(d, ctrl & PCI_MSIX_ENABLE);
-
-    return 0;
-}
-
-int pt_msix_write(struct pt_dev *d, uint32_t addr, uint32_t val, uint32_t len)
-{
-    struct pci_dev *pd;
-    int i, cur = addr;
-    uint8_t value;
-    PCIDevice *dev = (PCIDevice *)d;
-
-    if ( !d || !d->msix )
-        return 0;
-
-    if ( (addr >= (d->msix->offset + 4) ) ||
-         (addr + len) < d->msix->offset)
-        return 0;
-
-    PT_LOG("addr %x val %x len %x offset %x\n",
-            addr, val, len, d->msix->offset);
-
-    pd = d->pci_dev;
-
-    for ( i = 0; i < len; i++, cur++ )
-    {
-        uint8_t orig_value;
-
-        if ( cur != d->msix->offset + 3 )
-            continue;
-
-        value = (val >> (i * 8)) & 0xff;
-
-        orig_value = pci_read_byte(pd, cur);
-        value = (orig_value & ~PT_MSIX_CTRL_WR_MASK_HI) |
-                (value & PT_MSIX_CTRL_WR_MASK_HI);
-        dev->config[cur] = value;
-        pt_msix_control_update(d);
-        return 1;
-    }
-
-    return 0;
-}
-
-int pt_msix_read(struct pt_dev *d, int addr, int len, uint32_t *val)
-{
-    int e_addr = addr, e_len = len, offset = 0, i;
-    uint8_t e_val = 0;
-    PCIDevice *pd = (PCIDevice *)d;
-
-    if ( !d || !d->msix )
-        return 0;
-
-    if ( (addr > (d->msix->offset + 3) ) ||
-         (addr + len) <= d->msix->offset )
-        return 0;
-
-    if ( (addr + len ) > (d->msix->offset + 3) )
-        e_len -= addr + len - d->msix->offset - 3;
-
-    if ( addr < d->msix->offset )
-    {
-        e_addr = d->msix->offset;
-        offset = d->msix->offset - addr;
-        e_len -= offset;
-    }
-
-    for ( i = 0; i < e_len; i++ )
-    {
-        e_val = *(uint8_t *)(&pd->config[e_addr] + i);
-        *val &= ~(0xff << ( (offset + i) * 8));
-        *val |= (e_val << ( (offset + i) * 8));
-    }
-
-    PT_LOG("addr %x len %x val %x offset %x\n",
-            addr, len, *val, d->msix->offset);
-
-    return e_len;
-}
-
diff -r 1db0b09b290e -r 9cf72db44ee9 tools/ioemu/hw/pt-msi.h
--- a/tools/ioemu/hw/pt-msi.h   Fri Jul 04 11:51:59 2008 +0100
+++ b/tools/ioemu/hw/pt-msi.h   Fri Jul 04 11:54:21 2008 +0100
@@ -64,8 +64,6 @@
 #define     MSI_ADDR_REDIRECTION_CPU   (0 << MSI_ADDR_REDIRECTION_SHIFT)
 #define     MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT)
 
-#define PCI_MSI_FLAGS_PVMASK           0x100
-
 #define AUTO_ASSIGN -1
 
 /* shift count for gflags */
@@ -76,13 +74,16 @@
 #define GLFAGS_SHIFT_TRG_MODE       15
 
 int
-pt_msi_init(struct pt_dev *dev, int pos);
+pt_msi_setup(struct pt_dev *dev);
+
+uint32_t
+__get_msi_gflags(uint32_t data, uint64_t addr);
 
 int
-pt_msi_write(struct pt_dev *d, uint32_t addr, uint32_t val, uint32_t len);
+pt_msi_update(struct pt_dev *d);
 
 int
-pt_msi_read(struct pt_dev *d, int addr, int len, uint32_t *val);
+pt_msix_update(struct pt_dev *dev);
 
 int
 remove_msix_mapping(struct pt_dev *dev, int bar_index);
@@ -93,10 +94,4 @@ int
 int
 pt_msix_init(struct pt_dev *dev, int pos);
 
-int
-pt_msix_write(struct pt_dev *d, uint32_t addr, uint32_t val, uint32_t len);
-
-int
-pt_msix_read(struct pt_dev *d, int addr, int len, uint32_t *val);
-
 #endif
diff -r 1db0b09b290e -r 9cf72db44ee9 tools/ioemu/vl.h
--- a/tools/ioemu/vl.h  Fri Jul 04 11:51:59 2008 +0100
+++ b/tools/ioemu/vl.h  Fri Jul 04 11:54:21 2008 +0100
@@ -832,6 +832,8 @@ void pci_register_io_region(PCIDevice *p
                             uint32_t size, int type, 
                             PCIMapIORegionFunc *map_func);
 
+int pt_chk_bar_overlap(PCIBus *bus, int devfn, uint32_t addr, uint32_t size);
+
 void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level);
 
 uint32_t pci_default_read_config(PCIDevice *d, 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] ioemu: Support more Capability Structures (including MSI/MSI-X), Xen patchbot-unstable <=