|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] gross qemu behavior
On Fri, 28 Mar 2014, Stefano Stabellini wrote:
> CC'ing Paolo, hoping that he has a better idea on how to solve this
> problem.
>
>
> On Fri, 28 Mar 2014, Jan Beulich wrote:
> > Hi,
> >
> > so while doing all that EPT work I naturally also happened to look more
> > closely at the EPT table dumps, spotting an odd range of 16 pages
> > outside any supposedly populated address range. This range only
> > exists when guest memory doesn't extend past (by default) 0xf0000000
> > (the start of MMIO, i.e. normally the frame buffer). After spending quite
> > a bit of time I finally figured that this must be a left over of the Cirrus
> > VGA ROM, and I would have thought that this
> >
> > --- a/hw/pci/pci.c
> > +++ b/hw/pci/pci.c
> > @@ -1976,6 +1976,9 @@ static int pci_add_option_rom(PCIDevice
> > }
> >
> > pci_register_bar(pdev, PCI_ROM_SLOT, 0, &pdev->rom);
> > + memory_region_add_subregion_overlap(pdev->bus->address_space_mem,
> > + pdev->rom.ram_addr, &pdev->rom, 1);
> > + memory_region_del_subregion(pdev->bus->address_space_mem, &pdev->rom);
> >
> > return 0;
> > }
> >
> > should fix it. It does appear to work as far generic qemu is concerned,
> > but once looking at the Xen backend I had to conclude that this just
> > can't work: For one, xen_add_to_physmap() and
> > xen_remove_from_physmap() are _documented_ (in a comment) to
> > only be capable of a single region (VRAM). And the latter - even worse -
> > is implemented with a call to xc_domain_add_to_physmap(), completely
> > contrary to its name.
>
> xen_add_to_physmap and xen_remove_from_physmap are just to deal with the
> VRAM in their current implementation.
>
>
> > Instrumenting xen_region_{add,del}(), I can see that all regions get
> > properly reported to the Xen backend, just that it doesn't handle them
> > (this is with above patch in place):
> >
> > xra(fee00000,100000)
> > xra(fec00000,1000)
> > xra(fed00000,400)
> > xra(80000000,10000)
> > xrd(80000000,10000)
> > xra(f0000000,800000)
> > xra(f1000000,400000)
> > xra(f2000000,1000000)
> > xra(f3010000,4000)
> > xra(f3014000,1000)
> > xra(f3015000,3000)
> > xra(f3018000,1000)
> > xra(f3000000,10000)
> > xrd(f3000000,10000)
> > xrd(f0000000,800000)
> > xra(f0000000,800000)
> > mapping vram to f0000000 - f0800000
> >
> > Having wasted enough time getting to this point, I'd like to ask you
> > to advise a proper fix for this. We definitely shouldn't be leaving
> > stuff sitting at arbitrary positions in the physical address space of
> > the guest. And the fact that the range gets removed (from Xen's
> > perspective, but not from qemu's) when RAM extends beyond
> > 0xf0000000 (due to it being replaced with what is actually
> > intended to be there) makes me wonder what would happen if the
> > ROM got enabled by the guest.
>
> This is a thorny issue, fixing this behavior is not going to be trivial:
>
> - The hypervisor/libxc does not currently expose a
> xc_domain_remove_from_physmap function.
>
> - QEMU works by allocating memory regions at the end of the guest
> physmap and then moving them at the right place.
>
> - QEMU can destroy a memory region and in that case we could free the
> memory and remove it from the physmap, however that is NOT what QEMU
> does with the vga ROM. In that case it calls
> memory_region_del_subregion, so we can't be sure that the ROM won't be
> mapped again, therefore we cannot free it. We need to move it
> somewhere else, hence the problem.
>
>
> But fortunately we don't actually need to add the VGA ROM to the guest
> physmap for it to work, QEMU can trap and emulate. In fact even today we
> are not mapping it at the right place anyway, see xen_set_memory:
>
> if (add) {
> if (!memory_region_is_rom(section->mr)) {
> xen_add_to_physmap(state, start_addr, size,
> section->mr, section->offset_within_region);
> } else {
>
>
> So the only solution I can see right now is:
>
> - avoid allocating guest memory for the VGA ROM
> That means that at the beginning of xen_ram_alloc we need to realize
> that the memory region we are dealing with is the VGA ROM memory region
> and avoid calling xc_domain_populate_physmap_exact for it.
>
> - call g_malloc instead
> Simply use g_malloc to allocate QEMU memory for the VGA ROM,
> keep track of the allocation in a data structure internal to xen-all.c.
>
> - make sure that qemu_get_ram_ptr can deal with the different allocation
> Now that the VGA ROM is QEMU memory, we need to make sure that
> qemu_get_ram_ptr returns the right pointer for it.
>
>
> This is all very fiddly and hackish, but I can't see a better way of
> solving the issue.
Given that I feel that the explanation is not very clear, I am appending
a proof of concept patch. It is obviously horrible, I am by no means
suggesting it should be applied.
diff --git a/exec.c b/exec.c
index 91513c6..bdecc70 100644
--- a/exec.c
+++ b/exec.c
@@ -1453,6 +1453,7 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
It should not be used for general purpose DMA.
Use cpu_physical_memory_map/cpu_physical_memory_rw instead.
*/
+extern uint8_t* vga_rom;
void *qemu_get_ram_ptr(ram_addr_t addr)
{
RAMBlock *block = qemu_get_ram_block(addr);
@@ -1462,7 +1463,9 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
* because we don't want to map the entire memory in QEMU.
* In that case just map until the end of the page.
*/
- if (block->offset == 0) {
+ if (!strcmp(block->mr->name,"cirrus_vga.rom")) {
+ return vga_rom;
+ } else if (block->offset == 0) {
return xen_map_cache(addr, 0, 0);
} else if (block->host == NULL) {
block->host =
diff --git a/xen-all.c b/xen-all.c
index ba34739..6211946 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -101,6 +101,8 @@ typedef struct XenIOState {
Notifier wakeup;
} XenIOState;
+uint8_t* vga_rom;
+
/* Xen specific function for piix pci */
int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
@@ -217,6 +219,11 @@ void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size,
MemoryRegion *mr)
return;
}
+ if (!strcmp(mr->name,"cirrus_vga.rom")) {
+ vga_rom = g_malloc(size);
+ return;
+ }
+
trace_xen_ram_alloc(ram_addr, size);
nr_pfn = size >> TARGET_PAGE_BITS;
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |