diff mbox series

[v1] arm64/mm: Fix Boot panic on Ampere Altra

Message ID 20250225114638.2038006-1-ryan.roberts@arm.com (mailing list archive)
State New
Headers show
Series [v1] arm64/mm: Fix Boot panic on Ampere Altra | expand

Commit Message

Ryan Roberts Feb. 25, 2025, 11:46 a.m. UTC
When the range of present physical memory is sufficiently small enough
and the reserved address space for the linear map is sufficiently large
enough, The linear map base address is randomized in
arm64_memblock_init().

Prior to commit 62cffa496aac ("arm64/mm: Override PARange for !LPA2 and
use it consistently"), we decided if the sizes were suitable with the
help of the raw mmfr0.parange. But the commit changed this to use the
sanitized version instead. But the function runs before the register has
been sanitized so this returns 0, interpreted as a parange of 32 bits.
Some fun wrapping occurs and the logic concludes that there is enough
room to randomize the linear map base address, when really there isn't.
So the top of the linear map ends up outside the reserved address space.

Fix this by intoducing a helper, cpu_get_parange() which reads the raw
parange value and overrides it with any early override (e.g. due to
arm64.nolva).

Reported-by: Luiz Capitulino <luizcap@redhat.com>
Closes: https://lore.kernel.org/all/a3d9acbe-07c2-43b6-9ba9-a7585f770e83@redhat.com/
Fixes: 62cffa496aac ("arm64/mm: Override PARange for !LPA2 and use it consistently")
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---

This applies on top of v6.14-rc4. I'm hoping this can be merged for v6.14 since
it's fixing a regression introduced in v6.14-rc1.

Luiz, are you able to test this to make sure it's definitely fixing your
original issue. The symptom I was seeing was slightly different.

I'm going to see if it's possible for read_sanitised_ftr_reg() to warn about use
before initialization. I'll send a follow up patch for that.

Thanks,
Ryan


 arch/arm64/include/asm/cpufeature.h | 9 +++++++++
 arch/arm64/mm/init.c                | 8 +-------
 2 files changed, 10 insertions(+), 7 deletions(-)

--
2.43.0

Comments

Luiz Capitulino Feb. 25, 2025, 4:57 p.m. UTC | #1
On 2025-02-25 06:46, Ryan Roberts wrote:
> When the range of present physical memory is sufficiently small enough
> and the reserved address space for the linear map is sufficiently large
> enough, The linear map base address is randomized in
> arm64_memblock_init().
> 
> Prior to commit 62cffa496aac ("arm64/mm: Override PARange for !LPA2 and
> use it consistently"), we decided if the sizes were suitable with the
> help of the raw mmfr0.parange. But the commit changed this to use the
> sanitized version instead. But the function runs before the register has
> been sanitized so this returns 0, interpreted as a parange of 32 bits.
> Some fun wrapping occurs and the logic concludes that there is enough
> room to randomize the linear map base address, when really there isn't.
> So the top of the linear map ends up outside the reserved address space.
> 
> Fix this by intoducing a helper, cpu_get_parange() which reads the raw
> parange value and overrides it with any early override (e.g. due to
> arm64.nolva).
> 
> Reported-by: Luiz Capitulino <luizcap@redhat.com>
> Closes: https://lore.kernel.org/all/a3d9acbe-07c2-43b6-9ba9-a7585f770e83@redhat.com/
> Fixes: 62cffa496aac ("arm64/mm: Override PARange for !LPA2 and use it consistently")
> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
> ---
> 
> This applies on top of v6.14-rc4. I'm hoping this can be merged for v6.14 since
> it's fixing a regression introduced in v6.14-rc1.
> 
> Luiz, are you able to test this to make sure it's definitely fixing your
> original issue. The symptom I was seeing was slightly different.

Yes, this fixes it for me!

I was able to boot v6.14-rc4 one time without your patch, this is probably
what messed up my bisection. But I booted v6.14-rc4 with this patch
multiple times without an issue. I agree this needs to be in for
v6.14 and huge thanks for jumping in and getting this fixed.

Tested-by: Luiz Capitulino <luizcap@redhat.com>

> 
> I'm going to see if it's possible for read_sanitised_ftr_reg() to warn about use
> before initialization. I'll send a follow up patch for that.
> 
> Thanks,
> Ryan
> 
> 
>   arch/arm64/include/asm/cpufeature.h | 9 +++++++++
>   arch/arm64/mm/init.c                | 8 +-------
>   2 files changed, 10 insertions(+), 7 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
> index e0e4478f5fb5..2335f44b9a4d 100644
> --- a/arch/arm64/include/asm/cpufeature.h
> +++ b/arch/arm64/include/asm/cpufeature.h
> @@ -1066,6 +1066,15 @@ static inline bool cpu_has_lpa2(void)
>   #endif
>   }
> 
> +static inline u64 cpu_get_parange(void)
> +{
> +	u64 mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
> +
> +	return arm64_apply_feature_override(mmfr0,
> +					    ID_AA64MMFR0_EL1_PARANGE_SHIFT, 4,
> +					    &id_aa64mmfr0_override);
> +}
> +
>   #endif /* __ASSEMBLY__ */
> 
>   #endif
> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> index 9c0b8d9558fc..1b1a61191b9f 100644
> --- a/arch/arm64/mm/init.c
> +++ b/arch/arm64/mm/init.c
> @@ -280,13 +280,7 @@ void __init arm64_memblock_init(void)
>   	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
>   		extern u16 memstart_offset_seed;
> 
> -		/*
> -		 * Use the sanitised version of id_aa64mmfr0_el1 so that linear
> -		 * map randomization can be enabled by shrinking the IPA space.
> -		 */
> -		u64 mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
> -		int parange = cpuid_feature_extract_unsigned_field(
> -					mmfr0, ID_AA64MMFR0_EL1_PARANGE_SHIFT);
> +		int parange = cpu_get_parange();
>   		s64 range = linear_region_size -
>   			    BIT(id_aa64mmfr0_parange_to_phys_shift(parange));
> 
> --
> 2.43.0
>
Ryan Roberts Feb. 25, 2025, 5:13 p.m. UTC | #2
On 25/02/2025 16:57, Luiz Capitulino wrote:
> On 2025-02-25 06:46, Ryan Roberts wrote:
>> When the range of present physical memory is sufficiently small enough
>> and the reserved address space for the linear map is sufficiently large
>> enough, The linear map base address is randomized in
>> arm64_memblock_init().
>>
>> Prior to commit 62cffa496aac ("arm64/mm: Override PARange for !LPA2 and
>> use it consistently"), we decided if the sizes were suitable with the
>> help of the raw mmfr0.parange. But the commit changed this to use the
>> sanitized version instead. But the function runs before the register has
>> been sanitized so this returns 0, interpreted as a parange of 32 bits.
>> Some fun wrapping occurs and the logic concludes that there is enough
>> room to randomize the linear map base address, when really there isn't.
>> So the top of the linear map ends up outside the reserved address space.
>>
>> Fix this by intoducing a helper, cpu_get_parange() which reads the raw
>> parange value and overrides it with any early override (e.g. due to
>> arm64.nolva).
>>
>> Reported-by: Luiz Capitulino <luizcap@redhat.com>
>> Closes: https://lore.kernel.org/all/a3d9acbe-07c2-43b6-9ba9-
>> a7585f770e83@redhat.com/
>> Fixes: 62cffa496aac ("arm64/mm: Override PARange for !LPA2 and use it
>> consistently")
>> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
>> ---
>>
>> This applies on top of v6.14-rc4. I'm hoping this can be merged for v6.14 since
>> it's fixing a regression introduced in v6.14-rc1.
>>
>> Luiz, are you able to test this to make sure it's definitely fixing your
>> original issue. The symptom I was seeing was slightly different.
> 
> Yes, this fixes it for me!

Great!
> 
> I was able to boot v6.14-rc4 one time without your patch, this is probably
> what messed up my bisection. 

Yes the operation is also dependent on the value of the kaslr seed (which is why
you don't see the issue when kaslr is disabled). So sometimes a random kaslr
seed will be the right value to mask the issue. Another benefit of running this
in kvmtool is that I could pass the same seed in every time.

> But I booted v6.14-rc4 with this patch
> multiple times without an issue. I agree this needs to be in for
> v6.14 and huge thanks for jumping in and getting this fixed.

No worries!

> 
> Tested-by: Luiz Capitulino <luizcap@redhat.com>

Thanks!

> 
>>
>> I'm going to see if it's possible for read_sanitised_ftr_reg() to warn about use
>> before initialization. I'll send a follow up patch for that.
>>
>> Thanks,
>> Ryan
>>
>>
>>   arch/arm64/include/asm/cpufeature.h | 9 +++++++++
>>   arch/arm64/mm/init.c                | 8 +-------
>>   2 files changed, 10 insertions(+), 7 deletions(-)
>>
>> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/
>> cpufeature.h
>> index e0e4478f5fb5..2335f44b9a4d 100644
>> --- a/arch/arm64/include/asm/cpufeature.h
>> +++ b/arch/arm64/include/asm/cpufeature.h
>> @@ -1066,6 +1066,15 @@ static inline bool cpu_has_lpa2(void)
>>   #endif
>>   }
>>
>> +static inline u64 cpu_get_parange(void)
>> +{
>> +    u64 mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
>> +
>> +    return arm64_apply_feature_override(mmfr0,
>> +                        ID_AA64MMFR0_EL1_PARANGE_SHIFT, 4,
>> +                        &id_aa64mmfr0_override);
>> +}
>> +
>>   #endif /* __ASSEMBLY__ */
>>
>>   #endif
>> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
>> index 9c0b8d9558fc..1b1a61191b9f 100644
>> --- a/arch/arm64/mm/init.c
>> +++ b/arch/arm64/mm/init.c
>> @@ -280,13 +280,7 @@ void __init arm64_memblock_init(void)
>>       if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
>>           extern u16 memstart_offset_seed;
>>
>> -        /*
>> -         * Use the sanitised version of id_aa64mmfr0_el1 so that linear
>> -         * map randomization can be enabled by shrinking the IPA space.
>> -         */
>> -        u64 mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
>> -        int parange = cpuid_feature_extract_unsigned_field(
>> -                    mmfr0, ID_AA64MMFR0_EL1_PARANGE_SHIFT);
>> +        int parange = cpu_get_parange();
>>           s64 range = linear_region_size -
>>                   BIT(id_aa64mmfr0_parange_to_phys_shift(parange));
>>
>> -- 
>> 2.43.0
>>
>
Ard Biesheuvel Feb. 25, 2025, 6:05 p.m. UTC | #3
On Tue, 25 Feb 2025 at 12:46, Ryan Roberts <ryan.roberts@arm.com> wrote:
>
> When the range of present physical memory is sufficiently small enough
> and the reserved address space for the linear map is sufficiently large
> enough, The linear map base address is randomized in
> arm64_memblock_init().
>
> Prior to commit 62cffa496aac ("arm64/mm: Override PARange for !LPA2 and
> use it consistently"), we decided if the sizes were suitable with the
> help of the raw mmfr0.parange. But the commit changed this to use the
> sanitized version instead. But the function runs before the register has
> been sanitized so this returns 0, interpreted as a parange of 32 bits.
> Some fun wrapping occurs and the logic concludes that there is enough
> room to randomize the linear map base address, when really there isn't.
> So the top of the linear map ends up outside the reserved address space.
>
> Fix this by intoducing a helper, cpu_get_parange() which reads the raw
> parange value and overrides it with any early override (e.g. due to
> arm64.nolva).
>
> Reported-by: Luiz Capitulino <luizcap@redhat.com>
> Closes: https://lore.kernel.org/all/a3d9acbe-07c2-43b6-9ba9-a7585f770e83@redhat.com/
> Fixes: 62cffa496aac ("arm64/mm: Override PARange for !LPA2 and use it consistently")
> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
> ---
>
> This applies on top of v6.14-rc4. I'm hoping this can be merged for v6.14 since
> it's fixing a regression introduced in v6.14-rc1.
>
> Luiz, are you able to test this to make sure it's definitely fixing your
> original issue. The symptom I was seeing was slightly different.
>
> I'm going to see if it's possible for read_sanitised_ftr_reg() to warn about use
> before initialization. I'll send a follow up patch for that.
>

Apologies for the breakage, and thanks for the fix.

I have to admit that I was a bit overzealous here: there is no point
yet in using the sanitised value, given that we don't actually
override the PA range in the first place. This is something I've
prototyped for Android use, so that linear map randomization can be
force enabled on CPUs with a wide PArange, but right now, mainline
does not have that capability, and so I'd be inclined to just revert
the hunk that introduces the call to read_sanitised_ftr_reg() into
arm64_memblock_init(), especially given the fact that commit
62cffa496aac was tagged for stable, and was already pulled into 6.13
and 6.12

In any case, it would be good if we could get a fix into Linus's tree asap


>
>  arch/arm64/include/asm/cpufeature.h | 9 +++++++++
>  arch/arm64/mm/init.c                | 8 +-------
>  2 files changed, 10 insertions(+), 7 deletions(-)
>
> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
> index e0e4478f5fb5..2335f44b9a4d 100644
> --- a/arch/arm64/include/asm/cpufeature.h
> +++ b/arch/arm64/include/asm/cpufeature.h
> @@ -1066,6 +1066,15 @@ static inline bool cpu_has_lpa2(void)
>  #endif
>  }
>
> +static inline u64 cpu_get_parange(void)
> +{
> +       u64 mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
> +
> +       return arm64_apply_feature_override(mmfr0,
> +                                           ID_AA64MMFR0_EL1_PARANGE_SHIFT, 4,
> +                                           &id_aa64mmfr0_override);
> +}
> +
>  #endif /* __ASSEMBLY__ */
>
>  #endif
> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> index 9c0b8d9558fc..1b1a61191b9f 100644
> --- a/arch/arm64/mm/init.c
> +++ b/arch/arm64/mm/init.c
> @@ -280,13 +280,7 @@ void __init arm64_memblock_init(void)
>         if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
>                 extern u16 memstart_offset_seed;
>
> -               /*
> -                * Use the sanitised version of id_aa64mmfr0_el1 so that linear
> -                * map randomization can be enabled by shrinking the IPA space.
> -                */
> -               u64 mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
> -               int parange = cpuid_feature_extract_unsigned_field(
> -                                       mmfr0, ID_AA64MMFR0_EL1_PARANGE_SHIFT);
> +               int parange = cpu_get_parange();
>                 s64 range = linear_region_size -
>                             BIT(id_aa64mmfr0_parange_to_phys_shift(parange));
>
> --
> 2.43.0
>
Will Deacon Feb. 26, 2025, 12:10 a.m. UTC | #4
On Tue, Feb 25, 2025 at 07:05:35PM +0100, Ard Biesheuvel wrote:
> Apologies for the breakage, and thanks for the fix.
> 
> I have to admit that I was a bit overzealous here: there is no point
> yet in using the sanitised value, given that we don't actually
> override the PA range in the first place. This is something I've
> prototyped for Android use, so that linear map randomization can be
> force enabled on CPUs with a wide PArange, but right now, mainline
> does not have that capability, and so I'd be inclined to just revert
> the hunk that introduces the call to read_sanitised_ftr_reg() into
> arm64_memblock_init(), especially given the fact that commit
> 62cffa496aac was tagged for stable, and was already pulled into 6.13
> and 6.12
> 
> In any case, it would be good if we could get a fix into Linus's tree asap

Makes sense. So the patch below?

Will

--->8

From b76ddd40dd6fe350727a4b2ec50709fd919d8408 Mon Sep 17 00:00:00 2001
From: Ryan Roberts <ryan.roberts@arm.com>
Date: Tue, 25 Feb 2025 11:46:36 +0000
Subject: [PATCH] arm64/mm: Fix Boot panic on Ampere Altra

When the range of present physical memory is sufficiently small enough
and the reserved address space for the linear map is sufficiently large
enough, The linear map base address is randomized in
arm64_memblock_init().

Prior to commit 62cffa496aac ("arm64/mm: Override PARange for !LPA2 and
use it consistently"), we decided if the sizes were suitable with the
help of the raw mmfr0.parange. But the commit changed this to use the
sanitized version instead. But the function runs before the register has
been sanitized so this returns 0, interpreted as a parange of 32 bits.
Some fun wrapping occurs and the logic concludes that there is enough
room to randomize the linear map base address, when really there isn't.
So the top of the linear map ends up outside the reserved address space.

Since the PA range cannot be overridden in the first place, restore the
mmfr0 reading logic to its state prior to 62cffa496aac, where the raw
register value is used.

Reported-by: Luiz Capitulino <luizcap@redhat.com>
Suggested-by: Ard Biesheuvel <ardb@kernel.org>
Closes: https://lore.kernel.org/all/a3d9acbe-07c2-43b6-9ba9-a7585f770e83@redhat.com/
Fixes: 62cffa496aac ("arm64/mm: Override PARange for !LPA2 and use it consistently")
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
Link: https://lore.kernel.org/r/20250225114638.2038006-1-ryan.roberts@arm.com
Signed-off-by: Will Deacon <will@kernel.org>
---
 arch/arm64/mm/init.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 9c0b8d9558fc..ccdef53872a0 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -279,12 +279,7 @@ void __init arm64_memblock_init(void)
 
 	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
 		extern u16 memstart_offset_seed;
-
-		/*
-		 * Use the sanitised version of id_aa64mmfr0_el1 so that linear
-		 * map randomization can be enabled by shrinking the IPA space.
-		 */
-		u64 mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
+		u64 mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
 		int parange = cpuid_feature_extract_unsigned_field(
 					mmfr0, ID_AA64MMFR0_EL1_PARANGE_SHIFT);
 		s64 range = linear_region_size -
Ard Biesheuvel Feb. 26, 2025, 6:59 a.m. UTC | #5
On Wed, 26 Feb 2025 at 01:10, Will Deacon <will@kernel.org> wrote:
>
> On Tue, Feb 25, 2025 at 07:05:35PM +0100, Ard Biesheuvel wrote:
> > Apologies for the breakage, and thanks for the fix.
> >
> > I have to admit that I was a bit overzealous here: there is no point
> > yet in using the sanitised value, given that we don't actually
> > override the PA range in the first place. This is something I've
> > prototyped for Android use, so that linear map randomization can be
> > force enabled on CPUs with a wide PArange, but right now, mainline
> > does not have that capability, and so I'd be inclined to just revert
> > the hunk that introduces the call to read_sanitised_ftr_reg() into
> > arm64_memblock_init(), especially given the fact that commit
> > 62cffa496aac was tagged for stable, and was already pulled into 6.13
> > and 6.12
> >
> > In any case, it would be good if we could get a fix into Linus's tree asap
>
> Makes sense. So the patch below?
>

Yes, but please don't forget the cc:stable

To the patch below,

Acked-by: Ard Biesheuvel <ardb@kernel.org>


> --->8
>
> From b76ddd40dd6fe350727a4b2ec50709fd919d8408 Mon Sep 17 00:00:00 2001
> From: Ryan Roberts <ryan.roberts@arm.com>
> Date: Tue, 25 Feb 2025 11:46:36 +0000
> Subject: [PATCH] arm64/mm: Fix Boot panic on Ampere Altra
>
> When the range of present physical memory is sufficiently small enough
> and the reserved address space for the linear map is sufficiently large
> enough, The linear map base address is randomized in
> arm64_memblock_init().
>
> Prior to commit 62cffa496aac ("arm64/mm: Override PARange for !LPA2 and
> use it consistently"), we decided if the sizes were suitable with the
> help of the raw mmfr0.parange. But the commit changed this to use the
> sanitized version instead. But the function runs before the register has
> been sanitized so this returns 0, interpreted as a parange of 32 bits.
> Some fun wrapping occurs and the logic concludes that there is enough
> room to randomize the linear map base address, when really there isn't.
> So the top of the linear map ends up outside the reserved address space.
>
> Since the PA range cannot be overridden in the first place, restore the
> mmfr0 reading logic to its state prior to 62cffa496aac, where the raw
> register value is used.
>
> Reported-by: Luiz Capitulino <luizcap@redhat.com>
> Suggested-by: Ard Biesheuvel <ardb@kernel.org>
> Closes: https://lore.kernel.org/all/a3d9acbe-07c2-43b6-9ba9-a7585f770e83@redhat.com/
> Fixes: 62cffa496aac ("arm64/mm: Override PARange for !LPA2 and use it consistently")
> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
> Link: https://lore.kernel.org/r/20250225114638.2038006-1-ryan.roberts@arm.com
> Signed-off-by: Will Deacon <will@kernel.org>
> ---
>  arch/arm64/mm/init.c | 7 +------
>  1 file changed, 1 insertion(+), 6 deletions(-)
>
> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> index 9c0b8d9558fc..ccdef53872a0 100644
> --- a/arch/arm64/mm/init.c
> +++ b/arch/arm64/mm/init.c
> @@ -279,12 +279,7 @@ void __init arm64_memblock_init(void)
>
>         if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
>                 extern u16 memstart_offset_seed;
> -
> -               /*
> -                * Use the sanitised version of id_aa64mmfr0_el1 so that linear
> -                * map randomization can be enabled by shrinking the IPA space.
> -                */
> -               u64 mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
> +               u64 mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
>                 int parange = cpuid_feature_extract_unsigned_field(
>                                         mmfr0, ID_AA64MMFR0_EL1_PARANGE_SHIFT);
>                 s64 range = linear_region_size -
> --
> 2.48.1.658.g4767266eb4-goog
>
Ryan Roberts Feb. 26, 2025, 8:07 a.m. UTC | #6
On 26/02/2025 06:59, Ard Biesheuvel wrote:
> On Wed, 26 Feb 2025 at 01:10, Will Deacon <will@kernel.org> wrote:
>>
>> On Tue, Feb 25, 2025 at 07:05:35PM +0100, Ard Biesheuvel wrote:
>>> Apologies for the breakage, and thanks for the fix.
>>>
>>> I have to admit that I was a bit overzealous here: there is no point
>>> yet in using the sanitised value, given that we don't actually
>>> override the PA range in the first place. 

But unless I've misunderstood something, parange is overridden; Commit
62cffa496aac (the same one we are fixing) adds an override to force parange to
48 bits when arm64.nolva is specified for LPA2 systems (see mmfr2_varange_filter()).

I thought it would be preferable to honour that override, hence my use of
arm64_apply_feature_override() in the fix. Are you saying we don't need to worry
about that case?

Thanks,
Ryan

>>> This is something I've
>>> prototyped for Android use, so that linear map randomization can be
>>> force enabled on CPUs with a wide PArange, but right now, mainline
>>> does not have that capability, and so I'd be inclined to just revert
>>> the hunk that introduces the call to read_sanitised_ftr_reg() into
>>> arm64_memblock_init(), especially given the fact that commit
>>> 62cffa496aac was tagged for stable, and was already pulled into 6.13
>>> and 6.12
>>>
>>> In any case, it would be good if we could get a fix into Linus's tree asap
>>
>> Makes sense. So the patch below?
>>
> 
> Yes, but please don't forget the cc:stable
> 
> To the patch below,
> 
> Acked-by: Ard Biesheuvel <ardb@kernel.org>
> 
> 
>> --->8
>>
>> From b76ddd40dd6fe350727a4b2ec50709fd919d8408 Mon Sep 17 00:00:00 2001
>> From: Ryan Roberts <ryan.roberts@arm.com>
>> Date: Tue, 25 Feb 2025 11:46:36 +0000
>> Subject: [PATCH] arm64/mm: Fix Boot panic on Ampere Altra
>>
>> When the range of present physical memory is sufficiently small enough
>> and the reserved address space for the linear map is sufficiently large
>> enough, The linear map base address is randomized in
>> arm64_memblock_init().
>>
>> Prior to commit 62cffa496aac ("arm64/mm: Override PARange for !LPA2 and
>> use it consistently"), we decided if the sizes were suitable with the
>> help of the raw mmfr0.parange. But the commit changed this to use the
>> sanitized version instead. But the function runs before the register has
>> been sanitized so this returns 0, interpreted as a parange of 32 bits.
>> Some fun wrapping occurs and the logic concludes that there is enough
>> room to randomize the linear map base address, when really there isn't.
>> So the top of the linear map ends up outside the reserved address space.
>>
>> Since the PA range cannot be overridden in the first place, restore the
>> mmfr0 reading logic to its state prior to 62cffa496aac, where the raw
>> register value is used.
>>
>> Reported-by: Luiz Capitulino <luizcap@redhat.com>
>> Suggested-by: Ard Biesheuvel <ardb@kernel.org>
>> Closes: https://lore.kernel.org/all/a3d9acbe-07c2-43b6-9ba9-a7585f770e83@redhat.com/
>> Fixes: 62cffa496aac ("arm64/mm: Override PARange for !LPA2 and use it consistently")
>> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
>> Link: https://lore.kernel.org/r/20250225114638.2038006-1-ryan.roberts@arm.com
>> Signed-off-by: Will Deacon <will@kernel.org>
>> ---
>>  arch/arm64/mm/init.c | 7 +------
>>  1 file changed, 1 insertion(+), 6 deletions(-)
>>
>> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
>> index 9c0b8d9558fc..ccdef53872a0 100644
>> --- a/arch/arm64/mm/init.c
>> +++ b/arch/arm64/mm/init.c
>> @@ -279,12 +279,7 @@ void __init arm64_memblock_init(void)
>>
>>         if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
>>                 extern u16 memstart_offset_seed;
>> -
>> -               /*
>> -                * Use the sanitised version of id_aa64mmfr0_el1 so that linear
>> -                * map randomization can be enabled by shrinking the IPA space.
>> -                */
>> -               u64 mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
>> +               u64 mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
>>                 int parange = cpuid_feature_extract_unsigned_field(
>>                                         mmfr0, ID_AA64MMFR0_EL1_PARANGE_SHIFT);
>>                 s64 range = linear_region_size -
>> --
>> 2.48.1.658.g4767266eb4-goog
>>
Ard Biesheuvel Feb. 26, 2025, 8:33 a.m. UTC | #7
On Wed, 26 Feb 2025 at 09:07, Ryan Roberts <ryan.roberts@arm.com> wrote:
>
> On 26/02/2025 06:59, Ard Biesheuvel wrote:
> > On Wed, 26 Feb 2025 at 01:10, Will Deacon <will@kernel.org> wrote:
> >>
> >> On Tue, Feb 25, 2025 at 07:05:35PM +0100, Ard Biesheuvel wrote:
> >>> Apologies for the breakage, and thanks for the fix.
> >>>
> >>> I have to admit that I was a bit overzealous here: there is no point
> >>> yet in using the sanitised value, given that we don't actually
> >>> override the PA range in the first place.
>
> But unless I've misunderstood something, parange is overridden; Commit
> 62cffa496aac (the same one we are fixing) adds an override to force parange to
> 48 bits when arm64.nolva is specified for LPA2 systems (see mmfr2_varange_filter()).
>
> I thought it would be preferable to honour that override, hence my use of
> arm64_apply_feature_override() in the fix. Are you saying we don't need to worry
> about that case?
>

I wouldn't think so (but I'm glad you brought it up because this
didn't occur to me at all tbh)

With arm64.nolva, both the VA and PA ranges will be reduced, and so
the range of the linear map will be 47 bits. So if the PA range is
being reduced from 52 to 48, it will still exceed the size of the
linear map, and so it should make no difference in this particular
case.

The use case I had in mind was to allow the PA range to be reduced to
a value that is substantially less than the range of the linear map,
e.g, 40 bits on a 48-bit VA kernel. On the Android side, the issue of
the missing linear map randomization has come up a couple of times,
but there is no clear direction at this point, so adding this feature
here was premature (mea culpa)
Ryan Roberts Feb. 26, 2025, 8:55 a.m. UTC | #8
On 26/02/2025 08:33, Ard Biesheuvel wrote:
> On Wed, 26 Feb 2025 at 09:07, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>
>> On 26/02/2025 06:59, Ard Biesheuvel wrote:
>>> On Wed, 26 Feb 2025 at 01:10, Will Deacon <will@kernel.org> wrote:
>>>>
>>>> On Tue, Feb 25, 2025 at 07:05:35PM +0100, Ard Biesheuvel wrote:
>>>>> Apologies for the breakage, and thanks for the fix.
>>>>>
>>>>> I have to admit that I was a bit overzealous here: there is no point
>>>>> yet in using the sanitised value, given that we don't actually
>>>>> override the PA range in the first place.
>>
>> But unless I've misunderstood something, parange is overridden; Commit
>> 62cffa496aac (the same one we are fixing) adds an override to force parange to
>> 48 bits when arm64.nolva is specified for LPA2 systems (see mmfr2_varange_filter()).
>>
>> I thought it would be preferable to honour that override, hence my use of
>> arm64_apply_feature_override() in the fix. Are you saying we don't need to worry
>> about that case?
>>
> 
> I wouldn't think so (but I'm glad you brought it up because this
> didn't occur to me at all tbh)
> 
> With arm64.nolva, both the VA and PA ranges will be reduced, and so
> the range of the linear map will be 47 bits. So if the PA range is
> being reduced from 52 to 48, it will still exceed the size of the
> linear map, and so it should make no difference in this particular
> case.

OK, so I think you're saying it'll happen to work correctly even if we ignore
that override? That sounds a bit fragile to me. Surely we should be consistent
and either always honour the override or remove the override in the first place?

> 
> The use case I had in mind was to allow the PA range to be reduced to
> a value that is substantially less than the range of the linear map,
> e.g, 40 bits on a 48-bit VA kernel. On the Android side, the issue of
> the missing linear map randomization has come up a couple of times,
> but there is no clear direction at this point, so adding this feature
> here was premature (mea culpa)
Ard Biesheuvel Feb. 26, 2025, 9:04 a.m. UTC | #9
On Wed, 26 Feb 2025 at 09:55, Ryan Roberts <ryan.roberts@arm.com> wrote:
>
> On 26/02/2025 08:33, Ard Biesheuvel wrote:
> > On Wed, 26 Feb 2025 at 09:07, Ryan Roberts <ryan.roberts@arm.com> wrote:
> >>
> >> On 26/02/2025 06:59, Ard Biesheuvel wrote:
> >>> On Wed, 26 Feb 2025 at 01:10, Will Deacon <will@kernel.org> wrote:
> >>>>
> >>>> On Tue, Feb 25, 2025 at 07:05:35PM +0100, Ard Biesheuvel wrote:
> >>>>> Apologies for the breakage, and thanks for the fix.
> >>>>>
> >>>>> I have to admit that I was a bit overzealous here: there is no point
> >>>>> yet in using the sanitised value, given that we don't actually
> >>>>> override the PA range in the first place.
> >>
> >> But unless I've misunderstood something, parange is overridden; Commit
> >> 62cffa496aac (the same one we are fixing) adds an override to force parange to
> >> 48 bits when arm64.nolva is specified for LPA2 systems (see mmfr2_varange_filter()).
> >>
> >> I thought it would be preferable to honour that override, hence my use of
> >> arm64_apply_feature_override() in the fix. Are you saying we don't need to worry
> >> about that case?
> >>
> >
> > I wouldn't think so (but I'm glad you brought it up because this
> > didn't occur to me at all tbh)
> >
> > With arm64.nolva, both the VA and PA ranges will be reduced, and so
> > the range of the linear map will be 47 bits. So if the PA range is
> > being reduced from 52 to 48, it will still exceed the size of the
> > linear map, and so it should make no difference in this particular
> > case.
>
> OK, so I think you're saying it'll happen to work correctly even if we ignore
> that override? That sounds a bit fragile to me. Surely we should be consistent
> and either always honour the override or remove the override in the first place?
>

I'm trying to walk a fine line here between consistent use of the
override, and fixing something that I broke in a nasty way all the way
back to 6.12.

So yes, I agree that it would be better to use the override
consistently, and this is what we should do going forward. But the
purpose of the original patch was mainly to ensure that we
consistently program the MMU either in LPA2 or in non-LPA2 mode, and
not in a mix of the two. The linear mapping randomization change was
kind of secondary.

So perhaps this should be two patches:
- backing out the use of the sanitised register, as proposed by Will,
with cc:stable
- a follow up based on your proposal, which can be backported later if
needed, but without tagging it for stable.
Ryan Roberts Feb. 26, 2025, 9:45 a.m. UTC | #10
On 26/02/2025 09:04, Ard Biesheuvel wrote:
> On Wed, 26 Feb 2025 at 09:55, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>
>> On 26/02/2025 08:33, Ard Biesheuvel wrote:
>>> On Wed, 26 Feb 2025 at 09:07, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>>>
>>>> On 26/02/2025 06:59, Ard Biesheuvel wrote:
>>>>> On Wed, 26 Feb 2025 at 01:10, Will Deacon <will@kernel.org> wrote:
>>>>>>
>>>>>> On Tue, Feb 25, 2025 at 07:05:35PM +0100, Ard Biesheuvel wrote:
>>>>>>> Apologies for the breakage, and thanks for the fix.
>>>>>>>
>>>>>>> I have to admit that I was a bit overzealous here: there is no point
>>>>>>> yet in using the sanitised value, given that we don't actually
>>>>>>> override the PA range in the first place.
>>>>
>>>> But unless I've misunderstood something, parange is overridden; Commit
>>>> 62cffa496aac (the same one we are fixing) adds an override to force parange to
>>>> 48 bits when arm64.nolva is specified for LPA2 systems (see mmfr2_varange_filter()).
>>>>
>>>> I thought it would be preferable to honour that override, hence my use of
>>>> arm64_apply_feature_override() in the fix. Are you saying we don't need to worry
>>>> about that case?
>>>>
>>>
>>> I wouldn't think so (but I'm glad you brought it up because this
>>> didn't occur to me at all tbh)
>>>
>>> With arm64.nolva, both the VA and PA ranges will be reduced, and so
>>> the range of the linear map will be 47 bits. So if the PA range is
>>> being reduced from 52 to 48, it will still exceed the size of the
>>> linear map, and so it should make no difference in this particular
>>> case.
>>
>> OK, so I think you're saying it'll happen to work correctly even if we ignore
>> that override? That sounds a bit fragile to me. Surely we should be consistent
>> and either always honour the override or remove the override in the first place?
>>
> 
> I'm trying to walk a fine line here between consistent use of the
> override, and fixing something that I broke in a nasty way all the way
> back to 6.12.
> 
> So yes, I agree that it would be better to use the override
> consistently, and this is what we should do going forward. But the
> purpose of the original patch was mainly to ensure that we
> consistently program the MMU either in LPA2 or in non-LPA2 mode, and
> not in a mix of the two. The linear mapping randomization change was
> kind of secondary.
> 
> So perhaps this should be two patches:
> - backing out the use of the sanitised register, as proposed by Will,
> with cc:stable
> - a follow up based on your proposal, which can be backported later if
> needed, but without tagging it for stable.

I suspect I'm misunderstanding something crucial about the way the linear map
randomization works (TBH the details of the signed comparisons went a little
over my head).

But my rough understanding is that there are 2 values you want to compare; the
size of the linear map and the PA range. If the PA range is significantly bigger
than the linear map size then we conclude we have enough room to randomize. (I
think this assumes that VA size is always GTE PA size). But if linear map size
is based on an overridden VA and overridden PA size (which I assume it must be,
given the pgtables will be limitted to the overridden VA size) and PA size is
not overridden, isn't it possible to wrongly conclude that there is enough room
to randomize when there really is not?

By that logic, you must include any PA override in this decision and so Will's
patch does not fix this case. Mine does.

But as I say, I'm not confident I understand this logic properly. If my
understanding is incorrect, let's go with your proposal.

Thanks,
Ryan
Ard Biesheuvel Feb. 26, 2025, 10:07 a.m. UTC | #11
On Wed, 26 Feb 2025 at 10:45, Ryan Roberts <ryan.roberts@arm.com> wrote:
>
> On 26/02/2025 09:04, Ard Biesheuvel wrote:
> > On Wed, 26 Feb 2025 at 09:55, Ryan Roberts <ryan.roberts@arm.com> wrote:
> >>
> >> On 26/02/2025 08:33, Ard Biesheuvel wrote:
> >>> On Wed, 26 Feb 2025 at 09:07, Ryan Roberts <ryan.roberts@arm.com> wrote:
> >>>>
> >>>> On 26/02/2025 06:59, Ard Biesheuvel wrote:
> >>>>> On Wed, 26 Feb 2025 at 01:10, Will Deacon <will@kernel.org> wrote:
> >>>>>>
> >>>>>> On Tue, Feb 25, 2025 at 07:05:35PM +0100, Ard Biesheuvel wrote:
> >>>>>>> Apologies for the breakage, and thanks for the fix.
> >>>>>>>
> >>>>>>> I have to admit that I was a bit overzealous here: there is no point
> >>>>>>> yet in using the sanitised value, given that we don't actually
> >>>>>>> override the PA range in the first place.
> >>>>
> >>>> But unless I've misunderstood something, parange is overridden; Commit
> >>>> 62cffa496aac (the same one we are fixing) adds an override to force parange to
> >>>> 48 bits when arm64.nolva is specified for LPA2 systems (see mmfr2_varange_filter()).
> >>>>
> >>>> I thought it would be preferable to honour that override, hence my use of
> >>>> arm64_apply_feature_override() in the fix. Are you saying we don't need to worry
> >>>> about that case?
> >>>>
> >>>
> >>> I wouldn't think so (but I'm glad you brought it up because this
> >>> didn't occur to me at all tbh)
> >>>
> >>> With arm64.nolva, both the VA and PA ranges will be reduced, and so
> >>> the range of the linear map will be 47 bits. So if the PA range is
> >>> being reduced from 52 to 48, it will still exceed the size of the
> >>> linear map, and so it should make no difference in this particular
> >>> case.
> >>
> >> OK, so I think you're saying it'll happen to work correctly even if we ignore
> >> that override? That sounds a bit fragile to me. Surely we should be consistent
> >> and either always honour the override or remove the override in the first place?
> >>
> >
> > I'm trying to walk a fine line here between consistent use of the
> > override, and fixing something that I broke in a nasty way all the way
> > back to 6.12.
> >
> > So yes, I agree that it would be better to use the override
> > consistently, and this is what we should do going forward. But the
> > purpose of the original patch was mainly to ensure that we
> > consistently program the MMU either in LPA2 or in non-LPA2 mode, and
> > not in a mix of the two. The linear mapping randomization change was
> > kind of secondary.
> >
> > So perhaps this should be two patches:
> > - backing out the use of the sanitised register, as proposed by Will,
> > with cc:stable
> > - a follow up based on your proposal, which can be backported later if
> > needed, but without tagging it for stable.
>
> I suspect I'm misunderstanding something crucial about the way the linear map
> randomization works (TBH the details of the signed comparisons went a little
> over my head).
>
> But my rough understanding is that there are 2 values you want to compare; the
> size of the linear map and the PA range. If the PA range is significantly bigger
> than the linear map size then we conclude we have enough room to randomize.

It is the other way around: the linear map should be able to cover all
system RAM that may appear anywhere in the PA space, and so if the PA
space is very large (and memory hotplug is enabled), no randomization
is possible, as it may end up mapping RAM that appears later past the
top of the VA space. Note that the same is fundamentally true for
running a 39-bit VA kernel on hardware that has a PA range that
exceeds that.

As for the signed arithmetic: the randomization works by substracting
from memstart_addr (aka PHYS_OFFSET). Normally, if system RAM starts
at 1G, memstart_addr will be 1G, and the linear map will associate
PAGE_OFFSET with PA 1G.

To randomize the linear mapping, the system RAM has to be moved up in
the linear map (as this is the only direction it can be moved), and so
PAGE_OFFSET needs to map to a lower value, and so memstart_addr may
wrap around and become negative.

> (I
> think this assumes that VA size is always GTE PA size). But if linear map size
> is based on an overridden VA and overridden PA size (which I assume it must be,
> given the pgtables will be limitted to the overridden VA size) and PA size is
> not overridden, isn't it possible to wrongly conclude that there is enough room
> to randomize when there really is not?
>

No, if the linear map is only 47 bits, and the PA space is either 52
or 48 bits, no randomization is possible. We might even run out of
space without randomization, but this is an existing problem for
non-LPA2 too.
Ryan Roberts Feb. 26, 2025, 10:18 a.m. UTC | #12
On 26/02/2025 10:07, Ard Biesheuvel wrote:
> On Wed, 26 Feb 2025 at 10:45, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>
>> On 26/02/2025 09:04, Ard Biesheuvel wrote:
>>> On Wed, 26 Feb 2025 at 09:55, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>>>
>>>> On 26/02/2025 08:33, Ard Biesheuvel wrote:
>>>>> On Wed, 26 Feb 2025 at 09:07, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>>>>>
>>>>>> On 26/02/2025 06:59, Ard Biesheuvel wrote:
>>>>>>> On Wed, 26 Feb 2025 at 01:10, Will Deacon <will@kernel.org> wrote:
>>>>>>>>
>>>>>>>> On Tue, Feb 25, 2025 at 07:05:35PM +0100, Ard Biesheuvel wrote:
>>>>>>>>> Apologies for the breakage, and thanks for the fix.
>>>>>>>>>
>>>>>>>>> I have to admit that I was a bit overzealous here: there is no point
>>>>>>>>> yet in using the sanitised value, given that we don't actually
>>>>>>>>> override the PA range in the first place.
>>>>>>
>>>>>> But unless I've misunderstood something, parange is overridden; Commit
>>>>>> 62cffa496aac (the same one we are fixing) adds an override to force parange to
>>>>>> 48 bits when arm64.nolva is specified for LPA2 systems (see mmfr2_varange_filter()).
>>>>>>
>>>>>> I thought it would be preferable to honour that override, hence my use of
>>>>>> arm64_apply_feature_override() in the fix. Are you saying we don't need to worry
>>>>>> about that case?
>>>>>>
>>>>>
>>>>> I wouldn't think so (but I'm glad you brought it up because this
>>>>> didn't occur to me at all tbh)
>>>>>
>>>>> With arm64.nolva, both the VA and PA ranges will be reduced, and so
>>>>> the range of the linear map will be 47 bits. So if the PA range is
>>>>> being reduced from 52 to 48, it will still exceed the size of the
>>>>> linear map, and so it should make no difference in this particular
>>>>> case.
>>>>
>>>> OK, so I think you're saying it'll happen to work correctly even if we ignore
>>>> that override? That sounds a bit fragile to me. Surely we should be consistent
>>>> and either always honour the override or remove the override in the first place?
>>>>
>>>
>>> I'm trying to walk a fine line here between consistent use of the
>>> override, and fixing something that I broke in a nasty way all the way
>>> back to 6.12.
>>>
>>> So yes, I agree that it would be better to use the override
>>> consistently, and this is what we should do going forward. But the
>>> purpose of the original patch was mainly to ensure that we
>>> consistently program the MMU either in LPA2 or in non-LPA2 mode, and
>>> not in a mix of the two. The linear mapping randomization change was
>>> kind of secondary.
>>>
>>> So perhaps this should be two patches:
>>> - backing out the use of the sanitised register, as proposed by Will,
>>> with cc:stable
>>> - a follow up based on your proposal, which can be backported later if
>>> needed, but without tagging it for stable.
>>
>> I suspect I'm misunderstanding something crucial about the way the linear map
>> randomization works (TBH the details of the signed comparisons went a little
>> over my head).
>>
>> But my rough understanding is that there are 2 values you want to compare; the
>> size of the linear map and the PA range. If the PA range is significantly bigger
>> than the linear map size then we conclude we have enough room to randomize.
> 
> It is the other way around: the linear map should be able to cover all
> system RAM that may appear anywhere in the PA space, and so if the PA
> space is very large (and memory hotplug is enabled), no randomization
> is possible, as it may end up mapping RAM that appears later past the
> top of the VA space. Note that the same is fundamentally true for
> running a 39-bit VA kernel on hardware that has a PA range that
> exceeds that.
> 
> As for the signed arithmetic: the randomization works by substracting
> from memstart_addr (aka PHYS_OFFSET). Normally, if system RAM starts
> at 1G, memstart_addr will be 1G, and the linear map will associate
> PAGE_OFFSET with PA 1G.
> 
> To randomize the linear mapping, the system RAM has to be moved up in
> the linear map (as this is the only direction it can be moved), and so
> PAGE_OFFSET needs to map to a lower value, and so memstart_addr may
> wrap around and become negative.
> 
>> (I
>> think this assumes that VA size is always GTE PA size). But if linear map size
>> is based on an overridden VA and overridden PA size (which I assume it must be,
>> given the pgtables will be limitted to the overridden VA size) and PA size is
>> not overridden, isn't it possible to wrongly conclude that there is enough room
>> to randomize when there really is not?
>>
> 
> No, if the linear map is only 47 bits, and the PA space is either 52
> or 48 bits, no randomization is possible. We might even run out of
> space without randomization, but this is an existing problem for
> non-LPA2 too.

Ahh that all makes much more sense now! I'm happy to go with the patch Will
proposed.

Thanks,
Ryan
Will Deacon Feb. 27, 2025, 6:50 p.m. UTC | #13
On Tue, 25 Feb 2025 11:46:36 +0000, Ryan Roberts wrote:
> When the range of present physical memory is sufficiently small enough
> and the reserved address space for the linear map is sufficiently large
> enough, The linear map base address is randomized in
> arm64_memblock_init().
> 
> Prior to commit 62cffa496aac ("arm64/mm: Override PARange for !LPA2 and
> use it consistently"), we decided if the sizes were suitable with the
> help of the raw mmfr0.parange. But the commit changed this to use the
> sanitized version instead. But the function runs before the register has
> been sanitized so this returns 0, interpreted as a parange of 32 bits.
> Some fun wrapping occurs and the logic concludes that there is enough
> room to randomize the linear map base address, when really there isn't.
> So the top of the linear map ends up outside the reserved address space.
> 
> [...]

Applied the reduced version to arm64 (for-next/fixes), thanks!

[1/1] arm64/mm: Fix Boot panic on Ampere Altra
      https://git.kernel.org/arm64/c/2b1283e1ea9b

Cheers,
Luiz Capitulino Feb. 27, 2025, 8:43 p.m. UTC | #14
On 2025-02-27 13:50, Will Deacon wrote:
> On Tue, 25 Feb 2025 11:46:36 +0000, Ryan Roberts wrote:
>> When the range of present physical memory is sufficiently small enough
>> and the reserved address space for the linear map is sufficiently large
>> enough, The linear map base address is randomized in
>> arm64_memblock_init().
>>
>> Prior to commit 62cffa496aac ("arm64/mm: Override PARange for !LPA2 and
>> use it consistently"), we decided if the sizes were suitable with the
>> help of the raw mmfr0.parange. But the commit changed this to use the
>> sanitized version instead. But the function runs before the register has
>> been sanitized so this returns 0, interpreted as a parange of 32 bits.
>> Some fun wrapping occurs and the logic concludes that there is enough
>> room to randomize the linear map base address, when really there isn't.
>> So the top of the linear map ends up outside the reserved address space.
>>
>> [...]
> 
> Applied the reduced version to arm64 (for-next/fixes), thanks!
> 
> [1/1] arm64/mm: Fix Boot panic on Ampere Altra
>        https://git.kernel.org/arm64/c/2b1283e1ea9b

Just in case:

Tested-by: Luiz Capitulino <luizcap@redhat.com>
diff mbox series

Patch

diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index e0e4478f5fb5..2335f44b9a4d 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -1066,6 +1066,15 @@  static inline bool cpu_has_lpa2(void)
 #endif
 }

+static inline u64 cpu_get_parange(void)
+{
+	u64 mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
+
+	return arm64_apply_feature_override(mmfr0,
+					    ID_AA64MMFR0_EL1_PARANGE_SHIFT, 4,
+					    &id_aa64mmfr0_override);
+}
+
 #endif /* __ASSEMBLY__ */

 #endif
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 9c0b8d9558fc..1b1a61191b9f 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -280,13 +280,7 @@  void __init arm64_memblock_init(void)
 	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
 		extern u16 memstart_offset_seed;

-		/*
-		 * Use the sanitised version of id_aa64mmfr0_el1 so that linear
-		 * map randomization can be enabled by shrinking the IPA space.
-		 */
-		u64 mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
-		int parange = cpuid_feature_extract_unsigned_field(
-					mmfr0, ID_AA64MMFR0_EL1_PARANGE_SHIFT);
+		int parange = cpu_get_parange();
 		s64 range = linear_region_size -
 			    BIT(id_aa64mmfr0_parange_to_phys_shift(parange));