diff options
Diffstat (limited to 'include/hw/i386')
-rw-r--r-- | include/hw/i386/apic-msidef.h | 31 | ||||
-rw-r--r-- | include/hw/i386/apic.h | 27 | ||||
-rw-r--r-- | include/hw/i386/apic_internal.h | 231 | ||||
-rw-r--r-- | include/hw/i386/hostmem-epc.h | 28 | ||||
-rw-r--r-- | include/hw/i386/ich9.h | 256 | ||||
-rw-r--r-- | include/hw/i386/intel_iommu.h | 282 | ||||
-rw-r--r-- | include/hw/i386/ioapic.h | 33 | ||||
-rw-r--r-- | include/hw/i386/ioapic_internal.h | 118 | ||||
-rw-r--r-- | include/hw/i386/microvm.h | 116 | ||||
-rw-r--r-- | include/hw/i386/pc.h | 307 | ||||
-rw-r--r-- | include/hw/i386/sgx-epc.h | 67 | ||||
-rw-r--r-- | include/hw/i386/topology.h | 170 | ||||
-rw-r--r-- | include/hw/i386/vmport.h | 28 | ||||
-rw-r--r-- | include/hw/i386/x86-iommu.h | 163 | ||||
-rw-r--r-- | include/hw/i386/x86.h | 146 |
15 files changed, 2003 insertions, 0 deletions
diff --git a/include/hw/i386/apic-msidef.h b/include/hw/i386/apic-msidef.h new file mode 100644 index 000000000..420b41167 --- /dev/null +++ b/include/hw/i386/apic-msidef.h @@ -0,0 +1,31 @@ +#ifndef HW_APIC_MSIDEF_H +#define HW_APIC_MSIDEF_H + +/* + * Intel APIC constants: from include/asm/msidef.h + */ + +/* + * Shifts for MSI data + */ + +#define MSI_DATA_VECTOR_SHIFT 0 +#define MSI_DATA_VECTOR_MASK 0x000000ff + +#define MSI_DATA_DELIVERY_MODE_SHIFT 8 +#define MSI_DATA_LEVEL_SHIFT 14 +#define MSI_DATA_TRIGGER_SHIFT 15 + +/* + * Shift/mask fields for msi address + */ + +#define MSI_ADDR_DEST_MODE_SHIFT 2 + +#define MSI_ADDR_REDIRECTION_SHIFT 3 + +#define MSI_ADDR_DEST_ID_SHIFT 12 +#define MSI_ADDR_DEST_IDX_SHIFT 4 +#define MSI_ADDR_DEST_ID_MASK 0x000ff000 + +#endif /* HW_APIC_MSIDEF_H */ diff --git a/include/hw/i386/apic.h b/include/hw/i386/apic.h new file mode 100644 index 000000000..da1d2fe15 --- /dev/null +++ b/include/hw/i386/apic.h @@ -0,0 +1,27 @@ +#ifndef APIC_H +#define APIC_H + + +/* apic.c */ +void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, + uint8_t vector_num, uint8_t trigger_mode); +int apic_accept_pic_intr(DeviceState *s); +void apic_deliver_pic_intr(DeviceState *s, int level); +void apic_deliver_nmi(DeviceState *d); +int apic_get_interrupt(DeviceState *s); +void apic_reset_irq_delivered(void); +int apic_get_irq_delivered(void); +void cpu_set_apic_base(DeviceState *s, uint64_t val); +uint64_t cpu_get_apic_base(DeviceState *s); +void cpu_set_apic_tpr(DeviceState *s, uint8_t val); +uint8_t cpu_get_apic_tpr(DeviceState *s); +void apic_init_reset(DeviceState *s); +void apic_sipi(DeviceState *s); +void apic_poll_irq(DeviceState *d); +void apic_designate_bsp(DeviceState *d, bool bsp); +int apic_get_highest_priority_irr(DeviceState *dev); + +/* pc.c */ +DeviceState *cpu_get_current_apic(void); + +#endif diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h new file mode 100644 index 000000000..c175e7e71 --- /dev/null +++ b/include/hw/i386/apic_internal.h @@ -0,0 +1,231 @@ +/* + * APIC support - internal interfaces + * + * Copyright (c) 2004-2005 Fabrice Bellard + * Copyright (c) 2011 Jan Kiszka, Siemens AG + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/> + */ + +#ifndef QEMU_APIC_INTERNAL_H +#define QEMU_APIC_INTERNAL_H + +#include "cpu.h" +#include "exec/memory.h" +#include "qemu/timer.h" +#include "target/i386/cpu-qom.h" +#include "qom/object.h" + +/* APIC Local Vector Table */ +#define APIC_LVT_TIMER 0 +#define APIC_LVT_THERMAL 1 +#define APIC_LVT_PERFORM 2 +#define APIC_LVT_LINT0 3 +#define APIC_LVT_LINT1 4 +#define APIC_LVT_ERROR 5 +#define APIC_LVT_NB 6 + +/* APIC delivery modes */ +#define APIC_DM_FIXED 0 +#define APIC_DM_LOWPRI 1 +#define APIC_DM_SMI 2 +#define APIC_DM_NMI 4 +#define APIC_DM_INIT 5 +#define APIC_DM_SIPI 6 +#define APIC_DM_EXTINT 7 + +/* APIC destination mode */ +#define APIC_DESTMODE_FLAT 0xf +#define APIC_DESTMODE_CLUSTER 1 + +#define APIC_TRIGGER_EDGE 0 +#define APIC_TRIGGER_LEVEL 1 + +#define APIC_VECTOR_MASK 0xff +#define APIC_DCR_MASK 0xf + +#define APIC_LVT_TIMER_SHIFT 17 +#define APIC_LVT_MASKED_SHIFT 16 +#define APIC_LVT_LEVEL_TRIGGER_SHIFT 15 +#define APIC_LVT_REMOTE_IRR_SHIFT 14 +#define APIC_LVT_INT_POLARITY_SHIFT 13 +#define APIC_LVT_DELIV_STS_SHIFT 12 +#define APIC_LVT_DELIV_MOD_SHIFT 8 + +#define APIC_LVT_TIMER_TSCDEADLINE (2 << APIC_LVT_TIMER_SHIFT) +#define APIC_LVT_TIMER_PERIODIC (1 << APIC_LVT_TIMER_SHIFT) +#define APIC_LVT_MASKED (1 << APIC_LVT_MASKED_SHIFT) +#define APIC_LVT_LEVEL_TRIGGER (1 << APIC_LVT_LEVEL_TRIGGER_SHIFT) +#define APIC_LVT_REMOTE_IRR (1 << APIC_LVT_REMOTE_IRR_SHIFT) +#define APIC_LVT_INT_POLARITY (1 << APIC_LVT_INT_POLARITY_SHIFT) +#define APIC_LVT_DELIV_STS (1 << APIC_LVT_DELIV_STS_SHIFT) +#define APIC_LVT_DELIV_MOD (7 << APIC_LVT_DELIV_MOD_SHIFT) + +#define APIC_ESR_ILL_ADDRESS_SHIFT 7 +#define APIC_ESR_RECV_ILL_VECT_SHIFT 6 +#define APIC_ESR_SEND_ILL_VECT_SHIFT 5 +#define APIC_ESR_RECV_ACCEPT_SHIFT 3 +#define APIC_ESR_SEND_ACCEPT_SHIFT 2 +#define APIC_ESR_RECV_CHECK_SUM_SHIFT 1 + +#define APIC_ESR_ILLEGAL_ADDRESS (1 << APIC_ESR_ILL_ADDRESS_SHIFT) +#define APIC_ESR_RECV_ILLEGAL_VECT (1 << APIC_ESR_RECV_ILL_VECT_SHIFT) +#define APIC_ESR_SEND_ILLEGAL_VECT (1 << APIC_ESR_SEND_ILL_VECT_SHIFT) +#define APIC_ESR_RECV_ACCEPT (1 << APIC_ESR_RECV_ACCEPT_SHIFT) +#define APIC_ESR_SEND_ACCEPT (1 << APIC_ESR_SEND_ACCEPT_SHIFT) +#define APIC_ESR_RECV_CHECK_SUM (1 << APIC_ESR_RECV_CHECK_SUM_SHIFT) +#define APIC_ESR_SEND_CHECK_SUM 1 + +#define APIC_ICR_DEST_SHIFT 24 +#define APIC_ICR_DEST_SHORT_SHIFT 18 +#define APIC_ICR_TRIGGER_MOD_SHIFT 15 +#define APIC_ICR_LEVEL_SHIFT 14 +#define APIC_ICR_DELIV_STS_SHIFT 12 +#define APIC_ICR_DEST_MOD_SHIFT 11 +#define APIC_ICR_DELIV_MOD_SHIFT 8 + +#define APIC_ICR_DEST_SHORT (3 << APIC_ICR_DEST_SHORT_SHIFT) +#define APIC_ICR_TRIGGER_MOD (1 << APIC_ICR_TRIGGER_MOD_SHIFT) +#define APIC_ICR_LEVEL (1 << APIC_ICR_LEVEL_SHIFT) +#define APIC_ICR_DELIV_STS (1 << APIC_ICR_DELIV_STS_SHIFT) +#define APIC_ICR_DEST_MOD (1 << APIC_ICR_DEST_MOD_SHIFT) +#define APIC_ICR_DELIV_MOD (7 << APIC_ICR_DELIV_MOD_SHIFT) + +#define APIC_PR_CLASS_SHIFT 4 +#define APIC_PR_SUB_CLASS 0xf + +#define APIC_LOGDEST_XAPIC_SHIFT 4 +#define APIC_LOGDEST_XAPIC_ID 0xf + +#define APIC_LOGDEST_X2APIC_SHIFT 16 +#define APIC_LOGDEST_X2APIC_ID 0xffff + +#define APIC_SPURIO_FOCUS_SHIFT 9 +#define APIC_SPURIO_ENABLED_SHIFT 8 + +#define APIC_SPURIO_FOCUS (1 << APIC_SPURIO_FOCUS_SHIFT) +#define APIC_SPURIO_ENABLED (1 << APIC_SPURIO_ENABLED_SHIFT) + +#define APIC_SV_DIRECTED_IO (1 << 12) +#define APIC_SV_ENABLE (1 << 8) + +#define VAPIC_ENABLE_BIT 0 +#define VAPIC_ENABLE_MASK (1 << VAPIC_ENABLE_BIT) + +typedef struct APICCommonState APICCommonState; + +#define TYPE_APIC_COMMON "apic-common" +typedef struct APICCommonClass APICCommonClass; +DECLARE_OBJ_CHECKERS(APICCommonState, APICCommonClass, + APIC_COMMON, TYPE_APIC_COMMON) + +struct APICCommonClass { + DeviceClass parent_class; + + DeviceRealize realize; + DeviceUnrealize unrealize; + void (*set_base)(APICCommonState *s, uint64_t val); + void (*set_tpr)(APICCommonState *s, uint8_t val); + uint8_t (*get_tpr)(APICCommonState *s); + void (*enable_tpr_reporting)(APICCommonState *s, bool enable); + void (*vapic_base_update)(APICCommonState *s); + void (*external_nmi)(APICCommonState *s); + void (*pre_save)(APICCommonState *s); + void (*post_load)(APICCommonState *s); + void (*reset)(APICCommonState *s); + /* send_msi emulates an APIC bus and its proper place would be in a new + * device, but it's convenient to have it here for now. + */ + void (*send_msi)(MSIMessage *msi); +}; + +struct APICCommonState { + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + + MemoryRegion io_memory; + X86CPU *cpu; + uint32_t apicbase; + uint8_t id; /* legacy APIC ID */ + uint32_t initial_apic_id; + uint8_t version; + uint8_t arb_id; + uint8_t tpr; + uint32_t spurious_vec; + uint8_t log_dest; + uint8_t dest_mode; + uint32_t isr[8]; /* in service register */ + uint32_t tmr[8]; /* trigger mode register */ + uint32_t irr[8]; /* interrupt request register */ + uint32_t lvt[APIC_LVT_NB]; + uint32_t esr; /* error register */ + uint32_t icr[2]; + + uint32_t divide_conf; + int count_shift; + uint32_t initial_count; + int64_t initial_count_load_time; + int64_t next_time; + QEMUTimer *timer; + int64_t timer_expiry; + int sipi_vector; + int wait_for_sipi; + + uint32_t vapic_control; + DeviceState *vapic; + hwaddr vapic_paddr; /* note: persistence via kvmvapic */ + bool legacy_instance_id; +}; + +typedef struct VAPICState { + uint8_t tpr; + uint8_t isr; + uint8_t zero; + uint8_t irr; + uint8_t enabled; +} QEMU_PACKED VAPICState; + +extern bool apic_report_tpr_access; + +void apic_report_irq_delivered(int delivered); +bool apic_next_timer(APICCommonState *s, int64_t current_time); +void apic_enable_tpr_access_reporting(DeviceState *d, bool enable); +void apic_enable_vapic(DeviceState *d, hwaddr paddr); + +void vapic_report_tpr_access(DeviceState *dev, CPUState *cpu, target_ulong ip, + TPRAccess access); + +int apic_get_ppr(APICCommonState *s); +uint32_t apic_get_current_count(APICCommonState *s); + +static inline void apic_set_bit(uint32_t *tab, int index) +{ + int i, mask; + i = index >> 5; + mask = 1 << (index & 0x1f); + tab[i] |= mask; +} + +static inline int apic_get_bit(uint32_t *tab, int index) +{ + int i, mask; + i = index >> 5; + mask = 1 << (index & 0x1f); + return !!(tab[i] & mask); +} + +APICCommonClass *apic_get_class(void); + +#endif /* QEMU_APIC_INTERNAL_H */ diff --git a/include/hw/i386/hostmem-epc.h b/include/hw/i386/hostmem-epc.h new file mode 100644 index 000000000..846c72608 --- /dev/null +++ b/include/hw/i386/hostmem-epc.h @@ -0,0 +1,28 @@ +/* + * SGX EPC backend + * + * Copyright (C) 2019 Intel Corporation + * + * Authors: + * Sean Christopherson <sean.j.christopherson@intel.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef QEMU_HOSTMEM_EPC_H +#define QEMU_HOSTMEM_EPC_H + +#include "sysemu/hostmem.h" + +#define TYPE_MEMORY_BACKEND_EPC "memory-backend-epc" + +#define MEMORY_BACKEND_EPC(obj) \ + OBJECT_CHECK(HostMemoryBackendEpc, (obj), TYPE_MEMORY_BACKEND_EPC) + +typedef struct HostMemoryBackendEpc HostMemoryBackendEpc; + +struct HostMemoryBackendEpc { + HostMemoryBackend parent_obj; +}; + +#endif diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h new file mode 100644 index 000000000..23ee8e371 --- /dev/null +++ b/include/hw/i386/ich9.h @@ -0,0 +1,256 @@ +#ifndef HW_ICH9_H +#define HW_ICH9_H + +#include "hw/isa/isa.h" +#include "hw/sysbus.h" +#include "hw/i386/pc.h" +#include "hw/isa/apm.h" +#include "hw/pci/pci.h" +#include "hw/pci/pcie_host.h" +#include "hw/pci/pci_bridge.h" +#include "hw/acpi/acpi.h" +#include "hw/acpi/ich9.h" +#include "hw/pci/pci_bus.h" +#include "qom/object.h" + +void ich9_lpc_set_irq(void *opaque, int irq_num, int level); +int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx); +PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin); +void ich9_lpc_pm_init(PCIDevice *pci_lpc, bool smm_enabled); +I2CBus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base); + +void ich9_generate_smi(void); + +#define ICH9_CC_SIZE (16 * 1024) /* 16KB. Chipset configuration registers */ + +#define TYPE_ICH9_LPC_DEVICE "ICH9-LPC" +OBJECT_DECLARE_SIMPLE_TYPE(ICH9LPCState, ICH9_LPC_DEVICE) + +struct ICH9LPCState { + /* ICH9 LPC PCI to ISA bridge */ + PCIDevice d; + + /* (pci device, intx) -> pirq + * In real chipset case, the unused slots are never used + * as ICH9 supports only D25-D31 irq routing. + * On the other hand in qemu case, any slot/function can be populated + * via command line option. + * So fallback interrupt routing for any devices in any slots is necessary. + */ + uint8_t irr[PCI_SLOT_MAX][PCI_NUM_PINS]; + + APMState apm; + ICH9LPCPMRegs pm; + uint32_t sci_level; /* track sci level */ + uint8_t sci_gsi; + + /* 2.24 Pin Straps */ + struct { + bool spkr_hi; + } pin_strap; + + /* 10.1 Chipset Configuration registers(Memory Space) + which is pointed by RCBA */ + uint8_t chip_config[ICH9_CC_SIZE]; + + /* + * 13.7.5 RST_CNT---Reset Control Register (LPC I/F---D31:F0) + * + * register contents and IO memory region + */ + uint8_t rst_cnt; + MemoryRegion rst_cnt_mem; + + /* SMI feature negotiation via fw_cfg */ + uint64_t smi_host_features; /* guest-invisible, host endian */ + uint8_t smi_host_features_le[8]; /* guest-visible, read-only, little + * endian uint64_t */ + uint8_t smi_guest_features_le[8]; /* guest-visible, read-write, little + * endian uint64_t */ + uint8_t smi_features_ok; /* guest-visible, read-only; selecting it + * triggers feature lockdown */ + uint64_t smi_negotiated_features; /* guest-invisible, host endian */ + + /* isa bus */ + ISABus *isa_bus; + MemoryRegion rcrb_mem; /* root complex register block */ + Notifier machine_ready; + + qemu_irq gsi[GSI_NUM_PINS]; +}; + +#define Q35_MASK(bit, ms_bit, ls_bit) \ +((uint##bit##_t)(((1ULL << ((ms_bit) + 1)) - 1) & ~((1ULL << ls_bit) - 1))) + +/* ICH9: Chipset Configuration Registers */ +#define ICH9_CC_ADDR_MASK (ICH9_CC_SIZE - 1) + +#define ICH9_CC +#define ICH9_CC_D28IP 0x310C +#define ICH9_CC_D28IP_SHIFT 4 +#define ICH9_CC_D28IP_MASK 0xf +#define ICH9_CC_D28IP_DEFAULT 0x00214321 +#define ICH9_CC_D31IR 0x3140 +#define ICH9_CC_D30IR 0x3142 +#define ICH9_CC_D29IR 0x3144 +#define ICH9_CC_D28IR 0x3146 +#define ICH9_CC_D27IR 0x3148 +#define ICH9_CC_D26IR 0x314C +#define ICH9_CC_D25IR 0x3150 +#define ICH9_CC_DIR_DEFAULT 0x3210 +#define ICH9_CC_D30IR_DEFAULT 0x0 +#define ICH9_CC_DIR_SHIFT 4 +#define ICH9_CC_DIR_MASK 0x7 +#define ICH9_CC_OIC 0x31FF +#define ICH9_CC_OIC_AEN 0x1 +#define ICH9_CC_GCS 0x3410 +#define ICH9_CC_GCS_DEFAULT 0x00000020 +#define ICH9_CC_GCS_NO_REBOOT (1 << 5) + +/* D28:F[0-5] */ +#define ICH9_PCIE_DEV 28 +#define ICH9_PCIE_FUNC_MAX 6 + + +/* D29:F0 USB UHCI Controller #1 */ +#define ICH9_USB_UHCI1_DEV 29 +#define ICH9_USB_UHCI1_FUNC 0 + +/* D30:F0 DMI-to-PCI bridge */ +#define ICH9_D2P_BRIDGE "ICH9 D2P BRIDGE" +#define ICH9_D2P_BRIDGE_SAVEVM_VERSION 0 + +#define ICH9_D2P_BRIDGE_DEV 30 +#define ICH9_D2P_BRIDGE_FUNC 0 + +#define ICH9_D2P_SECONDARY_DEFAULT (256 - 8) + +#define ICH9_D2P_A2_REVISION 0x92 + +/* D31:F0 LPC Processor Interface */ +#define ICH9_RST_CNT_IOPORT 0xCF9 + +/* D31:F1 LPC controller */ +#define ICH9_A2_LPC "ICH9 A2 LPC" +#define ICH9_A2_LPC_SAVEVM_VERSION 0 + +#define ICH9_LPC_DEV 31 +#define ICH9_LPC_FUNC 0 + +#define ICH9_A2_LPC_REVISION 0x2 +#define ICH9_LPC_NB_PIRQS 8 /* PCI A-H */ + +#define ICH9_LPC_PMBASE 0x40 +#define ICH9_LPC_PMBASE_BASE_ADDRESS_MASK Q35_MASK(32, 15, 7) +#define ICH9_LPC_PMBASE_RTE 0x1 +#define ICH9_LPC_PMBASE_DEFAULT 0x1 + +#define ICH9_LPC_ACPI_CTRL 0x44 +#define ICH9_LPC_ACPI_CTRL_ACPI_EN 0x80 +#define ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK Q35_MASK(8, 2, 0) +#define ICH9_LPC_ACPI_CTRL_9 0x0 +#define ICH9_LPC_ACPI_CTRL_10 0x1 +#define ICH9_LPC_ACPI_CTRL_11 0x2 +#define ICH9_LPC_ACPI_CTRL_20 0x4 +#define ICH9_LPC_ACPI_CTRL_21 0x5 +#define ICH9_LPC_ACPI_CTRL_DEFAULT 0x0 + +#define ICH9_LPC_PIRQA_ROUT 0x60 +#define ICH9_LPC_PIRQB_ROUT 0x61 +#define ICH9_LPC_PIRQC_ROUT 0x62 +#define ICH9_LPC_PIRQD_ROUT 0x63 + +#define ICH9_LPC_PIRQE_ROUT 0x68 +#define ICH9_LPC_PIRQF_ROUT 0x69 +#define ICH9_LPC_PIRQG_ROUT 0x6a +#define ICH9_LPC_PIRQH_ROUT 0x6b + +#define ICH9_LPC_PIRQ_ROUT_IRQEN 0x80 +#define ICH9_LPC_PIRQ_ROUT_MASK Q35_MASK(8, 3, 0) +#define ICH9_LPC_PIRQ_ROUT_DEFAULT 0x80 + +#define ICH9_LPC_GEN_PMCON_1 0xa0 +#define ICH9_LPC_GEN_PMCON_1_SMI_LOCK (1 << 4) +#define ICH9_LPC_GEN_PMCON_2 0xa2 +#define ICH9_LPC_GEN_PMCON_3 0xa4 +#define ICH9_LPC_GEN_PMCON_LOCK 0xa6 + +#define ICH9_LPC_RCBA 0xf0 +#define ICH9_LPC_RCBA_BA_MASK Q35_MASK(32, 31, 14) +#define ICH9_LPC_RCBA_EN 0x1 +#define ICH9_LPC_RCBA_DEFAULT 0x0 + +#define ICH9_LPC_PIC_NUM_PINS 16 +#define ICH9_LPC_IOAPIC_NUM_PINS 24 + +#define ICH9_GPIO_GSI "gsi" + +/* D31:F2 SATA Controller #1 */ +#define ICH9_SATA1_DEV 31 +#define ICH9_SATA1_FUNC 2 + +/* D31:F0 power management I/O registers + offset from the address ICH9_LPC_PMBASE */ + +/* ICH9 LPC PM I/O registers are 128 ports and 128-aligned */ +#define ICH9_PMIO_SIZE 128 +#define ICH9_PMIO_MASK (ICH9_PMIO_SIZE - 1) + +#define ICH9_PMIO_PM1_STS 0x00 +#define ICH9_PMIO_PM1_EN 0x02 +#define ICH9_PMIO_PM1_CNT 0x04 +#define ICH9_PMIO_PM1_TMR 0x08 +#define ICH9_PMIO_GPE0_STS 0x20 +#define ICH9_PMIO_GPE0_EN 0x28 +#define ICH9_PMIO_GPE0_LEN 16 +#define ICH9_PMIO_SMI_EN 0x30 +#define ICH9_PMIO_SMI_EN_APMC_EN (1 << 5) +#define ICH9_PMIO_SMI_EN_TCO_EN (1 << 13) +#define ICH9_PMIO_SMI_STS 0x34 +#define ICH9_PMIO_TCO_RLD 0x60 +#define ICH9_PMIO_TCO_LEN 32 + +/* FADT ACPI_ENABLE/ACPI_DISABLE */ +#define ICH9_APM_ACPI_ENABLE 0x2 +#define ICH9_APM_ACPI_DISABLE 0x3 + + +/* D31:F3 SMBus controller */ +#define TYPE_ICH9_SMB_DEVICE "ICH9-SMB" + +#define ICH9_A2_SMB_REVISION 0x02 +#define ICH9_SMB_PI 0x00 + +#define ICH9_SMB_SMBMBAR0 0x10 +#define ICH9_SMB_SMBMBAR1 0x14 +#define ICH9_SMB_SMBM_BAR 0 +#define ICH9_SMB_SMBM_SIZE (1 << 8) +#define ICH9_SMB_SMB_BASE 0x20 +#define ICH9_SMB_SMB_BASE_BAR 4 +#define ICH9_SMB_SMB_BASE_SIZE (1 << 5) +#define ICH9_SMB_HOSTC 0x40 +#define ICH9_SMB_HOSTC_SSRESET ((uint8_t)(1 << 3)) +#define ICH9_SMB_HOSTC_I2C_EN ((uint8_t)(1 << 2)) +#define ICH9_SMB_HOSTC_SMB_SMI_EN ((uint8_t)(1 << 1)) +#define ICH9_SMB_HOSTC_HST_EN ((uint8_t)(1 << 0)) + +/* D31:F3 SMBus I/O and memory mapped I/O registers */ +#define ICH9_SMB_DEV 31 +#define ICH9_SMB_FUNC 3 + +#define ICH9_SMB_HST_STS 0x00 +#define ICH9_SMB_HST_CNT 0x02 +#define ICH9_SMB_HST_CMD 0x03 +#define ICH9_SMB_XMIT_SLVA 0x04 +#define ICH9_SMB_HST_D0 0x05 +#define ICH9_SMB_HST_D1 0x06 +#define ICH9_SMB_HOST_BLOCK_DB 0x07 + +#define ICH9_LPC_SMI_NEGOTIATED_FEAT_PROP "x-smi-negotiated-features" + +/* bit positions used in fw_cfg SMI feature negotiation */ +#define ICH9_LPC_SMI_F_BROADCAST_BIT 0 +#define ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT 1 +#define ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT 2 + +#endif /* HW_ICH9_H */ diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h new file mode 100644 index 000000000..41783ee46 --- /dev/null +++ b/include/hw/i386/intel_iommu.h @@ -0,0 +1,282 @@ +/* + * QEMU emulation of an Intel IOMMU (VT-d) + * (DMA Remapping device) + * + * Copyright (C) 2013 Knut Omang, Oracle <knut.omang@oracle.com> + * Copyright (C) 2014 Le Tan, <tamlokveer@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INTEL_IOMMU_H +#define INTEL_IOMMU_H + +#include "hw/i386/x86-iommu.h" +#include "qemu/iova-tree.h" +#include "qom/object.h" + +#define TYPE_INTEL_IOMMU_DEVICE "intel-iommu" +OBJECT_DECLARE_SIMPLE_TYPE(IntelIOMMUState, INTEL_IOMMU_DEVICE) + +#define TYPE_INTEL_IOMMU_MEMORY_REGION "intel-iommu-iommu-memory-region" + +/* DMAR Hardware Unit Definition address (IOMMU unit) */ +#define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed90000ULL + +#define VTD_PCI_BUS_MAX 256 +#define VTD_PCI_SLOT_MAX 32 +#define VTD_PCI_FUNC_MAX 8 +#define VTD_PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) +#define VTD_PCI_FUNC(devfn) ((devfn) & 0x07) +#define VTD_SID_TO_BUS(sid) (((sid) >> 8) & 0xff) +#define VTD_SID_TO_DEVFN(sid) ((sid) & 0xff) + +#define DMAR_REG_SIZE 0x230 +#define VTD_HOST_AW_39BIT 39 +#define VTD_HOST_AW_48BIT 48 +#define VTD_HOST_ADDRESS_WIDTH VTD_HOST_AW_39BIT +#define VTD_HAW_MASK(aw) ((1ULL << (aw)) - 1) + +#define DMAR_REPORT_F_INTR (1) + +#define VTD_MSI_ADDR_HI_MASK (0xffffffff00000000ULL) +#define VTD_MSI_ADDR_HI_SHIFT (32) +#define VTD_MSI_ADDR_LO_MASK (0x00000000ffffffffULL) + +typedef struct VTDContextEntry VTDContextEntry; +typedef struct VTDContextCacheEntry VTDContextCacheEntry; +typedef struct VTDAddressSpace VTDAddressSpace; +typedef struct VTDIOTLBEntry VTDIOTLBEntry; +typedef struct VTDBus VTDBus; +typedef union VTD_IR_TableEntry VTD_IR_TableEntry; +typedef union VTD_IR_MSIAddress VTD_IR_MSIAddress; +typedef struct VTDPASIDDirEntry VTDPASIDDirEntry; +typedef struct VTDPASIDEntry VTDPASIDEntry; + +/* Context-Entry */ +struct VTDContextEntry { + union { + struct { + uint64_t lo; + uint64_t hi; + }; + struct { + uint64_t val[4]; + }; + }; +}; + +struct VTDContextCacheEntry { + /* The cache entry is obsolete if + * context_cache_gen!=IntelIOMMUState.context_cache_gen + */ + uint32_t context_cache_gen; + struct VTDContextEntry context_entry; +}; + +/* PASID Directory Entry */ +struct VTDPASIDDirEntry { + uint64_t val; +}; + +/* PASID Table Entry */ +struct VTDPASIDEntry { + uint64_t val[8]; +}; + +struct VTDAddressSpace { + PCIBus *bus; + uint8_t devfn; + AddressSpace as; + IOMMUMemoryRegion iommu; + MemoryRegion root; /* The root container of the device */ + MemoryRegion nodmar; /* The alias of shared nodmar MR */ + MemoryRegion iommu_ir; /* Interrupt region: 0xfeeXXXXX */ + IntelIOMMUState *iommu_state; + VTDContextCacheEntry context_cache_entry; + QLIST_ENTRY(VTDAddressSpace) next; + /* Superset of notifier flags that this address space has */ + IOMMUNotifierFlag notifier_flags; + IOVATree *iova_tree; /* Traces mapped IOVA ranges */ +}; + +struct VTDBus { + PCIBus* bus; /* A reference to the bus to provide translation for */ + /* A table of VTDAddressSpace objects indexed by devfn */ + VTDAddressSpace *dev_as[]; +}; + +struct VTDIOTLBEntry { + uint64_t gfn; + uint16_t domain_id; + uint64_t slpte; + uint64_t mask; + uint8_t access_flags; +}; + +/* VT-d Source-ID Qualifier types */ +enum { + VTD_SQ_FULL = 0x00, /* Full SID verification */ + VTD_SQ_IGN_3 = 0x01, /* Ignore bit 3 */ + VTD_SQ_IGN_2_3 = 0x02, /* Ignore bits 2 & 3 */ + VTD_SQ_IGN_1_3 = 0x03, /* Ignore bits 1-3 */ + VTD_SQ_MAX, +}; + +/* VT-d Source Validation Types */ +enum { + VTD_SVT_NONE = 0x00, /* No validation */ + VTD_SVT_ALL = 0x01, /* Do full validation */ + VTD_SVT_BUS = 0x02, /* Validate bus range */ + VTD_SVT_MAX, +}; + +/* Interrupt Remapping Table Entry Definition */ +union VTD_IR_TableEntry { + struct { +#ifdef HOST_WORDS_BIGENDIAN + uint32_t __reserved_1:8; /* Reserved 1 */ + uint32_t vector:8; /* Interrupt Vector */ + uint32_t irte_mode:1; /* IRTE Mode */ + uint32_t __reserved_0:3; /* Reserved 0 */ + uint32_t __avail:4; /* Available spaces for software */ + uint32_t delivery_mode:3; /* Delivery Mode */ + uint32_t trigger_mode:1; /* Trigger Mode */ + uint32_t redir_hint:1; /* Redirection Hint */ + uint32_t dest_mode:1; /* Destination Mode */ + uint32_t fault_disable:1; /* Fault Processing Disable */ + uint32_t present:1; /* Whether entry present/available */ +#else + uint32_t present:1; /* Whether entry present/available */ + uint32_t fault_disable:1; /* Fault Processing Disable */ + uint32_t dest_mode:1; /* Destination Mode */ + uint32_t redir_hint:1; /* Redirection Hint */ + uint32_t trigger_mode:1; /* Trigger Mode */ + uint32_t delivery_mode:3; /* Delivery Mode */ + uint32_t __avail:4; /* Available spaces for software */ + uint32_t __reserved_0:3; /* Reserved 0 */ + uint32_t irte_mode:1; /* IRTE Mode */ + uint32_t vector:8; /* Interrupt Vector */ + uint32_t __reserved_1:8; /* Reserved 1 */ +#endif + uint32_t dest_id; /* Destination ID */ + uint16_t source_id; /* Source-ID */ +#ifdef HOST_WORDS_BIGENDIAN + uint64_t __reserved_2:44; /* Reserved 2 */ + uint64_t sid_vtype:2; /* Source-ID Validation Type */ + uint64_t sid_q:2; /* Source-ID Qualifier */ +#else + uint64_t sid_q:2; /* Source-ID Qualifier */ + uint64_t sid_vtype:2; /* Source-ID Validation Type */ + uint64_t __reserved_2:44; /* Reserved 2 */ +#endif + } QEMU_PACKED irte; + uint64_t data[2]; +}; + +#define VTD_IR_INT_FORMAT_COMPAT (0) /* Compatible Interrupt */ +#define VTD_IR_INT_FORMAT_REMAP (1) /* Remappable Interrupt */ + +/* Programming format for MSI/MSI-X addresses */ +union VTD_IR_MSIAddress { + struct { +#ifdef HOST_WORDS_BIGENDIAN + uint32_t __head:12; /* Should always be: 0x0fee */ + uint32_t index_l:15; /* Interrupt index bit 14-0 */ + uint32_t int_mode:1; /* Interrupt format */ + uint32_t sub_valid:1; /* SHV: Sub-Handle Valid bit */ + uint32_t index_h:1; /* Interrupt index bit 15 */ + uint32_t __not_care:2; +#else + uint32_t __not_care:2; + uint32_t index_h:1; /* Interrupt index bit 15 */ + uint32_t sub_valid:1; /* SHV: Sub-Handle Valid bit */ + uint32_t int_mode:1; /* Interrupt format */ + uint32_t index_l:15; /* Interrupt index bit 14-0 */ + uint32_t __head:12; /* Should always be: 0x0fee */ +#endif + } QEMU_PACKED addr; + uint32_t data; +}; + +/* When IR is enabled, all MSI/MSI-X data bits should be zero */ +#define VTD_IR_MSI_DATA (0) + +/* The iommu (DMAR) device state struct */ +struct IntelIOMMUState { + X86IOMMUState x86_iommu; + MemoryRegion csrmem; + MemoryRegion mr_nodmar; + MemoryRegion mr_ir; + MemoryRegion mr_sys_alias; + uint8_t csr[DMAR_REG_SIZE]; /* register values */ + uint8_t wmask[DMAR_REG_SIZE]; /* R/W bytes */ + uint8_t w1cmask[DMAR_REG_SIZE]; /* RW1C(Write 1 to Clear) bytes */ + uint8_t womask[DMAR_REG_SIZE]; /* WO (write only - read returns 0) */ + uint32_t version; + + bool caching_mode; /* RO - is cap CM enabled? */ + bool scalable_mode; /* RO - is Scalable Mode supported? */ + + dma_addr_t root; /* Current root table pointer */ + bool root_scalable; /* Type of root table (scalable or not) */ + bool dmar_enabled; /* Set if DMA remapping is enabled */ + + uint16_t iq_head; /* Current invalidation queue head */ + uint16_t iq_tail; /* Current invalidation queue tail */ + dma_addr_t iq; /* Current invalidation queue pointer */ + uint16_t iq_size; /* IQ Size in number of entries */ + bool iq_dw; /* IQ descriptor width 256bit or not */ + bool qi_enabled; /* Set if the QI is enabled */ + uint8_t iq_last_desc_type; /* The type of last completed descriptor */ + + /* The index of the Fault Recording Register to be used next. + * Wraps around from N-1 to 0, where N is the number of FRCD_REG. + */ + uint16_t next_frcd_reg; + + uint64_t cap; /* The value of capability reg */ + uint64_t ecap; /* The value of extended capability reg */ + + uint32_t context_cache_gen; /* Should be in [1,MAX] */ + GHashTable *iotlb; /* IOTLB */ + + GHashTable *vtd_as_by_busptr; /* VTDBus objects indexed by PCIBus* reference */ + VTDBus *vtd_as_by_bus_num[VTD_PCI_BUS_MAX]; /* VTDBus objects indexed by bus number */ + /* list of registered notifiers */ + QLIST_HEAD(, VTDAddressSpace) vtd_as_with_notifiers; + + /* interrupt remapping */ + bool intr_enabled; /* Whether guest enabled IR */ + dma_addr_t intr_root; /* Interrupt remapping table pointer */ + uint32_t intr_size; /* Number of IR table entries */ + bool intr_eime; /* Extended interrupt mode enabled */ + OnOffAuto intr_eim; /* Toggle for EIM cabability */ + bool buggy_eim; /* Force buggy EIM unless eim=off */ + uint8_t aw_bits; /* Host/IOVA address width (in bits) */ + bool dma_drain; /* Whether DMA r/w draining enabled */ + + /* + * Protects IOMMU states in general. Currently it protects the + * per-IOMMU IOTLB cache, and context entry cache in VTDAddressSpace. + */ + QemuMutex iommu_lock; +}; + +/* Find the VTD Address space associated with the given bus pointer, + * create a new one if none exists + */ +VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn); + +#endif diff --git a/include/hw/i386/ioapic.h b/include/hw/i386/ioapic.h new file mode 100644 index 000000000..ef37b8a9f --- /dev/null +++ b/include/hw/i386/ioapic.h @@ -0,0 +1,33 @@ +/* + * ioapic.c IOAPIC emulation logic + * + * Copyright (c) 2011 Jan Kiszka, Siemens AG + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef HW_IOAPIC_H +#define HW_IOAPIC_H + +#define IOAPIC_NUM_PINS 24 +#define IO_APIC_DEFAULT_ADDRESS 0xfec00000 +#define IO_APIC_SECONDARY_ADDRESS (IO_APIC_DEFAULT_ADDRESS + 0x10000) +#define IO_APIC_SECONDARY_IRQBASE 24 /* primary 0 -> 23, secondary 24 -> 47 */ + +#define TYPE_KVM_IOAPIC "kvm-ioapic" +#define TYPE_IOAPIC "ioapic" + +void ioapic_eoi_broadcast(int vector); + +#endif /* HW_IOAPIC_H */ diff --git a/include/hw/i386/ioapic_internal.h b/include/hw/i386/ioapic_internal.h new file mode 100644 index 000000000..021e715f1 --- /dev/null +++ b/include/hw/i386/ioapic_internal.h @@ -0,0 +1,118 @@ +/* + * IOAPIC emulation logic - internal interfaces + * + * Copyright (c) 2004-2005 Fabrice Bellard + * Copyright (c) 2009 Xiantao Zhang, Intel + * Copyright (c) 2011 Jan Kiszka, Siemens AG + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QEMU_IOAPIC_INTERNAL_H +#define QEMU_IOAPIC_INTERNAL_H + +#include "exec/memory.h" +#include "hw/sysbus.h" +#include "qemu/notify.h" +#include "qom/object.h" + +#define MAX_IOAPICS 2 + +#define IOAPIC_LVT_DEST_SHIFT 56 +#define IOAPIC_LVT_DEST_IDX_SHIFT 48 +#define IOAPIC_LVT_MASKED_SHIFT 16 +#define IOAPIC_LVT_TRIGGER_MODE_SHIFT 15 +#define IOAPIC_LVT_REMOTE_IRR_SHIFT 14 +#define IOAPIC_LVT_POLARITY_SHIFT 13 +#define IOAPIC_LVT_DELIV_STATUS_SHIFT 12 +#define IOAPIC_LVT_DEST_MODE_SHIFT 11 +#define IOAPIC_LVT_DELIV_MODE_SHIFT 8 + +#define IOAPIC_LVT_MASKED (1 << IOAPIC_LVT_MASKED_SHIFT) +#define IOAPIC_LVT_TRIGGER_MODE (1 << IOAPIC_LVT_TRIGGER_MODE_SHIFT) +#define IOAPIC_LVT_REMOTE_IRR (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT) +#define IOAPIC_LVT_POLARITY (1 << IOAPIC_LVT_POLARITY_SHIFT) +#define IOAPIC_LVT_DELIV_STATUS (1 << IOAPIC_LVT_DELIV_STATUS_SHIFT) +#define IOAPIC_LVT_DEST_MODE (1 << IOAPIC_LVT_DEST_MODE_SHIFT) +#define IOAPIC_LVT_DELIV_MODE (7 << IOAPIC_LVT_DELIV_MODE_SHIFT) + +/* Bits that are read-only for IOAPIC entry */ +#define IOAPIC_RO_BITS (IOAPIC_LVT_REMOTE_IRR | \ + IOAPIC_LVT_DELIV_STATUS) +#define IOAPIC_RW_BITS (~(uint64_t)IOAPIC_RO_BITS) + +#define IOAPIC_TRIGGER_EDGE 0 +#define IOAPIC_TRIGGER_LEVEL 1 + +/*io{apic,sapic} delivery mode*/ +#define IOAPIC_DM_FIXED 0x0 +#define IOAPIC_DM_LOWEST_PRIORITY 0x1 +#define IOAPIC_DM_PMI 0x2 +#define IOAPIC_DM_NMI 0x4 +#define IOAPIC_DM_INIT 0x5 +#define IOAPIC_DM_SIPI 0x6 +#define IOAPIC_DM_EXTINT 0x7 +#define IOAPIC_DM_MASK 0x7 + +#define IOAPIC_VECTOR_MASK 0xff + +#define IOAPIC_IOREGSEL 0x00 +#define IOAPIC_IOWIN 0x10 +#define IOAPIC_EOI 0x40 + +#define IOAPIC_REG_ID 0x00 +#define IOAPIC_REG_VER 0x01 +#define IOAPIC_REG_ARB 0x02 +#define IOAPIC_REG_REDTBL_BASE 0x10 +#define IOAPIC_ID 0x00 + +#define IOAPIC_ID_SHIFT 24 +#define IOAPIC_ID_MASK 0xf + +#define IOAPIC_VER_ENTRIES_SHIFT 16 + + +#define TYPE_IOAPIC_COMMON "ioapic-common" +OBJECT_DECLARE_TYPE(IOAPICCommonState, IOAPICCommonClass, IOAPIC_COMMON) + +struct IOAPICCommonClass { + SysBusDeviceClass parent_class; + + DeviceRealize realize; + DeviceUnrealize unrealize; + void (*pre_save)(IOAPICCommonState *s); + void (*post_load)(IOAPICCommonState *s); +}; + +struct IOAPICCommonState { + SysBusDevice busdev; + MemoryRegion io_memory; + uint8_t id; + uint8_t ioregsel; + uint32_t irr; + uint64_t ioredtbl[IOAPIC_NUM_PINS]; + Notifier machine_done; + uint8_t version; + uint64_t irq_count[IOAPIC_NUM_PINS]; + int irq_level[IOAPIC_NUM_PINS]; + int irq_eoi[IOAPIC_NUM_PINS]; + QEMUTimer *delayed_ioapic_service_timer; +}; + +void ioapic_reset_common(DeviceState *dev); + +void ioapic_print_redtbl(Monitor *mon, IOAPICCommonState *s); +void ioapic_stat_update_irq(IOAPICCommonState *s, int irq, int level); + +#endif /* QEMU_IOAPIC_INTERNAL_H */ diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h new file mode 100644 index 000000000..4d9c732d4 --- /dev/null +++ b/include/hw/i386/microvm.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2019 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef HW_I386_MICROVM_H +#define HW_I386_MICROVM_H + +#include "qemu-common.h" +#include "exec/hwaddr.h" +#include "qemu/notify.h" + +#include "hw/boards.h" +#include "hw/i386/x86.h" +#include "hw/acpi/acpi_dev_interface.h" +#include "hw/pci-host/gpex.h" +#include "qom/object.h" + +/* + * IRQ | pc | microvm (acpi=on) + * --------+------------+------------------ + * 0 | pit | + * 1 | kbd | + * 2 | cascade | + * 3 | serial 1 | + * 4 | serial 0 | serial + * 5 | - | + * 6 | floppy | + * 7 | parallel | + * 8 | rtc | rtc (rtc=on) + * 9 | acpi | acpi (ged) + * 10 | pci lnk | xhci (usb=on) + * 11 | pci lnk | + * 12 | ps2 | pcie + * 13 | fpu | pcie + * 14 | ide 0 | pcie + * 15 | ide 1 | pcie + * 16-23 | pci gsi | virtio + */ + +/* Platform virtio definitions */ +#define VIRTIO_MMIO_BASE 0xfeb00000 +#define VIRTIO_CMDLINE_MAXLEN 64 + +#define GED_MMIO_BASE 0xfea00000 +#define GED_MMIO_BASE_MEMHP (GED_MMIO_BASE + 0x100) +#define GED_MMIO_BASE_REGS (GED_MMIO_BASE + 0x200) +#define GED_MMIO_IRQ 9 + +#define MICROVM_XHCI_BASE 0xfe900000 +#define MICROVM_XHCI_IRQ 10 + +#define PCIE_MMIO_BASE 0xc0000000 +#define PCIE_MMIO_SIZE 0x20000000 +#define PCIE_ECAM_BASE 0xe0000000 +#define PCIE_ECAM_SIZE 0x10000000 + +/* Machine type options */ +#define MICROVM_MACHINE_PIT "pit" +#define MICROVM_MACHINE_PIC "pic" +#define MICROVM_MACHINE_RTC "rtc" +#define MICROVM_MACHINE_PCIE "pcie" +#define MICROVM_MACHINE_IOAPIC2 "ioapic2" +#define MICROVM_MACHINE_ISA_SERIAL "isa-serial" +#define MICROVM_MACHINE_OPTION_ROMS "x-option-roms" +#define MICROVM_MACHINE_AUTO_KERNEL_CMDLINE "auto-kernel-cmdline" + +struct MicrovmMachineClass { + X86MachineClass parent; + HotplugHandler *(*orig_hotplug_handler)(MachineState *machine, + DeviceState *dev); +}; + +struct MicrovmMachineState { + X86MachineState parent; + + /* Machine type options */ + OnOffAuto pic; + OnOffAuto pit; + OnOffAuto rtc; + OnOffAuto pcie; + OnOffAuto ioapic2; + bool isa_serial; + bool option_roms; + bool auto_kernel_cmdline; + + /* Machine state */ + uint32_t pcie_irq_base; + uint32_t virtio_irq_base; + uint32_t virtio_num_transports; + bool kernel_cmdline_fixed; + Notifier machine_done; + Notifier powerdown_req; + struct GPEXConfig gpex; + + /* device tree */ + void *fdt; + uint32_t ioapic_phandle[2]; +}; + +#define TYPE_MICROVM_MACHINE MACHINE_TYPE_NAME("microvm") +OBJECT_DECLARE_TYPE(MicrovmMachineState, MicrovmMachineClass, MICROVM_MACHINE) + +#endif diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h new file mode 100644 index 000000000..9ab39e428 --- /dev/null +++ b/include/hw/i386/pc.h @@ -0,0 +1,307 @@ +#ifndef HW_PC_H +#define HW_PC_H + +#include "qemu/notify.h" +#include "qapi/qapi-types-common.h" +#include "qemu/uuid.h" +#include "hw/boards.h" +#include "hw/block/fdc.h" +#include "hw/block/flash.h" +#include "hw/i386/x86.h" + +#include "hw/acpi/acpi_dev_interface.h" +#include "hw/hotplug.h" +#include "qom/object.h" +#include "hw/i386/sgx-epc.h" + +#define HPET_INTCAP "hpet-intcap" + +/** + * PCMachineState: + * @acpi_dev: link to ACPI PM device that performs ACPI hotplug handling + * @boot_cpus: number of present VCPUs + */ +typedef struct PCMachineState { + /*< private >*/ + X86MachineState parent_obj; + + /* <public> */ + + /* State for other subsystems/APIs: */ + Notifier machine_done; + + /* Pointers to devices and objects: */ + PCIBus *bus; + I2CBus *smbus; + PFlashCFI01 *flash[2]; + ISADevice *pcspk; + DeviceState *iommu; + + /* Configuration options: */ + uint64_t max_ram_below_4g; + OnOffAuto vmport; + + bool acpi_build_enabled; + bool smbus_enabled; + bool sata_enabled; + bool pit_enabled; + bool hpet_enabled; + bool default_bus_bypass_iommu; + uint64_t max_fw_size; + + /* ACPI Memory hotplug IO base address */ + hwaddr memhp_io_base; + + SGXEPCState sgx_epc; +} PCMachineState; + +#define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device" +#define PC_MACHINE_MAX_RAM_BELOW_4G "max-ram-below-4g" +#define PC_MACHINE_DEVMEM_REGION_SIZE "device-memory-region-size" +#define PC_MACHINE_VMPORT "vmport" +#define PC_MACHINE_SMBUS "smbus" +#define PC_MACHINE_SATA "sata" +#define PC_MACHINE_PIT "pit" +#define PC_MACHINE_MAX_FW_SIZE "max-fw-size" +/** + * PCMachineClass: + * + * Compat fields: + * + * @enforce_aligned_dimm: check that DIMM's address/size is aligned by + * backend's alignment value if provided + * @acpi_data_size: Size of the chunk of memory at the top of RAM + * for the BIOS ACPI tables and other BIOS + * datastructures. + * @gigabyte_align: Make sure that guest addresses aligned at + * 1Gbyte boundaries get mapped to host + * addresses aligned at 1Gbyte boundaries. This + * way we can use 1GByte pages in the host. + * + */ +struct PCMachineClass { + /*< private >*/ + X86MachineClass parent_class; + + /*< public >*/ + + /* Device configuration: */ + bool pci_enabled; + bool kvmclock_enabled; + const char *default_nic_model; + + /* Compat options: */ + + /* Default CPU model version. See x86_cpu_set_default_version(). */ + int default_cpu_version; + + /* ACPI compat: */ + bool has_acpi_build; + bool rsdp_in_ram; + int legacy_acpi_table_size; + unsigned acpi_data_size; + bool do_not_add_smb_acpi; + int pci_root_uid; + + /* SMBIOS compat: */ + bool smbios_defaults; + bool smbios_legacy_mode; + bool smbios_uuid_encoded; + + /* RAM / address space compat: */ + bool gigabyte_align; + bool has_reserved_memory; + bool enforce_aligned_dimm; + bool broken_reserved_end; + + /* generate legacy CPU hotplug AML */ + bool legacy_cpu_hotplug; + + /* use PVH to load kernels that support this feature */ + bool pvh_enabled; + + /* create kvmclock device even when KVM PV features are not exposed */ + bool kvmclock_create_always; +}; + +#define TYPE_PC_MACHINE "generic-pc-machine" +OBJECT_DECLARE_TYPE(PCMachineState, PCMachineClass, PC_MACHINE) + +/* ioapic.c */ + +GSIState *pc_gsi_create(qemu_irq **irqs, bool pci_enabled); + +/* pc.c */ +extern int fd_bootchk; + +void pc_acpi_smi_interrupt(void *opaque, int irq, int level); + +void pc_guest_info_init(PCMachineState *pcms); + +#define PCI_HOST_PROP_PCI_HOLE_START "pci-hole-start" +#define PCI_HOST_PROP_PCI_HOLE_END "pci-hole-end" +#define PCI_HOST_PROP_PCI_HOLE64_START "pci-hole64-start" +#define PCI_HOST_PROP_PCI_HOLE64_END "pci-hole64-end" +#define PCI_HOST_PROP_PCI_HOLE64_SIZE "pci-hole64-size" +#define PCI_HOST_BELOW_4G_MEM_SIZE "below-4g-mem-size" +#define PCI_HOST_ABOVE_4G_MEM_SIZE "above-4g-mem-size" + + +void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory, + MemoryRegion *pci_address_space); + +void xen_load_linux(PCMachineState *pcms); +void pc_memory_init(PCMachineState *pcms, + MemoryRegion *system_memory, + MemoryRegion *rom_memory, + MemoryRegion **ram_memory); +uint64_t pc_pci_hole64_start(void); +DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus); +void pc_basic_device_init(struct PCMachineState *pcms, + ISABus *isa_bus, qemu_irq *gsi, + ISADevice **rtc_state, + bool create_fdctrl, + uint32_t hpet_irqs); +void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd); +void pc_cmos_init(PCMachineState *pcms, + BusState *ide0, BusState *ide1, + ISADevice *s); +void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus); +void pc_pci_device_init(PCIBus *pci_bus); + +typedef void (*cpu_set_smm_t)(int smm, void *arg); + +void pc_i8259_create(ISABus *isa_bus, qemu_irq *i8259_irqs); + +ISADevice *pc_find_fdc0(void); + +/* port92.c */ +#define PORT92_A20_LINE "a20" + +#define TYPE_PORT92 "port92" + +/* pc_sysfw.c */ +void pc_system_flash_create(PCMachineState *pcms); +void pc_system_flash_cleanup_unused(PCMachineState *pcms); +void pc_system_firmware_init(PCMachineState *pcms, MemoryRegion *rom_memory); +bool pc_system_ovmf_table_find(const char *entry, uint8_t **data, + int *data_len); +void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size); + +/* hw/i386/acpi-common.c */ +void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, + const CPUArchIdList *apic_ids, GArray *entry, + bool force_enabled); + +/* sgx.c */ +void pc_machine_init_sgx_epc(PCMachineState *pcms); + +extern GlobalProperty pc_compat_6_1[]; +extern const size_t pc_compat_6_1_len; + +extern GlobalProperty pc_compat_6_0[]; +extern const size_t pc_compat_6_0_len; + +extern GlobalProperty pc_compat_5_2[]; +extern const size_t pc_compat_5_2_len; + +extern GlobalProperty pc_compat_5_1[]; +extern const size_t pc_compat_5_1_len; + +extern GlobalProperty pc_compat_5_0[]; +extern const size_t pc_compat_5_0_len; + +extern GlobalProperty pc_compat_4_2[]; +extern const size_t pc_compat_4_2_len; + +extern GlobalProperty pc_compat_4_1[]; +extern const size_t pc_compat_4_1_len; + +extern GlobalProperty pc_compat_4_0[]; +extern const size_t pc_compat_4_0_len; + +extern GlobalProperty pc_compat_3_1[]; +extern const size_t pc_compat_3_1_len; + +extern GlobalProperty pc_compat_3_0[]; +extern const size_t pc_compat_3_0_len; + +extern GlobalProperty pc_compat_2_12[]; +extern const size_t pc_compat_2_12_len; + +extern GlobalProperty pc_compat_2_11[]; +extern const size_t pc_compat_2_11_len; + +extern GlobalProperty pc_compat_2_10[]; +extern const size_t pc_compat_2_10_len; + +extern GlobalProperty pc_compat_2_9[]; +extern const size_t pc_compat_2_9_len; + +extern GlobalProperty pc_compat_2_8[]; +extern const size_t pc_compat_2_8_len; + +extern GlobalProperty pc_compat_2_7[]; +extern const size_t pc_compat_2_7_len; + +extern GlobalProperty pc_compat_2_6[]; +extern const size_t pc_compat_2_6_len; + +extern GlobalProperty pc_compat_2_5[]; +extern const size_t pc_compat_2_5_len; + +extern GlobalProperty pc_compat_2_4[]; +extern const size_t pc_compat_2_4_len; + +extern GlobalProperty pc_compat_2_3[]; +extern const size_t pc_compat_2_3_len; + +extern GlobalProperty pc_compat_2_2[]; +extern const size_t pc_compat_2_2_len; + +extern GlobalProperty pc_compat_2_1[]; +extern const size_t pc_compat_2_1_len; + +extern GlobalProperty pc_compat_2_0[]; +extern const size_t pc_compat_2_0_len; + +extern GlobalProperty pc_compat_1_7[]; +extern const size_t pc_compat_1_7_len; + +extern GlobalProperty pc_compat_1_6[]; +extern const size_t pc_compat_1_6_len; + +extern GlobalProperty pc_compat_1_5[]; +extern const size_t pc_compat_1_5_len; + +extern GlobalProperty pc_compat_1_4[]; +extern const size_t pc_compat_1_4_len; + +/* Helper for setting model-id for CPU models that changed model-id + * depending on QEMU versions up to QEMU 2.4. + */ +#define PC_CPU_MODEL_IDS(v) \ + { "qemu32-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\ + { "qemu64-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\ + { "athlon-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, }, + +#define DEFINE_PC_MACHINE(suffix, namestr, initfn, optsfn) \ + static void pc_machine_##suffix##_class_init(ObjectClass *oc, void *data) \ + { \ + MachineClass *mc = MACHINE_CLASS(oc); \ + optsfn(mc); \ + mc->init = initfn; \ + } \ + static const TypeInfo pc_machine_type_##suffix = { \ + .name = namestr TYPE_MACHINE_SUFFIX, \ + .parent = TYPE_PC_MACHINE, \ + .class_init = pc_machine_##suffix##_class_init, \ + }; \ + static void pc_machine_init_##suffix(void) \ + { \ + type_register(&pc_machine_type_##suffix); \ + } \ + type_init(pc_machine_init_##suffix) + +extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); +#endif diff --git a/include/hw/i386/sgx-epc.h b/include/hw/i386/sgx-epc.h new file mode 100644 index 000000000..a6a65be85 --- /dev/null +++ b/include/hw/i386/sgx-epc.h @@ -0,0 +1,67 @@ +/* + * SGX EPC device + * + * Copyright (C) 2019 Intel Corporation + * + * Authors: + * Sean Christopherson <sean.j.christopherson@intel.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef QEMU_SGX_EPC_H +#define QEMU_SGX_EPC_H + +#include "hw/i386/hostmem-epc.h" + +#define TYPE_SGX_EPC "sgx-epc" +#define SGX_EPC(obj) \ + OBJECT_CHECK(SGXEPCDevice, (obj), TYPE_SGX_EPC) +#define SGX_EPC_CLASS(oc) \ + OBJECT_CLASS_CHECK(SGXEPCDeviceClass, (oc), TYPE_SGX_EPC) +#define SGX_EPC_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SGXEPCDeviceClass, (obj), TYPE_SGX_EPC) + +#define SGX_EPC_ADDR_PROP "addr" +#define SGX_EPC_SIZE_PROP "size" +#define SGX_EPC_MEMDEV_PROP "memdev" + +/** + * SGXEPCDevice: + * @addr: starting guest physical address, where @SGXEPCDevice is mapped. + * Default value: 0, means that address is auto-allocated. + * @hostmem: host memory backend providing memory for @SGXEPCDevice + */ +typedef struct SGXEPCDevice { + /* private */ + DeviceState parent_obj; + + /* public */ + uint64_t addr; + HostMemoryBackendEpc *hostmem; +} SGXEPCDevice; + +/* + * @base: address in guest physical address space where EPC regions start + * @mr: address space container for memory devices + */ +typedef struct SGXEPCState { + uint64_t base; + uint64_t size; + + MemoryRegion mr; + + struct SGXEPCDevice **sections; + int nr_sections; +} SGXEPCState; + +bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size); + +static inline uint64_t sgx_epc_above_4g_end(SGXEPCState *sgx_epc) +{ + assert(sgx_epc != NULL && sgx_epc->base >= 0x100000000ULL); + + return sgx_epc->base + sgx_epc->size; +} + +#endif diff --git a/include/hw/i386/topology.h b/include/hw/i386/topology.h new file mode 100644 index 000000000..81573f6cf --- /dev/null +++ b/include/hw/i386/topology.h @@ -0,0 +1,170 @@ +/* + * x86 CPU topology data structures and functions + * + * Copyright (c) 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef HW_I386_TOPOLOGY_H +#define HW_I386_TOPOLOGY_H + +/* This file implements the APIC-ID-based CPU topology enumeration logic, + * documented at the following document: + * IntelĀ® 64 Architecture Processor Topology Enumeration + * http://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration/ + * + * This code should be compatible with AMD's "Extended Method" described at: + * AMD CPUID Specification (Publication #25481) + * Section 3: Multiple Core Calcuation + * as long as: + * nr_threads is set to 1; + * OFFSET_IDX is assumed to be 0; + * CPUID Fn8000_0008_ECX[ApicIdCoreIdSize[3:0]] is set to apicid_core_width(). + */ + + +#include "qemu/bitops.h" + +/* APIC IDs can be 32-bit, but beware: APIC IDs > 255 require x2APIC support + */ +typedef uint32_t apic_id_t; + +typedef struct X86CPUTopoIDs { + unsigned pkg_id; + unsigned die_id; + unsigned core_id; + unsigned smt_id; +} X86CPUTopoIDs; + +typedef struct X86CPUTopoInfo { + unsigned dies_per_pkg; + unsigned cores_per_die; + unsigned threads_per_core; +} X86CPUTopoInfo; + +/* Return the bit width needed for 'count' IDs + */ +static unsigned apicid_bitwidth_for_count(unsigned count) +{ + g_assert(count >= 1); + count -= 1; + return count ? 32 - clz32(count) : 0; +} + +/* Bit width of the SMT_ID (thread ID) field on the APIC ID + */ +static inline unsigned apicid_smt_width(X86CPUTopoInfo *topo_info) +{ + return apicid_bitwidth_for_count(topo_info->threads_per_core); +} + +/* Bit width of the Core_ID field + */ +static inline unsigned apicid_core_width(X86CPUTopoInfo *topo_info) +{ + return apicid_bitwidth_for_count(topo_info->cores_per_die); +} + +/* Bit width of the Die_ID field */ +static inline unsigned apicid_die_width(X86CPUTopoInfo *topo_info) +{ + return apicid_bitwidth_for_count(topo_info->dies_per_pkg); +} + +/* Bit offset of the Core_ID field + */ +static inline unsigned apicid_core_offset(X86CPUTopoInfo *topo_info) +{ + return apicid_smt_width(topo_info); +} + +/* Bit offset of the Die_ID field */ +static inline unsigned apicid_die_offset(X86CPUTopoInfo *topo_info) +{ + return apicid_core_offset(topo_info) + apicid_core_width(topo_info); +} + +/* Bit offset of the Pkg_ID (socket ID) field + */ +static inline unsigned apicid_pkg_offset(X86CPUTopoInfo *topo_info) +{ + return apicid_die_offset(topo_info) + apicid_die_width(topo_info); +} + +/* Make APIC ID for the CPU based on Pkg_ID, Core_ID, SMT_ID + * + * The caller must make sure core_id < nr_cores and smt_id < nr_threads. + */ +static inline apic_id_t x86_apicid_from_topo_ids(X86CPUTopoInfo *topo_info, + const X86CPUTopoIDs *topo_ids) +{ + return (topo_ids->pkg_id << apicid_pkg_offset(topo_info)) | + (topo_ids->die_id << apicid_die_offset(topo_info)) | + (topo_ids->core_id << apicid_core_offset(topo_info)) | + topo_ids->smt_id; +} + +/* Calculate thread/core/package IDs for a specific topology, + * based on (contiguous) CPU index + */ +static inline void x86_topo_ids_from_idx(X86CPUTopoInfo *topo_info, + unsigned cpu_index, + X86CPUTopoIDs *topo_ids) +{ + unsigned nr_dies = topo_info->dies_per_pkg; + unsigned nr_cores = topo_info->cores_per_die; + unsigned nr_threads = topo_info->threads_per_core; + + topo_ids->pkg_id = cpu_index / (nr_dies * nr_cores * nr_threads); + topo_ids->die_id = cpu_index / (nr_cores * nr_threads) % nr_dies; + topo_ids->core_id = cpu_index / nr_threads % nr_cores; + topo_ids->smt_id = cpu_index % nr_threads; +} + +/* Calculate thread/core/package IDs for a specific topology, + * based on APIC ID + */ +static inline void x86_topo_ids_from_apicid(apic_id_t apicid, + X86CPUTopoInfo *topo_info, + X86CPUTopoIDs *topo_ids) +{ + topo_ids->smt_id = apicid & + ~(0xFFFFFFFFUL << apicid_smt_width(topo_info)); + topo_ids->core_id = + (apicid >> apicid_core_offset(topo_info)) & + ~(0xFFFFFFFFUL << apicid_core_width(topo_info)); + topo_ids->die_id = + (apicid >> apicid_die_offset(topo_info)) & + ~(0xFFFFFFFFUL << apicid_die_width(topo_info)); + topo_ids->pkg_id = apicid >> apicid_pkg_offset(topo_info); +} + +/* Make APIC ID for the CPU 'cpu_index' + * + * 'cpu_index' is a sequential, contiguous ID for the CPU. + */ +static inline apic_id_t x86_apicid_from_cpu_idx(X86CPUTopoInfo *topo_info, + unsigned cpu_index) +{ + X86CPUTopoIDs topo_ids; + x86_topo_ids_from_idx(topo_info, cpu_index, &topo_ids); + return x86_apicid_from_topo_ids(topo_info, &topo_ids); +} + +#endif /* HW_I386_TOPOLOGY_H */ diff --git a/include/hw/i386/vmport.h b/include/hw/i386/vmport.h new file mode 100644 index 000000000..8f5e27c6f --- /dev/null +++ b/include/hw/i386/vmport.h @@ -0,0 +1,28 @@ +#ifndef HW_VMPORT_H +#define HW_VMPORT_H + +#include "hw/isa/isa.h" + +#define TYPE_VMPORT "vmport" +typedef uint32_t VMPortReadFunc(void *opaque, uint32_t address); + +typedef enum { + VMPORT_CMD_GETVERSION = 10, + VMPORT_CMD_GETBIOSUUID = 19, + VMPORT_CMD_GETRAMSIZE = 20, + VMPORT_CMD_VMMOUSE_DATA = 39, + VMPORT_CMD_VMMOUSE_STATUS = 40, + VMPORT_CMD_VMMOUSE_COMMAND = 41, + VMPORT_CMD_GETHZ = 45, + VMPORT_CMD_GET_VCPU_INFO = 68, + VMPORT_ENTRIES +} VMPortCommand; + +static inline void vmport_init(ISABus *bus) +{ + isa_create_simple(bus, TYPE_VMPORT); +} + +void vmport_register(VMPortCommand command, VMPortReadFunc *func, void *opaque); + +#endif diff --git a/include/hw/i386/x86-iommu.h b/include/hw/i386/x86-iommu.h new file mode 100644 index 000000000..5ba0c056d --- /dev/null +++ b/include/hw/i386/x86-iommu.h @@ -0,0 +1,163 @@ +/* + * Common IOMMU interface for X86 platform + * + * Copyright (C) 2016 Peter Xu, Red Hat <peterx@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef HW_I386_X86_IOMMU_H +#define HW_I386_X86_IOMMU_H + +#include "hw/sysbus.h" +#include "hw/pci/pci.h" +#include "hw/pci/msi.h" +#include "qom/object.h" + +#define TYPE_X86_IOMMU_DEVICE ("x86-iommu") +OBJECT_DECLARE_TYPE(X86IOMMUState, X86IOMMUClass, X86_IOMMU_DEVICE) + +#define X86_IOMMU_SID_INVALID (0xffff) + +typedef struct X86IOMMUIrq X86IOMMUIrq; +typedef struct X86IOMMU_MSIMessage X86IOMMU_MSIMessage; + +struct X86IOMMUClass { + SysBusDeviceClass parent; + /* Intel/AMD specific realize() hook */ + DeviceRealize realize; + /* MSI-based interrupt remapping */ + int (*int_remap)(X86IOMMUState *iommu, MSIMessage *src, + MSIMessage *dst, uint16_t sid); +}; + +/** + * iec_notify_fn - IEC (Interrupt Entry Cache) notifier hook, + * triggered when IR invalidation happens. + * @private: private data + * @global: whether this is a global IEC invalidation + * @index: IRTE index to invalidate (start from) + * @mask: invalidation mask + */ +typedef void (*iec_notify_fn)(void *private, bool global, + uint32_t index, uint32_t mask); + +struct IEC_Notifier { + iec_notify_fn iec_notify; + void *private; + QLIST_ENTRY(IEC_Notifier) list; +}; +typedef struct IEC_Notifier IEC_Notifier; + +struct X86IOMMUState { + SysBusDevice busdev; + OnOffAuto intr_supported; /* Whether vIOMMU supports IR */ + bool dt_supported; /* Whether vIOMMU supports DT */ + bool pt_supported; /* Whether vIOMMU supports pass-through */ + QLIST_HEAD(, IEC_Notifier) iec_notifiers; /* IEC notify list */ +}; + +bool x86_iommu_ir_supported(X86IOMMUState *s); + +/* Generic IRQ entry information when interrupt remapping is enabled */ +struct X86IOMMUIrq { + /* Used by both IOAPIC/MSI interrupt remapping */ + uint8_t trigger_mode; + uint8_t vector; + uint8_t delivery_mode; + uint32_t dest; + uint8_t dest_mode; + + /* only used by MSI interrupt remapping */ + uint8_t redir_hint; + uint8_t msi_addr_last_bits; +}; + +struct X86IOMMU_MSIMessage { + union { + struct { +#ifdef HOST_WORDS_BIGENDIAN + uint32_t __addr_head:12; /* 0xfee */ + uint32_t dest:8; + uint32_t __reserved:8; + uint32_t redir_hint:1; + uint32_t dest_mode:1; + uint32_t __not_used:2; +#else + uint32_t __not_used:2; + uint32_t dest_mode:1; + uint32_t redir_hint:1; + uint32_t __reserved:8; + uint32_t dest:8; + uint32_t __addr_head:12; /* 0xfee */ +#endif + uint32_t __addr_hi; + } QEMU_PACKED; + uint64_t msi_addr; + }; + union { + struct { +#ifdef HOST_WORDS_BIGENDIAN + uint16_t trigger_mode:1; + uint16_t level:1; + uint16_t __resved:3; + uint16_t delivery_mode:3; + uint16_t vector:8; +#else + uint16_t vector:8; + uint16_t delivery_mode:3; + uint16_t __resved:3; + uint16_t level:1; + uint16_t trigger_mode:1; +#endif + uint16_t __resved1; + } QEMU_PACKED; + uint32_t msi_data; + }; +}; + +/** + * x86_iommu_get_default - get default IOMMU device + * @return: pointer to default IOMMU device + */ +X86IOMMUState *x86_iommu_get_default(void); + +/** + * x86_iommu_iec_register_notifier - register IEC (Interrupt Entry + * Cache) notifiers + * @iommu: IOMMU device to register + * @fn: IEC notifier hook function + * @data: notifier private data + */ +void x86_iommu_iec_register_notifier(X86IOMMUState *iommu, + iec_notify_fn fn, void *data); + +/** + * x86_iommu_iec_notify_all - Notify IEC invalidations + * @iommu: IOMMU device that sends the notification + * @global: whether this is a global invalidation. If true, @index + * and @mask are undefined. + * @index: starting index of interrupt entry to invalidate + * @mask: index mask for the invalidation + */ +void x86_iommu_iec_notify_all(X86IOMMUState *iommu, bool global, + uint32_t index, uint32_t mask); + +/** + * x86_iommu_irq_to_msi_message - Populate one MSIMessage from X86IOMMUIrq + * @X86IOMMUIrq: The IRQ information + * @out: Output MSI message + */ +void x86_iommu_irq_to_msi_message(X86IOMMUIrq *irq, MSIMessage *out); +#endif diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h new file mode 100644 index 000000000..bb1cfb889 --- /dev/null +++ b/include/hw/i386/x86.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2019 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef HW_I386_X86_H +#define HW_I386_X86_H + +#include "qemu-common.h" +#include "exec/hwaddr.h" +#include "qemu/notify.h" + +#include "hw/i386/topology.h" +#include "hw/boards.h" +#include "hw/nmi.h" +#include "hw/isa/isa.h" +#include "hw/i386/ioapic.h" +#include "qom/object.h" + +struct X86MachineClass { + /*< private >*/ + MachineClass parent; + + /*< public >*/ + + /* TSC rate migration: */ + bool save_tsc_khz; + /* Enables contiguous-apic-ID mode */ + bool compat_apic_id_mode; + /* use DMA capable linuxboot option rom */ + bool fwcfg_dma_enabled; +}; + +struct X86MachineState { + /*< private >*/ + MachineState parent; + + /*< public >*/ + + /* Pointers to devices and objects: */ + ISADevice *rtc; + FWCfgState *fw_cfg; + qemu_irq *gsi; + DeviceState *ioapic2; + GMappedFile *initrd_mapped_file; + HotplugHandler *acpi_dev; + + /* RAM information (sizes, addresses, configuration): */ + ram_addr_t below_4g_mem_size, above_4g_mem_size; + + /* CPU and apic information: */ + bool apic_xrupt_override; + unsigned pci_irq_mask; + unsigned apic_id_limit; + uint16_t boot_cpus; + SgxEPCList *sgx_epc_list; + + OnOffAuto smm; + OnOffAuto acpi; + + char *oem_id; + char *oem_table_id; + /* + * Address space used by IOAPIC device. All IOAPIC interrupts + * will be translated to MSI messages in the address space. + */ + AddressSpace *ioapic_as; + + /* + * Ratelimit enforced on detected bus locks in guest. + * The default value of the bus_lock_ratelimit is 0 per second, + * which means no limitation on the guest's bus locks. + */ + uint64_t bus_lock_ratelimit; +}; + +#define X86_MACHINE_SMM "smm" +#define X86_MACHINE_ACPI "acpi" +#define X86_MACHINE_OEM_ID "x-oem-id" +#define X86_MACHINE_OEM_TABLE_ID "x-oem-table-id" +#define X86_MACHINE_BUS_LOCK_RATELIMIT "bus-lock-ratelimit" + +#define TYPE_X86_MACHINE MACHINE_TYPE_NAME("x86") +OBJECT_DECLARE_TYPE(X86MachineState, X86MachineClass, X86_MACHINE) + +void init_topo_info(X86CPUTopoInfo *topo_info, const X86MachineState *x86ms); + +uint32_t x86_cpu_apic_id_from_index(X86MachineState *pcms, + unsigned int cpu_index); + +void x86_cpu_new(X86MachineState *pcms, int64_t apic_id, Error **errp); +void x86_cpus_init(X86MachineState *pcms, int default_cpu_version); +CpuInstanceProperties x86_cpu_index_to_props(MachineState *ms, + unsigned cpu_index); +int64_t x86_get_default_cpu_node_id(const MachineState *ms, int idx); +const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms); +CPUArchId *x86_find_cpu_slot(MachineState *ms, uint32_t id, int *idx); +void x86_rtc_set_cpus_count(ISADevice *rtc, uint16_t cpus_count); +void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp); +void x86_cpu_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp); +void x86_cpu_unplug_request_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp); +void x86_cpu_unplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp); + +void x86_bios_rom_init(MachineState *ms, const char *default_firmware, + MemoryRegion *rom_memory, bool isapc_ram_fw); + +void x86_load_linux(X86MachineState *x86ms, + FWCfgState *fw_cfg, + int acpi_data_size, + bool pvh_enabled); + +bool x86_machine_is_smm_enabled(const X86MachineState *x86ms); +bool x86_machine_is_acpi_enabled(const X86MachineState *x86ms); + +/* Global System Interrupts */ + +#define GSI_NUM_PINS IOAPIC_NUM_PINS +#define ACPI_BUILD_PCI_IRQS ((1<<5) | (1<<9) | (1<<10) | (1<<11)) + +typedef struct GSIState { + qemu_irq i8259_irq[ISA_NUM_IRQS]; + qemu_irq ioapic_irq[IOAPIC_NUM_PINS]; + qemu_irq ioapic2_irq[IOAPIC_NUM_PINS]; +} GSIState; + +qemu_irq x86_allocate_cpu_irq(void); +void gsi_handler(void *opaque, int n, int level); +void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name); +DeviceState *ioapic_init_secondary(GSIState *gsi_state); + +#endif |