Revision 6152e2ae
b/kvm-all.c | ||
---|---|---|
98 | 98 |
return NULL; |
99 | 99 |
} |
100 | 100 |
|
101 |
static KVMSlot *kvm_lookup_slot(KVMState *s, target_phys_addr_t start_addr) |
|
101 |
/* |
|
102 |
* Find overlapping slot with lowest start address |
|
103 |
*/ |
|
104 |
static KVMSlot *kvm_lookup_overlapping_slot(KVMState *s, |
|
105 |
target_phys_addr_t start_addr, |
|
106 |
target_phys_addr_t end_addr) |
|
102 | 107 |
{ |
108 |
KVMSlot *found = NULL; |
|
103 | 109 |
int i; |
104 | 110 |
|
105 | 111 |
for (i = 0; i < ARRAY_SIZE(s->slots); i++) { |
106 | 112 |
KVMSlot *mem = &s->slots[i]; |
107 | 113 |
|
108 |
if (start_addr >= mem->start_addr && |
|
109 |
start_addr < (mem->start_addr + mem->memory_size)) |
|
110 |
return mem; |
|
114 |
if (mem->memory_size == 0 || |
|
115 |
(found && found->start_addr < mem->start_addr)) { |
|
116 |
continue; |
|
117 |
} |
|
118 |
|
|
119 |
if (end_addr > mem->start_addr && |
|
120 |
start_addr < mem->start_addr + mem->memory_size) { |
|
121 |
found = mem; |
|
122 |
} |
|
111 | 123 |
} |
112 | 124 |
|
113 |
return NULL;
|
|
125 |
return found;
|
|
114 | 126 |
} |
115 | 127 |
|
116 | 128 |
static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot) |
... | ... | |
567 | 579 |
{ |
568 | 580 |
KVMState *s = kvm_state; |
569 | 581 |
ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK; |
570 |
KVMSlot *mem; |
|
582 |
KVMSlot *mem, old; |
|
583 |
int err; |
|
571 | 584 |
|
572 | 585 |
if (start_addr & ~TARGET_PAGE_MASK) { |
573 | 586 |
fprintf(stderr, "Only page-aligned memory slots supported\n"); |
... | ... | |
577 | 590 |
/* KVM does not support read-only slots */ |
578 | 591 |
phys_offset &= ~IO_MEM_ROM; |
579 | 592 |
|
580 |
mem = kvm_lookup_slot(s, start_addr); |
|
581 |
if (mem) { |
|
582 |
if (flags >= IO_MEM_UNASSIGNED) { |
|
583 |
mem->memory_size = 0; |
|
584 |
mem->start_addr = start_addr; |
|
585 |
mem->phys_offset = 0; |
|
586 |
mem->flags = 0; |
|
587 |
|
|
588 |
kvm_set_user_memory_region(s, mem); |
|
589 |
} else if (start_addr >= mem->start_addr && |
|
590 |
(start_addr + size) <= (mem->start_addr + |
|
591 |
mem->memory_size)) { |
|
592 |
KVMSlot slot; |
|
593 |
target_phys_addr_t mem_start; |
|
594 |
ram_addr_t mem_size, mem_offset; |
|
595 |
|
|
596 |
/* Not splitting */ |
|
597 |
if ((phys_offset - (start_addr - mem->start_addr)) == |
|
598 |
mem->phys_offset) |
|
599 |
return; |
|
600 |
|
|
601 |
/* unregister whole slot */ |
|
602 |
memcpy(&slot, mem, sizeof(slot)); |
|
603 |
mem->memory_size = 0; |
|
604 |
kvm_set_user_memory_region(s, mem); |
|
605 |
|
|
606 |
/* register prefix slot */ |
|
607 |
mem_start = slot.start_addr; |
|
608 |
mem_size = start_addr - slot.start_addr; |
|
609 |
mem_offset = slot.phys_offset; |
|
610 |
if (mem_size) |
|
611 |
kvm_set_phys_mem(mem_start, mem_size, mem_offset); |
|
612 |
|
|
613 |
/* register new slot */ |
|
614 |
kvm_set_phys_mem(start_addr, size, phys_offset); |
|
615 |
|
|
616 |
/* register suffix slot */ |
|
617 |
mem_start = start_addr + size; |
|
618 |
mem_offset += mem_size + size; |
|
619 |
mem_size = slot.memory_size - mem_size - size; |
|
620 |
if (mem_size) |
|
621 |
kvm_set_phys_mem(mem_start, mem_size, mem_offset); |
|
593 |
while (1) { |
|
594 |
mem = kvm_lookup_overlapping_slot(s, start_addr, start_addr + size); |
|
595 |
if (!mem) { |
|
596 |
break; |
|
597 |
} |
|
622 | 598 |
|
599 |
if (flags < IO_MEM_UNASSIGNED && start_addr >= mem->start_addr && |
|
600 |
(start_addr + size <= mem->start_addr + mem->memory_size) && |
|
601 |
(phys_offset - start_addr == mem->phys_offset - mem->start_addr)) { |
|
602 |
/* The new slot fits into the existing one and comes with |
|
603 |
* identical parameters - nothing to be done. */ |
|
623 | 604 |
return; |
624 |
} else { |
|
625 |
printf("Registering overlapping slot\n"); |
|
605 |
} |
|
606 |
|
|
607 |
old = *mem; |
|
608 |
|
|
609 |
/* unregister the overlapping slot */ |
|
610 |
mem->memory_size = 0; |
|
611 |
err = kvm_set_user_memory_region(s, mem); |
|
612 |
if (err) { |
|
613 |
fprintf(stderr, "%s: error unregistering overlapping slot: %s\n", |
|
614 |
__func__, strerror(-err)); |
|
626 | 615 |
abort(); |
627 | 616 |
} |
617 |
|
|
618 |
/* Workaround for older KVM versions: we can't join slots, even not by |
|
619 |
* unregistering the previous ones and then registering the larger |
|
620 |
* slot. We have to maintain the existing fragmentation. Sigh. |
|
621 |
* |
|
622 |
* This workaround assumes that the new slot starts at the same |
|
623 |
* address as the first existing one. If not or if some overlapping |
|
624 |
* slot comes around later, we will fail (not seen in practice so far) |
|
625 |
* - and actually require a recent KVM version. */ |
|
626 |
if (old.start_addr == start_addr && old.memory_size < size && |
|
627 |
flags < IO_MEM_UNASSIGNED) { |
|
628 |
mem = kvm_alloc_slot(s); |
|
629 |
mem->memory_size = old.memory_size; |
|
630 |
mem->start_addr = old.start_addr; |
|
631 |
mem->phys_offset = old.phys_offset; |
|
632 |
mem->flags = 0; |
|
633 |
|
|
634 |
err = kvm_set_user_memory_region(s, mem); |
|
635 |
if (err) { |
|
636 |
fprintf(stderr, "%s: error updating slot: %s\n", __func__, |
|
637 |
strerror(-err)); |
|
638 |
abort(); |
|
639 |
} |
|
640 |
|
|
641 |
start_addr += old.memory_size; |
|
642 |
phys_offset += old.memory_size; |
|
643 |
size -= old.memory_size; |
|
644 |
continue; |
|
645 |
} |
|
646 |
|
|
647 |
/* register prefix slot */ |
|
648 |
if (old.start_addr < start_addr) { |
|
649 |
mem = kvm_alloc_slot(s); |
|
650 |
mem->memory_size = start_addr - old.start_addr; |
|
651 |
mem->start_addr = old.start_addr; |
|
652 |
mem->phys_offset = old.phys_offset; |
|
653 |
mem->flags = 0; |
|
654 |
|
|
655 |
err = kvm_set_user_memory_region(s, mem); |
|
656 |
if (err) { |
|
657 |
fprintf(stderr, "%s: error registering prefix slot: %s\n", |
|
658 |
__func__, strerror(-err)); |
|
659 |
abort(); |
|
660 |
} |
|
661 |
} |
|
662 |
|
|
663 |
/* register suffix slot */ |
|
664 |
if (old.start_addr + old.memory_size > start_addr + size) { |
|
665 |
ram_addr_t size_delta; |
|
666 |
|
|
667 |
mem = kvm_alloc_slot(s); |
|
668 |
mem->start_addr = start_addr + size; |
|
669 |
size_delta = mem->start_addr - old.start_addr; |
|
670 |
mem->memory_size = old.memory_size - size_delta; |
|
671 |
mem->phys_offset = old.phys_offset + size_delta; |
|
672 |
mem->flags = 0; |
|
673 |
|
|
674 |
err = kvm_set_user_memory_region(s, mem); |
|
675 |
if (err) { |
|
676 |
fprintf(stderr, "%s: error registering suffix slot: %s\n", |
|
677 |
__func__, strerror(-err)); |
|
678 |
abort(); |
|
679 |
} |
|
680 |
} |
|
628 | 681 |
} |
682 |
|
|
683 |
/* in case the KVM bug workaround already "consumed" the new slot */ |
|
684 |
if (!size) |
|
685 |
return; |
|
686 |
|
|
629 | 687 |
/* KVM does not need to know about this memory */ |
630 | 688 |
if (flags >= IO_MEM_UNASSIGNED) |
631 | 689 |
return; |
... | ... | |
636 | 694 |
mem->phys_offset = phys_offset; |
637 | 695 |
mem->flags = 0; |
638 | 696 |
|
639 |
kvm_set_user_memory_region(s, mem); |
|
640 |
/* FIXME deal with errors */ |
|
697 |
err = kvm_set_user_memory_region(s, mem); |
|
698 |
if (err) { |
|
699 |
fprintf(stderr, "%s: error registering slot: %s\n", __func__, |
|
700 |
strerror(-err)); |
|
701 |
abort(); |
|
702 |
} |
|
641 | 703 |
} |
642 | 704 |
|
643 | 705 |
int kvm_ioctl(KVMState *s, int type, ...) |
Also available in: Unified diff