*/
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],
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;
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"
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);
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");
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() )
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;
}
}
-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();
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);
cirrus_linear_bitblt_writel,
};
-static void *set_vram_mapping(unsigned long begin, unsigned long end)
-{
- xen_pfn_t *extent_start = NULL;
- unsigned long nr_extents;
- void *vram_pointer = NULL;
- int i;
-
- /* 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;
-
- extent_start = malloc(sizeof(xen_pfn_t) * nr_extents);
- if (extent_start == NULL) {
- fprintf(stderr, "Failed malloc on set_vram_mapping\n");
- return NULL;
- }
+static void set_vram_mapping(CirrusVGAState *s, unsigned long begin, unsigned long end)
+{
+ unsigned long i;
+ struct xen_add_to_physmap xatp;
+ int rc;
+
+ if (end > begin + VGA_RAM_SIZE)
+ end = begin + VGA_RAM_SIZE;
- memset(extent_start, 0, sizeof(xen_pfn_t) * nr_extents);
+ fprintf(logfile,"mapping vram to %lx - %lx\n", begin, end);
- for (i = 0; i < nr_extents; i++)
- extent_start[i] = (begin + i * TARGET_PAGE_SIZE) >> TARGET_PAGE_BITS;
+ xatp.domid = domid;
+ xatp.space = XENMAPSPACE_mfn;
- 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(
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 */
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;
}
} 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;
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)
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)
uint8_t vga_acc = 0;
int ret;
- if (version_id > 2)
+ if (version_id > 3)
return -EINVAL;
if (s->pci_dev && version_id >= 2) {
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 */
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);
}
/***************************************
*/
#include "vl.h"
#include "vga_int.h"
+#include <sys/mman.h>
//#define DEBUG_VGA
//#define DEBUG_VGA_MEM
#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)
int i;
#endif
- if (version_id > 3)
+ if (version_id > 4)
return -EINVAL;
if (s->pci_dev && version_id >= 2) {
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 */
/* 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)
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;
{
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);
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 */
#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; \
{
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)
}
+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)
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)
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;
#include <xg_private.h>
-/* 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)
{
/* 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 */
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;
(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
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,
}
+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;
long
arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
{
+ struct page_info *page = NULL;
+
switch (op) {
case XENMEM_add_to_physmap:
{
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;
}
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;
long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
{
+ struct page_info *page = NULL;
switch ( op )
{
case XENMEM_add_to_physmap:
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;
}
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;
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;
/* 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. */
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.
! 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
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
};
{
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 */
{
return 0;
}
+
+static int dummy_remove_from_physmap (struct domain *d1, struct domain *d2)
+{
+ return 0;
+}
#endif
struct xsm_operations dummy_xsm_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
}
{
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);
.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
};