forked from deepin-community/kernel
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This patch contains code to manage the RISC-V MMU, including definitions of the page tables and the page walking code. Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
- Loading branch information
1 parent
6d60b6e
commit 07037db
Showing
8 changed files
with
1,192 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* | ||
* Copyright (C) 2012 Regents of the University of California | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation, version 2. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#ifndef _ASM_RISCV_MMU_CONTEXT_H | ||
#define _ASM_RISCV_MMU_CONTEXT_H | ||
|
||
#include <asm-generic/mm_hooks.h> | ||
|
||
#include <linux/mm.h> | ||
#include <linux/sched.h> | ||
#include <asm/tlbflush.h> | ||
|
||
static inline void enter_lazy_tlb(struct mm_struct *mm, | ||
struct task_struct *task) | ||
{ | ||
} | ||
|
||
/* Initialize context-related info for a new mm_struct */ | ||
static inline int init_new_context(struct task_struct *task, | ||
struct mm_struct *mm) | ||
{ | ||
return 0; | ||
} | ||
|
||
static inline void destroy_context(struct mm_struct *mm) | ||
{ | ||
} | ||
|
||
static inline pgd_t *current_pgdir(void) | ||
{ | ||
return pfn_to_virt(csr_read(sptbr) & SPTBR_PPN); | ||
} | ||
|
||
static inline void set_pgdir(pgd_t *pgd) | ||
{ | ||
csr_write(sptbr, virt_to_pfn(pgd) | SPTBR_MODE); | ||
} | ||
|
||
static inline void switch_mm(struct mm_struct *prev, | ||
struct mm_struct *next, struct task_struct *task) | ||
{ | ||
if (likely(prev != next)) { | ||
set_pgdir(next->pgd); | ||
local_flush_tlb_all(); | ||
} | ||
} | ||
|
||
static inline void activate_mm(struct mm_struct *prev, | ||
struct mm_struct *next) | ||
{ | ||
switch_mm(prev, next, NULL); | ||
} | ||
|
||
static inline void deactivate_mm(struct task_struct *task, | ||
struct mm_struct *mm) | ||
{ | ||
} | ||
|
||
#endif /* _ASM_RISCV_MMU_CONTEXT_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
/* | ||
* Copyright (C) 2009 Chen Liqin <liqin.chen@sunplusct.com> | ||
* Copyright (C) 2012 Regents of the University of California | ||
* Copyright (C) 2017 SiFive | ||
* Copyright (C) 2017 XiaojingZhu <zhuxiaoj@ict.ac.cn> | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation, version 2. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#ifndef _ASM_RISCV_PAGE_H | ||
#define _ASM_RISCV_PAGE_H | ||
|
||
#include <linux/pfn.h> | ||
#include <linux/const.h> | ||
|
||
#define PAGE_SHIFT (12) | ||
#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) | ||
#define PAGE_MASK (~(PAGE_SIZE - 1)) | ||
|
||
/* | ||
* PAGE_OFFSET -- the first address of the first page of memory. | ||
* When not using MMU this corresponds to the first free page in | ||
* physical memory (aligned on a page boundary). | ||
*/ | ||
#define PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL) | ||
|
||
#define KERN_VIRT_SIZE (-PAGE_OFFSET) | ||
|
||
#ifndef __ASSEMBLY__ | ||
|
||
#define PAGE_UP(addr) (((addr)+((PAGE_SIZE)-1))&(~((PAGE_SIZE)-1))) | ||
#define PAGE_DOWN(addr) ((addr)&(~((PAGE_SIZE)-1))) | ||
|
||
/* align addr on a size boundary - adjust address up/down if needed */ | ||
#define _ALIGN_UP(addr, size) (((addr)+((size)-1))&(~((size)-1))) | ||
#define _ALIGN_DOWN(addr, size) ((addr)&(~((size)-1))) | ||
|
||
/* align addr on a size boundary - adjust address up if needed */ | ||
#define _ALIGN(addr, size) _ALIGN_UP(addr, size) | ||
|
||
#define clear_page(pgaddr) memset((pgaddr), 0, PAGE_SIZE) | ||
#define copy_page(to, from) memcpy((to), (from), PAGE_SIZE) | ||
|
||
#define clear_user_page(pgaddr, vaddr, page) memset((pgaddr), 0, PAGE_SIZE) | ||
#define copy_user_page(vto, vfrom, vaddr, topg) \ | ||
memcpy((vto), (vfrom), PAGE_SIZE) | ||
|
||
/* | ||
* Use struct definitions to apply C type checking | ||
*/ | ||
|
||
/* Page Global Directory entry */ | ||
typedef struct { | ||
unsigned long pgd; | ||
} pgd_t; | ||
|
||
/* Page Table entry */ | ||
typedef struct { | ||
unsigned long pte; | ||
} pte_t; | ||
|
||
typedef struct { | ||
unsigned long pgprot; | ||
} pgprot_t; | ||
|
||
typedef struct page *pgtable_t; | ||
|
||
#define pte_val(x) ((x).pte) | ||
#define pgd_val(x) ((x).pgd) | ||
#define pgprot_val(x) ((x).pgprot) | ||
|
||
#define __pte(x) ((pte_t) { (x) }) | ||
#define __pgd(x) ((pgd_t) { (x) }) | ||
#define __pgprot(x) ((pgprot_t) { (x) }) | ||
|
||
#ifdef CONFIG_64BITS | ||
#define PTE_FMT "%016lx" | ||
#else | ||
#define PTE_FMT "%08lx" | ||
#endif | ||
|
||
extern unsigned long va_pa_offset; | ||
extern unsigned long pfn_base; | ||
|
||
extern unsigned long max_low_pfn; | ||
extern unsigned long min_low_pfn; | ||
|
||
#define __pa(x) ((unsigned long)(x) - va_pa_offset) | ||
#define __va(x) ((void *)((unsigned long) (x) + va_pa_offset)) | ||
|
||
#define phys_to_pfn(phys) (PFN_DOWN(phys)) | ||
#define pfn_to_phys(pfn) (PFN_PHYS(pfn)) | ||
|
||
#define virt_to_pfn(vaddr) (phys_to_pfn(__pa(vaddr))) | ||
#define pfn_to_virt(pfn) (__va(pfn_to_phys(pfn))) | ||
|
||
#define virt_to_page(vaddr) (pfn_to_page(virt_to_pfn(vaddr))) | ||
#define page_to_virt(page) (pfn_to_virt(page_to_pfn(page))) | ||
|
||
#define page_to_phys(page) (pfn_to_phys(page_to_pfn(page))) | ||
#define page_to_bus(page) (page_to_phys(page)) | ||
#define phys_to_page(paddr) (pfn_to_page(phys_to_pfn(paddr))) | ||
|
||
#define pfn_valid(pfn) \ | ||
(((pfn) >= pfn_base) && (((pfn)-pfn_base) < max_mapnr)) | ||
|
||
#define ARCH_PFN_OFFSET (pfn_base) | ||
|
||
#endif /* __ASSEMBLY__ */ | ||
|
||
#define virt_addr_valid(vaddr) (pfn_valid(virt_to_pfn(vaddr))) | ||
|
||
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \ | ||
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) | ||
|
||
#include <asm-generic/memory_model.h> | ||
#include <asm-generic/getorder.h> | ||
|
||
/* vDSO support */ | ||
/* We do define AT_SYSINFO_EHDR but don't use the gate mechanism */ | ||
#define __HAVE_ARCH_GATE_AREA | ||
|
||
#endif /* _ASM_RISCV_PAGE_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
/* | ||
* Copyright (C) 2009 Chen Liqin <liqin.chen@sunplusct.com> | ||
* Copyright (C) 2012 Regents of the University of California | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation, version 2. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#ifndef _ASM_RISCV_PGALLOC_H | ||
#define _ASM_RISCV_PGALLOC_H | ||
|
||
#include <linux/mm.h> | ||
#include <asm/tlb.h> | ||
|
||
static inline void pmd_populate_kernel(struct mm_struct *mm, | ||
pmd_t *pmd, pte_t *pte) | ||
{ | ||
unsigned long pfn = virt_to_pfn(pte); | ||
|
||
set_pmd(pmd, __pmd((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE)); | ||
} | ||
|
||
static inline void pmd_populate(struct mm_struct *mm, | ||
pmd_t *pmd, pgtable_t pte) | ||
{ | ||
unsigned long pfn = virt_to_pfn(page_address(pte)); | ||
|
||
set_pmd(pmd, __pmd((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE)); | ||
} | ||
|
||
#ifndef __PAGETABLE_PMD_FOLDED | ||
static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) | ||
{ | ||
unsigned long pfn = virt_to_pfn(pmd); | ||
|
||
set_pud(pud, __pud((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE)); | ||
} | ||
#endif /* __PAGETABLE_PMD_FOLDED */ | ||
|
||
#define pmd_pgtable(pmd) pmd_page(pmd) | ||
|
||
static inline pgd_t *pgd_alloc(struct mm_struct *mm) | ||
{ | ||
pgd_t *pgd; | ||
|
||
pgd = (pgd_t *)__get_free_page(GFP_KERNEL); | ||
if (likely(pgd != NULL)) { | ||
memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); | ||
/* Copy kernel mappings */ | ||
memcpy(pgd + USER_PTRS_PER_PGD, | ||
init_mm.pgd + USER_PTRS_PER_PGD, | ||
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); | ||
} | ||
return pgd; | ||
} | ||
|
||
static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) | ||
{ | ||
free_page((unsigned long)pgd); | ||
} | ||
|
||
#ifndef __PAGETABLE_PMD_FOLDED | ||
|
||
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) | ||
{ | ||
return (pmd_t *)__get_free_page( | ||
GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_ZERO); | ||
} | ||
|
||
static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) | ||
{ | ||
free_page((unsigned long)pmd); | ||
} | ||
|
||
#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd) | ||
|
||
#endif /* __PAGETABLE_PMD_FOLDED */ | ||
|
||
static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, | ||
unsigned long address) | ||
{ | ||
return (pte_t *)__get_free_page( | ||
GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_ZERO); | ||
} | ||
|
||
static inline struct page *pte_alloc_one(struct mm_struct *mm, | ||
unsigned long address) | ||
{ | ||
struct page *pte; | ||
|
||
pte = alloc_page(GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_ZERO); | ||
if (likely(pte != NULL)) | ||
pgtable_page_ctor(pte); | ||
return pte; | ||
} | ||
|
||
static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) | ||
{ | ||
free_page((unsigned long)pte); | ||
} | ||
|
||
static inline void pte_free(struct mm_struct *mm, pgtable_t pte) | ||
{ | ||
pgtable_page_dtor(pte); | ||
__free_page(pte); | ||
} | ||
|
||
#define __pte_free_tlb(tlb, pte, buf) \ | ||
do { \ | ||
pgtable_page_dtor(pte); \ | ||
tlb_remove_page((tlb), pte); \ | ||
} while (0) | ||
|
||
static inline void check_pgt_cache(void) | ||
{ | ||
} | ||
|
||
#endif /* _ASM_RISCV_PGALLOC_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
* Copyright (C) 2012 Regents of the University of California | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation, version 2. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#ifndef _ASM_RISCV_PGTABLE_32_H | ||
#define _ASM_RISCV_PGTABLE_32_H | ||
|
||
#include <asm-generic/pgtable-nopmd.h> | ||
#include <linux/const.h> | ||
|
||
/* Size of region mapped by a page global directory */ | ||
#define PGDIR_SHIFT 22 | ||
#define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT) | ||
#define PGDIR_MASK (~(PGDIR_SIZE - 1)) | ||
|
||
#endif /* _ASM_RISCV_PGTABLE_32_H */ |
Oops, something went wrong.