Skip to content

Commit ef69d25

Browse files
Alexandre Ghitipalmer-dabbelt
authored andcommitted
riscv: Move early dtb mapping into the fixmap region
riscv establishes 2 virtual mappings: - early_pg_dir maps the kernel which allows to discover the system memory - swapper_pg_dir installs the final mapping (linear mapping included) We used to map the dtb in early_pg_dir using DTB_EARLY_BASE_VA, and this mapping was not carried over in swapper_pg_dir. It happens that early_init_fdt_scan_reserved_mem() must be called before swapper_pg_dir is setup otherwise we could allocate reserved memory defined in the dtb. And this function initializes reserved_mem variable with addresses that lie in the early_pg_dir dtb mapping: when those addresses are reused with swapper_pg_dir, this mapping does not exist and then we trap. The previous "fix" was incorrect as early_init_fdt_scan_reserved_mem() must be called before swapper_pg_dir is set up otherwise we could allocate in reserved memory defined in the dtb. So move the dtb mapping in the fixmap region which is established in early_pg_dir and handed over to swapper_pg_dir. Fixes: 922b037 ("riscv: Fix memblock reservation for device tree blob") Fixes: 8f3a2b4 ("RISC-V: Move DT mapping outof fixmap") Fixes: 50e63dd ("riscv: fix reserved memory setup") Reported-by: Conor Dooley <[email protected]> Link: https://lore.kernel.org/all/[email protected]/ Signed-off-by: Alexandre Ghiti <[email protected]> Reviewed-by: Conor Dooley <[email protected]> Tested-by: Conor Dooley <[email protected]> Link: https://lore.kernel.org/r/[email protected] Cc: [email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent 8d73648 commit ef69d25

5 files changed

Lines changed: 51 additions & 33 deletions

File tree

Documentation/riscv/vm-layout.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ RISC-V Linux Kernel SV39
4747
| Kernel-space virtual memory, shared between all processes:
4848
____________________________________________________________|___________________________________________________________
4949
| | | |
50-
ffffffc6fee00000 | -228 GB | ffffffc6feffffff | 2 MB | fixmap
50+
ffffffc6fea00000 | -228 GB | ffffffc6feffffff | 6 MB | fixmap
5151
ffffffc6ff000000 | -228 GB | ffffffc6ffffffff | 16 MB | PCI io
5252
ffffffc700000000 | -228 GB | ffffffc7ffffffff | 4 GB | vmemmap
5353
ffffffc800000000 | -224 GB | ffffffd7ffffffff | 64 GB | vmalloc/ioremap space
@@ -83,7 +83,7 @@ RISC-V Linux Kernel SV48
8383
| Kernel-space virtual memory, shared between all processes:
8484
____________________________________________________________|___________________________________________________________
8585
| | | |
86-
ffff8d7ffee00000 | -114.5 TB | ffff8d7ffeffffff | 2 MB | fixmap
86+
ffff8d7ffea00000 | -114.5 TB | ffff8d7ffeffffff | 6 MB | fixmap
8787
ffff8d7fff000000 | -114.5 TB | ffff8d7fffffffff | 16 MB | PCI io
8888
ffff8d8000000000 | -114.5 TB | ffff8f7fffffffff | 2 TB | vmemmap
8989
ffff8f8000000000 | -112.5 TB | ffffaf7fffffffff | 32 TB | vmalloc/ioremap space
@@ -119,7 +119,7 @@ RISC-V Linux Kernel SV57
119119
| Kernel-space virtual memory, shared between all processes:
120120
____________________________________________________________|___________________________________________________________
121121
| | | |
122-
ff1bfffffee00000 | -57 PB | ff1bfffffeffffff | 2 MB | fixmap
122+
ff1bfffffea00000 | -57 PB | ff1bfffffeffffff | 6 MB | fixmap
123123
ff1bffffff000000 | -57 PB | ff1bffffffffffff | 16 MB | PCI io
124124
ff1c000000000000 | -57 PB | ff1fffffffffffff | 1 PB | vmemmap
125125
ff20000000000000 | -56 PB | ff5fffffffffffff | 16 PB | vmalloc/ioremap space

arch/riscv/include/asm/fixmap.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@
2222
*/
2323
enum fixed_addresses {
2424
FIX_HOLE,
25+
/*
26+
* The fdt fixmap mapping must be PMD aligned and will be mapped
27+
* using PMD entries in fixmap_pmd in 64-bit and a PGD entry in 32-bit.
28+
*/
29+
FIX_FDT_END,
30+
FIX_FDT = FIX_FDT_END + FIX_FDT_SIZE / PAGE_SIZE - 1,
31+
32+
/* Below fixmaps will be mapped using fixmap_pte */
2533
FIX_PTE,
2634
FIX_PMD,
2735
FIX_PUD,

arch/riscv/include/asm/pgtable.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,13 @@
8787

8888
#define FIXADDR_TOP PCI_IO_START
8989
#ifdef CONFIG_64BIT
90-
#define FIXADDR_SIZE PMD_SIZE
90+
#define MAX_FDT_SIZE PMD_SIZE
91+
#define FIX_FDT_SIZE (MAX_FDT_SIZE + SZ_2M)
92+
#define FIXADDR_SIZE (PMD_SIZE + FIX_FDT_SIZE)
9193
#else
92-
#define FIXADDR_SIZE PGDIR_SIZE
94+
#define MAX_FDT_SIZE PGDIR_SIZE
95+
#define FIX_FDT_SIZE MAX_FDT_SIZE
96+
#define FIXADDR_SIZE (PGDIR_SIZE + FIX_FDT_SIZE)
9397
#endif
9498
#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
9599

arch/riscv/kernel/setup.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,6 @@ void __init setup_arch(char **cmdline_p)
283283
else
284284
pr_err("No DTB found in kernel mappings\n");
285285
#endif
286-
early_init_fdt_scan_reserved_mem();
287286
misc_mem_init();
288287

289288
init_resources();

arch/riscv/mm/init.c

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]
5757
EXPORT_SYMBOL(empty_zero_page);
5858

5959
extern char _start[];
60-
#define DTB_EARLY_BASE_VA PGDIR_SIZE
6160
void *_dtb_early_va __initdata;
6261
uintptr_t _dtb_early_pa __initdata;
6362

@@ -236,6 +235,14 @@ static void __init setup_bootmem(void)
236235
set_max_mapnr(max_low_pfn - ARCH_PFN_OFFSET);
237236

238237
reserve_initrd_mem();
238+
239+
/*
240+
* No allocation should be done before reserving the memory as defined
241+
* in the device tree, otherwise the allocation could end up in a
242+
* reserved region.
243+
*/
244+
early_init_fdt_scan_reserved_mem();
245+
239246
/*
240247
* If DTB is built in, no need to reserve its memblock.
241248
* Otherwise, do reserve it but avoid using
@@ -279,9 +286,6 @@ pgd_t trampoline_pg_dir[PTRS_PER_PGD] __page_aligned_bss;
279286
static pte_t fixmap_pte[PTRS_PER_PTE] __page_aligned_bss;
280287

281288
pgd_t early_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
282-
static p4d_t __maybe_unused early_dtb_p4d[PTRS_PER_P4D] __initdata __aligned(PAGE_SIZE);
283-
static pud_t __maybe_unused early_dtb_pud[PTRS_PER_PUD] __initdata __aligned(PAGE_SIZE);
284-
static pmd_t __maybe_unused early_dtb_pmd[PTRS_PER_PMD] __initdata __aligned(PAGE_SIZE);
285289

286290
#ifdef CONFIG_XIP_KERNEL
287291
#define pt_ops (*(struct pt_alloc_ops *)XIP_FIXUP(&pt_ops))
@@ -626,17 +630,13 @@ static void __init create_p4d_mapping(p4d_t *p4dp,
626630
#define trampoline_pgd_next (pgtable_l5_enabled ? \
627631
(uintptr_t)trampoline_p4d : (pgtable_l4_enabled ? \
628632
(uintptr_t)trampoline_pud : (uintptr_t)trampoline_pmd))
629-
#define early_dtb_pgd_next (pgtable_l5_enabled ? \
630-
(uintptr_t)early_dtb_p4d : (pgtable_l4_enabled ? \
631-
(uintptr_t)early_dtb_pud : (uintptr_t)early_dtb_pmd))
632633
#else
633634
#define pgd_next_t pte_t
634635
#define alloc_pgd_next(__va) pt_ops.alloc_pte(__va)
635636
#define get_pgd_next_virt(__pa) pt_ops.get_pte_virt(__pa)
636637
#define create_pgd_next_mapping(__nextp, __va, __pa, __sz, __prot) \
637638
create_pte_mapping(__nextp, __va, __pa, __sz, __prot)
638639
#define fixmap_pgd_next ((uintptr_t)fixmap_pte)
639-
#define early_dtb_pgd_next ((uintptr_t)early_dtb_pmd)
640640
#define create_p4d_mapping(__pmdp, __va, __pa, __sz, __prot) do {} while(0)
641641
#define create_pud_mapping(__pmdp, __va, __pa, __sz, __prot) do {} while(0)
642642
#define create_pmd_mapping(__pmdp, __va, __pa, __sz, __prot) do {} while(0)
@@ -860,32 +860,28 @@ static void __init create_kernel_page_table(pgd_t *pgdir, bool early)
860860
* this means 2 PMD entries whereas for 32-bit kernel, this is only 1 PGDIR
861861
* entry.
862862
*/
863-
static void __init create_fdt_early_page_table(pgd_t *pgdir, uintptr_t dtb_pa)
863+
static void __init create_fdt_early_page_table(pgd_t *pgdir,
864+
uintptr_t fix_fdt_va,
865+
uintptr_t dtb_pa)
864866
{
865-
#ifndef CONFIG_BUILTIN_DTB
866867
uintptr_t pa = dtb_pa & ~(PMD_SIZE - 1);
867868

868-
create_pgd_mapping(early_pg_dir, DTB_EARLY_BASE_VA,
869-
IS_ENABLED(CONFIG_64BIT) ? early_dtb_pgd_next : pa,
870-
PGDIR_SIZE,
871-
IS_ENABLED(CONFIG_64BIT) ? PAGE_TABLE : PAGE_KERNEL);
872-
873-
if (pgtable_l5_enabled)
874-
create_p4d_mapping(early_dtb_p4d, DTB_EARLY_BASE_VA,
875-
(uintptr_t)early_dtb_pud, P4D_SIZE, PAGE_TABLE);
876-
877-
if (pgtable_l4_enabled)
878-
create_pud_mapping(early_dtb_pud, DTB_EARLY_BASE_VA,
879-
(uintptr_t)early_dtb_pmd, PUD_SIZE, PAGE_TABLE);
869+
#ifndef CONFIG_BUILTIN_DTB
870+
/* Make sure the fdt fixmap address is always aligned on PMD size */
871+
BUILD_BUG_ON(FIX_FDT % (PMD_SIZE / PAGE_SIZE));
880872

881-
if (IS_ENABLED(CONFIG_64BIT)) {
882-
create_pmd_mapping(early_dtb_pmd, DTB_EARLY_BASE_VA,
873+
/* In 32-bit only, the fdt lies in its own PGD */
874+
if (!IS_ENABLED(CONFIG_64BIT)) {
875+
create_pgd_mapping(early_pg_dir, fix_fdt_va,
876+
pa, MAX_FDT_SIZE, PAGE_KERNEL);
877+
} else {
878+
create_pmd_mapping(fixmap_pmd, fix_fdt_va,
883879
pa, PMD_SIZE, PAGE_KERNEL);
884-
create_pmd_mapping(early_dtb_pmd, DTB_EARLY_BASE_VA + PMD_SIZE,
880+
create_pmd_mapping(fixmap_pmd, fix_fdt_va + PMD_SIZE,
885881
pa + PMD_SIZE, PMD_SIZE, PAGE_KERNEL);
886882
}
887883

888-
dtb_early_va = (void *)DTB_EARLY_BASE_VA + (dtb_pa & (PMD_SIZE - 1));
884+
dtb_early_va = (void *)fix_fdt_va + (dtb_pa & (PMD_SIZE - 1));
889885
#else
890886
/*
891887
* For 64-bit kernel, __va can't be used since it would return a linear
@@ -1055,7 +1051,8 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
10551051
create_kernel_page_table(early_pg_dir, true);
10561052

10571053
/* Setup early mapping for FDT early scan */
1058-
create_fdt_early_page_table(early_pg_dir, dtb_pa);
1054+
create_fdt_early_page_table(early_pg_dir,
1055+
__fix_to_virt(FIX_FDT), dtb_pa);
10591056

10601057
/*
10611058
* Bootime fixmap only can handle PMD_SIZE mapping. Thus, boot-ioremap
@@ -1097,6 +1094,16 @@ static void __init setup_vm_final(void)
10971094
u64 i;
10981095

10991096
/* Setup swapper PGD for fixmap */
1097+
#if !defined(CONFIG_64BIT)
1098+
/*
1099+
* In 32-bit, the device tree lies in a pgd entry, so it must be copied
1100+
* directly in swapper_pg_dir in addition to the pgd entry that points
1101+
* to fixmap_pte.
1102+
*/
1103+
unsigned long idx = pgd_index(__fix_to_virt(FIX_FDT));
1104+
1105+
set_pgd(&swapper_pg_dir[idx], early_pg_dir[idx]);
1106+
#endif
11001107
create_pgd_mapping(swapper_pg_dir, FIXADDR_START,
11011108
__pa_symbol(fixmap_pgd_next),
11021109
PGDIR_SIZE, PAGE_TABLE);

0 commit comments

Comments
 (0)