Commit 671f9a3e authored by Anup Patel's avatar Anup Patel Committed by Paul Walmsley

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: default avatarMike Rapoport <rppt@linux.ibm.com>
Signed-off-by: default avatarAnup Patel <anup.patel@wdc.com>
[paul.walmsley@sifive.com: updated to apply; fixed a checkpatch warning]
Signed-off-by: default avatarPaul Walmsley <paul.walmsley@sifive.com>
parent 2ebca1cb
...@@ -21,6 +21,11 @@ ...@@ -21,6 +21,11 @@
*/ */
enum fixed_addresses { enum fixed_addresses {
FIX_HOLE, FIX_HOLE,
#define FIX_FDT_SIZE SZ_1M
FIX_FDT_END,
FIX_FDT = FIX_FDT_END + FIX_FDT_SIZE / PAGE_SIZE - 1,
FIX_PTE,
FIX_PMD,
FIX_EARLYCON_MEM_BASE, FIX_EARLYCON_MEM_BASE,
__end_of_fixed_addresses __end_of_fixed_addresses
}; };
......
...@@ -70,6 +70,11 @@ static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t prot) ...@@ -70,6 +70,11 @@ static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t prot)
return __pmd((pfn << _PAGE_PFN_SHIFT) | pgprot_val(prot)); return __pmd((pfn << _PAGE_PFN_SHIFT) | pgprot_val(prot));
} }
static inline unsigned long _pmd_pfn(pmd_t pmd)
{
return pmd_val(pmd) >> _PAGE_PFN_SHIFT;
}
#define pmd_ERROR(e) \ #define pmd_ERROR(e) \
pr_err("%s:%d: bad pmd %016lx.\n", __FILE__, __LINE__, pmd_val(e)) pr_err("%s:%d: bad pmd %016lx.\n", __FILE__, __LINE__, pmd_val(e))
......
...@@ -59,6 +59,8 @@ ...@@ -59,6 +59,8 @@
#define PAGE_KERNEL __pgprot(_PAGE_KERNEL) #define PAGE_KERNEL __pgprot(_PAGE_KERNEL)
#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL | _PAGE_EXEC) #define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL | _PAGE_EXEC)
#define PAGE_TABLE __pgprot(_PAGE_TABLE)
extern pgd_t swapper_pg_dir[]; extern pgd_t swapper_pg_dir[];
/* MAP_PRIVATE permissions: xwr (copy-on-write) */ /* MAP_PRIVATE permissions: xwr (copy-on-write) */
...@@ -118,6 +120,11 @@ static inline pgd_t pfn_pgd(unsigned long pfn, pgprot_t prot) ...@@ -118,6 +120,11 @@ static inline pgd_t pfn_pgd(unsigned long pfn, pgprot_t prot)
return __pgd((pfn << _PAGE_PFN_SHIFT) | pgprot_val(prot)); return __pgd((pfn << _PAGE_PFN_SHIFT) | pgprot_val(prot));
} }
static inline unsigned long _pgd_pfn(pgd_t pgd)
{
return pgd_val(pgd) >> _PAGE_PFN_SHIFT;
}
#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) #define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
/* Locate an entry in the page global directory */ /* Locate an entry in the page global directory */
...@@ -400,6 +407,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma, ...@@ -400,6 +407,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
#define kern_addr_valid(addr) (1) /* FIXME */ #define kern_addr_valid(addr) (1) /* FIXME */
#endif #endif
extern void *dtb_early_va;
extern void setup_bootmem(void); extern void setup_bootmem(void);
extern void paging_init(void); extern void paging_init(void);
......
...@@ -55,7 +55,9 @@ clear_bss_done: ...@@ -55,7 +55,9 @@ clear_bss_done:
/* Initialize page tables and relocate to virtual addresses */ /* Initialize page tables and relocate to virtual addresses */
la sp, init_thread_union + THREAD_SIZE la sp, init_thread_union + THREAD_SIZE
mv a0, s1
call setup_vm call setup_vm
la a0, early_pg_dir
call relocate call relocate
/* Restore C environment */ /* Restore C environment */
...@@ -64,25 +66,23 @@ clear_bss_done: ...@@ -64,25 +66,23 @@ clear_bss_done:
la sp, init_thread_union + THREAD_SIZE la sp, init_thread_union + THREAD_SIZE
/* Start the kernel */ /* Start the kernel */
mv a0, s1
call parse_dtb call parse_dtb
tail start_kernel tail start_kernel
relocate: relocate:
/* Relocate return address */ /* Relocate return address */
li a1, PAGE_OFFSET li a1, PAGE_OFFSET
la a0, _start la a2, _start
sub a1, a1, a0 sub a1, a1, a2
add ra, ra, a1 add ra, ra, a1
/* Point stvec to virtual address of intruction after satp write */ /* Point stvec to virtual address of intruction after satp write */
la a0, 1f la a2, 1f
add a0, a0, a1 add a2, a2, a1
csrw CSR_STVEC, a0 csrw CSR_STVEC, a2
/* Compute satp for kernel page tables, but don't load it yet */ /* Compute satp for kernel page tables, but don't load it yet */
la a2, swapper_pg_dir srl a2, a0, PAGE_SHIFT
srl a2, a2, PAGE_SHIFT
li a1, SATP_MODE li a1, SATP_MODE
or a2, a2, a1 or a2, a2, a1
...@@ -148,6 +148,7 @@ relocate: ...@@ -148,6 +148,7 @@ relocate:
fence fence
/* Enable virtual memory and relocate to virtual address */ /* Enable virtual memory and relocate to virtual address */
la a0, swapper_pg_dir
call relocate call relocate
tail smp_callin tail smp_callin
......
...@@ -39,11 +39,9 @@ struct screen_info screen_info = { ...@@ -39,11 +39,9 @@ struct screen_info screen_info = {
atomic_t hart_lottery; atomic_t hart_lottery;
unsigned long boot_cpu_hartid; unsigned long boot_cpu_hartid;
void __init parse_dtb(phys_addr_t dtb_phys) void __init parse_dtb(void)
{ {
void *dtb = __va(dtb_phys); if (early_init_dt_scan(dtb_early_va))
if (early_init_dt_scan(dtb))
return; return;
pr_err("No DTB passed to the kernel\n"); pr_err("No DTB passed to the kernel\n");
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment