Commit f2c17aab authored by Anup Patel's avatar Anup Patel Committed by Anup Patel

RISC-V: Implement compile-time fixed mappings

This patch implements compile-time virtual to physical mappings. These
compile-time fixed mappings can be used by earlycon, ACPI, and early
ioremap for creating fixed mappings when FIX_EARLYCON_MEM=y.

To start with, we have enabled compile-time fixed mappings for earlycon.
Signed-off-by: default avatarAnup Patel <anup.patel@wdc.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarPalmer Dabbelt <palmer@sifive.com>
parent 6f1e9e94
...@@ -89,6 +89,9 @@ config GENERIC_CSUM ...@@ -89,6 +89,9 @@ config GENERIC_CSUM
config GENERIC_HWEIGHT config GENERIC_HWEIGHT
def_bool y def_bool y
config FIX_EARLYCON_MEM
def_bool y
config PGTABLE_LEVELS config PGTABLE_LEVELS
int int
default 3 if 64BIT default 3 if 64BIT
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2019 Western Digital Corporation or its affiliates.
*/
#ifndef _ASM_RISCV_FIXMAP_H
#define _ASM_RISCV_FIXMAP_H
#include <linux/kernel.h>
#include <linux/sizes.h>
#include <asm/page.h>
#include <asm/pgtable.h>
/*
* Here we define all the compile-time 'special' virtual addresses.
* The point is to have a constant address at compile time, but to
* set the physical address only in the boot process.
*
* These 'compile-time allocated' memory buffers are page-sized. Use
* set_fixmap(idx,phys) to associate physical memory with fixmap indices.
*/
enum fixed_addresses {
FIX_HOLE,
FIX_EARLYCON_MEM_BASE,
__end_of_fixed_addresses
};
#define FIXADDR_SIZE (__end_of_fixed_addresses * PAGE_SIZE)
#define FIXADDR_TOP (PAGE_OFFSET)
#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
#define FIXMAP_PAGE_IO PAGE_KERNEL
#define __early_set_fixmap __set_fixmap
#define __late_set_fixmap __set_fixmap
#define __late_clear_fixmap(idx) __set_fixmap((idx), 0, FIXMAP_PAGE_CLEAR)
extern void __set_fixmap(enum fixed_addresses idx,
phys_addr_t phys, pgprot_t prot);
#include <asm-generic/fixmap.h>
#endif /* _ASM_RISCV_FIXMAP_H */
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/of_fdt.h> #include <linux/of_fdt.h>
#include <asm/fixmap.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
...@@ -148,8 +149,28 @@ pgd_t trampoline_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE); ...@@ -148,8 +149,28 @@ pgd_t trampoline_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
#define NUM_SWAPPER_PMDS ((uintptr_t)-PAGE_OFFSET >> PGDIR_SHIFT) #define NUM_SWAPPER_PMDS ((uintptr_t)-PAGE_OFFSET >> PGDIR_SHIFT)
pmd_t swapper_pmd[PTRS_PER_PMD*((-PAGE_OFFSET)/PGDIR_SIZE)] __page_aligned_bss; pmd_t swapper_pmd[PTRS_PER_PMD*((-PAGE_OFFSET)/PGDIR_SIZE)] __page_aligned_bss;
pmd_t trampoline_pmd[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE); pmd_t trampoline_pmd[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
pmd_t fixmap_pmd[PTRS_PER_PMD] __page_aligned_bss;
#endif #endif
pte_t fixmap_pte[PTRS_PER_PTE] __page_aligned_bss;
void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
{
unsigned long addr = __fix_to_virt(idx);
pte_t *ptep;
BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses);
ptep = &fixmap_pte[pte_index(addr)];
if (pgprot_val(prot)) {
set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot));
} else {
pte_clear(&init_mm, addr, ptep);
local_flush_tlb_page(addr);
}
}
asmlinkage void __init setup_vm(void) asmlinkage void __init setup_vm(void)
{ {
extern char _start; extern char _start;
...@@ -172,20 +193,33 @@ asmlinkage void __init setup_vm(void) ...@@ -172,20 +193,33 @@ asmlinkage void __init setup_vm(void)
for (i = 0; i < (-PAGE_OFFSET)/PGDIR_SIZE; ++i) { for (i = 0; i < (-PAGE_OFFSET)/PGDIR_SIZE; ++i) {
size_t o = (PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD + i; size_t o = (PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD + i;
swapper_pg_dir[o] = swapper_pg_dir[o] =
pfn_pgd(PFN_DOWN((uintptr_t)swapper_pmd) + i, pfn_pgd(PFN_DOWN((uintptr_t)swapper_pmd) + i,
__pgprot(_PAGE_TABLE)); __pgprot(_PAGE_TABLE));
} }
for (i = 0; i < ARRAY_SIZE(swapper_pmd); i++) for (i = 0; i < ARRAY_SIZE(swapper_pmd); i++)
swapper_pmd[i] = pfn_pmd(PFN_DOWN(pa + i * PMD_SIZE), prot); swapper_pmd[i] = pfn_pmd(PFN_DOWN(pa + i * PMD_SIZE), prot);
swapper_pg_dir[(FIXADDR_START >> PGDIR_SHIFT) % PTRS_PER_PGD] =
pfn_pgd(PFN_DOWN((uintptr_t)fixmap_pmd),
__pgprot(_PAGE_TABLE));
fixmap_pmd[(FIXADDR_START >> PMD_SHIFT) % PTRS_PER_PMD] =
pfn_pmd(PFN_DOWN((uintptr_t)fixmap_pte),
__pgprot(_PAGE_TABLE));
#else #else
trampoline_pg_dir[(PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD] = trampoline_pg_dir[(PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD] =
pfn_pgd(PFN_DOWN(pa), prot); pfn_pgd(PFN_DOWN(pa), prot);
for (i = 0; i < (-PAGE_OFFSET)/PGDIR_SIZE; ++i) { for (i = 0; i < (-PAGE_OFFSET)/PGDIR_SIZE; ++i) {
size_t o = (PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD + i; size_t o = (PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD + i;
swapper_pg_dir[o] = swapper_pg_dir[o] =
pfn_pgd(PFN_DOWN(pa + i * PGDIR_SIZE), prot); pfn_pgd(PFN_DOWN(pa + i * PGDIR_SIZE), prot);
} }
swapper_pg_dir[(FIXADDR_START >> PGDIR_SHIFT) % PTRS_PER_PGD] =
pfn_pgd(PFN_DOWN((uintptr_t)fixmap_pte),
__pgprot(_PAGE_TABLE));
#endif #endif
} }
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