diff for duplicates of <53874719.5070604@imgtec.com> diff --git a/a/content_digest b/N1/content_digest index f9be802..6cdf46b 100644 --- a/a/content_digest +++ b/N1/content_digest @@ -6,9 +6,9 @@ "To\0Paolo Bonzini <pbonzini@redhat.com>\0" "Cc\0Andreas Herrmann <andreas.herrmann@caviumnetworks.com>" Gleb Natapov <gleb@kernel.org> - <kvm@vger.kernel.org> + kvm@vger.kernel.org Ralf Baechle <ralf@linux-mips.org> - <linux-mips@linux-mips.org> + linux-mips@linux-mips.org David Daney <david.daney@cavium.com> " Sanjay Lal <sanjayl@kymasys.com>\0" "\01:1\0" @@ -38,4 +38,4 @@ "fn\00001-timer-Add-cpu_get_clock_at.patch\0" "b\0" -73ed7cdee6840b69f362dd1d82d2b56d498699a60134fde2fd7f322a5c8b0a0c +abbe3d0f7b340e3c956b9a7ae3559718962293cc2e1f463a9e92f5217aca1341
diff --git a/a/2.txt b/N2/2.txt index 8b13789..01e126e 100644 --- a/a/2.txt +++ b/N2/2.txt @@ -1 +1,75 @@ +>From 1438f5eb5e05eb5ef8b90a6d52cfe73e67da254f Mon Sep 17 00:00:00 2001 +From: James Hogan <james.hogan@imgtec.com> +Date: Tue, 20 May 2014 00:52:08 +0100 +Subject: [PATCH 1/2] timer: Add cpu_get_clock_at() +Add a new cpu_get_clock_at() which gets the VM time at a particular +specified monotonic time rather than the current monotonic time. This is +to allow for operations that may need both the current monotonic time +and the VM time based on that, such as to allow synchronisation with a +KVM CPU clock. + +Signed-off-by: James Hogan <james.hogan@imgtec.com> +--- + cpus.c | 23 +++++++++++++++++++++-- + include/qemu/timer.h | 1 + + 2 files changed, 22 insertions(+), 2 deletions(-) + +diff --git a/cpus.c b/cpus.c +index dd7ac13..ac906a3 100644 +--- a/cpus.c ++++ b/cpus.c +@@ -186,18 +186,37 @@ int64_t cpu_get_ticks(void) + return ticks; + } + +-static int64_t cpu_get_clock_locked(void) ++static int64_t cpu_get_clock_at_locked(int64_t now) + { + int64_t ticks; + + ticks = timers_state.cpu_clock_offset; + if (timers_state.cpu_ticks_enabled) { +- ticks += get_clock(); ++ ticks += now; + } + + return ticks; + } + ++static int64_t cpu_get_clock_locked(void) ++{ ++ return cpu_get_clock_at_locked(get_clock()); ++} ++ ++/* return the host CPU monotonic timer and handle stop/restart */ ++int64_t cpu_get_clock_at(int64_t now) ++{ ++ int64_t ti; ++ unsigned start; ++ ++ do { ++ start = seqlock_read_begin(&timers_state.vm_clock_seqlock); ++ ti = cpu_get_clock_at_locked(now); ++ } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start)); ++ ++ return ti; ++} ++ + /* return the host CPU monotonic timer and handle stop/restart */ + int64_t cpu_get_clock(void) + { +diff --git a/include/qemu/timer.h b/include/qemu/timer.h +index 7f9a074..5b2e8c2 100644 +--- a/include/qemu/timer.h ++++ b/include/qemu/timer.h +@@ -745,6 +745,7 @@ static inline int64_t get_clock(void) + /* icount */ + int64_t cpu_get_icount(void); + int64_t cpu_get_clock(void); ++int64_t cpu_get_clock_at(int64_t now); + + /*******************************************/ + /* host CPU ticks (if available) */ +-- +1.9.3 diff --git a/N2/3.hdr b/N2/3.hdr new file mode 100644 index 0000000..0b39d49 --- /dev/null +++ b/N2/3.hdr @@ -0,0 +1,5 @@ +Content-Type: text/x-patch; + name="0002-target-mips-kvm-Save-restore-KVM-timer-state.patch" +Content-Transfer-Encoding: 7bit +Content-Disposition: attachment; + filename="0002-target-mips-kvm-Save-restore-KVM-timer-state.patch" diff --git a/N2/3.txt b/N2/3.txt new file mode 100644 index 0000000..de08959 --- /dev/null +++ b/N2/3.txt @@ -0,0 +1,345 @@ +>From 22c61769ec31cb222c5291c88bd6a658e23862f5 Mon Sep 17 00:00:00 2001 +From: James Hogan <james.hogan@imgtec.com> +Date: Thu, 29 May 2014 14:36:20 +0100 +Subject: [PATCH 2/2] target-mips: kvm: Save/restore KVM timer state + +Save and restore KVM timer state properly. When it's saved (or VM clock +stopped) the VM clock is also recorded. When it's restored (or VM clock +restarted) it is resumed with the stored count at the saved VM clock +translated into monotonic time, i.e. current time - elapsed VM +nanoseconds. This therefore behaves correctly after the VM clock has +been stopped. + +E.g. +sync state to QEMU + takes snapshot of Count, Cause and VM time(now) +sync state back to KVM + restores Count, Cause at translated VM time (unchanged) + time continues from the same Count without losing time or interrupts + +Or: +stop vm clock + takes snapshot of Count, Cause and VM time + +restart vm clock + restores Count, Cause at now - (vm time(now) - saved vm time) + time continues from the same Count but at a later monotonic time + depending on how long the vm clock was stopped + +The VM time at which the timer was stopped (count_save_time) is +saved/loaded by cpu_save and cpu_load so that it can be restarted +without losing time relative to the VM clock. + +Signed-off-by: James Hogan <james.hogan@imgtec.com> +--- + target-mips/cpu.h | 3 +- + target-mips/kvm.c | 196 +++++++++++++++++++++++++++++++++++++++++++++++--- + target-mips/machine.c | 6 ++ + 3 files changed, 195 insertions(+), 10 deletions(-) + +diff --git a/target-mips/cpu.h b/target-mips/cpu.h +index 67bf441..02a8da1 100644 +--- a/target-mips/cpu.h ++++ b/target-mips/cpu.h +@@ -495,6 +495,7 @@ struct CPUMIPSState { + const mips_def_t *cpu_model; + void *irq[8]; + QEMUTimer *timer; /* Internal timer */ ++ int64_t count_save_time; + }; + + #include "cpu-qom.h" +@@ -526,7 +527,7 @@ void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf); + extern void cpu_wrdsp(uint32_t rs, uint32_t mask_num, CPUMIPSState *env); + extern uint32_t cpu_rddsp(uint32_t mask_num, CPUMIPSState *env); + +-#define CPU_SAVE_VERSION 4 ++#define CPU_SAVE_VERSION 5 + + /* MMU modes definitions. We carefully match the indices with our + hflags layout. */ +diff --git a/target-mips/kvm.c b/target-mips/kvm.c +index 8765205..ee2dd1c 100644 +--- a/target-mips/kvm.c ++++ b/target-mips/kvm.c +@@ -33,6 +33,8 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + KVM_CAP_LAST_INFO + }; + ++static void kvm_mips_update_state(void *opaque, int running, RunState state); ++ + unsigned long kvm_arch_vcpu_id(CPUState *cs) + { + return cs->cpu_index; +@@ -50,6 +52,9 @@ int kvm_arch_init(KVMState *s) + int kvm_arch_init_vcpu(CPUState *cs) + { + int ret = 0; ++ ++ qemu_add_vm_change_state_handler(kvm_mips_update_state, cs); ++ + DPRINTF("%s\n", __func__); + return ret; + } +@@ -224,6 +229,17 @@ int kvm_mips_set_ipi_interrupt(MIPSCPU *cpu, int irq, int level) + #define KVM_REG_MIPS_CP0_XCONTEXT MIPS_CP0_64(20, 0) + #define KVM_REG_MIPS_CP0_ERROREPC MIPS_CP0_64(30, 0) + ++/* CP0_Count control */ ++#define KVM_REG_MIPS_COUNT_CTL (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \ ++ 0x20000 | 0) ++#define KVM_REG_MIPS_COUNT_CTL_DC 0x00000001 /* master disable */ ++/* CP0_Count resume monotonic nanoseconds */ ++#define KVM_REG_MIPS_COUNT_RESUME (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \ ++ 0x20000 | 1) ++/* CP0_Count rate in Hz */ ++#define KVM_REG_MIPS_COUNT_HZ (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \ ++ 0x20000 | 2) ++ + static inline int kvm_mips_put_one_reg(CPUState *cs, uint64_t reg_id, + int32_t *addr) + { +@@ -248,6 +264,17 @@ static inline int kvm_mips_put_one_ulreg(CPUState *cs, uint64_t reg_id, + return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &cp0reg); + } + ++static inline int kvm_mips_put_one_reg64(CPUState *cs, uint64_t reg_id, ++ uint64_t *addr) ++{ ++ struct kvm_one_reg cp0reg = { ++ .id = reg_id, ++ .addr = (uintptr_t)addr ++ }; ++ ++ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &cp0reg); ++} ++ + static inline int kvm_mips_get_one_reg(CPUState *cs, uint64_t reg_id, + int32_t *addr) + { +@@ -286,6 +313,151 @@ static inline int kvm_mips_get_one_ulreg(CPUState *cs, uint64 reg_id, + return ret; + } + ++static inline int kvm_mips_get_one_reg64(CPUState *cs, uint64 reg_id, ++ uint64_t *addr) ++{ ++ int ret; ++ struct kvm_one_reg cp0reg = { ++ .id = reg_id, ++ .addr = (uintptr_t)addr ++ }; ++ ++ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &cp0reg); ++ return ret; ++} ++ ++/* ++ * We freeze the KVM timer when either the VM clock is stopped or the state is ++ * saved (the state is dirty). ++ */ ++ ++/* ++ * Save the state of the KVM timer when VM clock is stopped or state is synced ++ * to QEMU. ++ */ ++static int kvm_mips_save_count(CPUState *cs) ++{ ++ MIPSCPU *cpu = MIPS_CPU(cs); ++ CPUMIPSState *env = &cpu->env; ++ uint64_t count_ctl, count_resume; ++ int ret; ++ ++ /* freeze KVM timer */ ++ ret = kvm_mips_get_one_reg64(cs, KVM_REG_MIPS_COUNT_CTL, &count_ctl); ++ if (ret < 0) { ++ return ret; ++ } ++ if (!(count_ctl & KVM_REG_MIPS_COUNT_CTL_DC)) { ++ count_ctl |= KVM_REG_MIPS_COUNT_CTL_DC; ++ ret = kvm_mips_put_one_reg64(cs, KVM_REG_MIPS_COUNT_CTL, &count_ctl); ++ if (ret < 0) { ++ return ret; ++ } ++ } ++ ++ /* read CP0_Cause */ ++ ret = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_CAUSE, &env->CP0_Cause); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ /* read CP0_Count */ ++ ret = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_COUNT, &env->CP0_Count); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ /* read COUNT_RESUME */ ++ ret = kvm_mips_get_one_reg64(cs, KVM_REG_MIPS_COUNT_RESUME, ++ &count_resume); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ /* translate monotonic COUNT_RESUME to VM time */ ++ env->count_save_time = cpu_get_clock_at(count_resume); ++ ++ return ret; ++} ++ ++/* ++ * Restore the state of the KVM timer when VM clock is restarted or state is ++ * synced to KVM. ++ */ ++static int kvm_mips_restore_count(CPUState *cs) ++{ ++ MIPSCPU *cpu = MIPS_CPU(cs); ++ CPUMIPSState *env = &cpu->env; ++ uint64_t count_ctl, count_resume; ++ int64_t now = get_clock(); ++ int ret = 0; ++ ++ /* check the timer is frozen */ ++ ret = kvm_mips_get_one_reg64(cs, KVM_REG_MIPS_COUNT_CTL, &count_ctl); ++ if (ret < 0) { ++ return ret; ++ } ++ if (!(count_ctl & KVM_REG_MIPS_COUNT_CTL_DC)) { ++ /* freeze timer (sets COUNT_RESUME for us) */ ++ count_ctl |= KVM_REG_MIPS_COUNT_CTL_DC; ++ ret = kvm_mips_put_one_reg64(cs, KVM_REG_MIPS_COUNT_CTL, &count_ctl); ++ if (ret < 0) { ++ return ret; ++ } ++ } else { ++ /* find time to resume the saved timer at */ ++ now = get_clock(); ++ count_resume = now - (cpu_get_clock_at(now) - env->count_save_time); ++ ret = kvm_mips_put_one_reg64(cs, KVM_REG_MIPS_COUNT_RESUME, ++ &count_resume); ++ if (ret < 0) { ++ return ret; ++ } ++ } ++ ++ /* load CP0_Cause */ ++ ret = kvm_mips_put_one_reg(cs, KVM_REG_MIPS_CP0_CAUSE, &env->CP0_Cause); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ /* load CP0_Count */ ++ ret = kvm_mips_put_one_reg(cs, KVM_REG_MIPS_CP0_COUNT, &env->CP0_Count); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ /* resume KVM timer */ ++ count_ctl &= ~KVM_REG_MIPS_COUNT_CTL_DC; ++ ret = kvm_mips_put_one_reg64(cs, KVM_REG_MIPS_COUNT_CTL, &count_ctl); ++ return ret; ++} ++ ++/* ++ * Handle the VM clock being started or stopped ++ */ ++static void kvm_mips_update_state(void *opaque, int running, RunState state) ++{ ++ CPUState *cs = opaque; ++ int ret; ++ ++ /* ++ * If state is already dirty (synced to QEMU) then the KVM timer state is ++ * already saved and can be restored when it is synced back to KVM. ++ */ ++ if (!cs->kvm_vcpu_dirty) { ++ if (running) { ++ ret = kvm_mips_restore_count(cs); ++ } else { ++ ret = kvm_mips_save_count(cs); ++ } ++ if (ret < 0) { ++ fprintf(stderr, "Failed update count (running=%d)\n", ++ running); ++ } ++ } ++} ++ + static int kvm_mips_put_cp0_registers(CPUState *cs, int level) + { + MIPSCPU *cpu = MIPS_CPU(cs); +@@ -322,15 +494,16 @@ static int kvm_mips_put_cp0_registers(CPUState *cs, int level) + fprintf(stderr, "Failed to put BADVADDR\n"); + return ret; + } +- if (level != KVM_PUT_RUNTIME_STATE) { +- /* don't write guest count during runtime or the clock might drift */ +- ret |= kvm_mips_put_one_reg(cs, KVM_REG_MIPS_CP0_COUNT, +- &env->CP0_Count); ++ ++ /* If VM clock stopped then state will be restored when it is restarted */ ++ if (runstate_is_running()) { ++ ret = kvm_mips_restore_count(cs); + if (ret < 0) { +- fprintf(stderr, "Failed to put COMPARE\n"); ++ fprintf(stderr, "Failed to put COUNT\n"); + return ret; + } + } ++ + ret |= kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_ENTRYHI, + &env->CP0_EntryHi); + if (ret < 0) { +@@ -397,10 +570,6 @@ static int kvm_mips_get_cp0_registers(CPUState *cs) + if (ret < 0) { + return ret; + } +- ret |= kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_COUNT, &env->CP0_Count); +- if (ret < 0) { +- return ret; +- } + ret |= kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_ENTRYHI, + &env->CP0_EntryHi); + if (ret < 0) { +@@ -419,6 +588,15 @@ static int kvm_mips_get_cp0_registers(CPUState *cs) + if (ret < 0) { + return ret; + } ++ ++ /* If VM clock stopped then state was already saved when it was stopped */ ++ if (runstate_is_running()) { ++ ret = kvm_mips_save_count(cs); ++ if (ret < 0) { ++ return ret; ++ } ++ } ++ + ret |= kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_EPC, &env->CP0_EPC); + if (ret < 0) { + return ret; +diff --git a/target-mips/machine.c b/target-mips/machine.c +index 0f36c9e..4916b13 100644 +--- a/target-mips/machine.c ++++ b/target-mips/machine.c +@@ -150,6 +150,8 @@ void cpu_save(QEMUFile *f, void *opaque) + save_tc(f, &env->tcs[i]); + for (i = 0; i < MIPS_FPU_MAX; i++) + save_fpu(f, &env->fpus[i]); ++ ++ qemu_put_sbe64s(f, &env->count_save_time); + } + + static void load_tc(QEMUFile *f, TCState *tc, int version_id) +@@ -310,5 +312,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) + + /* XXX: ensure compatibility for halted bit ? */ + tlb_flush(CPU(cpu), 1); ++ ++ if (version_id >= 5) { ++ qemu_get_sbe64s(f, &env->count_save_time); ++ } + return 0; + } +-- +1.9.3 diff --git a/a/content_digest b/N2/content_digest index f9be802..b182606 100644 --- a/a/content_digest +++ b/N2/content_digest @@ -37,5 +37,428 @@ "\01:2\0" "fn\00001-timer-Add-cpu_get_clock_at.patch\0" "b\0" + ">From 1438f5eb5e05eb5ef8b90a6d52cfe73e67da254f Mon Sep 17 00:00:00 2001\n" + "From: James Hogan <james.hogan@imgtec.com>\n" + "Date: Tue, 20 May 2014 00:52:08 +0100\n" + "Subject: [PATCH 1/2] timer: Add cpu_get_clock_at()\n" + "\n" + "Add a new cpu_get_clock_at() which gets the VM time at a particular\n" + "specified monotonic time rather than the current monotonic time. This is\n" + "to allow for operations that may need both the current monotonic time\n" + "and the VM time based on that, such as to allow synchronisation with a\n" + "KVM CPU clock.\n" + "\n" + "Signed-off-by: James Hogan <james.hogan@imgtec.com>\n" + "---\n" + " cpus.c | 23 +++++++++++++++++++++--\n" + " include/qemu/timer.h | 1 +\n" + " 2 files changed, 22 insertions(+), 2 deletions(-)\n" + "\n" + "diff --git a/cpus.c b/cpus.c\n" + "index dd7ac13..ac906a3 100644\n" + "--- a/cpus.c\n" + "+++ b/cpus.c\n" + "@@ -186,18 +186,37 @@ int64_t cpu_get_ticks(void)\n" + " return ticks;\n" + " }\n" + " \n" + "-static int64_t cpu_get_clock_locked(void)\n" + "+static int64_t cpu_get_clock_at_locked(int64_t now)\n" + " {\n" + " int64_t ticks;\n" + " \n" + " ticks = timers_state.cpu_clock_offset;\n" + " if (timers_state.cpu_ticks_enabled) {\n" + "- ticks += get_clock();\n" + "+ ticks += now;\n" + " }\n" + " \n" + " return ticks;\n" + " }\n" + " \n" + "+static int64_t cpu_get_clock_locked(void)\n" + "+{\n" + "+ return cpu_get_clock_at_locked(get_clock());\n" + "+}\n" + "+\n" + "+/* return the host CPU monotonic timer and handle stop/restart */\n" + "+int64_t cpu_get_clock_at(int64_t now)\n" + "+{\n" + "+ int64_t ti;\n" + "+ unsigned start;\n" + "+\n" + "+ do {\n" + "+ start = seqlock_read_begin(&timers_state.vm_clock_seqlock);\n" + "+ ti = cpu_get_clock_at_locked(now);\n" + "+ } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start));\n" + "+\n" + "+ return ti;\n" + "+}\n" + "+\n" + " /* return the host CPU monotonic timer and handle stop/restart */\n" + " int64_t cpu_get_clock(void)\n" + " {\n" + "diff --git a/include/qemu/timer.h b/include/qemu/timer.h\n" + "index 7f9a074..5b2e8c2 100644\n" + "--- a/include/qemu/timer.h\n" + "+++ b/include/qemu/timer.h\n" + "@@ -745,6 +745,7 @@ static inline int64_t get_clock(void)\n" + " /* icount */\n" + " int64_t cpu_get_icount(void);\n" + " int64_t cpu_get_clock(void);\n" + "+int64_t cpu_get_clock_at(int64_t now);\n" + " \n" + " /*******************************************/\n" + " /* host CPU ticks (if available) */\n" + "-- \n" + 1.9.3 + "\01:3\0" + "fn\00002-target-mips-kvm-Save-restore-KVM-timer-state.patch\0" + "b\0" + ">From 22c61769ec31cb222c5291c88bd6a658e23862f5 Mon Sep 17 00:00:00 2001\n" + "From: James Hogan <james.hogan@imgtec.com>\n" + "Date: Thu, 29 May 2014 14:36:20 +0100\n" + "Subject: [PATCH 2/2] target-mips: kvm: Save/restore KVM timer state\n" + "\n" + "Save and restore KVM timer state properly. When it's saved (or VM clock\n" + "stopped) the VM clock is also recorded. When it's restored (or VM clock\n" + "restarted) it is resumed with the stored count at the saved VM clock\n" + "translated into monotonic time, i.e. current time - elapsed VM\n" + "nanoseconds. This therefore behaves correctly after the VM clock has\n" + "been stopped.\n" + "\n" + "E.g.\n" + "sync state to QEMU\n" + " takes snapshot of Count, Cause and VM time(now)\n" + "sync state back to KVM\n" + " restores Count, Cause at translated VM time (unchanged)\n" + " time continues from the same Count without losing time or interrupts\n" + "\n" + "Or:\n" + "stop vm clock\n" + " takes snapshot of Count, Cause and VM time\n" + "\n" + "restart vm clock\n" + " restores Count, Cause at now - (vm time(now) - saved vm time)\n" + " time continues from the same Count but at a later monotonic time\n" + " depending on how long the vm clock was stopped\n" + "\n" + "The VM time at which the timer was stopped (count_save_time) is\n" + "saved/loaded by cpu_save and cpu_load so that it can be restarted\n" + "without losing time relative to the VM clock.\n" + "\n" + "Signed-off-by: James Hogan <james.hogan@imgtec.com>\n" + "---\n" + " target-mips/cpu.h | 3 +-\n" + " target-mips/kvm.c | 196 +++++++++++++++++++++++++++++++++++++++++++++++---\n" + " target-mips/machine.c | 6 ++\n" + " 3 files changed, 195 insertions(+), 10 deletions(-)\n" + "\n" + "diff --git a/target-mips/cpu.h b/target-mips/cpu.h\n" + "index 67bf441..02a8da1 100644\n" + "--- a/target-mips/cpu.h\n" + "+++ b/target-mips/cpu.h\n" + "@@ -495,6 +495,7 @@ struct CPUMIPSState {\n" + " const mips_def_t *cpu_model;\n" + " void *irq[8];\n" + " QEMUTimer *timer; /* Internal timer */\n" + "+ int64_t count_save_time;\n" + " };\n" + " \n" + " #include \"cpu-qom.h\"\n" + "@@ -526,7 +527,7 @@ void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf);\n" + " extern void cpu_wrdsp(uint32_t rs, uint32_t mask_num, CPUMIPSState *env);\n" + " extern uint32_t cpu_rddsp(uint32_t mask_num, CPUMIPSState *env);\n" + " \n" + "-#define CPU_SAVE_VERSION 4\n" + "+#define CPU_SAVE_VERSION 5\n" + " \n" + " /* MMU modes definitions. We carefully match the indices with our\n" + " hflags layout. */\n" + "diff --git a/target-mips/kvm.c b/target-mips/kvm.c\n" + "index 8765205..ee2dd1c 100644\n" + "--- a/target-mips/kvm.c\n" + "+++ b/target-mips/kvm.c\n" + "@@ -33,6 +33,8 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {\n" + " KVM_CAP_LAST_INFO\n" + " };\n" + " \n" + "+static void kvm_mips_update_state(void *opaque, int running, RunState state);\n" + "+\n" + " unsigned long kvm_arch_vcpu_id(CPUState *cs)\n" + " {\n" + " return cs->cpu_index;\n" + "@@ -50,6 +52,9 @@ int kvm_arch_init(KVMState *s)\n" + " int kvm_arch_init_vcpu(CPUState *cs)\n" + " {\n" + " int ret = 0;\n" + "+\n" + "+ qemu_add_vm_change_state_handler(kvm_mips_update_state, cs);\n" + "+\n" + " DPRINTF(\"%s\\n\", __func__);\n" + " return ret;\n" + " }\n" + "@@ -224,6 +229,17 @@ int kvm_mips_set_ipi_interrupt(MIPSCPU *cpu, int irq, int level)\n" + " #define KVM_REG_MIPS_CP0_XCONTEXT\tMIPS_CP0_64(20, 0)\n" + " #define KVM_REG_MIPS_CP0_ERROREPC\tMIPS_CP0_64(30, 0)\n" + " \n" + "+/* CP0_Count control */\n" + "+#define KVM_REG_MIPS_COUNT_CTL (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \\\n" + "+ 0x20000 | 0)\n" + "+#define KVM_REG_MIPS_COUNT_CTL_DC 0x00000001 /* master disable */\n" + "+/* CP0_Count resume monotonic nanoseconds */\n" + "+#define KVM_REG_MIPS_COUNT_RESUME (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \\\n" + "+ 0x20000 | 1)\n" + "+/* CP0_Count rate in Hz */\n" + "+#define KVM_REG_MIPS_COUNT_HZ (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \\\n" + "+ 0x20000 | 2)\n" + "+\n" + " static inline int kvm_mips_put_one_reg(CPUState *cs, uint64_t reg_id,\n" + " int32_t *addr)\n" + " {\n" + "@@ -248,6 +264,17 @@ static inline int kvm_mips_put_one_ulreg(CPUState *cs, uint64_t reg_id,\n" + " return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &cp0reg);\n" + " }\n" + " \n" + "+static inline int kvm_mips_put_one_reg64(CPUState *cs, uint64_t reg_id,\n" + "+ uint64_t *addr)\n" + "+{\n" + "+ struct kvm_one_reg cp0reg = {\n" + "+ .id = reg_id,\n" + "+ .addr = (uintptr_t)addr\n" + "+ };\n" + "+\n" + "+ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &cp0reg);\n" + "+}\n" + "+\n" + " static inline int kvm_mips_get_one_reg(CPUState *cs, uint64_t reg_id,\n" + " int32_t *addr)\n" + " {\n" + "@@ -286,6 +313,151 @@ static inline int kvm_mips_get_one_ulreg(CPUState *cs, uint64 reg_id,\n" + " return ret;\n" + " }\n" + " \n" + "+static inline int kvm_mips_get_one_reg64(CPUState *cs, uint64 reg_id,\n" + "+ uint64_t *addr)\n" + "+{\n" + "+ int ret;\n" + "+ struct kvm_one_reg cp0reg = {\n" + "+ .id = reg_id,\n" + "+ .addr = (uintptr_t)addr\n" + "+ };\n" + "+\n" + "+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &cp0reg);\n" + "+ return ret;\n" + "+}\n" + "+\n" + "+/*\n" + "+ * We freeze the KVM timer when either the VM clock is stopped or the state is\n" + "+ * saved (the state is dirty).\n" + "+ */\n" + "+\n" + "+/*\n" + "+ * Save the state of the KVM timer when VM clock is stopped or state is synced\n" + "+ * to QEMU.\n" + "+ */\n" + "+static int kvm_mips_save_count(CPUState *cs)\n" + "+{\n" + "+ MIPSCPU *cpu = MIPS_CPU(cs);\n" + "+ CPUMIPSState *env = &cpu->env;\n" + "+ uint64_t count_ctl, count_resume;\n" + "+ int ret;\n" + "+\n" + "+ /* freeze KVM timer */\n" + "+ ret = kvm_mips_get_one_reg64(cs, KVM_REG_MIPS_COUNT_CTL, &count_ctl);\n" + "+ if (ret < 0) {\n" + "+ return ret;\n" + "+ }\n" + "+ if (!(count_ctl & KVM_REG_MIPS_COUNT_CTL_DC)) {\n" + "+ count_ctl |= KVM_REG_MIPS_COUNT_CTL_DC;\n" + "+ ret = kvm_mips_put_one_reg64(cs, KVM_REG_MIPS_COUNT_CTL, &count_ctl);\n" + "+ if (ret < 0) {\n" + "+ return ret;\n" + "+ }\n" + "+ }\n" + "+\n" + "+ /* read CP0_Cause */\n" + "+ ret = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_CAUSE, &env->CP0_Cause);\n" + "+ if (ret < 0) {\n" + "+ return ret;\n" + "+ }\n" + "+\n" + "+ /* read CP0_Count */\n" + "+ ret = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_COUNT, &env->CP0_Count);\n" + "+ if (ret < 0) {\n" + "+ return ret;\n" + "+ }\n" + "+\n" + "+ /* read COUNT_RESUME */\n" + "+ ret = kvm_mips_get_one_reg64(cs, KVM_REG_MIPS_COUNT_RESUME,\n" + "+ &count_resume);\n" + "+ if (ret < 0) {\n" + "+ return ret;\n" + "+ }\n" + "+\n" + "+ /* translate monotonic COUNT_RESUME to VM time */\n" + "+ env->count_save_time = cpu_get_clock_at(count_resume);\n" + "+\n" + "+ return ret;\n" + "+}\n" + "+\n" + "+/*\n" + "+ * Restore the state of the KVM timer when VM clock is restarted or state is\n" + "+ * synced to KVM.\n" + "+ */\n" + "+static int kvm_mips_restore_count(CPUState *cs)\n" + "+{\n" + "+ MIPSCPU *cpu = MIPS_CPU(cs);\n" + "+ CPUMIPSState *env = &cpu->env;\n" + "+ uint64_t count_ctl, count_resume;\n" + "+ int64_t now = get_clock();\n" + "+ int ret = 0;\n" + "+\n" + "+ /* check the timer is frozen */\n" + "+ ret = kvm_mips_get_one_reg64(cs, KVM_REG_MIPS_COUNT_CTL, &count_ctl);\n" + "+ if (ret < 0) {\n" + "+ return ret;\n" + "+ }\n" + "+ if (!(count_ctl & KVM_REG_MIPS_COUNT_CTL_DC)) {\n" + "+ /* freeze timer (sets COUNT_RESUME for us) */\n" + "+ count_ctl |= KVM_REG_MIPS_COUNT_CTL_DC;\n" + "+ ret = kvm_mips_put_one_reg64(cs, KVM_REG_MIPS_COUNT_CTL, &count_ctl);\n" + "+ if (ret < 0) {\n" + "+ return ret;\n" + "+ }\n" + "+ } else {\n" + "+ /* find time to resume the saved timer at */\n" + "+ now = get_clock();\n" + "+ count_resume = now - (cpu_get_clock_at(now) - env->count_save_time);\n" + "+ ret = kvm_mips_put_one_reg64(cs, KVM_REG_MIPS_COUNT_RESUME,\n" + "+ &count_resume);\n" + "+ if (ret < 0) {\n" + "+ return ret;\n" + "+ }\n" + "+ }\n" + "+\n" + "+ /* load CP0_Cause */\n" + "+ ret = kvm_mips_put_one_reg(cs, KVM_REG_MIPS_CP0_CAUSE, &env->CP0_Cause);\n" + "+ if (ret < 0) {\n" + "+ return ret;\n" + "+ }\n" + "+\n" + "+ /* load CP0_Count */\n" + "+ ret = kvm_mips_put_one_reg(cs, KVM_REG_MIPS_CP0_COUNT, &env->CP0_Count);\n" + "+ if (ret < 0) {\n" + "+ return ret;\n" + "+ }\n" + "+\n" + "+ /* resume KVM timer */\n" + "+ count_ctl &= ~KVM_REG_MIPS_COUNT_CTL_DC;\n" + "+ ret = kvm_mips_put_one_reg64(cs, KVM_REG_MIPS_COUNT_CTL, &count_ctl);\n" + "+ return ret;\n" + "+}\n" + "+\n" + "+/*\n" + "+ * Handle the VM clock being started or stopped\n" + "+ */\n" + "+static void kvm_mips_update_state(void *opaque, int running, RunState state)\n" + "+{\n" + "+ CPUState *cs = opaque;\n" + "+ int ret;\n" + "+\n" + "+ /*\n" + "+ * If state is already dirty (synced to QEMU) then the KVM timer state is\n" + "+ * already saved and can be restored when it is synced back to KVM.\n" + "+ */\n" + "+ if (!cs->kvm_vcpu_dirty) {\n" + "+ if (running) {\n" + "+ ret = kvm_mips_restore_count(cs);\n" + "+ } else {\n" + "+ ret = kvm_mips_save_count(cs);\n" + "+ }\n" + "+ if (ret < 0) {\n" + "+ fprintf(stderr, \"Failed update count (running=%d)\\n\",\n" + "+ running);\n" + "+ }\n" + "+ }\n" + "+}\n" + "+\n" + " static int kvm_mips_put_cp0_registers(CPUState *cs, int level)\n" + " {\n" + " MIPSCPU *cpu = MIPS_CPU(cs);\n" + "@@ -322,15 +494,16 @@ static int kvm_mips_put_cp0_registers(CPUState *cs, int level)\n" + " fprintf(stderr, \"Failed to put BADVADDR\\n\");\n" + " return ret;\n" + " }\n" + "- if (level != KVM_PUT_RUNTIME_STATE) {\n" + "- /* don't write guest count during runtime or the clock might drift */\n" + "- ret |= kvm_mips_put_one_reg(cs, KVM_REG_MIPS_CP0_COUNT,\n" + "- &env->CP0_Count);\n" + "+\n" + "+ /* If VM clock stopped then state will be restored when it is restarted */\n" + "+ if (runstate_is_running()) {\n" + "+ ret = kvm_mips_restore_count(cs);\n" + " if (ret < 0) {\n" + "- fprintf(stderr, \"Failed to put COMPARE\\n\");\n" + "+ fprintf(stderr, \"Failed to put COUNT\\n\");\n" + " return ret;\n" + " }\n" + " }\n" + "+\n" + " ret |= kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_ENTRYHI,\n" + " &env->CP0_EntryHi);\n" + " if (ret < 0) {\n" + "@@ -397,10 +570,6 @@ static int kvm_mips_get_cp0_registers(CPUState *cs)\n" + " if (ret < 0) {\n" + " return ret;\n" + " }\n" + "- ret |= kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_COUNT, &env->CP0_Count);\n" + "- if (ret < 0) {\n" + "- return ret;\n" + "- }\n" + " ret |= kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_ENTRYHI,\n" + " &env->CP0_EntryHi);\n" + " if (ret < 0) {\n" + "@@ -419,6 +588,15 @@ static int kvm_mips_get_cp0_registers(CPUState *cs)\n" + " if (ret < 0) {\n" + " return ret;\n" + " }\n" + "+\n" + "+ /* If VM clock stopped then state was already saved when it was stopped */\n" + "+ if (runstate_is_running()) {\n" + "+ ret = kvm_mips_save_count(cs);\n" + "+ if (ret < 0) {\n" + "+ return ret;\n" + "+ }\n" + "+ }\n" + "+\n" + " ret |= kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_EPC, &env->CP0_EPC);\n" + " if (ret < 0) {\n" + " return ret;\n" + "diff --git a/target-mips/machine.c b/target-mips/machine.c\n" + "index 0f36c9e..4916b13 100644\n" + "--- a/target-mips/machine.c\n" + "+++ b/target-mips/machine.c\n" + "@@ -150,6 +150,8 @@ void cpu_save(QEMUFile *f, void *opaque)\n" + " save_tc(f, &env->tcs[i]);\n" + " for (i = 0; i < MIPS_FPU_MAX; i++)\n" + " save_fpu(f, &env->fpus[i]);\n" + "+\n" + "+ qemu_put_sbe64s(f, &env->count_save_time);\n" + " }\n" + " \n" + " static void load_tc(QEMUFile *f, TCState *tc, int version_id)\n" + "@@ -310,5 +312,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)\n" + " \n" + " /* XXX: ensure compatibility for halted bit ? */\n" + " tlb_flush(CPU(cpu), 1);\n" + "+\n" + "+ if (version_id >= 5) {\n" + "+ qemu_get_sbe64s(f, &env->count_save_time);\n" + "+ }\n" + " return 0;\n" + " }\n" + "-- \n" + 1.9.3 -73ed7cdee6840b69f362dd1d82d2b56d498699a60134fde2fd7f322a5c8b0a0c +0bf7b602beea1679ed1a85fa43bbb487ec7257befad5cc4cd79f5fc5e6c4b076
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.