aboutsummaryrefslogtreecommitdiffstats
path: root/hw/piix_pci.c
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2011-08-15 17:17:38 +0300
committerAnthony Liguori <aliguori@us.ibm.com>2011-08-22 10:47:49 -0500
commitae0a54664c76f1d2a2a7a268266d47b4e8c12a4c (patch)
treeb4a664a81fe572ce96640fdc74b0ec2ca172ee2a /hw/piix_pci.c
parentbe20f9e902ca47ea84e1b1c1e89b0a55d59b4c11 (diff)
440fx: fix PAM, PCI holes
The current implementation of PAM and the PCI holes is broken in several ways: - PCI BARs are not restricted to the PCI hole (a BAR may hide memory) - PCI devices do not respect PAM (if a PCI device maps a region while PAM maps the region to RAM, the request will be honored) This patch fixes things by introducing a pci address space, and using memory region aliases to represent PAM regions, SMRAM, and PCI holes. The memory hierarchy looks something like system_memory | +--- low memory alias (0-0xe0000000) | | | +-- ram@0 | +--- high memory alias (0x100000000-EOM) | | | +-- ram@0xe0000000 | +--- pci hole alias (end of low memory-0x100000000) | | | +-- pci@end-of-low-memory | | +--- pam[n] (0xc0000-0xc3fff etc) (when set to pci, priority 1) | | | +-- pci@0xc4000 etc | +--- smram (0xa0000-0xbffff) (when set to pci/vga, priority 1) | +-- pci@0xa0000 etc ram (simple ram region) pci | +--- BARn | +--- VGA 0xa0000-0xbffff | +--- ROMs Signed-off-by: Avi Kivity <avi@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/piix_pci.c')
-rw-r--r--hw/piix_pci.c114
1 files changed, 81 insertions, 33 deletions
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 28a3ee2e9..c563c6e1a 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -66,10 +66,22 @@ typedef struct PIIX3State {
int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
} PIIX3State;
+typedef struct PAMMemoryRegion {
+ MemoryRegion mem;
+ bool initialized;
+} PAMMemoryRegion;
+
struct PCII440FXState {
PCIDevice dev;
- target_phys_addr_t isa_page_descs[384 / 4];
+ MemoryRegion *system_memory;
+ MemoryRegion *pci_address_space;
+ MemoryRegion *ram_memory;
+ MemoryRegion pci_hole;
+ MemoryRegion pci_hole_64bit;
+ PAMMemoryRegion pam_regions[13];
+ MemoryRegion smram_region;
uint8_t smm_enabled;
+ bool smram_enabled;
PIIX3State *piix3;
};
@@ -92,50 +104,62 @@ static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
return (pci_intx + slot_addend) & 3;
}
-static void update_pam(PCII440FXState *d, uint32_t start, uint32_t end, int r)
+static void update_pam(PCII440FXState *d, uint32_t start, uint32_t end, int r,
+ PAMMemoryRegion *mem)
{
- uint32_t addr;
+ if (mem->initialized) {
+ memory_region_del_subregion(d->system_memory, &mem->mem);
+ memory_region_destroy(&mem->mem);
+ }
// printf("ISA mapping %08x-0x%08x: %d\n", start, end, r);
switch(r) {
case 3:
/* RAM */
- cpu_register_physical_memory(start, end - start,
- start);
+ memory_region_init_alias(&mem->mem, "pam-ram", d->ram_memory,
+ start, end - start);
break;
case 1:
/* ROM (XXX: not quite correct) */
- cpu_register_physical_memory(start, end - start,
- start | IO_MEM_ROM);
+ memory_region_init_alias(&mem->mem, "pam-rom", d->ram_memory,
+ start, end - start);
+ memory_region_set_readonly(&mem->mem, true);
break;
case 2:
case 0:
/* XXX: should distinguish read/write cases */
- for(addr = start; addr < end; addr += 4096) {
- cpu_register_physical_memory(addr, 4096,
- d->isa_page_descs[(addr - 0xa0000) >> 12]);
- }
+ memory_region_init_alias(&mem->mem, "pam-pci", d->pci_address_space,
+ start, end - start);
break;
}
+ memory_region_add_subregion_overlap(d->system_memory,
+ start, &mem->mem, 1);
+ mem->initialized = true;
}
static void i440fx_update_memory_mappings(PCII440FXState *d)
{
int i, r;
- uint32_t smram, addr;
+ uint32_t smram;
- update_pam(d, 0xf0000, 0x100000, (d->dev.config[I440FX_PAM] >> 4) & 3);
+ update_pam(d, 0xf0000, 0x100000, (d->dev.config[I440FX_PAM] >> 4) & 3,
+ &d->pam_regions[0]);
for(i = 0; i < 12; i++) {
r = (d->dev.config[(i >> 1) + (I440FX_PAM + 1)] >> ((i & 1) * 4)) & 3;
- update_pam(d, 0xc0000 + 0x4000 * i, 0xc0000 + 0x4000 * (i + 1), r);
+ update_pam(d, 0xc0000 + 0x4000 * i, 0xc0000 + 0x4000 * (i + 1), r,
+ &d->pam_regions[i+1]);
}
smram = d->dev.config[I440FX_SMRAM];
if ((d->smm_enabled && (smram & 0x08)) || (smram & 0x40)) {
- cpu_register_physical_memory(0xa0000, 0x20000, 0xa0000);
+ if (!d->smram_enabled) {
+ memory_region_del_subregion(d->system_memory, &d->smram_region);
+ d->smram_enabled = true;
+ }
} else {
- for(addr = 0xa0000; addr < 0xc0000; addr += 4096) {
- cpu_register_physical_memory(addr, 4096,
- d->isa_page_descs[(addr - 0xa0000) >> 12]);
+ if (d->smram_enabled) {
+ memory_region_add_subregion_overlap(d->system_memory, 0xa0000,
+ &d->smram_region, 1);
+ d->smram_enabled = false;
}
}
}
@@ -152,17 +176,6 @@ static void i440fx_set_smm(int val, void *arg)
}
-/* XXX: suppress when better memory API. We make the assumption that
- no device (in particular the VGA) changes the memory mappings in
- the 0xa0000-0x100000 range */
-void i440fx_init_memory_mappings(PCII440FXState *d)
-{
- int i;
- for(i = 0; i < 96; i++) {
- d->isa_page_descs[i] = cpu_get_physical_page_desc(0xa0000 + i * 0x1000);
- }
-}
-
static void i440fx_write_config(PCIDevice *dev,
uint32_t address, uint32_t val, int len)
{
@@ -244,24 +257,48 @@ static PCIBus *i440fx_common_init(const char *device_name,
qemu_irq *pic,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
- ram_addr_t ram_size)
+ ram_addr_t ram_size,
+ target_phys_addr_t pci_hole_start,
+ target_phys_addr_t pci_hole_size,
+ target_phys_addr_t pci_hole64_start,
+ target_phys_addr_t pci_hole64_size,
+ MemoryRegion *pci_address_space,
+ MemoryRegion *ram_memory)
{
DeviceState *dev;
PCIBus *b;
PCIDevice *d;
I440FXState *s;
PIIX3State *piix3;
+ PCII440FXState *f;
dev = qdev_create(NULL, "i440FX-pcihost");
s = FROM_SYSBUS(I440FXState, sysbus_from_qdev(dev));
s->address_space = address_space_mem;
- b = pci_bus_new(&s->busdev.qdev, NULL, s->address_space,
+ b = pci_bus_new(&s->busdev.qdev, NULL, pci_address_space,
address_space_io, 0);
s->bus = b;
qdev_init_nofail(dev);
d = pci_create_simple(b, 0, device_name);
*pi440fx_state = DO_UPCAST(PCII440FXState, dev, d);
+ f = *pi440fx_state;
+ f->system_memory = address_space_mem;
+ f->pci_address_space = pci_address_space;
+ f->ram_memory = ram_memory;
+ memory_region_init_alias(&f->pci_hole, "pci-hole", f->pci_address_space,
+ pci_hole_start, pci_hole_size);
+ memory_region_add_subregion(f->system_memory, pci_hole_start, &f->pci_hole);
+ memory_region_init_alias(&f->pci_hole_64bit, "pci-hole64",
+ f->pci_address_space,
+ pci_hole64_start, pci_hole64_size);
+ if (pci_hole64_size) {
+ memory_region_add_subregion(f->system_memory, pci_hole64_start,
+ &f->pci_hole_64bit);
+ }
+ memory_region_init_alias(&f->smram_region, "smram-region",
+ f->pci_address_space, 0xa0000, 0x20000);
+ f->smram_enabled = true;
/* Xen supports additional interrupt routes from the PCI devices to
* the IOAPIC: the four pins of each PCI device on the bus are also
@@ -289,6 +326,8 @@ static PCIBus *i440fx_common_init(const char *device_name,
ram_size = 255;
(*pi440fx_state)->dev.config[0x57]=ram_size;
+ i440fx_update_memory_mappings(f);
+
return b;
}
@@ -296,12 +335,21 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
qemu_irq *pic,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
- ram_addr_t ram_size)
+ ram_addr_t ram_size,
+ target_phys_addr_t pci_hole_start,
+ target_phys_addr_t pci_hole_size,
+ target_phys_addr_t pci_hole64_start,
+ target_phys_addr_t pci_hole64_size,
+ MemoryRegion *pci_memory, MemoryRegion *ram_memory)
+
{
PCIBus *b;
b = i440fx_common_init("i440FX", pi440fx_state, piix3_devfn, pic,
- address_space_mem, address_space_io, ram_size);
+ address_space_mem, address_space_io, ram_size,
+ pci_hole_start, pci_hole_size,
+ pci_hole64_size, pci_hole64_size,
+ pci_memory, ram_memory);
return b;
}