[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v1 1/1] Q35 support
--- docs/man/xl.cfg.5.pod.in | 27 ++ tools/firmware/hvmloader/Makefile | 2 +- tools/firmware/hvmloader/config.h | 6 + tools/firmware/hvmloader/hvmloader.c | 13 +- tools/firmware/hvmloader/ovmf.c | 7 +- tools/firmware/hvmloader/pci.c | 285 +++++++++---- tools/firmware/hvmloader/pci_regs.h | 6 + tools/firmware/hvmloader/seabios.c | 5 + tools/firmware/hvmloader/util.c | 130 +++++- tools/firmware/hvmloader/util.h | 10 + tools/libacpi/Makefile | 10 +- tools/libacpi/acpi2_0.h | 21 + tools/libacpi/build.c | 43 ++ tools/libacpi/dsdt_q35.asl | 578 +++++++++++++++++++++++++++ tools/libacpi/libacpi.h | 4 + tools/libs/light/libxl_dm.c | 60 ++- tools/libs/light/libxl_types.idl | 8 + tools/xl/xl_parse.c | 14 + 18 files changed, 1120 insertions(+), 109 deletions(-) create mode 100644 tools/libacpi/dsdt_q35.asl diff --git a/docs/man/xl.cfg.5.pod.in b/docs/man/xl.cfg.5.pod.in index 24ac927182..be61227313 100644 --- a/docs/man/xl.cfg.5.pod.in +++ b/docs/man/xl.cfg.5.pod.in @@ -2838,6 +2838,33 @@ you have existing guests then, depending on the nature of the guest Operating System, you may wish to force them to use the device model which they were installed with. +=item B<device_model_machine="STRING"> + +Selects which chipset the device model should emulate for this +guest. + +Valid options are: + +=over 4 + +=item B<"i440"> + +Use i440 emulation (a default setting) + +=item B<"q35"> + +Use Q35/ICH9 emulation. This enables additional features for +PCIe device passthrough + +=back + +Note that omitting device_model_machine parameter means i440 system +by default, so the default behavior doesn't change for old domain +config files. + +It is recommended to install the guest OS from scratch to avoid issues +due to the emulated platform change. + =item B<device_model_override="PATH"> Override the path to the binary to be used as the device-model running in diff --git a/tools/firmware/hvmloader/Makefile b/tools/firmware/hvmloader/Makefile index e5de1ade17..e3c8eb3ca1 100644 --- a/tools/firmware/hvmloader/Makefile +++ b/tools/firmware/hvmloader/Makefile @@ -70,7 +70,7 @@ rombios.o: roms.inc smbios.o: CFLAGS += -D__SMBIOS_DATE__="\"$(SMBIOS_REL_DATE)\"" ACPI_PATH = ../../libacpi -DSDT_FILES = dsdt_anycpu.c dsdt_15cpu.c dsdt_anycpu_qemu_xen.c +DSDT_FILES = dsdt_anycpu.c dsdt_15cpu.c dsdt_anycpu_qemu_xen.c dsdt_q35_anycpu_qemu_xen.c ACPI_OBJS = $(patsubst %.c,%.o,$(DSDT_FILES)) build.o static_tables.o $(ACPI_OBJS): CFLAGS += -iquote . -DLIBACPI_STDUTILS=\"$(CURDIR)/util.h\" CFLAGS += -I$(ACPI_PATH) diff --git a/tools/firmware/hvmloader/config.h b/tools/firmware/hvmloader/config.h index c82adf6dc5..53a3300d6e 100644 --- a/tools/firmware/hvmloader/config.h +++ b/tools/firmware/hvmloader/config.h @@ -54,6 +54,12 @@ extern uint8_t ioapic_version; #define PCI_ISA_DEVFN 0x08 /* dev 1, fn 0 */ #define PCI_ISA_IRQ_MASK 0x0c20U /* ISA IRQs 5,10,11 are PCI connected */ +#define PCI_ICH9_LPC_DEVFN 0xf8 /* dev 31, fn 0 */ +#define PCI_MCH_DEVFN 0 /* bus 0, dev 0, func 0 */ + +/* possible values are: 64, 128, 256 */ +#define PCI_MAX_MCFG_BUSES 64 + #define ACPI_TIS_HDR_ADDRESS 0xFED40F00UL diff --git a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c index c58841e5b5..ef0e66b214 100644 --- a/tools/firmware/hvmloader/hvmloader.c +++ b/tools/firmware/hvmloader/hvmloader.c @@ -259,8 +259,17 @@ static const struct bios_config *detect_bios(void) static void acpi_enable_sci(void) { uint8_t pm1a_cnt_val; + uint8_t acpi_enable_val; + +#define SMI_CMD_IOPORT 0xb2 +#define PIIX4_ACPI_ENABLE 0xf1 +#define ICH9_ACPI_ENABLE 0x02 + + if (get_pc_machine_type() == MACHINE_TYPE_Q35) + acpi_enable_val = ICH9_ACPI_ENABLE; + else + acpi_enable_val = PIIX4_ACPI_ENABLE; -#define PIIX4_SMI_CMD_IOPORT 0xb2 #define PIIX4_ACPI_ENABLE 0xf1 /* @@ -269,7 +278,7 @@ static void acpi_enable_sci(void) */ pm1a_cnt_val = inb(ACPI_PM1A_CNT_BLK_ADDRESS_V1); if ( !(pm1a_cnt_val & ACPI_PM1C_SCI_EN) ) - outb(PIIX4_SMI_CMD_IOPORT, PIIX4_ACPI_ENABLE); + outb(SMI_CMD_IOPORT, acpi_enable_val); pm1a_cnt_val = inb(ACPI_PM1A_CNT_BLK_ADDRESS_V1); BUG_ON(!(pm1a_cnt_val & ACPI_PM1C_SCI_EN)); diff --git a/tools/firmware/hvmloader/ovmf.c b/tools/firmware/hvmloader/ovmf.c index 23610a0717..3886b71431 100644 --- a/tools/firmware/hvmloader/ovmf.c +++ b/tools/firmware/hvmloader/ovmf.c @@ -121,10 +121,15 @@ static void ovmf_acpi_build_tables(void) struct acpi_config config = { .dsdt_anycpu = dsdt_anycpu_qemu_xen, .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len, - .dsdt_15cpu = NULL, + .dsdt_15cpu = NULL, .dsdt_15cpu_len = 0 }; + if (get_pc_machine_type() == MACHINE_TYPE_Q35) { + config.dsdt_anycpu = dsdt_q35_anycpu_qemu_xen; + config.dsdt_anycpu_len = dsdt_q35_anycpu_qemu_xen_len; + } + hvmloader_acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS); } diff --git a/tools/firmware/hvmloader/pci.c b/tools/firmware/hvmloader/pci.c index 257a6feb61..1137387c43 100644 --- a/tools/firmware/hvmloader/pci.c +++ b/tools/firmware/hvmloader/pci.c @@ -34,6 +34,7 @@ const uint32_t pci_mem_end = RESERVED_MEMBASE; uint64_t pci_hi_mem_start = 0, pci_hi_mem_end = 0; enum virtual_vga virtual_vga = VGA_none; +uint32_t vga_devfn = 256; unsigned long igd_opregion_pgbase = 0; /* Check if the specified range conflicts with any reserved device memory. */ @@ -75,14 +76,94 @@ static int find_next_rmrr(uint32_t base) return next_rmrr; } +#define SCI_EN_IOPORT (ACPI_PM1A_EVT_BLK_ADDRESS_V1 + 0x30) +#define GBL_SMI_EN (1 << 0) +#define APMC_EN (1 << 5) + +static void class_specific_pci_device_setup(uint16_t vendor_id, + uint16_t device_id, + uint8_t bus, uint8_t devfn) +{ + uint16_t class; + + class = pci_readw(devfn, PCI_CLASS_DEVICE); + + switch ( class ) + { + case 0x0300: + /* If emulated VGA is found, preserve it as primary VGA. */ + if ( (vendor_id == 0x1234) && (device_id == 0x1111) ) + { + vga_devfn = devfn; + virtual_vga = VGA_std; + } + else if ( (vendor_id == 0x1013) && (device_id == 0xb8) ) + { + vga_devfn = devfn; + virtual_vga = VGA_cirrus; + } + else if ( virtual_vga == VGA_none ) + { + vga_devfn = devfn; + virtual_vga = VGA_pt; + if ( vendor_id == 0x8086 ) + { + igd_opregion_pgbase = mem_hole_alloc(IGD_OPREGION_PAGES); + /* + * Write the the OpRegion offset to give the opregion + * address to the device model. The device model will trap + * and map the OpRegion at the give address. + */ + pci_writel(vga_devfn, PCI_INTEL_OPREGION, + igd_opregion_pgbase << PAGE_SHIFT); + } + } + break; + + case 0x0680: + /* PIIX4 ACPI PM. Special device with special PCI config space. */ + ASSERT((vendor_id == 0x8086) && (device_id == 0x7113)); + pci_writew(devfn, 0x20, 0x0000); /* No smb bus IO enable */ + pci_writew(devfn, 0xd2, 0x0000); /* No smb bus IO enable */ + pci_writew(devfn, 0x22, 0x0000); + pci_writew(devfn, 0x3c, 0x0009); /* Hardcoded IRQ9 */ + pci_writew(devfn, 0x3d, 0x0001); + pci_writel(devfn, 0x40, ACPI_PM1A_EVT_BLK_ADDRESS_V1 | 1); + pci_writeb(devfn, 0x80, 0x01); /* enable PM io space */ + break; + + case 0x0601: + /* LPC bridge */ + if (vendor_id == 0x8086 && device_id == 0x2918) + { + pci_writeb(devfn, 0x3c, 0x09); /* Hardcoded IRQ9 */ + pci_writeb(devfn, 0x3d, 0x01); + pci_writel(devfn, 0x40, ACPI_PM1A_EVT_BLK_ADDRESS_V1 | 1); + pci_writeb(devfn, 0x44, 0x80); /* enable PM io space */ + outl(SCI_EN_IOPORT, inl(SCI_EN_IOPORT) | GBL_SMI_EN | APMC_EN); + } + break; + + case 0x0101: + if ( vendor_id == 0x8086 ) + { + /* Intel ICHs since PIIX3: enable IDE legacy mode. */ + pci_writew(devfn, 0x40, 0x8000); /* enable IDE0 */ + pci_writew(devfn, 0x42, 0x8000); /* enable IDE1 */ + } + break; + } +} + void pci_setup(void) { - uint8_t is_64bar, using_64bar, bar64_relocate = 0; + uint8_t is_64bar, using_64bar, bar64_relocate = 0, is_mem; uint32_t devfn, bar_reg, cmd, bar_data, bar_data_upper; uint64_t base, bar_sz, bar_sz_upper, mmio_total = 0; - uint32_t vga_devfn = 256; - uint16_t class, vendor_id, device_id; + uint64_t addr_mask; + uint16_t vendor_id, device_id; unsigned int bar, pin, link, isa_irq; + int is_running_on_q35 = 0; uint8_t pci_devfn_decode_type[256] = {}; /* Resources assignable to PCI devices via BARs. */ @@ -92,10 +173,14 @@ void pci_setup(void) /* Create a list of device BARs in descending order of size. */ struct bars { - uint32_t is_64bar; uint32_t devfn; uint32_t bar_reg; uint64_t bar_sz; + uint64_t addr_mask; /* which bits of the base address can be written */ + uint32_t bar_data; /* initial value - BAR flags here */ + uint8_t is_64bar; + uint8_t is_mem; + uint8_t padding[2]; } *bars = (struct bars *)scratch_start; unsigned int i, nr_bars = 0; uint64_t mmio_hole_size = 0; @@ -137,13 +222,28 @@ void pci_setup(void) if ( s ) mmio_hole_size = strtoll(s, NULL, 0); + /* check if we are on Q35 and set the flag if it is the case */ + is_running_on_q35 = get_pc_machine_type() == MACHINE_TYPE_Q35; + /* Program PCI-ISA bridge with appropriate link routes. */ isa_irq = 0; for ( link = 0; link < 4; link++ ) { do { isa_irq = (isa_irq + 1) & 15; } while ( !(PCI_ISA_IRQ_MASK & (1U << isa_irq)) ); - pci_writeb(PCI_ISA_DEVFN, 0x60 + link, isa_irq); + + if (is_running_on_q35) + { + pci_writeb(PCI_ICH9_LPC_DEVFN, 0x60 + link, isa_irq); + + /* PIRQE..PIRQH are unused */ + pci_writeb(PCI_ICH9_LPC_DEVFN, 0x68 + link, 0x80); + } + else + { + pci_writeb(PCI_ISA_DEVFN, 0x60 + link, isa_irq); + } + printf("PCI-ISA link %u routed to IRQ%u\n", link, isa_irq); } @@ -154,66 +254,13 @@ void pci_setup(void) /* Scan the PCI bus and map resources. */ for ( devfn = 0; devfn < 256; devfn++ ) { - class = pci_readw(devfn, PCI_CLASS_DEVICE); vendor_id = pci_readw(devfn, PCI_VENDOR_ID); device_id = pci_readw(devfn, PCI_DEVICE_ID); if ( (vendor_id == 0xffff) && (device_id == 0xffff) ) continue; - ASSERT((devfn != PCI_ISA_DEVFN) || - ((vendor_id == 0x8086) && (device_id == 0x7000))); - - switch ( class ) - { - case 0x0300: - /* If emulated VGA is found, preserve it as primary VGA. */ - if ( (vendor_id == 0x1234) && (device_id == 0x1111) ) - { - vga_devfn = devfn; - virtual_vga = VGA_std; - } - else if ( (vendor_id == 0x1013) && (device_id == 0xb8) ) - { - vga_devfn = devfn; - virtual_vga = VGA_cirrus; - } - else if ( virtual_vga == VGA_none ) - { - vga_devfn = devfn; - virtual_vga = VGA_pt; - if ( vendor_id == 0x8086 ) - { - igd_opregion_pgbase = mem_hole_alloc(IGD_OPREGION_PAGES); - /* - * Write the the OpRegion offset to give the opregion - * address to the device model. The device model will trap - * and map the OpRegion at the give address. - */ - pci_writel(vga_devfn, PCI_INTEL_OPREGION, - igd_opregion_pgbase << PAGE_SHIFT); - } - } - break; - case 0x0680: - /* PIIX4 ACPI PM. Special device with special PCI config space. */ - ASSERT((vendor_id == 0x8086) && (device_id == 0x7113)); - pci_writew(devfn, 0x20, 0x0000); /* No smb bus IO enable */ - pci_writew(devfn, 0xd2, 0x0000); /* No smb bus IO enable */ - pci_writew(devfn, 0x22, 0x0000); - pci_writew(devfn, 0x3c, 0x0009); /* Hardcoded IRQ9 */ - pci_writew(devfn, 0x3d, 0x0001); - pci_writel(devfn, 0x40, ACPI_PM1A_EVT_BLK_ADDRESS_V1 | 1); - pci_writeb(devfn, 0x80, 0x01); /* enable PM io space */ - break; - case 0x0101: - if ( vendor_id == 0x8086 ) - { - /* Intel ICHs since PIIX3: enable IDE legacy mode. */ - pci_writew(devfn, 0x40, 0x8000); /* enable IDE0 */ - pci_writew(devfn, 0x42, 0x8000); /* enable IDE1 */ - } - break; - } + class_specific_pci_device_setup(vendor_id, device_id, + 0 /* virt_bus support TBD */, devfn); /* * It is recommended that BAR programming be done whilst decode @@ -238,13 +285,20 @@ void pci_setup(void) bar_reg = PCI_ROM_ADDRESS; bar_data = pci_readl(devfn, bar_reg); + + is_mem = !!(((bar_data & PCI_BASE_ADDRESS_SPACE) == + PCI_BASE_ADDRESS_SPACE_MEMORY) || + (bar_reg == PCI_ROM_ADDRESS)); + if ( bar_reg != PCI_ROM_ADDRESS ) { - is_64bar = !!((bar_data & (PCI_BASE_ADDRESS_SPACE | - PCI_BASE_ADDRESS_MEM_TYPE_MASK)) == - (PCI_BASE_ADDRESS_SPACE_MEMORY | + is_64bar = !!(is_mem && + ((bar_data & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64)); pci_writel(devfn, bar_reg, ~0); + + addr_mask = is_mem ? PCI_BASE_ADDRESS_MEM_MASK + : PCI_BASE_ADDRESS_IO_MASK; } else { @@ -252,15 +306,15 @@ void pci_setup(void) pci_writel(devfn, bar_reg, (bar_data | PCI_ROM_ADDRESS_MASK) & ~PCI_ROM_ADDRESS_ENABLE); + + addr_mask = PCI_ROM_ADDRESS_MASK; } bar_sz = pci_readl(devfn, bar_reg); pci_writel(devfn, bar_reg, bar_data); if ( bar_reg != PCI_ROM_ADDRESS ) - bar_sz &= (((bar_data & PCI_BASE_ADDRESS_SPACE) == - PCI_BASE_ADDRESS_SPACE_MEMORY) ? - PCI_BASE_ADDRESS_MEM_MASK : - (PCI_BASE_ADDRESS_IO_MASK & 0xffff)); + bar_sz &= is_mem ? PCI_BASE_ADDRESS_MEM_MASK : + (PCI_BASE_ADDRESS_IO_MASK & 0xffff); else bar_sz &= PCI_ROM_ADDRESS_MASK; if (is_64bar) { @@ -274,6 +328,9 @@ void pci_setup(void) if ( bar_sz == 0 ) continue; + /* leave only memtype/enable bits etc */ + bar_data &= ~addr_mask; + for ( i = 0; i < nr_bars; i++ ) if ( bars[i].bar_sz < bar_sz ) break; @@ -281,14 +338,15 @@ void pci_setup(void) if ( i != nr_bars ) memmove(&bars[i+1], &bars[i], (nr_bars-i) * sizeof(*bars)); - bars[i].is_64bar = is_64bar; - bars[i].devfn = devfn; - bars[i].bar_reg = bar_reg; - bars[i].bar_sz = bar_sz; + bars[i].is_64bar = is_64bar; + bars[i].is_mem = is_mem; + bars[i].devfn = devfn; + bars[i].bar_reg = bar_reg; + bars[i].bar_sz = bar_sz; + bars[i].addr_mask = addr_mask; + bars[i].bar_data = bar_data; - if ( ((bar_data & PCI_BASE_ADDRESS_SPACE) == - PCI_BASE_ADDRESS_SPACE_MEMORY) || - (bar_reg == PCI_ROM_ADDRESS) ) + if ( is_mem ) mmio_total += bar_sz; nr_bars++; @@ -304,7 +362,9 @@ void pci_setup(void) { /* This is the barber's pole mapping used by Xen. */ link = ((pin - 1) + (devfn >> 3)) & 3; - isa_irq = pci_readb(PCI_ISA_DEVFN, 0x60 + link); + isa_irq = pci_readb(is_running_on_q35 ? + PCI_ICH9_LPC_DEVFN : PCI_ISA_DEVFN, + 0x60 + link); pci_writeb(devfn, PCI_INTERRUPT_LINE, isa_irq); printf("pci dev %02x:%x INT%c->IRQ%u\n", devfn>>3, devfn&7, 'A'+pin-1, isa_irq); @@ -314,6 +374,63 @@ void pci_setup(void) pci_devfn_decode_type[devfn] = PCI_COMMAND_MASTER; } + /* + * Calculate MMCONFIG area size and squeeze it into the bars array + * for assigning a slot in the MMIO hole + */ + if (is_running_on_q35) + { + /* disable PCIEXBAR decoding for now */ + pci_writel(PCI_MCH_DEVFN, PCI_MCH_PCIEXBAR, 0); + pci_writel(PCI_MCH_DEVFN, PCI_MCH_PCIEXBAR + 4, 0); + +#define PCIEXBAR_64_BUSES (2 << 1) +#define PCIEXBAR_128_BUSES (1 << 1) +#define PCIEXBAR_256_BUSES (0 << 1) +#define PCIEXBAR_ENABLE (1 << 0) + + switch (PCI_MAX_MCFG_BUSES) + { + case 64: + bar_data = PCIEXBAR_64_BUSES | PCIEXBAR_ENABLE; + bar_sz = MB(64); + break; + + case 128: + bar_data = PCIEXBAR_128_BUSES | PCIEXBAR_ENABLE; + bar_sz = MB(128); + break; + + case 256: + bar_data = PCIEXBAR_256_BUSES | PCIEXBAR_ENABLE; + bar_sz = MB(256); + break; + + default: + /* unsupported number of buses specified */ + BUG(); + } + + addr_mask = ~(bar_sz - 1); + + for ( i = 0; i < nr_bars; i++ ) + if ( bars[i].bar_sz < bar_sz ) + break; + + if ( i != nr_bars ) + memmove(&bars[i+1], &bars[i], (nr_bars-i) * sizeof(*bars)); + + bars[i].is_mem = 1; + bars[i].devfn = PCI_MCH_DEVFN; + bars[i].bar_reg = PCI_MCH_PCIEXBAR; + bars[i].bar_sz = bar_sz; + bars[i].addr_mask = addr_mask; + bars[i].bar_data = bar_data; + + mmio_total += bar_sz; + nr_bars++; + } + if ( mmio_hole_size ) { uint64_t max_ram_below_4g = GB(4) - mmio_hole_size; @@ -448,10 +565,9 @@ void pci_setup(void) */ using_64bar = bars[i].is_64bar && bar64_relocate && (mmio_total > (mem_resource.max - mem_resource.base)); - bar_data = pci_readl(devfn, bar_reg); + bar_data = bars[i].bar_data; - if ( (bar_data & PCI_BASE_ADDRESS_SPACE) == - PCI_BASE_ADDRESS_SPACE_MEMORY ) + if ( bars[i].is_mem ) { /* Mapping high memory if PCI device is 64 bits bar */ if ( using_64bar ) { @@ -461,18 +577,15 @@ void pci_setup(void) if ( !pci_hi_mem_start ) pci_hi_mem_start = high_mem_resource.base; resource = &high_mem_resource; - bar_data &= ~PCI_BASE_ADDRESS_MEM_MASK; - } + } else { resource = &mem_resource; - bar_data &= ~PCI_BASE_ADDRESS_MEM_MASK; } mmio_total -= bar_sz; } else { resource = &io_resource; - bar_data &= ~PCI_BASE_ADDRESS_IO_MASK; } base = (resource->base + bar_sz - 1) & ~(uint64_t)(bar_sz - 1); @@ -494,7 +607,7 @@ void pci_setup(void) } } - bar_data |= (uint32_t)base; + bar_data |= (uint32_t) (base & bars[i].addr_mask); bar_data_upper = (uint32_t)(base >> 32); base += bar_sz; @@ -515,10 +628,8 @@ void pci_setup(void) devfn>>3, devfn&7, bar_reg, PRIllx_arg(bar_sz), bar_data_upper, bar_data); - - if ( (bar_reg == PCI_ROM_ADDRESS) || - ((bar_data & PCI_BASE_ADDRESS_SPACE) == - PCI_BASE_ADDRESS_SPACE_MEMORY) ) + + if ( bars[i].is_mem ) pci_devfn_decode_type[devfn] |= PCI_COMMAND_MEMORY; else pci_devfn_decode_type[devfn] |= PCI_COMMAND_IO; diff --git a/tools/firmware/hvmloader/pci_regs.h b/tools/firmware/hvmloader/pci_regs.h index 7bf2d873ab..b9261ee2af 100644 --- a/tools/firmware/hvmloader/pci_regs.h +++ b/tools/firmware/hvmloader/pci_regs.h @@ -107,6 +107,12 @@ #define PCI_INTEL_OPREGION 0xfc /* 4 bits */ +#define PCI_VENDOR_ID_INTEL 0x8086 +#define PCI_DEVICE_ID_INTEL_82441 0x1237 +#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0 + +#define PCI_MCH_PCIEXBAR 0x60 + #endif /* __HVMLOADER_PCI_REGS_H__ */ /* diff --git a/tools/firmware/hvmloader/seabios.c b/tools/firmware/hvmloader/seabios.c index 444d118ddb..72aabea130 100644 --- a/tools/firmware/hvmloader/seabios.c +++ b/tools/firmware/hvmloader/seabios.c @@ -96,6 +96,11 @@ static void seabios_acpi_build_tables(void) .dsdt_15cpu_len = 0, }; + if (get_pc_machine_type() == MACHINE_TYPE_Q35) { + config.dsdt_anycpu = dsdt_q35_anycpu_qemu_xen; + config.dsdt_anycpu_len = dsdt_q35_anycpu_qemu_xen_len; + } + hvmloader_acpi_build_tables(&config, rsdp); add_table(rsdp); } diff --git a/tools/firmware/hvmloader/util.c b/tools/firmware/hvmloader/util.c index e82047d993..7a75c07467 100644 --- a/tools/firmware/hvmloader/util.c +++ b/tools/firmware/hvmloader/util.c @@ -22,6 +22,7 @@ #include "hypercall.h" #include "ctype.h" #include "vnuma.h" +#include "pci_regs.h" #include <acpi2_0.h> #include <libacpi.h> #include <stdint.h> @@ -735,6 +736,115 @@ void __bug(const char *file, int line) crash(); } + +static int machine_type = MACHINE_TYPE_UNDEFINED; + +int get_pc_machine_type(void) +{ + uint16_t vendor_id; + uint16_t device_id; + + if (machine_type != MACHINE_TYPE_UNDEFINED) + return machine_type; + + machine_type = MACHINE_TYPE_UNKNOWN; + + vendor_id = pci_readw(0, PCI_VENDOR_ID); + device_id = pci_readw(0, PCI_DEVICE_ID); + + /* only Intel platforms are emulated currently */ + if (vendor_id == PCI_VENDOR_ID_INTEL) + { + switch (device_id) + { + case PCI_DEVICE_ID_INTEL_82441: + machine_type = MACHINE_TYPE_I440; + printf("Detected i440 chipset\n"); + break; + + case PCI_DEVICE_ID_INTEL_Q35_MCH: + machine_type = MACHINE_TYPE_Q35; + printf("Detected Q35 chipset\n"); + break; + + default: + break; + } + } + + if (machine_type == MACHINE_TYPE_UNKNOWN) + { + printf("Unknown emulated chipset encountered, VID=%04Xh, DID=%04Xh\n", + vendor_id, device_id); + BUG(); + } + + return machine_type; +} + +#define PCIEXBAR_ADDR_MASK_64MB (~((1ULL << 26) - 1)) +#define PCIEXBAR_ADDR_MASK_128MB (~((1ULL << 27) - 1)) +#define PCIEXBAR_ADDR_MASK_256MB (~((1ULL << 28) - 1)) +#define PCIEXBAR_LENGTH_BITS(reg) (((reg) >> 1) & 3) +#define PCIEXBAREN 1 + +static uint64_t mmconfig_get_base(void) +{ + uint64_t base; + uint32_t reg = pci_readl(PCI_MCH_DEVFN, PCI_MCH_PCIEXBAR); + + base = reg | (uint64_t) pci_readl(PCI_MCH_DEVFN, PCI_MCH_PCIEXBAR+4) << 32; + + switch (PCIEXBAR_LENGTH_BITS(reg)) + { + case 0: + base &= PCIEXBAR_ADDR_MASK_256MB; + break; + case 1: + base &= PCIEXBAR_ADDR_MASK_128MB; + break; + case 2: + base &= PCIEXBAR_ADDR_MASK_64MB; + break; + case 3: + BUG(); /* a reserved value encountered */ + } + + return base; +} + +static uint32_t mmconfig_get_size(void) +{ + uint32_t reg = pci_readl(PCI_MCH_DEVFN, PCI_MCH_PCIEXBAR); + + switch (PCIEXBAR_LENGTH_BITS(reg)) + { + case 0: return MB(256); + case 1: return MB(128); + case 2: return MB(64); + case 3: + BUG(); /* a reserved value encountered */ + } + + return 0; +} + +static uint32_t mmconfig_is_enabled(void) +{ + return pci_readl(PCI_MCH_DEVFN, PCI_MCH_PCIEXBAR) & PCIEXBAREN; +} + +static int is_mmconfig_used(void) +{ + if (get_pc_machine_type() == MACHINE_TYPE_Q35) + { + if (mmconfig_is_enabled() && mmconfig_get_base()) + return 1; + } + + return 0; +} + static void validate_hvm_info(struct hvm_info_table *t) { uint8_t *ptr = (uint8_t *)t; @@ -937,8 +1047,17 @@ void hvmloader_acpi_build_tables(struct acpi_config *config, } else if ( !strncmp(s, "qemu_xen", 9) ) { - config->dsdt_anycpu = dsdt_anycpu_qemu_xen; - config->dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len; + if (get_pc_machine_type() == MACHINE_TYPE_Q35) + { + config->dsdt_anycpu = dsdt_q35_anycpu_qemu_xen; + config->dsdt_anycpu_len = dsdt_q35_anycpu_qemu_xen_len; + } + else + { + config->dsdt_anycpu = dsdt_anycpu_qemu_xen; + config->dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len; + } + config->dsdt_15cpu = NULL; config->dsdt_15cpu_len = 0; } @@ -966,6 +1085,13 @@ void hvmloader_acpi_build_tables(struct acpi_config *config, config->pci_hi_len = pci_hi_mem_end - pci_hi_mem_start; } + if ( is_mmconfig_used() ) + { + config->table_flags |= ACPI_HAS_MCFG; + config->mmconfig_addr = mmconfig_get_base(); + config->mmconfig_len = mmconfig_get_size(); + } + s = xenstore_read("platform/generation-id", "0:0"); if ( s ) { diff --git a/tools/firmware/hvmloader/util.h b/tools/firmware/hvmloader/util.h index 87be213dec..c6747c336d 100644 --- a/tools/firmware/hvmloader/util.h +++ b/tools/firmware/hvmloader/util.h @@ -90,6 +90,14 @@ void pci_write(uint32_t devfn, uint32_t reg, uint32_t len, uint32_t val); #define pci_writew(devfn, reg, val) pci_write(devfn, reg, 2, (uint16_t)(val)) #define pci_writel(devfn, reg, val) pci_write(devfn, reg, 4, (uint32_t)(val)) +/* Emulated machine types */ +#define MACHINE_TYPE_UNDEFINED 0 +#define MACHINE_TYPE_I440 1 +#define MACHINE_TYPE_Q35 2 +#define MACHINE_TYPE_UNKNOWN (-1) + +int get_pc_machine_type(void); + /* Get a pointer to the shared-info page */ struct shared_info *get_shared_info(void) __attribute__ ((const)); @@ -270,7 +278,9 @@ bool check_overlap(uint64_t start, uint64_t size, uint64_t reserved_start, uint64_t reserved_size); extern const unsigned char dsdt_anycpu_qemu_xen[], dsdt_anycpu[], dsdt_15cpu[]; +extern const unsigned char dsdt_q35_anycpu_qemu_xen[]; extern const int dsdt_anycpu_qemu_xen_len, dsdt_anycpu_len, dsdt_15cpu_len; +extern const int dsdt_q35_anycpu_qemu_xen_len; unsigned long acpi_pages_allocated(void); diff --git a/tools/libacpi/Makefile b/tools/libacpi/Makefile index b21a64c6b4..d1ad2c6d85 100644 --- a/tools/libacpi/Makefile +++ b/tools/libacpi/Makefile @@ -11,7 +11,7 @@ endif MK_DSDT = $(ACPI_BUILD_DIR)/mk_dsdt -C_SRC-$(CONFIG_X86) = dsdt_anycpu.c dsdt_15cpu.c dsdt_anycpu_qemu_xen.c dsdt_pvh.c +C_SRC-$(CONFIG_X86) = dsdt_anycpu.c dsdt_15cpu.c dsdt_anycpu_qemu_xen.c dsdt_q35_anycpu_qemu_xen.c dsdt_pvh.c C_SRC-$(CONFIG_ARM_64) = dsdt_anycpu_arm.c DSDT_FILES ?= $(C_SRC-y) C_SRC = $(addprefix $(ACPI_BUILD_DIR)/, $(DSDT_FILES)) @@ -54,6 +54,14 @@ $(ACPI_BUILD_DIR)/dsdt_%cpu.asl: dsdt.asl dsdt_acpi_info.asl $(MK_DSDT) $(MK_DSDT) --debug=$(debug) --maxcpu $* >> $@.$(TMP_SUFFIX) mv -f $@.$(TMP_SUFFIX) $@ +$(ACPI_BUILD_DIR)/dsdt_q35_anycpu_qemu_xen.asl: dsdt_q35.asl dsdt_acpi_info.asl $(MK_DSDT) + # Remove last bracket + awk 'NR > 1 {print s} {s=$$0}' $< > $@.$(TMP_SUFFIX) + cat dsdt_acpi_info.asl >> $@.$(TMP_SUFFIX) + $(MK_DSDT) --debug=$(debug) --dm-version qemu-xen >> $@.$(TMP_SUFFIX) + mv -f $@.$(TMP_SUFFIX) $@ + + $(ACPI_BUILD_DIR)/dsdt_pvh.asl: dsdt_acpi_info.asl $(MK_DSDT) printf "DefinitionBlock (\"DSDT.aml\", \"DSDT\", 5, \"Xen\", \"HVM\", 0)\n{" > $@ cat dsdt_acpi_info.asl >> $@ diff --git a/tools/libacpi/acpi2_0.h b/tools/libacpi/acpi2_0.h index 6dfa939a8c..02b0cf1098 100644 --- a/tools/libacpi/acpi2_0.h +++ b/tools/libacpi/acpi2_0.h @@ -442,6 +442,24 @@ struct acpi_20_slit { uint64_t localities; uint8_t entry[0]; }; +/* + * PCI Express Memory Mapped Configuration Description Table + */ +struct mcfg_range_entry { + uint64_t base_address; + uint16_t pci_segment; + uint8_t start_pci_bus_num; + uint8_t end_pci_bus_num; + uint32_t reserved; +}; + +struct acpi_mcfg { + struct acpi_header header; + uint8_t reserved[8]; + struct mcfg_range_entry entries[1]; +}; + +#define MCFG_SIZE_TO_NUM_BUSES(size) ((size) >> 20) /* * Table Signatures. @@ -458,6 +476,8 @@ struct acpi_20_slit { #define ACPI_2_0_WAET_SIGNATURE ASCII32('W','A','E','T') #define ACPI_2_0_SRAT_SIGNATURE ASCII32('S','R','A','T') #define ACPI_2_0_SLIT_SIGNATURE ASCII32('S','L','I','T') +#define ACPI_MCFG_SIGNATURE ASCII32('M','C','F','G') + /* * Table revision numbers. @@ -473,6 +493,7 @@ struct acpi_20_slit { #define ACPI_1_0_FADT_REVISION 0x01 #define ACPI_2_0_SRAT_REVISION 0x01 #define ACPI_2_0_SLIT_REVISION 0x01 +#define ACPI_1_0_MCFG_REVISION 0x01 #pragma pack () diff --git a/tools/libacpi/build.c b/tools/libacpi/build.c index 2f29863db1..fc029d18bf 100644 --- a/tools/libacpi/build.c +++ b/tools/libacpi/build.c @@ -295,6 +295,37 @@ static struct acpi_20_slit *construct_slit(struct acpi_ctxt *ctxt, return slit; } +static struct acpi_mcfg *construct_mcfg(struct acpi_ctxt *ctxt, + const struct acpi_config *config) +{ + struct acpi_mcfg *mcfg; + + /* Warning: this code expects that we have only one PCI segment */ + mcfg = ctxt->mem_ops.alloc(ctxt, sizeof(*mcfg), 16); + if (!mcfg) + return NULL; + + memset(mcfg, 0, sizeof(*mcfg)); + mcfg->header.signature = ACPI_MCFG_SIGNATURE; + mcfg->header.revision = ACPI_1_0_MCFG_REVISION; + fixed_strcpy(mcfg->header.oem_id, ACPI_OEM_ID); + fixed_strcpy(mcfg->header.oem_table_id, ACPI_OEM_TABLE_ID); + mcfg->header.oem_revision = ACPI_OEM_REVISION; + mcfg->header.creator_id = ACPI_CREATOR_ID; + mcfg->header.creator_revision = ACPI_CREATOR_REVISION; + mcfg->header.length = sizeof(*mcfg); + + mcfg->entries[0].base_address = config->mmconfig_addr; + mcfg->entries[0].pci_segment = 0; + mcfg->entries[0].start_pci_bus_num = 0; + mcfg->entries[0].end_pci_bus_num = + MCFG_SIZE_TO_NUM_BUSES(config->mmconfig_len) - 1; + + set_checksum(mcfg, offsetof(struct acpi_header, checksum), sizeof(*mcfg)); + + return mcfg;; +} + static int construct_passthrough_tables(struct acpi_ctxt *ctxt, unsigned long *table_ptrs, int nr_tables, @@ -342,6 +373,7 @@ static int construct_secondary_tables(struct acpi_ctxt *ctxt, struct acpi_20_hpet *hpet; struct acpi_20_waet *waet; struct acpi_20_tcpa *tcpa; + struct acpi_mcfg *mcfg; struct acpi_20_tpm2 *tpm2; unsigned char *ssdt; void *lasa; @@ -402,6 +434,17 @@ static int construct_secondary_tables(struct acpi_ctxt *ctxt, memcpy(ssdt, ssdt_laptop_slate, sizeof(ssdt_laptop_slate)); table_ptrs[nr_tables++] = ctxt->mem_ops.v2p(ctxt, ssdt); } + + /* MCFG */ + if ( config->table_flags & ACPI_HAS_MCFG ) + { + mcfg = construct_mcfg(ctxt, config); + if (!mcfg) + return -1; + + table_ptrs[nr_tables++] = ctxt->mem_ops.v2p(ctxt, mcfg); + } + /* TPM and its SSDT. */ if ( config->table_flags & ACPI_HAS_TPM ) { diff --git a/tools/libacpi/dsdt_q35.asl b/tools/libacpi/dsdt_q35.asl new file mode 100644 index 0000000000..1ec32a8010 --- /dev/null +++ b/tools/libacpi/dsdt_q35.asl @@ -0,0 +1,578 @@ +/****************************************************************************** + * DSDT for Xen with Qemu device model (for Q35 machine) + * + * Copyright (c) 2004, Intel Corporation. + * + * This program 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; version 2.1 only. with the special + * exception on linking described in file LICENSE. + * + * 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 Lesser General Public License for more details. + */ + +DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0) +{ + Name (\PMBS, 0x0C00) + Name (\PMLN, 0x08) + Name (\IOB1, 0x00) + Name (\IOL1, 0x00) + Name (\APCB, 0xFEC00000) + Name (\APCL, 0x00010000) + Name (\PUID, 0x00) + + + Scope (\_SB) + { + + /* Fix HCT test for 0x400 pci memory: + * - need to report low 640 MB mem as motherboard resource + */ + Device(MEM0) + { + Name(_HID, EISAID("PNP0C02")) + Name(_CRS, ResourceTemplate() { + QWordMemory( + ResourceConsumer, PosDecode, MinFixed, + MaxFixed, Cacheable, ReadWrite, + 0x00000000, + 0x00000000, + 0x0009ffff, + 0x00000000, + 0x000a0000) + }) + } + + Device (PCI0) + { + Name (_HID, EisaId ("PNP0A08")) + Name(_CID, EisaId("PNP0A03")) + Name (_UID, 0x00) + Name (_ADR, 0x00) + Name (_BBN, 0x00) + + /* _OSC, modified from ASL sample in ACPI spec */ + Name(SUPP, 0) /* PCI _OSC Support Field value */ + Name(CTRL, 0) /* PCI _OSC Control Field value */ + Method(_OSC, 4) { + /* Create DWORD-addressable fields from the Capabilities Buffer */ + CreateDWordField(Arg3, 0, CDW1) + + /* Switch by UUID. + * Only PCI Host Bridge Device capabilities UUID used for now + */ + If (LEqual(Arg0, ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766"))) { + /* Create DWORD-addressable fields from the Capabilities Buffer */ + CreateDWordField(Arg3, 4, CDW2) + CreateDWordField(Arg3, 8, CDW3) + + /* Save Capabilities DWORD2 & 3 */ + Store(CDW2, SUPP) + Store(CDW3, CTRL) + + /* Validate Revision DWORD */ + If (LNotEqual(Arg1, One)) { + /* Unknown revision */ + /* Support and Control DWORDs will be returned anyway */ + Or(CDW1, 0x08, CDW1) + } + + /* Control field bits are: + * bit 0 PCI Express Native Hot Plug control + * bit 1 SHPC Native Hot Plug control + * bit 2 PCI Express Native Power Management Events control + * bit 3 PCI Express Advanced Error Reporting control + * bit 4 PCI Express Capability Structure control + */ + + /* Always allow native PME, AER (no dependencies) + * Never allow SHPC (no SHPC controller in this system) + * Do not allow PCIe Capability Structure control for now + * Also, ACPI hotplug is used for now instead of PCIe + * Native Hot Plug + */ + And(CTRL, 0x0C, CTRL) + + If (LNotEqual(CDW3, CTRL)) { + /* Some of Capabilities bits were masked */ + Or(CDW1, 0x10, CDW1) + } + /* Update DWORD3 in the buffer */ + Store(CTRL, CDW3) + } Else { + Or(CDW1, 4, CDW1) /* Unrecognized UUID */ + } + Return (Arg3) + } + /* end of _OSC */ + + + /* Make cirrues VGA S3 suspend/resume work in Windows XP/2003 */ + Device (VGA) + { + Name (_ADR, 0x00020000) + + Method (_S1D, 0, NotSerialized) + { + Return (0x00) + } + Method (_S2D, 0, NotSerialized) + { + Return (0x00) + } + Method (_S3D, 0, NotSerialized) + { + Return (0x00) + } + } + + Method (_CRS, 0, NotSerialized) + { + Store (ResourceTemplate () + { + /* bus number is from 0 - 255*/ + WordBusNumber( + ResourceProducer, MinFixed, MaxFixed, SubDecode, + 0x0000, + 0x0000, + 0x00FF, + 0x0000, + 0x0100) + IO (Decode16, 0x0CF8, 0x0CF8, 0x01, 0x08) + WordIO( + ResourceProducer, MinFixed, MaxFixed, PosDecode, + EntireRange, + 0x0000, + 0x0000, + 0x0CF7, + 0x0000, + 0x0CF8) + WordIO( + ResourceProducer, MinFixed, MaxFixed, PosDecode, + EntireRange, + 0x0000, + 0x0D00, + 0xFFFF, + 0x0000, + 0xF300) + + /* reserve memory for pci devices */ + DWordMemory( + ResourceProducer, PosDecode, MinFixed, MaxFixed, + WriteCombining, ReadWrite, + 0x00000000, + 0x000A0000, + 0x000BFFFF, + 0x00000000, + 0x00020000) + + DWordMemory( + ResourceProducer, PosDecode, MinFixed, MaxFixed, + NonCacheable, ReadWrite, + 0x00000000, + 0xF0000000, + 0xF4FFFFFF, + 0x00000000, + 0x05000000, + ,, _Y01) + + QWordMemory ( + ResourceProducer, PosDecode, MinFixed, MaxFixed, + NonCacheable, ReadWrite, + 0x0000000000000000, + 0x0000000FFFFFFFF0, + 0x0000000FFFFFFFFF, + 0x0000000000000000, + 0x0000000000000010, + ,, _Y02) + + }, Local1) + + CreateDWordField(Local1, \_SB.PCI0._CRS._Y01._MIN, MMIN) + CreateDWordField(Local1, \_SB.PCI0._CRS._Y01._MAX, MMAX) + CreateDWordField(Local1, \_SB.PCI0._CRS._Y01._LEN, MLEN) + + Store(\_SB.PMIN, MMIN) + Store(\_SB.PLEN, MLEN) + Add(MMIN, MLEN, MMAX) + Subtract(MMAX, One, MMAX) + + /* + * WinXP / Win2K3 blue-screen for operations on 64-bit values. + * Therefore we need to split the 64-bit calculations needed + * here, but different iasl versions evaluate name references + * to integers differently: + * Year (approximate) 2006 2008 2012 + * \_SB.PCI0._CRS._Y02 zero valid valid + * \_SB.PCI0._CRS._Y02._MIN valid valid huge + */ + If(LEqual(Zero, \_SB.PCI0._CRS._Y02)) { + Subtract(\_SB.PCI0._CRS._Y02._MIN, 14, Local0) + } Else { + Store(\_SB.PCI0._CRS._Y02, Local0) + } + CreateDWordField(Local1, Add(Local0, 14), MINL) + CreateDWordField(Local1, Add(Local0, 18), MINH) + CreateDWordField(Local1, Add(Local0, 22), MAXL) + CreateDWordField(Local1, Add(Local0, 26), MAXH) + CreateDWordField(Local1, Add(Local0, 38), LENL) + CreateDWordField(Local1, Add(Local0, 42), LENH) + + Store(\_SB.LMIN, MINL) + Store(\_SB.HMIN, MINH) + Store(\_SB.LLEN, LENL) + Store(\_SB.HLEN, LENH) + Add(MINL, LENL, MAXL) + Add(MINH, LENH, MAXH) + If(LLess(MAXL, MINL)) { + Add(MAXH, One, MAXH) + } + If(LOr(MINH, LENL)) { + If(LEqual(MAXL, 0)) { + Subtract(MAXH, One, MAXH) + } + Subtract(MAXL, One, MAXL) + } + + Return (Local1) + } + + Device(HPET) { + Name(_HID, EISAID("PNP0103")) + Name(_UID, 0) + Method (_STA, 0, NotSerialized) { + If(LEqual(\_SB.HPET, 0)) { + Return(0x00) + } Else { + Return(0x0F) + } + } + Name(_CRS, ResourceTemplate() { + DWordMemory( + ResourceConsumer, PosDecode, MinFixed, MaxFixed, + NonCacheable, ReadWrite, + 0x00000000, + 0xFED00000, + 0xFED003FF, + 0x00000000, + 0x00000400 /* 1K memory: FED00000 - FED003FF */ + ) + }) + } + + + /**************************************************************** + * LPC ISA bridge + ****************************************************************/ + + Device (ISA) + { + Name (_ADR, 0x001f0000) /* device 31, fn 0 */ + + /* PCI Interrupt Routing Register 1 - PIRQA..PIRQD */ + OperationRegion(PIRQ, PCI_Config, 0x60, 0x4) + Scope(\) { + Field (\_SB.PCI0.ISA.PIRQ, ByteAcc, NoLock, Preserve) { + PIRA, 8, + PIRB, 8, + PIRC, 8, + PIRD, 8 + } + } + /* + PCI Interrupt Routing Register 2 (PIRQE..PIRQH) cannot be + used because of existing Xen IRQ limitations (4 PCI links + only) + */ + + /* LPC_I/O: I/O Decode Ranges Register */ + OperationRegion(LPCD, PCI_Config, 0x80, 0x2) + Field(LPCD, AnyAcc, NoLock, Preserve) { + COMA, 3, + , 1, + COMB, 3, + + Offset(0x01), + LPTD, 2, + , 2, + FDCD, 2 + } + + /* LPC_EN: LPC I/F Enables Register */ + OperationRegion(LPCE, PCI_Config, 0x82, 0x2) + Field(LPCE, AnyAcc, NoLock, Preserve) { + CAEN, 1, + CBEN, 1, + LPEN, 1, + FDEN, 1 + } + + Device (SYSR) + { + Name (_HID, EisaId ("PNP0C02")) + Name (_UID, 0x01) + Name (CRS, ResourceTemplate () + { + /* TODO: list hidden resources */ + IO (Decode16, 0x0010, 0x0010, 0x00, 0x10) + IO (Decode16, 0x0022, 0x0022, 0x00, 0x0C) + IO (Decode16, 0x0030, 0x0030, 0x00, 0x10) + IO (Decode16, 0x0044, 0x0044, 0x00, 0x1C) + IO (Decode16, 0x0062, 0x0062, 0x00, 0x02) + IO (Decode16, 0x0065, 0x0065, 0x00, 0x0B) + IO (Decode16, 0x0072, 0x0072, 0x00, 0x0E) + IO (Decode16, 0x0080, 0x0080, 0x00, 0x01) + IO (Decode16, 0x0084, 0x0084, 0x00, 0x03) + IO (Decode16, 0x0088, 0x0088, 0x00, 0x01) + IO (Decode16, 0x008C, 0x008C, 0x00, 0x03) + IO (Decode16, 0x0090, 0x0090, 0x00, 0x10) + IO (Decode16, 0x00A2, 0x00A2, 0x00, 0x1C) + IO (Decode16, 0x00E0, 0x00E0, 0x00, 0x10) + IO (Decode16, 0x08A0, 0x08A0, 0x00, 0x04) + IO (Decode16, 0x0CC0, 0x0CC0, 0x00, 0x10) + IO (Decode16, 0x04D0, 0x04D0, 0x00, 0x02) + }) + Method (_CRS, 0, NotSerialized) + { + Return (CRS) + } + } + + Device (PIC) + { + Name (_HID, EisaId ("PNP0000")) + Name (_CRS, ResourceTemplate () + { + IO (Decode16, 0x0020, 0x0020, 0x01, 0x02) + IO (Decode16, 0x00A0, 0x00A0, 0x01, 0x02) + IRQNoFlags () {2} + }) + } + + Device (DMA0) + { + Name (_HID, EisaId ("PNP0200")) + Name (_CRS, ResourceTemplate () + { + DMA (Compatibility, BusMaster, Transfer8) {4} + IO (Decode16, 0x0000, 0x0000, 0x00, 0x10) + IO (Decode16, 0x0081, 0x0081, 0x00, 0x03) + IO (Decode16, 0x0087, 0x0087, 0x00, 0x01) + IO (Decode16, 0x0089, 0x0089, 0x00, 0x03) + IO (Decode16, 0x008F, 0x008F, 0x00, 0x01) + IO (Decode16, 0x00C0, 0x00C0, 0x00, 0x20) + IO (Decode16, 0x0480, 0x0480, 0x00, 0x10) + }) + } + + Device (TMR) + { + Name (_HID, EisaId ("PNP0100")) + Name (_CRS, ResourceTemplate () + { + IO (Decode16, 0x0040, 0x0040, 0x00, 0x04) + IRQNoFlags () {0} + }) + } + + Device (RTC) + { + Name (_HID, EisaId ("PNP0B00")) + Name (_CRS, ResourceTemplate () + { + IO (Decode16, 0x0070, 0x0070, 0x00, 0x02) + IRQNoFlags () {8} + }) + } + + Device (SPKR) + { + Name (_HID, EisaId ("PNP0800")) + Name (_CRS, ResourceTemplate () + { + IO (Decode16, 0x0061, 0x0061, 0x00, 0x01) + }) + } + + Device (PS2M) + { + Name (_HID, EisaId ("PNP0F13")) + Name (_CID, 0x130FD041) + Method (_STA, 0, NotSerialized) + { + Return (0x0F) + } + + Name (_CRS, ResourceTemplate () + { + IRQNoFlags () {12} + }) + } + + Device (PS2K) + { + Name (_HID, EisaId ("PNP0303")) + Name (_CID, 0x0B03D041) + Method (_STA, 0, NotSerialized) + { + Return (0x0F) + } + + Name (_CRS, ResourceTemplate () + { + IO (Decode16, 0x0060, 0x0060, 0x00, 0x01) + IO (Decode16, 0x0064, 0x0064, 0x00, 0x01) + IRQNoFlags () {1} + }) + } + + Device(FDC0) + { + Name(_HID, EisaId("PNP0700")) + Method(_STA, 0, NotSerialized) + { + Store(FDEN, Local0) + If (LEqual(Local0, 0)) { + Return (0x00) + } Else { + Return (0x0F) + } + } + + Name(_CRS, ResourceTemplate() + { + IO(Decode16, 0x03F2, 0x03F2, 0x00, 0x04) + IO(Decode16, 0x03F7, 0x03F7, 0x00, 0x01) + IRQNoFlags() { 6 } + DMA(Compatibility, NotBusMaster, Transfer8) { 2 } + }) + } + + Device (UAR1) + { + Name (_HID, EisaId ("PNP0501")) + Name (_UID, 0x01) + Method (_STA, 0, NotSerialized) + { + If(LEqual(\_SB.UAR1, 0)) { + Return(0x00) + } Else { + Return(0x0F) + } + } + + Name (_CRS, ResourceTemplate() + { + IO (Decode16, 0x03F8, 0x03F8, 8, 8) + IRQNoFlags () {4} + }) + } + + Device (UAR2) + { + Name (_HID, EisaId ("PNP0501")) + Name (_UID, 0x02) + Method (_STA, 0, NotSerialized) + { + If(LEqual(\_SB.UAR2, 0)) { + Return(0x00) + } Else { + Return(0x0F) + } + } + + Name (_CRS, ResourceTemplate() + { + IO (Decode16, 0x02F8, 0x02F8, 8, 8) + IRQNoFlags () {3} + }) + } + + Device (LTP1) + { + Name (_HID, EisaId ("PNP0400")) + Name (_UID, 0x02) + Method (_STA, 0, NotSerialized) + { + If(LEqual(\_SB.LTP1, 0)) { + Return(0x00) + } Else { + Return(0x0F) + } + } + + Name (_CRS, ResourceTemplate() + { + IO (Decode16, 0x0378, 0x0378, 0x08, 0x08) + IRQNoFlags () {7} + }) + } + + Device(VGID) { + Name(_HID, EisaId ("XEN0000")) + Name(_UID, 0x00) + Name(_CID, "VM_Gen_Counter") + Name(_DDN, "VM_Gen_Counter") + Method(_STA, 0, NotSerialized) + { + If(LEqual(\_SB.VGIA, 0x00000000)) { + Return(0x00) + } Else { + Return(0x0F) + } + } + Name(PKG, Package () + { + 0x00000000, + 0x00000000 + }) + Method(ADDR, 0, NotSerialized) + { + Store(\_SB.VGIA, Index(PKG, 0)) + Return(PKG) + } + } + + /* EHCI Controller 0:1d.0 */ + + Device (EHC1) + { + Name(_ADR, 0x001d0000) + + /* Power Resources for Wake */ + Name(_PRW, Package() { 13, 4 }) + + /* Highest D state in S3 state */ + Name(_S3D, 2) + + /* Highest D state in S4 state */ + Name(_S4D, 2) + + Device (HUB7) + { + Name(_ADR, 0x00000000) + + Device(PRT1) { Name(_ADR, 1) } /* USB Port 0 */ + Device(PRT2) { Name(_ADR, 2) } /* USB Port 1 */ + Device(PRT3) { Name(_ADR, 3) } /* USB Port 2 */ + Device(PRT4) { Name(_ADR, 4) } /* USB Port 3 */ + } + } + } + } + } + /* _S3 and _S4 are in separate SSDTs */ + Name (\_S5, Package (0x04) { + 0x00, /* PM1a_CNT.SLP_TYP */ + 0x00, /* PM1b_CNT.SLP_TYP */ + 0x00, /* reserved */ + 0x00 /* reserved */ + }) + Name(PICD, 0) + Method(_PIC, 1) { + Store(Arg0, PICD) + } +} diff --git a/tools/libacpi/libacpi.h b/tools/libacpi/libacpi.h index deda39e5db..b4d3116ca5 100644 --- a/tools/libacpi/libacpi.h +++ b/tools/libacpi/libacpi.h @@ -27,6 +27,7 @@ #define ACPI_HAS_8042 (1<<13) #define ACPI_HAS_CMOS_RTC (1<<14) #define ACPI_HAS_SSDT_LAPTOP_SLATE (1<<15) +#define ACPI_HAS_MCFG (1<<16) struct xen_vmemrange; struct acpi_numa { @@ -89,6 +90,9 @@ struct acpi_config { uint32_t ioapic_base_address; uint16_t pci_isa_irq_mask; uint8_t ioapic_id; + + uint64_t mmconfig_addr; + uint32_t mmconfig_len; }; int acpi_build_tables(struct acpi_ctxt *ctxt, struct acpi_config *config); diff --git a/tools/libs/light/libxl_dm.c b/tools/libs/light/libxl_dm.c index fc264a3a13..792dbc4383 100644 --- a/tools/libs/light/libxl_dm.c +++ b/tools/libs/light/libxl_dm.c @@ -1809,13 +1809,21 @@ static int libxl__build_device_model_args_new(libxl__gc *gc, flexarray_append(dm_args, b_info->extra_pv[i]); break; case LIBXL_DOMAIN_TYPE_HVM: - if (!libxl_defbool_val(b_info->u.hvm.xen_platform_pci)) { - /* Switching here to the machine "pc" which does not add - * the xen-platform device instead of the default "xenfv" machine. - */ - machinearg = libxl__strdup(gc, "pc,accel=xen,suppress-vmdesc=on"); + if (b_info->device_model_machine == LIBXL_DEVICE_MODEL_MACHINE_Q35) { + if (!libxl_defbool_val(b_info->u.hvm.xen_platform_pci)) { + machinearg = libxl__sprintf(gc, "q35,accel=xen"); + } else { + machinearg = libxl__sprintf(gc, "q35,accel=xen,xen-platform-dev=on"); + } } else { - machinearg = libxl__strdup(gc, "xenfv,suppress-vmdesc=on"); + if (!libxl_defbool_val(b_info->u.hvm.xen_platform_pci)) { + /* Switching here to the machine "pc" which does not add + * the xen-platform device instead of the default "xenfv" machine. + */ + machinearg = libxl__strdup(gc, "pc,accel=xen,suppress-vmdesc=on"); + } else { + machinearg = libxl__strdup(gc, "xenfv,suppress-vmdesc=on"); + } } if (b_info->u.hvm.mmio_hole_memkb) { uint64_t max_ram_below_4g = (1ULL << 32) - @@ -1929,29 +1937,51 @@ static int libxl__build_device_model_args_new(libxl__gc *gc, if (disks[i].is_cdrom) { const char *drive_id; - if (disk > 4) { + if (disk > 4 && b_info->device_model_machine == LIBXL_DEVICE_MODEL_MACHINE_I440) { LOGD(WARN, guest_domid, "Emulated CDROM can be only one of the first 4 disks.\n" "Disk %s will be available via PV drivers but not as an " "emulated disk.", disks[i].vdev); continue; + } else if (disk > 6 && + b_info->device_model_machine == LIBXL_DEVICE_MODEL_MACHINE_Q35) { + LOGD(WARN, guest_domid, "Emulated CDROM can be only one of the first 6 disks.\n" + "Disk %s will be available via PV drivers but not as an " + "emulated disk.", + disks[i].vdev); + continue; } + if (b_info->device_model_machine == LIBXL_DEVICE_MODEL_MACHINE_I440) { + drive_id = GCSPRINTF("ide-%i", dev_number); + drive = GCSPRINTF("if=none,readonly=on,id=%s", drive_id); - drive_id = GCSPRINTF("ide-%i", dev_number); - drive = GCSPRINTF("if=none,readonly=on,id=%s", drive_id); - - if (target_path) - drive = libxl__sprintf(gc, "%s,file=%s,format=%s", - drive, target_path, format); + if (target_path) + drive = libxl__sprintf(gc, "%s,file=%s,format=%s", + drive, target_path, format); - flexarray_vappend(dm_args, + flexarray_vappend(dm_args, "-drive", drive, "-device", GCSPRINTF("ide-cd,id=%s,drive=%s,bus=ide.%u,unit=%u", drive_id, drive_id, disk / 2, disk % 2), NULL); - continue; + continue; + } else { + drive_id = GCSPRINTF("sata-0-%i", dev_number); + drive = GCSPRINTF("if=none,readonly=on,id=%s", drive_id); + if (target_path) + drive = libxl__sprintf(gc, "%s,file=%s,format=%s", + drive, target_path, format); + + flexarray_vappend(dm_args, + "-drive", drive, + "-device", + GCSPRINTF("ide-cd,id=%s,drive=%s,bus=ide.0", + drive_id, drive_id), + NULL); + continue; + } } else { /* * Explicit sd disks are passed through as is. diff --git a/tools/libs/light/libxl_types.idl b/tools/libs/light/libxl_types.idl index c10292e0d7..b1aadae877 100644 --- a/tools/libs/light/libxl_types.idl +++ b/tools/libs/light/libxl_types.idl @@ -108,6 +108,13 @@ libxl_device_model_version = Enumeration("device_model_version", [ (2, "QEMU_XEN"), # Upstream based qemu-xen device model ]) +libxl_device_model_machine = Enumeration("device_model_machine", [ + (0, "UNKNOWN"), + (1, "I440"), + (2, "Q35"), + ]) + + libxl_console_type = Enumeration("console_type", [ (0, "UNKNOWN"), (1, "SERIAL"), @@ -575,6 +582,7 @@ libxl_domain_build_info = Struct("domain_build_info",[ ("device_model_ssidref", uint32), ("device_model_ssid_label", string), ("device_model_user", string), + ("device_model_machine", libxl_device_model_machine), # extra parameters pass directly to qemu, NULL terminated ("extra", libxl_string_list), diff --git a/tools/xl/xl_parse.c b/tools/xl/xl_parse.c index 1f6f47daf4..e6fb7a409a 100644 --- a/tools/xl/xl_parse.c +++ b/tools/xl/xl_parse.c @@ -2689,6 +2689,20 @@ skip_usbdev: if (!xlu_cfg_get_long (config, "stubdomain_memory", &l, 0)) b_info->stubdomain_memkb = l * 1024; + if (!xlu_cfg_get_string (config, "device_model_machine", &buf, 0)) { + if (!strcmp(buf, "i440")) { + b_info->device_model_machine = LIBXL_DEVICE_MODEL_MACHINE_I440; + } else if (!strcmp(buf, "q35")) { + b_info->device_model_machine = LIBXL_DEVICE_MODEL_MACHINE_Q35; + } else { + fprintf(stderr, + "Unknown device_model_machine \"%s\" specified\n", buf); + exit(1); + } + } else { + b_info->device_model_machine = LIBXL_DEVICE_MODEL_MACHINE_UNKNOWN; + } + #define parse_extra_args(type) \ e = xlu_cfg_get_list_as_string_list(config, "device_model_args"#type, \ &b_info->extra##type, 0); \ -- 2.34.1
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |