Skip to content

Commit 17e9521

Browse files
pigmoralPaul Walmsley
authored andcommitted
riscv: mm: Use mmu-type from FDT to limit SATP mode
Some RISC-V implementations may hang when attempting to write an unsupported SATP mode, even though the latest RISC-V specification states such writes should have no effect. To avoid this issue, the logic for selecting SATP mode has been refined: The kernel now determines the SATP mode limit by taking the minimum of the value specified by the kernel command line (noXlvl) and the "mmu-type" property in the device tree (FDT). If only one is specified, use that. - If the resulting limit is sv48 or higher, the kernel will probe SATP modes from this limit downward until a supported mode is found. - If the limit is sv39, the kernel will directly use sv39 without probing. This ensures SATP mode selection is safe and compatible with both hardware and user configuration, minimizing the risk of hangs. Signed-off-by: Junhui Liu <junhui.liu@pigmoral.tech> Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com> Reviewed-by: Nutty Liu <liujingqi@lanxincomputing.com> Link: https://lore.kernel.org/r/20250722-satp-from-fdt-v1-2-5ba22218fa5f@pigmoral.tech Signed-off-by: Paul Walmsley <pjw@kernel.org>
1 parent f3243be commit 17e9521

File tree

3 files changed

+49
-3
lines changed

3 files changed

+49
-3
lines changed

arch/riscv/kernel/pi/fdt_early.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <linux/init.h>
44
#include <linux/libfdt.h>
55
#include <linux/ctype.h>
6+
#include <asm/csr.h>
67

78
#include "pi.h"
89

@@ -183,3 +184,42 @@ bool fdt_early_match_extension_isa(const void *fdt, const char *ext_name)
183184

184185
return ret;
185186
}
187+
188+
/**
189+
* set_satp_mode_from_fdt - determine SATP mode based on the MMU type in fdt
190+
*
191+
* @dtb_pa: physical address of the device tree blob
192+
*
193+
* Returns the SATP mode corresponding to the MMU type of the first enabled CPU,
194+
* 0 otherwise
195+
*/
196+
u64 set_satp_mode_from_fdt(uintptr_t dtb_pa)
197+
{
198+
const void *fdt = (const void *)dtb_pa;
199+
const char *mmu_type;
200+
int node, parent;
201+
202+
parent = fdt_path_offset(fdt, "/cpus");
203+
if (parent < 0)
204+
return 0;
205+
206+
fdt_for_each_subnode(node, fdt, parent) {
207+
if (!fdt_node_name_eq(fdt, node, "cpu"))
208+
continue;
209+
210+
if (!fdt_device_is_available(fdt, node))
211+
continue;
212+
213+
mmu_type = fdt_getprop(fdt, node, "mmu-type", NULL);
214+
if (!mmu_type)
215+
break;
216+
217+
if (!strcmp(mmu_type, "riscv,sv39"))
218+
return SATP_MODE_39;
219+
else if (!strcmp(mmu_type, "riscv,sv48"))
220+
return SATP_MODE_48;
221+
break;
222+
}
223+
224+
return 0;
225+
}

arch/riscv/kernel/pi/pi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ u64 get_kaslr_seed(uintptr_t dtb_pa);
1414
u64 get_kaslr_seed_zkr(const uintptr_t dtb_pa);
1515
bool set_nokaslr_from_cmdline(uintptr_t dtb_pa);
1616
u64 set_satp_mode_from_cmdline(uintptr_t dtb_pa);
17+
u64 set_satp_mode_from_fdt(uintptr_t dtb_pa);
1718

1819
bool fdt_early_match_extension_isa(const void *fdt, const char *ext_name);
1920

arch/riscv/mm/init.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,7 @@ static __meminit pgprot_t pgprot_from_va(uintptr_t va)
816816

817817
#if defined(CONFIG_64BIT) && !defined(CONFIG_XIP_KERNEL)
818818
u64 __pi_set_satp_mode_from_cmdline(uintptr_t dtb_pa);
819+
u64 __pi_set_satp_mode_from_fdt(uintptr_t dtb_pa);
819820

820821
static void __init disable_pgtable_l5(void)
821822
{
@@ -855,18 +856,22 @@ static void __init set_mmap_rnd_bits_max(void)
855856
* underlying hardware: establish 1:1 mapping in 4-level page table mode
856857
* then read SATP to see if the configuration was taken into account
857858
* meaning sv48 is supported.
859+
* The maximum SATP mode is limited by both the command line and the "mmu-type"
860+
* property in the device tree, since some platforms may hang if an unsupported
861+
* SATP mode is attempted.
858862
*/
859863
static __init void set_satp_mode(uintptr_t dtb_pa)
860864
{
861865
u64 identity_satp, hw_satp;
862866
uintptr_t set_satp_mode_pmd = ((unsigned long)set_satp_mode) & PMD_MASK;
863-
u64 satp_mode_cmdline = __pi_set_satp_mode_from_cmdline(dtb_pa);
867+
u64 satp_mode_limit = min_not_zero(__pi_set_satp_mode_from_cmdline(dtb_pa),
868+
__pi_set_satp_mode_from_fdt(dtb_pa));
864869

865870
kernel_map.page_offset = PAGE_OFFSET_L5;
866871

867-
if (satp_mode_cmdline == SATP_MODE_48) {
872+
if (satp_mode_limit == SATP_MODE_48) {
868873
disable_pgtable_l5();
869-
} else if (satp_mode_cmdline == SATP_MODE_39) {
874+
} else if (satp_mode_limit == SATP_MODE_39) {
870875
disable_pgtable_l5();
871876
disable_pgtable_l4();
872877
return;

0 commit comments

Comments
 (0)