Revision 46dbef6a kvm-all.c
b/kvm-all.c | ||
---|---|---|
402 | 402 |
return ret; |
403 | 403 |
} |
404 | 404 |
|
405 |
void kvm_set_phys_mem(target_phys_addr_t start_addr, |
|
406 |
ram_addr_t size, |
|
407 |
ram_addr_t phys_offset) |
|
408 |
{ |
|
409 |
KVMState *s = kvm_state; |
|
410 |
ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK; |
|
411 |
KVMSlot *mem, old; |
|
412 |
int err; |
|
413 |
|
|
414 |
if (start_addr & ~TARGET_PAGE_MASK) { |
|
415 |
if (flags >= IO_MEM_UNASSIGNED) { |
|
416 |
if (!kvm_lookup_overlapping_slot(s, start_addr, |
|
417 |
start_addr + size)) { |
|
418 |
return; |
|
419 |
} |
|
420 |
fprintf(stderr, "Unaligned split of a KVM memory slot\n"); |
|
421 |
} else { |
|
422 |
fprintf(stderr, "Only page-aligned memory slots supported\n"); |
|
423 |
} |
|
424 |
abort(); |
|
425 |
} |
|
426 |
|
|
427 |
/* KVM does not support read-only slots */ |
|
428 |
phys_offset &= ~IO_MEM_ROM; |
|
429 |
|
|
430 |
while (1) { |
|
431 |
mem = kvm_lookup_overlapping_slot(s, start_addr, start_addr + size); |
|
432 |
if (!mem) { |
|
433 |
break; |
|
434 |
} |
|
435 |
|
|
436 |
if (flags < IO_MEM_UNASSIGNED && start_addr >= mem->start_addr && |
|
437 |
(start_addr + size <= mem->start_addr + mem->memory_size) && |
|
438 |
(phys_offset - start_addr == mem->phys_offset - mem->start_addr)) { |
|
439 |
/* The new slot fits into the existing one and comes with |
|
440 |
* identical parameters - nothing to be done. */ |
|
441 |
return; |
|
442 |
} |
|
443 |
|
|
444 |
old = *mem; |
|
445 |
|
|
446 |
/* unregister the overlapping slot */ |
|
447 |
mem->memory_size = 0; |
|
448 |
err = kvm_set_user_memory_region(s, mem); |
|
449 |
if (err) { |
|
450 |
fprintf(stderr, "%s: error unregistering overlapping slot: %s\n", |
|
451 |
__func__, strerror(-err)); |
|
452 |
abort(); |
|
453 |
} |
|
454 |
|
|
455 |
/* Workaround for older KVM versions: we can't join slots, even not by |
|
456 |
* unregistering the previous ones and then registering the larger |
|
457 |
* slot. We have to maintain the existing fragmentation. Sigh. |
|
458 |
* |
|
459 |
* This workaround assumes that the new slot starts at the same |
|
460 |
* address as the first existing one. If not or if some overlapping |
|
461 |
* slot comes around later, we will fail (not seen in practice so far) |
|
462 |
* - and actually require a recent KVM version. */ |
|
463 |
if (s->broken_set_mem_region && |
|
464 |
old.start_addr == start_addr && old.memory_size < size && |
|
465 |
flags < IO_MEM_UNASSIGNED) { |
|
466 |
mem = kvm_alloc_slot(s); |
|
467 |
mem->memory_size = old.memory_size; |
|
468 |
mem->start_addr = old.start_addr; |
|
469 |
mem->phys_offset = old.phys_offset; |
|
470 |
mem->flags = 0; |
|
471 |
|
|
472 |
err = kvm_set_user_memory_region(s, mem); |
|
473 |
if (err) { |
|
474 |
fprintf(stderr, "%s: error updating slot: %s\n", __func__, |
|
475 |
strerror(-err)); |
|
476 |
abort(); |
|
477 |
} |
|
478 |
|
|
479 |
start_addr += old.memory_size; |
|
480 |
phys_offset += old.memory_size; |
|
481 |
size -= old.memory_size; |
|
482 |
continue; |
|
483 |
} |
|
484 |
|
|
485 |
/* register prefix slot */ |
|
486 |
if (old.start_addr < start_addr) { |
|
487 |
mem = kvm_alloc_slot(s); |
|
488 |
mem->memory_size = start_addr - old.start_addr; |
|
489 |
mem->start_addr = old.start_addr; |
|
490 |
mem->phys_offset = old.phys_offset; |
|
491 |
mem->flags = 0; |
|
492 |
|
|
493 |
err = kvm_set_user_memory_region(s, mem); |
|
494 |
if (err) { |
|
495 |
fprintf(stderr, "%s: error registering prefix slot: %s\n", |
|
496 |
__func__, strerror(-err)); |
|
497 |
abort(); |
|
498 |
} |
|
499 |
} |
|
500 |
|
|
501 |
/* register suffix slot */ |
|
502 |
if (old.start_addr + old.memory_size > start_addr + size) { |
|
503 |
ram_addr_t size_delta; |
|
504 |
|
|
505 |
mem = kvm_alloc_slot(s); |
|
506 |
mem->start_addr = start_addr + size; |
|
507 |
size_delta = mem->start_addr - old.start_addr; |
|
508 |
mem->memory_size = old.memory_size - size_delta; |
|
509 |
mem->phys_offset = old.phys_offset + size_delta; |
|
510 |
mem->flags = 0; |
|
511 |
|
|
512 |
err = kvm_set_user_memory_region(s, mem); |
|
513 |
if (err) { |
|
514 |
fprintf(stderr, "%s: error registering suffix slot: %s\n", |
|
515 |
__func__, strerror(-err)); |
|
516 |
abort(); |
|
517 |
} |
|
518 |
} |
|
519 |
} |
|
520 |
|
|
521 |
/* in case the KVM bug workaround already "consumed" the new slot */ |
|
522 |
if (!size) |
|
523 |
return; |
|
524 |
|
|
525 |
/* KVM does not need to know about this memory */ |
|
526 |
if (flags >= IO_MEM_UNASSIGNED) |
|
527 |
return; |
|
528 |
|
|
529 |
mem = kvm_alloc_slot(s); |
|
530 |
mem->memory_size = size; |
|
531 |
mem->start_addr = start_addr; |
|
532 |
mem->phys_offset = phys_offset; |
|
533 |
mem->flags = 0; |
|
534 |
|
|
535 |
err = kvm_set_user_memory_region(s, mem); |
|
536 |
if (err) { |
|
537 |
fprintf(stderr, "%s: error registering slot: %s\n", __func__, |
|
538 |
strerror(-err)); |
|
539 |
abort(); |
|
540 |
} |
|
541 |
} |
|
542 |
|
|
405 | 543 |
int kvm_init(int smp_cpus) |
406 | 544 |
{ |
407 | 545 |
static const char upgrade_note[] = |
... | ... | |
680 | 818 |
return ret; |
681 | 819 |
} |
682 | 820 |
|
683 |
void kvm_set_phys_mem(target_phys_addr_t start_addr, |
|
684 |
ram_addr_t size, |
|
685 |
ram_addr_t phys_offset) |
|
686 |
{ |
|
687 |
KVMState *s = kvm_state; |
|
688 |
ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK; |
|
689 |
KVMSlot *mem, old; |
|
690 |
int err; |
|
691 |
|
|
692 |
if (start_addr & ~TARGET_PAGE_MASK) { |
|
693 |
if (flags >= IO_MEM_UNASSIGNED) { |
|
694 |
if (!kvm_lookup_overlapping_slot(s, start_addr, |
|
695 |
start_addr + size)) { |
|
696 |
return; |
|
697 |
} |
|
698 |
fprintf(stderr, "Unaligned split of a KVM memory slot\n"); |
|
699 |
} else { |
|
700 |
fprintf(stderr, "Only page-aligned memory slots supported\n"); |
|
701 |
} |
|
702 |
abort(); |
|
703 |
} |
|
704 |
|
|
705 |
/* KVM does not support read-only slots */ |
|
706 |
phys_offset &= ~IO_MEM_ROM; |
|
707 |
|
|
708 |
while (1) { |
|
709 |
mem = kvm_lookup_overlapping_slot(s, start_addr, start_addr + size); |
|
710 |
if (!mem) { |
|
711 |
break; |
|
712 |
} |
|
713 |
|
|
714 |
if (flags < IO_MEM_UNASSIGNED && start_addr >= mem->start_addr && |
|
715 |
(start_addr + size <= mem->start_addr + mem->memory_size) && |
|
716 |
(phys_offset - start_addr == mem->phys_offset - mem->start_addr)) { |
|
717 |
/* The new slot fits into the existing one and comes with |
|
718 |
* identical parameters - nothing to be done. */ |
|
719 |
return; |
|
720 |
} |
|
721 |
|
|
722 |
old = *mem; |
|
723 |
|
|
724 |
/* unregister the overlapping slot */ |
|
725 |
mem->memory_size = 0; |
|
726 |
err = kvm_set_user_memory_region(s, mem); |
|
727 |
if (err) { |
|
728 |
fprintf(stderr, "%s: error unregistering overlapping slot: %s\n", |
|
729 |
__func__, strerror(-err)); |
|
730 |
abort(); |
|
731 |
} |
|
732 |
|
|
733 |
/* Workaround for older KVM versions: we can't join slots, even not by |
|
734 |
* unregistering the previous ones and then registering the larger |
|
735 |
* slot. We have to maintain the existing fragmentation. Sigh. |
|
736 |
* |
|
737 |
* This workaround assumes that the new slot starts at the same |
|
738 |
* address as the first existing one. If not or if some overlapping |
|
739 |
* slot comes around later, we will fail (not seen in practice so far) |
|
740 |
* - and actually require a recent KVM version. */ |
|
741 |
if (s->broken_set_mem_region && |
|
742 |
old.start_addr == start_addr && old.memory_size < size && |
|
743 |
flags < IO_MEM_UNASSIGNED) { |
|
744 |
mem = kvm_alloc_slot(s); |
|
745 |
mem->memory_size = old.memory_size; |
|
746 |
mem->start_addr = old.start_addr; |
|
747 |
mem->phys_offset = old.phys_offset; |
|
748 |
mem->flags = 0; |
|
749 |
|
|
750 |
err = kvm_set_user_memory_region(s, mem); |
|
751 |
if (err) { |
|
752 |
fprintf(stderr, "%s: error updating slot: %s\n", __func__, |
|
753 |
strerror(-err)); |
|
754 |
abort(); |
|
755 |
} |
|
756 |
|
|
757 |
start_addr += old.memory_size; |
|
758 |
phys_offset += old.memory_size; |
|
759 |
size -= old.memory_size; |
|
760 |
continue; |
|
761 |
} |
|
762 |
|
|
763 |
/* register prefix slot */ |
|
764 |
if (old.start_addr < start_addr) { |
|
765 |
mem = kvm_alloc_slot(s); |
|
766 |
mem->memory_size = start_addr - old.start_addr; |
|
767 |
mem->start_addr = old.start_addr; |
|
768 |
mem->phys_offset = old.phys_offset; |
|
769 |
mem->flags = 0; |
|
770 |
|
|
771 |
err = kvm_set_user_memory_region(s, mem); |
|
772 |
if (err) { |
|
773 |
fprintf(stderr, "%s: error registering prefix slot: %s\n", |
|
774 |
__func__, strerror(-err)); |
|
775 |
abort(); |
|
776 |
} |
|
777 |
} |
|
778 |
|
|
779 |
/* register suffix slot */ |
|
780 |
if (old.start_addr + old.memory_size > start_addr + size) { |
|
781 |
ram_addr_t size_delta; |
|
782 |
|
|
783 |
mem = kvm_alloc_slot(s); |
|
784 |
mem->start_addr = start_addr + size; |
|
785 |
size_delta = mem->start_addr - old.start_addr; |
|
786 |
mem->memory_size = old.memory_size - size_delta; |
|
787 |
mem->phys_offset = old.phys_offset + size_delta; |
|
788 |
mem->flags = 0; |
|
789 |
|
|
790 |
err = kvm_set_user_memory_region(s, mem); |
|
791 |
if (err) { |
|
792 |
fprintf(stderr, "%s: error registering suffix slot: %s\n", |
|
793 |
__func__, strerror(-err)); |
|
794 |
abort(); |
|
795 |
} |
|
796 |
} |
|
797 |
} |
|
798 |
|
|
799 |
/* in case the KVM bug workaround already "consumed" the new slot */ |
|
800 |
if (!size) |
|
801 |
return; |
|
802 |
|
|
803 |
/* KVM does not need to know about this memory */ |
|
804 |
if (flags >= IO_MEM_UNASSIGNED) |
|
805 |
return; |
|
806 |
|
|
807 |
mem = kvm_alloc_slot(s); |
|
808 |
mem->memory_size = size; |
|
809 |
mem->start_addr = start_addr; |
|
810 |
mem->phys_offset = phys_offset; |
|
811 |
mem->flags = 0; |
|
812 |
|
|
813 |
err = kvm_set_user_memory_region(s, mem); |
|
814 |
if (err) { |
|
815 |
fprintf(stderr, "%s: error registering slot: %s\n", __func__, |
|
816 |
strerror(-err)); |
|
817 |
abort(); |
|
818 |
} |
|
819 |
} |
|
820 |
|
|
821 | 821 |
int kvm_ioctl(KVMState *s, int type, ...) |
822 | 822 |
{ |
823 | 823 |
int ret; |
Also available in: Unified diff