pc: pass pci window data to guests
cover pc: pass pci window data to guests
This makes it possible for bios to load pci window data from host.
This makes it possible for host to make sure setup matches hardware exactly: especially important for when ACPI tables are loaded from host. This will also make it easier to add more chipsets down the road.
Michael S. Tsirkin (3):
range: add structure to pass ranges around
pc: factor out pci hole math
pc: pass PCI hole ranges to Guests
hw/i386/pc.c | 34 +++++++++++++++++++++++++++++++--- hw/i386/pc_piix.c | 14 +++++++------- hw/i386/pc_q35.c | 9 ++++++--- hw/pci-host/q35.c | 18 ++++++++---------- include/hw/i386/pc.h | 25 ++++++++++++++++++++++++- include/hw/pci-host/q35.h | 4 ++-- include/qemu/range.h | 24 ++++++++++++++++++++++++ 7 files changed, 102 insertions(+), 26 deletions(-)
Signature · 1 line
MST
PATCH 1/3 range: add structure to pass ranges around
Convenient structure to pass ranges around, and calculate length avoiding 64 bit overlap issues.
--- include/qemu/range.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
include/qemu/range.h +24 -0
@@ -1,6 +1,30 @@#ifndef QEMU_RANGE_H #define QEMU_RANGE_H +#include <inttypes.h> + +struct Range { +uint64_t min; +uint64_t max; +}; +typedef struct Range Range ; + +/* max <= min means not valid */ +static inline bool range_valid (Range *r) +{ +return r->max > r->min; +} + +static inline uint64_t range_len (Range *r) +{ +return range_valid (r) ? r->max - r->min +1 :0 ; +} + +static inline uint64_t range_start (Range *r) +{ +return r->min; +} +/* Get last byte of a range from offset + length. * Undefined for ranges that wrap around 0. */ static inline uint64_t range_get_last (uint64_t offset,uint64_t len)
Signature · 1 line
MST
PATCH 2/3 pc: factor out pci hole math
In reply to Michael S. TsirkinMove common code for calculating ranges for 32 and 64 bit pci holes for use by guest to pc.c.
Pass ranges to Q35/PIIX respectively.
Note: ranges are passed within a generic GuestInfo structure, we are going to add more fields of interest to Guests in the future.
--- hw/i386/pc.c | 15 +++++++++++++++ hw/i386/pc_piix.c | 12 ++++++------ hw/i386/pc_q35.c | 7 +++++-- hw/pci-host/q35.c | 18 ++++++++---------- include/hw/i386/pc.h | 13 +++++++++++++ include/hw/pci-host/q35.h | 4 ++-- 6 files changed, 49 insertions(+), 20 deletions(-)
hw/i386/pc.c +15 -0
@@ -922,6 +922,21 @@ void pc_acpi_init(const char *default_dsdt) } } +void pc_guest_info_init (PcGuestInfo *guest_info, +ram_addr_t below_4g_mem_size, +ram_addr_t above_4g_mem_size) +{ + guest_info->pci_info.w32.min = below_4g_mem_size; + guest_info->pci_info.w32.max =0x100000000ULL -0x1 ; +if (sizeof (hwaddr) ==4 ) { + guest_info->pci_info.w64.min =0x100000000ULL + above_4g_mem_size; + guest_info->pci_info.w64.max = +range_get_last (guest_info->pci_info.w64.min, (0x1ULL <<62 )); + }else { + guest_info->pci_info.w64.min = guest_info->pci_info.w64.max =0 ; + } +} + FWCfgState *pc_memory_init(MemoryRegion *system_memory, const char *kernel_filename, const char *kernel_cmdline,
hw/i386/pc_piix.c +6 -6
@@ -86,6 +86,7 @@ static void pc_init1(MemoryRegion *system_memory,MemoryRegion *pci_memory;MemoryRegion *rom_memory;FWCfgState *fw_cfg =NULL ; +PcGuestInfo guest_info;pc_cpus_init (cpu_model);pc_acpi_init ("acpi-dsdt.aml" );
@@ -111,6 +112,7 @@ static void pc_init1(MemoryRegion *system_memory, rom_memory = system_memory; } +pc_guest_info_init (&guest_info, below_4g_mem_size, above_4g_mem_size);/* allocate ram and load rom/bios */ if (!xen_enabled ()) { fw_cfg = pc_memory_init(system_memory,
@@ -131,12 +133,10 @@ static void pc_init1(MemoryRegion *system_memory,if (pci_enabled) { pci_bus =i440fx_init (&i440fx_state, &piix3_devfn, &isa_bus, gsi, system_memory, system_io, ram_size, - below_4g_mem_size, -0x100000000ULL - below_4g_mem_size, -0x100000000ULL + above_4g_mem_size, - (sizeof (hwaddr) ==4 - ?0 - : ((uint64_t )1 <<62 )), +range_start (&guest_info.pci_info.w32), +range_len (&guest_info.pci_info.w32), +range_start (&guest_info.pci_info.w64), +range_len (&guest_info.pci_info.w64), pci_memory, ram_memory); }else { pci_bus =NULL ;
hw/i386/pc_q35.c +5 -2
@@ -85,6 +85,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)ICH9LPCState *ich9_lpc;PCIDevice *ahci;qemu_irq *cmos_s3; +PcGuestInfo guest_info;pc_cpus_init (cpu_model);pc_acpi_init ("q35-acpi-dsdt.aml" );
@@ -109,6 +110,8 @@ static void pc_q35_init(QEMUMachineInitArgs *args) rom_memory =get_system_memory (); } +pc_guest_info_init (&guest_info, below_4g_mem_size, above_4g_mem_size); +/* allocate ram and load rom/bios */ if (!xen_enabled ()) { pc_memory_init(get_system_memory(), kernel_filename, kernel_cmdline,
@@ -133,8 +136,8 @@ static void pc_q35_init(QEMUMachineInitArgs *args) q35_host->mch.pci_address_space = pci_memory; q35_host->mch.system_memory =get_system_memory (); q35_host->mch.address_space_io =get_system_io ();; - q35_host->mch.below_4g_mem_size = below_4g_mem_size; - q35_host->mch.above_4g_mem_size = above_4g_mem_size; + q35_host->mch.below_4g_mem_range = guest_info.pci_info.w32; + q35_host->mch.above_4g_mem_range = guest_info.pci_info.w64;/* pci */ qdev_init_nofail (DEVICE (q35_host)); host_bus = q35_host->host.pci.bus;
hw/pci-host/q35.c +8 -10
@@ -240,25 +240,23 @@ static void mch_reset(DeviceState *qdev)static int mch_init (PCIDevice *d) {int i; -hwaddr pci_hole64_size;MCHPCIState *mch =MCH_PCI_DEVICE (d);/* setup pci memory regions */ memory_region_init_alias (&mch->pci_hole,"pci-hole" , mch->pci_address_space, - mch->below_4g_mem_size, -0x100000000ULL - mch->below_4g_mem_size); -memory_region_add_subregion (mch->system_memory, mch->below_4g_mem_size, +range_start (&mch->below_4g_mem_range), +range_len (&mch->below_4g_mem_range)); +memory_region_add_subregion (mch->system_memory, +range_len (&mch->below_4g_mem_range), &mch->pci_hole); - pci_hole64_size = (sizeof (hwaddr) ==4 ?0 : - ((uint64_t )1 <<62 ));memory_region_init_alias (&mch->pci_hole_64bit,"pci-hole64" , mch->pci_address_space, -0x100000000ULL + mch->above_4g_mem_size, - pci_hole64_size); -if (pci_hole64_size) { +range_start (&mch->above_4g_mem_range), +range_len (&mch->above_4g_mem_range)); +if (range_valid (&mch->above_4g_mem_range)) {memory_region_add_subregion (mch->system_memory, -0x100000000ULL + mch->above_4g_mem_size, +range_len (&mch->above_4g_mem_range), &mch->pci_hole_64bit); }/* smram */
include/hw/i386/pc.h +13 -0
@@ -10,9 +10,19 @@#include "exec/memory.h" #include "hw/i386/ioapic.h" #include "hw/nvram/fw_cfg.h" +#include "qemu/range.h" /* PC-style peripherals (also used by other machines). */ +typedef struct PciGuestInfo { +Range w32; +Range w64; +}PciGuestInfo ; + +typedef struct PcGuestInfo { +PciGuestInfo pci_info; +}PcGuestInfo ; +/* parallel.c */ static inline bool parallel_init (ISABus *bus,int index,CharDriverState *chr) {
@@ -81,6 +91,9 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level);void pc_cpus_init (const char *cpu_model);void pc_acpi_init (const char *default_dsdt); +void pc_guest_info_init (PcGuestInfo *guest_info, +ram_addr_t below_4g_mem_size, +ram_addr_t above_4g_mem_size); FWCfgState *pc_memory_init(MemoryRegion *system_memory, const char *kernel_filename, const char *kernel_cmdline,
include/hw/pci-host/q35.h +2 -2
@@ -53,8 +53,8 @@ typedef struct MCHPCIState {MemoryRegion pci_hole;MemoryRegion pci_hole_64bit;uint8_t smm_enabled; -ram_addr_t below_4g_mem_size; -ram_addr_t above_4g_mem_size; +Range below_4g_mem_range; +Range above_4g_mem_range; } MCHPCIState; typedef struct Q35PCIHost {
Signature · 1 line
MST
PATCH 3/3 pc: pass PCI hole ranges to Guests
In reply to Michael S. TsirkinGuest currently has to jump through lots of
hoops to guess the PCI hole ranges.
It's fragile, and makes us change BIOS each time we add a new chipset. Let's report the window in a ROM file, to make
BIOS do exactly what QEMU intends.
--- hw/i386/pc.c | 19 ++++++++++++++++--- hw/i386/pc_piix.c | 2 +- hw/i386/pc_q35.c | 2 +- include/hw/i386/pc.h | 18 ++++++++++++++---- 4 files changed, 32 insertions(+), 9 deletions(-)
hw/i386/pc.c +16 -3
@@ -567,7 +567,7 @@ static unsigned int pc_apic_id_limit(unsigned int max_cpus)return x86_cpu_apic_id_from_index (max_cpus -1 ) +1 ; } -static FWCfgState *bochs_bios_init (void ) +static FWCfgState *bochs_bios_init (PcGuestInfo *guest_info) {FWCfgState *fw_cfg;uint8_t *smbios_table;
@@ -629,6 +629,9 @@ static FWCfgState *bochs_bios_init(void) (1 + apic_id_limit + nb_numa_nodes) * sizeof(*numa_fw_cfg)); +fw_cfg_add_file (fw_cfg,"etc/pci-info" , guest_info->pci_info_rom, +sizeof *guest_info->pci_info_rom); +return fw_cfg; }
@@ -926,6 +929,8 @@ void pc_guest_info_init(PcGuestInfo *guest_info, ram_addr_t below_4g_mem_size, ram_addr_t above_4g_mem_size) { +PcRomPciInfo *pci_info; + guest_info->pci_info.w32.min = below_4g_mem_size; guest_info->pci_info.w32.max =0x100000000ULL -0x1 ;if (sizeof (hwaddr) ==4 ) {
@@ -935,6 +940,13 @@ void pc_guest_info_init(PcGuestInfo *guest_info, }else { guest_info->pci_info.w64.min = guest_info->pci_info.w64.max =0 ; } + + guest_info->pci_info_rom = pci_info =g_malloc0 (sizeof *pci_info); + pci_info->w32_min =cpu_to_le64 (guest_info->pci_info.w32.min); + pci_info->w32_max =cpu_to_le64 (MIN (guest_info->pci_info.w32.max, +IO_APIC_DEFAULT_ADDRESS )); + pci_info->w64_min =cpu_to_le64 (guest_info->pci_info.w64.min); + pci_info->w64_max =cpu_to_le64 (guest_info->pci_info.w64.max); } FWCfgState *pc_memory_init(MemoryRegion *system_memory,
@@ -944,7 +956,8 @@ FWCfgState *pc_memory_init(MemoryRegion *system_memory,ram_addr_t below_4g_mem_size, ram_addr_t above_4g_mem_size, MemoryRegion *rom_memory, - MemoryRegion **ram_memory) + MemoryRegion **ram_memory, + PcGuestInfo *guest_info) { int linux_boot, i;MemoryRegion *ram, *option_rom_mr;
@@ -986,7 +999,7 @@ FWCfgState *pc_memory_init(MemoryRegion *system_memory, option_rom_mr, 1); - fw_cfg =bochs_bios_init (); + fw_cfg =bochs_bios_init (guest_info);rom_set_fw (fw_cfg);if (linux_boot) {
hw/i386/pc_piix.c +1 -1
@@ -118,7 +118,7 @@ static void pc_init1(MemoryRegion *system_memory, fw_cfg =pc_memory_init (system_memory, kernel_filename, kernel_cmdline, initrd_filename, below_4g_mem_size, above_4g_mem_size, - rom_memory, &ram_memory); + rom_memory, &ram_memory, &guest_info); } gsi_state =g_malloc0 (sizeof (*gsi_state));
hw/i386/pc_q35.c +1 -1
@@ -116,7 +116,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)if (!xen_enabled ()) {pc_memory_init (get_system_memory (), kernel_filename, kernel_cmdline, initrd_filename, below_4g_mem_size, above_4g_mem_size, - rom_memory, &ram_memory); + rom_memory, &ram_memory, &guest_info); }/* irq lines */
include/hw/i386/pc.h +14 -4
@@ -14,13 +14,22 @@/* PC-style peripherals (also used by other machines). */ -typedef struct PciGuestInfo { +typedef struct PcPciInfo {Range w32;Range w64; -}PciGuestInfo ; +}PcPciInfo ; + +/* pci-info ROM file. Little endian format */ +typedef struct PcRomPciInfo { +uint64_t w32_min; +uint64_t w32_max; +uint64_t w64_min; +uint64_t w64_max; +}PcRomPciInfo ;typedef struct PcGuestInfo { -PciGuestInfo pci_info; +PcPciInfo pci_info; +PcRomPciInfo *pci_info_rom; }PcGuestInfo ;/* parallel.c */
@@ -101,7 +110,8 @@ FWCfgState *pc_memory_init(MemoryRegion *system_memory,ram_addr_t below_4g_mem_size, ram_addr_t above_4g_mem_size, MemoryRegion *rom_memory, - MemoryRegion **ram_memory); + MemoryRegion **ram_memory, + PcGuestInfo *guest_info);qemu_irq *pc_allocate_cpu_irq (void );DeviceState *pc_vga_init (ISABus *isa_bus,PCIBus *pci_bus); void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
Signature · 1 line
MST