162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef _ASM_POWERPC_BOOK3S_32_MMU_HASH_H_ 362306a36Sopenharmony_ci#define _ASM_POWERPC_BOOK3S_32_MMU_HASH_H_ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci/* 662306a36Sopenharmony_ci * 32-bit hash table MMU support 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/* 1062306a36Sopenharmony_ci * BATs 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* Block size masks */ 1462306a36Sopenharmony_ci#define BL_128K 0x000 1562306a36Sopenharmony_ci#define BL_256K 0x001 1662306a36Sopenharmony_ci#define BL_512K 0x003 1762306a36Sopenharmony_ci#define BL_1M 0x007 1862306a36Sopenharmony_ci#define BL_2M 0x00F 1962306a36Sopenharmony_ci#define BL_4M 0x01F 2062306a36Sopenharmony_ci#define BL_8M 0x03F 2162306a36Sopenharmony_ci#define BL_16M 0x07F 2262306a36Sopenharmony_ci#define BL_32M 0x0FF 2362306a36Sopenharmony_ci#define BL_64M 0x1FF 2462306a36Sopenharmony_ci#define BL_128M 0x3FF 2562306a36Sopenharmony_ci#define BL_256M 0x7FF 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* BAT Access Protection */ 2862306a36Sopenharmony_ci#define BPP_XX 0x00 /* No access */ 2962306a36Sopenharmony_ci#define BPP_RX 0x01 /* Read only */ 3062306a36Sopenharmony_ci#define BPP_RW 0x02 /* Read/write */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 3362306a36Sopenharmony_ci/* Contort a phys_addr_t into the right format/bits for a BAT */ 3462306a36Sopenharmony_ci#ifdef CONFIG_PHYS_64BIT 3562306a36Sopenharmony_ci#define BAT_PHYS_ADDR(x) ((u32)((x & 0x00000000fffe0000ULL) | \ 3662306a36Sopenharmony_ci ((x & 0x0000000e00000000ULL) >> 24) | \ 3762306a36Sopenharmony_ci ((x & 0x0000000100000000ULL) >> 30))) 3862306a36Sopenharmony_ci#define PHYS_BAT_ADDR(x) (((u64)(x) & 0x00000000fffe0000ULL) | \ 3962306a36Sopenharmony_ci (((u64)(x) << 24) & 0x0000000e00000000ULL) | \ 4062306a36Sopenharmony_ci (((u64)(x) << 30) & 0x0000000100000000ULL)) 4162306a36Sopenharmony_ci#else 4262306a36Sopenharmony_ci#define BAT_PHYS_ADDR(x) (x) 4362306a36Sopenharmony_ci#define PHYS_BAT_ADDR(x) ((x) & 0xfffe0000) 4462306a36Sopenharmony_ci#endif 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistruct ppc_bat { 4762306a36Sopenharmony_ci u32 batu; 4862306a36Sopenharmony_ci u32 batl; 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci#endif /* !__ASSEMBLY__ */ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci * Hash table 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* Values for PP (assumes Ks=0, Kp=1) */ 5762306a36Sopenharmony_ci#define PP_RWXX 0 /* Supervisor read/write, User none */ 5862306a36Sopenharmony_ci#define PP_RWRX 1 /* Supervisor read/write, User read */ 5962306a36Sopenharmony_ci#define PP_RWRW 2 /* Supervisor read/write, User read/write */ 6062306a36Sopenharmony_ci#define PP_RXRX 3 /* Supervisor read, User read */ 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* Values for Segment Registers */ 6362306a36Sopenharmony_ci#define SR_NX 0x10000000 /* No Execute */ 6462306a36Sopenharmony_ci#define SR_KP 0x20000000 /* User key */ 6562306a36Sopenharmony_ci#define SR_KS 0x40000000 /* Supervisor key */ 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#ifdef __ASSEMBLY__ 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#include <asm/asm-offsets.h> 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci.macro uus_addi sr reg1 reg2 imm 7262306a36Sopenharmony_ci .if NUM_USER_SEGMENTS > \sr 7362306a36Sopenharmony_ci addi \reg1,\reg2,\imm 7462306a36Sopenharmony_ci .endif 7562306a36Sopenharmony_ci.endm 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci.macro uus_mtsr sr reg1 7862306a36Sopenharmony_ci .if NUM_USER_SEGMENTS > \sr 7962306a36Sopenharmony_ci mtsr \sr, \reg1 8062306a36Sopenharmony_ci .endif 8162306a36Sopenharmony_ci.endm 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* 8462306a36Sopenharmony_ci * This isync() shouldn't be necessary as the kernel is not excepted to run 8562306a36Sopenharmony_ci * any instruction in userspace soon after the update of segments and 'rfi' 8662306a36Sopenharmony_ci * instruction is used to return to userspace, but hash based cores 8762306a36Sopenharmony_ci * (at least G3) seem to exhibit a random behaviour when the 'isync' is not 8862306a36Sopenharmony_ci * there. 603 cores don't have this behaviour so don't do the 'isync' as it 8962306a36Sopenharmony_ci * saves several CPU cycles. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_ci.macro uus_isync 9262306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_604 9362306a36Sopenharmony_ciBEGIN_MMU_FTR_SECTION 9462306a36Sopenharmony_ci isync 9562306a36Sopenharmony_ciEND_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE) 9662306a36Sopenharmony_ci#endif 9762306a36Sopenharmony_ci.endm 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci.macro update_user_segments_by_4 tmp1 tmp2 tmp3 tmp4 10062306a36Sopenharmony_ci uus_addi 1, \tmp2, \tmp1, 0x111 10162306a36Sopenharmony_ci uus_addi 2, \tmp3, \tmp1, 0x222 10262306a36Sopenharmony_ci uus_addi 3, \tmp4, \tmp1, 0x333 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci uus_mtsr 0, \tmp1 10562306a36Sopenharmony_ci uus_mtsr 1, \tmp2 10662306a36Sopenharmony_ci uus_mtsr 2, \tmp3 10762306a36Sopenharmony_ci uus_mtsr 3, \tmp4 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci uus_addi 4, \tmp1, \tmp1, 0x444 11062306a36Sopenharmony_ci uus_addi 5, \tmp2, \tmp2, 0x444 11162306a36Sopenharmony_ci uus_addi 6, \tmp3, \tmp3, 0x444 11262306a36Sopenharmony_ci uus_addi 7, \tmp4, \tmp4, 0x444 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci uus_mtsr 4, \tmp1 11562306a36Sopenharmony_ci uus_mtsr 5, \tmp2 11662306a36Sopenharmony_ci uus_mtsr 6, \tmp3 11762306a36Sopenharmony_ci uus_mtsr 7, \tmp4 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci uus_addi 8, \tmp1, \tmp1, 0x444 12062306a36Sopenharmony_ci uus_addi 9, \tmp2, \tmp2, 0x444 12162306a36Sopenharmony_ci uus_addi 10, \tmp3, \tmp3, 0x444 12262306a36Sopenharmony_ci uus_addi 11, \tmp4, \tmp4, 0x444 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci uus_mtsr 8, \tmp1 12562306a36Sopenharmony_ci uus_mtsr 9, \tmp2 12662306a36Sopenharmony_ci uus_mtsr 10, \tmp3 12762306a36Sopenharmony_ci uus_mtsr 11, \tmp4 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci uus_addi 12, \tmp1, \tmp1, 0x444 13062306a36Sopenharmony_ci uus_addi 13, \tmp2, \tmp2, 0x444 13162306a36Sopenharmony_ci uus_addi 14, \tmp3, \tmp3, 0x444 13262306a36Sopenharmony_ci uus_addi 15, \tmp4, \tmp4, 0x444 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci uus_mtsr 12, \tmp1 13562306a36Sopenharmony_ci uus_mtsr 13, \tmp2 13662306a36Sopenharmony_ci uus_mtsr 14, \tmp3 13762306a36Sopenharmony_ci uus_mtsr 15, \tmp4 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci uus_isync 14062306a36Sopenharmony_ci.endm 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci#else 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* 14562306a36Sopenharmony_ci * This macro defines the mapping from contexts to VSIDs (virtual 14662306a36Sopenharmony_ci * segment IDs). We use a skew on both the context and the high 4 bits 14762306a36Sopenharmony_ci * of the 32-bit virtual address (the "effective segment ID") in order 14862306a36Sopenharmony_ci * to spread out the entries in the MMU hash table. Note, if this 14962306a36Sopenharmony_ci * function is changed then hash functions will have to be 15062306a36Sopenharmony_ci * changed to correspond. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_ci#define CTX_TO_VSID(c, id) ((((c) * (897 * 16)) + (id * 0x111)) & 0xffffff) 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* 15562306a36Sopenharmony_ci * Hardware Page Table Entry 15662306a36Sopenharmony_ci * Note that the xpn and x bitfields are used only by processors that 15762306a36Sopenharmony_ci * support extended addressing; otherwise, those bits are reserved. 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_cistruct hash_pte { 16062306a36Sopenharmony_ci unsigned long v:1; /* Entry is valid */ 16162306a36Sopenharmony_ci unsigned long vsid:24; /* Virtual segment identifier */ 16262306a36Sopenharmony_ci unsigned long h:1; /* Hash algorithm indicator */ 16362306a36Sopenharmony_ci unsigned long api:6; /* Abbreviated page index */ 16462306a36Sopenharmony_ci unsigned long rpn:20; /* Real (physical) page number */ 16562306a36Sopenharmony_ci unsigned long xpn:3; /* Real page number bits 0-2, optional */ 16662306a36Sopenharmony_ci unsigned long r:1; /* Referenced */ 16762306a36Sopenharmony_ci unsigned long c:1; /* Changed */ 16862306a36Sopenharmony_ci unsigned long w:1; /* Write-thru cache mode */ 16962306a36Sopenharmony_ci unsigned long i:1; /* Cache inhibited */ 17062306a36Sopenharmony_ci unsigned long m:1; /* Memory coherence */ 17162306a36Sopenharmony_ci unsigned long g:1; /* Guarded */ 17262306a36Sopenharmony_ci unsigned long x:1; /* Real page number bit 3, optional */ 17362306a36Sopenharmony_ci unsigned long pp:2; /* Page protection */ 17462306a36Sopenharmony_ci}; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_citypedef struct { 17762306a36Sopenharmony_ci unsigned long id; 17862306a36Sopenharmony_ci unsigned long sr0; 17962306a36Sopenharmony_ci void __user *vdso; 18062306a36Sopenharmony_ci} mm_context_t; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci#ifdef CONFIG_PPC_KUEP 18362306a36Sopenharmony_ci#define INIT_MM_CONTEXT(mm) .context.sr0 = SR_NX 18462306a36Sopenharmony_ci#endif 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_civoid update_bats(void); 18762306a36Sopenharmony_cistatic inline void cleanup_cpu_mmu_context(void) { } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/* patch sites */ 19062306a36Sopenharmony_ciextern s32 patch__hash_page_A0, patch__hash_page_A1, patch__hash_page_A2; 19162306a36Sopenharmony_ciextern s32 patch__hash_page_B, patch__hash_page_C; 19262306a36Sopenharmony_ciextern s32 patch__flush_hash_A0, patch__flush_hash_A1, patch__flush_hash_A2; 19362306a36Sopenharmony_ciextern s32 patch__flush_hash_B; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci#include <asm/reg.h> 19662306a36Sopenharmony_ci#include <asm/task_size_32.h> 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic __always_inline void update_user_segment(u32 n, u32 val) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci if (n << 28 < TASK_SIZE) 20162306a36Sopenharmony_ci mtsr(val + n * 0x111, n << 28); 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic __always_inline void update_user_segments(u32 val) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci val &= 0xf0ffffff; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci update_user_segment(0, val); 20962306a36Sopenharmony_ci update_user_segment(1, val); 21062306a36Sopenharmony_ci update_user_segment(2, val); 21162306a36Sopenharmony_ci update_user_segment(3, val); 21262306a36Sopenharmony_ci update_user_segment(4, val); 21362306a36Sopenharmony_ci update_user_segment(5, val); 21462306a36Sopenharmony_ci update_user_segment(6, val); 21562306a36Sopenharmony_ci update_user_segment(7, val); 21662306a36Sopenharmony_ci update_user_segment(8, val); 21762306a36Sopenharmony_ci update_user_segment(9, val); 21862306a36Sopenharmony_ci update_user_segment(10, val); 21962306a36Sopenharmony_ci update_user_segment(11, val); 22062306a36Sopenharmony_ci update_user_segment(12, val); 22162306a36Sopenharmony_ci update_user_segment(13, val); 22262306a36Sopenharmony_ci update_user_segment(14, val); 22362306a36Sopenharmony_ci update_user_segment(15, val); 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ciint __init find_free_bat(void); 22762306a36Sopenharmony_ciunsigned int bat_block_size(unsigned long base, unsigned long top); 22862306a36Sopenharmony_ci#endif /* !__ASSEMBLY__ */ 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci/* We happily ignore the smaller BATs on 601, we don't actually use 23162306a36Sopenharmony_ci * those definitions on hash32 at the moment anyway 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci#define mmu_virtual_psize MMU_PAGE_4K 23462306a36Sopenharmony_ci#define mmu_linear_psize MMU_PAGE_256M 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci#endif /* _ASM_POWERPC_BOOK3S_32_MMU_HASH_H_ */ 237