diff --git a/tools/firmware/hvmloader/32bitbios_support.c b/tools/firmware/hvmloader/32bitbios_support.c index 7add4df1f3..b96f9650e3 100644 --- a/tools/firmware/hvmloader/32bitbios_support.c +++ b/tools/firmware/hvmloader/32bitbios_support.c @@ -76,7 +76,7 @@ static void relocate_32bitbios(char *elfarray, uint32_t elfarraysize) */ reloc_size = reloc_off; printf("%d bytes of ROMBIOS high-memory extensions:\n", reloc_size); - highbiosarea = (char *)(long)e820_malloc(reloc_size); + highbiosarea = (char *)(long)e820_malloc(reloc_size, 0); BUG_ON(highbiosarea == NULL); printf(" Relocating to 0x%x-0x%x ... ", (uint32_t)&highbiosarea[0], diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c index e753bf3276..cb6e06d3f2 100644 --- a/tools/firmware/hvmloader/acpi/build.c +++ b/tools/firmware/hvmloader/acpi/build.c @@ -233,7 +233,7 @@ static int construct_secondary_tables(uint8_t *buf, unsigned long *table_ptrs) tcpa->header.oem_revision = ACPI_OEM_REVISION; tcpa->header.creator_id = ACPI_CREATOR_ID; tcpa->header.creator_revision = ACPI_CREATOR_REVISION; - tcpa->lasa = e820_malloc(ACPI_2_0_TCPA_LAML_SIZE); + tcpa->lasa = e820_malloc(ACPI_2_0_TCPA_LAML_SIZE, 0); if ( tcpa->lasa ) { tcpa->laml = ACPI_2_0_TCPA_LAML_SIZE; @@ -363,7 +363,7 @@ void acpi_build_tables(void) memset(buf, 0, high_sz); /* Allocate data area and set up ACPI tables there. */ - buf = (uint8_t *)e820_malloc(high_sz); + buf = (uint8_t *)e820_malloc(high_sz, 0); __acpi_build_tables(buf, &low_sz, &high_sz); printf(" - Lo data: %08lx-%08lx\n" diff --git a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c index decb1d2188..d12dc916b9 100644 --- a/tools/firmware/hvmloader/hvmloader.c +++ b/tools/firmware/hvmloader/hvmloader.c @@ -430,12 +430,14 @@ static void cmos_write_memory_size(void) cmos_outb(0x35, (uint8_t)( alt_mem >> 8)); } -static void init_xen_platform_io_base(void) +static uint16_t init_xen_platform_io_base(void) { struct bios_info *bios_info = (struct bios_info *)ACPI_PHYSICAL_ADDRESS; uint32_t devfn, bar_data; uint16_t vendor_id, device_id; + bios_info->xen_pfiob = 0; + for ( devfn = 0; devfn < 128; devfn++ ) { vendor_id = pci_readw(devfn, PCI_VENDOR_ID); @@ -445,12 +447,16 @@ static void init_xen_platform_io_base(void) bar_data = pci_readl(devfn, PCI_BASE_ADDRESS_0); bios_info->xen_pfiob = bar_data & PCI_BASE_ADDRESS_IO_MASK; } + + return bios_info->xen_pfiob; } int main(void) { int vgabios_sz = 0, etherboot_sz = 0, rombios_sz, smbios_sz; int extboot_sz = 0; + uint32_t vga_ram = 0; + uint16_t xen_pfiob; printf("HVM Loader\n"); @@ -497,6 +503,12 @@ int main(void) break; } + if ( virtual_vga != VGA_none ) + { + vga_ram = e820_malloc(8 << 20, 4096); + printf("VGA RAM at %08x\n", vga_ram); + } + etherboot_sz = scan_etherboot_nic((void*)ETHERBOOT_PHYSICAL_ADDRESS); if ( must_load_extboot() ) @@ -537,7 +549,9 @@ int main(void) ROMBIOS_PHYSICAL_ADDRESS, ROMBIOS_PHYSICAL_ADDRESS + rombios_sz - 1); - init_xen_platform_io_base(); + xen_pfiob = init_xen_platform_io_base(); + if ( xen_pfiob && vga_ram ) + outl(xen_pfiob + 4, vga_ram); printf("Invoking ROMBIOS ...\n"); return 0; diff --git a/tools/firmware/hvmloader/util.c b/tools/firmware/hvmloader/util.c index c98fd73049..1b2bdd9947 100644 --- a/tools/firmware/hvmloader/util.c +++ b/tools/firmware/hvmloader/util.c @@ -325,35 +325,34 @@ static void e820_collapse(void) } } -uint32_t e820_malloc(uint32_t size) +uint32_t e820_malloc(uint32_t size, uint32_t align) { uint32_t addr; int i; struct e820entry *ent = (struct e820entry *)HVM_E820; - /* Align allocation request to a reasonable boundary (1kB). */ - size = (size + 1023) & ~1023; + /* Align to at leats one kilobyte. */ + if ( align < 1024 ) + align = 1024; for ( i = *HVM_E820_NR - 1; i >= 0; i-- ) { - addr = ent[i].addr; + addr = (ent[i].size - size) & ~(align-1); if ( (ent[i].type != E820_RAM) || /* not ram? */ - (ent[i].size < size) || /* too small? */ - (addr != ent[i].addr) || /* starts above 4gb? */ + (addr < ent[i].addr) || /* too small or starts above 4gb? */ ((addr + size) < addr) ) /* ends above 4gb? */ continue; - if ( ent[i].size != size ) + if ( addr != ent[i].addr ) { memmove(&ent[i+1], &ent[i], (*HVM_E820_NR-i) * sizeof(*ent)); (*HVM_E820_NR)++; - ent[i].size -= size; - addr += ent[i].size; + ent[i].size = addr - ent[i].addr; + ent[i+1].addr = addr; + ent[i+1].size -= ent[i].size; i++; } - ent[i].addr = addr; - ent[i].size = size; ent[i].type = E820_RESERVED; e820_collapse(); diff --git a/tools/firmware/hvmloader/util.h b/tools/firmware/hvmloader/util.h index 957f25350e..81f0e4f4c4 100644 --- a/tools/firmware/hvmloader/util.h +++ b/tools/firmware/hvmloader/util.h @@ -132,7 +132,7 @@ int printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); int vprintf(const char *fmt, va_list ap); /* Reserve a RAM region in the e820 table. */ -uint32_t e820_malloc(uint32_t size); +uint32_t e820_malloc(uint32_t size, uint32_t align); /* Prepare the 32bit BIOS */ void highbios_setup(void); diff --git a/tools/ioemu/hw/cirrus_vga.c b/tools/ioemu/hw/cirrus_vga.c index 7b87b2b9cf..64ac7458fe 100644 --- a/tools/ioemu/hw/cirrus_vga.c +++ b/tools/ioemu/hw/cirrus_vga.c @@ -2543,34 +2543,28 @@ static CPUWriteMemoryFunc *cirrus_linear_bitblt_write[3] = { cirrus_linear_bitblt_writel, }; -static void *set_vram_mapping(unsigned long begin, unsigned long end) +static void set_vram_mapping(CirrusVGAState *s, unsigned long begin, unsigned long end) { - xen_pfn_t *extent_start = NULL; - unsigned long nr_extents; - void *vram_pointer = NULL; - int i; + unsigned long i; + struct xen_add_to_physmap xatp; + int rc; - /* align begin and end address */ - begin = begin & TARGET_PAGE_MASK; - end = begin + VGA_RAM_SIZE; - end = (end + TARGET_PAGE_SIZE -1 ) & TARGET_PAGE_MASK; - nr_extents = (end - begin) >> TARGET_PAGE_BITS; + if (end > begin + VGA_RAM_SIZE) + end = begin + VGA_RAM_SIZE; - extent_start = malloc(sizeof(xen_pfn_t) * nr_extents); - if (extent_start == NULL) { - fprintf(stderr, "Failed malloc on set_vram_mapping\n"); - return NULL; - } + fprintf(logfile,"mapping vram to %lx - %lx\n", begin, end); - memset(extent_start, 0, sizeof(xen_pfn_t) * nr_extents); + xatp.domid = domid; + xatp.space = XENMAPSPACE_mfn; - for (i = 0; i < nr_extents; i++) - extent_start[i] = (begin + i * TARGET_PAGE_SIZE) >> TARGET_PAGE_BITS; - - if (set_mm_mapping(xc_handle, domid, nr_extents, 0, extent_start) < 0) { - fprintf(logfile, "Failed set_mm_mapping\n"); - free(extent_start); - return NULL; + for (i = 0; i < (end - begin) >> TARGET_PAGE_BITS; i++) { + xatp.idx = s->vram_mfns[i]; + xatp.gpfn = (begin >> TARGET_PAGE_BITS) + i; + rc = xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp); + if (rc) { + fprintf(stderr, "add_to_physmap MFN %"PRI_xen_pfn" to PFN %"PRI_xen_pfn" failed: %d\n", xatp.idx, xatp.gpfn, rc); + return; + } } (void)xc_domain_pin_memory_cacheattr( @@ -2578,61 +2572,42 @@ static void *set_vram_mapping(unsigned long begin, unsigned long end) begin >> TARGET_PAGE_BITS, end >> TARGET_PAGE_BITS, XEN_DOMCTL_MEM_CACHEATTR_WB); - - vram_pointer = xc_map_foreign_pages(xc_handle, domid, - PROT_READ|PROT_WRITE, - extent_start, nr_extents); - if (vram_pointer == NULL) { - fprintf(logfile, "xc_map_foreign_batch vgaram returned error %d\n", - errno); - free(extent_start); - return NULL; - } - - memset(vram_pointer, 0, nr_extents * TARGET_PAGE_SIZE); - -#ifdef CONFIG_STUBDOM - xenfb_pv_display_start(vram_pointer); -#endif - - free(extent_start); - - return vram_pointer; } -static int unset_vram_mapping(unsigned long begin, unsigned long end, - void *mapping) +static void unset_vram_mapping(CirrusVGAState *s, unsigned long begin, unsigned long end) { - xen_pfn_t *extent_start = NULL; - unsigned long nr_extents; - int i; + if (s->stolen_vram_addr) { + /* We can put it there for xend to save it efficiently */ + set_vram_mapping(s, s->stolen_vram_addr, s->stolen_vram_addr + VGA_RAM_SIZE); + } else { + /* Old image, we have to unmap them completely */ + struct xen_remove_from_physmap xrfp; + unsigned long i; + int rc; - /* align begin and end address */ + if (end > begin + VGA_RAM_SIZE) + end = begin + VGA_RAM_SIZE; - end = begin + VGA_RAM_SIZE; - begin = begin & TARGET_PAGE_MASK; - end = (end + TARGET_PAGE_SIZE -1 ) & TARGET_PAGE_MASK; - nr_extents = (end - begin) >> TARGET_PAGE_BITS; + fprintf(logfile,"unmapping vram from %lx - %lx\n", begin, end); - extent_start = malloc(sizeof(xen_pfn_t) * nr_extents); + xrfp.domid = domid; - if (extent_start == NULL) { - fprintf(stderr, "Failed malloc on set_mm_mapping\n"); - return -1; + for (i = 0; i < (end - begin) >> TARGET_PAGE_BITS; i++) { + xrfp.gpfn = (begin >> TARGET_PAGE_BITS) + i; + rc = xc_memory_op(xc_handle, XENMEM_remove_from_physmap, &xrfp); + if (rc) { + fprintf(stderr, "remove_from_physmap PFN %"PRI_xen_pfn" failed: %d\n", xrfp.gpfn, rc); + return; + } + } } +} - /* Drop our own references to the vram pages */ - munmap(mapping, nr_extents * TARGET_PAGE_SIZE); - - /* Now drop the guest's mappings */ - memset(extent_start, 0, sizeof(xen_pfn_t) * nr_extents); - for (i = 0; i < nr_extents; i++) - extent_start[i] = (begin + (i * TARGET_PAGE_SIZE)) >> TARGET_PAGE_BITS; - unset_mm_mapping(xc_handle, domid, nr_extents, 0, extent_start); - - free(extent_start); - - return 0; +void cirrus_restart_acc(CirrusVGAState *s) +{ + set_vram_mapping(s, s->lfb_addr, s->lfb_end); + s->map_addr = s->lfb_addr; + s->map_end = s->lfb_end; } /* Compute the memory access functions */ @@ -2654,17 +2629,7 @@ static void cirrus_update_memory_access(CirrusVGAState *s) mode = s->gr[0x05] & 0x7; if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) { if (s->lfb_addr && s->lfb_end && !s->map_addr) { - void *vram_pointer, *old_vram; - - vram_pointer = set_vram_mapping(s->lfb_addr, - s->lfb_end); - if (!vram_pointer) - fprintf(stderr, "NULL vram_pointer\n"); - else { - old_vram = vga_update_vram((VGAState *)s, vram_pointer, - VGA_RAM_SIZE); - qemu_free(old_vram); - } + set_vram_mapping(s, s->lfb_addr, s->lfb_end); s->map_addr = s->lfb_addr; s->map_end = s->lfb_end; } @@ -2674,14 +2639,7 @@ static void cirrus_update_memory_access(CirrusVGAState *s) } else { generic_io: if (s->lfb_addr && s->lfb_end && s->map_addr) { - void *old_vram; - - old_vram = vga_update_vram((VGAState *)s, NULL, VGA_RAM_SIZE); - - unset_vram_mapping(s->lfb_addr, - s->lfb_end, - old_vram); - + unset_vram_mapping(s, s->map_addr, s->map_end); s->map_addr = s->map_end = 0; } s->cirrus_linear_write[0] = cirrus_linear_writeb; @@ -3040,36 +2998,6 @@ static CPUWriteMemoryFunc *cirrus_mmio_write[3] = { cirrus_mmio_writel, }; -void cirrus_stop_acc(CirrusVGAState *s) -{ - if (s->map_addr){ - int error; - s->map_addr = 0; - error = unset_vram_mapping(s->lfb_addr, - s->lfb_end, s->vram_ptr); - fprintf(stderr, "cirrus_stop_acc:unset_vram_mapping.\n"); - } -} - -void cirrus_restart_acc(CirrusVGAState *s) -{ - if (s->lfb_addr && s->lfb_end) { - void *vram_pointer, *old_vram; - fprintf(stderr, "cirrus_vga_load:re-enable vga acc.lfb_addr=0x%lx, lfb_end=0x%lx.\n", - s->lfb_addr, s->lfb_end); - vram_pointer = set_vram_mapping(s->lfb_addr ,s->lfb_end); - if (!vram_pointer){ - fprintf(stderr, "cirrus_vga_load:NULL vram_pointer\n"); - } else { - old_vram = vga_update_vram((VGAState *)s, vram_pointer, - VGA_RAM_SIZE); - qemu_free(old_vram); - s->map_addr = s->lfb_addr; - s->map_end = s->lfb_end; - } - } -} - /* load/save state */ static void cirrus_vga_save(QEMUFile *f, void *opaque) @@ -3118,7 +3046,10 @@ static void cirrus_vga_save(QEMUFile *f, void *opaque) qemu_put_8s(f, &vga_acc); qemu_put_be64s(f, (uint64_t*)&s->lfb_addr); qemu_put_be64s(f, (uint64_t*)&s->lfb_end); - qemu_put_buffer(f, s->vram_ptr, VGA_RAM_SIZE); + qemu_put_be64s(f, &s->stolen_vram_addr); + if (!s->stolen_vram_addr && !vga_acc) + /* Old guest: VRAM is not mapped, we have to save it ourselves */ + qemu_put_buffer(f, s->vram_ptr, VGA_RAM_SIZE); } static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id) @@ -3127,7 +3058,7 @@ static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id) uint8_t vga_acc = 0; int ret; - if (version_id > 2) + if (version_id > 3) return -EINVAL; if (s->pci_dev && version_id >= 2) { @@ -3173,9 +3104,20 @@ static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id) qemu_get_8s(f, &vga_acc); qemu_get_be64s(f, (uint64_t*)&s->lfb_addr); qemu_get_be64s(f, (uint64_t*)&s->lfb_end); - qemu_get_buffer(f, s->vram_ptr, VGA_RAM_SIZE); - if (vga_acc){ - cirrus_restart_acc(s); + if (version_id >= 3) { + qemu_get_be64s(f, &s->stolen_vram_addr); + if (!s->stolen_vram_addr && !vga_acc) { + /* Old guest, VRAM is not mapped, we have to restore it ourselves */ + qemu_get_buffer(f, s->vram_ptr, VGA_RAM_SIZE); + xen_vga_populate_vram(s->lfb_addr); + } else + xen_vga_vram_map(vga_acc ? s->lfb_addr : s->stolen_vram_addr, 0); + } else { + /* Old image, we have to populate and restore VRAM ourselves */ + xen_vga_populate_vram(s->lfb_addr); + qemu_get_buffer(f, s->vram_ptr, VGA_RAM_SIZE); + if (vga_acc) + cirrus_restart_acc(s); } /* force refresh */ @@ -3297,7 +3239,7 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) s->cursor_invalidate = cirrus_cursor_invalidate; s->cursor_draw_line = cirrus_cursor_draw_line; - register_savevm("cirrus_vga", 0, 2, cirrus_vga_save, cirrus_vga_load, s); + register_savevm("cirrus_vga", 0, 3, cirrus_vga_save, cirrus_vga_load, s); } /*************************************** diff --git a/tools/ioemu/hw/vga.c b/tools/ioemu/hw/vga.c index 6b1f7439bc..baf96faf51 100644 --- a/tools/ioemu/hw/vga.c +++ b/tools/ioemu/hw/vga.c @@ -23,6 +23,7 @@ */ #include "vl.h" #include "vga_int.h" +#include //#define DEBUG_VGA //#define DEBUG_VGA_MEM @@ -1776,7 +1777,10 @@ static void vga_save(QEMUFile *f, void *opaque) #endif vram_size = s->vram_size; qemu_put_be32s(f, &vram_size); - qemu_put_buffer(f, s->vram_ptr, s->vram_size); + qemu_put_be64s(f, &s->stolen_vram_addr); + if (!s->stolen_vram_addr) + /* Old guest: VRAM is not mapped, we have to save it ourselves */ + qemu_put_buffer(f, s->vram_ptr, VGA_RAM_SIZE); } static int vga_load(QEMUFile *f, void *opaque, int version_id) @@ -1788,7 +1792,7 @@ static int vga_load(QEMUFile *f, void *opaque, int version_id) int i; #endif - if (version_id > 3) + if (version_id > 4) return -EINVAL; if (s->pci_dev && version_id >= 2) { @@ -1839,7 +1843,14 @@ static int vga_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &vram_size); if (vram_size != s->vram_size) return -EINVAL; - qemu_get_buffer(f, s->vram_ptr, s->vram_size); + if (version_id >= 4) { + qemu_get_be64s(f, &s->stolen_vram_addr); + if (s->stolen_vram_addr) + xen_vga_vram_map(s->stolen_vram_addr, 0); + } + /* Old guest, VRAM is not mapped, we have to restore it ourselves */ + if (!s->stolen_vram_addr) + qemu_get_buffer(f, s->vram_ptr, s->vram_size); } /* force refresh */ @@ -1994,6 +2005,100 @@ void vga_bios_init(VGAState *s) /* TODO: add vbe support if enabled */ } + +static VGAState *xen_vga_state; + +/* When loading old images we have to populate the video ram ourselves */ +void xen_vga_populate_vram(uint64_t vram_addr) +{ + unsigned long nr_pfn; + struct xen_remove_from_physmap xrfp; + xen_pfn_t *pfn_list; + int i; + int rc; + + fprintf(logfile, "populating video RAM at %lx\n", vram_addr); + + nr_pfn = VGA_RAM_SIZE >> TARGET_PAGE_BITS; + + pfn_list = malloc(sizeof(*pfn_list) * nr_pfn); + + for (i = 0; i < nr_pfn; i++) + pfn_list[i] = (vram_addr >> TARGET_PAGE_BITS) + i; + + if (xc_domain_memory_populate_physmap(xc_handle, domid, nr_pfn, 0, 0, pfn_list)) { + fprintf(stderr, "Failed to populate video ram\n"); + exit(1); + } + free(pfn_list); + + xen_vga_vram_map(vram_addr, 0); + + /* Unmap them from the guest for now. */ + xrfp.domid = domid; + for (i = 0; i < nr_pfn; i++) { + xrfp.gpfn = (vram_addr >> TARGET_PAGE_BITS) + i; + rc = xc_memory_op(xc_handle, XENMEM_remove_from_physmap, &xrfp); + if (rc) { + fprintf(stderr, "remove_from_physmap PFN %"PRI_xen_pfn" failed: %d\n", xrfp.gpfn, rc); + break; + } + } +} + +/* Called once video memory has been allocated in the GPFN space */ +void xen_vga_vram_map(uint64_t vram_addr, int copy) +{ + unsigned long nr_pfn; + xen_pfn_t *pfn_list; + int i; + void *vram; + + fprintf(logfile, "mapping video RAM from %lx\n", vram_addr); + + nr_pfn = VGA_RAM_SIZE >> TARGET_PAGE_BITS; + + pfn_list = malloc(sizeof(*pfn_list) * nr_pfn); + + for (i = 0; i < nr_pfn; i++) + pfn_list[i] = (vram_addr >> TARGET_PAGE_BITS) + i; + + vram = xc_map_foreign_pages(xc_handle, domid, + PROT_READ|PROT_WRITE, + pfn_list, nr_pfn); + + if (!vram) { + fprintf(stderr, "Failed to map vram\n"); + exit(1); + } + + if (xc_domain_memory_translate_gpfn_list(xc_handle, domid, nr_pfn, + pfn_list, pfn_list)) { + fprintf(stderr, "Failed translation in xen_vga_vram_addr\n"); + exit(1); + } + + if (copy) + memcpy(vram, xen_vga_state->vram_ptr, VGA_RAM_SIZE); + qemu_free(xen_vga_state->vram_ptr); + xen_vga_state->vram_ptr = vram; + xen_vga_state->vram_mfns = pfn_list; +#ifdef CONFIG_STUBDOM + xenfb_pv_display_start(vram); +#endif +} + +/* Called at boot time when the BIOS has allocated video RAM */ +void xen_vga_stolen_vram_addr(uint64_t stolen_vram_addr) +{ + fprintf(logfile, "stolen video RAM at %lx\n", stolen_vram_addr); + + xen_vga_state->stolen_vram_addr = stolen_vram_addr; + + /* And copy from the initialization value */ + xen_vga_vram_map(stolen_vram_addr, 1); +} + /* when used on xen environment, the vga_ram_base is not used */ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size) @@ -2025,13 +2130,9 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, vga_reset(s); - /* Video RAM must be page-aligned for PVFB memory sharing */ - s->vram_ptr = s->vram_alloc = qemu_memalign(TARGET_PAGE_SIZE, vga_ram_size); - -#ifdef CONFIG_STUBDOM - if (!cirrus_vga_enabled) - xenfb_pv_display_start(s->vram_ptr); -#endif + s->vram_ptr = qemu_malloc(vga_ram_size); + s->vram_mfns = NULL; + xen_vga_state = s; s->vram_offset = vga_ram_offset; s->vram_size = vga_ram_size; @@ -2051,7 +2152,7 @@ static void vga_init(VGAState *s) { int vga_io_memory; - register_savevm("vga", 0, 3, vga_save, vga_load, s); + register_savevm("vga", 0, 4, vga_save, vga_load, s); register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s); @@ -2163,33 +2264,6 @@ int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, return 0; } -void *vga_update_vram(VGAState *s, void *vga_ram_base, int vga_ram_size) -{ - uint8_t *old_pointer; - - if (s->vram_size != vga_ram_size) { - fprintf(stderr, "No support to change vga_ram_size\n"); - return NULL; - } - - if (!vga_ram_base) { - vga_ram_base = qemu_memalign(TARGET_PAGE_SIZE, vga_ram_size + TARGET_PAGE_SIZE + 1); - if (!vga_ram_base) { - fprintf(stderr, "reallocate error\n"); - return NULL; - } - } - - /* XXX lock needed? */ - old_pointer = s->vram_alloc; - s->vram_alloc = vga_ram_base; - vga_ram_base = (uint8_t *)((long)(vga_ram_base + 15) & ~15L); - memcpy(vga_ram_base, s->vram_ptr, vga_ram_size); - s->vram_ptr = vga_ram_base; - - return old_pointer; -} - /********************************************************/ /* vga screen dump */ diff --git a/tools/ioemu/hw/vga_int.h b/tools/ioemu/hw/vga_int.h index fd223a644c..7b2f33f067 100644 --- a/tools/ioemu/hw/vga_int.h +++ b/tools/ioemu/hw/vga_int.h @@ -80,9 +80,9 @@ #define VGA_MAX_HEIGHT 2048 #define VGA_STATE_COMMON \ - uint8_t *vram_alloc; \ uint8_t *vram_ptr; \ - uint8_t *vram_shadow; \ + xen_pfn_t *vram_mfns; \ + uint64_t stolen_vram_addr; /* Address of stolen RAM */ \ unsigned long vram_offset; \ unsigned int vram_size; \ unsigned long bios_offset; \ diff --git a/tools/ioemu/hw/xen_platform.c b/tools/ioemu/hw/xen_platform.c index fe9b91b27f..cb34d63f7c 100644 --- a/tools/ioemu/hw/xen_platform.c +++ b/tools/ioemu/hw/xen_platform.c @@ -34,6 +34,7 @@ typedef struct PCIXenPlatformState { PCIDevice pci_dev; uint8_t platform_flags; + uint64_t vga_stolen_ram; } PCIXenPlatformState; static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr) @@ -69,11 +70,46 @@ static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val } +static uint32_t xen_platform_ioport_readl(void *opaque, uint32_t addr) +{ + PCIXenPlatformState *d = opaque; + + addr &= 0xff; + + switch (addr) { + case 4: /* VGA stolen memory address */ + return d->vga_stolen_ram; + default: + return ~0u; + } +} + +static void xen_platform_ioport_writel(void *opaque, uint32_t addr, uint32_t val) +{ + PCIXenPlatformState *d = opaque; + + addr &= 0xff; + val &= 0xffffffff; + + switch (addr) { + case 4: /* VGA stolen memory address */ + d->vga_stolen_ram = val; + xen_vga_stolen_vram_addr(val); + break; + default: + break; + } +} + + + static void platform_ioport_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { PCIXenPlatformState *d = (PCIXenPlatformState *)pci_dev; register_ioport_write(addr, size, 1, xen_platform_ioport_writeb, d); + register_ioport_write(addr, size, 4, xen_platform_ioport_writel, d); register_ioport_read(addr, size, 1, xen_platform_ioport_readb, d); + register_ioport_read(addr, size, 4, xen_platform_ioport_readl, d); } static uint32_t platform_mmio_read(void *opaque, target_phys_addr_t addr) @@ -155,6 +191,7 @@ void xen_pci_save(QEMUFile *f, void *opaque) pci_device_save(&d->pci_dev, f); qemu_put_8s(f, &d->platform_flags); + qemu_put_be64s(f, &d->vga_stolen_ram); } int xen_pci_load(QEMUFile *f, void *opaque, int version_id) @@ -173,6 +210,7 @@ int xen_pci_load(QEMUFile *f, void *opaque, int version_id) uint8_t flags; qemu_get_8s(f, &flags); xen_platform_ioport_writeb(d, 0, flags); + qemu_get_be64s(f, &d->vga_stolen_ram); } return 0; diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index 00507282d4..fc40a4c243 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -7023,38 +7023,6 @@ static BOOL WINAPI qemu_ctrl_handler(DWORD type) #include -/* FIXME Flush the shadow page */ -int unset_mm_mapping(int xc_handle, uint32_t domid, - unsigned long nr_pages, unsigned int address_bits, - xen_pfn_t *extent_start) -{ - int err = 0; - - err = xc_domain_memory_decrease_reservation(xc_handle, domid, - nr_pages, 0, extent_start); - if (err) - fprintf(stderr, "Failed to decrease physmap\n"); - - return err; -} - -int set_mm_mapping(int xc_handle, uint32_t domid, - unsigned long nr_pages, unsigned int address_bits, - xen_pfn_t *extent_start) -{ - int err = 0; - - err = xc_domain_memory_populate_physmap( - xc_handle, domid, nr_pages, 0, - XENMEMF_address_bits(address_bits), extent_start); - if (err) { - fprintf(stderr, "Failed to populate physmap\n"); - return -1; - } - - return 0; -} - int main(int argc, char **argv) { diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h index c0e2381030..ecaaef8721 100644 --- a/tools/ioemu/vl.h +++ b/tools/ioemu/vl.h @@ -1560,6 +1560,9 @@ void timeoffset_get(void); /* xen_platform.c */ #ifndef QEMU_TOOL void pci_xen_platform_init(PCIBus *bus); +void xen_vga_stolen_vram_addr(uint64_t vram_addr); +void xen_vga_populate_vram(uint64_t vram_addr); +void xen_vga_vram_map(uint64_t vram_addr, int copy); #endif /* pci_emulation.c */ diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index 551d8d1ada..767843b3ca 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -537,6 +537,33 @@ int xc_domain_memory_populate_physmap(int xc_handle, return err; } +int xc_domain_memory_translate_gpfn_list(int xc_handle, + uint32_t domid, + unsigned long nr_gpfns, + xen_pfn_t *gpfn_list, + xen_pfn_t *mfn_list) +{ + int err; + struct xen_translate_gpfn_list translate_gpfn_list = { + .domid = domid, + .nr_gpfns = nr_gpfns, + }; + set_xen_guest_handle(translate_gpfn_list.gpfn_list, gpfn_list); + set_xen_guest_handle(translate_gpfn_list.mfn_list, mfn_list); + + err = xc_memory_op(xc_handle, XENMEM_translate_gpfn_list, &translate_gpfn_list); + + if ( err != 0 ) + { + DPRINTF("Failed translation for dom %d (%ld PFNs)\n", + domid, nr_gpfns); + errno = -err; + err = -1; + } + + return err; +} + int xc_domain_max_vcpus(int xc_handle, uint32_t domid, unsigned int max) { DECLARE_DOMCTL; diff --git a/tools/libxc/xc_domain_save.c b/tools/libxc/xc_domain_save.c index 687e0d84fa..3046adf287 100644 --- a/tools/libxc/xc_domain_save.c +++ b/tools/libxc/xc_domain_save.c @@ -1111,12 +1111,6 @@ int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, (test_bit(n, to_fix) && last_iter)) ) continue; - /* Skip PFNs that aren't really there */ - if ( hvm && ((n >= 0xa0 && n < 0xc0) /* VGA hole */ - || (n >= (HVM_BELOW_4G_MMIO_START >> PAGE_SHIFT) - && n < (1ULL<<32) >> PAGE_SHIFT)) /* MMIO */ ) - continue; - /* ** we get here if: ** 1. page is marked to_send & hasn't already been re-dirtied diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index 341d117695..8b4ed304e5 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -628,6 +628,12 @@ int xc_domain_memory_populate_physmap(int xc_handle, unsigned int mem_flags, xen_pfn_t *extent_start); +int xc_domain_memory_translate_gpfn_list(int xc_handle, + uint32_t domid, + unsigned long nr_gpfns, + xen_pfn_t *gpfn_list, + xen_pfn_t *mfn_list); + int xc_domain_ioport_permission(int xc_handle, uint32_t domid, uint32_t first_port, diff --git a/xen/arch/ia64/xen/mm.c b/xen/arch/ia64/xen/mm.c index 385cac3189..6defe203e9 100644 --- a/xen/arch/ia64/xen/mm.c +++ b/xen/arch/ia64/xen/mm.c @@ -2698,6 +2698,20 @@ void put_page_type(struct page_info *page) } +static int get_page_from_pagenr(unsigned long page_nr, struct domain *d) +{ + struct page_info *page = mfn_to_page(page_nr); + + if ( unlikely(!mfn_valid(page_nr)) || unlikely(!get_page(page, d)) ) + { + MEM_LOG("Could not get page ref for pfn %lx", page_nr); + return 0; + } + + return 1; +} + + int get_page_type(struct page_info *page, u32 type) { u64 nx, x, y = page->u.inuse.type_info; @@ -2792,6 +2806,8 @@ int memory_is_conventional_ram(paddr_t p) long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) { + struct page_info *page = NULL; + switch (op) { case XENMEM_add_to_physmap: { @@ -2836,11 +2852,21 @@ arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) spin_unlock(&d->grant_table->lock); break; + case XENMAPSPACE_mfn: + { + if ( get_page_from_pagenr(xatp.idx, d) ) { + mfn = xatp.idx; + page = mfn_to_page(mfn); + } + break; + } default: break; } if (mfn == 0) { + if ( page ) + put_page(page); rcu_unlock_domain(d); return -EINVAL; } @@ -2872,12 +2898,54 @@ arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) out: domain_unlock(d); - + + if ( page ) + put_page(page); + rcu_unlock_domain(d); break; } + case XENMEM_remove_from_physmap: + { + struct xen_remove_from_physmap xrfp; + unsigned long mfn; + struct domain *d; + + if ( copy_from_guest(&xrfp, arg, 1) ) + return -EFAULT; + + if ( xrfp.domid == DOMID_SELF ) + { + d = rcu_lock_current_domain(); + } + else + { + if ( (d = rcu_lock_domain_by_id(xrfp.domid)) == NULL ) + return -ESRCH; + if ( !IS_PRIV_FOR(current->domain, d) ) + { + rcu_unlock_domain(d); + return -EPERM; + } + } + + domain_lock(d); + + mfn = gmfn_to_mfn(d, xrfp.gpfn); + + if ( mfn_valid(mfn) ) + guest_physmap_remove_page(d, xrfp.gpfn, mfn, 0); + + domain_unlock(d); + + rcu_unlock_domain(d); + + break; + } + + case XENMEM_machine_memory_map: { struct xen_memory_map memmap; diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 150d987514..b8723d688e 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -3339,6 +3339,7 @@ DEFINE_XEN_GUEST_HANDLE(e820entry_t); long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) { + struct page_info *page = NULL; switch ( op ) { case XENMEM_add_to_physmap: @@ -3389,12 +3390,22 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) spin_unlock(&d->grant_table->lock); break; + case XENMAPSPACE_mfn: + { + if ( get_page_from_pagenr(xatp.idx, d) ) { + mfn = xatp.idx; + page = mfn_to_page(mfn); + } + break; + } default: break; } if ( !paging_mode_translate(d) || (mfn == 0) ) { + if ( page ) + put_page(page); rcu_unlock_domain(d); return -EINVAL; } @@ -3423,6 +3434,53 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) domain_unlock(d); + if ( page ) + put_page(page); + + rcu_unlock_domain(d); + + break; + } + + case XENMEM_remove_from_physmap: + { + struct xen_remove_from_physmap xrfp; + unsigned long mfn; + struct domain *d; + + if ( copy_from_guest(&xrfp, arg, 1) ) + return -EFAULT; + + if ( xrfp.domid == DOMID_SELF ) + { + d = rcu_lock_current_domain(); + } + else + { + if ( (d = rcu_lock_domain_by_id(xrfp.domid)) == NULL ) + return -ESRCH; + if ( !IS_PRIV_FOR(current->domain, d) ) + { + rcu_unlock_domain(d); + return -EPERM; + } + } + + if ( xsm_remove_from_physmap(current->domain, d) ) + { + rcu_unlock_domain(d); + return -EPERM; + } + + domain_lock(d); + + mfn = gmfn_to_mfn(d, xrfp.gpfn); + + if ( mfn_valid(mfn) ) + guest_physmap_remove_page(d, xrfp.gpfn, mfn, 0); + + domain_unlock(d); + rcu_unlock_domain(d); break; diff --git a/xen/arch/x86/x86_64/compat/mm.c b/xen/arch/x86/x86_64/compat/mm.c index 96030f924d..913760c14f 100644 --- a/xen/arch/x86/x86_64/compat/mm.c +++ b/xen/arch/x86/x86_64/compat/mm.c @@ -69,6 +69,20 @@ int compat_arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) break; } + case XENMEM_remove_from_physmap: + { + struct compat_remove_from_physmap cmp; + struct xen_remove_from_physmap *nat = (void *)COMPAT_ARG_XLAT_VIRT_BASE; + + if ( copy_from_guest(&cmp, arg, 1) ) + return -EFAULT; + + XLAT_remove_from_physmap(nat, &cmp); + rc = arch_memory_op(op, guest_handle_from_ptr(nat, void)); + + break; + } + case XENMEM_set_memory_map: { struct compat_foreign_memory_map cmp; diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h index ccf73fa43c..d7b9fff972 100644 --- a/xen/include/public/memory.h +++ b/xen/include/public/memory.h @@ -204,6 +204,7 @@ struct xen_add_to_physmap { /* Source mapping space. */ #define XENMAPSPACE_shared_info 0 /* shared info page */ #define XENMAPSPACE_grant_table 1 /* grant table page */ +#define XENMAPSPACE_mfn 2 /* usual MFN */ unsigned int space; /* Index into source mapping space. */ @@ -215,6 +216,22 @@ struct xen_add_to_physmap { typedef struct xen_add_to_physmap xen_add_to_physmap_t; DEFINE_XEN_GUEST_HANDLE(xen_add_to_physmap_t); +/* + * Unmaps the page appearing at a particular GPFN from the specified guest's + * pseudophysical address space. + * arg == addr of xen_remove_from_physmap_t. + */ +#define XENMEM_remove_from_physmap 15 +struct xen_remove_from_physmap { + /* Which domain to change the mapping for. */ + domid_t domid; + + /* GPFN of the current mapping of the page. */ + xen_pfn_t gpfn; +}; +typedef struct xen_remove_from_physmap xen_remove_from_physmap_t; +DEFINE_XEN_GUEST_HANDLE(xen_remove_from_physmap_t); + /* * Translates a list of domain-specific GPFNs into MFNs. Returns a -ve error * code on failure. This call only works for auto-translated guests. diff --git a/xen/include/xlat.lst b/xen/include/xlat.lst index 7b9a7ad9e1..6f0b662b00 100644 --- a/xen/include/xlat.lst +++ b/xen/include/xlat.lst @@ -33,6 +33,7 @@ ! kexec_image kexec.h ! kexec_range kexec.h ! add_to_physmap memory.h +! remove_from_physmap memory.h ! foreign_memory_map memory.h ! memory_exchange memory.h ! memory_map memory.h diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index 7277e18c99..f12a700aa9 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -136,6 +136,7 @@ struct xsm_operations { int (*mmu_machphys_update) (struct domain *d, unsigned long mfn); int (*update_va_mapping) (struct domain *d, l1_pgentry_t pte); int (*add_to_physmap) (struct domain *d1, struct domain *d2); + int (*remove_from_physmap) (struct domain *d1, struct domain *d2); #endif }; @@ -532,6 +533,11 @@ static inline int xsm_add_to_physmap(struct domain *d1, struct domain *d2) { return xsm_call(add_to_physmap(d1, d2)); } + +static inline int xsm_remove_from_physmap(struct domain *d1, struct domain *d2) +{ + return xsm_call(remove_from_physmap(d1, d2)); +} #endif /* CONFIG_X86 */ #endif /* __XSM_H */ diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c index b9ff510b42..345172283a 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -385,6 +385,11 @@ static int dummy_add_to_physmap (struct domain *d1, struct domain *d2) { return 0; } + +static int dummy_remove_from_physmap (struct domain *d1, struct domain *d2) +{ + return 0; +} #endif struct xsm_operations dummy_xsm_ops; @@ -484,5 +489,6 @@ void xsm_fixup_ops (struct xsm_operations *ops) set_to_dummy_if_null(ops, mmu_machphys_update); set_to_dummy_if_null(ops, update_va_mapping); set_to_dummy_if_null(ops, add_to_physmap); + set_to_dummy_if_null(ops, remove_from_physmap); #endif } diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index a7553c1250..9f77d99a82 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -1028,6 +1028,11 @@ static int flask_add_to_physmap(struct domain *d1, struct domain *d2) { return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__PHYSMAP); } + +static int flask_remove_from_physmap(struct domain *d1, struct domain *d2) +{ + return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__PHYSMAP); +} #endif long do_flask_op(XEN_GUEST_HANDLE(xsm_op_t) u_flask_op); @@ -1115,6 +1120,7 @@ static struct xsm_operations flask_ops = { .mmu_machphys_update = flask_mmu_machphys_update, .update_va_mapping = flask_update_va_mapping, .add_to_physmap = flask_add_to_physmap, + .remove_from_physmap = flask_remove_from_physmap, #endif };