aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cpu-defs.h1
-rw-r--r--exec.c4
-rw-r--r--gdbstub.c8
-rw-r--r--hw/apic.c6
-rw-r--r--hw/pc.c1
-rw-r--r--kvm-all.c13
-rw-r--r--kvm.h8
-rw-r--r--monitor.c4
-rw-r--r--qemu-kvm.c17
-rw-r--r--qemu-kvm.h9
-rw-r--r--target-i386/machine.c7
-rw-r--r--target-ppc/machine.c6
12 files changed, 56 insertions, 28 deletions
diff --git a/cpu-defs.h b/cpu-defs.h
index a7d6d94e4..b7a6d8cb2 100644
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -143,6 +143,7 @@ struct KVMCPUState {
int signalled;
void *vcpu_ctx;
struct qemu_work_item *queued_work_first, *queued_work_last;
+ int regs_modified;
};
#define CPU_TEMP_BUF_NLONGS 128
diff --git a/exec.c b/exec.c
index e94be0c6b..29cd729d7 100644
--- a/exec.c
+++ b/exec.c
@@ -531,7 +531,7 @@ static void cpu_common_save(QEMUFile *f, void *opaque)
{
CPUState *env = opaque;
- cpu_synchronize_state(env, 0);
+ cpu_synchronize_state(env);
qemu_put_be32s(f, &env->halted);
qemu_put_be32s(f, &env->interrupt_request);
@@ -541,6 +541,7 @@ static int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
{
CPUState *env = opaque;
+ cpu_synchronize_state(env);
if (version_id != CPU_COMMON_SAVE_VERSION)
return -EINVAL;
@@ -550,7 +551,6 @@ static int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
version_id is increased. */
env->interrupt_request &= ~0x01;
tlb_flush(env, 1);
- cpu_synchronize_state(env, 1);
return 0;
}
diff --git a/gdbstub.c b/gdbstub.c
index 622b2cc5b..c9304cd20 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1569,8 +1569,8 @@ static void gdb_breakpoint_remove_all(void)
static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
{
#if defined(TARGET_I386)
+ cpu_synchronize_state(s->c_cpu);
s->c_cpu->eip = pc;
- cpu_synchronize_state(s->c_cpu, 1);
#elif defined (TARGET_PPC)
s->c_cpu->nip = pc;
#elif defined (TARGET_SPARC)
@@ -1756,7 +1756,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
}
break;
case 'g':
- cpu_synchronize_state(s->g_cpu, 0);
+ cpu_synchronize_state(s->g_cpu);
len = 0;
for (addr = 0; addr < num_g_regs; addr++) {
reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr);
@@ -1766,6 +1766,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
put_packet(s, buf);
break;
case 'G':
+ cpu_synchronize_state(s->g_cpu);
registers = mem_buf;
len = strlen(p) / 2;
hextomem((uint8_t *)registers, p, len);
@@ -1774,7 +1775,6 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
len -= reg_size;
registers += reg_size;
}
- cpu_synchronize_state(s->g_cpu, 1);
put_packet(s, "OK");
break;
case 'm':
@@ -1930,7 +1930,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
thread = strtoull(p+16, (char **)&p, 16);
env = find_cpu(thread);
if (env != NULL) {
- cpu_synchronize_state(env, 0);
+ cpu_synchronize_state(env);
len = snprintf((char *)mem_buf, sizeof(mem_buf),
"CPU#%d [%s]", env->cpu_index,
env->halted ? "halted " : "running");
diff --git a/hw/apic.c b/hw/apic.c
index 5ed2a87c9..18db3be4e 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -1059,8 +1059,11 @@ static const VMStateDescription vmstate_apic = {
static void apic_reset(void *opaque)
{
APICState *s = opaque;
- int bsp = cpu_is_bsp(s->cpu_env);
+ int bsp;
+ cpu_synchronize_state(s->cpu_env);
+
+ bsp = cpu_is_bsp(s->cpu_env);
s->apicbase = 0xfee00000 |
(bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
@@ -1075,7 +1078,6 @@ static void apic_reset(void *opaque)
*/
s->lvt[APIC_LVT_LINT0] = 0x700;
}
- cpu_synchronize_state(s->cpu_env, 1);
qemu_kvm_load_lapic(s->cpu_env);
}
diff --git a/hw/pc.c b/hw/pc.c
index 6b3b8ddf8..67713372c 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1099,6 +1099,7 @@ CPUState *pc_new_cpu(const char *cpu_model)
fprintf(stderr, "Unable to find x86 CPU definition\n");
exit(1);
}
+ env->kvm_cpu_state.regs_modified = 1;
if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) {
env->cpuid_apic_id = env->cpu_index;
/* APIC reset callback resets cpu */
diff --git a/kvm-all.c b/kvm-all.c
index 794ac2c0a..d5bf7ae1b 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -579,6 +579,14 @@ static void kvm_run_coalesced_mmio(CPUState *env, struct kvm_run *run)
#endif
}
+void kvm_cpu_synchronize_state(CPUState *env)
+{
+ if (!env->kvm_state->regs_modified) {
+ kvm_arch_get_registers(env);
+ env->kvm_state->regs_modified = 1;
+ }
+}
+
int kvm_cpu_exec(CPUState *env)
{
struct kvm_run *run = env->kvm_run;
@@ -593,6 +601,11 @@ int kvm_cpu_exec(CPUState *env)
break;
}
+ if (env->kvm_state->regs_modified) {
+ kvm_arch_put_registers(env);
+ env->kvm_state->regs_modified = 0;
+ }
+
kvm_arch_pre_run(env, run);
ret = kvm_vcpu_ioctl(env, KVM_RUN, 0);
kvm_arch_post_run(env, run);
diff --git a/kvm.h b/kvm.h
index cca8b3da0..5f7029901 100644
--- a/kvm.h
+++ b/kvm.h
@@ -131,16 +131,14 @@ int kvm_check_extension(KVMState *s, unsigned int extension);
uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
int reg);
+void kvm_cpu_synchronize_state(CPUState *env);
/* generic hooks - to be moved/refactored once there are more users */
-static inline void cpu_synchronize_state(CPUState *env, int modified)
+static inline void cpu_synchronize_state(CPUState *env)
{
if (kvm_enabled()) {
- if (modified)
- kvm_arch_put_registers(env);
- else
- kvm_arch_get_registers(env);
+ kvm_cpu_synchronize_state(env);
}
}
diff --git a/monitor.c b/monitor.c
index 0acee726c..5e26e9a38 100644
--- a/monitor.c
+++ b/monitor.c
@@ -334,7 +334,7 @@ static CPUState *mon_get_cpu(void)
if (!cur_mon->mon_cpu) {
mon_set_cpu(0);
}
- cpu_synchronize_state(cur_mon->mon_cpu, 0);
+ cpu_synchronize_state(cur_mon->mon_cpu);
return cur_mon->mon_cpu;
}
@@ -361,7 +361,7 @@ static void do_info_cpus(Monitor *mon)
mon_get_cpu();
for(env = first_cpu; env != NULL; env = env->next_cpu) {
- cpu_synchronize_state(env, 0);
+ cpu_synchronize_state(env);
monitor_printf(mon, "%c CPU #%d:",
(env == mon->mon_cpu) ? '*' : ' ',
env->cpu_index);
diff --git a/qemu-kvm.c b/qemu-kvm.c
index b59e40370..2d3ca7166 100644
--- a/qemu-kvm.c
+++ b/qemu-kvm.c
@@ -874,6 +874,15 @@ int kvm_set_mpstate(kvm_vcpu_context_t vcpu, struct kvm_mp_state *mp_state)
}
#endif
+void kvm_cpu_synchronize_state(CPUState *env)
+{
+ if (!env->kvm_cpu_state.regs_modified) {
+ kvm_arch_get_registers(env);
+ kvm_arch_save_mpstate(env);
+ env->kvm_cpu_state.regs_modified = 1;
+ }
+}
+
static int handle_mmio(kvm_vcpu_context_t vcpu)
{
unsigned long addr = vcpu->run->mmio.phys_addr;
@@ -947,6 +956,7 @@ int kvm_run(kvm_vcpu_context_t vcpu, void *env)
int fd = vcpu->fd;
struct kvm_run *run = vcpu->run;
kvm_context_t kvm = vcpu->kvm;
+ CPUState *_env = env;
again:
push_nmi(kvm);
@@ -954,6 +964,13 @@ int kvm_run(kvm_vcpu_context_t vcpu, void *env)
if (!kvm->irqchip_in_kernel)
run->request_interrupt_window = kvm_arch_try_push_interrupts(env);
#endif
+
+ if (_env->kvm_cpu_state.regs_modified) {
+ kvm_arch_put_registers(_env);
+ kvm_arch_load_mpstate(_env);
+ _env->kvm_cpu_state.regs_modified = 0;
+ }
+
r = pre_kvm_run(kvm, env);
if (r)
return r;
diff --git a/qemu-kvm.h b/qemu-kvm.h
index 6476e6f0a..2c1730b11 100644
--- a/qemu-kvm.h
+++ b/qemu-kvm.h
@@ -1165,13 +1165,12 @@ static inline void kvm_arch_put_registers(CPUState *env)
kvm_load_mpstate(env);
}
-static inline void cpu_synchronize_state(CPUState *env, int modified)
+void kvm_cpu_synchronize_state(CPUState *env);
+
+static inline void cpu_synchronize_state(CPUState *env)
{
if (kvm_enabled()) {
- if (modified)
- kvm_arch_put_registers(env);
- else
- kvm_arch_get_registers(env);
+ kvm_cpu_synchronize_state(env);
}
}
diff --git a/target-i386/machine.c b/target-i386/machine.c
index ca32a92a0..a4f2d22fb 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -33,10 +33,7 @@ void cpu_save(QEMUFile *f, void *opaque)
int32_t pending_irq;
int i, bit;
- if (kvm_enabled()) {
- kvm_save_registers(env);
- kvm_arch_save_mpstate(env);
- }
+ cpu_synchronize_state(env);
for(i = 0; i < CPU_NB_REGS; i++)
qemu_put_betls(f, &env->regs[i]);
@@ -209,6 +206,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
int32_t a20_mask;
int32_t pending_irq;
+ cpu_synchronize_state(env);
if (version_id < 3 || version_id > CPU_SAVE_VERSION)
return -EINVAL;
for(i = 0; i < CPU_NB_REGS; i++)
@@ -383,7 +381,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
/* XXX: compute redundant hflags bits */
env->hflags = hflags;
tlb_flush(env, 1);
- cpu_synchronize_state(env, 1);
if (kvm_enabled()) {
/* when in-kernel irqchip is used, env->halted causes deadlock
because no userspace IRQs will ever clear this flag */
diff --git a/target-ppc/machine.c b/target-ppc/machine.c
index 101f408b5..ead38e180 100644
--- a/target-ppc/machine.c
+++ b/target-ppc/machine.c
@@ -8,7 +8,7 @@ void cpu_save(QEMUFile *f, void *opaque)
CPUState *env = (CPUState *)opaque;
unsigned int i, j;
- cpu_synchronize_state(env, 0);
+ cpu_synchronize_state(env);
for (i = 0; i < 32; i++)
qemu_put_betls(f, &env->gpr[i]);
@@ -97,6 +97,8 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
CPUState *env = (CPUState *)opaque;
unsigned int i, j;
+ cpu_synchronize_state(env);
+
for (i = 0; i < 32; i++)
qemu_get_betls(f, &env->gpr[i]);
#if !defined(TARGET_PPC64)
@@ -178,7 +180,5 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
qemu_get_sbe32s(f, &env->mmu_idx);
qemu_get_sbe32s(f, &env->power_mode);
- cpu_synchronize_state(env, 1);
-
return 0;
}