32 |
32 |
#include "sysemu/cpus.h"
|
33 |
33 |
#include "sysemu/kvm.h"
|
34 |
34 |
#include "kvm_ppc.h"
|
|
35 |
#include "mmu-hash64.h"
|
35 |
36 |
|
36 |
37 |
#include "hw/boards.h"
|
37 |
38 |
#include "hw/ppc/ppc.h"
|
... | ... | |
666 |
667 |
|
667 |
668 |
env->spr[SPR_HIOR] = 0;
|
668 |
669 |
|
669 |
|
env->external_htab = spapr->htab;
|
|
670 |
env->external_htab = (uint8_t *)spapr->htab;
|
670 |
671 |
env->htab_base = -1;
|
671 |
672 |
env->htab_mask = HTAB_SIZE(spapr) - 1;
|
672 |
673 |
env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab |
|
... | ... | |
710 |
711 |
}
|
711 |
712 |
}
|
712 |
713 |
|
|
714 |
static const VMStateDescription vmstate_spapr = {
|
|
715 |
.name = "spapr",
|
|
716 |
.version_id = 1,
|
|
717 |
.minimum_version_id = 1,
|
|
718 |
.minimum_version_id_old = 1,
|
|
719 |
.fields = (VMStateField []) {
|
|
720 |
VMSTATE_UINT32(next_irq, sPAPREnvironment),
|
|
721 |
|
|
722 |
/* RTC offset */
|
|
723 |
VMSTATE_UINT64(rtc_offset, sPAPREnvironment),
|
|
724 |
|
|
725 |
VMSTATE_END_OF_LIST()
|
|
726 |
},
|
|
727 |
};
|
|
728 |
|
|
729 |
#define HPTE(_table, _i) (void *)(((uint64_t *)(_table)) + ((_i) * 2))
|
|
730 |
#define HPTE_VALID(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
|
|
731 |
#define HPTE_DIRTY(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
|
|
732 |
#define CLEAN_HPTE(_hpte) ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
|
|
733 |
|
|
734 |
static int htab_save_setup(QEMUFile *f, void *opaque)
|
|
735 |
{
|
|
736 |
sPAPREnvironment *spapr = opaque;
|
|
737 |
|
|
738 |
spapr->htab_save_index = 0;
|
|
739 |
spapr->htab_first_pass = true;
|
|
740 |
|
|
741 |
/* "Iteration" header */
|
|
742 |
qemu_put_be32(f, spapr->htab_shift);
|
|
743 |
|
|
744 |
return 0;
|
|
745 |
}
|
|
746 |
|
|
747 |
#define MAX_ITERATION_NS 5000000 /* 5 ms */
|
|
748 |
|
|
749 |
static void htab_save_first_pass(QEMUFile *f, sPAPREnvironment *spapr,
|
|
750 |
int64_t max_ns)
|
|
751 |
{
|
|
752 |
int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
|
|
753 |
int index = spapr->htab_save_index;
|
|
754 |
int64_t starttime = qemu_get_clock_ns(rt_clock);
|
|
755 |
|
|
756 |
assert(spapr->htab_first_pass);
|
|
757 |
|
|
758 |
do {
|
|
759 |
int chunkstart;
|
|
760 |
|
|
761 |
/* Consume invalid HPTEs */
|
|
762 |
while ((index < htabslots)
|
|
763 |
&& !HPTE_VALID(HPTE(spapr->htab, index))) {
|
|
764 |
index++;
|
|
765 |
CLEAN_HPTE(HPTE(spapr->htab, index));
|
|
766 |
}
|
|
767 |
|
|
768 |
/* Consume valid HPTEs */
|
|
769 |
chunkstart = index;
|
|
770 |
while ((index < htabslots)
|
|
771 |
&& HPTE_VALID(HPTE(spapr->htab, index))) {
|
|
772 |
index++;
|
|
773 |
CLEAN_HPTE(HPTE(spapr->htab, index));
|
|
774 |
}
|
|
775 |
|
|
776 |
if (index > chunkstart) {
|
|
777 |
int n_valid = index - chunkstart;
|
|
778 |
|
|
779 |
qemu_put_be32(f, chunkstart);
|
|
780 |
qemu_put_be16(f, n_valid);
|
|
781 |
qemu_put_be16(f, 0);
|
|
782 |
qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
|
|
783 |
HASH_PTE_SIZE_64 * n_valid);
|
|
784 |
|
|
785 |
if ((qemu_get_clock_ns(rt_clock) - starttime) > max_ns) {
|
|
786 |
break;
|
|
787 |
}
|
|
788 |
}
|
|
789 |
} while ((index < htabslots) && !qemu_file_rate_limit(f));
|
|
790 |
|
|
791 |
if (index >= htabslots) {
|
|
792 |
assert(index == htabslots);
|
|
793 |
index = 0;
|
|
794 |
spapr->htab_first_pass = false;
|
|
795 |
}
|
|
796 |
spapr->htab_save_index = index;
|
|
797 |
}
|
|
798 |
|
|
799 |
static bool htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr,
|
|
800 |
int64_t max_ns)
|
|
801 |
{
|
|
802 |
bool final = max_ns < 0;
|
|
803 |
int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
|
|
804 |
int examined = 0, sent = 0;
|
|
805 |
int index = spapr->htab_save_index;
|
|
806 |
int64_t starttime = qemu_get_clock_ns(rt_clock);
|
|
807 |
|
|
808 |
assert(!spapr->htab_first_pass);
|
|
809 |
|
|
810 |
do {
|
|
811 |
int chunkstart, invalidstart;
|
|
812 |
|
|
813 |
/* Consume non-dirty HPTEs */
|
|
814 |
while ((index < htabslots)
|
|
815 |
&& !HPTE_DIRTY(HPTE(spapr->htab, index))) {
|
|
816 |
index++;
|
|
817 |
examined++;
|
|
818 |
}
|
|
819 |
|
|
820 |
chunkstart = index;
|
|
821 |
/* Consume valid dirty HPTEs */
|
|
822 |
while ((index < htabslots)
|
|
823 |
&& HPTE_DIRTY(HPTE(spapr->htab, index))
|
|
824 |
&& HPTE_VALID(HPTE(spapr->htab, index))) {
|
|
825 |
CLEAN_HPTE(HPTE(spapr->htab, index));
|
|
826 |
index++;
|
|
827 |
examined++;
|
|
828 |
}
|
|
829 |
|
|
830 |
invalidstart = index;
|
|
831 |
/* Consume invalid dirty HPTEs */
|
|
832 |
while ((index < htabslots)
|
|
833 |
&& HPTE_DIRTY(HPTE(spapr->htab, index))
|
|
834 |
&& !HPTE_VALID(HPTE(spapr->htab, index))) {
|
|
835 |
CLEAN_HPTE(HPTE(spapr->htab, index));
|
|
836 |
index++;
|
|
837 |
examined++;
|
|
838 |
}
|
|
839 |
|
|
840 |
if (index > chunkstart) {
|
|
841 |
int n_valid = invalidstart - chunkstart;
|
|
842 |
int n_invalid = index - invalidstart;
|
|
843 |
|
|
844 |
qemu_put_be32(f, chunkstart);
|
|
845 |
qemu_put_be16(f, n_valid);
|
|
846 |
qemu_put_be16(f, n_invalid);
|
|
847 |
qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
|
|
848 |
HASH_PTE_SIZE_64 * n_valid);
|
|
849 |
sent += index - chunkstart;
|
|
850 |
|
|
851 |
if (!final && (qemu_get_clock_ns(rt_clock) - starttime) > max_ns) {
|
|
852 |
break;
|
|
853 |
}
|
|
854 |
}
|
|
855 |
|
|
856 |
if (examined >= htabslots) {
|
|
857 |
break;
|
|
858 |
}
|
|
859 |
|
|
860 |
if (index >= htabslots) {
|
|
861 |
assert(index == htabslots);
|
|
862 |
index = 0;
|
|
863 |
}
|
|
864 |
} while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final));
|
|
865 |
|
|
866 |
if (index >= htabslots) {
|
|
867 |
assert(index == htabslots);
|
|
868 |
index = 0;
|
|
869 |
}
|
|
870 |
|
|
871 |
spapr->htab_save_index = index;
|
|
872 |
|
|
873 |
return (examined >= htabslots) && (sent == 0);
|
|
874 |
}
|
|
875 |
|
|
876 |
static int htab_save_iterate(QEMUFile *f, void *opaque)
|
|
877 |
{
|
|
878 |
sPAPREnvironment *spapr = opaque;
|
|
879 |
bool nothingleft = false;;
|
|
880 |
|
|
881 |
/* Iteration header */
|
|
882 |
qemu_put_be32(f, 0);
|
|
883 |
|
|
884 |
if (spapr->htab_first_pass) {
|
|
885 |
htab_save_first_pass(f, spapr, MAX_ITERATION_NS);
|
|
886 |
} else {
|
|
887 |
nothingleft = htab_save_later_pass(f, spapr, MAX_ITERATION_NS);
|
|
888 |
}
|
|
889 |
|
|
890 |
/* End marker */
|
|
891 |
qemu_put_be32(f, 0);
|
|
892 |
qemu_put_be16(f, 0);
|
|
893 |
qemu_put_be16(f, 0);
|
|
894 |
|
|
895 |
return nothingleft ? 1 : 0;
|
|
896 |
}
|
|
897 |
|
|
898 |
static int htab_save_complete(QEMUFile *f, void *opaque)
|
|
899 |
{
|
|
900 |
sPAPREnvironment *spapr = opaque;
|
|
901 |
|
|
902 |
/* Iteration header */
|
|
903 |
qemu_put_be32(f, 0);
|
|
904 |
|
|
905 |
htab_save_later_pass(f, spapr, -1);
|
|
906 |
|
|
907 |
/* End marker */
|
|
908 |
qemu_put_be32(f, 0);
|
|
909 |
qemu_put_be16(f, 0);
|
|
910 |
qemu_put_be16(f, 0);
|
|
911 |
|
|
912 |
return 0;
|
|
913 |
}
|
|
914 |
|
|
915 |
static int htab_load(QEMUFile *f, void *opaque, int version_id)
|
|
916 |
{
|
|
917 |
sPAPREnvironment *spapr = opaque;
|
|
918 |
uint32_t section_hdr;
|
|
919 |
|
|
920 |
if (version_id < 1 || version_id > 1) {
|
|
921 |
fprintf(stderr, "htab_load() bad version\n");
|
|
922 |
return -EINVAL;
|
|
923 |
}
|
|
924 |
|
|
925 |
section_hdr = qemu_get_be32(f);
|
|
926 |
|
|
927 |
if (section_hdr) {
|
|
928 |
/* First section, just the hash shift */
|
|
929 |
if (spapr->htab_shift != section_hdr) {
|
|
930 |
return -EINVAL;
|
|
931 |
}
|
|
932 |
return 0;
|
|
933 |
}
|
|
934 |
|
|
935 |
while (true) {
|
|
936 |
uint32_t index;
|
|
937 |
uint16_t n_valid, n_invalid;
|
|
938 |
|
|
939 |
index = qemu_get_be32(f);
|
|
940 |
n_valid = qemu_get_be16(f);
|
|
941 |
n_invalid = qemu_get_be16(f);
|
|
942 |
|
|
943 |
if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) {
|
|
944 |
/* End of Stream */
|
|
945 |
break;
|
|
946 |
}
|
|
947 |
|
|
948 |
if ((index + n_valid + n_invalid) >=
|
|
949 |
(HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) {
|
|
950 |
/* Bad index in stream */
|
|
951 |
fprintf(stderr, "htab_load() bad index %d (%hd+%hd entries) "
|
|
952 |
"in htab stream\n", index, n_valid, n_invalid);
|
|
953 |
return -EINVAL;
|
|
954 |
}
|
|
955 |
|
|
956 |
if (n_valid) {
|
|
957 |
qemu_get_buffer(f, HPTE(spapr->htab, index),
|
|
958 |
HASH_PTE_SIZE_64 * n_valid);
|
|
959 |
}
|
|
960 |
if (n_invalid) {
|
|
961 |
memset(HPTE(spapr->htab, index + n_valid), 0,
|
|
962 |
HASH_PTE_SIZE_64 * n_invalid);
|
|
963 |
}
|
|
964 |
}
|
|
965 |
|
|
966 |
return 0;
|
|
967 |
}
|
|
968 |
|
|
969 |
static SaveVMHandlers savevm_htab_handlers = {
|
|
970 |
.save_live_setup = htab_save_setup,
|
|
971 |
.save_live_iterate = htab_save_iterate,
|
|
972 |
.save_live_complete = htab_save_complete,
|
|
973 |
.load_state = htab_load,
|
|
974 |
};
|
|
975 |
|
713 |
976 |
/* pSeries LPAR / sPAPR hardware init */
|
714 |
977 |
static void ppc_spapr_init(QEMUMachineInitArgs *args)
|
715 |
978 |
{
|
... | ... | |
950 |
1213 |
|
951 |
1214 |
spapr->entry_point = 0x100;
|
952 |
1215 |
|
|
1216 |
vmstate_register(NULL, 0, &vmstate_spapr, spapr);
|
|
1217 |
register_savevm_live(NULL, "spapr/htab", -1, 1,
|
|
1218 |
&savevm_htab_handlers, spapr);
|
|
1219 |
|
953 |
1220 |
/* Prepare the device tree */
|
954 |
1221 |
spapr->fdt_skel = spapr_create_fdt_skel(cpu_model,
|
955 |
1222 |
initrd_base, initrd_size,
|