* [PATCH] fix for Failed VMEntry on VMX
@ 2006-05-02 14:58 David Lively
2006-05-02 16:19 ` Keir Fraser
0 siblings, 1 reply; 6+ messages in thread
From: David Lively @ 2006-05-02 14:58 UTC (permalink / raw)
To: xen-devel
[-- Attachment #1: Type: text/plain, Size: 589 bytes --]
I've been getting a "Failed VMEntry" when trying to boot a second
VMX guest (while the first one is still running, but is no longer in
real mode). This patch fixes it.
VMX(assist) uses vm86 in its real mode emulation. Upon vmentry
into a guest in vm86 mode, all segment bases must be equal to the
corresponding segment selector shifted left four bits. The vmx
routine vmx_load_cpu_guest_regs() was loading the segment
selectors. Now it makes sure to set the segment bases appropriately
if we're in vm86 mode.
Tested on 64bit hypervisor with 2 64-bit VMX domUs (on
2-way dom0).
Dave
[-- Attachment #2: failed-vmentry-fix.patch --]
[-- Type: text/x-patch, Size: 2249 bytes --]
Ensure segment bases are consistent with their
selectors for VMX guests in VM86 mode.
Signed-off-by: David Lively <dlively@virtualiron.com>
diff -r 880433ba7487 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c Mon May 1 17:08:02 2006 -0400
+++ b/xen/arch/x86/hvm/vmx/vmx.c Tue May 2 10:31:03 2006 -0400
@@ -487,6 +487,33 @@ static void vmx_store_cpu_guest_regs(
__vmptrld(virt_to_maddr(current->arch.hvm_vmx.vmcs));
}
+/* Ensure segment bases are consistent with their
+ * selectors for guests in VM86 mode.
+ */
+static void fixup_vm86_seg_bases(struct cpu_user_regs *regs)
+{
+ unsigned long base;
+
+ BUG_ON(__vmread(GUEST_ES_BASE, &base));
+ if (regs->es << 4 != base)
+ BUG_ON(__vmwrite(GUEST_ES_BASE, regs->es << 4));
+ BUG_ON(__vmread(GUEST_CS_BASE, &base));
+ if (regs->cs << 4 != base)
+ BUG_ON(__vmwrite(GUEST_CS_BASE, regs->cs << 4));
+ BUG_ON(__vmread(GUEST_SS_BASE, &base));
+ if (regs->ss << 4 != base)
+ BUG_ON(__vmwrite(GUEST_SS_BASE, regs->ss << 4));
+ BUG_ON(__vmread(GUEST_DS_BASE, &base));
+ if (regs->ds << 4 != base)
+ BUG_ON(__vmwrite(GUEST_DS_BASE, regs->ds << 4));
+ BUG_ON(__vmread(GUEST_FS_BASE, &base));
+ if (regs->fs << 4 != base)
+ BUG_ON(__vmwrite(GUEST_FS_BASE, regs->fs << 4));
+ BUG_ON(__vmread(GUEST_GS_BASE, &base));
+ if (regs->gs << 4 != base)
+ BUG_ON(__vmwrite(GUEST_GS_BASE, regs->gs << 4));
+}
+
void vmx_load_cpu_guest_regs(struct vcpu *v, struct cpu_user_regs *regs)
{
if ( v != current )
@@ -523,6 +550,8 @@ void vmx_load_cpu_guest_regs(struct vcpu
__vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
else
__vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
+ if (regs->rflags & EF_VM)
+ fixup_vm86_seg_bases(regs);
__vmwrite(GUEST_CS_SELECTOR, regs->cs);
__vmwrite(GUEST_RIP, regs->rip);
@@ -540,6 +569,8 @@ void vmx_load_cpu_guest_regs(struct vcpu
__vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
else
__vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
+ if (regs->eflags & EF_VM)
+ fixup_vm86_seg_bases(regs);
__vmwrite(GUEST_CS_SELECTOR, regs->cs);
__vmwrite(GUEST_RIP, regs->eip);
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 6+ messages in thread
* RE: [PATCH] fix for Failed VMEntry on VMX
@ 2006-05-02 15:30 Petersson, Mats
2006-05-02 16:04 ` Dave Lively
0 siblings, 1 reply; 6+ messages in thread
From: Petersson, Mats @ 2006-05-02 15:30 UTC (permalink / raw)
To: David Lively, xen-devel
> -----Original Message-----
> From: xen-devel-bounces@lists.xensource.com
> [mailto:xen-devel-bounces@lists.xensource.com] On Behalf Of
> David Lively
> Sent: 02 May 2006 15:58
> To: xen-devel@lists.xensource.com
> Subject: [Xen-devel] [PATCH] fix for Failed VMEntry on VMX
>
> I've been getting a "Failed VMEntry" when trying to boot a
> second VMX guest (while the first one is still running, but
> is no longer in real mode). This patch fixes it.
>
> VMX(assist) uses vm86 in its real mode emulation. Upon
> vmentry into a guest in vm86 mode, all segment bases must be
> equal to the corresponding segment selector shifted left four
> bits. The vmx routine vmx_load_cpu_guest_regs() was loading
> the segment selectors. Now it makes sure to set the segment
> bases appropriately if we're in vm86 mode.
>
> Tested on 64bit hypervisor with 2 64-bit VMX domUs (on 2-way dom0).
Will this not break "big real-mode" type behaviour? Or am I missing
something here? Certainly the x86 architecture itself allows the segment
(in real mode) to have a different base address than the "selector << 4"
that you get when you LOAD a selector in REAL MODE. It's just that in
real-mode, you can't set a different base, but code that has temporarily
run in non-real mode (i.e. enter protected mode then set segment
register than exit back to real-mode) can do all sorts of magic. If this
is really expected behaviour, it would also be expected to have a limit
of 0xffff, or you're sort of half-breaking the rules still...
--
Mats
>
> Dave
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] fix for Failed VMEntry on VMX
2006-05-02 15:30 Petersson, Mats
@ 2006-05-02 16:04 ` Dave Lively
0 siblings, 0 replies; 6+ messages in thread
From: Dave Lively @ 2006-05-02 16:04 UTC (permalink / raw)
To: Petersson, Mats; +Cc: xen-devel
[-- Attachment #1.1: Type: text/plain, Size: 1331 bytes --]
I don't think so. If a CPU in real mode is allowed to use
a segment base set in another mode (to something other than
sel << 4), I think that's outside the scope of what vmxassist
was designed to do. (Because vmxassist relies on vm86 mode,
and the VMX spec says vm86 mode guests must have their segment
bases = sel << 4 upon vmentry ... and the chips certainly behave
as specified in this regard.)
I don't really understand the implications of not supporting arbitrary
segment bases in real mode guests (what code actually does this?),
but since it can't work in the current implementation, this patch must
not be breaking it ...
Dave
Will this not break "big real-mode" type behaviour? Or am I missing
> something here? Certainly the x86 architecture itself allows the segment
> (in real mode) to have a different base address than the "selector << 4"
> that you get when you LOAD a selector in REAL MODE. It's just that in
> real-mode, you can't set a different base, but code that has temporarily
> run in non-real mode (i.e. enter protected mode then set segment
> register than exit back to real-mode) can do all sorts of magic. If this
> is really expected behaviour, it would also be expected to have a limit
> of 0xffff, or you're sort of half-breaking the rules still...
>
> --
> Mats
>
[-- Attachment #1.2: Type: text/html, Size: 1617 bytes --]
[-- Attachment #2: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] fix for Failed VMEntry on VMX
2006-05-02 14:58 [PATCH] fix for Failed VMEntry on VMX David Lively
@ 2006-05-02 16:19 ` Keir Fraser
2006-05-02 16:58 ` David Lively
0 siblings, 1 reply; 6+ messages in thread
From: Keir Fraser @ 2006-05-02 16:19 UTC (permalink / raw)
To: David Lively; +Cc: xen-devel
On 2 May 2006, at 15:58, David Lively wrote:
> I've been getting a "Failed VMEntry" when trying to boot a second
> VMX guest (while the first one is still running, but is no longer in
> real mode). This patch fixes it.
Please `or' the vmread/vmwrite error returns together into an error
variable and BUG_ON(error) just once at the bottom of the function.
Also extend the comment a little to explicitly explain that this is
working around a VMENTRY validation check.
Apart from that it looks good.
-- Keir
^ permalink raw reply [flat|nested] 6+ messages in thread
* RE: [PATCH] fix for Failed VMEntry on VMX
@ 2006-05-02 16:34 Petersson, Mats
0 siblings, 0 replies; 6+ messages in thread
From: Petersson, Mats @ 2006-05-02 16:34 UTC (permalink / raw)
To: Dave Lively; +Cc: xen-devel
[-- Attachment #1.1: Type: text/plain, Size: 3562 bytes --]
Leendert was fixing problems caused by this a while back.
The essence is that you have some code that want's to generally access
real-mode BIOS functions, but also access "high memory", typically when
booting [loading the image from disk - once the image is in memory we
can switch to protected mode once and for all] (this is ONE example,
there's other things you can do that needs this functionality). There's
two solutions to my example:
1. Switch between real-mode and protected mode many times - this is not
just performance-wise a bad idea, but it also makes the code have lots
of stuff in it that causes problems - for example, do you allow
interrupts only when in protected mode, only in real-mode, or do you
have TWO sets of interrupt handling and switch that too? [If you rely on
the BIOS, you probably need to use REAL MODE for interrupt handling].
2. Do a short visit into protected mode and set some segment register to
base = 0, limit = 4G and use that for the duration of this processing.
Typically, this is the GS or FS segment, since that segment isn't being
used by the BIOS or commonly used in real-mode code. Then you can use a
GS prefix together with a 32-bit address override [i.e. mov %eax,
gs:(%ebx) - or whatever the syntax is in gas]. If you tried this in a
"traditional" real-mode register, it would GP-fault if the ebx register
is bigger than 64K, and combined with the maximum segment base being
0xFFFF, you can only access (1M + 64K - 16) bytes of memory, which may
not be good enough to for example load the OS into memory.
I know that SLES 9 uses this mode of operation for graphical boot mode -
it loads the graphics image from the disk onto the VGA card using "big
real mode".
What I'm not sure about is whether this gets run only once during boot
(in which case it's fine) or every time you switch to/from the domain
(in which case it isn't fine).
--
Mats
________________________________
From: Dave Lively [mailto:dave.lively@gmail.com]
Sent: 02 May 2006 17:05
To: Petersson, Mats
Cc: xen-devel@lists.xensource.com
Subject: Re: [Xen-devel] [PATCH] fix for Failed VMEntry on VMX
I don't think so. If a CPU in real mode is allowed to use
a segment base set in another mode (to something other than
sel << 4), I think that's outside the scope of what vmxassist
was designed to do. (Because vmxassist relies on vm86 mode,
and the VMX spec says vm86 mode guests must have their segment
bases = sel << 4 upon vmentry ... and the chips certainly behave
as specified in this regard.)
I don't really understand the implications of not supporting
arbitrary
segment bases in real mode guests (what code actually does
this?),
but since it can't work in the current implementation, this
patch must
not be breaking it ...
Dave
Will this not break "big real-mode" type behaviour? Or
am I missing
something here? Certainly the x86 architecture itself
allows the segment
(in real mode) to have a different base address than the
"selector << 4"
that you get when you LOAD a selector in REAL MODE. It's
just that in
real-mode, you can't set a different base, but code that
has temporarily
run in non-real mode (i.e. enter protected mode then set
segment
register than exit back to real-mode) can do all sorts
of magic. If this
is really expected behaviour, it would also be expected
to have a limit
of 0xffff, or you're sort of half-breaking the rules
still...
--
Mats
[-- Attachment #1.2: Type: text/html, Size: 5819 bytes --]
[-- Attachment #2: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] fix for Failed VMEntry on VMX
2006-05-02 16:19 ` Keir Fraser
@ 2006-05-02 16:58 ` David Lively
0 siblings, 0 replies; 6+ messages in thread
From: David Lively @ 2006-05-02 16:58 UTC (permalink / raw)
To: Keir Fraser; +Cc: xen-devel
[-- Attachment #1: Type: text/plain, Size: 608 bytes --]
Okay - revised patch attached.
Thanks,
Dave
Keir Fraser wrote:
>
> On 2 May 2006, at 15:58, David Lively wrote:
>
>> I've been getting a "Failed VMEntry" when trying to boot a second
>> VMX guest (while the first one is still running, but is no longer in
>> real mode). This patch fixes it.
>
>
> Please `or' the vmread/vmwrite error returns together into an error
> variable and BUG_ON(error) just once at the bottom of the function.
> Also extend the comment a little to explicitly explain that this is
> working around a VMENTRY validation check.
>
> Apart from that it looks good.
>
> -- Keir
>
[-- Attachment #2: failed-vmentry-fix.patch --]
[-- Type: text/x-patch, Size: 2663 bytes --]
Ensure segment bases are consistent with their
selectors for VMX guests in VM86 mode.
Signed-off-by: David Lively <dlively@virtualiron.com>
diff -r 880433ba7487 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c Mon May 1 17:08:02 2006 -0400
+++ b/xen/arch/x86/hvm/vmx/vmx.c Tue May 2 12:43:47 2006 -0400
@@ -487,6 +487,44 @@ static void vmx_store_cpu_guest_regs(
__vmptrld(virt_to_maddr(current->arch.hvm_vmx.vmcs));
}
+/* The VMX spec (section 4.3.1.2, Checks on Guest Segment
+ * Registers) says that virtual-8086 mode guests' segment
+ * base-address fields in the VMCS must be equal to their
+ * corresponding segment selector field shifted right by
+ * four bits upon vmentry.
+ *
+ * This function (called only for VM86-mode guests) fixes
+ * the bases to be consistent with the selectors in regs
+ * if they're not already. Without this, we can fail the
+ * vmentry check mentioned above.
+ */
+static void fixup_vm86_seg_bases(struct cpu_user_regs *regs)
+{
+ int err = 0;
+ unsigned long base;
+
+ err |= __vmread(GUEST_ES_BASE, &base);
+ if (regs->es << 4 != base)
+ err |= __vmwrite(GUEST_ES_BASE, regs->es << 4);
+ err |= __vmread(GUEST_CS_BASE, &base);
+ if (regs->cs << 4 != base)
+ err |= __vmwrite(GUEST_CS_BASE, regs->cs << 4);
+ err |= __vmread(GUEST_SS_BASE, &base);
+ if (regs->ss << 4 != base)
+ err |= __vmwrite(GUEST_SS_BASE, regs->ss << 4);
+ err |= __vmread(GUEST_DS_BASE, &base);
+ if (regs->ds << 4 != base)
+ err |= __vmwrite(GUEST_DS_BASE, regs->ds << 4);
+ err |= __vmread(GUEST_FS_BASE, &base);
+ if (regs->fs << 4 != base)
+ err |= __vmwrite(GUEST_FS_BASE, regs->fs << 4);
+ err |= __vmread(GUEST_GS_BASE, &base);
+ if (regs->gs << 4 != base)
+ err |= __vmwrite(GUEST_GS_BASE, regs->gs << 4);
+
+ BUG_ON(err);
+}
+
void vmx_load_cpu_guest_regs(struct vcpu *v, struct cpu_user_regs *regs)
{
if ( v != current )
@@ -523,6 +561,8 @@ void vmx_load_cpu_guest_regs(struct vcpu
__vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
else
__vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
+ if (regs->rflags & EF_VM)
+ fixup_vm86_seg_bases(regs);
__vmwrite(GUEST_CS_SELECTOR, regs->cs);
__vmwrite(GUEST_RIP, regs->rip);
@@ -540,6 +580,8 @@ void vmx_load_cpu_guest_regs(struct vcpu
__vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
else
__vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
+ if (regs->eflags & EF_VM)
+ fixup_vm86_seg_bases(regs);
__vmwrite(GUEST_CS_SELECTOR, regs->cs);
__vmwrite(GUEST_RIP, regs->eip);
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2006-05-02 16:58 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-02 14:58 [PATCH] fix for Failed VMEntry on VMX David Lively
2006-05-02 16:19 ` Keir Fraser
2006-05-02 16:58 ` David Lively
-- strict thread matches above, loose matches on Subject: below --
2006-05-02 15:30 Petersson, Mats
2006-05-02 16:04 ` Dave Lively
2006-05-02 16:34 Petersson, Mats
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.