linux-headers/arch/e2k/include/asm/pgtable-v6.h

323 lines
9.9 KiB
C

/*
* E2K ISET V6 page table structure and common definitions.
*
* Copyright 2017 Salavat S. Guiliazov (atic@mcst.ru)
*/
#ifndef _ASM_E2K_PGTABLE_V6_H
#define _ASM_E2K_PGTABLE_V6_H
/*
* This file contains the functions and defines necessary to modify and
* use the E2K ISET V6 page tables.
* NOTE: E2K has four levels of page tables.
*/
#include <linux/types.h>
#include <asm/pgtable_types.h>
#ifndef __ASSEMBLY__
/*
* PTE-V6 format
*/
/* numbers of PTE's bits */
#define _PAGE_P_BIT_V6 0 /* Present */
#define _PAGE_W_BIT_V6 1 /* Writable */
#define _PAGE_PV_BIT_V6 2 /* PriVileged */
#define _PAGE_VALID_BIT_V6 3 /* Valid */
#define _PAGE_INT_PR_BIT_V6 4 /* PRotected */
#define _PAGE_A_BIT_V6 5 /* page Accessed */
#define _PAGE_D_BIT_V6 6 /* page Dirty */
#define _PAGE_HUGE_BIT_V6 7 /* huge Page Size */
#define _PAGE_G_BIT_V6 8 /* Global page */
#define _PAGE_NWA_BIT_V6 9 /* No Writable Address */
#define _PAGE_SW1_BIT_V6 10 /* SoftWare bit #1 */
#define _PAGE_SW2_BIT_V6 11 /* SoftWare bit #2 */
#define _PAGE_PFN_SHIFT_V6 12 /* shift of Physical Page Number */
#define _PAGE_MT_SHIFT_V6 60 /* shift of Memory Type field */
#define _PAGE_MT_BITS_NUM_V6 3 /* occupies 3 bits */
#define _PAGE_NON_EX_BIT_V6 63 /* NON EXecutable */
#define _PAGE_P_V6 (1ULL << _PAGE_P_BIT_V6)
#define _PAGE_W_V6 (1ULL << _PAGE_W_BIT_V6)
#define _PAGE_PV_V6 (1ULL << _PAGE_PV_BIT_V6)
#define _PAGE_VALID_V6 (1ULL << _PAGE_VALID_BIT_V6)
#define _PAGE_INT_PR_V6 (1ULL << _PAGE_INT_PR_BIT_V6)
#define _PAGE_A_V6 (1ULL << _PAGE_A_BIT_V6)
#define _PAGE_D_V6 (1ULL << _PAGE_D_BIT_V6)
#define _PAGE_HUGE_V6 (1ULL << _PAGE_HUGE_BIT_V6)
#define _PAGE_G_V6 (1ULL << _PAGE_G_BIT_V6)
#define _PAGE_NWA_V6 (1ULL << _PAGE_NWA_BIT_V6)
#define _PAGE_SW1_V6 (1ULL << _PAGE_SW1_BIT_V6)
#define _PAGE_SW2_V6 (1ULL << _PAGE_SW2_BIT_V6)
#define _PAGE_MMIO_SW_V6 0x0c00000000000000ULL /* pte is MMIO */
/* software flag */
#define _PAGE_PFN_V6 \
((((1ULL << E2K_MAX_PHYS_BITS_V6) - 1) >> \
PAGE_SHIFT) << \
_PAGE_PFN_SHIFT_V6)
#define _PAGE_MT_V6 \
(((1ULL << _PAGE_MT_BITS_NUM_V6) - 1) << _PAGE_MT_SHIFT_V6)
#define _PAGE_NON_EX_V6 (1ULL << _PAGE_NON_EX_BIT_V6)
/*
* The _PAGE_PROTNONE bit is set only when the _PAGE_PRESENT bit
* is cleared, so we can use almost any bits for it. Must make
* sure though that pte_modify() will work with _PAGE_PROTNONE.
*/
#define _PAGE_PROTNONE_V6 _PAGE_NWA_V6
#define _PAGE_SOFTWARE_MT _PAGE_SW1_V6
#define _PAGE_AVAIL_V6 _PAGE_SW2_V6
#define _PAGE_SPECIAL_V6 _PAGE_SW2_V6
#define _PAGE_GFN_V6 _PAGE_SW2_V6 /* Page is mapped to guest */
/* physical memory */
#define _PAGE_MT_GET_VAL(x) (((x) & _PAGE_MT_V6) >> _PAGE_MT_SHIFT_V6)
#define _PAGE_MT_SET_VAL(x, mt) \
(((x) & ~_PAGE_MT_V6) | \
(((pteval_t)(mt) << _PAGE_MT_SHIFT_V6) & _PAGE_MT_V6))
/* some useful PT entries protection basis values */
#define _PAGE_KERNEL_RX_NOT_GLOB_V6 \
(_PAGE_P_V6 | _PAGE_VALID_V6 | \
_PAGE_PV_V6 | _PAGE_A_V6)
#define _PAGE_KERNEL_RO_NOT_GLOB_V6 \
(_PAGE_KERNEL_RX_NOT_GLOB_V6 | _PAGE_NON_EX_V6)
#define _PAGE_KERNEL_RWX_NOT_GLOB_V6 \
(_PAGE_KERNEL_RX_NOT_GLOB_V6 | \
_PAGE_W_V6 | _PAGE_D_V6)
#define _PAGE_KERNEL_RW_NOT_GLOB_V6 \
(_PAGE_KERNEL_RWX_NOT_GLOB_V6 | _PAGE_NON_EX_V6)
#define _PAGE_KERNEL_HUGE_RW_NOT_GLOB_V6 \
(_PAGE_KERNEL_RW_NOT_GLOB_V6 | _PAGE_HUGE_V6)
#define _PAGE_KERNEL_RX_GLOB_V6 \
(_PAGE_KERNEL_RX_NOT_GLOB_V6 | _PAGE_G_V6)
#define _PAGE_KERNEL_RO_GLOB_V6 \
(_PAGE_KERNEL_RO_NOT_GLOB_V6 | _PAGE_G_V6)
#define _PAGE_KERNEL_RWX_GLOB_V6 \
(_PAGE_KERNEL_RWX_NOT_GLOB_V6 | _PAGE_G_V6)
#define _PAGE_KERNEL_RW_GLOB_V6 \
(_PAGE_KERNEL_RW_NOT_GLOB_V6 | _PAGE_G_V6)
#define _PAGE_KERNEL_HUGE_RW_GLOB_V6 \
(_PAGE_KERNEL_HUGE_RW_NOT_GLOB_V6 | _PAGE_G_V6)
#ifdef CONFIG_GLOBAL_CONTEXT
#define _PAGE_KERNEL_RX_V6 _PAGE_KERNEL_RX_GLOB_V6
#define _PAGE_KERNEL_RO_V6 _PAGE_KERNEL_RO_GLOB_V6
#define _PAGE_KERNEL_RWX_V6 _PAGE_KERNEL_RWX_GLOB_V6
#define _PAGE_KERNEL_RW_V6 _PAGE_KERNEL_RW_GLOB_V6
#define _PAGE_KERNEL_HUGE_RW_V6 _PAGE_KERNEL_HUGE_RW_GLOB_V6
#else /* ! CONFIG_GLOBAL_CONTEXT */
#define _PAGE_KERNEL_RX_V6 _PAGE_KERNEL_RX_NOT_GLOB_V6
#define _PAGE_KERNEL_RO_V6 _PAGE_KERNEL_RO_NOT_GLOB_V6
#define _PAGE_KERNEL_RWX_V6 _PAGE_KERNEL_RWX_NOT_GLOB_V6
#define _PAGE_KERNEL_RW_V6 _PAGE_KERNEL_RW_NOT_GLOB_V6
#define _PAGE_KERNEL_HUGE_RW_V6 _PAGE_KERNEL_HUGE_RW_NOT_GLOB_V6
#endif /* CONFIG_GLOBAL_CONTEXT */
#define _PAGE_KERNEL_V6 _PAGE_KERNEL_RW_V6
#define _PAGE_KERNEL_HUGE_V6 _PAGE_KERNEL_HUGE_RW_V6
#define _PAGE_KERNEL_IMAGE_V6 _PAGE_KERNEL_RX_V6
#define _PAGE_KERNEL_MODULE_V6 _PAGE_KERNEL_RWX_V6
#define _PAGE_KERNEL_PT_V6 _PAGE_KERNEL_V6
#define _PAGE_USER_PT_V6 _PAGE_KERNEL_RW_NOT_GLOB_V6
/* convert physical address to page frame number for PTE */
#define _PAGE_PADDR_TO_PFN_V6(phys_addr) \
(((e2k_addr_t)phys_addr) & _PAGE_PFN_V6)
/* convert the page frame number from PTE to physical address */
#define _PAGE_PFN_TO_PADDR_V6(pte_val) \
((e2k_addr_t)(pte_val) & _PAGE_PFN_V6)
/* get/set pte Compilation Unit Index field */
/* PTE V6 has not more field CUI, so fix error */
#define _PAGE_INDEX_TO_CUNIT_V6(index) BUILD_BUG_ON(true)
#define _PAGE_INDEX_FROM_CUNIT_V6(prot) BUILD_BUG_ON(true)
#define SET_PAGE_CUI_V6(pte_val, cui) BUILD_BUG_ON(true)
/* PTE flags mask to can update/reduce and restricted to update */
#define _PAGE_CHG_MASK_V6 (_PAGE_PFN_V6 | _PAGE_A_V6 | _PAGE_D_V6 | \
_PAGE_SW1_V6 | _PAGE_SW2_V6 | \
_PAGE_MT_V6)
#define _HPAGE_CHG_MASK_V6 (_PAGE_CHG_MASK_V6 | _PAGE_HUGE_V6)
#define _PROT_REDUCE_MASK_V6 (_PAGE_P_V6 | _PAGE_W_V6 | _PAGE_A_V6 | \
_PAGE_D_V6 | _PAGE_VALID_V6 | _PAGE_G_V6 | \
_PAGE_MT_V6)
#define _PROT_RESTRICT_MASK_V6 (_PAGE_PV_V6 | _PAGE_NON_EX_V6 | \
_PAGE_INT_PR_V6)
static inline pteval_t
get_pte_val_v6_changeable_mask(void)
{
return _PAGE_CHG_MASK_V6;
}
static inline pteval_t
get_huge_pte_val_v6_changeable_mask(void)
{
return _HPAGE_CHG_MASK_V6;
}
static inline pteval_t
get_pte_val_v6_reduceable_mask(void)
{
return _PROT_REDUCE_MASK_V6;
}
static inline pteval_t
get_pte_val_v6_restricted_mask(void)
{
return _PROT_RESTRICT_MASK_V6;
}
static inline pteval_t
covert_uni_pte_flags_to_pte_val_v6(const uni_pteval_t uni_flags)
{
pteval_t pte_flags = 0;
if (uni_flags & UNI_PAGE_PRESENT)
pte_flags |= (_PAGE_P_V6);
if (uni_flags & UNI_PAGE_WRITE)
pte_flags |= (_PAGE_W_V6);
if (uni_flags & UNI_PAGE_PRIV)
pte_flags |= (_PAGE_PV_V6);
if (uni_flags & UNI_PAGE_VALID)
pte_flags |= (_PAGE_VALID_V6);
if (uni_flags & UNI_PAGE_PROTECT)
pte_flags |= (_PAGE_INT_PR_V6);
if (uni_flags & UNI_PAGE_ACCESSED)
pte_flags |= (_PAGE_A_V6);
if (uni_flags & UNI_PAGE_DIRTY)
pte_flags |= (_PAGE_D_V6);
if (uni_flags & UNI_PAGE_HUGE)
pte_flags |= (_PAGE_HUGE_V6);
if (uni_flags & UNI_PAGE_GLOBAL)
pte_flags |= (_PAGE_G_V6);
if (uni_flags & UNI_PAGE_NWA)
pte_flags |= (_PAGE_NWA_V6);
if (uni_flags & UNI_PAGE_NON_EX)
pte_flags |= (_PAGE_NON_EX_V6);
if (uni_flags & UNI_PAGE_PROTNONE)
pte_flags |= (_PAGE_PROTNONE_V6);
if (uni_flags & UNI_PAGE_AVAIL)
pte_flags |= (_PAGE_SW2_V6);
if (uni_flags & UNI_PAGE_SPECIAL)
pte_flags |= (_PAGE_SPECIAL_V6);
if (uni_flags & UNI_PAGE_GFN)
pte_flags |= (_PAGE_GFN_V6);
if (uni_flags & UNI_PAGE_PFN)
pte_flags |= (_PAGE_PFN_V6);
if (uni_flags & UNI_PAGE_MEM_TYPE)
pte_flags |= (_PAGE_MT_V6);
BUG_ON(pte_flags == 0);
return pte_flags;
}
static inline pteval_t
fill_pte_val_v6_flags(const uni_pteval_t uni_flags)
{
return covert_uni_pte_flags_to_pte_val_v6(uni_flags);
}
static inline pteval_t
get_pte_val_v6_flags(pteval_t pte_val, const uni_pteval_t uni_flags)
{
return pte_val & covert_uni_pte_flags_to_pte_val_v6(uni_flags);
}
static inline bool
test_pte_val_v6_flags(pteval_t pte_val, const uni_pteval_t uni_flags)
{
return get_pte_val_v6_flags(pte_val, uni_flags) != 0;
}
static inline pteval_t
set_pte_val_v6_flags(pteval_t pte_val, const uni_pteval_t uni_flags)
{
return pte_val | covert_uni_pte_flags_to_pte_val_v6(uni_flags);
}
static inline pteval_t
clear_pte_val_v6_flags(pteval_t pte_val, const uni_pteval_t uni_flags)
{
return pte_val & ~covert_uni_pte_flags_to_pte_val_v6(uni_flags);
}
static inline pteval_t
convert_kernel_text_pte_val_v6_to_protected(pteval_t kernel_text_pte_val)
{
return kernel_text_pte_val;
}
static inline pte_mem_type_t get_pte_val_v6_memory_type(pteval_t pte_val)
{
int hardware_mt = _PAGE_MT_GET_VAL(pte_val);
if (!(pte_val & _PAGE_SOFTWARE_MT))
return hardware_mt;
if (hardware_mt == GEN_CACHE_MT) {
return EXT_CACHE_MT;
} else if (hardware_mt == GEN_NON_CACHE_MT) {
return GEN_NON_CACHE_ORDERED_MT;
} else {
WARN_ON_ONCE(1);
return EXT_CACHE_MT;
}
}
static inline pteval_t
set_pte_val_v6_memory_type(pteval_t pte_val, pte_mem_type_t memory_type)
{
BUG_ON(memory_type != GEN_CACHE_MT &&
memory_type != GEN_NON_CACHE_MT &&
memory_type != GEN_NON_CACHE_ORDERED_MT &&
memory_type != EXT_PREFETCH_MT &&
memory_type != EXT_NON_PREFETCH_MT &&
memory_type != EXT_CONFIG_MT &&
memory_type != EXT_CACHE_MT);
if (memory_type == EXT_CACHE_MT) {
pte_val |= _PAGE_SOFTWARE_MT;
memory_type = GEN_CACHE_MT;
} else if (memory_type == GEN_NON_CACHE_ORDERED_MT) {
pte_val |= _PAGE_SOFTWARE_MT;
memory_type = GEN_NON_CACHE_MT;
} else {
pte_val &= ~_PAGE_SOFTWARE_MT;
}
return _PAGE_MT_SET_VAL(pte_val, memory_type);
}
/*
* Encode and de-code a swap entry
*
* Format of swap offset:
* bits 20-63: swap offset
*/
static inline unsigned long
get_swap_offset_v6(swp_entry_t swap_entry)
{
return swap_entry.val >> __SWP_OFFSET_SHIFT;
}
static inline swp_entry_t
create_swap_entry_v6(unsigned long type, unsigned long offset)
{
swp_entry_t swap_entry;
swap_entry.val = type << __SWP_TYPE_SHIFT;
swap_entry.val |= (offset << __SWP_OFFSET_SHIFT);
return swap_entry;
}
static inline pte_t
convert_swap_entry_to_pte_v6(swp_entry_t swap_entry)
{
pte_t pte;
pte_val(pte) = swap_entry.val;
#ifdef CONFIG_MAKE_ALL_PAGES_VALID
pte_val(pte) |= _PAGE_VALID_V6;
#endif /* CONFIG_MAKE_ALL_PAGES_VALID */
return pte;
}
#endif /* ! __ASSEMBLY__ */
#endif /* ! _ASM_E2K_PGTABLE_V6_H */