#ifndef __LUNAIX_ARCH_PAGETABLE_H #define __LUNAIX_ARCH_PAGETABLE_H #include #include #include "aa64_mmu.h" /* ******** Page Table Manipulation ******** */ #define _PTW_LEVEL 4 // Note: we set VMS_SIZE = VMS_MASK as it is impossible // to express 4Gi in 32bit unsigned integer #define VMS_BITS 48 #define PMS_BITS CONFIG_AA64_OA_SIZE #define VMS_SIZE ( 1UL << VMS_BITS) #define VMS_MASK ( VMS_SIZE - 1 ) #define PMS_SIZE ( 1UL << PMS_BITS ) #define PMS_MASK ( PMS_SIZE - 1 ) #define __index(va) ( (va) & VMS_MASK ) #define __vaddr(va) \ ( (__index(va) ^ ((VMS_MASK + 1) >> 1)) - ((VMS_MASK + 1) >> 1) ) #define __paddr(pa) ( (pa) & PMS_MASK ) #if defined(CONFIG_AA64_PAGE_GRAN_4K) #define _PAGE_BASE_SHIFT 12 #elif defined(CONFIG_AA64_PAGE_GRAN_16K) #define _PAGE_BASE_SHIFT 14 #elif defined(CONFIG_AA64_PAGE_GRAN_64K) #define _PAGE_BASE_SHIFT 16 #endif #define _PAGE_BASE_SIZE ( 1UL << _PAGE_BASE_SHIFT ) #define _PAGE_BASE_MASK ( (_PAGE_BASE_SIZE - 1) & VMS_MASK ) #define _PAGE_LEVEL_SHIFT 9 #define _PAGE_LEVEL_SIZE ( 1UL << _PAGE_LEVEL_SHIFT ) #define _PAGE_LEVEL_MASK ( _PAGE_LEVEL_SIZE - 1 ) #define _PAGE_Ln_SIZE(n) \ ( 1UL << (_PAGE_BASE_SHIFT + _PAGE_LEVEL_SHIFT * (_PTW_LEVEL - (n) - 1)) ) /* General size of a LnT huge page */ #define L0T_SIZE _PAGE_Ln_SIZE(0) #define L1T_SIZE _PAGE_Ln_SIZE(1) #define L2T_SIZE _PAGE_Ln_SIZE(2) #define L3T_SIZE _PAGE_Ln_SIZE(3) #define LFT_SIZE _PAGE_Ln_SIZE(3) struct __pte { unsigned long val; } align(8); // upper attributes #define _PTE_UXN (1UL << 54) #define _PTE_PXN (1UL << 53) #define _PTE_XN (_PTE_UXN | _PTE_PXN) #define _PTE_Contig (1UL << 52) #define _PTE_DBM (1UL << 51) #ifdef _MMU_USE_OA52 #if CONFIG_AA64_PAGE_GRAN_64K #define __OA_HIGH_MASK ( 0b1111 << 12 ) #define __OA_HEAD(pa) ((pa) & ((1UL << 48) - 1) & ~PAGE_MASK) #define __OA_TAIL(pa) ((((pa) >> 48) & 0b1111) << 12) #else #define __OA_HIGH_MASK ( 0b0011 << 8 ) #define __OA_HEAD(pa) ((pa) & ((1UL << 50) - 1) & ~PAGE_MASK) #define __OA_TAIL(pa) ((((pa) >> 50) & 0b0011) << 8) #endif #else #define __OA_HIGH_MASK (0) #define __OA_HEAD(pa) (__paddr(pa) & ~PAGE_MASK) #define __OA_TAIL(pa) (0) #endif #define _PTE_OA(pa) (__OA_HEAD(pa) | __OA_TAIL(pa)) // lower attributes #define _PTE_nG (1UL << 11) #define _PTE_AF (1UL << 10) // AP bits: R_RNGJG #define _PTE_AP(p, u) ((((p) & 1) << 1 | ((u) & 1)) << 6) #define _PTE_PRW _PTE_AP(0 , 0) // priv rw, unpriv none #define _PTE_PRWURW _PTE_AP(0 , 1) // priv rw, unpriv rw #define _PTE_U _PTE_AP(0 , 1) // generic unpriv flag #define _PTE_PRO _PTE_AP(1 , 0) // priv ro, unpriv none #define _PTE_PROURO _PTE_AP(1 , 1) // priv ro, unpriv ro #define _PTE_BLKDESC (0b01) #define _PTE_TABDESC (0b11) #define _PTE_LFTDESC (0b11) #define _PTE_VALID (0b01) #define _PTE_DESC_MASK (0b11) #define _PTE_SET_DESC(pte_val, desc) \ ( ((pte_val) & ~_PTE_DESC_MASK) | ((desc) & _PTE_DESC_MASK) ) #define _PTE_GET_DESC(pte_val) \ ( (pte_val) & _PTE_DESC_MASK ) #define __MEMGUARD 0xf0f0f0f0f0f0f0f0UL typedef unsigned long pte_attr_t; typedef unsigned long pfn_t; // always do sign extend on x86_64 /* General mask to get page offset of a LnT huge page */ #define L0T_MASK ( L0T_SIZE - 1 ) #define L1T_MASK ( L1T_SIZE - 1 ) #define L2T_MASK ( L2T_SIZE - 1 ) #define L3T_MASK ( L3T_SIZE - 1 ) #define LFT_MASK ( LFT_SIZE - 1 ) /* Masks to get index of a LnTE */ #define L0T_INDEX_MASK ( VMS_MASK ^ L0T_MASK ) #define L1T_INDEX_MASK ( L0T_MASK ^ L1T_MASK ) #define L2T_INDEX_MASK ( L1T_MASK ^ L2T_MASK ) #define L3T_INDEX_MASK ( L2T_MASK ^ L3T_MASK ) #define LFT_INDEX_MASK ( L3T_MASK ^ LFT_MASK ) #define PAGE_SHIFT _PAGE_BASE_SHIFT #define PAGE_SIZE _PAGE_BASE_SIZE #define PAGE_MASK _PAGE_BASE_MASK #define LEVEL_SHIFT _PAGE_LEVEL_SHIFT #define LEVEL_SIZE _PAGE_LEVEL_SIZE #define LEVEL_MASK _PAGE_LEVEL_MASK // max PTEs number #define MAX_PTEN _PAGE_LEVEL_SIZE // max translation level supported #define MAX_LEVEL _PTW_LEVEL typedef struct __pte pte_t; #define _PTE_PROT_MASK ( ~((1UL << 50) - 1) | (PAGE_MASK & __OA_HIGH_MASK) ) #define _PTE_PPFN_MASK ( ~_PTE_PROT_MASK ) #define _PAGE_BASIC ( _PTE_VALID ) #define KERNEL_EXEC ( _PAGE_BASIC | _PTE_PRO | _PTE_UXN ) #define KERNEL_DATA ( _PAGE_BASIC | _PTE_PRW | _PTE_XN ) #define KERNEL_RDONLY ( _PAGE_BASIC | _PTE_PRO | _PTE_XN ) #define KERNEL_ROEXEC KERNEL_EXEC #define KERNEL_PGTAB ( _PAGE_BASIC | _PTE_TABDESC ) #define USER_EXEC ( _PAGE_BASIC | _PTE_PROURO | _PTE_PXN ) #define USER_DATA ( _PAGE_BASIC | _PTE_PRWURW | _PTE_XN ) #define USER_RDONLY ( _PAGE_BASIC | _PTE_PROURO ) #define USER_ROEXEC USER_EXEC #define USER_PGTAB ( _PAGE_BASIC | _PTE_TABDESC ) #define SELF_MAP ( KERNEL_DATA | _PTE_TABDESC ) #define __mkpte_from(pte_val) ((pte_t){ .val = (pte_val) }) #define null_pte ( __mkpte_from(0) ) #define guard_pte ( __mkpte_from(__MEMGUARD) ) #define pte_val(pte) ( pte.val ) static inline bool pte_isguardian(pte_t pte) { return pte.val == __MEMGUARD; } static inline pte_t mkpte_prot(pte_attr_t prot) { pte_attr_t attrs = (prot & _PTE_PROT_MASK) | _PTE_LFTDESC; return __mkpte_from(attrs); } static inline pte_t mkpte(ptr_t paddr, pte_attr_t prot) { pte_attr_t attrs = (prot & _PTE_PROT_MASK) | _PTE_LFTDESC; return __mkpte_from((paddr & ~_PAGE_BASE_MASK) | attrs); } static inline pte_t mkpte_root(ptr_t paddr, pte_attr_t prot) { pte_attr_t attrs = (prot & _PTE_PROT_MASK) | _PTE_TABDESC; return __mkpte_from((paddr & ~_PAGE_BASE_MASK) | attrs); } static inline pte_t mkpte_raw(unsigned long pte_val) { return __mkpte_from(pte_val); } static inline pte_t pte_setpaddr(pte_t pte, ptr_t paddr) { return __mkpte_from((pte.val & _PTE_PROT_MASK) | (paddr & ~_PTE_PROT_MASK)); } static inline pte_t pte_setppfn(pte_t pte, pfn_t ppfn) { return pte_setpaddr(pte, ppfn * PAGE_SIZE); } static inline ptr_t pte_paddr(pte_t pte) { return __paddr(pte.val) & ~_PTE_PROT_MASK; } static inline pfn_t pte_ppfn(pte_t pte) { return pte_paddr(pte) >> _PAGE_BASE_SHIFT; } static inline pte_t pte_setprot(pte_t pte, ptr_t prot) { return __mkpte_from((pte.val & ~_PTE_PROT_MASK) | (prot & _PTE_PROT_MASK)); } static inline pte_attr_t pte_prot(pte_t pte) { return (pte.val & _PTE_PROT_MASK); } static inline bool pte_isnull(pte_t pte) { return !pte.val; } static inline pte_t pte_mkhuge(pte_t pte) { return __mkpte_from(_PTE_SET_DESC(pte.val, _PTE_BLKDESC)); } static inline pte_t pte_mkvolatile(pte_t pte) { return __mkpte_from(pte.val); } static inline pte_t pte_mkroot(pte_t pte) { return __mkpte_from(_PTE_SET_DESC(pte.val, _PTE_TABDESC)); } static inline bool pte_huge(pte_t pte) { return _PTE_GET_DESC(pte.val) == _PTE_BLKDESC; } static inline pte_t pte_mkloaded(pte_t pte) { return __mkpte_from(pte.val | _PTE_VALID); } static inline pte_t pte_mkunloaded(pte_t pte) { return __mkpte_from(pte.val & ~_PTE_VALID); } static inline bool pte_isloaded(pte_t pte) { return !!(pte.val & _PTE_VALID); } static inline pte_t pte_mkwprotect(pte_t pte) { return __mkpte_from(pte.val | _PTE_PRO); } static inline pte_t pte_mkwritable(pte_t pte) { return __mkpte_from(pte.val & ~_PTE_PRO); } static inline bool pte_iswprotect(pte_t pte) { return !(pte.val & _PTE_PRO); } static inline pte_t pte_mkuser(pte_t pte) { return __mkpte_from(pte.val | _PTE_U); } static inline pte_t pte_mkkernel(pte_t pte) { return __mkpte_from(pte.val & ~_PTE_U); } static inline bool pte_allow_user(pte_t pte) { return !!(pte.val & _PTE_U); } static inline pte_t pte_mkexec(pte_t pte) { return __mkpte_from(pte.val & ~_PTE_PXN); } static inline pte_t pte_mknexec(pte_t pte) { return __mkpte_from(pte.val | _PTE_PXN); } static inline pte_t pte_mkuexec(pte_t pte) { return __mkpte_from(pte.val & ~_PTE_UXN); } static inline pte_t pte_mknuexec(pte_t pte) { return __mkpte_from(pte.val | _PTE_UXN); } static inline bool pte_isexec(pte_t pte) { return !(pte.val & _PTE_PXN); } static inline bool pte_isuexec(pte_t pte) { return !(pte.val & _PTE_UXN); } static inline pte_t pte_mkuntouch(pte_t pte) { return __mkpte_from(pte.val & ~_PTE_AF); } static inline bool pte_istouched(pte_t pte) { return !!(pte.val & _PTE_AF); } static inline pte_t pte_mkclean(pte_t pte) { return __mkpte_from(pte.val & ~_PTE_DBM); } static inline bool pte_dirty(pte_t pte) { return !!(pte.val & _PTE_DBM); } static inline void set_pte(pte_t* ptep, pte_t pte) { ptep->val = pte.val; } static inline pte_t pte_at(pte_t* ptep) { return *ptep; } pte_t translate_vmr_prot(unsigned int vmr_prot, pte_t pte); #endif /* __LUNAIX_ARCH_PAGETABLE_H */