kvm: move kvm_set_phys_mem around
move kvm_set_phys_mem so that it will be later available earlier in the file. needed for next patch using memory notifiers. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Acked-by: Avi Kivity <avi@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
parent
f6f3fbcab0
commit
46dbef6ade
276
kvm-all.c
276
kvm-all.c
@ -402,6 +402,144 @@ int kvm_check_extension(KVMState *s, unsigned int extension)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void kvm_set_phys_mem(target_phys_addr_t start_addr,
|
||||||
|
ram_addr_t size,
|
||||||
|
ram_addr_t phys_offset)
|
||||||
|
{
|
||||||
|
KVMState *s = kvm_state;
|
||||||
|
ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
|
||||||
|
KVMSlot *mem, old;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (start_addr & ~TARGET_PAGE_MASK) {
|
||||||
|
if (flags >= IO_MEM_UNASSIGNED) {
|
||||||
|
if (!kvm_lookup_overlapping_slot(s, start_addr,
|
||||||
|
start_addr + size)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "Unaligned split of a KVM memory slot\n");
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Only page-aligned memory slots supported\n");
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* KVM does not support read-only slots */
|
||||||
|
phys_offset &= ~IO_MEM_ROM;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
mem = kvm_lookup_overlapping_slot(s, start_addr, start_addr + size);
|
||||||
|
if (!mem) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags < IO_MEM_UNASSIGNED && start_addr >= mem->start_addr &&
|
||||||
|
(start_addr + size <= mem->start_addr + mem->memory_size) &&
|
||||||
|
(phys_offset - start_addr == mem->phys_offset - mem->start_addr)) {
|
||||||
|
/* The new slot fits into the existing one and comes with
|
||||||
|
* identical parameters - nothing to be done. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
old = *mem;
|
||||||
|
|
||||||
|
/* unregister the overlapping slot */
|
||||||
|
mem->memory_size = 0;
|
||||||
|
err = kvm_set_user_memory_region(s, mem);
|
||||||
|
if (err) {
|
||||||
|
fprintf(stderr, "%s: error unregistering overlapping slot: %s\n",
|
||||||
|
__func__, strerror(-err));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Workaround for older KVM versions: we can't join slots, even not by
|
||||||
|
* unregistering the previous ones and then registering the larger
|
||||||
|
* slot. We have to maintain the existing fragmentation. Sigh.
|
||||||
|
*
|
||||||
|
* This workaround assumes that the new slot starts at the same
|
||||||
|
* address as the first existing one. If not or if some overlapping
|
||||||
|
* slot comes around later, we will fail (not seen in practice so far)
|
||||||
|
* - and actually require a recent KVM version. */
|
||||||
|
if (s->broken_set_mem_region &&
|
||||||
|
old.start_addr == start_addr && old.memory_size < size &&
|
||||||
|
flags < IO_MEM_UNASSIGNED) {
|
||||||
|
mem = kvm_alloc_slot(s);
|
||||||
|
mem->memory_size = old.memory_size;
|
||||||
|
mem->start_addr = old.start_addr;
|
||||||
|
mem->phys_offset = old.phys_offset;
|
||||||
|
mem->flags = 0;
|
||||||
|
|
||||||
|
err = kvm_set_user_memory_region(s, mem);
|
||||||
|
if (err) {
|
||||||
|
fprintf(stderr, "%s: error updating slot: %s\n", __func__,
|
||||||
|
strerror(-err));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
start_addr += old.memory_size;
|
||||||
|
phys_offset += old.memory_size;
|
||||||
|
size -= old.memory_size;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* register prefix slot */
|
||||||
|
if (old.start_addr < start_addr) {
|
||||||
|
mem = kvm_alloc_slot(s);
|
||||||
|
mem->memory_size = start_addr - old.start_addr;
|
||||||
|
mem->start_addr = old.start_addr;
|
||||||
|
mem->phys_offset = old.phys_offset;
|
||||||
|
mem->flags = 0;
|
||||||
|
|
||||||
|
err = kvm_set_user_memory_region(s, mem);
|
||||||
|
if (err) {
|
||||||
|
fprintf(stderr, "%s: error registering prefix slot: %s\n",
|
||||||
|
__func__, strerror(-err));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* register suffix slot */
|
||||||
|
if (old.start_addr + old.memory_size > start_addr + size) {
|
||||||
|
ram_addr_t size_delta;
|
||||||
|
|
||||||
|
mem = kvm_alloc_slot(s);
|
||||||
|
mem->start_addr = start_addr + size;
|
||||||
|
size_delta = mem->start_addr - old.start_addr;
|
||||||
|
mem->memory_size = old.memory_size - size_delta;
|
||||||
|
mem->phys_offset = old.phys_offset + size_delta;
|
||||||
|
mem->flags = 0;
|
||||||
|
|
||||||
|
err = kvm_set_user_memory_region(s, mem);
|
||||||
|
if (err) {
|
||||||
|
fprintf(stderr, "%s: error registering suffix slot: %s\n",
|
||||||
|
__func__, strerror(-err));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* in case the KVM bug workaround already "consumed" the new slot */
|
||||||
|
if (!size)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* KVM does not need to know about this memory */
|
||||||
|
if (flags >= IO_MEM_UNASSIGNED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mem = kvm_alloc_slot(s);
|
||||||
|
mem->memory_size = size;
|
||||||
|
mem->start_addr = start_addr;
|
||||||
|
mem->phys_offset = phys_offset;
|
||||||
|
mem->flags = 0;
|
||||||
|
|
||||||
|
err = kvm_set_user_memory_region(s, mem);
|
||||||
|
if (err) {
|
||||||
|
fprintf(stderr, "%s: error registering slot: %s\n", __func__,
|
||||||
|
strerror(-err));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int kvm_init(int smp_cpus)
|
int kvm_init(int smp_cpus)
|
||||||
{
|
{
|
||||||
static const char upgrade_note[] =
|
static const char upgrade_note[] =
|
||||||
@ -680,144 +818,6 @@ int kvm_cpu_exec(CPUState *env)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void kvm_set_phys_mem(target_phys_addr_t start_addr,
|
|
||||||
ram_addr_t size,
|
|
||||||
ram_addr_t phys_offset)
|
|
||||||
{
|
|
||||||
KVMState *s = kvm_state;
|
|
||||||
ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
|
|
||||||
KVMSlot *mem, old;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (start_addr & ~TARGET_PAGE_MASK) {
|
|
||||||
if (flags >= IO_MEM_UNASSIGNED) {
|
|
||||||
if (!kvm_lookup_overlapping_slot(s, start_addr,
|
|
||||||
start_addr + size)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fprintf(stderr, "Unaligned split of a KVM memory slot\n");
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Only page-aligned memory slots supported\n");
|
|
||||||
}
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* KVM does not support read-only slots */
|
|
||||||
phys_offset &= ~IO_MEM_ROM;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
mem = kvm_lookup_overlapping_slot(s, start_addr, start_addr + size);
|
|
||||||
if (!mem) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags < IO_MEM_UNASSIGNED && start_addr >= mem->start_addr &&
|
|
||||||
(start_addr + size <= mem->start_addr + mem->memory_size) &&
|
|
||||||
(phys_offset - start_addr == mem->phys_offset - mem->start_addr)) {
|
|
||||||
/* The new slot fits into the existing one and comes with
|
|
||||||
* identical parameters - nothing to be done. */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
old = *mem;
|
|
||||||
|
|
||||||
/* unregister the overlapping slot */
|
|
||||||
mem->memory_size = 0;
|
|
||||||
err = kvm_set_user_memory_region(s, mem);
|
|
||||||
if (err) {
|
|
||||||
fprintf(stderr, "%s: error unregistering overlapping slot: %s\n",
|
|
||||||
__func__, strerror(-err));
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Workaround for older KVM versions: we can't join slots, even not by
|
|
||||||
* unregistering the previous ones and then registering the larger
|
|
||||||
* slot. We have to maintain the existing fragmentation. Sigh.
|
|
||||||
*
|
|
||||||
* This workaround assumes that the new slot starts at the same
|
|
||||||
* address as the first existing one. If not or if some overlapping
|
|
||||||
* slot comes around later, we will fail (not seen in practice so far)
|
|
||||||
* - and actually require a recent KVM version. */
|
|
||||||
if (s->broken_set_mem_region &&
|
|
||||||
old.start_addr == start_addr && old.memory_size < size &&
|
|
||||||
flags < IO_MEM_UNASSIGNED) {
|
|
||||||
mem = kvm_alloc_slot(s);
|
|
||||||
mem->memory_size = old.memory_size;
|
|
||||||
mem->start_addr = old.start_addr;
|
|
||||||
mem->phys_offset = old.phys_offset;
|
|
||||||
mem->flags = 0;
|
|
||||||
|
|
||||||
err = kvm_set_user_memory_region(s, mem);
|
|
||||||
if (err) {
|
|
||||||
fprintf(stderr, "%s: error updating slot: %s\n", __func__,
|
|
||||||
strerror(-err));
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
start_addr += old.memory_size;
|
|
||||||
phys_offset += old.memory_size;
|
|
||||||
size -= old.memory_size;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* register prefix slot */
|
|
||||||
if (old.start_addr < start_addr) {
|
|
||||||
mem = kvm_alloc_slot(s);
|
|
||||||
mem->memory_size = start_addr - old.start_addr;
|
|
||||||
mem->start_addr = old.start_addr;
|
|
||||||
mem->phys_offset = old.phys_offset;
|
|
||||||
mem->flags = 0;
|
|
||||||
|
|
||||||
err = kvm_set_user_memory_region(s, mem);
|
|
||||||
if (err) {
|
|
||||||
fprintf(stderr, "%s: error registering prefix slot: %s\n",
|
|
||||||
__func__, strerror(-err));
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* register suffix slot */
|
|
||||||
if (old.start_addr + old.memory_size > start_addr + size) {
|
|
||||||
ram_addr_t size_delta;
|
|
||||||
|
|
||||||
mem = kvm_alloc_slot(s);
|
|
||||||
mem->start_addr = start_addr + size;
|
|
||||||
size_delta = mem->start_addr - old.start_addr;
|
|
||||||
mem->memory_size = old.memory_size - size_delta;
|
|
||||||
mem->phys_offset = old.phys_offset + size_delta;
|
|
||||||
mem->flags = 0;
|
|
||||||
|
|
||||||
err = kvm_set_user_memory_region(s, mem);
|
|
||||||
if (err) {
|
|
||||||
fprintf(stderr, "%s: error registering suffix slot: %s\n",
|
|
||||||
__func__, strerror(-err));
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* in case the KVM bug workaround already "consumed" the new slot */
|
|
||||||
if (!size)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* KVM does not need to know about this memory */
|
|
||||||
if (flags >= IO_MEM_UNASSIGNED)
|
|
||||||
return;
|
|
||||||
|
|
||||||
mem = kvm_alloc_slot(s);
|
|
||||||
mem->memory_size = size;
|
|
||||||
mem->start_addr = start_addr;
|
|
||||||
mem->phys_offset = phys_offset;
|
|
||||||
mem->flags = 0;
|
|
||||||
|
|
||||||
err = kvm_set_user_memory_region(s, mem);
|
|
||||||
if (err) {
|
|
||||||
fprintf(stderr, "%s: error registering slot: %s\n", __func__,
|
|
||||||
strerror(-err));
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int kvm_ioctl(KVMState *s, int type, ...)
|
int kvm_ioctl(KVMState *s, int type, ...)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
Loading…
Reference in New Issue
Block a user