2022-09-22 05:49:04

by Samuel Holland

[permalink] [raw]
Subject: [PATCH 1/2] riscv: Fix crash during early errata patching

The patch function for the T-Head PBMT errata calls __pa_symbol() before
relocation. This crashes when CONFIG_DEBUG_VIRTUAL is enabled, because
__pa_symbol() forwards to __phys_addr_symbol(), and __phys_addr_symbol()
checks against the absolute kernel start/end address.

Fix this by directly using the underlying kernel_mapping_va_to_pa().

Fixes: a35707c3d850 ("riscv: add memory-type errata for T-Head")
Signed-off-by: Samuel Holland <[email protected]>
---

arch/riscv/errata/thead/errata.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c
index 202c83f677b2..83174f13783e 100644
--- a/arch/riscv/errata/thead/errata.c
+++ b/arch/riscv/errata/thead/errata.c
@@ -76,8 +76,9 @@ void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct al
if (cpu_req_errata & tmp) {
/* On vm-alternatives, the mmu isn't running yet */
if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
- memcpy((void *)__pa_symbol(alt->old_ptr),
- (void *)__pa_symbol(alt->alt_ptr), alt->alt_len);
+ memcpy((void *)kernel_mapping_va_to_pa((unsigned long)alt->old_ptr),
+ (void *)kernel_mapping_va_to_pa((unsigned long)alt->alt_ptr),
+ alt->alt_len);
else
patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
}
--
2.35.1


2022-09-22 06:12:50

by Samuel Holland

[permalink] [raw]
Subject: [PATCH 2/2] riscv: Move cast inside kernel_mapping_[pv]a_to_[vp]a

Before commit 44c922572952 ("RISC-V: enable XIP"), these macros cast
their argument to unsigned long. That commit moved the cast after an
assignment to an unsigned long variable, rendering it ineffectual.
Move the cast back, so we can remove the cast at each call site.

Signed-off-by: Samuel Holland <[email protected]>
---

arch/riscv/errata/thead/errata.c | 4 ++--
arch/riscv/include/asm/page.h | 18 +++++++++---------
arch/riscv/mm/init.c | 16 ++++++++--------
3 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c
index 83174f13783e..38c2c6b0f6b8 100644
--- a/arch/riscv/errata/thead/errata.c
+++ b/arch/riscv/errata/thead/errata.c
@@ -76,8 +76,8 @@ void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct al
if (cpu_req_errata & tmp) {
/* On vm-alternatives, the mmu isn't running yet */
if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
- memcpy((void *)kernel_mapping_va_to_pa((unsigned long)alt->old_ptr),
- (void *)kernel_mapping_va_to_pa((unsigned long)alt->alt_ptr),
+ memcpy((void *)kernel_mapping_va_to_pa(alt->old_ptr),
+ (void *)kernel_mapping_va_to_pa(alt->alt_ptr),
alt->alt_len);
else
patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h
index ac70b0fd9a9a..9f432c1b5289 100644
--- a/arch/riscv/include/asm/page.h
+++ b/arch/riscv/include/asm/page.h
@@ -123,20 +123,20 @@ extern phys_addr_t phys_ram_base;
((x) >= PAGE_OFFSET && (!IS_ENABLED(CONFIG_64BIT) || (x) < PAGE_OFFSET + KERN_VIRT_SIZE))

#define linear_mapping_pa_to_va(x) ((void *)((unsigned long)(x) + kernel_map.va_pa_offset))
-#define kernel_mapping_pa_to_va(y) ({ \
- unsigned long _y = y; \
- (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < phys_ram_base) ? \
- (void *)((unsigned long)(_y) + kernel_map.va_kernel_xip_pa_offset) : \
- (void *)((unsigned long)(_y) + kernel_map.va_kernel_pa_offset + XIP_OFFSET); \
+#define kernel_mapping_pa_to_va(y) ({ \
+ unsigned long _y = (unsigned long)(y); \
+ (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < phys_ram_base) ? \
+ (void *)(_y + kernel_map.va_kernel_xip_pa_offset) : \
+ (void *)(_y + kernel_map.va_kernel_pa_offset + XIP_OFFSET); \
})
#define __pa_to_va_nodebug(x) linear_mapping_pa_to_va(x)

#define linear_mapping_va_to_pa(x) ((unsigned long)(x) - kernel_map.va_pa_offset)
#define kernel_mapping_va_to_pa(y) ({ \
- unsigned long _y = y; \
- (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < kernel_map.virt_addr + XIP_OFFSET) ? \
- ((unsigned long)(_y) - kernel_map.va_kernel_xip_pa_offset) : \
- ((unsigned long)(_y) - kernel_map.va_kernel_pa_offset - XIP_OFFSET); \
+ unsigned long _y = (unsigned long)(y); \
+ (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < kernel_map.virt_addr + XIP_OFFSET) ? \
+ (_y - kernel_map.va_kernel_xip_pa_offset) : \
+ (_y - kernel_map.va_kernel_pa_offset - XIP_OFFSET); \
})

#define __va_to_pa_nodebug(x) ({ \
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index b56a0a75533f..7d59516ce6b3 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -927,15 +927,15 @@ static void __init pt_ops_set_early(void)
*/
static void __init pt_ops_set_fixmap(void)
{
- pt_ops.alloc_pte = kernel_mapping_pa_to_va((uintptr_t)alloc_pte_fixmap);
- pt_ops.get_pte_virt = kernel_mapping_pa_to_va((uintptr_t)get_pte_virt_fixmap);
+ pt_ops.alloc_pte = kernel_mapping_pa_to_va(alloc_pte_fixmap);
+ pt_ops.get_pte_virt = kernel_mapping_pa_to_va(get_pte_virt_fixmap);
#ifndef __PAGETABLE_PMD_FOLDED
- pt_ops.alloc_pmd = kernel_mapping_pa_to_va((uintptr_t)alloc_pmd_fixmap);
- pt_ops.get_pmd_virt = kernel_mapping_pa_to_va((uintptr_t)get_pmd_virt_fixmap);
- pt_ops.alloc_pud = kernel_mapping_pa_to_va((uintptr_t)alloc_pud_fixmap);
- pt_ops.get_pud_virt = kernel_mapping_pa_to_va((uintptr_t)get_pud_virt_fixmap);
- pt_ops.alloc_p4d = kernel_mapping_pa_to_va((uintptr_t)alloc_p4d_fixmap);
- pt_ops.get_p4d_virt = kernel_mapping_pa_to_va((uintptr_t)get_p4d_virt_fixmap);
+ pt_ops.alloc_pmd = kernel_mapping_pa_to_va(alloc_pmd_fixmap);
+ pt_ops.get_pmd_virt = kernel_mapping_pa_to_va(get_pmd_virt_fixmap);
+ pt_ops.alloc_pud = kernel_mapping_pa_to_va(alloc_pud_fixmap);
+ pt_ops.get_pud_virt = kernel_mapping_pa_to_va(get_pud_virt_fixmap);
+ pt_ops.alloc_p4d = kernel_mapping_pa_to_va(alloc_p4d_fixmap);
+ pt_ops.get_p4d_virt = kernel_mapping_pa_to_va(get_p4d_virt_fixmap);
#endif
}

--
2.35.1

2022-09-22 06:19:28

by Guo Ren

[permalink] [raw]
Subject: Re: [PATCH 1/2] riscv: Fix crash during early errata patching

Good catch!

Reviewed-by: Guo Ren <[email protected]>

On Thu, Sep 22, 2022 at 1:47 PM Samuel Holland <[email protected]> wrote:
>
> The patch function for the T-Head PBMT errata calls __pa_symbol() before
> relocation. This crashes when CONFIG_DEBUG_VIRTUAL is enabled, because
> __pa_symbol() forwards to __phys_addr_symbol(), and __phys_addr_symbol()
> checks against the absolute kernel start/end address.
>
> Fix this by directly using the underlying kernel_mapping_va_to_pa().
>
> Fixes: a35707c3d850 ("riscv: add memory-type errata for T-Head")
> Signed-off-by: Samuel Holland <[email protected]>
> ---
>
> arch/riscv/errata/thead/errata.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c
> index 202c83f677b2..83174f13783e 100644
> --- a/arch/riscv/errata/thead/errata.c
> +++ b/arch/riscv/errata/thead/errata.c
> @@ -76,8 +76,9 @@ void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct al
> if (cpu_req_errata & tmp) {
> /* On vm-alternatives, the mmu isn't running yet */
> if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
> - memcpy((void *)__pa_symbol(alt->old_ptr),
> - (void *)__pa_symbol(alt->alt_ptr), alt->alt_len);
> + memcpy((void *)kernel_mapping_va_to_pa((unsigned long)alt->old_ptr),
> + (void *)kernel_mapping_va_to_pa((unsigned long)alt->alt_ptr),
> + alt->alt_len);
> else
> patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
> }
> --
> 2.35.1
>


--
Best Regards
Guo Ren

2022-09-22 07:50:55

by Alexandre Ghiti

[permalink] [raw]
Subject: Re: [PATCH 1/2] riscv: Fix crash during early errata patching

Hi Samuel,

On 9/22/22 07:47, Samuel Holland wrote:
> The patch function for the T-Head PBMT errata calls __pa_symbol() before
> relocation. This crashes when CONFIG_DEBUG_VIRTUAL is enabled, because
> __pa_symbol() forwards to __phys_addr_symbol(), and __phys_addr_symbol()
> checks against the absolute kernel start/end address.
>
> Fix this by directly using the underlying kernel_mapping_va_to_pa().


I'd rather fix __phys_addr_symbol so that we can use __pa_symbol and
then take advantage of the address range check. Instead of using _end in
phys_addr_symbol, we have access to the size of the kernel mapping, so
we could do something like that:

diff --git a/arch/riscv/mm/physaddr.c b/arch/riscv/mm/physaddr.c
index f981b1f95fa0..150691aef058 100644
--- a/arch/riscv/mm/physaddr.c
+++ b/arch/riscv/mm/physaddr.c
@@ -22,7 +22,7 @@ EXPORT_SYMBOL(__virt_to_phys);
 phys_addr_t __phys_addr_symbol(unsigned long x)
 {
        unsigned long kernel_start = kernel_map.virt_addr;
-       unsigned long kernel_end = (unsigned long)_end;
+       unsigned long kernel_end = kernel_map.virt_addr + kernel_map.size;

        /*
         * Boundary checking aginst the kernel image mapping.

Thanks,

Alex

>
> Fixes: a35707c3d850 ("riscv: add memory-type errata for T-Head")
> Signed-off-by: Samuel Holland <[email protected]>
> ---
>
> arch/riscv/errata/thead/errata.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c
> index 202c83f677b2..83174f13783e 100644
> --- a/arch/riscv/errata/thead/errata.c
> +++ b/arch/riscv/errata/thead/errata.c
> @@ -76,8 +76,9 @@ void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct al
> if (cpu_req_errata & tmp) {
> /* On vm-alternatives, the mmu isn't running yet */
> if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
> - memcpy((void *)__pa_symbol(alt->old_ptr),
> - (void *)__pa_symbol(alt->alt_ptr), alt->alt_len);
> + memcpy((void *)kernel_mapping_va_to_pa((unsigned long)alt->old_ptr),
> + (void *)kernel_mapping_va_to_pa((unsigned long)alt->alt_ptr),
> + alt->alt_len);
> else
> patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
> }

2022-09-22 08:05:27

by Alexandre Ghiti

[permalink] [raw]
Subject: Re: [PATCH 2/2] riscv: Move cast inside kernel_mapping_[pv]a_to_[vp]a


On 9/22/22 07:47, Samuel Holland wrote:
> Before commit 44c922572952 ("RISC-V: enable XIP"), these macros cast
> their argument to unsigned long. That commit moved the cast after an
> assignment to an unsigned long variable, rendering it ineffectual.
> Move the cast back, so we can remove the cast at each call site.
>
> Signed-off-by: Samuel Holland <[email protected]>
> ---
>
> arch/riscv/errata/thead/errata.c | 4 ++--
> arch/riscv/include/asm/page.h | 18 +++++++++---------
> arch/riscv/mm/init.c | 16 ++++++++--------
> 3 files changed, 19 insertions(+), 19 deletions(-)
>
> diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c
> index 83174f13783e..38c2c6b0f6b8 100644
> --- a/arch/riscv/errata/thead/errata.c
> +++ b/arch/riscv/errata/thead/errata.c
> @@ -76,8 +76,8 @@ void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct al
> if (cpu_req_errata & tmp) {
> /* On vm-alternatives, the mmu isn't running yet */
> if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
> - memcpy((void *)kernel_mapping_va_to_pa((unsigned long)alt->old_ptr),
> - (void *)kernel_mapping_va_to_pa((unsigned long)alt->alt_ptr),
> + memcpy((void *)kernel_mapping_va_to_pa(alt->old_ptr),
> + (void *)kernel_mapping_va_to_pa(alt->alt_ptr),
> alt->alt_len);
> else
> patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
> diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h
> index ac70b0fd9a9a..9f432c1b5289 100644
> --- a/arch/riscv/include/asm/page.h
> +++ b/arch/riscv/include/asm/page.h
> @@ -123,20 +123,20 @@ extern phys_addr_t phys_ram_base;
> ((x) >= PAGE_OFFSET && (!IS_ENABLED(CONFIG_64BIT) || (x) < PAGE_OFFSET + KERN_VIRT_SIZE))
>
> #define linear_mapping_pa_to_va(x) ((void *)((unsigned long)(x) + kernel_map.va_pa_offset))
> -#define kernel_mapping_pa_to_va(y) ({ \
> - unsigned long _y = y; \
> - (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < phys_ram_base) ? \
> - (void *)((unsigned long)(_y) + kernel_map.va_kernel_xip_pa_offset) : \
> - (void *)((unsigned long)(_y) + kernel_map.va_kernel_pa_offset + XIP_OFFSET); \
> +#define kernel_mapping_pa_to_va(y) ({ \
> + unsigned long _y = (unsigned long)(y); \
> + (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < phys_ram_base) ? \
> + (void *)(_y + kernel_map.va_kernel_xip_pa_offset) : \
> + (void *)(_y + kernel_map.va_kernel_pa_offset + XIP_OFFSET); \
> })
> #define __pa_to_va_nodebug(x) linear_mapping_pa_to_va(x)
>
> #define linear_mapping_va_to_pa(x) ((unsigned long)(x) - kernel_map.va_pa_offset)
> #define kernel_mapping_va_to_pa(y) ({ \
> - unsigned long _y = y; \
> - (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < kernel_map.virt_addr + XIP_OFFSET) ? \
> - ((unsigned long)(_y) - kernel_map.va_kernel_xip_pa_offset) : \
> - ((unsigned long)(_y) - kernel_map.va_kernel_pa_offset - XIP_OFFSET); \
> + unsigned long _y = (unsigned long)(y); \
> + (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < kernel_map.virt_addr + XIP_OFFSET) ? \
> + (_y - kernel_map.va_kernel_xip_pa_offset) : \
> + (_y - kernel_map.va_kernel_pa_offset - XIP_OFFSET); \
> })
>
> #define __va_to_pa_nodebug(x) ({ \
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index b56a0a75533f..7d59516ce6b3 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -927,15 +927,15 @@ static void __init pt_ops_set_early(void)
> */
> static void __init pt_ops_set_fixmap(void)
> {
> - pt_ops.alloc_pte = kernel_mapping_pa_to_va((uintptr_t)alloc_pte_fixmap);
> - pt_ops.get_pte_virt = kernel_mapping_pa_to_va((uintptr_t)get_pte_virt_fixmap);
> + pt_ops.alloc_pte = kernel_mapping_pa_to_va(alloc_pte_fixmap);
> + pt_ops.get_pte_virt = kernel_mapping_pa_to_va(get_pte_virt_fixmap);
> #ifndef __PAGETABLE_PMD_FOLDED
> - pt_ops.alloc_pmd = kernel_mapping_pa_to_va((uintptr_t)alloc_pmd_fixmap);
> - pt_ops.get_pmd_virt = kernel_mapping_pa_to_va((uintptr_t)get_pmd_virt_fixmap);
> - pt_ops.alloc_pud = kernel_mapping_pa_to_va((uintptr_t)alloc_pud_fixmap);
> - pt_ops.get_pud_virt = kernel_mapping_pa_to_va((uintptr_t)get_pud_virt_fixmap);
> - pt_ops.alloc_p4d = kernel_mapping_pa_to_va((uintptr_t)alloc_p4d_fixmap);
> - pt_ops.get_p4d_virt = kernel_mapping_pa_to_va((uintptr_t)get_p4d_virt_fixmap);
> + pt_ops.alloc_pmd = kernel_mapping_pa_to_va(alloc_pmd_fixmap);
> + pt_ops.get_pmd_virt = kernel_mapping_pa_to_va(get_pmd_virt_fixmap);
> + pt_ops.alloc_pud = kernel_mapping_pa_to_va(alloc_pud_fixmap);
> + pt_ops.get_pud_virt = kernel_mapping_pa_to_va(get_pud_virt_fixmap);
> + pt_ops.alloc_p4d = kernel_mapping_pa_to_va(alloc_p4d_fixmap);
> + pt_ops.get_p4d_virt = kernel_mapping_pa_to_va(get_p4d_virt_fixmap);
> #endif
> }
>


Indeed, the inner cast was useless:

Reviewed-by: Alexandre Ghiti <[email protected]>

Thanks,

Alex

2022-09-23 09:45:05

by Heiko Stuebner

[permalink] [raw]
Subject: Re: [PATCH 2/2] riscv: Move cast inside kernel_mapping_[pv]a_to_[vp]a

Am Donnerstag, 22. September 2022, 07:47:42 CEST schrieb Samuel Holland:
> Before commit 44c922572952 ("RISC-V: enable XIP"), these macros cast
> their argument to unsigned long. That commit moved the cast after an
> assignment to an unsigned long variable, rendering it ineffectual.
> Move the cast back, so we can remove the cast at each call site.
>
> Signed-off-by: Samuel Holland <[email protected]>

makes the code a lot nicer to read

Reviewed-by: Heiko Stuebner <[email protected]>

> ---
>
> arch/riscv/errata/thead/errata.c | 4 ++--
> arch/riscv/include/asm/page.h | 18 +++++++++---------
> arch/riscv/mm/init.c | 16 ++++++++--------
> 3 files changed, 19 insertions(+), 19 deletions(-)
>
> diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c
> index 83174f13783e..38c2c6b0f6b8 100644
> --- a/arch/riscv/errata/thead/errata.c
> +++ b/arch/riscv/errata/thead/errata.c
> @@ -76,8 +76,8 @@ void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct al
> if (cpu_req_errata & tmp) {
> /* On vm-alternatives, the mmu isn't running yet */
> if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
> - memcpy((void *)kernel_mapping_va_to_pa((unsigned long)alt->old_ptr),
> - (void *)kernel_mapping_va_to_pa((unsigned long)alt->alt_ptr),
> + memcpy((void *)kernel_mapping_va_to_pa(alt->old_ptr),
> + (void *)kernel_mapping_va_to_pa(alt->alt_ptr),
> alt->alt_len);
> else
> patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
> diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h
> index ac70b0fd9a9a..9f432c1b5289 100644
> --- a/arch/riscv/include/asm/page.h
> +++ b/arch/riscv/include/asm/page.h
> @@ -123,20 +123,20 @@ extern phys_addr_t phys_ram_base;
> ((x) >= PAGE_OFFSET && (!IS_ENABLED(CONFIG_64BIT) || (x) < PAGE_OFFSET + KERN_VIRT_SIZE))
>
> #define linear_mapping_pa_to_va(x) ((void *)((unsigned long)(x) + kernel_map.va_pa_offset))
> -#define kernel_mapping_pa_to_va(y) ({ \
> - unsigned long _y = y; \
> - (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < phys_ram_base) ? \
> - (void *)((unsigned long)(_y) + kernel_map.va_kernel_xip_pa_offset) : \
> - (void *)((unsigned long)(_y) + kernel_map.va_kernel_pa_offset + XIP_OFFSET); \
> +#define kernel_mapping_pa_to_va(y) ({ \
> + unsigned long _y = (unsigned long)(y); \
> + (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < phys_ram_base) ? \
> + (void *)(_y + kernel_map.va_kernel_xip_pa_offset) : \
> + (void *)(_y + kernel_map.va_kernel_pa_offset + XIP_OFFSET); \
> })
> #define __pa_to_va_nodebug(x) linear_mapping_pa_to_va(x)
>
> #define linear_mapping_va_to_pa(x) ((unsigned long)(x) - kernel_map.va_pa_offset)
> #define kernel_mapping_va_to_pa(y) ({ \
> - unsigned long _y = y; \
> - (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < kernel_map.virt_addr + XIP_OFFSET) ? \
> - ((unsigned long)(_y) - kernel_map.va_kernel_xip_pa_offset) : \
> - ((unsigned long)(_y) - kernel_map.va_kernel_pa_offset - XIP_OFFSET); \
> + unsigned long _y = (unsigned long)(y); \
> + (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < kernel_map.virt_addr + XIP_OFFSET) ? \
> + (_y - kernel_map.va_kernel_xip_pa_offset) : \
> + (_y - kernel_map.va_kernel_pa_offset - XIP_OFFSET); \
> })
>
> #define __va_to_pa_nodebug(x) ({ \
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index b56a0a75533f..7d59516ce6b3 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -927,15 +927,15 @@ static void __init pt_ops_set_early(void)
> */
> static void __init pt_ops_set_fixmap(void)
> {
> - pt_ops.alloc_pte = kernel_mapping_pa_to_va((uintptr_t)alloc_pte_fixmap);
> - pt_ops.get_pte_virt = kernel_mapping_pa_to_va((uintptr_t)get_pte_virt_fixmap);
> + pt_ops.alloc_pte = kernel_mapping_pa_to_va(alloc_pte_fixmap);
> + pt_ops.get_pte_virt = kernel_mapping_pa_to_va(get_pte_virt_fixmap);
> #ifndef __PAGETABLE_PMD_FOLDED
> - pt_ops.alloc_pmd = kernel_mapping_pa_to_va((uintptr_t)alloc_pmd_fixmap);
> - pt_ops.get_pmd_virt = kernel_mapping_pa_to_va((uintptr_t)get_pmd_virt_fixmap);
> - pt_ops.alloc_pud = kernel_mapping_pa_to_va((uintptr_t)alloc_pud_fixmap);
> - pt_ops.get_pud_virt = kernel_mapping_pa_to_va((uintptr_t)get_pud_virt_fixmap);
> - pt_ops.alloc_p4d = kernel_mapping_pa_to_va((uintptr_t)alloc_p4d_fixmap);
> - pt_ops.get_p4d_virt = kernel_mapping_pa_to_va((uintptr_t)get_p4d_virt_fixmap);
> + pt_ops.alloc_pmd = kernel_mapping_pa_to_va(alloc_pmd_fixmap);
> + pt_ops.get_pmd_virt = kernel_mapping_pa_to_va(get_pmd_virt_fixmap);
> + pt_ops.alloc_pud = kernel_mapping_pa_to_va(alloc_pud_fixmap);
> + pt_ops.get_pud_virt = kernel_mapping_pa_to_va(get_pud_virt_fixmap);
> + pt_ops.alloc_p4d = kernel_mapping_pa_to_va(alloc_p4d_fixmap);
> + pt_ops.get_p4d_virt = kernel_mapping_pa_to_va(get_p4d_virt_fixmap);
> #endif
> }
>
>




2022-09-23 11:05:31

by Heiko Stuebner

[permalink] [raw]
Subject: Re: [PATCH 1/2] riscv: Fix crash during early errata patching

Hi,

Am Donnerstag, 22. September 2022, 09:31:56 CEST schrieb Alexandre Ghiti:
> Hi Samuel,
>
> On 9/22/22 07:47, Samuel Holland wrote:
> > The patch function for the T-Head PBMT errata calls __pa_symbol() before
> > relocation. This crashes when CONFIG_DEBUG_VIRTUAL is enabled, because
> > __pa_symbol() forwards to __phys_addr_symbol(), and __phys_addr_symbol()
> > checks against the absolute kernel start/end address.
> >
> > Fix this by directly using the underlying kernel_mapping_va_to_pa().
>
>
> I'd rather fix __phys_addr_symbol so that we can use __pa_symbol and
> then take advantage of the address range check. Instead of using _end in
> phys_addr_symbol, we have access to the size of the kernel mapping, so
> we could do something like that:
>
> diff --git a/arch/riscv/mm/physaddr.c b/arch/riscv/mm/physaddr.c
> index f981b1f95fa0..150691aef058 100644
> --- a/arch/riscv/mm/physaddr.c
> +++ b/arch/riscv/mm/physaddr.c
> @@ -22,7 +22,7 @@ EXPORT_SYMBOL(__virt_to_phys);
> phys_addr_t __phys_addr_symbol(unsigned long x)
> {
> unsigned long kernel_start = kernel_map.virt_addr;
> - unsigned long kernel_end = (unsigned long)_end;
> + unsigned long kernel_end = kernel_map.virt_addr + kernel_map.size;
>
> /*
> * Boundary checking aginst the kernel image mapping.
>

so I did the whole set of original code
- works without DEBUG_VIRTUAL
- breaks with DEBUG_VIRTUAL

and then applied you suggested change to __phys_addr_symbol,
which fixes the breakage. And I guess making this usable at all
times also makes a lot of sense, so

Tested-by: Heiko Stuebner <[email protected]>
Reviewed-by: Heiko Stuebner <[email protected]>


> > Fixes: a35707c3d850 ("riscv: add memory-type errata for T-Head")
> > Signed-off-by: Samuel Holland <[email protected]>
> > ---
> >
> > arch/riscv/errata/thead/errata.c | 5 +++--
> > 1 file changed, 3 insertions(+), 2 deletions(-)
> >
> > diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c
> > index 202c83f677b2..83174f13783e 100644
> > --- a/arch/riscv/errata/thead/errata.c
> > +++ b/arch/riscv/errata/thead/errata.c
> > @@ -76,8 +76,9 @@ void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct al
> > if (cpu_req_errata & tmp) {
> > /* On vm-alternatives, the mmu isn't running yet */
> > if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
> > - memcpy((void *)__pa_symbol(alt->old_ptr),
> > - (void *)__pa_symbol(alt->alt_ptr), alt->alt_len);
> > + memcpy((void *)kernel_mapping_va_to_pa((unsigned long)alt->old_ptr),
> > + (void *)kernel_mapping_va_to_pa((unsigned long)alt->alt_ptr),
> > + alt->alt_len);
> > else
> > patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
> > }
>




2022-12-09 19:09:18

by Palmer Dabbelt

[permalink] [raw]
Subject: Re: [PATCH 1/2] riscv: Fix crash during early errata patching

On Wed, 21 Sep 2022 22:47:41 PDT (-0700), [email protected] wrote:
> The patch function for the T-Head PBMT errata calls __pa_symbol() before
> relocation. This crashes when CONFIG_DEBUG_VIRTUAL is enabled, because
> __pa_symbol() forwards to __phys_addr_symbol(), and __phys_addr_symbol()
> checks against the absolute kernel start/end address.
>
> Fix this by directly using the underlying kernel_mapping_va_to_pa().
>
> Fixes: a35707c3d850 ("riscv: add memory-type errata for T-Head")
> Signed-off-by: Samuel Holland <[email protected]>
> ---
>
> arch/riscv/errata/thead/errata.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c
> index 202c83f677b2..83174f13783e 100644
> --- a/arch/riscv/errata/thead/errata.c
> +++ b/arch/riscv/errata/thead/errata.c
> @@ -76,8 +76,9 @@ void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct al
> if (cpu_req_errata & tmp) {
> /* On vm-alternatives, the mmu isn't running yet */
> if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
> - memcpy((void *)__pa_symbol(alt->old_ptr),
> - (void *)__pa_symbol(alt->alt_ptr), alt->alt_len);
> + memcpy((void *)kernel_mapping_va_to_pa((unsigned long)alt->old_ptr),
> + (void *)kernel_mapping_va_to_pa((unsigned long)alt->alt_ptr),
> + alt->alt_len);
> else
> patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
> }

Thanks, these are on for-next.