On Fri, Oct 30, 2009 at 09:21:11PM +0900, Isaku Yamahata wrote: > implemented pci 64bit bar support. > The tricky bit is pci_update_mapping(). > An OS is allowed to set the BAR such that OS can't address the area > pointed by BAR. It doesn't make sense, though.
It might make sense. 32 bit guest can address more than 4G of physical RAM, e.g. using PAE. Since I think qemu can not support this if target phys address is 32 bit, we should declare lack of support for 64 bit addressing on these platforms, by forcing BAR into 32 bit mode, rather than silently failing to map it. > In that case, don't map the BAR. > > Signed-off-by: Isaku Yamahata <yamah...@valinux.co.jp> > --- > hw/pci.c | 35 ++++++++++++++++++++++++++++++----- > hw/pci.h | 1 + > 2 files changed, 31 insertions(+), 5 deletions(-) > > diff --git a/hw/pci.c b/hw/pci.c > index b462bd6..7da3db9 100644 > --- a/hw/pci.c > +++ b/hw/pci.c > @@ -484,8 +484,14 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, > wmask |= PCI_ROM_ADDRESS_ENABLE; > } > pci_set_long(pci_dev->config + addr, type); > - pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff); > - pci_set_long(pci_dev->cmask + addr, 0xffffffff); > + if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) && > + r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { > + pci_set_quad(pci_dev->wmask + addr, wmask); > + pci_set_quad(pci_dev->cmask + addr, ~0ULL); > + } else { > + pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff); > + pci_set_long(pci_dev->cmask + addr, 0xffffffff); > + } > } > > static void pci_update_mappings(PCIDevice *d) > @@ -513,7 +519,11 @@ static void pci_update_mappings(PCIDevice *d) > } > } else { > if (cmd & PCI_COMMAND_MEMORY) { > - new_addr = pci_get_long(d->config + pci_bar(d, i)); > + if (r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { > + new_addr = pci_get_quad(d->config + pci_bar(d, i)); > + } else { > + new_addr = pci_get_long(d->config + pci_bar(d, i)); > + } > /* the ROM slot has a specific enable bit */ > if (i == PCI_ROM_SLOT && !(new_addr & > PCI_ROM_ADDRESS_ENABLE)) > goto no_mem_map; > @@ -531,7 +541,15 @@ static void pci_update_mappings(PCIDevice *d) > * Without this, PC ide doesn't work well. > * TODO: remove this work around. > */ > - last_addr >= UINT32_MAX) { > + (!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) && > + last_addr >= UINT32_MAX) || > + > + /* > + * OS is allowed to set BAR beyond its addressable > + * bits. For example, 32 bit OS can set 64bit bar > + * to >4G. Check it. > + */ > + last_addr >= TARGET_PHYS_ADDR_MAX) { > new_addr = PCI_BAR_UNMAPPED; > } > } else { > @@ -773,8 +791,15 @@ static void pci_info_device(PCIDevice *d) > " [0x%04"FMT_PCIBUS"].\n", > r->addr, r->addr + r->size - 1); > } else { > - monitor_printf(mon, "32 bit memory at 0x%08"FMT_PCIBUS > + const char *type = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64 ? > + "64 bit" : "32 bit"; > + const char *prefetch = > + r->type & PCI_BASE_ADDRESS_MEM_PREFETCH ? > + " prefetchable" : ""; > + > + monitor_printf(mon, "%s%s memory at 0x%08"FMT_PCIBUS > " [0x%08"FMT_PCIBUS"].\n", > + type, prefetch, > r->addr, r->addr + r->size - 1); > } > } > diff --git a/hw/pci.h b/hw/pci.h > index 305c030..e83faf5 100644 > --- a/hw/pci.h > +++ b/hw/pci.h > @@ -114,6 +114,7 @@ typedef struct PCIIORegion { > #define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ > #define PCI_BASE_ADDRESS_SPACE_IO 0x01 > #define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00 > +#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ > #define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ > #define PCI_PRIMARY_BUS 0x18 /* Primary bus number */ > #define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ > -- > 1.6.0.2 > >