162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2020, Sandipan Das, IBM Corp. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#ifndef _SELFTESTS_POWERPC_PKEYS_H 762306a36Sopenharmony_ci#define _SELFTESTS_POWERPC_PKEYS_H 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <sys/mman.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "reg.h" 1262306a36Sopenharmony_ci#include "utils.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* 1562306a36Sopenharmony_ci * Older versions of libc use the Intel-specific access rights. 1662306a36Sopenharmony_ci * Hence, override the definitions as they might be incorrect. 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci#undef PKEY_DISABLE_ACCESS 1962306a36Sopenharmony_ci#define PKEY_DISABLE_ACCESS 0x3 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#undef PKEY_DISABLE_WRITE 2262306a36Sopenharmony_ci#define PKEY_DISABLE_WRITE 0x2 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#undef PKEY_DISABLE_EXECUTE 2562306a36Sopenharmony_ci#define PKEY_DISABLE_EXECUTE 0x4 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* Older versions of libc do not define this */ 2862306a36Sopenharmony_ci#ifndef SEGV_PKUERR 2962306a36Sopenharmony_ci#define SEGV_PKUERR 4 3062306a36Sopenharmony_ci#endif 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define SI_PKEY_OFFSET 0x20 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define __NR_pkey_mprotect 386 3562306a36Sopenharmony_ci#define __NR_pkey_alloc 384 3662306a36Sopenharmony_ci#define __NR_pkey_free 385 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define PKEY_BITS_PER_PKEY 2 3962306a36Sopenharmony_ci#define NR_PKEYS 32 4062306a36Sopenharmony_ci#define PKEY_BITS_MASK ((1UL << PKEY_BITS_PER_PKEY) - 1) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ciinline unsigned long pkeyreg_get(void) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci return mfspr(SPRN_AMR); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciinline void pkeyreg_set(unsigned long amr) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci set_amr(amr); 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_civoid pkey_set_rights(int pkey, unsigned long rights) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci unsigned long amr, shift; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci shift = (NR_PKEYS - pkey - 1) * PKEY_BITS_PER_PKEY; 5762306a36Sopenharmony_ci amr = pkeyreg_get(); 5862306a36Sopenharmony_ci amr &= ~(PKEY_BITS_MASK << shift); 5962306a36Sopenharmony_ci amr |= (rights & PKEY_BITS_MASK) << shift; 6062306a36Sopenharmony_ci pkeyreg_set(amr); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ciint sys_pkey_mprotect(void *addr, size_t len, int prot, int pkey) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci return syscall(__NR_pkey_mprotect, addr, len, prot, pkey); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ciint sys_pkey_alloc(unsigned long flags, unsigned long rights) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci return syscall(__NR_pkey_alloc, flags, rights); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciint sys_pkey_free(int pkey) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci return syscall(__NR_pkey_free, pkey); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ciint pkeys_unsupported(void) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci bool hash_mmu = false; 8162306a36Sopenharmony_ci int pkey; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* Protection keys are currently supported on Hash MMU only */ 8462306a36Sopenharmony_ci FAIL_IF(using_hash_mmu(&hash_mmu)); 8562306a36Sopenharmony_ci SKIP_IF(!hash_mmu); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* Check if the system call is supported */ 8862306a36Sopenharmony_ci pkey = sys_pkey_alloc(0, 0); 8962306a36Sopenharmony_ci SKIP_IF(pkey < 0); 9062306a36Sopenharmony_ci sys_pkey_free(pkey); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ciint siginfo_pkey(siginfo_t *si) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci /* 9862306a36Sopenharmony_ci * In older versions of libc, siginfo_t does not have si_pkey as 9962306a36Sopenharmony_ci * a member. 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_ci#ifdef si_pkey 10262306a36Sopenharmony_ci return si->si_pkey; 10362306a36Sopenharmony_ci#else 10462306a36Sopenharmony_ci return *((int *)(((char *) si) + SI_PKEY_OFFSET)); 10562306a36Sopenharmony_ci#endif 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci#define pkey_rights(r) ({ \ 10962306a36Sopenharmony_ci static char buf[4] = "rwx"; \ 11062306a36Sopenharmony_ci unsigned int amr_bits; \ 11162306a36Sopenharmony_ci if ((r) & PKEY_DISABLE_EXECUTE) \ 11262306a36Sopenharmony_ci buf[2] = '-'; \ 11362306a36Sopenharmony_ci amr_bits = (r) & PKEY_BITS_MASK; \ 11462306a36Sopenharmony_ci if (amr_bits & PKEY_DISABLE_WRITE) \ 11562306a36Sopenharmony_ci buf[1] = '-'; \ 11662306a36Sopenharmony_ci if (amr_bits & PKEY_DISABLE_ACCESS & ~PKEY_DISABLE_WRITE) \ 11762306a36Sopenharmony_ci buf[0] = '-'; \ 11862306a36Sopenharmony_ci buf; \ 11962306a36Sopenharmony_ci}) 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ciunsigned long next_pkey_rights(unsigned long rights) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci if (rights == PKEY_DISABLE_ACCESS) 12462306a36Sopenharmony_ci return PKEY_DISABLE_EXECUTE; 12562306a36Sopenharmony_ci else if (rights == (PKEY_DISABLE_ACCESS | PKEY_DISABLE_EXECUTE)) 12662306a36Sopenharmony_ci return 0; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if ((rights & PKEY_BITS_MASK) == 0) 12962306a36Sopenharmony_ci rights |= PKEY_DISABLE_WRITE; 13062306a36Sopenharmony_ci else if ((rights & PKEY_BITS_MASK) == PKEY_DISABLE_WRITE) 13162306a36Sopenharmony_ci rights |= PKEY_DISABLE_ACCESS; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci return rights; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci#endif /* _SELFTESTS_POWERPC_PKEYS_H */ 137