pc: pass PCI hole ranges to Guests

Guest 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.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Michael S. Tsirkin 2013-05-13 20:00:23 +03:00
parent 3459a62521
commit f8c457b88d
4 changed files with 52 additions and 3 deletions

View File

@ -989,6 +989,31 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
}
}
/* 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;
static void pc_fw_cfg_guest_info(PcGuestInfo *guest_info)
{
PcRomPciInfo *info;
if (!guest_info->has_pci_info) {
return;
}
info = g_malloc(sizeof *info);
info->w32_min = cpu_to_le64(guest_info->pci_info.w32.begin);
info->w32_max = cpu_to_le64(guest_info->pci_info.w32.end);
info->w64_min = cpu_to_le64(guest_info->pci_info.w64.begin);
info->w64_max = cpu_to_le64(guest_info->pci_info.w64.end);
/* Pass PCI hole info to guest via a side channel.
* Required so guest PCI enumeration does the right thing. */
fw_cfg_add_file(guest_info->fw_cfg, "etc/pci-info", info, sizeof *info);
}
typedef struct PcGuestInfoState {
PcGuestInfo info;
Notifier machine_done;
@ -1000,6 +1025,7 @@ void pc_guest_info_machine_done(Notifier *notifier, void *data)
PcGuestInfoState *guest_info_state = container_of(notifier,
PcGuestInfoState,
machine_done);
pc_fw_cfg_guest_info(&guest_info_state->info);
}
PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,

View File

@ -57,6 +57,7 @@ static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
static bool has_pvpanic = true;
static bool has_pci_info = true;
/* PC hardware initialisation */
static void pc_init1(MemoryRegion *system_memory,
@ -126,6 +127,7 @@ static void pc_init1(MemoryRegion *system_memory,
}
guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size);
guest_info->has_pci_info = has_pci_info;
/* Set PCI window size the way seabios has always done it. */
/* Power of 2 so bios can cover it with a single MTRR */
@ -260,8 +262,15 @@ static void pc_init_pci(QEMUMachineInitArgs *args)
initrd_filename, cpu_model, 1, 1);
}
static void pc_init_pci_1_5(QEMUMachineInitArgs *args)
{
has_pci_info = false;
pc_init_pci(args);
}
static void pc_init_pci_1_4(QEMUMachineInitArgs *args)
{
has_pci_info = false;
has_pvpanic = false;
x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
pc_init_pci(args);
@ -269,6 +278,7 @@ static void pc_init_pci_1_4(QEMUMachineInitArgs *args)
static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
{
has_pci_info = false;
enable_compat_apic_id_mode();
has_pvpanic = false;
pc_init_pci(args);
@ -277,6 +287,7 @@ static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
/* PC machine init function for pc-1.1 to pc-1.2 */
static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
{
has_pci_info = false;
disable_kvm_pv_eoi();
enable_compat_apic_id_mode();
has_pvpanic = false;
@ -286,6 +297,7 @@ static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
/* PC machine init function for pc-0.14 to pc-1.0 */
static void pc_init_pci_1_0(QEMUMachineInitArgs *args)
{
has_pci_info = false;
disable_kvm_pv_eoi();
enable_compat_apic_id_mode();
has_pvpanic = false;
@ -302,6 +314,7 @@ static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args)
const char *initrd_filename = args->initrd_filename;
const char *boot_device = args->boot_device;
has_pvpanic = false;
has_pci_info = false;
disable_kvm_pv_eoi();
enable_compat_apic_id_mode();
pc_init1(get_system_memory(),
@ -320,6 +333,7 @@ static void pc_init_isa(QEMUMachineInitArgs *args)
const char *initrd_filename = args->initrd_filename;
const char *boot_device = args->boot_device;
has_pvpanic = false;
has_pci_info = false;
if (cpu_model == NULL)
cpu_model = "486";
disable_kvm_pv_eoi();
@ -359,7 +373,7 @@ static QEMUMachine pc_i440fx_machine_v1_6 = {
static QEMUMachine pc_i440fx_machine_v1_5 = {
.name = "pc-i440fx-1.5",
.desc = "Standard PC (i440FX + PIIX, 1996)",
.init = pc_init_pci,
.init = pc_init_pci_1_5,
.hot_add_cpu = pc_hot_add_cpu,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {

View File

@ -47,6 +47,7 @@
#define MAX_SATA_PORTS 6
static bool has_pvpanic = true;
static bool has_pci_info = true;
/* PC hardware initialisation */
static void pc_q35_init(QEMUMachineInitArgs *args)
@ -107,6 +108,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
}
guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size);
guest_info->has_pci_info = has_pci_info;
/* allocate ram and load rom/bios */
if (!xen_enabled()) {
@ -212,11 +214,17 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
}
}
static void pc_q35_init_1_5(QEMUMachineInitArgs *args)
{
has_pci_info = false;
pc_q35_init(args);
}
static void pc_q35_init_1_4(QEMUMachineInitArgs *args)
{
has_pvpanic = false;
x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
pc_q35_init(args);
pc_q35_init_1_5(args);
}
static QEMUMachine pc_q35_machine_v1_6 = {
@ -232,7 +240,7 @@ static QEMUMachine pc_q35_machine_v1_6 = {
static QEMUMachine pc_q35_machine_v1_5 = {
.name = "pc-q35-1.5",
.desc = "Standard PC (Q35 + ICH9, 2009)",
.init = pc_q35_init,
.init = pc_q35_init_1_5,
.hot_add_cpu = pc_hot_add_cpu,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {

View File

@ -20,6 +20,7 @@ typedef struct PcPciInfo {
struct PcGuestInfo {
PcPciInfo pci_info;
bool has_pci_info;
FWCfgState *fw_cfg;
};