[PATCH v2 -next] riscv: mm: remove redundant trampoline PGD for 64bit

Alex Ghiti alex at ghiti.fr
Mon Aug 2 05:43:02 PDT 2021


Hi Nanyong,

Le 28/07/2021 à 13:55, Alex Ghiti a écrit :
> 
> 
> Le 28/07/2021 à 04:49, Nanyong Sun a écrit :
>> Remove redundant trampoline PGD for 64bit and add more comment
>> for why 32bit systems need trampoline PGD.
>>
>> There was a patch and discussion similar to this,refer to
>> the link [1][2].
>>
>> The trampoline PGD is redundant for 64bit systems because:
>> 1. The early PGD covers the entire kernel mapping. Directly
>> loading early PGD can achieve the result in boot stage.
>> A more trampoline PGD makes code hard to understand.
>> 2. Directly loading early PGD is safe in 64bit systems since
>> the kernel virtual address starts as 0xFFFFxxxxxxxxxxxx,
>> which has a very big gap with RAM address.It won't fall into
>> the corner case that 32bit system worrys.
>> 3. Remove redundant trampoline PGD can benefit to code maintaince,
>> because 64bit systems have more page table levels.For example:
>> If we want to support SV48 which has 4 page table levels, we have
>> to add a trampoline_pud and insert it before trampoline_pmd.
>>
>> Reference link:
>> [1]https://lore.kernel.org/linux-riscv/20190325092234.5451-4-anup.patel@wdc.com/ 
>>
>> [2]https://lkml.org/lkml/2019/3/28/147
>>
>> Signed-off-by: Nanyong Sun <sunnanyong at huawei.com>
>> Reviewed-by: Alexandre Ghiti <alex at ghiti.fr>
> 
> I have not reviewed this patch yet! :)
> 
>> Reviewed-by: Kefeng Wang <wangkefeng.wang at huawei.com>
>> Reviewed-by: weiyongjun <weiyongjun1 at huawei.com>
>> ---
>> v2 changes:
>>    Adjust codes based on the review suggestions from Alex Ghiti,
>>    make codes more readable.
>> ---
>>   arch/riscv/kernel/head.S | 46 ++++++++++++++++++++++++++--------------
>>   arch/riscv/mm/init.c     | 16 ++++----------
>>   2 files changed, 34 insertions(+), 28 deletions(-)
>>
>> diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
>> index fce5184b22c3..3816aa5edc69 100644
>> --- a/arch/riscv/kernel/head.S
>> +++ b/arch/riscv/kernel/head.S
>> @@ -89,29 +89,52 @@ relocate:
>>       add ra, ra, a1
>>       /* Point stvec to virtual address of intruction after satp write */
>> -    la a2, 1f
>> +#ifdef CONFIG_64BIT
>> +    la a2, load_done
>> +#else
>> +    la a2, load_kernel_pgd
>> +#endif
>>       add a2, a2, a1
>>       csrw CSR_TVEC, a2
>> -    /* Compute satp for kernel page tables, but don't load it yet */
>> +    /* Compute satp for kernel page tables.
>> +     * For 64bit systems, load it and trap to stvec.
>> +     * For 32bit systems, don't load it yet.
>> +     */
>>       srl a2, a0, PAGE_SHIFT
>>       li a1, SATP_MODE
>>       or a2, a2, a1
>>       /*
>> +     * Before writing satp, we need a full fence here because 
>> setup_vm() just
>> +     * wrote these PTEs and we need to ensure the new translations 
>> are in use.
>> +     */
>> +    sfence.vma
>> +#ifndef CONFIG_64BIT
>> +    /*
>> +     * 32bit systems need firstly loading a trampoline to handle a 
>> corner
>> +     * case where load address range overlaps kernel virtual address 
>> range.
>>        * Load trampoline page directory, which will cause us to trap to
>> -     * stvec if VA != PA, or simply fall through if VA == PA.  We need a
>> -     * full fence here because setup_vm() just wrote these PTEs and 
>> we need
>> -     * to ensure the new translations are in use.
>> +     * stvec if VA != PA, or simply fall through if VA == PA.
>>        */
>>       la a0, trampoline_pg_dir
>>       XIP_FIXUP_OFFSET a0
>>       srl a0, a0, PAGE_SHIFT
>>       or a0, a0, a1
>> -    sfence.vma
>>       csrw CSR_SATP, a0
>> +#endif
>>   .align 2
>> -1:
>> +load_kernel_pgd:
>> +        /*
>> +         * Switch to kernel page tables.  A full fence is necessary 
>> in order to
>> +         * avoid using the trampoline translations, which are only 
>> correct for
>> +         * the first superpage.  Fetching the fence is guarnteed to work
>> +         * because that first superpage is translated the same way.
>> +         */
>> +        csrw CSR_SATP, a2
>> +        sfence.vma
>> +
>> +load_done:
>>       /* Set trap vector to spin forever to help debug */
>>       la a0, .Lsecondary_park
>>       csrw CSR_TVEC, a0


I suppose stvec was set this way to catch any problem with early_pg_dir, 
you moved that and then this defeats this original purpose.


>> @@ -122,15 +145,6 @@ relocate:
>>       la gp, __global_pointer$
>>   .option pop
>> -    /*
>> -     * Switch to kernel page tables.  A full fence is necessary in 
>> order to
>> -     * avoid using the trampoline translations, which are only 
>> correct for
>> -     * the first superpage.  Fetching the fence is guarnteed to work
>> -     * because that first superpage is translated the same way.
>> -     */
>> -    csrw CSR_SATP, a2
>> -    sfence.vma
>> -
>>       ret
>>   #endif /* CONFIG_MMU */
>>   #ifdef CONFIG_SMP
>> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
>> index ac48742fa6fc..306fcb2334fa 100644
>> --- a/arch/riscv/mm/init.c
>> +++ b/arch/riscv/mm/init.c
>> @@ -219,13 +219,17 @@ unsigned long pfn_base __ro_after_init;
>>   EXPORT_SYMBOL(pfn_base);
>>   pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_bss;
>> +#ifndef CONFIG_64BIT
>>   pgd_t trampoline_pg_dir[PTRS_PER_PGD] __page_aligned_bss;
>> +#endif /* CONFIG_64BIT */


As stated in Documentation/process/coding-style.rst, it is better to use 
__maybe_unused rather than #ifdefs.


>>   static pte_t fixmap_pte[PTRS_PER_PTE] __page_aligned_bss;
>>   pgd_t early_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
>>   #ifdef CONFIG_XIP_KERNEL
>> +#ifndef CONFIG_64BIT
>>   #define trampoline_pg_dir      ((pgd_t *)XIP_FIXUP(trampoline_pg_dir))
>> +#endif /* CONFIG_64BIT */


Using __maybe_unused allows to remove those too.


>>   #define fixmap_pte             ((pte_t *)XIP_FIXUP(fixmap_pte))
>>   #define early_pg_dir           ((pgd_t *)XIP_FIXUP(early_pg_dir))
>>   #endif /* CONFIG_XIP_KERNEL */
>> @@ -300,13 +304,11 @@ static void __init create_pte_mapping(pte_t *ptep,
>>   #ifndef __PAGETABLE_PMD_FOLDED
>> -static pmd_t trampoline_pmd[PTRS_PER_PMD] __page_aligned_bss;
>>   static pmd_t fixmap_pmd[PTRS_PER_PMD] __page_aligned_bss;
>>   static pmd_t early_pmd[PTRS_PER_PMD] __initdata __aligned(PAGE_SIZE);
>>   static pmd_t early_dtb_pmd[PTRS_PER_PMD] __initdata 
>> __aligned(PAGE_SIZE);
>>   #ifdef CONFIG_XIP_KERNEL
>> -#define trampoline_pmd ((pmd_t *)XIP_FIXUP(trampoline_pmd))
>>   #define fixmap_pmd     ((pmd_t *)XIP_FIXUP(fixmap_pmd))
>>   #define early_pmd      ((pmd_t *)XIP_FIXUP(early_pmd))
>>   #endif /* CONFIG_XIP_KERNEL */
>> @@ -585,16 +587,6 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
>>       /* Setup fixmap PMD */
>>       create_pmd_mapping(fixmap_pmd, FIXADDR_START,
>>                  (uintptr_t)fixmap_pte, PMD_SIZE, PAGE_TABLE);
>> -    /* Setup trampoline PGD and PMD */
>> -    create_pgd_mapping(trampoline_pg_dir, kernel_map.virt_addr,
>> -               (uintptr_t)trampoline_pmd, PGDIR_SIZE, PAGE_TABLE);
>> -#ifdef CONFIG_XIP_KERNEL
>> -    create_pmd_mapping(trampoline_pmd, kernel_map.virt_addr,
>> -               kernel_map.xiprom, PMD_SIZE, PAGE_KERNEL_EXEC);
>> -#else
>> -    create_pmd_mapping(trampoline_pmd, kernel_map.virt_addr,
>> -               kernel_map.phys_addr, PMD_SIZE, PAGE_KERNEL_EXEC);
>> -#endif
>>   #else
>>       /* Setup trampoline PGD */
>>       create_pgd_mapping(trampoline_pg_dir, kernel_map.virt_addr,
>>
> 

Overall this version adds more complexity to assembly code than I 
thought, but I don't see any way to improve that (which does not mean 
there isn't!).

Thanks,

Alex


> _______________________________________________
> linux-riscv mailing list
> linux-riscv at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv



More information about the linux-riscv mailing list