From: Patrick G. Bridges Date: Wed, 25 Apr 2012 14:57:29 +0000 (-0600) Subject: Fixed merge conflict in vmm_halt.c X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=commitdiff_plain;h=f7e4262b2d65bbe3eb0c21ab3a6c4bb185531af7;hp=b114cb5ecaeb5e330511684a1c8d56e23fb2f136;p=palacios.git Fixed merge conflict in vmm_halt.c --- diff --git a/linux_module/iface-file.c b/linux_module/iface-file.c index be31f16..091c773 100644 --- a/linux_module/iface-file.c +++ b/linux_module/iface-file.c @@ -243,7 +243,7 @@ static int palacios_file_close(void * file_ptr) { return 0; } -static long long palacios_file_size(void * file_ptr) { +static unsigned long long palacios_file_size(void * file_ptr) { struct palacios_file * pfile = (struct palacios_file *)file_ptr; struct file * filp = pfile->filp; struct kstat s; @@ -259,7 +259,7 @@ static long long palacios_file_size(void * file_ptr) { return s.size; } -static long long palacios_file_read(void * file_ptr, void * buffer, long long length, long long offset){ +static unsigned long long palacios_file_read(void * file_ptr, void * buffer, unsigned long long length, unsigned long long offset){ struct palacios_file * pfile = (struct palacios_file *)file_ptr; struct file * filp = pfile->filp; ssize_t ret; @@ -273,14 +273,14 @@ static long long palacios_file_read(void * file_ptr, void * buffer, long long le set_fs(old_fs); if (ret <= 0) { - printk("sys_read of %p for %lld bytes failed\n", filp, length); + printk("sys_read of %p for %lld bytes at offset %llu failed (ret=%ld)\n", filp, length, offset, ret); } return ret; } -static long long palacios_file_write(void * file_ptr, void * buffer, long long length, long long offset) { +static unsigned long long palacios_file_write(void * file_ptr, void * buffer, unsigned long long length, unsigned long long offset) { struct palacios_file * pfile = (struct palacios_file *)file_ptr; struct file * filp = pfile->filp; mm_segment_t old_fs; @@ -295,7 +295,7 @@ static long long palacios_file_write(void * file_ptr, void * buffer, long long l if (ret <= 0) { - printk("sys_write failed\n"); + printk("sys_write for %llu bytes at offset %llu failed (ret=%ld)\n", length, offset, ret); } return ret; diff --git a/linux_module/palacios-stubs.c b/linux_module/palacios-stubs.c index c5b0ca0..12b4e45 100644 --- a/linux_module/palacios-stubs.c +++ b/linux_module/palacios-stubs.c @@ -158,6 +158,7 @@ palacios_xcall( struct lnx_thread_arg { int (*fn)(void * arg); void * arg; + char * name; }; static int lnx_thread_target(void * arg) { @@ -176,6 +177,9 @@ static int lnx_thread_target(void * arg) { kfree(thread_info); // handle cleanup + + printk("Palacios Thread (%s) EXITTING\n", thread_info->name); + do_exit(ret); return 0; // should not get here. @@ -194,6 +198,7 @@ palacios_start_kernel_thread( thread_info->fn = fn; thread_info->arg = arg; + thread_info->name = thread_name; return kthread_run( lnx_thread_target, thread_info, thread_name ); } @@ -212,6 +217,7 @@ palacios_start_thread_on_cpu(int cpu_id, thread_info->fn = fn; thread_info->arg = arg; + thread_info->name = thread_name; thread = kthread_create( lnx_thread_target, thread_info, thread_name ); diff --git a/linux_module/vm.c b/linux_module/vm.c index da9b460..e2b621a 100644 --- a/linux_module/vm.c +++ b/linux_module/vm.c @@ -16,6 +16,7 @@ #include #include #include +#include #include diff --git a/linux_usr/v3_cons_sc.c b/linux_usr/v3_cons_sc.c index 3b9e192..6404905 100644 --- a/linux_usr/v3_cons_sc.c +++ b/linux_usr/v3_cons_sc.c @@ -600,6 +600,16 @@ int main(int argc, char* argv[]) { writeit(cons_fd,sc); sc |= 0x80; writeit(cons_fd,sc); + } else if (key == '~') { // CTRL-C + unsigned char sc; + sc = 0x1d; // left ctrl down + writeit(cons_fd,sc); + sc = 0x2e; // c down + writeit(cons_fd,sc); + sc = 0x2e | 0x80; // c up + writeit(cons_fd,sc); + sc = 0x1d | 0x80; // left ctrl up + writeit(cons_fd,sc); }else { if (send_char_to_palacios_as_scancodes(cons_fd,key)) { fprintf(stderr, "Error sendign key to console\n"); diff --git a/palacios/include/devices/apic.h b/palacios/include/devices/apic.h index 4ddfc7c..0be5283 100644 --- a/palacios/include/devices/apic.h +++ b/palacios/include/devices/apic.h @@ -24,13 +24,14 @@ #include - typedef enum {IPI_FIXED = 0, IPI_LOWEST_PRIO = 1, IPI_SMI = 2, + IPI_RES1 = 3, IPI_NMI = 4, IPI_INIT = 5, - IPI_EXINT = 7 } ipi_mode_t; + IPI_SIPI = 6, + IPI_EXTINT = 7 } ipi_mode_t; struct v3_gen_ipi { @@ -42,13 +43,14 @@ struct v3_gen_ipi { uint8_t dst_shorthand : 2; uint8_t dst; + + + int (*ack)(struct guest_info * core, uint32_t irq, void * private_data); + void * private_data; } __attribute__((packed)); int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev_data); -int v3_apic_raise_intr(struct v3_vm_info * vm, - uint32_t irq, uint32_t dst, - void * dev_data); diff --git a/palacios/include/devices/pci.h b/palacios/include/devices/pci.h index ff2e27d..bbb61c5 100644 --- a/palacios/include/devices/pci.h +++ b/palacios/include/devices/pci.h @@ -27,13 +27,22 @@ #include #include +#include #include - struct vm_device; +typedef enum { PCI_CMD_DMA_DISABLE = 1, + PCI_CMD_DMA_ENABLE = 2, + PCI_CMD_INTX_DISABLE = 3, + PCI_CMD_INTX_ENABLE = 4, + PCI_CMD_MSI_DISABLE = 5, + PCI_CMD_MSI_ENABLE = 6, + PCI_CMD_MSIX_DISABLE = 7, + PCI_CMD_MSIX_ENABLE = 8 } pci_cmd_t; + typedef enum { PCI_BAR_IO, PCI_BAR_MEM24, PCI_BAR_MEM32, @@ -104,6 +113,13 @@ struct v3_pci_bar { #define PCI_MEM64_BASE_LO(bar_val) (bar_val & PCI_MEM64_MASK_LO) #define PCI_EXP_ROM_BASE(rom_val) (rom_val & PCI_EXP_ROM_MASK) +#define PCI_IO_BAR_VAL(addr) ((addr & PCI_IO_MASK) | 0x1) +#define PCI_MEM24_BAR_VAL(addr, prefetch) (((addr & PCI_MEM24_MASK) | 0x2) | ((prefetch) != 0) << 3) +#define PCI_MEM32_BAR_VAL(addr, prefetch) (((addr & PCI_MEM_MASK) | ((prefetch) != 0) << 3)) +#define PCI_MEM64_HI_BAR_VAL(addr, prefetch) (addr & PCI_MEM64_MASK_HI) +#define PCI_MEM64_LO_BAR_VAL(addr, prefetch) ((((addr) & PCI_MEM64_MASK_LO) | 0x4) | ((prefetch) != 0) << 3) +#define PCI_EXP_ROM_VAL(addr, enable) (((addr) & PCI_EXP_ROM_MASK) | ((enable) != 0)) + struct pci_device { @@ -134,30 +150,45 @@ struct pci_device { char name[64]; - int (*config_update)(uint_t reg_num, void * src, uint_t length, void * priv_data); - - int (*cmd_update)(struct pci_device * pci_dev, uchar_t io_enabled, uchar_t mem_enabled); + int (*config_write)(struct pci_device * pci_dev, uint32_t reg_num, void * src, + uint_t length, void * priv_data); + int (*config_read)(struct pci_device * pci_dev, uint32_t reg_num, void * dst, + uint_t length, void * priv_data); + int (*cmd_update)(struct pci_device * pci_dev, pci_cmd_t cmd, uint64_t arg, void * priv_data); int (*exp_rom_update)(struct pci_device * pci_dev, uint32_t * src, void * private_data); - int (*config_write)(uint_t reg_num, void * src, uint_t length, void * private_data); - int (*config_read)(uint_t reg_num, void * dst, uint_t length, void * private_data); + struct v3_vm_info * vm; + struct list_head cfg_hooks; + struct list_head capabilities; - int exp_rom_update_flag; - int bar_update_flag; + struct msi_msg_ctrl * msi_cap; + struct msix_cap * msix_cap; + struct vm_device * apic_dev; + + enum {IRQ_NONE, IRQ_INTX, IRQ_MSI, IRQ_MSIX} irq_type; void * priv_data; }; int v3_pci_set_irq_bridge(struct vm_device * pci_bus, int bus_num, - int (*raise_pci_irq)(struct pci_device * pci_dev, void * dev_data), - int (*lower_pci_irq)(struct pci_device * pci_dev, void * dev_data), + int (*raise_pci_irq)(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec), + int (*lower_pci_irq)(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec), void * dev_data); -int v3_pci_raise_irq(struct vm_device * pci_bus, int bus_num, struct pci_device * dev); -int v3_pci_lower_irq(struct vm_device * pci_bus, int bus_num, struct pci_device * dev); +/* Raising a PCI IRQ requires the specification of a vector index. + * If you are not sure, set vec_index to 0. + * For IntX IRQs, the index is the interrupt line the device is using (INTA=0, INTB=1, ...) - only used in multi-function devices + * For MSI and MSIX, the index is the vector index if multi-vectors are enabled + */ + +int v3_pci_raise_irq(struct vm_device * pci_bus, struct pci_device * dev, uint32_t vec_index); +int v3_pci_lower_irq(struct vm_device * pci_bus, struct pci_device * dev, uint32_t vec_index); + +int v3_pci_raise_acked_irq(struct vm_device * pci_bus, struct pci_device * dev, struct v3_irq vec); +int v3_pci_lower_acked_irq(struct vm_device * pci_bus, struct pci_device * dev, struct v3_irq vec); struct pci_device * v3_pci_register_device(struct vm_device * pci, @@ -167,21 +198,34 @@ v3_pci_register_device(struct vm_device * pci, int fn_num, const char * name, struct v3_pci_bar * bars, - int (*config_update)(uint_t reg_num, void * src, uint_t length, void * private_data), - int (*cmd_update)(struct pci_device *pci_dev, uchar_t io_enabled, uchar_t mem_enabled), + int (*config_write)(struct pci_device * pci_dev, uint32_t reg_num, void * src, + uint_t length, void * private_data), + int (*config_read)(struct pci_device * pci_dev, uint32_t reg_num, void * dst, + uint_t length, void * private_data), + int (*cmd_update)(struct pci_device *pci_dev, pci_cmd_t cmd, uint64_t arg, void * priv_data), int (*exp_rom_update)(struct pci_device * pci_dev, uint32_t * src, void * private_data), void * priv_data); -struct pci_device * -v3_pci_register_passthrough_device(struct vm_device * pci, - int bus_num, - int dev_num, - int fn_num, - const char * name, - int (*config_write)(uint_t reg_num, void * src, uint_t length, void * private_data), - int (*config_read)(uint_t reg_num, void * dst, uint_t length, void * private_data), - void * private_data); + +int v3_pci_hook_config_range(struct pci_device * pci, + uint32_t start, uint32_t length, + int (*write)(struct pci_device * pci_dev, uint32_t offset, + void * src, uint_t length, void * private_data), + int (*read)(struct pci_device * pci_dev, uint32_t offset, + void * src, uint_t length, void * private_data), + void * private_data); + + + + +typedef enum { PCI_CAP_INVALID = 0, + PCI_CAP_PM = 0x1, + PCI_CAP_MSI = 0x5, + PCI_CAP_MSIX = 0x11, + PCI_CAP_PCIE = 0x10 } pci_cap_type_t; + +int v3_pci_enable_capability(struct pci_device * pci, pci_cap_type_t cap_type); #endif diff --git a/palacios/include/devices/pci_types.h b/palacios/include/devices/pci_types.h index c3cd4cb..f6a98ce 100644 --- a/palacios/include/devices/pci_types.h +++ b/palacios/include/devices/pci_types.h @@ -63,6 +63,28 @@ struct pci_config_header { } __attribute__((packed)); +struct pci_cmd_reg { + union { + uint16_t val; + struct { + uint16_t io_enable : 1; + uint16_t mem_enable : 1; + uint16_t dma_enable : 1; + uint16_t special_cycles : 1; + uint16_t mem_wr_inv_enable : 1; + uint16_t vga_snoop : 1; + uint16_t parity_err_resp : 1; + uint16_t rsvd1 : 1; + uint16_t serr_enable : 1; + uint16_t fast_b2b_enable : 1; + uint16_t intx_disable : 1; + uint16_t rsvd2 : 5; + } __attribute__((packed)); + } __attribute__((packed)); + +} __attribute__((packed)); + + typedef enum { PCI_CLASS_PRE2 = 0x00, PCI_CLASS_STORAGE = 0x01, PCI_CLASS_NETWORK = 0x02, @@ -165,5 +187,357 @@ typedef enum { PCI_BRIDGE_SUBCLASS_HOST_PCI = 0x00, }; */ + + +struct msi_addr { + union { + uint32_t val; + struct { + uint32_t rsvd1 : 2; + uint32_t dst_mode : 1; + uint32_t redir_hint : 1; + uint32_t rsvd2 : 8; + uint32_t dst_id : 8; + uint32_t fixaddr : 12; + } __attribute__((packed)); + } __attribute__((packed)); +} __attribute__((packed)); + + +struct msi_data { + union { + uint16_t val; + struct { + uint16_t vector : 8; + uint16_t del_mode : 3; + uint16_t rsvd1 : 3; + uint16_t level : 1; + uint16_t trig_mode : 1; + } __attribute__((packed));; + } __attribute__((packed)); +} __attribute__((packed)); + + +struct msi_msg_ctrl { + union { + uint16_t val; + struct { + uint16_t msi_enable : 1; + uint16_t mult_msg_capable : 3; + uint16_t mult_msg_enable : 3; + uint16_t cap_64bit : 1; + uint16_t per_vect_mask : 1; + uint16_t rsvd : 7; + } __attribute__((packed)); + } __attribute__((packed)); +} __attribute__((packed)); + + +struct msi32_msg_addr { + struct msi_msg_ctrl msg_ctrl; + struct msi_addr addr; + struct msi_data data; +} __attribute__((packed)); + + +struct msi64_msg_addr { + struct msi_msg_ctrl msg_ctrl; + struct msi_addr addr; + uint32_t hi_addr; + struct msi_data data; +} __attribute__((packed)); + + +struct msi64_pervec_msg_addr { + struct msi_msg_ctrl msg_ctrl; + struct msi_addr addr; + uint32_t hi_addr; + struct msi_data data; + uint16_t rsvd; + uint32_t mask; + uint32_t pending; +} __attribute__((packed)); + + +struct msix_msg_ctrl { + uint16_t table_size : 11; + uint16_t rsvd : 4; + uint16_t msix_enable : 1; +} __attribute__((packed)); + +struct msix_cap { + struct msix_msg_ctrl msg_ctrl; + uint32_t hi_addr; + uint32_t bir : 3; + uint32_t table_offset : 29; +} __attribute__((packed)); + + +struct msix_table { + struct { + struct msi_data data; + struct msi_addr addr; + } __attribute__((packed)) entries[0]; +} __attribute__((packed)); + + + +// See PCI power management specification (1.2) +struct pmc_cap { + struct { + uint16_t version : 3; + uint16_t pme_clock : 1; + uint16_t rsvd1 : 1; + uint16_t dsi : 1; + uint16_t aux_current : 3; + uint16_t d1_support : 1; + uint16_t d2_support : 1; + uint16_t pme_support : 5; + } __attribute__((packed)) pmc; + + struct { + uint16_t power_state : 2; + uint16_t rsvd1 : 1; + uint16_t no_soft_reset : 1; + uint16_t rsvd2 : 4; + uint16_t pme_en : 1; + uint16_t data_select : 4; + uint16_t data_scale : 2; + uint16_t pme_status : 1; + } __attribute__((packed)) pmcsr; + + struct { + uint8_t rsvd1 : 6; + uint8_t b2_b3 : 1; + uint8_t bpcc_en : 1; + } __attribute__((packed)) pmcsr_bse; + + uint8_t data; +} __attribute__((packed)); + + +struct pcie_cap_reg { + uint16_t version : 4; + uint16_t type : 4; + uint16_t slot_impl : 1; + uint16_t irq_msg_num : 5; + uint16_t rsvd : 2; +} __attribute__((packed)); + +struct pcie_cap_v1 { + struct pcie_cap_reg pcie_cap; + + union { + uint32_t val; + struct { + uint32_t max_payload : 3; + uint32_t phantom_fns : 2; + uint32_t ext_tag_support : 1; + uint32_t endpt_L0_latency : 3; + uint32_t endpt_L1_latency : 3; + uint32_t maybe_rsvd1 : 3; + uint32_t role_err_reporting : 1; + uint32_t rsvd2 : 2; + uint32_t slot_pwr_lim_val : 8; + uint32_t slot_pwr_lim_scale : 2; + uint32_t rsvd3 : 4; + } __attribute__((packed)); + } __attribute__((packed)) dev_cap; + + union { + uint16_t val; + struct { + uint16_t correctable_err_enable : 1; + uint16_t non_fatal_err_enable : 1; + uint16_t fatal_err_enable : 1; + uint16_t unsupp_req_enable : 1; + uint16_t relaxed_order_enable : 1; + uint16_t max_payload_size : 3; + uint16_t ext_tag_field_enable : 1; + uint16_t phantom_fn_enable : 1; + uint16_t aux_pwr_enable : 1; + uint16_t no_snoop_enable : 1; + uint16_t max_read_req_size : 3; + uint16_t bridge_cfg_retry_enable : 1; + } __attribute__((packed)); + } __attribute__((packed)) dev_ctrl; + + union { + uint16_t val; + struct { + uint16_t correctable_err : 1; + uint16_t non_fatal_err : 1; + uint16_t fatal_err : 1; + uint16_t unsupp_req : 1; + uint16_t aux_pwr : 1; + uint16_t transaction_pending : 1; + uint16_t rsvd : 10; + } __attribute__((packed)); + } __attribute__((packed)) dev_status; + + union { + uint32_t val; + struct { + uint32_t max_link_speed : 4; + uint32_t max_link_width : 6; + uint32_t aspm_support : 2; /* Active State Power Management Support */ + uint32_t L0_exit_latency : 3; + uint32_t L1_exit_latency : 3; + uint32_t clk_pwr_mngmt : 1; + uint32_t surprise_pwr_down_capable : 1; + uint32_t data_link_active_capable : 1; + uint32_t rsvd1 : 3; + uint32_t port_number : 8; + } __attribute__((packed)); + } __attribute__((packed)) link_cap; + + + union { + uint16_t val; + struct { + uint16_t aspm_ctrl : 2; + uint16_t rsvd1 : 1; + uint16_t rd_cmpl_bndry : 1; + uint16_t link_disable : 1; + uint16_t retrain_link : 1; + uint16_t common_clk_cfg : 1; + uint16_t ext_synch : 1; + uint16_t clk_pwr_mngmt_enable : 1; + uint16_t rsvd2 : 7; + } __attribute__((packed)); + } __attribute__((packed)) link_ctrl; + + + union { + uint16_t val; + struct { + uint16_t link_speed : 4; + uint16_t negotiate_link_width : 6; + uint16_t undef : 1; + uint16_t link_training : 1; + uint16_t slot_clk_cfg : 1; + uint16_t data_link_layer_active : 1; + uint16_t rsvd : 2; + } __attribute__((packed)); + } __attribute__((packed)) link_status; + +} __attribute__((packed)); + + + + +struct pcie_cap_v2 { + struct pcie_cap_reg pcie_cap; + + union { + uint32_t val; + struct { + uint32_t max_payload : 3; + uint32_t phantom_fns : 2; + uint32_t ext_tag_support : 1; + uint32_t endpt_L0_latency : 3; + uint32_t endpt_L1_latency : 3; + uint32_t maybe_rsvd1 : 3; + uint32_t role_err_reporting : 1; + uint32_t rsvd2 : 2; + uint32_t slot_pwr_lim_val : 8; + uint32_t slot_pwr_lim_scale : 2; + uint32_t fn_level_reset : 1; + uint32_t rsvd3 : 3; + } __attribute__((packed)); + } __attribute__((packed)) dev_cap; + + union { + uint16_t val; + struct { + uint16_t correctable_err_enable : 1; + uint16_t non_fatal_err_enable : 1; + uint16_t fatal_err_enable : 1; + uint16_t unsupp_req_enable : 1; + uint16_t relaxed_order_enable : 1; + uint16_t max_payload_size : 3; + uint16_t ext_tag_field_enable : 1; + uint16_t phantom_fn_enable : 1; + uint16_t aux_pwr_enable : 1; + uint16_t no_snoop_enable : 1; + uint16_t max_read_req_size : 3; + uint16_t bridge_cfg_retry_enable : 1; + } __attribute__((packed)); + } __attribute__((packed)) dev_ctrl; + + union { + uint16_t val; + struct { + uint16_t correctable_err : 1; + uint16_t non_fatal_err : 1; + uint16_t fatal_err : 1; + uint16_t unsupp_req : 1; + uint16_t aux_pwr : 1; + uint16_t transaction_pending : 1; + uint16_t rsvd : 10; + } __attribute__((packed)); + } __attribute__((packed)) dev_status; + + union { + uint32_t val; + struct { + uint32_t max_link_speed : 4; + uint32_t max_link_width : 6; + uint32_t aspm_support : 2; /* Active State Power Management Support */ + uint32_t L0_exit_latency : 3; + uint32_t L1_exit_latency : 3; + uint32_t clk_pwr_mngmt : 1; + uint32_t surprise_pwr_down_capable : 1; + uint32_t data_link_active_capable : 1; + uint32_t rsvd1 : 3; + uint32_t port_number : 8; + } __attribute__((packed)); + } __attribute__((packed)) link_cap; + + + union { + uint16_t val; + struct { + uint16_t aspm_ctrl : 2; + uint16_t rsvd1 : 1; + uint16_t rd_cmpl_bndry : 1; + uint16_t link_disable : 1; + uint16_t retrain_link : 1; + uint16_t common_clk_cfg : 1; + uint16_t ext_synch : 1; + uint16_t clk_pwr_mngmt_enable : 1; + uint16_t rsvd2 : 7; + } __attribute__((packed)); + } __attribute__((packed)) link_ctrl; + + + union { + uint16_t val; + struct { + uint16_t link_speed : 4; + uint16_t negotiate_link_width : 6; + uint16_t undef : 1; + uint16_t link_training : 1; + uint16_t slot_clk_cfg : 1; + uint16_t data_link_layer_active : 1; + uint16_t rsvd : 2; + } __attribute__((packed)); + } __attribute__((packed)) link_status; + + + /* Some crap whose format we don't know because the PCI-SIG sucks */ + + uint32_t slot_cap; + uint16_t slot_ctrl; + uint16_t slot_status; + + uint16_t root_ctrl; + uint16_t root_cap; + uint32_t root_status; + +} __attribute__((packed)); + + + #endif diff --git a/palacios/include/interfaces/vmm_file.h b/palacios/include/interfaces/vmm_file.h index 69b78d8..421c73e 100644 --- a/palacios/include/interfaces/vmm_file.h +++ b/palacios/include/interfaces/vmm_file.h @@ -49,11 +49,11 @@ struct v3_file_hooks { void * (*open)(const char * path, int mode, void * host_data); int (*close)(void * fd); - long long (*size)(void * fd); + unsigned long long (*size)(void * fd); // blocking reads and writes - long long (*read)(void * fd, void * buffer, long long length, long long offset); - long long (*write)(void * fd, void * buffer, long long length, long long offset); + unsigned long long (*read)(void * fd, void * buffer, unsigned long long length, unsigned long long offset); + unsigned long long (*write)(void * fd, void * buffer, unsigned long long length, unsigned long long offset); }; diff --git a/palacios/include/palacios/vmm_intr.h b/palacios/include/palacios/vmm_intr.h index adf2aa4..de98185 100644 --- a/palacios/include/palacios/vmm_intr.h +++ b/palacios/include/palacios/vmm_intr.h @@ -35,6 +35,14 @@ struct v3_vm_info; struct v3_interrupt; +struct v3_irq { + uint32_t irq; + + int (*ack)(struct guest_info * core, uint32_t irq, void * private_data); + void * private_data; +}; + + struct v3_irq_hook { int (*handler)(struct v3_vm_info * vm, struct v3_interrupt * intr, void * priv_data); @@ -82,6 +90,12 @@ int v3_lower_virq(struct guest_info * info, int irq); int v3_raise_irq(struct v3_vm_info * vm, int irq); int v3_lower_irq(struct v3_vm_info * vm, int irq); +/* The irq structure is passed by value to avoid confusion and + * the possibility that people will dynamically allocate memory for it + */ +int v3_raise_acked_irq(struct v3_vm_info * vm, struct v3_irq irq); +int v3_lower_acked_irq(struct v3_vm_info * vm, struct v3_irq irq); + int v3_raise_swintr(struct guest_info * core, uint8_t vector); @@ -93,8 +107,8 @@ struct intr_ctrl_ops { }; struct intr_router_ops { - int (*raise_intr)(struct v3_vm_info * vm, void * private_data, int irq); - int (*lower_intr)(struct v3_vm_info * vm, void * private_data, int irq); + int (*raise_intr)(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq); + int (*lower_intr)(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq); }; void v3_clear_pending_intr(struct guest_info * core); diff --git a/palacios/src/devices/8259a.c b/palacios/src/devices/8259a.c index b383151..7e4b7a4 100644 --- a/palacios/src/devices/8259a.c +++ b/palacios/src/devices/8259a.c @@ -159,6 +159,11 @@ struct pic_internal { struct guest_info * core; + struct { + int (*ack)(struct guest_info * core, uint32_t irq, void * private_data); + void * private_data; + } irq_ack_cbs[15]; + void * router_handle; void * controller_handle; @@ -197,46 +202,53 @@ static void DumpPICState(struct pic_internal *p) } -static int pic_raise_intr(struct v3_vm_info * vm, void * private_data, int irq) { +static int pic_raise_intr(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq) { struct pic_internal * state = (struct pic_internal*)private_data; + uint8_t irq_num = irq->irq; - if (irq == 2) { - irq = 9; - state->master_irr |= 0x04; // PAD + if (irq_num == 2) { + irq_num = 9; + state->master_irr |= 0x04; } - PrintDebug("8259 PIC: Raising irq %d in the PIC\n", irq); + PrintDebug("8259 PIC: Raising irq %d in the PIC\n", irq_num); - if (irq <= 7) { - state->master_irr |= 0x01 << irq; - } else if ((irq > 7) && (irq < 16)) { - state->slave_irr |= 0x01 << (irq - 8); // PAD if -7 then irq 15=no irq + if (irq_num <= 7) { + state->master_irr |= 0x01 << irq_num; + } else if ((irq_num > 7) && (irq_num < 16)) { + state->slave_irr |= 0x01 << (irq_num - 8); } else { - PrintDebug("8259 PIC: Invalid IRQ raised (%d)\n", irq); + PrintDebug("8259 PIC: Invalid IRQ raised (%d)\n", irq_num); return -1; } -#ifdef V3_CONFIG_MULTITHREAD_OS - v3_interrupt_cpu(vm, 0, 0); -#endif + state->irq_ack_cbs[irq_num].ack = irq->ack; + state->irq_ack_cbs[irq_num].private_data = irq->private_data; + + if (V3_Get_CPU() != vm->cores[0].pcpu_id) { + // guest is running on another core, interrupt it to deliver irq + v3_interrupt_cpu(vm, 0, 0); + } return 0; } -static int pic_lower_intr(struct v3_vm_info * vm, void * private_data, int irq) { +static int pic_lower_intr(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq) { struct pic_internal * state = (struct pic_internal*)private_data; + uint8_t irq_num = irq->irq; - PrintDebug("[pic_lower_intr] IRQ line %d now low\n", irq); - if (irq <= 7) { - state->master_irr &= ~(1 << irq); + PrintDebug("[pic_lower_intr] IRQ line %d now low\n", irq_num); + if (irq_num <= 7) { + + state->master_irr &= ~(1 << irq_num); if ((state->master_irr & ~(state->master_imr)) == 0) { PrintDebug("\t\tFIXME: Master maybe should do sth\n"); } - } else if ((irq > 7) && (irq < 16)) { + } else if ((irq_num > 7) && (irq_num < 16)) { - state->slave_irr &= ~(1 << (irq - 8)); + state->slave_irr &= ~(1 << (irq_num - 8)); if ((state->slave_irr & (~(state->slave_imr))) == 0) { PrintDebug("\t\tFIXME: Slave maybe should do sth\n"); } @@ -325,7 +337,7 @@ static int pic_begin_irq(struct guest_info * info, void * private_data, int irq) state->master_irr &= ~(0x1 << irq); } } else { - PrintDebug("8259 PIC: (master) Ignoring begin_irq for %d since I don't own it\n",irq); + PrintDebug("8259 PIC: (master) Ignoring begin_irq for %d since I don't own it\n", irq); } } else { @@ -337,11 +349,12 @@ static int pic_begin_irq(struct guest_info * info, void * private_data, int irq) state->slave_irr &= ~(0x1 << (irq - 8)); } } else { - PrintDebug("8259 PIC: (slave) Ignoring begin_irq for %d since I don't own it\n",irq); + PrintDebug("8259 PIC: (slave) Ignoring begin_irq for %d since I don't own it\n", irq); } - } + + return 0; } @@ -462,6 +475,15 @@ static int write_master_port1(struct guest_info * core, ushort_t port, void * sr if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) { // specific EOI; state->master_isr &= ~(0x01 << cw2->level); + + + /* + // ack the irq if requested + if (state->irq_ack_cbs[irq].ack) { + state->irq_ack_cbs[irq].ack(info, irq, state->irq_ack_cbs[irq].private_data); + } + */ + } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) { int i; // Non-specific EOI diff --git a/palacios/src/devices/apic.c b/palacios/src/devices/apic.c index 80f3d30..44ca08d 100644 --- a/palacios/src/devices/apic.c +++ b/palacios/src/devices/apic.c @@ -72,14 +72,6 @@ static char * deliverymode_str[] = { typedef enum { APIC_TMR_INT, APIC_THERM_INT, APIC_PERF_INT, APIC_LINT0_INT, APIC_LINT1_INT, APIC_ERR_INT } apic_irq_type_t; -#define APIC_FIXED_DELIVERY 0x0 -#define APIC_LOWEST_DELIVERY 0x1 -#define APIC_SMI_DELIVERY 0x2 -#define APIC_RES1_DELIVERY 0x3 -#define APIC_NMI_DELIVERY 0x4 -#define APIC_INIT_DELIVERY 0x5 -#define APIC_SIPI_DELIVERY 0x6 -#define APIC_EXTINT_DELIVERY 0x7 #define APIC_SHORTHAND_NONE 0x0 #define APIC_SHORTHAND_SELF 0x1 @@ -180,6 +172,18 @@ struct apic_msr { + +struct irq_queue_entry { + uint32_t vector; + int (*ack)(struct guest_info * core, uint32_t irq, void * private_data); + void * private_data; + + struct list_head list_node; +}; + + + + typedef enum {INIT_ST, SIPI, STARTED} ipi_state_t; @@ -234,6 +238,11 @@ struct apic_state { uint8_t int_en_reg[32]; uint8_t trig_mode_reg[32]; + struct { + int (*ack)(struct guest_info * core, uint32_t irq, void * private_data); + void * private_data; + } irq_ack_cbs[256]; + struct guest_info * core; void * controller_handle; @@ -241,7 +250,12 @@ struct apic_state { struct v3_timer * timer; - struct v3_queue irq_queue; + struct { + v3_lock_t lock; + + uint64_t num_entries; + struct list_head entries; + } irq_queue ; uint32_t eoi; @@ -328,8 +342,9 @@ static void init_apic_state(struct apic_state * apic, uint32_t id) { apic->spec_eoi.val = 0x00000000; - v3_init_queue(&(apic->irq_queue)); - + INIT_LIST_HEAD(&(apic->irq_queue.entries)); + v3_lock_init(&(apic->irq_queue.lock)); + apic->irq_queue.num_entries = 0; } @@ -388,7 +403,9 @@ static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, vo // irq_num is the bit offset into a 256 bit buffer... -static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) { +static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num, + int (*ack)(struct guest_info * core, uint32_t irq, void * private_data), + void * private_data) { int major_offset = (irq_num & ~0x00000007) >> 3; int minor_offset = irq_num & 0x00000007; uint8_t * req_location = apic->int_req_reg + major_offset; @@ -405,6 +422,9 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) { if (*en_location & flag) { *req_location |= flag; + apic->irq_ack_cbs[irq_num].ack = ack; + apic->irq_ack_cbs[irq_num].private_data = private_data; + return 1; } else { PrintDebug("apic %u: core %d: Interrupt not enabled... %.2x\n", @@ -415,7 +435,12 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) { } -static int add_apic_irq_entry(struct apic_state * apic, uint8_t irq_num) { + +static int add_apic_irq_entry(struct apic_state * apic, uint32_t irq_num, + int (*ack)(struct guest_info * core, uint32_t irq, void * private_data), + void * private_data) { + unsigned int flags = 0; + struct irq_queue_entry * entry = NULL; if (irq_num <= 15) { PrintError("core %d: Attempting to raise an invalid interrupt: %d\n", @@ -423,16 +448,53 @@ static int add_apic_irq_entry(struct apic_state * apic, uint8_t irq_num) { return -1; } - v3_enqueue(&(apic->irq_queue), (addr_t)irq_num); + entry = V3_Malloc(sizeof(struct irq_queue_entry)); + + if (entry == NULL) { + PrintError("Could not allocate irq queue entry\n"); + return -1; + } + + entry->vector = irq_num; + entry->ack = ack; + entry->private_data = private_data; + + flags = v3_lock_irqsave(apic->irq_queue.lock); + + list_add_tail(&(entry->list_node), &(apic->irq_queue.entries)); + apic->irq_queue.num_entries++; + + v3_unlock_irqrestore(apic->irq_queue.lock, flags); + return 0; } static void drain_irq_entries(struct apic_state * apic) { - uint32_t irq = 0; - while ((irq = (uint32_t)v3_dequeue(&(apic->irq_queue))) != 0) { - activate_apic_irq(apic, irq); + while (1) { + unsigned int flags = 0; + struct irq_queue_entry * entry = NULL; + + flags = v3_lock_irqsave(apic->irq_queue.lock); + + if (!list_empty(&(apic->irq_queue.entries))) { + struct list_head * q_entry = apic->irq_queue.entries.next; + entry = list_entry(q_entry, struct irq_queue_entry, list_node); + + apic->irq_queue.num_entries--; + list_del(q_entry); + } + + v3_unlock_irqrestore(apic->irq_queue.lock, flags); + + if (entry == NULL) { + break; + } + + activate_apic_irq(apic, entry->vector, entry->ack, entry->private_data); + + V3_Free(entry); } } @@ -485,7 +547,7 @@ static int get_highest_irr(struct apic_state * apic) { -static int apic_do_eoi(struct apic_state * apic) { +static int apic_do_eoi(struct guest_info * core, struct apic_state * apic) { int isr_irq = get_highest_isr(apic); if (isr_irq != -1) { @@ -498,6 +560,10 @@ static int apic_do_eoi(struct apic_state * apic) { *svc_location &= ~flag; + if (apic->irq_ack_cbs[isr_irq].ack) { + apic->irq_ack_cbs[isr_irq].ack(core, isr_irq, apic->irq_ack_cbs[isr_irq].private_data); + } + #ifdef V3_CONFIG_CRAY_XT if ((isr_irq == 238) || @@ -526,7 +592,7 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t switch (int_type) { case APIC_TMR_INT: vec_num = apic->tmr_vec_tbl.vec; - del_mode = APIC_FIXED_DELIVERY; + del_mode = IPI_FIXED; masked = apic->tmr_vec_tbl.mask; break; case APIC_THERM_INT: @@ -551,7 +617,7 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t break; case APIC_ERR_INT: vec_num = apic->err_vec_tbl.vec; - del_mode = APIC_FIXED_DELIVERY; + del_mode = IPI_FIXED; masked = apic->err_vec_tbl.mask; break; default: @@ -565,9 +631,9 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t return 0; } - if (del_mode == APIC_FIXED_DELIVERY) { + if (del_mode == IPI_FIXED) { //PrintDebug("Activating internal APIC IRQ %d\n", vec_num); - return add_apic_irq_entry(apic, vec_num); + return add_apic_irq_entry(apic, vec_num, NULL, NULL); } else { PrintError("apic %u: core ?: Unhandled Delivery Mode\n", apic->lapic_id.val); return -1; @@ -681,34 +747,31 @@ static int should_deliver_ipi(struct apic_dev_state * apic_dev, // Only the src_apic pointer is used static int deliver_ipi(struct apic_state * src_apic, struct apic_state * dst_apic, - uint32_t vector, uint8_t del_mode) { + struct v3_gen_ipi * ipi) { struct guest_info * dst_core = dst_apic->core; - switch (del_mode) { + switch (ipi->mode) { - case APIC_FIXED_DELIVERY: - case APIC_LOWEST_DELIVERY: { + case IPI_FIXED: + case IPI_LOWEST_PRIO: { // lowest priority - // caller needs to have decided which apic to deliver to! - PrintDebug("delivering IRQ %d to core %u\n", vector, dst_core->vcpu_id); + PrintDebug("delivering IRQ %d to core %u\n", ipi->vector, dst_core->vcpu_id); - add_apic_irq_entry(dst_apic, vector); + add_apic_irq_entry(dst_apic, ipi->vector, ipi->ack, ipi->private_data); -#ifdef V3_CONFIG_MULTITHREAD_OS if (dst_apic != src_apic) { PrintDebug(" non-local core with new interrupt, forcing it to exit now\n"); v3_interrupt_cpu(dst_core->vm_info, dst_core->pcpu_id, 0); } -#endif - break; } - case APIC_INIT_DELIVERY: { + case IPI_INIT: { PrintDebug(" INIT delivery to core %u\n", dst_core->vcpu_id); @@ -735,7 +798,7 @@ static int deliver_ipi(struct apic_state * src_apic, break; } - case APIC_SIPI_DELIVERY: { + case IPI_SIPI: { // Sanity check if (dst_apic->ipi_state != SIPI) { @@ -744,10 +807,10 @@ static int deliver_ipi(struct apic_state * src_apic, break; } - v3_reset_vm_core(dst_core, vector); + v3_reset_vm_core(dst_core, ipi->vector); PrintDebug(" SIPI delivery (0x%x -> 0x%x:0x0) to core %u\n", - vector, dst_core->segments.cs.selector, dst_core->vcpu_id); + ipi->vector, dst_core->segments.cs.selector, dst_core->vcpu_id); // Maybe need to adjust the APIC? // We transition the target core to SIPI state @@ -761,7 +824,7 @@ static int deliver_ipi(struct apic_state * src_apic, break; } - case APIC_EXTINT_DELIVERY: // EXTINT + case IPI_EXTINT: // EXTINT /* Two possible things to do here: * 1. Ignore the IPI and assume the 8259a (PIC) will handle it * 2. Add 32 to the vector and inject it... @@ -769,11 +832,11 @@ static int deliver_ipi(struct apic_state * src_apic, */ return 0; - case APIC_SMI_DELIVERY: - case APIC_RES1_DELIVERY: // reserved - case APIC_NMI_DELIVERY: + case IPI_SMI: + case IPI_RES1: // reserved + case IPI_NMI: default: - PrintError("IPI %d delivery is unsupported\n", del_mode); + PrintError("IPI %d delivery is unsupported\n", ipi->mode); return -1; } @@ -810,34 +873,32 @@ static struct apic_state * find_physical_apic(struct apic_dev_state * apic_dev, static int route_ipi(struct apic_dev_state * apic_dev, struct apic_state * src_apic, - struct int_cmd_reg * icr) { + struct v3_gen_ipi * ipi) { struct apic_state * dest_apic = NULL; - PrintDebug("apic: IPI %s %u from apic %p to %s %s %u (icr=0x%llx)\n", - deliverymode_str[icr->del_mode], - icr->vec, + PrintDebug("apic: IPI %s %u from apic %p to %s %s %u\n", + deliverymode_str[ipi->mode], + ipi->vector, src_apic, - (icr->dst_mode == 0) ? "(physical)" : "(logical)", - shorthand_str[icr->dst_shorthand], - icr->dst, - icr->val); + (ipi->logical == 0) ? "(physical)" : "(logical)", + shorthand_str[ipi->dst_shorthand], + ipi->dst); - switch (icr->dst_shorthand) { + switch (ipi->dst_shorthand) { case APIC_SHORTHAND_NONE: // no shorthand - if (icr->dst_mode == APIC_DEST_PHYSICAL) { + if (ipi->logical == APIC_DEST_PHYSICAL) { - dest_apic = find_physical_apic(apic_dev, icr->dst); + dest_apic = find_physical_apic(apic_dev, ipi->dst); if (dest_apic == NULL) { - PrintError("apic: Attempted send to unregistered apic id=%u\n", icr->dst); + PrintError("apic: Attempted send to unregistered apic id=%u\n", ipi->dst); return -1; } - if (deliver_ipi(src_apic, dest_apic, - icr->vec, icr->del_mode) == -1) { + if (deliver_ipi(src_apic, dest_apic, ipi) == -1) { PrintError("apic: Could not deliver IPI\n"); return -1; } @@ -845,11 +906,11 @@ static int route_ipi(struct apic_dev_state * apic_dev, PrintDebug("apic: done\n"); - } else if (icr->dst_mode == APIC_DEST_LOGICAL) { + } else if (ipi->logical == APIC_DEST_LOGICAL) { - if (icr->del_mode != APIC_LOWEST_DELIVERY) { + if (ipi->mode != IPI_LOWEST_PRIO) { int i; - uint8_t mda = icr->dst; + uint8_t mda = ipi->dst; // logical, but not lowest priority // we immediately trigger @@ -869,8 +930,7 @@ static int route_ipi(struct apic_dev_state * apic_dev, return -1; } else if (del_flag == 1) { - if (deliver_ipi(src_apic, dest_apic, - icr->vec, icr->del_mode) == -1) { + if (deliver_ipi(src_apic, dest_apic, ipi) == -1) { PrintError("apic: Error: Could not deliver IPI\n"); return -1; } @@ -878,7 +938,7 @@ static int route_ipi(struct apic_dev_state * apic_dev, } } else { // APIC_LOWEST_DELIVERY struct apic_state * cur_best_apic = NULL; - uint8_t mda = icr->dst; + uint8_t mda = ipi->dst; int i; // logical, lowest priority @@ -908,15 +968,14 @@ static int route_ipi(struct apic_dev_state * apic_dev, v3_unlock_irqrestore(apic_dev->state_lock, flags); - } + } } // now we will deliver to the best one if it exists if (!cur_best_apic) { PrintDebug("apic: lowest priority deliver, but no destinations!\n"); } else { - if (deliver_ipi(src_apic, cur_best_apic, - icr->vec, icr->del_mode) == -1) { + if (deliver_ipi(src_apic, cur_best_apic, ipi) == -1) { PrintError("apic: Error: Could not deliver IPI\n"); return -1; } @@ -936,15 +995,15 @@ static int route_ipi(struct apic_dev_state * apic_dev, - if (icr->dst_mode == APIC_DEST_PHYSICAL) { /* physical delivery */ - if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) { + if (ipi->logical == APIC_DEST_PHYSICAL) { /* physical delivery */ + if (deliver_ipi(src_apic, src_apic, ipi) == -1) { PrintError("apic: Could not deliver IPI to self (physical)\n"); return -1; } - } else if (icr->dst_mode == APIC_DEST_LOGICAL) { /* logical delivery */ + } else if (ipi->logical == APIC_DEST_LOGICAL) { /* logical delivery */ PrintError("apic: use of logical delivery in self (untested)\n"); - if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) { + if (deliver_ipi(src_apic, src_apic, ipi) == -1) { PrintError("apic: Could not deliver IPI to self (logical)\n"); return -1; } @@ -961,8 +1020,8 @@ static int route_ipi(struct apic_dev_state * apic_dev, for (i = 0; i < apic_dev->num_apics; i++) { dest_apic = &(apic_dev->apics[i]); - if ((dest_apic != src_apic) || (icr->dst_shorthand == APIC_SHORTHAND_ALL)) { - if (deliver_ipi(src_apic, dest_apic, icr->vec, icr->del_mode) == -1) { + if ((dest_apic != src_apic) || (ipi->dst_shorthand == APIC_SHORTHAND_ALL)) { + if (deliver_ipi(src_apic, dest_apic, ipi) == -1) { PrintError("apic: Error: Could not deliver IPI\n"); return -1; } @@ -972,7 +1031,7 @@ static int route_ipi(struct apic_dev_state * apic_dev, break; } default: - PrintError("apic: Error routing IPI, invalid Mode (%d)\n", icr->dst_shorthand); + PrintError("apic: Error routing IPI, invalid Mode (%d)\n", ipi->dst_shorthand); return -1; } @@ -1410,23 +1469,32 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u // Action Registers case EOI_OFFSET: // do eoi - apic_do_eoi(apic); + apic_do_eoi(core, apic); break; case INT_CMD_LO_OFFSET: { // execute command - struct int_cmd_reg tmp_icr; + struct v3_gen_ipi tmp_ipi; apic->int_cmd.lo = op_val; - tmp_icr = apic->int_cmd; + tmp_ipi.vector = apic->int_cmd.vec; + tmp_ipi.mode = apic->int_cmd.del_mode; + tmp_ipi.logical = apic->int_cmd.dst_mode; + tmp_ipi.trigger_mode = apic->int_cmd.trig_mode; + tmp_ipi.dst_shorthand = apic->int_cmd.dst_shorthand; + tmp_ipi.dst = apic->int_cmd.dst; + + tmp_ipi.ack = NULL; + tmp_ipi.private_data = NULL; + // V3_Print("apic %u: core %u: sending cmd 0x%llx to apic %u\n", // apic->lapic_id.val, core->vcpu_id, // apic->int_cmd.val, apic->int_cmd.dst); - if (route_ipi(apic_dev, apic, &tmp_icr) == -1) { + if (route_ipi(apic_dev, apic, &tmp_ipi) == -1) { PrintError("IPI Routing failure\n"); return -1; } @@ -1504,41 +1572,11 @@ static int apic_get_intr_number(struct guest_info * core, void * private_data) { int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev_data) { struct apic_dev_state * apic_dev = (struct apic_dev_state *) (((struct vm_device *)dev_data)->private_data); - struct int_cmd_reg tmp_icr; - - // zero out all the fields - tmp_icr.val = 0; - tmp_icr.vec = ipi->vector; - tmp_icr.del_mode = ipi->mode; - tmp_icr.dst_mode = ipi->logical; - tmp_icr.trig_mode = ipi->trigger_mode; - tmp_icr.dst_shorthand = ipi->dst_shorthand; - tmp_icr.dst = ipi->dst; - - - return route_ipi(apic_dev, NULL, &tmp_icr); + return route_ipi(apic_dev, NULL, ipi); } -int v3_apic_raise_intr(struct v3_vm_info * vm, uint32_t irq, uint32_t dst, void * dev_data) { - struct apic_dev_state * apic_dev = (struct apic_dev_state *) - (((struct vm_device*)dev_data)->private_data); - struct apic_state * apic = &(apic_dev->apics[dst]); - - PrintDebug("apic %u core ?: raising interrupt IRQ %u (dst = %u).\n", apic->lapic_id.val, irq, dst); - - add_apic_irq_entry(apic, irq); - -#ifdef V3_CONFIG_MULTITHREAD_OS - if ((V3_Get_CPU() != dst)) { - v3_interrupt_cpu(vm, dst, 0); - } -#endif - - return 0; -} - static int apic_begin_irq(struct guest_info * core, void * private_data, int irq) { diff --git a/palacios/src/devices/cirrus_gfx_card.c b/palacios/src/devices/cirrus_gfx_card.c index e9d27be..ce25023 100644 --- a/palacios/src/devices/cirrus_gfx_card.c +++ b/palacios/src/devices/cirrus_gfx_card.c @@ -539,8 +539,8 @@ static int cirrus_gfx_card_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg){ // Not sure if STD pci_dev = v3_pci_register_device(video_state->pci_bus, PCI_STD_DEVICE, 0, //or0 1st null could be pci_config_update - -1, 0, "CIRRUS_GFX_CARD", bars, NULL, NULL, - NULL, dev); + -1, 0, "CIRRUS_GFX_CARD", bars, NULL, NULL, + NULL, NULL, dev); if (pci_dev == NULL) { PrintError("Failed to register VIDEO %d with PCI\n", i); diff --git a/palacios/src/devices/filedisk.c b/palacios/src/devices/filedisk.c index bf1aaf8..9625d3b 100644 --- a/palacios/src/devices/filedisk.c +++ b/palacios/src/devices/filedisk.c @@ -36,10 +36,10 @@ struct disk_state { -static int write_all(v3_file_t fd, char * buf, int offset, int length) { - int bytes_written = 0; +static int write_all(v3_file_t fd, char * buf, uint64_t offset, uint64_t length) { + uint64_t bytes_written = 0; - PrintDebug("Writing %d bytes\n", length - bytes_written); + PrintDebug("Writing %llu bytes\n", length - bytes_written); while (bytes_written < length) { int tmp_bytes = v3_file_write(fd, buf + bytes_written, length - bytes_written, offset + bytes_written); PrintDebug("Wrote %d bytes\n", tmp_bytes); @@ -56,10 +56,10 @@ static int write_all(v3_file_t fd, char * buf, int offset, int length) { } -static int read_all(v3_file_t fd, char * buf, int offset, int length) { - int bytes_read = 0; +static int read_all(v3_file_t fd, char * buf, uint64_t offset, uint64_t length) { + uint64_t bytes_read = 0; - PrintDebug("Reading %d bytes\n", length - bytes_read); + PrintDebug("Reading %llu bytes\n", length - bytes_read); while (bytes_read < length) { int tmp_bytes = v3_file_read(fd, buf + bytes_read, length - bytes_read, offset + bytes_read); PrintDebug("Read %d bytes\n", tmp_bytes); @@ -78,7 +78,7 @@ static int read_all(v3_file_t fd, char * buf, int offset, int length) { static int read(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) { struct disk_state * disk = (struct disk_state *)private_data; - PrintDebug("Reading %d bytes from %p to %p\n", (uint32_t)num_bytes, (uint8_t *)(disk->disk_image + lba), buf); + PrintDebug("Reading %llu bytes from %p to %p\n", num_bytes, (uint8_t *)(disk->disk_image + lba), buf); if (lba + num_bytes > disk->capacity) { PrintError("Out of bounds read: lba=%llu, num_bytes=%llu, capacity=%llu\n", @@ -93,7 +93,7 @@ static int read(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_ static int write(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) { struct disk_state * disk = (struct disk_state *)private_data; - PrintDebug("Writing %d bytes from %p to %p\n", (uint32_t)num_bytes, buf, (uint8_t *)(disk->disk_image + lba)); + PrintDebug("Writing %llu bytes from %p to %p\n", num_bytes, buf, (uint8_t *)(disk->disk_image + lba)); if (lba + num_bytes > disk->capacity) { PrintError("Out of bounds read: lba=%llu, num_bytes=%llu, capacity=%llu\n", @@ -109,8 +109,7 @@ static int write(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private static uint64_t get_capacity(void * private_data) { struct disk_state * disk = (struct disk_state *)private_data; - PrintDebug("Querying FILEDISK capacity %d\n", - (uint32_t)(disk->capacity)); + PrintDebug("Querying FILEDISK capacity %llu\n", disk->capacity); return disk->capacity; } @@ -183,8 +182,8 @@ static int disk_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { disk->capacity = v3_file_size(disk->fd); - PrintDebug("Registering FILEDISK %s (path=%s, fd=%lu, size=%lu)\n", - dev_id, path, file->fd, file->capacity); + V3_Print("Registering FILEDISK %s (path=%s, fd=%lu, size=%llu)\n", + dev_id, path, (addr_t)disk->fd, disk->capacity); if (v3_dev_connect_blk(vm, v3_cfg_val(frontend_cfg, "tag"), diff --git a/palacios/src/devices/i440fx.c b/palacios/src/devices/i440fx.c index 6c587d3..01e8088 100644 --- a/palacios/src/devices/i440fx.c +++ b/palacios/src/devices/i440fx.c @@ -107,7 +107,7 @@ static int i440_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { pci_dev = v3_pci_register_device(state->pci, PCI_STD_DEVICE, 0, 0, 0, "i440FX", bars, - NULL, NULL, NULL, state); + NULL, NULL, NULL, NULL, state); if (!pci_dev) { v3_remove_device(dev); diff --git a/palacios/src/devices/ide.c b/palacios/src/devices/ide.c index 285e534..206a8ef 100644 --- a/palacios/src/devices/ide.c +++ b/palacios/src/devices/ide.c @@ -206,9 +206,17 @@ struct ide_channel { // Control Registers struct ide_ctrl_reg ctrl_reg; // [write] 0x3f6,0x376 - struct ide_dma_cmd_reg dma_cmd; - struct ide_dma_status_reg dma_status; - uint32_t dma_prd_addr; + union { + uint8_t dma_ports[8]; + struct { + struct ide_dma_cmd_reg dma_cmd; + uint8_t rsvd1; + struct ide_dma_status_reg dma_status; + uint8_t rsvd2; + uint32_t dma_prd_addr; + } __attribute__((packed)); + } __attribute__((packed)); + uint32_t dma_tbl_index; }; @@ -283,7 +291,9 @@ static inline int is_lba_enabled(struct ide_channel * channel) { /* Drive Commands */ static void ide_raise_irq(struct ide_internal * ide, struct ide_channel * channel) { if (channel->ctrl_reg.irq_disable == 0) { - // PrintError("Raising IDE Interrupt %d\n", channel->irq); + + //PrintError("Raising IDE Interrupt %d\n", channel->irq); + channel->dma_status.int_gen = 1; v3_raise_irq(ide->vm, channel->irq); } @@ -356,12 +366,12 @@ static int dma_write(struct guest_info * core, struct ide_internal * ide, struct #include "ata.h" -#ifdef V3_CONFIG_DEBUG_IDE + static void print_prd_table(struct ide_internal * ide, struct ide_channel * channel) { struct ide_dma_prd prd_entry; int index = 0; - PrintDebug("Dumping PRD table\n"); + V3_Print("Dumping PRD table\n"); while (1) { uint32_t prd_entry_addr = channel->dma_prd_addr + (sizeof(struct ide_dma_prd) * index); @@ -374,7 +384,7 @@ static void print_prd_table(struct ide_internal * ide, struct ide_channel * chan return; } - PrintDebug("\tPRD Addr: %x, PRD Len: %d, EOT: %d\n", + V3_Print("\tPRD Addr: %x, PRD Len: %d, EOT: %d\n", prd_entry.base_addr, (prd_entry.size == 0) ? 0x10000 : prd_entry.size, prd_entry.end_of_table); @@ -388,7 +398,7 @@ static void print_prd_table(struct ide_internal * ide, struct ide_channel * chan return; } -#endif + /* IO Operations */ static int dma_read(struct guest_info * core, struct ide_internal * ide, struct ide_channel * channel) { @@ -456,15 +466,18 @@ static int dma_read(struct guest_info * core, struct ide_internal * ide, struct } } else { /* - PrintError("DMA of command packet\n"); PrintError("How does this work (ATAPI CMD=%x)???\n", drive->cd_state.atapi_cmd); return -1; */ int cmd_ret = 0; + //V3_Print("DMA of command packet\n"); + bytes_to_write = (prd_bytes_left > bytes_left) ? bytes_left : prd_bytes_left; prd_bytes_left = bytes_to_write; + + // V3_Print("Writing ATAPI cmd OP DMA (cmd=%x) (len=%d)\n", drive->cd_state.atapi_cmd, prd_bytes_left); cmd_ret = v3_write_gpa_memory(core, prd_entry.base_addr + prd_offset, bytes_to_write, drive->data_buf); @@ -591,7 +604,13 @@ static int dma_write(struct guest_info * core, struct ide_internal * ide, struct PrintDebug("PRD Addr: %x, PRD Len: %d, EOT: %d\n", prd_entry.base_addr, prd_entry.size, prd_entry.end_of_table); - prd_bytes_left = prd_entry.size; + + if (prd_entry.size == 0) { + // a size of 0 means 64k + prd_bytes_left = 0x10000; + } else { + prd_bytes_left = prd_entry.size; + } while (prd_bytes_left > 0) { uint_t bytes_to_write = 0; @@ -632,6 +651,12 @@ static int dma_write(struct guest_info * core, struct ide_internal * ide, struct if ((prd_entry.end_of_table == 1) && (bytes_left > 0)) { PrintError("DMA table not large enough for data transfer...\n"); + PrintError("\t(bytes_left=%u) (transfer_length=%u)...\n", + bytes_left, drive->transfer_length); + PrintError("PRD Addr: %x, PRD Len: %d, EOT: %d\n", + prd_entry.base_addr, prd_entry.size, prd_entry.end_of_table); + + print_prd_table(ide, channel); return -1; } } @@ -745,7 +770,7 @@ static int write_dma_port(struct guest_info * core, ushort_t port, void * src, u } -static int read_dma_port(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * private_data) { +static int read_dma_port(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * private_data) { struct ide_internal * ide = (struct ide_internal *)private_data; uint16_t port_offset = port & (DMA_CHANNEL_FLAG - 1); uint_t channel_flag = (port & DMA_CHANNEL_FLAG) >> 3; @@ -753,44 +778,13 @@ static int read_dma_port(struct guest_info * core, ushort_t port, void * dst, ui PrintDebug("Reading DMA port %d (%x) (channel=%d)\n", port, port, channel_flag); - switch (port_offset) { - case DMA_CMD_PORT: - *(uint8_t *)dst = channel->dma_cmd.val; - break; - - case DMA_STATUS_PORT: - if (length != 1) { - PrintError("Invalid read length for DMA status port\n"); - return -1; - } - - *(uint8_t *)dst = channel->dma_status.val; - break; - - case DMA_PRD_PORT0: - case DMA_PRD_PORT1: - case DMA_PRD_PORT2: - case DMA_PRD_PORT3: { - uint_t addr_index = port_offset & 0x3; - uint8_t * addr_buf = (uint8_t *)&(channel->dma_prd_addr); - int i = 0; - - if (addr_index + length > 4) { - PrintError("DMA Port space overrun port=%x len=%d\n", port_offset, length); - return -1; - } - - for (i = 0; i < length; i++) { - *((uint8_t *)dst + i) = addr_buf[addr_index + i]; - } - - break; - } - default: - PrintError("IDE: Invalid DMA Port (%d) (%s)\n", port, dma_port_to_str(port_offset)); - break; + if (port_offset + length > 16) { + PrintError("DMA Port Read: Port overrun (port_offset=%d, length=%d)\n", port_offset, length); + return -1; } + memcpy(dst, channel->dma_ports + port_offset, length); + PrintDebug("\tval=%x (len=%d)\n", *(uint32_t *)dst, length); return length; @@ -1453,7 +1447,6 @@ static void init_channel(struct ide_channel * channel) { channel->cmd_reg = 0x00; channel->ctrl_reg.val = 0x08; - channel->dma_cmd.val = 0; channel->dma_status.val = 0; channel->dma_prd_addr = 0; @@ -1466,7 +1459,7 @@ static void init_channel(struct ide_channel * channel) { } -static int pci_config_update(uint_t reg_num, void * src, uint_t length, void * private_data) { +static int pci_config_update(struct pci_device * pci_dev, uint32_t reg_num, void * src, uint_t length, void * private_data) { PrintDebug("PCI Config Update\n"); /* struct ide_internal * ide = (struct ide_internal *)(private_data); @@ -1855,7 +1848,7 @@ static int ide_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { pci_dev = v3_pci_register_device(ide->pci_bus, PCI_STD_DEVICE, 0, sb_pci->dev_num, 1, "PIIX3_IDE", bars, - pci_config_update, NULL, NULL, ide); + pci_config_update, NULL, NULL, NULL, ide); if (pci_dev == NULL) { PrintError("Failed to register IDE BUS %d with PCI\n", i); diff --git a/palacios/src/devices/io_apic.c b/palacios/src/devices/io_apic.c index 0d7c3dc..9d477de 100644 --- a/palacios/src/devices/io_apic.c +++ b/palacios/src/devices/io_apic.c @@ -263,11 +263,12 @@ static int ioapic_write(struct guest_info * core, addr_t guest_addr, void * src, } -static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq) { +static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq) { struct io_apic_state * ioapic = (struct io_apic_state *)(private_data); struct redir_tbl_entry * irq_entry = NULL; + uint8_t irq_num = irq->irq; - if (irq==0) { + if (irq_num == 0) { // IRQ 0 being raised, in the Palacios context, means the PIT // However, the convention is that it is the PIC that is connected // to PIN 0 of the IOAPIC and the PIT is connected to pin 2 @@ -275,15 +276,15 @@ static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq // the PIC may signal to the IOAPIC in a different path. // Yes, this is kind of hideous, but it is needed to have the // PIT correctly show up via the IOAPIC - irq=2; + irq_num = 2; } - if (irq > 24) { + if (irq_num > 24) { PrintDebug("ioapic %u: IRQ out of range of IO APIC\n", ioapic->ioapic_id.id); return -1; } - irq_entry = &(ioapic->redir_tbl[irq]); + irq_entry = &(ioapic->redir_tbl[irq_num]); if (irq_entry->mask == 0) { struct v3_gen_ipi ipi; @@ -299,6 +300,8 @@ static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq ipi.dst = irq_entry->dst_field; ipi.dst_shorthand = 0; + ipi.ack = irq->ack; + ipi.private_data = irq->private_data; PrintDebug("ioapic %u: IPI: vector 0x%x, mode 0x%x, logical 0x%x, trigger 0x%x, dst 0x%x, shorthand 0x%x\n", ioapic->ioapic_id.id, ipi.vector, ipi.mode, ipi.logical, ipi.trigger_mode, ipi.dst, ipi.dst_shorthand); @@ -313,7 +316,7 @@ static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq } /* I don't know if we can do anything here.... */ -static int ioapic_lower_irq(struct v3_vm_info * vm, void * private_data, int irq) { +static int ioapic_lower_irq(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq) { return 0; } diff --git a/palacios/src/devices/keyboard.c b/palacios/src/devices/keyboard.c index 794e8b3..ea57b32 100644 --- a/palacios/src/devices/keyboard.c +++ b/palacios/src/devices/keyboard.c @@ -188,6 +188,9 @@ struct keyboard_internal { // after having a f0 sent to 60 // we wait for a new output byte on 60 GETSET_SCANCODES, + // first send ACK (0xfa) + // then wait for reception, and reset kb state + SET_DEFAULTS, } state; @@ -223,6 +226,9 @@ struct keyboard_internal { }; +static int keyboard_reset_device(struct keyboard_internal * kbd); + + static int update_kb_irq(struct keyboard_internal * state) { int irq_num = 0; @@ -898,6 +904,11 @@ static int keyboard_write_output(struct guest_info * core, ushort_t port, void * kbd->state = NORMAL; break; + case SET_DEFAULTS: + keyboard_reset_device(kbd); + kbd->state = NORMAL; + break; + default: case NORMAL: { // command is being sent to keyboard controller @@ -942,6 +953,15 @@ static int keyboard_write_output(struct guest_info * core, ushort_t port, void * kbd->state = GETSET_SCANCODES; break; + + case 0xf6: // set defaults + // ACK command + // clear output buffer + // reset to init state + push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD); + kbd->state = SET_DEFAULTS; + break; + case 0xfe: // resend case 0xfd: // set key type make case 0xfc: // set key typ make/break @@ -950,7 +970,7 @@ static int keyboard_write_output(struct guest_info * core, ushort_t port, void * case 0xf9: // set all make case 0xf8: // set all make/break case 0xf7: // set all typemaktic - case 0xf6: // set defaults + PrintError("keyboard: unhandled known command 0x%x on output buffer (60h)\n", data); ret = -1; break; diff --git a/palacios/src/devices/lnx_virtio_balloon.c b/palacios/src/devices/lnx_virtio_balloon.c index e936f9e..af3a903 100644 --- a/palacios/src/devices/lnx_virtio_balloon.c +++ b/palacios/src/devices/lnx_virtio_balloon.c @@ -172,7 +172,7 @@ static int handle_kick(struct guest_info * core, struct virtio_balloon_state * v if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) { PrintDebug("Raising IRQ %d\n", virtio->pci_dev->config_header.intr_line); - v3_pci_raise_irq(virtio->pci_bus, 0, virtio->pci_dev); + v3_pci_raise_irq(virtio->pci_bus, virtio->pci_dev, 0); virtio->virtio_cfg.pci_isr = VIRTIO_ISR_ACTIVE; } @@ -336,7 +336,7 @@ static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, u case VIRTIO_ISR_PORT: *(uint8_t *)dst = virtio->virtio_cfg.pci_isr; virtio->virtio_cfg.pci_isr = 0; - v3_pci_lower_irq(virtio->pci_bus, 0, virtio->pci_dev); + v3_pci_lower_irq(virtio->pci_bus, virtio->pci_dev, 0); break; default: @@ -379,7 +379,7 @@ static int set_size(struct virtio_balloon_state * virtio, addr_t size) { PrintDebug("Requesting %d pages\n", virtio->balloon_cfg.requested_pages); - v3_pci_raise_irq(virtio->pci_bus, 0, virtio->pci_dev); + v3_pci_raise_irq(virtio->pci_bus, virtio->pci_dev, 0); virtio->virtio_cfg.pci_isr = VIRTIO_ISR_ACTIVE | VIRTIO_ISR_CFG_CHANGED; return 0; @@ -476,7 +476,7 @@ static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 0, PCI_AUTO_DEV_NUM, 0, "LNX_VIRTIO_BALLOON", bars, - NULL, NULL, NULL, virtio_state); + NULL, NULL, NULL, NULL, virtio_state); if (!pci_dev) { PrintError("Could not register PCI Device\n"); diff --git a/palacios/src/devices/lnx_virtio_blk.c b/palacios/src/devices/lnx_virtio_blk.c index fd9ec61..6cdfa06 100644 --- a/palacios/src/devices/lnx_virtio_blk.c +++ b/palacios/src/devices/lnx_virtio_blk.c @@ -285,7 +285,7 @@ static int handle_kick(struct guest_info * core, struct virtio_blk_state * blk_s if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) { PrintDebug("Raising IRQ %d\n", blk_state->pci_dev->config_header.intr_line); - v3_pci_raise_irq(blk_state->virtio_dev->pci_bus, 0, blk_state->pci_dev); + v3_pci_raise_irq(blk_state->virtio_dev->pci_bus, blk_state->pci_dev, 0); blk_state->virtio_cfg.pci_isr = 1; } @@ -454,7 +454,7 @@ static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, u case VIRTIO_ISR_PORT: *(uint8_t *)dst = blk_state->virtio_cfg.pci_isr; blk_state->virtio_cfg.pci_isr = 0; - v3_pci_lower_irq(blk_state->virtio_dev->pci_bus, 0, blk_state->pci_dev); + v3_pci_lower_irq(blk_state->virtio_dev->pci_bus, blk_state->pci_dev, 0); break; default: @@ -548,7 +548,7 @@ static int register_dev(struct virtio_dev_state * virtio, struct virtio_blk_stat pci_dev = v3_pci_register_device(virtio->pci_bus, PCI_STD_DEVICE, 0, PCI_AUTO_DEV_NUM, 0, "LNX_VIRTIO_BLK", bars, - NULL, NULL, NULL, blk_state); + NULL, NULL, NULL, NULL, blk_state); if (!pci_dev) { PrintError("Could not register PCI Device\n"); diff --git a/palacios/src/devices/lnx_virtio_console.c b/palacios/src/devices/lnx_virtio_console.c index f7f2a11..0afefb8 100644 --- a/palacios/src/devices/lnx_virtio_console.c +++ b/palacios/src/devices/lnx_virtio_console.c @@ -147,7 +147,7 @@ static int handle_kick(struct guest_info * core, struct virtio_console_state * v if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) { PrintDebug("Raising IRQ %d\n", virtio->pci_dev->config_header.intr_line); - v3_pci_raise_irq(virtio->pci_bus, 0, virtio->pci_dev); + v3_pci_raise_irq(virtio->pci_bus, virtio->pci_dev, 0); virtio->virtio_cfg.pci_isr = VIRTIO_ISR_ACTIVE; } @@ -194,7 +194,7 @@ static uint64_t virtio_input(struct v3_vm_info * vm, uint8_t * buf, uint64_t len // say hello if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) { - v3_pci_raise_irq(cons_state->pci_bus, 0, cons_state->pci_dev); + v3_pci_raise_irq(cons_state->pci_bus, cons_state->pci_dev, 0); cons_state->virtio_cfg.pci_isr = 0x1; } @@ -359,7 +359,7 @@ static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, u case VIRTIO_ISR_PORT: *(uint8_t *)dst = virtio->virtio_cfg.pci_isr; virtio->virtio_cfg.pci_isr = 0; - v3_pci_lower_irq(virtio->pci_bus, 0, virtio->pci_dev); + v3_pci_lower_irq(virtio->pci_bus, virtio->pci_dev, 0); break; default: @@ -489,7 +489,7 @@ static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 0, PCI_AUTO_DEV_NUM, 0, "LNX_VIRTIO_CONSOLE", bars, - NULL, NULL, NULL, virtio_state); + NULL, NULL, NULL, NULL, virtio_state); if (!pci_dev) { PrintError("Could not register PCI Device\n"); diff --git a/palacios/src/devices/lnx_virtio_nic.c b/palacios/src/devices/lnx_virtio_nic.c index 400cb0c..7f217ae 100644 --- a/palacios/src/devices/lnx_virtio_nic.c +++ b/palacios/src/devices/lnx_virtio_nic.c @@ -266,81 +266,78 @@ static int handle_pkt_tx(struct guest_info * core, struct virtio_net_state * virtio_state, int quote) { - struct virtio_queue *q = &(virtio_state->tx_vq); + struct virtio_queue * q; int txed = 0, left = 0; unsigned long flags; + q = &(virtio_state->tx_vq); if (!q->ring_avail_addr) { return -1; } - flags = v3_lock_irqsave(virtio_state->tx_lock); - while (q->cur_avail_idx != q->avail->index) { - struct virtio_net_hdr_mrg_rxbuf * hdr = NULL; + while (1) { struct vring_desc * hdr_desc = NULL; addr_t hdr_addr = 0; - uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % q->queue_size]; - int desc_cnt = get_desc_count(q, desc_idx); + uint16_t desc_idx, tmp_idx; + int desc_cnt; + + flags = v3_lock_irqsave(virtio_state->tx_lock); + + if(q->cur_avail_idx == q->avail->index || + (quote > 0 && txed >= quote)) { + left = (q->cur_avail_idx != q->avail->index); + break; + } + + desc_idx = q->avail->ring[q->cur_avail_idx % q->queue_size]; + tmp_idx = q->cur_avail_idx ++; + + v3_unlock_irqrestore(virtio_state->tx_lock, flags); + desc_cnt = get_desc_count(q, desc_idx); if(desc_cnt != 2){ PrintError("VNIC: merged rx buffer not supported, desc_cnt %d\n", desc_cnt); - goto exit_error; } hdr_desc = &(q->desc[desc_idx]); - if (v3_gpa_to_hva(core, hdr_desc->addr_gpa, &(hdr_addr)) == -1) { - PrintError("Could not translate block header address\n"); - goto exit_error; - } + if (v3_gpa_to_hva(core, hdr_desc->addr_gpa, &(hdr_addr)) != -1) { + struct virtio_net_hdr_mrg_rxbuf * hdr; + struct vring_desc * buf_desc; - hdr = (struct virtio_net_hdr_mrg_rxbuf *)hdr_addr; - desc_idx = hdr_desc->next; + hdr = (struct virtio_net_hdr_mrg_rxbuf *)hdr_addr; + desc_idx = hdr_desc->next; - V3_Net_Print(2, "Virtio NIC: TX hdr count : %d\n", hdr->num_buffers); - - /* here we assumed that one ethernet pkt is not splitted into multiple buffer */ - struct vring_desc * buf_desc = &(q->desc[desc_idx]); - if (tx_one_pkt(core, virtio_state, buf_desc) == -1) { - PrintError("Virtio NIC: Fails to send packet\n"); - } - if(buf_desc->next & VIRTIO_NEXT_FLAG){ - PrintError("Virtio NIC: TX more buffer need to read\n"); + /* here we assumed that one ethernet pkt is not splitted into multiple buffer */ + buf_desc = &(q->desc[desc_idx]); + if (tx_one_pkt(core, virtio_state, buf_desc) == -1) { + PrintError("Virtio NIC: Fails to send packet\n"); + } + } else { + PrintError("Could not translate block header address\n"); } + + flags = v3_lock_irqsave(virtio_state->tx_lock); q->used->ring[q->used->index % q->queue_size].id = - q->avail->ring[q->cur_avail_idx % q->queue_size]; + q->avail->ring[tmp_idx % q->queue_size]; - q->used->ring[q->used->index % q->queue_size].length = - buf_desc->length; /* What do we set this to???? */ + //q->used->ring[q->used->index % q->queue_size].length = buf_desc->length; /* What do we set this to???? */ q->used->index ++; - q->cur_avail_idx ++; - if(++txed >= quote && quote > 0){ - left = (q->cur_avail_idx != q->avail->index); - break; - } + v3_unlock_irqrestore(virtio_state->tx_lock, flags); + + txed ++; } - - v3_unlock_irqrestore(virtio_state->tx_lock, flags); - + if (txed && !(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) { v3_pci_raise_irq(virtio_state->virtio_dev->pci_bus, - 0, virtio_state->pci_dev); + virtio_state->pci_dev, 0); virtio_state->virtio_cfg.pci_isr = 0x1; virtio_state->stats.rx_interrupts ++; } - if(txed > 0) { - V3_Net_Print(2, "Virtio Handle TX: txed pkts: %d, left %d\n", txed, left); - } - return left; - - exit_error: - - v3_unlock_irqrestore(virtio_state->tx_lock, flags); - return -1; } @@ -557,7 +554,7 @@ static int virtio_io_read(struct guest_info *core, *(uint8_t *)dst = virtio->virtio_cfg.pci_isr; virtio->virtio_cfg.pci_isr = 0; v3_pci_lower_irq(virtio->virtio_dev->pci_bus, - 0, virtio->pci_dev); + virtio->pci_dev, 0); break; case VIRTIO_NET_CONFIG ... VIRTIO_NET_CONFIG + ETH_ALEN: @@ -712,7 +709,7 @@ static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) { virtio->pci_dev->config_header.intr_line); virtio->virtio_cfg.pci_isr = 0x1; - v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev); + v3_pci_raise_irq(virtio->virtio_dev->pci_bus, virtio->pci_dev, 0); virtio->stats.rx_interrupts ++; } @@ -807,7 +804,7 @@ static int register_dev(struct virtio_dev_state * virtio, pci_dev = v3_pci_register_device(virtio->pci_bus, PCI_STD_DEVICE, 0, PCI_AUTO_DEV_NUM, 0, "LNX_VIRTIO_NIC", bars, - NULL, NULL, NULL, net_state); + NULL, NULL, NULL, NULL, net_state); if (!pci_dev) { PrintError("Virtio NIC: Could not register PCI Device\n"); @@ -842,6 +839,7 @@ static int register_dev(struct virtio_dev_state * virtio, return 0; } +#if 0 #define RATE_UPPER_THRESHOLD 10 /* 10000 pkts per second, around 100Mbits */ #define RATE_LOWER_THRESHOLD 1 #define PROFILE_PERIOD 10000 /*us*/ @@ -909,7 +907,7 @@ static void virtio_nic_timer(struct guest_info * core, static struct v3_timer_ops timer_ops = { .update_timer = virtio_nic_timer, }; - +#endif static int connect_fn(struct v3_vm_info * info, void * frontend_data, @@ -930,8 +928,7 @@ static int connect_fn(struct v3_vm_info * info, net_state->tx_notify = 1; net_state->rx_notify = 1; - net_state->timer = v3_add_timer(&(info->cores[0]), - &timer_ops,net_state); + //net_state->timer = v3_add_timer(&(info->cores[0]), &timer_ops,net_state); ops->recv = virtio_rx; ops->poll = virtio_poll; diff --git a/palacios/src/devices/lnx_virtio_sym.c b/palacios/src/devices/lnx_virtio_sym.c index f5b6501..010415f 100644 --- a/palacios/src/devices/lnx_virtio_sym.c +++ b/palacios/src/devices/lnx_virtio_sym.c @@ -147,7 +147,7 @@ static int handle_kick(struct guest_info * core, struct virtio_sym_state * sym_s if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) { PrintDebug("Raising IRQ %d\n", sym_state->pci_dev->config_header.intr_line); - v3_pci_raise_irq(sym_state->pci_bus, 0, sym_state->pci_dev); + v3_pci_raise_irq(sym_state->pci_bus, sym_state->pci_dev, 0); sym_state->virtio_cfg.pci_isr = VIRTIO_ISR_ACTIVE; } @@ -314,7 +314,7 @@ static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, u case VIRTIO_ISR_PORT: *(uint8_t *)dst = sym_state->virtio_cfg.pci_isr; sym_state->virtio_cfg.pci_isr = 0; - v3_pci_lower_irq(sym_state->pci_bus, 0, sym_state->pci_dev); + v3_pci_lower_irq(sym_state->pci_bus, sym_state->pci_dev, 0); break; default: @@ -420,7 +420,7 @@ static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 0, PCI_AUTO_DEV_NUM, 0, "LNX_VIRTIO_SYM", bars, - NULL, NULL, NULL, virtio_state); + NULL, NULL, NULL, NULL, virtio_state); if (!pci_dev) { PrintError("Could not register PCI Device\n"); diff --git a/palacios/src/devices/lnx_virtio_symmod.c b/palacios/src/devices/lnx_virtio_symmod.c index 993dcb6..d8172df 100644 --- a/palacios/src/devices/lnx_virtio_symmod.c +++ b/palacios/src/devices/lnx_virtio_symmod.c @@ -238,7 +238,7 @@ static int handle_xfer_kick(struct guest_info * core, struct virtio_sym_state * if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) { PrintDebug("Raising IRQ %d\n", sym_state->pci_dev->config_header.intr_line); - v3_pci_raise_irq(sym_state->pci_bus, 0, sym_state->pci_dev); + v3_pci_raise_irq(sym_state->pci_bus, sym_state->pci_dev, 0); sym_state->virtio_cfg.pci_isr = 1; } @@ -307,7 +307,7 @@ static int handle_notification_kick(struct guest_info * core, struct virtio_sym_ if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) { PrintDebug("Raising IRQ %d\n", sym_state->pci_dev->config_header.intr_line); - v3_pci_raise_irq(sym_state->pci_bus, 0, sym_state->pci_dev); + v3_pci_raise_irq(sym_state->pci_bus, sym_state->pci_dev, 0); sym_state->virtio_cfg.pci_isr = 1; } @@ -491,7 +491,7 @@ static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, u case VIRTIO_ISR_PORT: *(uint8_t *)dst = sym_state->virtio_cfg.pci_isr; sym_state->virtio_cfg.pci_isr = 0; - v3_pci_lower_irq(sym_state->pci_bus, 0, sym_state->pci_dev); + v3_pci_lower_irq(sym_state->pci_bus, sym_state->pci_dev, 0); break; default: @@ -579,7 +579,7 @@ static int virtio_load_capsule(struct v3_vm_info * vm, struct v3_sym_capsule * m if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) { PrintDebug("SYMMOD: Raising IRQ %d\n", virtio->pci_dev->config_header.intr_line); - v3_pci_raise_irq(virtio->pci_bus, 0, virtio->pci_dev); + v3_pci_raise_irq(virtio->pci_bus, virtio->pci_dev, 0); virtio->virtio_cfg.pci_isr = 0x1; } @@ -677,7 +677,7 @@ static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 0, PCI_AUTO_DEV_NUM, 0, "LNX_VIRTIO_SYMMOD", bars, - NULL, NULL, NULL, virtio_state); + NULL, NULL, NULL, NULL, virtio_state); if (!pci_dev) { PrintError("Could not register PCI Device\n"); diff --git a/palacios/src/devices/lnx_virtio_vnet.c b/palacios/src/devices/lnx_virtio_vnet.c index 7b6d75c..5bf8ae0 100644 --- a/palacios/src/devices/lnx_virtio_vnet.c +++ b/palacios/src/devices/lnx_virtio_vnet.c @@ -204,7 +204,7 @@ static int handle_cmd_kick(struct guest_info * core, if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) { PrintDebug("Raising IRQ %d\n", vnet_state->pci_dev->config_header.intr_line); - v3_pci_raise_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev); + v3_pci_raise_irq(vnet_state->pci_bus, vnet_state->pci_dev, 0); vnet_state->virtio_cfg.pci_isr = 1; } @@ -258,7 +258,7 @@ static int vnet_pkt_input_cb(struct v3_vm_info * vm, } if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) { - v3_pci_raise_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev); + v3_pci_raise_irq(vnet_state->pci_bus, vnet_state->pci_dev, 0); vnet_state->virtio_cfg.pci_isr = 0x1; PrintDebug("Raising IRQ %d\n", vnet_state->pci_dev->config_header.intr_line); } @@ -320,8 +320,8 @@ static int do_tx_pkts(struct guest_info * core, } if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) { - v3_pci_raise_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev); - vnet_state->virtio_cfg.pci_isr = 0x1; + v3_pci_raise_irq(vnet_state->pci_bus, vnet_state->pci_dev, 0); + vnet_state->virtio_cfg.pci_isr = 0x1; } return 0; @@ -525,7 +525,7 @@ static int vnet_virtio_io_read(struct guest_info * core, case VIRTIO_ISR_PORT: *(uint8_t *)dst = vnet_state->virtio_cfg.pci_isr; vnet_state->virtio_cfg.pci_isr = 0; - v3_pci_lower_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev); + v3_pci_lower_irq(vnet_state->pci_bus, vnet_state->pci_dev, 0); break; default: @@ -623,7 +623,7 @@ static int dev_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 0, 5 /*PCI_AUTO_DEV_NUM*/, 0, "LNX_VIRTIO_VNET", bars, - NULL, NULL, NULL, vnet_state); + NULL, NULL, NULL, NULL, vnet_state); if (!pci_dev) { PrintError("Could not register PCI Device\n"); diff --git a/palacios/src/devices/ne2k.c b/palacios/src/devices/ne2k.c index b4796f7..3c8fa06 100644 --- a/palacios/src/devices/ne2k.c +++ b/palacios/src/devices/ne2k.c @@ -334,7 +334,7 @@ static int ne2k_update_irq(struct ne2k_state * nic_state) { if (pci_dev == NULL){ v3_raise_virq(&(nic_state->vm->cores[0]), NE2K_DEFAULT_IRQ); } else { - v3_pci_raise_irq(nic_state->pci_bus, 0, nic_state->pci_dev); + v3_pci_raise_irq(nic_state->pci_bus, nic_state->pci_dev, 0); } nic_state->statistics.rx_interrupts ++; @@ -1124,7 +1124,7 @@ static int register_dev(struct ne2k_state * nic_state) pci_dev = v3_pci_register_device(nic_state->pci_bus, PCI_STD_DEVICE, 0, -1, 0, "NE2000", bars, - pci_config_update, NULL, NULL, nic_state); + pci_config_update, NULL, NULL, NULL, nic_state); if (pci_dev == NULL) { diff --git a/palacios/src/devices/pci.c b/palacios/src/devices/pci.c index 05272a8..f9a2f9b 100644 --- a/palacios/src/devices/pci.c +++ b/palacios/src/devices/pci.c @@ -34,8 +34,11 @@ #include #include +#include +#include + #ifndef V3_CONFIG_DEBUG_PCI #undef PrintDebug @@ -53,6 +56,10 @@ // This must always be a multiple of 8 #define MAX_BUS_DEVICES 32 +#define PCI_CAP_ID_MSI 0x05 +#define PCI_CAP_ID_MSIX 0x11 + + struct pci_addr_reg { union { uint32_t val; @@ -62,7 +69,8 @@ struct pci_addr_reg { uint_t fn_num : 3; uint_t dev_num : 5; uint_t bus_num : 8; - uint_t rsvd2 : 7; + uint_t hi_reg_num : 4; + uint_t rsvd2 : 3; uint_t enable : 1; } __attribute__((packed)); } __attribute__((packed)); @@ -82,8 +90,8 @@ struct pci_bus { uint8_t dev_map[MAX_BUS_DEVICES / 8]; - int (*raise_pci_irq)(struct pci_device * pci_dev, void * dev_data); - int (*lower_pci_irq)(struct pci_device * pci_dev, void * dev_data); + int (*raise_pci_irq)(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec); + int (*lower_pci_irq)(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec); void * irq_dev_data; }; @@ -102,6 +110,58 @@ struct pci_internal { +struct cfg_range_hook { + uint32_t start; + uint32_t length; + + int (*write)(struct pci_device * pci_dev, uint32_t offset, + void * src, uint_t length, void * private_data); + + int (*read)(struct pci_device * pci_dev, uint32_t offset, + void * dst, uint_t length, void * private_data); + + void * private_data; + + struct list_head list_node; +}; + + + +struct pci_cap { + uint8_t id; + uint32_t offset; + uint8_t enabled; + + struct list_head cap_node; +}; + + +// These mark read only fields in the pci config header. +// If a bit is 1, then the field is writable in the header +/* Notes: + * BIST is disabled by default (All writes to it will be dropped + * Cardbus CIS is disabled (All writes are dropped) + * Writes to capability pointer are disabled + */ +static uint8_t pci_hdr_write_mask_00[64] = { 0x00, 0x00, 0x00, 0x00, /* Device ID, Vendor ID */ + 0xbf, 0xff, 0x00, 0xf9, /* Command, status */ + 0x00, 0x00, 0x00, 0x00, /* Revision ID, Class code */ + 0x00, 0xff, 0x00, 0x00, /* CacheLine Size, Latency Timer, Header Type, BIST */ + 0xff, 0xff, 0xff, 0xff, /* BAR 0 */ + 0xff, 0xff, 0xff, 0xff, /* BAR 1 */ + 0xff, 0xff, 0xff, 0xff, /* BAR 2 */ + 0xff, 0xff, 0xff, 0xff, /* BAR 3 */ + 0xff, 0xff, 0xff, 0xff, /* BAR 4 */ + 0xff, 0xff, 0xff, 0xff, /* BAR 5 */ + 0x00, 0x00, 0x00, 0x00, /* CardBus CIS Ptr */ + 0xff, 0xff, 0xff, 0xff, /* SubSystem Vendor ID, SubSystem ID */ + 0xff, 0xff, 0xff, 0xff, /* ExpRom BAR */ + 0x00, 0x00, 0x00, 0x00, /* CAP ptr (0xfc to enable), RSVD */ + 0x00, 0x00, 0x00, 0x00, /* Reserved */ + 0xff, 0x00, 0x00, 0x00 /* INTR Line, INTR Pin, MIN_GNT, MAX_LAT */ +}; + + #ifdef V3_CONFIG_DEBUG_PCI @@ -225,181 +285,565 @@ static struct pci_device * get_device(struct pci_bus * bus, uint8_t dev_num, uin +// There won't be many hooks at all, so unordered lists are acceptible for now +static struct cfg_range_hook * find_cfg_range_hook(struct pci_device * pci, uint32_t start, uint32_t length) { + uint32_t end = start + length - 1; // end is inclusive + struct cfg_range_hook * hook = NULL; + list_for_each_entry(hook, &(pci->cfg_hooks), list_node) { + uint32_t hook_end = hook->start + hook->length - 1; + if (!((hook->start > end) || (hook_end < start))) { + return hook; + } + } + + return NULL; +} -static int addr_port_read(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) { - struct pci_internal * pci_state = priv_data; - int reg_offset = port & 0x3; - uint8_t * reg_addr = ((uint8_t *)&(pci_state->addr_reg.val)) + reg_offset; +int v3_pci_hook_config_range(struct pci_device * pci, + uint32_t start, uint32_t length, + int (*write)(struct pci_device * pci_dev, uint32_t offset, + void * src, uint_t length, void * private_data), + int (*read)(struct pci_device * pci_dev, uint32_t offset, + void * dst, uint_t length, void * private_data), + void * private_data) { + struct cfg_range_hook * hook = NULL; + - PrintDebug("Reading PCI Address Port (%x): %x len=%d\n", port, pci_state->addr_reg.val, length); + if (find_cfg_range_hook(pci, start, length)) { + PrintError("Tried to hook an already hooked config region\n"); + return -1; + } + + hook = V3_Malloc(sizeof(struct cfg_range_hook)); - if (length == 4) { - if (reg_offset != 0) { - PrintError("Invalid Address Port Read\n"); - return -1; + if (!hook) { + PrintError("Could not allocate range hook\n"); + return -1; + } + + memset(hook, 0, sizeof(struct cfg_range_hook)); + + hook->start = start; + hook->length = length; + hook->private_data = private_data; + hook->write = write; + hook->read = read; + + list_add(&(hook->list_node), &(pci->cfg_hooks)); + + return 0; + +} + + + + +// Note byte ordering: LSB -> MSB +static uint8_t msi_32_rw_bitmask[10] = { 0x00, 0x00, /* ID, next ptr */ + 0x71, 0x00, /* MSG CTRL */ + 0xfc, 0xff, 0xff, 0xff, /* MSG ADDR */ + 0xff, 0xff}; /* MSG DATA */ + +static uint8_t msi_64_rw_bitmask[14] = { 0x00, 0x00, /* ID, next ptr */ + 0x71, 0x00, /* MSG CTRL */ + 0xfc, 0xff, 0xff, 0xff, /* MSG LO ADDR */ + 0xff, 0xff, 0xff, 0xff, /* MSG HI ADDR */ + 0xff, 0xff}; /* MSG DATA */ + +static uint8_t msi_64pervect_rw_bitmask[24] = { 0x00, 0x00, /* ID, next ptr */ + 0x71, 0x00, /* MSG CTRL */ + 0xfc, 0xff, 0xff, 0xff, /* MSG LO CTRL */ + 0xff, 0xff, 0xff, 0xff, /* MSG HI ADDR */ + 0xff, 0xff, /* MSG DATA */ + 0x00, 0x00, /* RSVD */ + 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00}; + +static uint8_t msix_rw_bitmask[12] = { 0x00, 0x00, /* ID, next ptr */ + 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, + 0x08, 0xff, 0xff, 0xff}; + + +/* I am completely guessing what the format is here. + I only have version 1 of the PCIe spec and cannot download version 2 or 3 + without paying the PCI-SIG $3000 a year for membership. + So this is just cobbled together from the version 1 spec and KVM. +*/ + + +static uint8_t pciev1_rw_bitmask[20] = { 0x00, 0x00, /* ID, next ptr */ + 0x00, 0x00, /* PCIE CAP register */ + 0x00, 0x00, 0x00, 0x00, /* DEV CAP */ + 0xff, 0xff, /* DEV CTRL */ + 0x0f, 0x00, /* DEV STATUS */ + 0x00, 0x00, 0x00, 0x00, /* LINK CAP */ + 0xfb, 0x01, /* LINK CTRL */ + 0x00, 0x00 /* LINK STATUS */ +}; + + +static uint8_t pciev2_rw_bitmask[60] = { 0x00, 0x00, /* ID, next ptr */ + 0x00, 0x00, /* PCIE CAP register */ + 0x00, 0x00, 0x00, 0x00, /* DEV CAP */ + 0xff, 0xff, /* DEV CTRL */ + 0x0f, 0x00, /* DEV STATUS */ + 0x00, 0x00, 0x00, 0x00, /* LINK CAP */ + 0xfb, 0x01, /* LINK CTRL */ + 0x00, 0x00, /* LINK STATUS */ + 0x00, 0x00, 0x00, 0x00, /* SLOT CAP ?? */ + 0x00, 0x00, /* SLOT CTRL ?? */ + 0x00, 0x00, /* SLOT STATUS */ + 0x00, 0x00, /* ROOT CTRL */ + 0x00, 0x00, /* ROOT CAP */ + 0x00, 0x00, 0x00, 0x00, /* ROOT STATUS */ + 0x00, 0x00, 0x00, 0x00, /* WHO THE FUCK KNOWS */ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +static uint8_t pm_rw_bitmask[] = { 0x00, 0x00, /* ID, next ptr */ + 0x00, 0x00, /* PWR MGMT CAPS */ + 0x03, 0x9f, /* PWR MGMT CTRL */ + 0x00, 0x00 /* PMCSR_BSE, Data */ +}; + + + +int cap_write(struct pci_device * pci, uint32_t offset, void * src, uint_t length, void * private_data) { + struct pci_cap * cap = private_data; + uint32_t cap_offset = cap->offset; + pci_cap_type_t cap_type = cap->id; + + uint32_t write_offset = offset - cap_offset; + void * cap_ptr = &(pci->config_space[cap_offset + 2]); + int i = 0; + + int msi_was_enabled = 0; + int msix_was_enabled = 0; + + + V3_Print("CAP write trapped (val=%x, cfg_offset=%d, write_offset=%d)\n", *(uint32_t *)src, offset, write_offset); + + if (cap_type == PCI_CAP_MSI) { + struct msi_msg_ctrl * msg_ctrl = cap_ptr; + + if (msg_ctrl->msi_enable == 1) { + msi_was_enabled = 1; } - *(uint32_t *)dst = *(uint32_t *)reg_addr; - } else if (length == 2) { - if (reg_offset > 2) { - PrintError("Invalid Address Port Read\n"); + } else if (cap_type == PCI_CAP_MSIX) { + struct msix_cap * msix_cap = cap_ptr; + + if (msix_cap->msg_ctrl.msix_enable == 1) { + msix_was_enabled = 1; + } + } + + for (i = 0; i < length; i++) { + uint8_t mask = 0; + + if (cap_type == PCI_CAP_MSI) { + struct msi_msg_ctrl * msg_ctrl = cap_ptr; + + V3_Print("MSI Cap Ctrl=%x\n", *(uint16_t *)pci->msi_cap); + V3_Print("MSI ADDR=%x\n", *(uint32_t *)(cap_ptr + 2)); + V3_Print("MSI HI ADDR=%x\n", *(uint32_t *)(cap_ptr + 6)); + V3_Print("MSI Data=%x\n", *(uint16_t *)(cap_ptr + 10)); + + if (msg_ctrl->cap_64bit) { + if (msg_ctrl->per_vect_mask) { + mask = msi_64pervect_rw_bitmask[write_offset]; + } else { + mask = msi_64_rw_bitmask[write_offset]; + } + } else { + mask = msi_32_rw_bitmask[write_offset]; + } + } else if (cap_type == PCI_CAP_MSIX) { + mask = msix_rw_bitmask[write_offset]; + } else if (cap_type == PCI_CAP_PCIE) { + struct pcie_cap_reg * pcie_cap = cap_ptr; + + if (pcie_cap->version == 1) { + mask = pciev1_rw_bitmask[write_offset]; + } else if (pcie_cap->version == 2) { + mask = pciev2_rw_bitmask[write_offset]; + } else { + return 0; + } + } else if (cap_type == PCI_CAP_PM) { + mask = pm_rw_bitmask[write_offset]; + } + + pci->config_space[offset + i] &= ~mask; + pci->config_space[offset + i] |= ((*(uint8_t *)(src + i)) & mask); + + write_offset++; + } + + + if (pci->cmd_update) { + + /* Detect changes to interrupt types for cmd updates */ + if (cap_type == PCI_CAP_MSI) { + struct msi_msg_ctrl * msg_ctrl = cap_ptr; + + V3_Print("msi_was_enabled=%d, msi_is_enabled=%d\n", msi_was_enabled, msg_ctrl->msi_enable); + + if ((msg_ctrl->msi_enable == 1) && (msi_was_enabled == 0)) { + pci->irq_type = IRQ_MSI; + pci->cmd_update(pci, PCI_CMD_MSI_ENABLE, msg_ctrl->mult_msg_enable, pci->priv_data); + } else if ((msg_ctrl->msi_enable == 0) && (msi_was_enabled == 1)) { + pci->irq_type = IRQ_NONE; + pci->cmd_update(pci, PCI_CMD_MSI_DISABLE, 0, pci->priv_data); + } + } else if (cap_type == PCI_CAP_MSIX) { + struct msix_cap * msix_cap = cap_ptr; + + if ((msix_cap->msg_ctrl.msix_enable == 1) && (msix_was_enabled == 0)) { + pci->irq_type = IRQ_MSIX; + pci->cmd_update(pci, PCI_CMD_MSIX_ENABLE, msix_cap->msg_ctrl.table_size, pci->priv_data); + } else if ((msix_cap->msg_ctrl.msix_enable == 0) && (msix_was_enabled == 1)) { + pci->irq_type = IRQ_NONE; + pci->cmd_update(pci, PCI_CMD_MSIX_DISABLE, msix_cap->msg_ctrl.table_size, pci->priv_data); + } + } + } + + return 0; +} + + +static int init_pci_cap(struct pci_device * pci, pci_cap_type_t cap_type, uint_t cap_offset) { + void * cap_ptr = &(pci->config_space[cap_offset + 2]); + + if (cap_type == PCI_CAP_MSI) { + struct msi32_msg_addr * msi = cap_ptr; + + // We only expose a basic 32 bit MSI interface + msi->msg_ctrl.msi_enable = 0; + msi->msg_ctrl.mult_msg_enable = 0; + msi->msg_ctrl.cap_64bit = 0; + msi->msg_ctrl.per_vect_mask = 0; + + msi->addr.val = 0; + msi->data.val = 0; + + } else if (cap_type == PCI_CAP_MSIX) { + + + + } else if (cap_type == PCI_CAP_PCIE) { + struct pcie_cap_v2 * pcie = cap_ptr; + + // The v1 and v2 formats are identical for the first X bytes + // So we use the v2 struct, and only modify extended fields if v2 is detected + + pcie->dev_cap.fn_level_reset = 0; + + pcie->dev_ctrl.val &= 0x70e0; // only preserve max_payload_size and max_read_req_size untouched + pcie->dev_ctrl.relaxed_order_enable = 1; + pcie->dev_ctrl.no_snoop_enable = 1; + + pcie->dev_status.val = 0; + + pcie->link_cap.val &= 0x0003ffff; + + pcie->link_status.val &= 0x03ff; + + if (pcie->pcie_cap.version >= 2) { + pcie->slot_cap = 0; + pcie->slot_ctrl = 0; + pcie->slot_status = 0; + + pcie->root_ctrl = 0; + pcie->root_cap = 0; + pcie->root_status = 0; + } + } else if (cap_type == PCI_CAP_PM) { + + } + + + return 0; +} + + +// enumerate all capabilities and disable them. +static int scan_pci_caps(struct pci_device * pci) { + uint_t cap_offset = pci->config_header.cap_ptr; + + V3_Print("Scanning for Capabilities (cap_offset=%d)\n", cap_offset); + + while (cap_offset != 0) { + uint8_t id = pci->config_space[cap_offset]; + uint8_t next = pci->config_space[cap_offset + 1]; + + V3_Print("Found Capability 0x%x at offset %d (0x%x)\n", + id, cap_offset, cap_offset); + + struct pci_cap * cap = V3_Malloc(sizeof(struct pci_cap)); + + if (!cap) { + PrintError("Error allocating PCI CAP info\n"); return -1; } - *(uint16_t *)dst = *(uint16_t *)reg_addr; - } else if (length == 1) { - *(uint8_t *)dst = *(uint8_t *)reg_addr; - } else { - PrintError("Invalid read length (%d) for PCI address register\n", length); + memset(cap, 0, sizeof(struct pci_cap)); + + cap->id = id; + cap->offset = cap_offset; + + list_add(&(cap->cap_node), &(pci->capabilities)); + + // set correct init values + init_pci_cap(pci, id, cap_offset); + + + // set to the next pointer + cap_offset = next; + } + + // Disable Capabilities + pci->config_header.cap_ptr = 0; + + // Hook Cap pointer to return cached config space value + if (v3_pci_hook_config_range(pci, 0x34, 1, + NULL, NULL, NULL) == -1) { + PrintError("Could not hook cap pointer\n"); return -1; } - return length; + +/* + // Disable all PCIE extended capabilities for now + pci->config_space[0x100] = 0; + pci->config_space[0x101] = 0; + pci->config_space[0x102] = 0; + pci->config_space[0x103] = 0; +*/ + + + return 0; + } +int v3_pci_enable_capability(struct pci_device * pci, pci_cap_type_t cap_type) { + uint32_t size = 0; + struct pci_cap * tmp_cap = NULL; + struct pci_cap * cap = NULL; + void * cap_ptr = NULL; -static int addr_port_write(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) { - struct pci_internal * pci_state = priv_data; - int reg_offset = port & 0x3; - uint8_t * reg_addr = ((uint8_t *)&(pci_state->addr_reg.val)) + reg_offset; + + list_for_each_entry(tmp_cap, &(pci->capabilities), cap_node) { + if (tmp_cap->id == cap_type) { + cap = tmp_cap; + break; + } + } + + if ((cap == NULL) || (cap->enabled)) { + return -1; + } - if (length == 4) { - if (reg_offset != 0) { - PrintError("Invalid Address Port Write\n"); - return -1; + V3_Print("Found Capability %x at %x (%d)\n", cap_type, cap->offset, cap->offset); + + // found the capability + + // mark it as enabled + cap->enabled = 1; + + cap_ptr = &(pci->config_space[cap->offset + 2]); + + if (cap_type == PCI_CAP_MSI) { + pci->msi_cap = cap_ptr; + + if (pci->msi_cap->cap_64bit) { + if (pci->msi_cap->per_vect_mask) { + // 64 bit MSI w/ per vector masking + size = 22; + } else { + // 64 bit MSI + size = 12; + } + } else { + // 32 bit MSI + size = 8; } + } else if (cap_type == PCI_CAP_MSIX) { + pci->msix_cap = cap_ptr; + + // disable passthrough for MSIX BAR + + pci->bar[pci->msix_cap->bir].type = PCI_BAR_MEM32; - PrintDebug("Writing PCI 4 bytes Val=%x\n", *(uint32_t *)src); + size = 10; + } else if (cap_type == PCI_CAP_PCIE) { + struct pcie_cap_reg * pcie_cap = (struct pcie_cap_reg *)&(pci->config_space[cap->offset + 2]); - *(uint32_t *)reg_addr = *(uint32_t *)src; - } else if (length == 2) { - if (reg_offset > 2) { - PrintError("Invalid Address Port Write\n"); + if (pcie_cap->version == 1) { + size = 20; + } else if (pcie_cap->version == 2) { + size = 60; + } else { return -1; } + } else if (cap_type == PCI_CAP_PM) { + size = 8; + } - PrintDebug("Writing PCI 2 byte Val=%x\n", *(uint16_t *)src); - *(uint16_t *)reg_addr = *(uint16_t *)src; - } else if (length == 1) { - PrintDebug("Writing PCI 1 byte Val=%x\n", *(uint8_t *)src); - *(uint8_t *)reg_addr = *(uint8_t *)src; - } else { - PrintError("Invalid write length (%d) for PCI address register\n", length); + V3_Print("Hooking capability range (offset=%d, size=%d)\n", cap->offset, size); + + if (v3_pci_hook_config_range(pci, cap->offset, size + 2, + cap_write, NULL, cap) == -1) { + PrintError("Could not hook config range (start=%d, size=%d)\n", + cap->offset + 2, size); return -1; } - PrintDebug("Writing PCI Address Port(%x): %x\n", port, pci_state->addr_reg.val); + + + // link it to the active capabilities list + pci->config_space[cap->offset + 1] = pci->config_header.cap_ptr; + pci->config_header.cap_ptr = cap->offset; // add to the head of the list + + return 0; +} + + + + +static int addr_port_read(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) { + struct pci_internal * pci_state = priv_data; + int reg_offset = port & 0x3; + uint8_t * reg_addr = ((uint8_t *)&(pci_state->addr_reg.val)) + reg_offset; + + PrintDebug("Reading PCI Address Port (%x): %x len=%d\n", port, pci_state->addr_reg.val, length); + + if (reg_offset + length > 4) { + PrintError("Invalid Address port write\n"); + return -1; + } + + memcpy(dst, reg_addr, length); return length; } -static int data_port_read(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) { +static int addr_port_write(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) { + struct pci_internal * pci_state = priv_data; + int reg_offset = port & 0x3; + uint8_t * reg_addr = ((uint8_t *)&(pci_state->addr_reg.val)) + reg_offset; + + if (reg_offset + length > 4) { + PrintError("Invalid Address port write\n"); + return -1; + } + + // Set address register + memcpy(reg_addr, src, length); + + PrintDebug("Writing PCI Address Port(%x): AddrReg=%x (op_val = %x, len=%d) \n", port, pci_state->addr_reg.val, *(uint32_t *)src, length); + + return length; +} + + +static int data_port_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data) { struct pci_internal * pci_state = priv_data; struct pci_device * pci_dev = NULL; - uint_t reg_num = (pci_state->addr_reg.reg_num << 2) + (port & 0x3); - int i; + uint_t reg_num = (pci_state->addr_reg.hi_reg_num << 16) +(pci_state->addr_reg.reg_num << 2) + (port & 0x3); + int i = 0; + int bytes_left = length; if (pci_state->addr_reg.bus_num != 0) { - int i = 0; - for (i = 0; i < length; i++) { - *((uint8_t *)dst + i) = 0xff; - } - + memset(dst, 0xff, length); return length; } - PrintDebug("Reading PCI Data register. bus = %d, dev = %d, reg = %d (%x), cfg_reg = %x\n", + + pci_dev = get_device(&(pci_state->bus_list[0]), pci_state->addr_reg.dev_num, pci_state->addr_reg.fn_num); + + if (pci_dev == NULL) { + memset(dst, 0xff, length); + return length; + } + + PrintDebug("Reading PCI Data register. bus = %d, dev = %d, fn = %d, reg = %d (%x), cfg_reg = %x\n", pci_state->addr_reg.bus_num, pci_state->addr_reg.dev_num, + pci_state->addr_reg.fn_num, reg_num, reg_num, pci_state->addr_reg.val); - pci_dev = get_device(&(pci_state->bus_list[0]), pci_state->addr_reg.dev_num, pci_state->addr_reg.fn_num); - - if (pci_dev == NULL) { - for (i = 0; i < length; i++) { - *(uint8_t *)((uint8_t *)dst + i) = 0xff; - } - return length; - } + while (bytes_left > 0) { + struct cfg_range_hook * cfg_hook = find_cfg_range_hook(pci_dev, reg_num + i, 1); + void * cfg_dst = &(pci_dev->config_space[reg_num + i]); - if (pci_dev->type == PCI_PASSTHROUGH) { - if (pci_dev->config_read(reg_num, dst, length, pci_dev->priv_data) == -1) { - PrintError("Failed to handle configuration update for passthrough pci_device\n"); - return -1; - } - - return 0; - } + if (cfg_hook) { + uint_t range_len = cfg_hook->length - ((reg_num + i) - cfg_hook->start); + range_len = (range_len > bytes_left) ? bytes_left : range_len; - for (i = 0; i < length; i++) { - *(uint8_t *)((uint8_t *)dst + i) = pci_dev->config_space[reg_num + i]; - } + if (cfg_hook->read) { + cfg_hook->read(pci_dev, reg_num + i, cfg_dst, range_len, cfg_hook->private_data); + } + + bytes_left -= range_len; + i += range_len; + } else { + if (pci_dev->config_read) { + if (pci_dev->config_read(pci_dev, reg_num + i, cfg_dst, 1, pci_dev->priv_data) != 0) { + PrintError("Error in config_read from PCI device (%s)\n", pci_dev->name); + } + } + bytes_left--; + i++; + } + } + + memcpy(dst, &(pci_dev->config_space[reg_num]), length); + PrintDebug("\tVal=%x, len=%d\n", *(uint32_t *)dst, length); return length; } -static inline int is_cfg_reg_writable(uchar_t header_type, int reg_num) { - if (header_type == 0x00) { - switch (reg_num) { - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0e: - case 0x3d: - return 0; - - default: - return 1; - - } - } else if (header_type == 0x80) { - switch (reg_num) { - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0e: - case 0x3d: - return 0; - - default: - return 1; - - } - } else { - // PCI to PCI Bridge = 0x01 - // CardBus Bridge = 0x02 - // huh? - PrintError("Invalid PCI Header type (0x%.2x)\n", header_type); +static int bar_update(struct pci_device * pci_dev, uint32_t offset, + void * src, uint_t length, void * private_data) { + struct v3_pci_bar * bar = (struct v3_pci_bar *)private_data; + int bar_offset = offset & ~0x03; + int bar_num = (bar_offset - 0x10) / 4; + uint32_t new_val = *(uint32_t *)src; + + PrintDebug("Updating BAR Register (Dev=%s) (bar=%d) (old_val=0x%x) (new_val=0x%x)\n", + pci_dev->name, bar_num, bar->val, new_val); - return -1; - } -} + // Cache the changes locally + memcpy(&(pci_dev->config_space[offset]), src, length); -static int bar_update(struct guest_info * info, struct pci_device * pci, int bar_num, uint32_t new_val) { - struct v3_pci_bar * bar = &(pci->bar[bar_num]); + if (bar->type == PCI_BAR_PASSTHROUGH) { + if (bar->bar_write(bar_num, (void *)(pci_dev->config_space + bar_offset), bar->private_data) == -1) { + PrintError("Error in Passthrough bar write operation\n"); + return -1; + } + + return 0; + } + + // Else we are a virtualized BAR - PrintDebug("Updating BAR Register (Dev=%s) (bar=%d) (old_val=0x%x) (new_val=0x%x)\n", - pci->name, bar_num, bar->val, new_val); + *(uint32_t *)(pci_dev->config_space + offset) &= bar->mask; switch (bar->type) { case PCI_BAR_IO: { @@ -410,7 +854,7 @@ static int bar_update(struct guest_info * info, struct pci_device * pci, int bar bar->num_ports); // only do this if pci device is enabled.... - if (!(pci->config_header.status & 0x1)) { + if (!(pci_dev->config_header.status & 0x1)) { PrintError("PCI Device IO space not enabled\n"); } @@ -419,15 +863,15 @@ static int bar_update(struct guest_info * info, struct pci_device * pci, int bar PrintDebug("Rehooking PCI IO port (old port=%u) (new port=%u)\n", PCI_IO_BASE(bar->val) + i, PCI_IO_BASE(new_val) + i); - v3_unhook_io_port(info->vm_info, PCI_IO_BASE(bar->val) + i); + v3_unhook_io_port(pci_dev->vm, PCI_IO_BASE(bar->val) + i); - if (v3_hook_io_port(info->vm_info, PCI_IO_BASE(new_val) + i, + if (v3_hook_io_port(pci_dev->vm, PCI_IO_BASE(new_val) + i, bar->io_read, bar->io_write, bar->private_data) == -1) { PrintError("Could not hook PCI IO port (old port=%u) (new port=%u)\n", PCI_IO_BASE(bar->val) + i, PCI_IO_BASE(new_val) + i); - v3_print_io_map(info->vm_info); + v3_print_io_map(pci_dev->vm); return -1; } } @@ -437,12 +881,12 @@ static int bar_update(struct guest_info * info, struct pci_device * pci, int bar break; } case PCI_BAR_MEM32: { - v3_unhook_mem(info->vm_info, V3_MEM_CORE_ANY, (addr_t)(bar->val)); + v3_unhook_mem(pci_dev->vm, V3_MEM_CORE_ANY, (addr_t)(bar->val)); if (bar->mem_read) { - v3_hook_full_mem(info->vm_info, V3_MEM_CORE_ANY, PCI_MEM32_BASE(new_val), + v3_hook_full_mem(pci_dev->vm, V3_MEM_CORE_ANY, PCI_MEM32_BASE(new_val), PCI_MEM32_BASE(new_val) + (bar->num_pages * PAGE_SIZE_4KB), - bar->mem_read, bar->mem_write, pci->priv_data); + bar->mem_read, bar->mem_write, pci_dev->priv_data); } else { PrintError("Write hooks not supported for PCI\n"); return -1; @@ -454,7 +898,7 @@ static int bar_update(struct guest_info * info, struct pci_device * pci, int bar } case PCI_BAR_NONE: { PrintDebug("Reprogramming an unsupported BAR register (Dev=%s) (bar=%d) (val=%x)\n", - pci->name, bar_num, new_val); + pci_dev->name, bar_num, new_val); break; } default: @@ -466,12 +910,12 @@ static int bar_update(struct guest_info * info, struct pci_device * pci, int bar } -static int data_port_write(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) { +static int data_port_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data) { struct pci_internal * pci_state = priv_data; struct pci_device * pci_dev = NULL; - uint_t reg_num = (pci_state->addr_reg.reg_num << 2) + (port & 0x3); - int i; - + uint_t reg_num = (pci_state->addr_reg.hi_reg_num << 16) +(pci_state->addr_reg.reg_num << 2) + (port & 0x3); + int i = 0; + int ret = length; if (pci_state->addr_reg.bus_num != 0) { return length; @@ -493,110 +937,107 @@ static int data_port_write(struct guest_info * core, ushort_t port, void * src, pci_state->addr_reg.dev_num); return -1; } - - if (pci_dev->type == PCI_PASSTHROUGH) { - if (pci_dev->config_write(reg_num, src, length, pci_dev->priv_data) == -1) { - PrintError("Failed to handle configuration update for passthrough pci_device\n"); - return -1; - } - - return 0; - } + /* update the config space + If a hook has been registered for a given region, call the hook with the max write length + */ + while (length > 0) { + struct cfg_range_hook * cfg_hook = find_cfg_range_hook(pci_dev, reg_num + i, 1); - for (i = 0; i < length; i++) { - uint_t cur_reg = reg_num + i; - int writable = is_cfg_reg_writable(pci_dev->config_header.header_type, cur_reg); - - if (writable == -1) { - PrintError("Invalid PCI configuration space\n"); - return -1; - } - - if (writable) { - pci_dev->config_space[cur_reg] = *(uint8_t *)((uint8_t *)src + i); + if (cfg_hook) { + uint_t range_len = cfg_hook->length - ((reg_num + i) - cfg_hook->start); + range_len = (range_len > length) ? length : range_len; + + if (cfg_hook->write) { + cfg_hook->write(pci_dev, reg_num + i, (void *)(src + i), range_len, cfg_hook->private_data); + } - if ((cur_reg >= 0x10) && (cur_reg < 0x28)) { - // BAR Register Update - int bar_reg = ((cur_reg & ~0x3) - 0x10) / 4; - - pci_dev->bar_update_flag = 1; - pci_dev->bar[bar_reg].updated = 1; - - // PrintDebug("Updating BAR register %d\n", bar_reg); + length -= range_len; + i += range_len; + } else { + // send the writes to the cached config space, and to the generic callback if present + uint8_t mask = 0xff; - } else if ((cur_reg >= 0x30) && (cur_reg < 0x34)) { - // Extension ROM update + if (reg_num < 64) { + mask = pci_hdr_write_mask_00[reg_num + i]; + } + + if (mask != 0) { + uint8_t new_val = *(uint8_t *)(src + i); + uint8_t old_val = pci_dev->config_space[reg_num + i]; - pci_dev->exp_rom_update_flag = 1; - } else if (cur_reg == 0x04) { - // COMMAND update - uint8_t command = *((uint8_t *)src + i); + pci_dev->config_space[reg_num + i] = ((new_val & mask) | (old_val & ~mask)); - PrintError("command update for %s old=%x new=%x\n", - pci_dev->name, - pci_dev->config_space[cur_reg],command); - - pci_dev->config_space[cur_reg] = command; - - if (pci_dev->cmd_update) { - pci_dev->cmd_update(pci_dev, (command & 0x01), (command & 0x02)); + if (pci_dev->config_write) { + pci_dev->config_write(pci_dev, reg_num + i, &(pci_dev->config_space[reg_num + i]), 1, pci_dev->priv_data); } - - } else if (cur_reg == 0x0f) { - // BIST update - pci_dev->config_header.BIST = 0x00; - } - } else { - PrintError("PCI Write to read only register %d\n", cur_reg); + } + + length--; + i++; } } - if (pci_dev->config_update) { - pci_dev->config_update(reg_num, src, length, pci_dev->priv_data); + return ret; +} + + + +static int exp_rom_write(struct pci_device * pci_dev, uint32_t offset, + void * src, uint_t length, void * private_data) { + int bar_offset = offset & ~0x03; + + if (pci_dev->exp_rom_update) { + pci_dev->exp_rom_update(pci_dev, (void *)(pci_dev->config_space + bar_offset), pci_dev->priv_data); + + return 0; } - // Scan for BAR updated - if (pci_dev->bar_update_flag) { - for (i = 0; i < 6; i++) { - if (pci_dev->bar[i].updated) { - int bar_offset = 0x10 + 4 * i; + PrintError("Expansion ROM update not handled. Will appear to not Exist\n"); + return 0; +} - if (pci_dev->bar[i].type == PCI_BAR_PASSTHROUGH) { - if (pci_dev->bar[i].bar_write(i, (uint32_t *)(pci_dev->config_space + bar_offset), pci_dev->bar[i].private_data) == -1) { - PrintError("Error in passthrough bar write operation\n"); - return -1; - } - } else { - *(uint32_t *)(pci_dev->config_space + bar_offset) &= pci_dev->bar[i].mask; - // check special flags.... +static int cmd_write(struct pci_device * pci_dev, uint32_t offset, + void * src, uint_t length, void * private_data) { - // bar_update - if (bar_update(core, pci_dev, i, *(uint32_t *)(pci_dev->config_space + bar_offset)) == -1) { - PrintError("PCI Device %s: Bar update Error Bar=%d\n", pci_dev->name, i); - return -1; - } - } + int i = 0; - pci_dev->bar[i].updated = 0; - } - } - pci_dev->bar_update_flag = 0; - } + struct pci_cmd_reg old_cmd; + struct pci_cmd_reg new_cmd; + old_cmd.val = pci_dev->config_header.command; + + for (i = 0; i < length; i++) { + uint8_t mask = pci_hdr_write_mask_00[offset + i]; + uint8_t new_val = *(uint8_t *)(src + i); + uint8_t old_val = pci_dev->config_space[offset + i]; - if ((pci_dev->exp_rom_update_flag) && (pci_dev->exp_rom_update)) { - pci_dev->exp_rom_update(pci_dev, &(pci_dev->config_header.expansion_rom_address), pci_dev->priv_data); - pci_dev->exp_rom_update_flag = 0; + pci_dev->config_space[offset + i] = ((new_val & mask) | (old_val & ~mask)); } + new_cmd.val = pci_dev->config_header.command; - return length; -} + + if (pci_dev->cmd_update) { + if ((new_cmd.intx_disable == 1) && (old_cmd.intx_disable == 0)) { + pci_dev->irq_type = IRQ_NONE; + pci_dev->cmd_update(pci_dev, PCI_CMD_INTX_DISABLE, 0, pci_dev->priv_data); + } else if ((new_cmd.intx_disable == 0) && (old_cmd.intx_disable == 1)) { + pci_dev->irq_type = IRQ_INTX; + pci_dev->cmd_update(pci_dev, PCI_CMD_INTX_ENABLE, 0, pci_dev->priv_data); + } + if ((new_cmd.dma_enable == 1) && (old_cmd.dma_enable == 0)) { + pci_dev->cmd_update(pci_dev, PCI_CMD_DMA_ENABLE, 0, pci_dev->priv_data); + } else if ((new_cmd.dma_enable == 0) && (old_cmd.dma_enable == 1)) { + pci_dev->cmd_update(pci_dev, PCI_CMD_DMA_DISABLE, 0, pci_dev->priv_data); + } + } + return 0; +} static void init_pci_busses(struct pci_internal * pci_state) { @@ -625,6 +1066,27 @@ static int pci_free(struct pci_internal * pci_state) { node = v3_rb_next(node); v3_rb_erase(&(dev->dev_tree_node), &(bus->devices)); + + // Free config range hooks + { + struct cfg_range_hook * hook = NULL; + struct cfg_range_hook * tmp = NULL; + list_for_each_entry_safe(hook, tmp, &(dev->cfg_hooks), list_node) { + list_del(&(hook->list_node)); + V3_Free(hook); + } + } + + // Free caps + { + struct pci_cap * cap = NULL; + struct pci_cap * tmp = NULL; + list_for_each_entry_safe(cap, tmp, &(dev->cfg_hooks), cap_node) { + list_del(&(cap->cap_node)); + V3_Free(cap); + } + } + V3_Free(dev); } @@ -785,82 +1247,85 @@ static inline int init_bars(struct v3_vm_info * vm, struct pci_device * pci_dev) for (i = 0; i < 6; i++) { int bar_offset = 0x10 + (4 * i); + struct v3_pci_bar * bar = &(pci_dev->bar[i]); - if (pci_dev->bar[i].type == PCI_BAR_IO) { + if (bar->type == PCI_BAR_IO) { int j = 0; - pci_dev->bar[i].mask = (~((pci_dev->bar[i].num_ports) - 1)) | 0x01; + bar->mask = (~((bar->num_ports) - 1)) | 0x01; - if (pci_dev->bar[i].default_base_port != 0xffff) { - pci_dev->bar[i].val = pci_dev->bar[i].default_base_port & pci_dev->bar[i].mask; + if (bar->default_base_port != 0xffff) { + bar->val = bar->default_base_port & bar->mask; } else { - pci_dev->bar[i].val = 0; + bar->val = 0; } - pci_dev->bar[i].val |= 0x00000001; + bar->val |= 0x00000001; - for (j = 0; j < pci_dev->bar[i].num_ports; j++) { + for (j = 0; j < bar->num_ports; j++) { // hook IO - if (pci_dev->bar[i].default_base_port != 0xffff) { - if (v3_hook_io_port(vm, pci_dev->bar[i].default_base_port + j, - pci_dev->bar[i].io_read, pci_dev->bar[i].io_write, - pci_dev->bar[i].private_data) == -1) { - PrintError("Could not hook default io port %x\n", pci_dev->bar[i].default_base_port + j); + if (bar->default_base_port != 0xffff) { + if (v3_hook_io_port(vm, bar->default_base_port + j, + bar->io_read, bar->io_write, + bar->private_data) == -1) { + PrintError("Could not hook default io port %x\n", bar->default_base_port + j); return -1; } } } - *(uint32_t *)(pci_dev->config_space + bar_offset) = pci_dev->bar[i].val; + *(uint32_t *)(pci_dev->config_space + bar_offset) = bar->val; - } else if (pci_dev->bar[i].type == PCI_BAR_MEM32) { - pci_dev->bar[i].mask = ~((pci_dev->bar[i].num_pages << 12) - 1); - pci_dev->bar[i].mask |= 0xf; // preserve the configuration flags + } else if (bar->type == PCI_BAR_MEM32) { + bar->mask = ~((bar->num_pages << 12) - 1); + bar->mask |= 0xf; // preserve the configuration flags - if (pci_dev->bar[i].default_base_addr != 0xffffffff) { - pci_dev->bar[i].val = pci_dev->bar[i].default_base_addr & pci_dev->bar[i].mask; + if (bar->default_base_addr != 0xffffffff) { + bar->val = bar->default_base_addr & bar->mask; } else { - pci_dev->bar[i].val = 0; + bar->val = 0; } // hook memory - if (pci_dev->bar[i].mem_read) { + if (bar->mem_read) { // full hook - v3_hook_full_mem(vm, V3_MEM_CORE_ANY, pci_dev->bar[i].default_base_addr, - pci_dev->bar[i].default_base_addr + (pci_dev->bar[i].num_pages * PAGE_SIZE_4KB), - pci_dev->bar[i].mem_read, pci_dev->bar[i].mem_write, pci_dev->priv_data); - } else if (pci_dev->bar[i].mem_write) { + v3_hook_full_mem(vm, V3_MEM_CORE_ANY, bar->default_base_addr, + bar->default_base_addr + (bar->num_pages * PAGE_SIZE_4KB), + bar->mem_read, bar->mem_write, pci_dev->priv_data); + } else if (bar->mem_write) { // write hook PrintError("Write hooks not supported for PCI devices\n"); return -1; /* - v3_hook_write_mem(pci_dev->vm_dev->vm, pci_dev->bar[i].default_base_addr, - pci_dev->bar[i].default_base_addr + (pci_dev->bar[i].num_pages * PAGE_SIZE_4KB), - pci_dev->bar[i].mem_write, pci_dev->vm_dev); + v3_hook_write_mem(pci_dev->vm_dev->vm, bar->default_base_addr, + bar->default_base_addr + (bar->num_pages * PAGE_SIZE_4KB), + bar->mem_write, pci_dev->vm_dev); */ } else { // set the prefetchable flag... - pci_dev->bar[i].val |= 0x00000008; + bar->val |= 0x00000008; } - *(uint32_t *)(pci_dev->config_space + bar_offset) = pci_dev->bar[i].val; + *(uint32_t *)(pci_dev->config_space + bar_offset) = bar->val; - } else if (pci_dev->bar[i].type == PCI_BAR_MEM24) { + } else if (bar->type == PCI_BAR_MEM24) { PrintError("16 Bit memory ranges not supported (reg: %d)\n", i); return -1; - } else if (pci_dev->bar[i].type == PCI_BAR_NONE) { - pci_dev->bar[i].val = 0x00000000; - pci_dev->bar[i].mask = 0x00000000; // This ensures that all updates will be dropped - *(uint32_t *)(pci_dev->config_space + bar_offset) = pci_dev->bar[i].val; - } else if (pci_dev->bar[i].type == PCI_BAR_PASSTHROUGH) { + } else if (bar->type == PCI_BAR_NONE) { + bar->val = 0x00000000; + bar->mask = 0x00000000; // This ensures that all updates will be dropped + *(uint32_t *)(pci_dev->config_space + bar_offset) = bar->val; + } else if (bar->type == PCI_BAR_PASSTHROUGH) { // Call the bar init function to get the local cached value - pci_dev->bar[i].bar_init(i, &(pci_dev->bar[i].val), pci_dev->bar[i].private_data); + bar->bar_init(i, &(bar->val), bar->private_data); } else { PrintError("Invalid BAR type for bar #%d\n", i); return -1; } + + v3_pci_hook_config_range(pci_dev, bar_offset, 4, bar_update, NULL, bar); } return 0; @@ -868,8 +1333,8 @@ static inline int init_bars(struct v3_vm_info * vm, struct pci_device * pci_dev) int v3_pci_set_irq_bridge(struct vm_device * pci_bus, int bus_num, - int (*raise_pci_irq)(struct pci_device * pci_dev, void * dev_data), - int (*lower_pci_irq)(struct pci_device * pci_dev, void * dev_data), + int (*raise_pci_irq)(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec), + int (*lower_pci_irq)(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec), void * priv_data) { struct pci_internal * pci_state = (struct pci_internal *)pci_bus->private_data; @@ -881,20 +1346,129 @@ int v3_pci_set_irq_bridge(struct vm_device * pci_bus, int bus_num, return 0; } -int v3_pci_raise_irq(struct vm_device * pci_bus, int bus_num, struct pci_device * dev) { - struct pci_internal * pci_state = (struct pci_internal *)pci_bus->private_data; - struct pci_bus * bus = &(pci_state->bus_list[bus_num]); +int v3_pci_raise_irq(struct vm_device * pci_bus, struct pci_device * dev, uint32_t vec_index) { + struct v3_irq vec; - return bus->raise_pci_irq(dev, bus->irq_dev_data); + vec.ack = NULL; + vec.private_data = NULL; + vec.irq = vec_index; + + return v3_pci_raise_acked_irq(pci_bus, dev, vec); } -int v3_pci_lower_irq(struct vm_device * pci_bus, int bus_num, struct pci_device * dev) { +int v3_pci_lower_irq(struct vm_device * pci_bus, struct pci_device * dev, uint32_t vec_index) { + struct v3_irq vec; + + vec.irq = vec_index; + vec.ack = NULL; + vec.private_data = NULL; + + return v3_pci_lower_acked_irq(pci_bus, dev, vec); +} + +int v3_pci_raise_acked_irq(struct vm_device * pci_bus, struct pci_device * dev, struct v3_irq vec) { struct pci_internal * pci_state = (struct pci_internal *)pci_bus->private_data; - struct pci_bus * bus = &(pci_state->bus_list[bus_num]); + struct pci_bus * bus = &(pci_state->bus_list[dev->bus_num]); + + + if (dev->irq_type == IRQ_INTX) { + return bus->raise_pci_irq(dev, bus->irq_dev_data, &vec); + } else if (dev->irq_type == IRQ_MSI) { + struct v3_gen_ipi ipi; + struct msi_addr * addr = NULL; + struct msi_data * data = NULL; + + if (dev->msi_cap->cap_64bit) { + if (dev->msi_cap->per_vect_mask) { + struct msi64_pervec_msg_addr * msi = (void *)dev->msi_cap; + addr = &(msi->addr); + data = &(msi->data); + } else { + struct msi64_msg_addr * msi = (void *)dev->msi_cap; + addr = &(msi->addr); + data = &(msi->data); + } + } else { + struct msi32_msg_addr * msi = (void *)dev->msi_cap; + addr = &(msi->addr); + data = &(msi->data); + } + + memset(&ipi, 0, sizeof(struct v3_gen_ipi)); + + // decode MSI fields into IPI + + ipi.vector = data->vector + vec.irq; + ipi.mode = data->del_mode; + ipi.logical = addr->dst_mode; + ipi.trigger_mode = data->trig_mode; + ipi.dst_shorthand = 0; + ipi.dst = addr->dst_id; + + + v3_apic_send_ipi(dev->vm, &ipi, dev->apic_dev); + + return 0; + } else if (dev->irq_type == IRQ_MSIX) { + addr_t msix_table_gpa = 0; + struct msix_table * msix_table = NULL; + uint_t bar_idx = dev->msix_cap->bir; + struct v3_gen_ipi ipi; + struct msi_addr * addr = NULL; + struct msi_data * data = NULL; + + if (dev->bar[bar_idx].type != PCI_BAR_MEM32) { + PrintError("Non 32bit MSIX BAR registers are not supported\n"); + return -1; + } + + msix_table_gpa = dev->bar[bar_idx].val; + msix_table_gpa += dev->msix_cap->table_offset; + + if (v3_gpa_to_hva(&(dev->vm->cores[0]), msix_table_gpa, (void *)&(msix_table)) != 0) { + PrintError("Could not translate MSIX Table GPA (%p)\n", (void *)msix_table_gpa); + return -1; + } + + memset(&ipi, 0, sizeof(struct v3_gen_ipi)); + + data = &(msix_table->entries[vec.irq].data); + addr = &(msix_table->entries[vec.irq].addr);; + + // decode MSIX fields into IPI + ipi.vector = data->vector + vec.irq; + ipi.mode = data->del_mode; + ipi.logical = addr->dst_mode; + ipi.trigger_mode = data->trig_mode; + ipi.dst_shorthand = 0; + ipi.dst = addr->dst_id; + + + + V3_Print("Decode MSIX\n"); + + v3_apic_send_ipi(dev->vm, &ipi, dev->apic_dev); + + return 0; + } + + // Should never get here + return -1; - return bus->lower_pci_irq(dev, bus->irq_dev_data); } +int v3_pci_lower_acked_irq(struct vm_device * pci_bus, struct pci_device * dev, struct v3_irq vec) { + if (dev->irq_type == IRQ_INTX) { + struct pci_internal * pci_state = (struct pci_internal *)pci_bus->private_data; + struct pci_bus * bus = &(pci_state->bus_list[dev->bus_num]); + + return bus->lower_pci_irq(dev, bus->irq_dev_data, &vec); + } else { + return -1; + } +} + + // if dev_num == -1, auto assign struct pci_device * v3_pci_register_device(struct vm_device * pci, pci_device_type_t dev_type, @@ -903,8 +1477,11 @@ struct pci_device * v3_pci_register_device(struct vm_device * pci, int fn_num, const char * name, struct v3_pci_bar * bars, - int (*config_update)(uint_t reg_num, void * src, uint_t length, void * priv_data), - int (*cmd_update)(struct pci_device * pci_dev, uchar_t io_enabled, uchar_t mem_enabled), + int (*config_write)(struct pci_device * pci_dev, uint32_t reg_num, void * src, + uint_t length, void * priv_data), + int (*config_read)(struct pci_device * pci_dev, uint32_t reg_num, void * dst, + uint_t length, void * priv_data), + int (*cmd_update)(struct pci_device * pci_dev, pci_cmd_t cmd, uint64_t arg, void * priv_data), int (*exp_rom_update)(struct pci_device * pci_dev, uint32_t * src, void * priv_data), void * priv_data) { @@ -966,14 +1543,53 @@ struct pci_device * v3_pci_register_device(struct vm_device * pci, pci_dev->fn_num = fn_num; strncpy(pci_dev->name, name, sizeof(pci_dev->name)); + pci_dev->vm = pci->vm; pci_dev->priv_data = priv_data; + INIT_LIST_HEAD(&(pci_dev->cfg_hooks)); + INIT_LIST_HEAD(&(pci_dev->capabilities)); + + + { + // locate APIC for MSI/MSI-X + pci_dev->apic_dev = v3_find_dev(pci->vm, "apic"); + } + // register update callbacks - pci_dev->config_update = config_update; + pci_dev->config_write = config_write; + pci_dev->config_read = config_read; pci_dev->cmd_update = cmd_update; pci_dev->exp_rom_update = exp_rom_update; + + if (config_read) { + int i = 0; + + // Only 256 bytes for now, should expand it in the future + for (i = 0; i < 256; i++) { + config_read(pci_dev, i, &(pci_dev->config_space[i]), 1, pci_dev->priv_data); + } + } + + V3_Print("Scanning for Capabilities\n"); + + // scan for caps + scan_pci_caps(pci_dev); + + pci_dev->irq_type = IRQ_INTX; + + V3_Print("Caps scanned\n"); + + // hook important regions + v3_pci_hook_config_range(pci_dev, 0x30, 4, exp_rom_write, NULL, NULL); // ExpRom + v3_pci_hook_config_range(pci_dev, 0x04, 2, cmd_write, NULL, NULL); // CMD Reg + // * Status resets + // * Drop BIST + // + + + //copy bars for (i = 0; i < 6; i ++) { pci_dev->bar[i].type = bars[i].type; @@ -1024,70 +1640,3 @@ struct pci_device * v3_pci_register_device(struct vm_device * pci, return pci_dev; } - - -// if dev_num == -1, auto assign -struct pci_device * v3_pci_register_passthrough_device(struct vm_device * pci, - int bus_num, - int dev_num, - int fn_num, - const char * name, - int (*config_write)(uint_t reg_num, void * src, uint_t length, void * private_data), - int (*config_read)(uint_t reg_num, void * dst, uint_t length, void * private_data), - void * private_data) { - - struct pci_internal * pci_state = (struct pci_internal *)pci->private_data; - struct pci_bus * bus = &(pci_state->bus_list[bus_num]); - struct pci_device * pci_dev = NULL; - - if (dev_num > MAX_BUS_DEVICES) { - PrintError("Requested Invalid device number (%d)\n", dev_num); - return NULL; - } - - if (dev_num == PCI_AUTO_DEV_NUM) { - PrintDebug("Searching for free device number\n"); - if ((dev_num = get_free_dev_num(bus)) == -1) { - PrintError("No more available PCI slots on bus %d\n", bus->bus_num); - return NULL; - } - } - - PrintDebug("Checking for PCI Device\n"); - - if (get_device(bus, dev_num, fn_num) != NULL) { - PrintError("PCI Device already registered at slot %d on bus %d\n", - dev_num, bus->bus_num); - return NULL; - } - - - pci_dev = (struct pci_device *)V3_Malloc(sizeof(struct pci_device)); - - if (pci_dev == NULL) { - PrintError("Could not allocate pci device\n"); - return NULL; - } - - memset(pci_dev, 0, sizeof(struct pci_device)); - - pci_dev->bus_num = bus_num; - pci_dev->dev_num = dev_num; - pci_dev->fn_num = fn_num; - - strncpy(pci_dev->name, name, sizeof(pci_dev->name)); - pci_dev->priv_data = private_data; - - // register update callbacks - pci_dev->config_write = config_write; - pci_dev->config_read = config_read; - - // add the device - add_device_to_bus(bus, pci_dev); - -#ifdef V3_CONFIG_DEBUG_PCI - pci_dump_state(pci_state); -#endif - - return pci_dev; -} diff --git a/palacios/src/devices/pci_front.c b/palacios/src/devices/pci_front.c index 70dc980..68428b5 100644 --- a/palacios/src/devices/pci_front.c +++ b/palacios/src/devices/pci_front.c @@ -607,7 +607,7 @@ static int pci_bar_write(int bar_num, uint32_t * src, void * private_data) { } -static int pci_front_config_update(uint_t reg_num, void * src, uint_t length, void * private_data) +static int pci_front_config_update(struct pci_device *pci_dev, uint_t reg_num, void * src, uint_t length, void * private_data) { int i; struct vm_device * dev = (struct vm_device *)private_data; @@ -690,6 +690,7 @@ static int setup_virt_pci_dev(struct v3_vm_info * vm_info, struct vm_device * de bus_num, -1, 0, state->name, bars, pci_front_config_update, + NULL, // no suport for config reads NULL, // no support for command updates NULL, // no support for expansion roms dev); diff --git a/palacios/src/devices/pci_passthrough.c b/palacios/src/devices/pci_passthrough.c index b8f921b..e8d72db 100644 --- a/palacios/src/devices/pci_passthrough.c +++ b/palacios/src/devices/pci_passthrough.c @@ -588,7 +588,7 @@ static int pci_bar_write(int bar_num, uint32_t * src, void * private_data) { } -static int pt_config_update(uint_t reg_num, void * src, uint_t length, void * private_data) { +static int pt_config_update(struct pci_device * pci_dev, uint_t reg_num, void * src, uint_t length, void * private_data) { struct vm_device * dev = (struct vm_device *)private_data; struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data; union pci_addr_reg pci_addr = {state->phys_pci_addr.value}; @@ -732,6 +732,7 @@ static int setup_virt_pci_dev(struct v3_vm_info * vm_info, struct vm_device * de bus_num, -1, 0, state->name, bars, pt_config_update, + NULL, NULL, pt_exp_rom_write, dev); @@ -762,7 +763,7 @@ static int irq_handler(struct v3_vm_info * vm, struct v3_interrupt * intr, void struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data; - v3_pci_raise_irq(state->pci_bus, 0, state->pci_dev); + v3_pci_raise_irq(state->pci_bus, state->pci_dev, 0); V3_ACK_IRQ(intr->irq); diff --git a/palacios/src/devices/piix3.c b/palacios/src/devices/piix3.c index b482b48..35925b5 100644 --- a/palacios/src/devices/piix3.c +++ b/palacios/src/devices/piix3.c @@ -371,12 +371,16 @@ struct pirq_rc_reg { */ -static int raise_pci_irq(struct pci_device * pci_dev, void * dev_data) { +static int raise_pci_irq(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec) { struct v3_southbridge * piix3 = dev_data; struct pci_device * piix3_pci = piix3->southbridge_pci; struct piix3_config_space * piix3_cfg = (struct piix3_config_space *)(piix3_pci->config_data); int intr_pin = pci_dev->config_header.intr_pin - 1; int irq_index = (intr_pin + pci_dev->dev_num - 1) & 0x3; + struct v3_irq irq; // Make a copy of the irq state because we will switch the irq number + + irq.ack = vec->ack; + irq.private_data = vec->private_data; /* PrintError("Raising PCI dev %d intr %d via IOAPIC as IRQ %d and via PIRQ as IRQ %d on VM %p\n", @@ -388,7 +392,10 @@ static int raise_pci_irq(struct pci_device * pci_dev, void * dev_data) { // deliver first by PIRQ, if it exists // if (piix3_cfg->pirq_rc[irq_index] < 16) { - v3_raise_irq(piix3->vm, piix3_cfg->pirq_rc[irq_index] & 0xf); + irq.irq = piix3_cfg->pirq_rc[irq_index] & 0xf; + + // V3_Print("Raising PIIX IRQ %d\n", irq.irq); + v3_raise_acked_irq(piix3->vm, irq); } else { // not an error } @@ -396,7 +403,9 @@ static int raise_pci_irq(struct pci_device * pci_dev, void * dev_data) { // deliver next via the PCI0 to ioapic mapping defined in the // mptable (ioapic, pins 16->19 are used for PCI0) // ideally this would check to verify that an ioapic is actually available - v3_raise_irq(piix3->vm, 16+irq_index); + irq.irq = (irq_index + 1) + 16; + // V3_Print("Raising PIIX IRQ (#2) %d\n", irq.irq); + v3_raise_acked_irq(piix3->vm, irq); return 0; @@ -404,21 +413,26 @@ static int raise_pci_irq(struct pci_device * pci_dev, void * dev_data) { -static int lower_pci_irq(struct pci_device * pci_dev, void * dev_data) { +static int lower_pci_irq(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec) { struct v3_southbridge * piix3 = dev_data; struct pci_device * piix3_pci = piix3->southbridge_pci; struct piix3_config_space * piix3_cfg = (struct piix3_config_space *)(piix3_pci->config_data); int intr_pin = pci_dev->config_header.intr_pin - 1; int irq_index = (intr_pin + pci_dev->dev_num - 1) & 0x3; - + struct v3_irq irq; // Make a copy of the irq state because we will switch the irq number + + irq.ack = vec->ack; + irq.private_data = vec->private_data; // PrintError("Lowering PCI IRQ %d\n", piix3_cfg->pirq_rc[irq_index]); // First, lower the pin on the ioapic - v3_lower_irq(piix3->vm, irq_index+16); + irq.irq = (irq_index + 1) + 16; + v3_lower_acked_irq(piix3->vm, irq); // Next, lower whatever we asserted by the PIRQs if (piix3_cfg->pirq_rc[irq_index] < 16) { - v3_lower_irq(piix3->vm, piix3_cfg->pirq_rc[irq_index] & 0xf); + irq.irq = piix3_cfg->pirq_rc[irq_index] & 0xf; + v3_lower_acked_irq(piix3->vm, irq); } else { // not an error } @@ -457,7 +471,7 @@ static int setup_pci(struct v3_southbridge * piix3) { pci_dev = v3_pci_register_device(piix3->pci_bus, PCI_MULTIFUNCTION, bus_num, -1, 0, "PIIX3", bars, - NULL, NULL, NULL, piix3); + NULL, NULL, NULL, NULL, piix3); if (pci_dev == NULL) { PrintError("Could not register PCI Device for PIIX3\n"); return -1; diff --git a/palacios/src/devices/rtl8139.c b/palacios/src/devices/rtl8139.c index 33a5cfa..fde3ef9 100644 --- a/palacios/src/devices/rtl8139.c +++ b/palacios/src/devices/rtl8139.c @@ -582,7 +582,7 @@ static inline void rtl8139_update_irq(struct rtl8139_state * nic_state) { int isr = ((nic_state->regs.isr & nic_state->regs.imr) & 0xffff); if(isr & 0xffff){ - v3_pci_raise_irq(nic_state->pci_bus, 0, nic_state->pci_dev); + v3_pci_raise_irq(nic_state->pci_bus, nic_state->pci_dev, 0); nic_state->statistic.tx_interrupts ++; } } @@ -1732,7 +1732,7 @@ static int register_dev(struct rtl8139_state * nic_state) { pci_dev = v3_pci_register_device(nic_state->pci_bus, PCI_STD_DEVICE, 0, -1, 0, "RTL8139", bars, - NULL, NULL, NULL, nic_state); + NULL, NULL, NULL, NULL, nic_state); if (pci_dev == NULL) { diff --git a/palacios/src/interfaces/vmm_file.c b/palacios/src/interfaces/vmm_file.c index c4d3f28..4827a95 100644 --- a/palacios/src/interfaces/vmm_file.c +++ b/palacios/src/interfaces/vmm_file.c @@ -28,8 +28,7 @@ static struct v3_file_hooks * file_hooks = NULL; void V3_Init_File(struct v3_file_hooks * hooks) { file_hooks = hooks; - PrintDebug("V3 file access inited\n"); - + V3_Print("V3 file interface intialized\n"); return; } diff --git a/palacios/src/palacios/svm.c b/palacios/src/palacios/svm.c index 28fe355..115a369 100644 --- a/palacios/src/palacios/svm.c +++ b/palacios/src/palacios/svm.c @@ -155,7 +155,7 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * core) { ctrl_area->instrs.NMI = 1; ctrl_area->instrs.SMI = 0; // allow SMIs to run in guest ctrl_area->instrs.INIT = 1; - ctrl_area->instrs.PAUSE = 1; + // ctrl_area->instrs.PAUSE = 1; ctrl_area->instrs.shutdown_evts = 1; diff --git a/palacios/src/palacios/svm_handler.c b/palacios/src/palacios/svm_handler.c index 1fc0b7c..96fcaa1 100644 --- a/palacios/src/palacios/svm_handler.c +++ b/palacios/src/palacios/svm_handler.c @@ -56,7 +56,8 @@ int v3_handle_svm_exit(struct guest_info * info, addr_t exit_code, addr_t exit_i #endif - //PrintDebug("SVM Returned: Exit Code: %x\n",exit_code); + + // PrintDebug("SVM Returned: Exit Code: %p\n", (void *)exit_code); switch (exit_code) { case VMEXIT_IOIO: { @@ -309,10 +310,10 @@ int v3_handle_svm_exit(struct guest_info * info, addr_t exit_code, addr_t exit_i PrintError("SVM Returned: Exit Code: %p\n", (void *)(addr_t)exit_code); PrintError("io_info1 low = 0x%.8x\n", *(uint_t*)&(exit_info1)); - PrintError("io_info1 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(exit_info1)) + 4)); + PrintError("io_info1 high = 0x%.8x\n", *(uint_t *)(((uint8_t *)&(exit_info1)) + 4)); PrintError("io_info2 low = 0x%.8x\n", *(uint_t*)&(exit_info2)); - PrintError("io_info2 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(exit_info2)) + 4)); + PrintError("io_info2 high = 0x%.8x\n", *(uint_t *)(((uint8_t *)&(exit_info2)) + 4)); if (info->shdw_pg_mode == SHADOW_PAGING) { diff --git a/palacios/src/palacios/vmm_dev_mgr.c b/palacios/src/palacios/vmm_dev_mgr.c index d08b227..a9e2af9 100644 --- a/palacios/src/palacios/vmm_dev_mgr.c +++ b/palacios/src/palacios/vmm_dev_mgr.c @@ -68,7 +68,7 @@ int V3_init_devices() { while (tmp_dev != __stop__v3_devices) { - PrintDebug("Device: %s\n", tmp_dev->name); + V3_Print("Registering Device: %s\n", tmp_dev->name); if (v3_htable_search(master_dev_table, (addr_t)(tmp_dev->name))) { PrintError("Multiple instance of device (%s)\n", tmp_dev->name); diff --git a/palacios/src/palacios/vmm_halt.c b/palacios/src/palacios/vmm_halt.c index 621b68c..eca50cf 100644 --- a/palacios/src/palacios/vmm_halt.c +++ b/palacios/src/palacios/vmm_halt.c @@ -40,7 +40,7 @@ int v3_handle_halt(struct guest_info * info) { } else { PrintDebug("CPU Yield\n"); - while (!v3_intr_pending(info)) { + while (!v3_intr_pending(info) && (info->vm_info->run_state == VM_RUNNING)) { uint64_t t, cycles; /* Yield, allowing time to pass while yielded */ t = v3_get_host_time(&info->time_state); diff --git a/palacios/src/palacios/vmm_intr.c b/palacios/src/palacios/vmm_intr.c index 9010a4c..02b8fbd 100644 --- a/palacios/src/palacios/vmm_intr.c +++ b/palacios/src/palacios/vmm_intr.c @@ -274,37 +274,59 @@ int v3_lower_virq(struct guest_info * info, int irq) { int v3_lower_irq(struct v3_vm_info * vm, int irq) { + struct v3_irq irq_state; + + irq_state.irq = irq; + irq_state.ack = NULL; + irq_state.private_data = NULL; + + return v3_lower_acked_irq(vm, irq_state); +} + +int v3_raise_irq(struct v3_vm_info * vm, int irq) { + struct v3_irq irq_state; + + irq_state.irq = irq; + irq_state.ack = NULL; + irq_state.private_data = NULL; + + return v3_raise_acked_irq(vm, irq_state); +} + + +int v3_raise_acked_irq(struct v3_vm_info * vm, struct v3_irq irq) { struct intr_router * router = NULL; struct v3_intr_routers * routers = &(vm->intr_routers); - // PrintDebug("[v3_lower_irq]\n"); + // PrintDebug("[v3_raise_irq (%d)]\n", irq); addr_t irq_state = v3_lock_irqsave(routers->irq_lock); list_for_each_entry(router, &(routers->router_list), router_node) { - router->router_ops->lower_intr(vm, router->priv_data, irq); + router->router_ops->raise_intr(vm, router->priv_data, &irq); } - + v3_unlock_irqrestore(routers->irq_lock, irq_state); return 0; } -int v3_raise_irq(struct v3_vm_info * vm, int irq) { + +int v3_lower_acked_irq(struct v3_vm_info * vm, struct v3_irq irq) { struct intr_router * router = NULL; struct v3_intr_routers * routers = &(vm->intr_routers); - // PrintDebug("[v3_raise_irq (%d)]\n", irq); + // PrintDebug("[v3_lower_irq]\n"); addr_t irq_state = v3_lock_irqsave(routers->irq_lock); list_for_each_entry(router, &(routers->router_list), router_node) { - router->router_ops->raise_intr(vm, router->priv_data, irq); + router->router_ops->lower_intr(vm, router->priv_data, &irq); } - + v3_unlock_irqrestore(routers->irq_lock, irq_state); return 0; -} +} @@ -325,7 +347,15 @@ v3_intr_type_t v3_intr_pending(struct guest_info * info) { // PrintDebug("[intr_pending]\n"); addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock); - // VIRQs have priority + // External IRQs have lowest priority + list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) { + if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data) == 1) { + ret = V3_EXTERNAL_IRQ; + break; + } + } + + // VIRQs have 2nd priority for (i = 0; i < MAX_IRQ / 8; i++) { if (intr_state->virq_map[i] != 0) { ret = V3_VIRTUAL_IRQ; @@ -333,16 +363,7 @@ v3_intr_type_t v3_intr_pending(struct guest_info * info) { } } - if (ret == V3_INVALID_INTR) { - list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) { - if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data) == 1) { - ret = V3_EXTERNAL_IRQ; - break; - } - } - } - - /* for swintr injection */ + /* SWINTRs have highest */ if (intr_state->swintr_posted == 1) { ret = V3_SOFTWARE_INTR; } diff --git a/palacios/src/palacios/vmm_shadow_paging.c b/palacios/src/palacios/vmm_shadow_paging.c index f57ddda..d3e4c93 100644 --- a/palacios/src/palacios/vmm_shadow_paging.c +++ b/palacios/src/palacios/vmm_shadow_paging.c @@ -197,6 +197,11 @@ int v3_init_shdw_impl(struct v3_vm_info * vm) { int v3_deinit_shdw_impl(struct v3_vm_info * vm) { struct v3_shdw_pg_impl * impl = vm->shdw_impl.current_impl; + if (impl == NULL) { + // Shadow paging not implemented + return 0; + } + if (impl->deinit(vm) == -1) { PrintError("Error deinitializing shadow paging implementation\n"); return -1;