Skip to content

Commit 671f9a3

Browse files
avpatelpaul-walmsley-sifive
authored andcommitted
RISC-V: Setup initial page tables in two stages
Currently, the setup_vm() does initial page table setup in one-shot very early before enabling MMU. Due to this, the setup_vm() has to map all possible kernel virtual addresses since it does not know size and location of RAM. This means we have kernel mappings for non-existent RAM and any buggy driver (or kernel) code doing out-of-bound access to RAM will not fault and cause underterministic behaviour. Further, the setup_vm() creates PMD mappings (i.e. 2M mappings) for RV64 systems. This means for PAGE_OFFSET=0xffffffe000000000 (i.e. MAXPHYSMEM_128GB=y), the setup_vm() will require 129 pages (i.e. 516 KB) of memory for initial page tables which is never freed. The memory required for initial page tables will further increase if we chose a lower value of PAGE_OFFSET (e.g. 0xffffff0000000000) This patch implements two-staged initial page table setup, as follows: 1. Early (i.e. setup_vm()): This stage maps kernel image and DTB in a early page table (i.e. early_pg_dir). The early_pg_dir will be used only by boot HART so it can be freed as-part of init memory free-up. 2. Final (i.e. setup_vm_final()): This stage maps all possible RAM banks in the final page table (i.e. swapper_pg_dir). The boot HART will start using swapper_pg_dir at the end of setup_vm_final(). All non-boot HARTs directly use the swapper_pg_dir created by boot HART. We have following advantages with this new approach: 1. Kernel mappings for non-existent RAM don't exists anymore. 2. Memory consumed by initial page tables is now indpendent of the chosen PAGE_OFFSET. 3. Memory consumed by initial page tables on RV64 system is 2 pages (i.e. 8 KB) which has significantly reduced and these pages will be freed as-part of the init memory free-up. The patch also provides a foundation for implementing strict kernel mappings where we protect kernel text and rodata using PTE permissions. Suggested-by: Mike Rapoport <[email protected]> Signed-off-by: Anup Patel <[email protected]> [[email protected]: updated to apply; fixed a checkpatch warning] Signed-off-by: Paul Walmsley <[email protected]>
1 parent 2ebca1c commit 671f9a3

File tree

6 files changed

+284
-64
lines changed

6 files changed

+284
-64
lines changed

arch/riscv/include/asm/fixmap.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
*/
2222
enum fixed_addresses {
2323
FIX_HOLE,
24+
#define FIX_FDT_SIZE SZ_1M
25+
FIX_FDT_END,
26+
FIX_FDT = FIX_FDT_END + FIX_FDT_SIZE / PAGE_SIZE - 1,
27+
FIX_PTE,
28+
FIX_PMD,
2429
FIX_EARLYCON_MEM_BASE,
2530
__end_of_fixed_addresses
2631
};

arch/riscv/include/asm/pgtable-64.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t prot)
7070
return __pmd((pfn << _PAGE_PFN_SHIFT) | pgprot_val(prot));
7171
}
7272

73+
static inline unsigned long _pmd_pfn(pmd_t pmd)
74+
{
75+
return pmd_val(pmd) >> _PAGE_PFN_SHIFT;
76+
}
77+
7378
#define pmd_ERROR(e) \
7479
pr_err("%s:%d: bad pmd %016lx.\n", __FILE__, __LINE__, pmd_val(e))
7580

arch/riscv/include/asm/pgtable.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@
5959
#define PAGE_KERNEL __pgprot(_PAGE_KERNEL)
6060
#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL | _PAGE_EXEC)
6161

62+
#define PAGE_TABLE __pgprot(_PAGE_TABLE)
63+
6264
extern pgd_t swapper_pg_dir[];
6365

6466
/* MAP_PRIVATE permissions: xwr (copy-on-write) */
@@ -118,6 +120,11 @@ static inline pgd_t pfn_pgd(unsigned long pfn, pgprot_t prot)
118120
return __pgd((pfn << _PAGE_PFN_SHIFT) | pgprot_val(prot));
119121
}
120122

123+
static inline unsigned long _pgd_pfn(pgd_t pgd)
124+
{
125+
return pgd_val(pgd) >> _PAGE_PFN_SHIFT;
126+
}
127+
121128
#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
122129

123130
/* Locate an entry in the page global directory */
@@ -400,6 +407,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
400407
#define kern_addr_valid(addr) (1) /* FIXME */
401408
#endif
402409

410+
extern void *dtb_early_va;
403411
extern void setup_bootmem(void);
404412
extern void paging_init(void);
405413

arch/riscv/kernel/head.S

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ clear_bss_done:
5555

5656
/* Initialize page tables and relocate to virtual addresses */
5757
la sp, init_thread_union + THREAD_SIZE
58+
mv a0, s1
5859
call setup_vm
60+
la a0, early_pg_dir
5961
call relocate
6062

6163
/* Restore C environment */
@@ -64,25 +66,23 @@ clear_bss_done:
6466
la sp, init_thread_union + THREAD_SIZE
6567

6668
/* Start the kernel */
67-
mv a0, s1
6869
call parse_dtb
6970
tail start_kernel
7071

7172
relocate:
7273
/* Relocate return address */
7374
li a1, PAGE_OFFSET
74-
la a0, _start
75-
sub a1, a1, a0
75+
la a2, _start
76+
sub a1, a1, a2
7677
add ra, ra, a1
7778

7879
/* Point stvec to virtual address of intruction after satp write */
79-
la a0, 1f
80-
add a0, a0, a1
81-
csrw CSR_STVEC, a0
80+
la a2, 1f
81+
add a2, a2, a1
82+
csrw CSR_STVEC, a2
8283

8384
/* Compute satp for kernel page tables, but don't load it yet */
84-
la a2, swapper_pg_dir
85-
srl a2, a2, PAGE_SHIFT
85+
srl a2, a0, PAGE_SHIFT
8686
li a1, SATP_MODE
8787
or a2, a2, a1
8888

@@ -148,6 +148,7 @@ relocate:
148148
fence
149149

150150
/* Enable virtual memory and relocate to virtual address */
151+
la a0, swapper_pg_dir
151152
call relocate
152153

153154
tail smp_callin

arch/riscv/kernel/setup.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,9 @@ struct screen_info screen_info = {
3939
atomic_t hart_lottery;
4040
unsigned long boot_cpu_hartid;
4141

42-
void __init parse_dtb(phys_addr_t dtb_phys)
42+
void __init parse_dtb(void)
4343
{
44-
void *dtb = __va(dtb_phys);
45-
46-
if (early_init_dt_scan(dtb))
44+
if (early_init_dt_scan(dtb_early_va))
4745
return;
4846

4947
pr_err("No DTB passed to the kernel\n");

0 commit comments

Comments
 (0)