Signed-off-by: Andrew Jones <drjones@xxxxxxxxxx> --- lib/arm64/asm/page.h | 66 +++++++++++++++++++- lib/arm64/asm/pgtable-hwdef.h | 136 ++++++++++++++++++++++++++++++++++++++++++ lib/arm64/asm/pgtable.h | 69 +++++++++++++++++++++ 3 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 lib/arm64/asm/pgtable-hwdef.h create mode 100644 lib/arm64/asm/pgtable.h diff --git a/lib/arm64/asm/page.h b/lib/arm64/asm/page.h index 395760cad5f82..29ad1f1f720c4 100644 --- a/lib/arm64/asm/page.h +++ b/lib/arm64/asm/page.h @@ -1 +1,65 @@ -#include "../../arm/asm/page.h" +#ifndef _ASMARM64_PAGE_H_ +#define _ASMARM64_PAGE_H_ +/* + * Adapted from + * arch/arm64/include/asm/pgtable-types.h + * include/asm-generic/pgtable-nopud.h + * include/asm-generic/pgtable-nopmd.h + * + * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@xxxxxxxxxx> + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ + +#include <const.h> + +#define PGTABLE_LEVELS 2 +#define VA_BITS 42 + +#define PAGE_SHIFT 16 +#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#ifndef __ASSEMBLY__ + +#define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE) + +#include <alloc.h> + +typedef u64 pteval_t; +typedef u64 pmdval_t; +typedef u64 pudval_t; +typedef u64 pgdval_t; +typedef struct { pteval_t pte; } pte_t; +typedef struct { pgdval_t pgd; } pgd_t; +typedef struct { pteval_t pgprot; } pgprot_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) } ) + +typedef struct { pgd_t pgd; } pud_t; +#define pud_val(x) (pgd_val((x).pgd)) +#define __pud(x) ((pud_t) { __pgd(x) } ) + +typedef struct { pud_t pud; } pmd_t; +#define pmd_val(x) (pud_val((x).pud)) +#define __pmd(x) ((pmd_t) { __pud(x) } ) + +#ifndef __virt_to_phys +#define __phys_to_virt(x) ((unsigned long) (x)) +#define __virt_to_phys(x) (x) +#endif + +#define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) +#define __pa(x) __virt_to_phys((unsigned long)(x)) + +#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) +#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) + +#endif /* !__ASSEMBLY__ */ +#endif /* _ASMARM64_PAGE_H_ */ diff --git a/lib/arm64/asm/pgtable-hwdef.h b/lib/arm64/asm/pgtable-hwdef.h new file mode 100644 index 0000000000000..20ac9fa402987 --- /dev/null +++ b/lib/arm64/asm/pgtable-hwdef.h @@ -0,0 +1,136 @@ +#ifndef _ASMARM64_PGTABLE_HWDEF_H_ +#define _ASMARM64_PGTABLE_HWDEF_H_ +/* + * From arch/arm64/include/asm/pgtable-hwdef.h + * arch/arm64/include/asm/memory.h + */ +#define UL(x) _AC(x, UL) + +#define PTRS_PER_PTE (1 << (PAGE_SHIFT - 3)) + +/* + * PGDIR_SHIFT determines the size a top-level page table entry can map + * (depending on the configuration, this level can be 0, 1 or 2). + */ +#define PGDIR_SHIFT ((PAGE_SHIFT - 3) * PGTABLE_LEVELS + 3) +#define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) +#define PTRS_PER_PGD (1 << (VA_BITS - PGDIR_SHIFT)) + +/* From include/asm-generic/pgtable-nopud.h */ +#define PUD_SHIFT PGDIR_SHIFT +#define PTRS_PER_PUD 1 +#define PUD_SIZE (UL(1) << PUD_SHIFT) +#define PUD_MASK (~(PUD_SIZE-1)) +/* From include/asm-generic/pgtable-nopmd.h */ +#define PMD_SHIFT PUD_SHIFT +#define PTRS_PER_PMD 1 +#define PMD_SIZE (UL(1) << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) + +/* + * Section address mask and size definitions. + */ +#define SECTION_SHIFT PMD_SHIFT +#define SECTION_SIZE (_AC(1, UL) << SECTION_SHIFT) +#define SECTION_MASK (~(SECTION_SIZE-1)) + +/* + * Hardware page table definitions. + * + * Level 1 descriptor (PUD). + */ +#define PUD_TYPE_TABLE (_AT(pudval_t, 3) << 0) +#define PUD_TABLE_BIT (_AT(pgdval_t, 1) << 1) +#define PUD_TYPE_MASK (_AT(pgdval_t, 3) << 0) +#define PUD_TYPE_SECT (_AT(pgdval_t, 1) << 0) + +/* + * Level 2 descriptor (PMD). + */ +#define PMD_TYPE_MASK (_AT(pmdval_t, 3) << 0) +#define PMD_TYPE_FAULT (_AT(pmdval_t, 0) << 0) +#define PMD_TYPE_TABLE (_AT(pmdval_t, 3) << 0) +#define PMD_TYPE_SECT (_AT(pmdval_t, 1) << 0) +#define PMD_TABLE_BIT (_AT(pmdval_t, 1) << 1) + +/* + * Section + */ +#define PMD_SECT_VALID (_AT(pmdval_t, 1) << 0) +#define PMD_SECT_PROT_NONE (_AT(pmdval_t, 1) << 58) +#define PMD_SECT_USER (_AT(pmdval_t, 1) << 6) /* AP[1] */ +#define PMD_SECT_RDONLY (_AT(pmdval_t, 1) << 7) /* AP[2] */ +#define PMD_SECT_S (_AT(pmdval_t, 3) << 8) +#define PMD_SECT_AF (_AT(pmdval_t, 1) << 10) +#define PMD_SECT_NG (_AT(pmdval_t, 1) << 11) +#define PMD_SECT_PXN (_AT(pmdval_t, 1) << 53) +#define PMD_SECT_UXN (_AT(pmdval_t, 1) << 54) + +/* + * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers). + */ +#define PMD_ATTRINDX(t) (_AT(pmdval_t, (t)) << 2) +#define PMD_ATTRINDX_MASK (_AT(pmdval_t, 7) << 2) + +/* + * Level 3 descriptor (PTE). + */ +#define PTE_TYPE_MASK (_AT(pteval_t, 3) << 0) +#define PTE_TYPE_FAULT (_AT(pteval_t, 0) << 0) +#define PTE_TYPE_PAGE (_AT(pteval_t, 3) << 0) +#define PTE_TABLE_BIT (_AT(pteval_t, 1) << 1) +#define PTE_USER (_AT(pteval_t, 1) << 6) /* AP[1] */ +#define PTE_RDONLY (_AT(pteval_t, 1) << 7) /* AP[2] */ +#define PTE_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */ +#define PTE_AF (_AT(pteval_t, 1) << 10) /* Access Flag */ +#define PTE_NG (_AT(pteval_t, 1) << 11) /* nG */ +#define PTE_PXN (_AT(pteval_t, 1) << 53) /* Privileged XN */ +#define PTE_UXN (_AT(pteval_t, 1) << 54) /* User XN */ + +/* + * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers). + */ +#define PTE_ATTRINDX(t) (_AT(pteval_t, (t)) << 2) +#define PTE_ATTRINDX_MASK (_AT(pteval_t, 7) << 2) + +/* + * Highest possible physical address supported. + */ +#define PHYS_MASK_SHIFT (48) +#define PHYS_MASK ((UL(1) << PHYS_MASK_SHIFT) - 1) + +/* + * TCR flags. + */ +#define TCR_TxSZ(x) (((UL(64) - (x)) << 16) | ((UL(64) - (x)) << 0)) +#define TCR_IRGN_NC ((UL(0) << 8) | (UL(0) << 24)) +#define TCR_IRGN_WBWA ((UL(1) << 8) | (UL(1) << 24)) +#define TCR_IRGN_WT ((UL(2) << 8) | (UL(2) << 24)) +#define TCR_IRGN_WBnWA ((UL(3) << 8) | (UL(3) << 24)) +#define TCR_IRGN_MASK ((UL(3) << 8) | (UL(3) << 24)) +#define TCR_ORGN_NC ((UL(0) << 10) | (UL(0) << 26)) +#define TCR_ORGN_WBWA ((UL(1) << 10) | (UL(1) << 26)) +#define TCR_ORGN_WT ((UL(2) << 10) | (UL(2) << 26)) +#define TCR_ORGN_WBnWA ((UL(3) << 10) | (UL(3) << 26)) +#define TCR_ORGN_MASK ((UL(3) << 10) | (UL(3) << 26)) +#define TCR_SHARED ((UL(3) << 12) | (UL(3) << 28)) +#define TCR_TG0_4K (UL(0) << 14) +#define TCR_TG0_64K (UL(1) << 14) +#define TCR_TG0_16K (UL(2) << 14) +#define TCR_TG1_16K (UL(1) << 30) +#define TCR_TG1_4K (UL(2) << 30) +#define TCR_TG1_64K (UL(3) << 30) +#define TCR_ASID16 (UL(1) << 36) +#define TCR_TBI0 (UL(1) << 37) + +/* + * Memory types available. + */ +#define MT_DEVICE_nGnRnE 0 /* noncached */ +#define MT_DEVICE_nGnRE 1 /* device */ +#define MT_DEVICE_GRE 2 +#define MT_NORMAL_NC 3 /* writecombine */ +#define MT_NORMAL 4 + +#endif /* _ASMARM64_PGTABLE_HWDEF_H_ */ diff --git a/lib/arm64/asm/pgtable.h b/lib/arm64/asm/pgtable.h new file mode 100644 index 0000000000000..3635b075682ad --- /dev/null +++ b/lib/arm64/asm/pgtable.h @@ -0,0 +1,69 @@ +#ifndef _ASMARM64_PGTABLE_H_ +#define _ASMARM64_PGTABLE_H_ +/* + * Adapted from arch/arm64/include/asm/pgtable.h + * include/asm-generic/pgtable-nopmd.h + * include/asm-generic/pgtable-nopud.h + * include/linux/mm.h + * + * Note: some Linux function APIs have been modified. Nothing crazy, + * but if a function took, for example, an mm_struct, then + * that was either removed or replaced. + */ +#include <alloc.h> +#include <asm/setup.h> +#include <asm/page.h> +#include <asm/pgtable-hwdef.h> + +#define pgd_none(pgd) (!pgd_val(pgd)) +#define pud_none(pud) (!pud_val(pud)) +#define pmd_none(pmd) (!pmd_val(pmd)) +#define pte_none(pte) (!pte_val(pte)) + +#define pgd_index(addr) \ + (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) +#define pgd_offset(pgtable, addr) ((pgtable) + pgd_index(addr)) + +#define pgd_free(pgd) free(pgd) +static inline pgd_t *pgd_alloc(void) +{ + pgd_t *pgd = memalign(PAGE_SIZE, PTRS_PER_PGD * sizeof(pgd_t)); + memset(pgd, 0, PTRS_PER_PGD * sizeof(pgd_t)); + return pgd; +} + +#define pud_offset(pgd, addr) ((pud_t *)pgd) +#define pud_free(pud) +#define pud_alloc(pgd, addr) pud_offset(pgd, addr) + +#define pmd_offset(pud, addr) ((pmd_t *)pud) +#define pmd_free(pmd) +#define pmd_alloc(pud, addr) pmd_offset(pud, addr) + +static inline pte_t *pmd_page_vaddr(pmd_t pmd) +{ + return __va(pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK); +} + +#define pte_index(addr) \ + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +#define pte_offset(pmd, addr) \ + (pmd_page_vaddr(*(pmd)) + pte_index(addr)) + +#define pte_free(pte) free(pte) +static inline pte_t *pte_alloc_one(void) +{ + pte_t *pte = memalign(PAGE_SIZE, PTRS_PER_PTE * sizeof(pte_t)); + memset(pte, 0, PTRS_PER_PTE * sizeof(pte_t)); + return pte; +} +static inline pte_t *pte_alloc(pmd_t *pmd, unsigned long addr) +{ + if (pmd_none(*pmd)) { + pte_t *pte = pte_alloc_one(); + pmd_val(*pmd) = __pa(pte) | PMD_TYPE_TABLE; + } + return pte_offset(pmd, addr); +} + +#endif /* _ASMARM64_PGTABLE_H_ */ -- 1.9.3 _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/mailman/listinfo/kvmarm