[PATCH] target/i386: Fix legacy page table walk

Alexander Graf posted 1 patch 2 weeks, 3 days ago
target/i386/cpu.h                    | 1 +
target/i386/tcg/seg_helper.c         | 2 +-
target/i386/tcg/sysemu/excp_helper.c | 2 +-
3 files changed, 3 insertions(+), 2 deletions(-)
[PATCH] target/i386: Fix legacy page table walk
Posted by Alexander Graf 2 weeks, 3 days ago
Commit b56617bbcb4 ("target/i386: Walk NPT in guest real mode") added
logic to run the page table walker even in real mode if we are in NPT
mode.  That function then determined whether real mode or paging is
active based on whether the pg_mode variable was 0.

Unfortunately pg_mode is 0 in two situations:

  1) Paging is disabled (real mode)
  2) Paging is in 2-level paging mode (32bit without PAE)

That means the walker now assumed that 2-level paging mode was real
mode, breaking NetBSD as well as Windows XP.

To fix that, this patch adds a new PG flag to pg_mode which indicates
whether paging is active at all and uses that to determine whether we
are in real mode or not.

Cc: qemu-stable@nongnu.org
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2654
Fixes: b56617bbcb4 ("target/i386: Walk NPT in guest real mode")
Signed-off-by: Alexander Graf <graf@amazon.com>
Reported-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 target/i386/cpu.h                    | 1 +
 target/i386/tcg/seg_helper.c         | 2 +-
 target/i386/tcg/sysemu/excp_helper.c | 2 +-
 3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index c24d81bf31..99d4805ac1 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -346,6 +346,7 @@ typedef enum X86Seg {
 #define PG_MODE_PKE      (1 << 17)
 #define PG_MODE_PKS      (1 << 18)
 #define PG_MODE_SMEP     (1 << 19)
+#define PG_MODE_PG       (1 << 20)
 
 #define MCG_CTL_P       (1ULL<<8)   /* MCG_CAP register available */
 #define MCG_SER_P       (1ULL<<24) /* MCA recovery/new status bits */
diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c
index 02ae6a0d1f..71962113fb 100644
--- a/target/i386/tcg/seg_helper.c
+++ b/target/i386/tcg/seg_helper.c
@@ -94,7 +94,7 @@ static uint32_t popl(StackAccess *sa)
 
 int get_pg_mode(CPUX86State *env)
 {
-    int pg_mode = 0;
+    int pg_mode = PG_MODE_PG;
     if (!(env->cr[0] & CR0_PG_MASK)) {
         return 0;
     }
diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c
index da187c8792..02d3486421 100644
--- a/target/i386/tcg/sysemu/excp_helper.c
+++ b/target/i386/tcg/sysemu/excp_helper.c
@@ -298,7 +298,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
         /* combine pde and pte nx, user and rw protections */
         ptep &= pte ^ PG_NX_MASK;
         page_size = 4096;
-    } else if (pg_mode) {
+    } else if (pg_mode & PG_MODE_PG) {
         /*
          * Page table level 2
          */
-- 
2.40.1




Amazon Web Services Development Center Germany GmbH
Krausenstr. 38
10117 Berlin
Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss
Eingetragen am Amtsgericht Charlottenburg unter HRB 257764 B
Sitz: Berlin
Ust-ID: DE 365 538 597
Re: [PATCH] target/i386: Fix legacy page table walk
Posted by Mark Cave-Ayland 2 weeks, 2 days ago
On 06/11/2024 15:43, Alexander Graf wrote:

> Commit b56617bbcb4 ("target/i386: Walk NPT in guest real mode") added
> logic to run the page table walker even in real mode if we are in NPT
> mode.  That function then determined whether real mode or paging is
> active based on whether the pg_mode variable was 0.
> 
> Unfortunately pg_mode is 0 in two situations:
> 
>    1) Paging is disabled (real mode)
>    2) Paging is in 2-level paging mode (32bit without PAE)
> 
> That means the walker now assumed that 2-level paging mode was real
> mode, breaking NetBSD as well as Windows XP.
> 
> To fix that, this patch adds a new PG flag to pg_mode which indicates
> whether paging is active at all and uses that to determine whether we
> are in real mode or not.
> 
> Cc: qemu-stable@nongnu.org
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2654
> Fixes: b56617bbcb4 ("target/i386: Walk NPT in guest real mode")
> Signed-off-by: Alexander Graf <graf@amazon.com>
> Reported-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>   target/i386/cpu.h                    | 1 +
>   target/i386/tcg/seg_helper.c         | 2 +-
>   target/i386/tcg/sysemu/excp_helper.c | 2 +-
>   3 files changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/target/i386/cpu.h b/target/i386/cpu.h
> index c24d81bf31..99d4805ac1 100644
> --- a/target/i386/cpu.h
> +++ b/target/i386/cpu.h
> @@ -346,6 +346,7 @@ typedef enum X86Seg {
>   #define PG_MODE_PKE      (1 << 17)
>   #define PG_MODE_PKS      (1 << 18)
>   #define PG_MODE_SMEP     (1 << 19)
> +#define PG_MODE_PG       (1 << 20)
>   
>   #define MCG_CTL_P       (1ULL<<8)   /* MCG_CAP register available */
>   #define MCG_SER_P       (1ULL<<24) /* MCA recovery/new status bits */
> diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c
> index 02ae6a0d1f..71962113fb 100644
> --- a/target/i386/tcg/seg_helper.c
> +++ b/target/i386/tcg/seg_helper.c
> @@ -94,7 +94,7 @@ static uint32_t popl(StackAccess *sa)
>   
>   int get_pg_mode(CPUX86State *env)
>   {
> -    int pg_mode = 0;
> +    int pg_mode = PG_MODE_PG;
>       if (!(env->cr[0] & CR0_PG_MASK)) {
>           return 0;
>       }
> diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c
> index da187c8792..02d3486421 100644
> --- a/target/i386/tcg/sysemu/excp_helper.c
> +++ b/target/i386/tcg/sysemu/excp_helper.c
> @@ -298,7 +298,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
>           /* combine pde and pte nx, user and rw protections */
>           ptep &= pte ^ PG_NX_MASK;
>           page_size = 4096;
> -    } else if (pg_mode) {
> +    } else if (pg_mode & PG_MODE_PG) {
>           /*
>            * Page table level 2
>            */

Thanks Alex! This patch fixes the issue for me, so:

Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>


ATB,

Mark.
Re: [PATCH] target/i386: Fix legacy page table walk
Posted by Paolo Bonzini 2 weeks, 3 days ago
Queued, thanks.

Paolo