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