diff mbox

Fix for incorrect SYSRET instruction implementation -- anyone looked at this yet?

Message ID 201503091548.01462.wpaul@windriver.com
State New
Headers show

Commit Message

Bill Paul March 9, 2015, 10:48 p.m. UTC
I'm certain I'm sending this in plain text mode this time. According to my 
reading of the Intel documentation, the SYSRET instruction is supposed to 
force the RPL bits of the %ss register to 3 when returning to user mode. The 
actual sequence is:

SS.Selector <-- (IA32_STAR[63:48]+8) OR 3; (* RPL forced to 3 *)

However, the code in helper_sysret() leaves them at 0 (in other words, the "OR 
3" part of the above sequence is missing). It does set the privilege level 
bits of %cs correctly though.

This has caused me trouble with some of my VxWorks development: code that runs 
okay on real hardware will crash on QEMU, unless I apply the patch below.

Can someone confirm that this is in fact a real bug? The Intel architecture 
manual seems quite clear about the SYSRET behavior. The bug seems to have been 
around as far back as QEMU 0.10.5.

I am using QEMU 2.2.0 on FreeBSD/amd64 9.1-RELEASE.

-Bill

Signed-off-by: Bill Paul <wpaul@windriver.com>

---
 target-i386/seg_helper.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Comments

Fam Zheng March 10, 2015, 8:29 a.m. UTC | #1
On Mon, 03/09 15:48, Bill Paul wrote:
> I'm certain I'm sending this in plain text mode this time. According to my 
> reading of the Intel documentation, the SYSRET instruction is supposed to 
> force the RPL bits of the %ss register to 3 when returning to user mode. The 
> actual sequence is:
> 
> SS.Selector <-- (IA32_STAR[63:48]+8) OR 3; (* RPL forced to 3 *)
> 
> However, the code in helper_sysret() leaves them at 0 (in other words, the "OR 
> 3" part of the above sequence is missing). It does set the privilege level 
> bits of %cs correctly though.
> 
> This has caused me trouble with some of my VxWorks development: code that runs 
> okay on real hardware will crash on QEMU, unless I apply the patch below.
> 
> Can someone confirm that this is in fact a real bug? The Intel architecture 
> manual seems quite clear about the SYSRET behavior. The bug seems to have been 
> around as far back as QEMU 0.10.5.
> 
> I am using QEMU 2.2.0 on FreeBSD/amd64 9.1-RELEASE.
> 
> -Bill

Reviewed-by: Fam Zheng <famz@redhat.com>

It matches the manual now. Cc'ing maintainers and qemu-stable.

Some trimming may be needed when applying, please follow the guideline [1] when
submitting patches - better to add "[PATCH]" prefix to subject, Cc relevant
people, and leave any unrelated words to the patch itself below the "---" line
so that they don't get committed to the git log, including those in the subject
line.

[1]: http://wiki.qemu-project.org/Contribute/SubmitAPatch

> 
> Signed-off-by: Bill Paul <wpaul@windriver.com>
> 
> ---
>  target-i386/seg_helper.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c
> index fa374d0..2bc757a 100644
> --- a/target-i386/seg_helper.c
> +++ b/target-i386/seg_helper.c
> @@ -1043,7 +1043,7 @@ void helper_sysret(CPUX86State *env, int dflag)
>                                     DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
>              env->eip = (uint32_t)env->regs[R_ECX];
>          }
> -        cpu_x86_load_seg_cache(env, R_SS, selector + 8,
> +        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) | 3,
>                                 0, 0xffffffff,
>                                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
>                                 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
> @@ -1056,7 +1056,7 @@ void helper_sysret(CPUX86State *env, int dflag)
>                                 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
>                                 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
>          env->eip = (uint32_t)env->regs[R_ECX];
> -        cpu_x86_load_seg_cache(env, R_SS, selector + 8,
> +        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) | 3,
>                                 0, 0xffffffff,
>                                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
>                                 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
> -- 
> 1.8.0
>
Paolo Bonzini March 10, 2015, 9:38 a.m. UTC | #2
On 09/03/2015 23:48, Bill Paul wrote:
> I'm certain I'm sending this in plain text mode this time. According to my 
> reading of the Intel documentation, the SYSRET instruction is supposed to 
> force the RPL bits of the %ss register to 3 when returning to user mode. The 
> actual sequence is:
> 
> SS.Selector <-- (IA32_STAR[63:48]+8) OR 3; (* RPL forced to 3 *)
> 
> However, the code in helper_sysret() leaves them at 0 (in other words, the "OR 
> 3" part of the above sequence is missing). It does set the privilege level 
> bits of %cs correctly though.
> 
> This has caused me trouble with some of my VxWorks development: code that runs 
> okay on real hardware will crash on QEMU, unless I apply the patch below.
> 
> Can someone confirm that this is in fact a real bug? The Intel architecture 
> manual seems quite clear about the SYSRET behavior. The bug seems to have been 
> around as far back as QEMU 0.10.5.
> 
> I am using QEMU 2.2.0 on FreeBSD/amd64 9.1-RELEASE.
> 
> -Bill
> 
> Signed-off-by: Bill Paul <wpaul@windriver.com>
> 
> ---
>  target-i386/seg_helper.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c
> index fa374d0..2bc757a 100644
> --- a/target-i386/seg_helper.c
> +++ b/target-i386/seg_helper.c
> @@ -1043,7 +1043,7 @@ void helper_sysret(CPUX86State *env, int dflag)
>                                     DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
>              env->eip = (uint32_t)env->regs[R_ECX];
>          }
> -        cpu_x86_load_seg_cache(env, R_SS, selector + 8,
> +        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) | 3,
>                                 0, 0xffffffff,
>                                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
>                                 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
> @@ -1056,7 +1056,7 @@ void helper_sysret(CPUX86State *env, int dflag)
>                                 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
>                                 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
>          env->eip = (uint32_t)env->regs[R_ECX];
> -        cpu_x86_load_seg_cache(env, R_SS, selector + 8,
> +        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) | 3,
>                                 0, 0xffffffff,
>                                 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
>                                 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
> 

Applied, thanks.  I will send a pull request today.

Paolo
diff mbox

Patch

diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c
index fa374d0..2bc757a 100644
--- a/target-i386/seg_helper.c
+++ b/target-i386/seg_helper.c
@@ -1043,7 +1043,7 @@  void helper_sysret(CPUX86State *env, int dflag)
                                    DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
             env->eip = (uint32_t)env->regs[R_ECX];
         }
-        cpu_x86_load_seg_cache(env, R_SS, selector + 8,
+        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) | 3,
                                0, 0xffffffff,
                                DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                                DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
@@ -1056,7 +1056,7 @@  void helper_sysret(CPUX86State *env, int dflag)
                                DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
                                DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
         env->eip = (uint32_t)env->regs[R_ECX];
-        cpu_x86_load_seg_cache(env, R_SS, selector + 8,
+        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) | 3,
                                0, 0xffffffff,
                                DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                                DESC_S_MASK | (3 << DESC_DPL_SHIFT) |