diff mbox series

[v3,3/3] target/ppc: Check page dir/table base alignment

Message ID 20220628133959.15131-4-leandro.lupori@eldorado.org.br (mailing list archive)
State New, archived
Headers show
Series ppc: Check for bad Radix configs | expand

Commit Message

Leandro Lupori June 28, 2022, 1:39 p.m. UTC
According to PowerISA 3.1B, Book III 6.7.6 programming note, the
page directory base addresses are expected to be aligned to their
size. Real hardware seems to rely on that and will access the
wrong address if they are misaligned. This results in a
translation failure even if the page tables seem to be properly
populated.

Signed-off-by: Leandro Lupori <leandro.lupori@eldorado.org.br>
---
 target/ppc/mmu-radix64.c | 28 ++++++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)

Comments

Leandro Lupori July 12, 2022, 4:38 p.m. UTC | #1
On 6/28/22 10:39, Leandro Lupori wrote:
> According to PowerISA 3.1B, Book III 6.7.6 programming note, the
> page directory base addresses are expected to be aligned to their
> size. Real hardware seems to rely on that and will access the
> wrong address if they are misaligned. This results in a
> translation failure even if the page tables seem to be properly
> populated.
> 
> Signed-off-by: Leandro Lupori <leandro.lupori@eldorado.org.br>
> ---
>   target/ppc/mmu-radix64.c | 28 ++++++++++++++++++++++++----
>   1 file changed, 24 insertions(+), 4 deletions(-)
> 
> diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
> index 705bff76be..00f2e9fa2e 100644
> --- a/target/ppc/mmu-radix64.c
> +++ b/target/ppc/mmu-radix64.c
> @@ -265,7 +265,7 @@ static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr,
>                                     uint64_t *pte_addr, uint64_t *nls,
>                                     int *psize, uint64_t *pte, int *fault_cause)
>   {
> -    uint64_t index, pde;
> +    uint64_t index, mask, nlb, pde;
>   
>       /* Read page <directory/table> entry from guest address space */
>       pde = ldq_phys(as, *pte_addr);
> @@ -280,7 +280,17 @@ static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr,
>           *nls = pde & R_PDE_NLS;
>           index = eaddr >> (*psize - *nls);       /* Shift */
>           index &= ((1UL << *nls) - 1);           /* Mask */
> -        *pte_addr = (pde & R_PDE_NLB) + (index * sizeof(pde));
> +        nlb = pde & R_PDE_NLB;
> +        mask = MAKE_64BIT_MASK(0, *nls + 3);
> +
> +        if (nlb & mask) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                "%s: misaligned page dir/table base: 0x"TARGET_FMT_lx
> +                " page dir size: 0x"TARGET_FMT_lx"\n",
> +                __func__, nlb, mask + 1);
> +            nlb &= ~mask;
> +        }
> +        *pte_addr = nlb + index * sizeof(pde);
>       }
>       return 0;
>   }
> @@ -294,8 +304,18 @@ static int ppc_radix64_walk_tree(AddressSpace *as, vaddr eaddr,
>       int level = 0;
>   
>       index = eaddr >> (*psize - nls);    /* Shift */
> -    index &= ((1UL << nls) - 1);       /* Mask */
> -    *pte_addr = base_addr + (index * sizeof(pde));
> +    index &= ((1UL << nls) - 1);        /* Mask */
> +    mask = MAKE_64BIT_MASK(0, nls + 3);
> +
> +    if (base_addr & mask) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +            "%s: misaligned page dir base: 0x"TARGET_FMT_lx
> +            " page dir size: 0x"TARGET_FMT_lx"\n",
> +            __func__, base_addr, mask + 1);
> +        base_addr &= ~mask;
> +    }
> +    *pte_addr = base_addr + index * sizeof(pde);
> +
>       do {
>           int ret;
>   

Is the v3 of this patch ok, now that cpu behavior on misaligned page 
dir/table base is also being emulated?

Thanks,
Leandro
Daniel Henrique Barboza July 15, 2022, 12:54 p.m. UTC | #2
On 6/28/22 10:39, Leandro Lupori wrote:
> According to PowerISA 3.1B, Book III 6.7.6 programming note, the
> page directory base addresses are expected to be aligned to their
> size. Real hardware seems to rely on that and will access the
> wrong address if they are misaligned. This results in a
> translation failure even if the page tables seem to be properly
> populated.
> 
> Signed-off-by: Leandro Lupori <leandro.lupori@eldorado.org.br>
> ---

Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>

>   target/ppc/mmu-radix64.c | 28 ++++++++++++++++++++++++----
>   1 file changed, 24 insertions(+), 4 deletions(-)
> 
> diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
> index 705bff76be..00f2e9fa2e 100644
> --- a/target/ppc/mmu-radix64.c
> +++ b/target/ppc/mmu-radix64.c
> @@ -265,7 +265,7 @@ static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr,
>                                     uint64_t *pte_addr, uint64_t *nls,
>                                     int *psize, uint64_t *pte, int *fault_cause)
>   {
> -    uint64_t index, pde;
> +    uint64_t index, mask, nlb, pde;
>   
>       /* Read page <directory/table> entry from guest address space */
>       pde = ldq_phys(as, *pte_addr);
> @@ -280,7 +280,17 @@ static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr,
>           *nls = pde & R_PDE_NLS;
>           index = eaddr >> (*psize - *nls);       /* Shift */
>           index &= ((1UL << *nls) - 1);           /* Mask */
> -        *pte_addr = (pde & R_PDE_NLB) + (index * sizeof(pde));
> +        nlb = pde & R_PDE_NLB;
> +        mask = MAKE_64BIT_MASK(0, *nls + 3);
> +
> +        if (nlb & mask) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                "%s: misaligned page dir/table base: 0x"TARGET_FMT_lx
> +                " page dir size: 0x"TARGET_FMT_lx"\n",
> +                __func__, nlb, mask + 1);
> +            nlb &= ~mask;
> +        }
> +        *pte_addr = nlb + index * sizeof(pde);
>       }
>       return 0;
>   }
> @@ -294,8 +304,18 @@ static int ppc_radix64_walk_tree(AddressSpace *as, vaddr eaddr,
>       int level = 0;
>   
>       index = eaddr >> (*psize - nls);    /* Shift */
> -    index &= ((1UL << nls) - 1);       /* Mask */
> -    *pte_addr = base_addr + (index * sizeof(pde));
> +    index &= ((1UL << nls) - 1);        /* Mask */
> +    mask = MAKE_64BIT_MASK(0, nls + 3);
> +
> +    if (base_addr & mask) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +            "%s: misaligned page dir base: 0x"TARGET_FMT_lx
> +            " page dir size: 0x"TARGET_FMT_lx"\n",
> +            __func__, base_addr, mask + 1);
> +        base_addr &= ~mask;
> +    }
> +    *pte_addr = base_addr + index * sizeof(pde);
> +
>       do {
>           int ret;
>
diff mbox series

Patch

diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
index 705bff76be..00f2e9fa2e 100644
--- a/target/ppc/mmu-radix64.c
+++ b/target/ppc/mmu-radix64.c
@@ -265,7 +265,7 @@  static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr,
                                   uint64_t *pte_addr, uint64_t *nls,
                                   int *psize, uint64_t *pte, int *fault_cause)
 {
-    uint64_t index, pde;
+    uint64_t index, mask, nlb, pde;
 
     /* Read page <directory/table> entry from guest address space */
     pde = ldq_phys(as, *pte_addr);
@@ -280,7 +280,17 @@  static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr,
         *nls = pde & R_PDE_NLS;
         index = eaddr >> (*psize - *nls);       /* Shift */
         index &= ((1UL << *nls) - 1);           /* Mask */
-        *pte_addr = (pde & R_PDE_NLB) + (index * sizeof(pde));
+        nlb = pde & R_PDE_NLB;
+        mask = MAKE_64BIT_MASK(0, *nls + 3);
+
+        if (nlb & mask) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                "%s: misaligned page dir/table base: 0x"TARGET_FMT_lx
+                " page dir size: 0x"TARGET_FMT_lx"\n",
+                __func__, nlb, mask + 1);
+            nlb &= ~mask;
+        }
+        *pte_addr = nlb + index * sizeof(pde);
     }
     return 0;
 }
@@ -294,8 +304,18 @@  static int ppc_radix64_walk_tree(AddressSpace *as, vaddr eaddr,
     int level = 0;
 
     index = eaddr >> (*psize - nls);    /* Shift */
-    index &= ((1UL << nls) - 1);       /* Mask */
-    *pte_addr = base_addr + (index * sizeof(pde));
+    index &= ((1UL << nls) - 1);        /* Mask */
+    mask = MAKE_64BIT_MASK(0, nls + 3);
+
+    if (base_addr & mask) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "%s: misaligned page dir base: 0x"TARGET_FMT_lx
+            " page dir size: 0x"TARGET_FMT_lx"\n",
+            __func__, base_addr, mask + 1);
+        base_addr &= ~mask;
+    }
+    *pte_addr = base_addr + index * sizeof(pde);
+
     do {
         int ret;