From 444ba6797ef6ef331fe9fd34309b1ec59caaede3 Mon Sep 17 00:00:00 2001 From: Orit Wasserman Date: Mon, 22 Jul 2013 20:29:41 +0300 Subject: Fix real mode guest migration Older KVM versions save CS dpl value to an invalid value for real mode guests (0x3). This patch detect this situation when loading CPU state and set all the segments dpl to zero. This will allow migration from older KVM on host without unrestricted guest to hosts with restricted guest support. For example migration from a Penryn host (with kernel 2.6.32) to a Westmere host (for real mode guest) will fail with "kvm: unhandled exit 80000021". Signed-off-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- target-i386/machine.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'target-i386') diff --git a/target-i386/machine.c b/target-i386/machine.c index 3659db9e94..af4c167f84 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -260,6 +260,24 @@ static int cpu_post_load(void *opaque, int version_id) CPUX86State *env = &cpu->env; int i; + /* + * Real mode guest segments register DPL should be zero. + * Older KVM version were setting it wrongly. + * Fixing it will allow live migration from such host that don't have + * restricted guest support to a host with unrestricted guest support + * (otherwise the migration will fail with invalid guest state + * error). + */ + if (!(env->cr[0] & CR0_PE_MASK) && + (env->segs[R_CS].flags >> DESC_DPL_SHIFT & 3) != 0) { + env->segs[R_CS].flags &= ~(env->segs[R_CS].flags & DESC_DPL_MASK); + env->segs[R_DS].flags &= ~(env->segs[R_DS].flags & DESC_DPL_MASK); + env->segs[R_ES].flags &= ~(env->segs[R_ES].flags & DESC_DPL_MASK); + env->segs[R_FS].flags &= ~(env->segs[R_FS].flags & DESC_DPL_MASK); + env->segs[R_GS].flags &= ~(env->segs[R_GS].flags & DESC_DPL_MASK); + env->segs[R_SS].flags &= ~(env->segs[R_SS].flags & DESC_DPL_MASK); + } + /* XXX: restore FPU round state */ env->fpstt = (env->fpus_vmstate >> 11) & 7; env->fpus = env->fpus_vmstate & ~0x3800; -- cgit v1.2.1 From 3e47c249b93d5cc1e0f9404dbe243682598ba8fb Mon Sep 17 00:00:00 2001 From: Orit Wasserman Date: Mon, 22 Jul 2013 20:29:42 +0300 Subject: Fix real mode guest segments dpl value in savevm Older KVM version put invalid value in the segments registers dpl field for real mode guests (0x3). This breaks migration from those hosts to hosts with unrestricted guest support. We detect it by checking CS dpl value for real mode guest and fix the dpl values of all the segment registers. Signed-off-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- target-i386/machine.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'target-i386') diff --git a/target-i386/machine.c b/target-i386/machine.c index af4c167f84..f9ec581faa 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -252,6 +252,24 @@ static void cpu_pre_save(void *opaque) } env->fpregs_format_vmstate = 0; + + /* + * Real mode guest segments register DPL should be zero. + * Older KVM version were setting it wrongly. + * Fixing it will allow live migration to host with unrestricted guest + * support (otherwise the migration will fail with invalid guest state + * error). + */ + if (!(env->cr[0] & CR0_PE_MASK) && + (env->segs[R_CS].flags >> DESC_DPL_SHIFT & 3) != 0) { + env->segs[R_CS].flags &= ~(env->segs[R_CS].flags & DESC_DPL_MASK); + env->segs[R_DS].flags &= ~(env->segs[R_DS].flags & DESC_DPL_MASK); + env->segs[R_ES].flags &= ~(env->segs[R_ES].flags & DESC_DPL_MASK); + env->segs[R_FS].flags &= ~(env->segs[R_FS].flags & DESC_DPL_MASK); + env->segs[R_GS].flags &= ~(env->segs[R_GS].flags & DESC_DPL_MASK); + env->segs[R_SS].flags &= ~(env->segs[R_SS].flags & DESC_DPL_MASK); + } + } static int cpu_post_load(void *opaque, int version_id) -- cgit v1.2.1