Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1688056 > unrolled thread
| Started by | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| First post | 2017-07-16 06:00 +0200 |
| Last post | 2017-07-16 06:20 +0200 |
| Articles | 20 on this page of 56 — 1 participant |
Back to article view | Back to linux.kernel
[RFC v6 00/62] powerpc: Memory Protection Keys Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:00 +0200
[RFC v6 11/62] powerpc: initial pkey plumbing Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:00 +0200
[RFC v6 31/62] powerpc: Handle exceptions caused by pkey violation Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:00 +0200
[RFC v6 15/62] powerpc: helper functions to initialize AMR, IAMR and UMOR registers Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:00 +0200
[RFC v6 06/62] powerpc: use helper functions in __hash_page_64K() for 64K PTE Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:00 +0200
[RFC v6 33/62] powerpc: introduce get_pte_pkey() helper Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:00 +0200
[RFC v6 26/62] powerpc: Program HPTE key protection bits Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:00 +0200
[RFC v6 49/62] selftest/vm: fix alloc_random_pkey() to make it really random Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 45/62] selftest/vm: generics function to handle shadow key register Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 53/62] selftest/vm: powerpc implementation for generic abstraction Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 51/62] selftest/vm: pkey register should match shadow pkey Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 38/62] powerpc: implementation for arch_pkeys_enabled() Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 37/62] x86: implementation for arch_pkeys_enabled() Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 46/62] selftest/vm: fix the wrong assert in pkey_disable_set() Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 62/62] Documentation/vm: PowerPC specific updates to memory protection keys Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 22/62] powerpc: ability to associate pkey to a vma Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 27/62] powerpc: helper to validate key-access permissions of a pte Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 30/62] powerpc: implementation for arch_vma_access_permitted() Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 44/62] selftest/vm: typecast the pkey register Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 24/62] powerpc: map vma key-protection bits to pte key bits. Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 55/62] selftest/vm: associate key on a mapped page and detect access violation Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 58/62] selftest/vm: detect no write key-violation on a freed key Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 61/62] Documentation/x86: Move protecton key documentation to arch neutral directory Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 52/62] selftest/vm: generic cleanup Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 54/62] selftest/vm: fix an assertion in test_pkey_alloc_exhaust() Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 60/62] selftest/vm: sub-page allocator Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 32/62] powerpc: capture AMR register content on pkey violation Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 34/62] powerpc: capture the violated protection key on fault Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 50/62] selftest/vm: introduce two arch independent abstraction Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 25/62] powerpc: sys_pkey_mprotect() system call Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 59/62] selftest/vm: detect write violation on a mapped access-denied-key page Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 57/62] selftest/vm: associate key on a mapped page and detect write violation Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 36/62] mm: introduce arch_pkeys_enabled() Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 40/62] x86: delete arch_show_smap() Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 29/62] powerpc: Macro the mask used for checking DSI exception Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 47/62] selftest/vm: fixed bugs in pkey_disable_clear() Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 28/62] powerpc: check key protection for user page access Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 48/62] selftest/vm: clear the bits in shadow reg when a pkey is freed. Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 56/62] selftest/vm: detect no key violation on a freed key Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 39/62] mm: display pkey in smaps if arch_pkeys_enabled() is true Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 42/62] selftest/vm: rename all references to pkru to a generic name Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:10 +0200
[RFC v6 07/62] powerpc: use helper functions in __hash_page_huge() for 64K PTE Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:20 +0200
[RFC v6 12/62] mm: introduce an additional vma bit for powerpc pkey Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:20 +0200
[RFC v6 13/62] powerpc: track allocation status of all pkeys Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:20 +0200
[RFC v6 09/62] powerpc: use helper functions in __hash_page_4K() for 4K PTE Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:20 +0200
[RFC v6 01/62] powerpc: Free up four 64K PTE bits in 4K backed HPTE pages Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:20 +0200
[RFC v6 08/62] powerpc: use helper functions in __hash_page_4K() for 64K PTE Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:20 +0200
[RFC v6 05/62] powerpc: capture the PTE format changes in the dump pte report Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:20 +0200
[RFC v6 02/62] powerpc: Free up four 64K PTE bits in 64K backed HPTE pages Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:20 +0200
[RFC v6 14/62] powerpc: helper function to read,write AMR,IAMR,UAMOR registers Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:20 +0200
[RFC v6 18/62] powerpc: sys_pkey_alloc() and sys_pkey_free() system calls Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:20 +0200
[RFC v6 03/62] powerpc: introduce pte_set_hash_slot() helper Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:20 +0200
[RFC v6 21/62] powerpc: introduce execute-only pkey Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:20 +0200
[RFC v6 10/62] powerpc: use helper functions in flush_hash_page() Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:20 +0200
[RFC v6 16/62] powerpc: cleaup AMR,iAMR when a key is allocated or freed Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:20 +0200
[RFC v6 20/62] powerpc: store and restore the pkey state across context switches Ram Pai <linuxram@us.ibm.com> - 2017-07-16 06:20 +0200
Page 1 of 3 [1] 2 3 Next page →
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:00 +0200 |
| Subject | [RFC v6 00/62] powerpc: Memory Protection Keys |
| Message-ID | <u3ISR-1St-3@gated-at.bofh.it> |
Memory protection keys enable applications to protect its
address space from inadvertent access or corruption from
itself.
The overall idea:
-----------------
A process allocates a key and associates it with
an address range within its address space.
The process then can dynamically set read/write
permissions on the key without involving the
kernel. Any code that violates the permissions
of the address space; as defined by its associated
key, will receive a segmentation fault.
This patch series enables the feature on PPC64 HPTE
platform.
ISA3.0 section 5.7.13 describes the detailed
specifications.
Highlevel view of the design:
---------------------------
When an application associates a key with a address
address range, program the key in the Linux PTE.
When the MMU detects a page fault, allocate a hash
page and program the key into HPTE. And finally
when the MMU detects a key violation; due to
invalid application access, invoke the registered
signal handler and provide the violated key number
as well as the state of the key register (AMR), at
the time it faulted.
Testing:
-------
This patch series has passed all the protection key
tests available in the selftests directory.The
tests are updated to work on both x86 and powerpc.
Outstanding issues:
-------------------
How will the application know if pkey is enabled, if
so how many pkeys are available? Is
PKEY_DISABLE_EXECUTE supported? - Ben.
History:
-------
version v6:
(1) selftest changes are broken down into 20
incremental patches.
(2) A separate key allocation mask that
includes PKEY_DISABLE_EXECUTE is
added for powerpc
(3) pkey feature is enabled for 64K HPT case
only. RPT and 4k HPT is disabled.
(4) Documentation is updated to better
capture the semantics.
(5) introduced arch_pkeys_enabled() to find
if an arch enables pkeys. Correspond-
ing change the logic that displays
key value in smaps.
(6) code rearranged in many places based on
comments from Dave Hansen, Balbir,
Anshuman.
(7) fixed one bug where a bogus key could be
associated successfully in
pkey_mprotect().
version v5:
(1) reverted back to the old design -- store
the key in the pte, instead of bypassing
it. The v4 design slowed down the hash
page path.
(2) detects key violation when kernel is told
to access user pages.
(3) further refined the patches into smaller
consumable units
(4) page faults handlers captures the fault-
ing key
from the pte instead of the vma. This
closes a race between where the key
update in the vma and a key fault caused
by the key programmed in the pte.
(5) a key created with access-denied should
also set it up to deny write. Fixed it.
(6) protection-key number is displayed in
smaps the x86 way.
version v4:
(1) patches no more depend on the pte bits
to program the hpte
-- comment by Balbir
(2) documentation updates
(3) fixed a bug in the selftest.
(4) unlike x86, powerpc lets signal handler
change key permission bits; the
change will persist across signal
handler boundaries. Earlier we
allowed the signal handler to
modify a field in the siginfo
structure which would than be used
by the kernel to program the key
protection register (AMR)
-- resolves a issue raised by Ben.
"Calls to sys_swapcontext with a
made-up context will end up with a
crap AMR if done by code who didn't
know about that register".
(5) these changes enable protection keys on
4k-page kernel aswell.
version v3:
(1) split the patches into smaller consumable
patches.
(2) added the ability to disable execute
permission on a key at creation.
(3) rename calc_pte_to_hpte_pkey_bits() to
pte_to_hpte_pkey_bits()
-- suggested by Anshuman
(4) some code optimization and clarity in
do_page_fault()
(5) A bug fix while invalidating a hpte slot
in __hash_page_4K()
-- noticed by Aneesh
version v2:
(1) documentation and selftest added.
(2) fixed a bug in 4k hpte backed 64k pte
where page invalidation was not
done correctly, and initialization
of second-part-of-the-pte was not
done correctly if the pte was not
yet Hashed with a hpte.
-- Reported by Aneesh.
(3) Fixed ABI breakage caused in siginfo
structure.
-- Reported by Anshuman.
version v1: Initial version
Ram Pai (62):
powerpc: Free up four 64K PTE bits in 4K backed HPTE pages
powerpc: Free up four 64K PTE bits in 64K backed HPTE pages
powerpc: introduce pte_set_hash_slot() helper
powerpc: introduce pte_get_hash_gslot() helper
powerpc: capture the PTE format changes in the dump pte report
powerpc: use helper functions in __hash_page_64K() for 64K PTE
powerpc: use helper functions in __hash_page_huge() for 64K PTE
powerpc: use helper functions in __hash_page_4K() for 64K PTE
powerpc: use helper functions in __hash_page_4K() for 4K PTE
powerpc: use helper functions in flush_hash_page()
powerpc: initial pkey plumbing
mm: introduce an additional vma bit for powerpc pkey
powerpc: track allocation status of all pkeys
powerpc: helper function to read,write AMR,IAMR,UAMOR registers
powerpc: helper functions to initialize AMR, IAMR and UMOR registers
powerpc: cleaup AMR,iAMR when a key is allocated or freed
powerpc: implementation for arch_set_user_pkey_access()
powerpc: sys_pkey_alloc() and sys_pkey_free() system calls
powerpc: ability to create execute-disabled pkeys
powerpc: store and restore the pkey state across context switches
powerpc: introduce execute-only pkey
powerpc: ability to associate pkey to a vma
powerpc: implementation for arch_override_mprotect_pkey()
powerpc: map vma key-protection bits to pte key bits.
powerpc: sys_pkey_mprotect() system call
powerpc: Program HPTE key protection bits
powerpc: helper to validate key-access permissions of a pte
powerpc: check key protection for user page access
powerpc: Macro the mask used for checking DSI exception
powerpc: implementation for arch_vma_access_permitted()
powerpc: Handle exceptions caused by pkey violation
powerpc: capture AMR register content on pkey violation
powerpc: introduce get_pte_pkey() helper
powerpc: capture the violated protection key on fault
powerpc: Deliver SEGV signal on pkey violation
mm: introduce arch_pkeys_enabled()
x86: implementation for arch_pkeys_enabled()
powerpc: implementation for arch_pkeys_enabled()
mm: display pkey in smaps if arch_pkeys_enabled() is true
x86: delete arch_show_smap()
selftest/x86: Move protecton key selftest to arch neutral directory
selftest/vm: rename all references to pkru to a generic name
selftest/vm: move generic definitions to header file
selftest/vm: typecast the pkey register
selftest/vm: generics function to handle shadow key register
selftest/vm: fix the wrong assert in pkey_disable_set()
selftest/vm: fixed bugs in pkey_disable_clear()
selftest/vm: clear the bits in shadow reg when a pkey is freed.
selftest/vm: fix alloc_random_pkey() to make it really random
selftest/vm: introduce two arch independent abstraction
selftest/vm: pkey register should match shadow pkey
selftest/vm: generic cleanup
selftest/vm: powerpc implementation for generic abstraction
selftest/vm: fix an assertion in test_pkey_alloc_exhaust()
selftest/vm: associate key on a mapped page and detect access
violation
selftest/vm: detect no key violation on a freed key
selftest/vm: associate key on a mapped page and detect write
violation
selftest/vm: detect no write key-violation on a freed key
selftest/vm: detect write violation on a mapped access-denied-key
page
selftest/vm: sub-page allocator
Documentation/x86: Move protecton key documentation to arch neutral
directory
Documentation/vm: PowerPC specific updates to memory protection keys
Documentation/vm/protection-keys.txt | 125 ++
Documentation/x86/protection-keys.txt | 85 --
arch/powerpc/Kconfig | 16 +
arch/powerpc/include/asm/book3s/64/hash-4k.h | 20 +
arch/powerpc/include/asm/book3s/64/hash-64k.h | 60 +-
arch/powerpc/include/asm/book3s/64/hash.h | 7 +-
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 10 +
arch/powerpc/include/asm/book3s/64/mmu.h | 10 +
arch/powerpc/include/asm/book3s/64/pgtable.h | 64 +-
arch/powerpc/include/asm/mman.h | 16 +-
arch/powerpc/include/asm/mmu_context.h | 14 +
arch/powerpc/include/asm/paca.h | 4 +
arch/powerpc/include/asm/pkeys.h | 226 ++++
arch/powerpc/include/asm/processor.h | 5 +
arch/powerpc/include/asm/reg.h | 8 +-
arch/powerpc/include/asm/systbl.h | 3 +
arch/powerpc/include/asm/unistd.h | 6 +-
arch/powerpc/include/uapi/asm/ptrace.h | 1 +
arch/powerpc/include/uapi/asm/unistd.h | 3 +
arch/powerpc/kernel/asm-offsets.c | 6 +
arch/powerpc/kernel/exceptions-64s.S | 2 +-
arch/powerpc/kernel/process.c | 18 +
arch/powerpc/kernel/setup_64.c | 4 +
arch/powerpc/kernel/signal_32.c | 5 +
arch/powerpc/kernel/signal_64.c | 4 +
arch/powerpc/kernel/traps.c | 15 +
arch/powerpc/mm/Makefile | 1 +
arch/powerpc/mm/dump_linuxpagetables.c | 3 +-
arch/powerpc/mm/fault.c | 31 +
arch/powerpc/mm/hash64_4k.c | 14 +-
arch/powerpc/mm/hash64_64k.c | 124 ++-
arch/powerpc/mm/hash_utils_64.c | 65 +-
arch/powerpc/mm/hugetlbpage-hash64.c | 16 +-
arch/powerpc/mm/mmu_context_book3s64.c | 2 +
arch/powerpc/mm/pkeys.c | 279 +++++
arch/x86/include/asm/pkeys.h | 1 +
arch/x86/kernel/fpu/xstate.c | 5 +
arch/x86/kernel/setup.c | 8 -
fs/proc/task_mmu.c | 15 +-
include/linux/mm.h | 20 +-
include/linux/pkeys.h | 5 +
tools/testing/selftests/vm/Makefile | 1 +
tools/testing/selftests/vm/pkey-helpers.h | 394 +++++++
tools/testing/selftests/vm/protection_keys.c | 1500 +++++++++++++++++++++++++
tools/testing/selftests/x86/Makefile | 2 +-
tools/testing/selftests/x86/pkey-helpers.h | 219 ----
tools/testing/selftests/x86/protection_keys.c | 1395 -----------------------
47 files changed, 2993 insertions(+), 1844 deletions(-)
create mode 100644 Documentation/vm/protection-keys.txt
delete mode 100644 Documentation/x86/protection-keys.txt
create mode 100644 arch/powerpc/include/asm/pkeys.h
create mode 100644 arch/powerpc/mm/pkeys.c
create mode 100644 tools/testing/selftests/vm/pkey-helpers.h
create mode 100644 tools/testing/selftests/vm/protection_keys.c
delete mode 100644 tools/testing/selftests/x86/pkey-helpers.h
delete mode 100644 tools/testing/selftests/x86/protection_keys.c
[toc] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:00 +0200 |
| Subject | [RFC v6 11/62] powerpc: initial pkey plumbing |
| Message-ID | <u3ISS-1St-19@gated-at.bofh.it> |
| In reply to | #1688056 |
basic setup to initialize the pkey system. Only 64K kernel in HPT
mode, enables the pkey system.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
arch/powerpc/Kconfig | 16 ++++++++++
arch/powerpc/include/asm/mmu_context.h | 5 +++
arch/powerpc/include/asm/pkeys.h | 51 ++++++++++++++++++++++++++++++++
arch/powerpc/kernel/setup_64.c | 4 ++
arch/powerpc/mm/Makefile | 1 +
arch/powerpc/mm/hash_utils_64.c | 1 +
arch/powerpc/mm/pkeys.c | 18 +++++++++++
7 files changed, 96 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/include/asm/pkeys.h
create mode 100644 arch/powerpc/mm/pkeys.c
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index bf4391d..5c60fd6 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -855,6 +855,22 @@ config SECCOMP
If unsure, say Y. Only embedded should say N here.
+config PPC64_MEMORY_PROTECTION_KEYS
+ prompt "PowerPC Memory Protection Keys"
+ def_bool y
+ # Note: only available in 64-bit mode
+ depends on PPC64 && PPC_64K_PAGES
+ select ARCH_USES_HIGH_VMA_FLAGS
+ select ARCH_HAS_PKEYS
+ ---help---
+ Memory Protection Keys provides a mechanism for enforcing
+ page-based protections, but without requiring modification of the
+ page tables when an application changes protection domains.
+
+ For details, see Documentation/vm/protection-keys.txt
+
+ If unsure, say y.
+
endmenu
config ISA_DMA_API
diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h
index da7e943..4b93547 100644
--- a/arch/powerpc/include/asm/mmu_context.h
+++ b/arch/powerpc/include/asm/mmu_context.h
@@ -181,5 +181,10 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
/* by default, allow everything */
return true;
}
+
+#ifndef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+#define pkey_initialize()
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
#endif /* __KERNEL__ */
#endif /* __ASM_POWERPC_MMU_CONTEXT_H */
diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h
new file mode 100644
index 0000000..203d7de
--- /dev/null
+++ b/arch/powerpc/include/asm/pkeys.h
@@ -0,0 +1,51 @@
+#ifndef _ASM_PPC64_PKEYS_H
+#define _ASM_PPC64_PKEYS_H
+
+extern bool pkey_inited;
+#define ARCH_VM_PKEY_FLAGS 0
+
+static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
+{
+ return (pkey == 0);
+}
+
+static inline int mm_pkey_alloc(struct mm_struct *mm)
+{
+ return -1;
+}
+
+static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
+{
+ return -EINVAL;
+}
+
+/*
+ * Try to dedicate one of the protection keys to be used as an
+ * execute-only protection key.
+ */
+static inline int execute_only_pkey(struct mm_struct *mm)
+{
+ return 0;
+}
+
+static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
+ int prot, int pkey)
+{
+ return 0;
+}
+
+static inline int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
+ unsigned long init_val)
+{
+ return 0;
+}
+
+static inline void pkey_initialize(void)
+{
+#ifdef CONFIG_PPC_64K_PAGES
+ pkey_inited = !radix_enabled();
+#else
+ pkey_inited = false;
+#endif
+}
+#endif /*_ASM_PPC64_PKEYS_H */
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 4640f6d..50accab 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -37,6 +37,7 @@
#include <linux/memblock.h>
#include <linux/memory.h>
#include <linux/nmi.h>
+#include <linux/pkeys.h>
#include <asm/io.h>
#include <asm/kdump.h>
@@ -316,6 +317,9 @@ void __init early_setup(unsigned long dt_ptr)
/* Initialize the hash table or TLB handling */
early_init_mmu();
+ /* initialize the key subsystem */
+ pkey_initialize();
+
/*
* At this point, we can let interrupts switch to virtual mode
* (the MMU has been setup), so adjust the MSR in the PACA to
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 7414034..8cc2ff1 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -45,3 +45,4 @@ obj-$(CONFIG_PPC_COPRO_BASE) += copro_fault.o
obj-$(CONFIG_SPAPR_TCE_IOMMU) += mmu_context_iommu.o
obj-$(CONFIG_PPC_PTDUMP) += dump_linuxpagetables.o
obj-$(CONFIG_PPC_HTDUMP) += dump_hashpagetable.o
+obj-$(CONFIG_PPC64_MEMORY_PROTECTION_KEYS) += pkeys.o
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index d863696..f88423b 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -35,6 +35,7 @@
#include <linux/memblock.h>
#include <linux/context_tracking.h>
#include <linux/libfdt.h>
+#include <linux/pkeys.h>
#include <asm/debugfs.h>
#include <asm/processor.h>
diff --git a/arch/powerpc/mm/pkeys.c b/arch/powerpc/mm/pkeys.c
new file mode 100644
index 0000000..c3acee1
--- /dev/null
+++ b/arch/powerpc/mm/pkeys.c
@@ -0,0 +1,18 @@
+/*
+ * PowerPC Memory Protection Keys management
+ * Copyright (c) 2015, Intel Corporation.
+ * Copyright (c) 2017, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+#include <uapi/asm-generic/mman-common.h>
+#include <linux/pkeys.h> /* PKEY_* */
+
+bool pkey_inited;
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:00 +0200 |
| Subject | [RFC v6 31/62] powerpc: Handle exceptions caused by pkey violation |
| Message-ID | <u3ISS-1St-21@gated-at.bofh.it> |
| In reply to | #1688056 |
Handle Data and Instruction exceptions caused by memory
protection-key.
The CPU will detect the key fault if the HPTE is already
programmed with the key.
However if the HPTE is not hashed, a key fault will not
be detected by the hardware. The software will detect
pkey violation in such a case.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
arch/powerpc/include/asm/reg.h | 3 ++-
arch/powerpc/mm/fault.c | 21 +++++++++++++++++++++
2 files changed, 23 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index ee04bc0..b7cbc8c 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -286,7 +286,8 @@
#define DSISR_SET_RC 0x00040000 /* Failed setting of R/C bits */
#define DSISR_PGDIRFAULT 0x00020000 /* Fault on page directory */
#define DSISR_PAGE_FAULT_MASK (DSISR_BIT32 | DSISR_PAGEATTR_CONFLT | \
- DSISR_BADACCESS | DSISR_DABRMATCH | DSISR_BIT43)
+ DSISR_BADACCESS | DSISR_KEYFAULT | \
+ DSISR_DABRMATCH | DSISR_BIT43)
#define SPRN_TBRL 0x10C /* Time Base Read Lower Register (user, R/O) */
#define SPRN_TBRU 0x10D /* Time Base Read Upper Register (user, R/O) */
#define SPRN_CIR 0x11B /* Chip Information Register (hyper, R/0) */
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 3a7d580..ea74fe2 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -261,6 +261,13 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
}
#endif
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+ if (error_code & DSISR_KEYFAULT) {
+ code = SEGV_PKUERR;
+ goto bad_area_nosemaphore;
+ }
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
/* We restore the interrupt state now */
if (!arch_irq_disabled_regs(regs))
local_irq_enable();
@@ -441,6 +448,20 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
WARN_ON_ONCE(error_code & DSISR_PROTFAULT);
#endif /* CONFIG_PPC_STD_MMU */
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+ if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
+ is_exec, 0)) {
+ code = SEGV_PKUERR;
+ goto bad_area;
+ }
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
+
+ /* handle_mm_fault() needs to know if its a instruction access
+ * fault.
+ */
+ if (is_exec)
+ flags |= FAULT_FLAG_INSTRUCTION;
/*
* If for any reason at all we couldn't handle the fault,
* make sure we exit gracefully rather than endlessly redo
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:00 +0200 |
| Subject | [RFC v6 15/62] powerpc: helper functions to initialize AMR, IAMR and UMOR registers |
| Message-ID | <u3ISS-1St-23@gated-at.bofh.it> |
| In reply to | #1688056 |
Introduce helper functions that can initialize the bits in the AMR,
IAMR and UMOR register; the bits that correspond to the given pkey.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
arch/powerpc/include/asm/pkeys.h | 1 +
arch/powerpc/mm/pkeys.c | 44 ++++++++++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h
index 09b268e..4327842 100644
--- a/arch/powerpc/include/asm/pkeys.h
+++ b/arch/powerpc/include/asm/pkeys.h
@@ -5,6 +5,7 @@
#define arch_max_pkey() 32
#define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
VM_PKEY_BIT3 | VM_PKEY_BIT4)
+#define AMR_BITS_PER_PKEY 2
/*
* Bits are in BE format.
* NOTE: key 31, 1, 0 are not used.
diff --git a/arch/powerpc/mm/pkeys.c b/arch/powerpc/mm/pkeys.c
index c3acee1..04ee361 100644
--- a/arch/powerpc/mm/pkeys.c
+++ b/arch/powerpc/mm/pkeys.c
@@ -16,3 +16,47 @@
#include <linux/pkeys.h> /* PKEY_* */
bool pkey_inited;
+#define pkeyshift(pkey) ((arch_max_pkey()-pkey-1) * AMR_BITS_PER_PKEY)
+
+static inline void init_amr(int pkey, u8 init_bits)
+{
+ u64 new_amr_bits = (((u64)init_bits & 0x3UL) << pkeyshift(pkey));
+ u64 old_amr = read_amr() & ~((u64)(0x3ul) << pkeyshift(pkey));
+
+ write_amr(old_amr | new_amr_bits);
+}
+
+static inline void init_iamr(int pkey, u8 init_bits)
+{
+ u64 new_iamr_bits = (((u64)init_bits & 0x3UL) << pkeyshift(pkey));
+ u64 old_iamr = read_iamr() & ~((u64)(0x3ul) << pkeyshift(pkey));
+
+ write_amr(old_iamr | new_iamr_bits);
+}
+
+static void pkey_status_change(int pkey, bool enable)
+{
+ u64 old_uamor;
+
+ /* reset the AMR and IAMR bits for this key */
+ init_amr(pkey, 0x0);
+ init_iamr(pkey, 0x0);
+
+ /* enable/disable key */
+ old_uamor = read_uamor();
+ if (enable)
+ old_uamor |= (0x3ul << pkeyshift(pkey));
+ else
+ old_uamor &= ~(0x3ul << pkeyshift(pkey));
+ write_uamor(old_uamor);
+}
+
+void __arch_activate_pkey(int pkey)
+{
+ pkey_status_change(pkey, true);
+}
+
+void __arch_deactivate_pkey(int pkey)
+{
+ pkey_status_change(pkey, false);
+}
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:00 +0200 |
| Subject | [RFC v6 06/62] powerpc: use helper functions in __hash_page_64K() for 64K PTE |
| Message-ID | <u3ISS-1St-25@gated-at.bofh.it> |
| In reply to | #1688056 |
replace redundant code in __hash_page_64K() with helper
functions pte_get_hash_gslot() and pte_set_hash_slot()
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
arch/powerpc/mm/hash64_64k.c | 24 ++++--------------------
1 files changed, 4 insertions(+), 20 deletions(-)
diff --git a/arch/powerpc/mm/hash64_64k.c b/arch/powerpc/mm/hash64_64k.c
index 0012618..645f621 100644
--- a/arch/powerpc/mm/hash64_64k.c
+++ b/arch/powerpc/mm/hash64_64k.c
@@ -244,7 +244,6 @@ int __hash_page_64K(unsigned long ea, unsigned long access,
unsigned long flags, int ssize)
{
real_pte_t rpte;
- unsigned long *hidxp;
unsigned long hpte_group;
unsigned long rflags, pa;
unsigned long old_pte, new_pte;
@@ -289,18 +288,12 @@ int __hash_page_64K(unsigned long ea, unsigned long access,
vpn = hpt_vpn(ea, vsid, ssize);
if (unlikely(old_pte & H_PAGE_HASHPTE)) {
- unsigned long hash, slot, hidx;
-
- hash = hpt_hash(vpn, shift, ssize);
- hidx = __rpte_to_hidx(rpte, 0);
- if (hidx & _PTEIDX_SECONDARY)
- hash = ~hash;
- slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
- slot += hidx & _PTEIDX_GROUP_IX;
+ unsigned long gslot;
/*
* There MIGHT be an HPTE for this pte
*/
- if (mmu_hash_ops.hpte_updatepp(slot, rflags, vpn, MMU_PAGE_64K,
+ gslot = pte_get_hash_gslot(vpn, shift, ssize, rpte, 0);
+ if (mmu_hash_ops.hpte_updatepp(gslot, rflags, vpn, MMU_PAGE_64K,
MMU_PAGE_64K, ssize,
flags) == -1)
old_pte &= ~_PAGE_HPTEFLAGS;
@@ -350,17 +343,8 @@ int __hash_page_64K(unsigned long ea, unsigned long access,
return -1;
}
- /*
- * Insert slot number & secondary bit in PTE second half.
- */
- hidxp = (unsigned long *)(ptep + PTRS_PER_PTE);
- rpte.hidx &= ~(0xfUL);
- *hidxp = rpte.hidx | (slot & 0xfUL);
- /*
- * check __real_pte for details on matching smp_rmb()
- */
- smp_wmb();
new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | H_PAGE_HASHPTE;
+ new_pte |= pte_set_hash_slot(ptep, rpte, 0, slot);
}
*ptep = __pte(new_pte & ~H_PAGE_BUSY);
return 0;
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:00 +0200 |
| Subject | [RFC v6 33/62] powerpc: introduce get_pte_pkey() helper |
| Message-ID | <u3ISS-1St-27@gated-at.bofh.it> |
| In reply to | #1688056 |
get_pte_pkey() helper returns the pkey associated with
a address corresponding to a given mm_struct.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 5 +++++
arch/powerpc/mm/hash_utils_64.c | 25 +++++++++++++++++++++++++
2 files changed, 30 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
index f7a6ed3..369f9ff 100644
--- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h
+++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
@@ -450,6 +450,11 @@ extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap,
int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
pte_t *ptep, unsigned long trap, unsigned long flags,
int ssize, unsigned int shift, unsigned int mmu_psize);
+
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+u16 get_pte_pkey(struct mm_struct *mm, unsigned long address);
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
extern int __hash_page_thp(unsigned long ea, unsigned long access,
unsigned long vsid, pmd_t *pmdp, unsigned long trap,
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 1e74529..6bc8e91 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -1573,6 +1573,31 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
local_irq_restore(flags);
}
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+/*
+ * return the protection key associated with the given address
+ * and the mm_struct.
+ */
+u16 get_pte_pkey(struct mm_struct *mm, unsigned long address)
+{
+ pte_t *ptep;
+ u16 pkey = 0;
+ unsigned long flags;
+
+ if (!mm || !mm->pgd)
+ return 0;
+
+ local_irq_save(flags);
+ ptep = find_linux_pte_or_hugepte(mm->pgd, address,
+ NULL, NULL);
+ if (ptep)
+ pkey = pte_to_pkey_bits(pte_val(READ_ONCE(*ptep)));
+ local_irq_restore(flags);
+
+ return pkey;
+}
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
static inline void tm_flush_hash_page(int local)
{
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:00 +0200 |
| Subject | [RFC v6 26/62] powerpc: Program HPTE key protection bits |
| Message-ID | <u3ISS-1St-29@gated-at.bofh.it> |
| In reply to | #1688056 |
Map the PTE protection key bits to the HPTE key protection bits,
while creating HPTE entries.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 5 +++++
arch/powerpc/include/asm/pkeys.h | 12 ++++++++++++
arch/powerpc/mm/hash_utils_64.c | 4 ++++
3 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
index 6981a52..f7a6ed3 100644
--- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h
+++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
@@ -90,6 +90,8 @@
#define HPTE_R_PP0 ASM_CONST(0x8000000000000000)
#define HPTE_R_TS ASM_CONST(0x4000000000000000)
#define HPTE_R_KEY_HI ASM_CONST(0x3000000000000000)
+#define HPTE_R_KEY_BIT0 ASM_CONST(0x2000000000000000)
+#define HPTE_R_KEY_BIT1 ASM_CONST(0x1000000000000000)
#define HPTE_R_RPN_SHIFT 12
#define HPTE_R_RPN ASM_CONST(0x0ffffffffffff000)
#define HPTE_R_RPN_3_0 ASM_CONST(0x01fffffffffff000)
@@ -104,6 +106,9 @@
#define HPTE_R_C ASM_CONST(0x0000000000000080)
#define HPTE_R_R ASM_CONST(0x0000000000000100)
#define HPTE_R_KEY_LO ASM_CONST(0x0000000000000e00)
+#define HPTE_R_KEY_BIT2 ASM_CONST(0x0000000000000800)
+#define HPTE_R_KEY_BIT3 ASM_CONST(0x0000000000000400)
+#define HPTE_R_KEY_BIT4 ASM_CONST(0x0000000000000200)
#define HPTE_V_1TB_SEG ASM_CONST(0x4000000000000000)
#define HPTE_V_VRMA_MASK ASM_CONST(0x4001ffffff000000)
diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h
index ad39db0..bbb5d85 100644
--- a/arch/powerpc/include/asm/pkeys.h
+++ b/arch/powerpc/include/asm/pkeys.h
@@ -41,6 +41,18 @@ static inline u64 vmflag_to_page_pkey_bits(u64 vm_flags)
((vm_flags & VM_PKEY_BIT4) ? H_PAGE_PKEY_BIT0 : 0x0UL));
}
+static inline u64 pte_to_hpte_pkey_bits(u64 pteflags)
+{
+ if (!pkey_inited)
+ return 0x0UL;
+
+ return (((pteflags & H_PAGE_PKEY_BIT0) ? HPTE_R_KEY_BIT0 : 0x0UL) |
+ ((pteflags & H_PAGE_PKEY_BIT1) ? HPTE_R_KEY_BIT1 : 0x0UL) |
+ ((pteflags & H_PAGE_PKEY_BIT2) ? HPTE_R_KEY_BIT2 : 0x0UL) |
+ ((pteflags & H_PAGE_PKEY_BIT3) ? HPTE_R_KEY_BIT3 : 0x0UL) |
+ ((pteflags & H_PAGE_PKEY_BIT4) ? HPTE_R_KEY_BIT4 : 0x0UL));
+}
+
static inline int vma_pkey(struct vm_area_struct *vma)
{
if (!pkey_inited)
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index f88423b..1e74529 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -231,6 +231,10 @@ unsigned long htab_convert_pte_flags(unsigned long pteflags)
*/
rflags |= HPTE_R_M;
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+ rflags |= pte_to_hpte_pkey_bits(pteflags);
+#endif
+
return rflags;
}
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:10 +0200 |
| Subject | [RFC v6 49/62] selftest/vm: fix alloc_random_pkey() to make it really random |
| Message-ID | <u3J2x-2aY-1@gated-at.bofh.it> |
| In reply to | #1688056 |
alloc_random_pkey() was allocating the same pkey every time.
Not all pkeys were geting tested. fixed it.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
tools/testing/selftests/vm/protection_keys.c | 10 +++++++---
1 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/tools/testing/selftests/vm/protection_keys.c b/tools/testing/selftests/vm/protection_keys.c
index 4f4ce36..1c8ef39 100644
--- a/tools/testing/selftests/vm/protection_keys.c
+++ b/tools/testing/selftests/vm/protection_keys.c
@@ -23,6 +23,7 @@
#define _GNU_SOURCE
#include <errno.h>
#include <linux/futex.h>
+#include <time.h>
#include <sys/time.h>
#include <sys/syscall.h>
#include <string.h>
@@ -602,13 +603,15 @@ int alloc_random_pkey(void)
int alloced_pkeys[NR_PKEYS];
int nr_alloced = 0;
int random_index;
+
memset(alloced_pkeys, 0, sizeof(alloced_pkeys));
+ srand((unsigned int)time(NULL));
/* allocate every possible key and make a note of which ones we got */
max_nr_pkey_allocs = NR_PKEYS;
- max_nr_pkey_allocs = 1;
for (i = 0; i < max_nr_pkey_allocs; i++) {
int new_pkey = alloc_pkey();
+
if (new_pkey < 0)
break;
alloced_pkeys[nr_alloced++] = new_pkey;
@@ -624,13 +627,14 @@ int alloc_random_pkey(void)
/* go through the allocated ones that we did not want and free them */
for (i = 0; i < nr_alloced; i++) {
int free_ret;
+
if (!alloced_pkeys[i])
continue;
free_ret = sys_pkey_free(alloced_pkeys[i]);
pkey_assert(!free_ret);
}
- dprintf1("%s()::%d, ret: %d pkey_reg: 0x%x shadow: 0x%x\n", __func__,
- __LINE__, ret, __rdpkey_reg(), shadow_pkey_reg);
+ dprintf1("%s()::%d, ret: %d pkey_reg: 0x%x shadow: 0x%016lx\n",
+ __func__, __LINE__, ret, __rdpkey_reg(), shadow_pkey_reg);
return ret;
}
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:10 +0200 |
| Subject | [RFC v6 45/62] selftest/vm: generics function to handle shadow key register |
| Message-ID | <u3J2x-2aY-3@gated-at.bofh.it> |
| In reply to | #1688056 |
helper functions to handler shadow pkey register
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
tools/testing/selftests/vm/pkey-helpers.h | 27 ++++++++++++++++++++
tools/testing/selftests/vm/protection_keys.c | 34 ++++++++++++++++---------
2 files changed, 49 insertions(+), 12 deletions(-)
diff --git a/tools/testing/selftests/vm/pkey-helpers.h b/tools/testing/selftests/vm/pkey-helpers.h
index 12260e8..f50b5f2 100644
--- a/tools/testing/selftests/vm/pkey-helpers.h
+++ b/tools/testing/selftests/vm/pkey-helpers.h
@@ -43,6 +43,33 @@
#define DEBUG_LEVEL 0
#endif
#define DPRINT_IN_SIGNAL_BUF_SIZE 4096
+
+static inline u32 pkey_to_shift(int pkey)
+{
+ return pkey * PKEY_BITS_PER_PKEY;
+}
+
+static inline pkey_reg_t reset_bits(int pkey, pkey_reg_t bits)
+{
+ u32 shift = pkey_to_shift(pkey);
+
+ return ~(bits << shift);
+}
+
+static inline pkey_reg_t left_shift_bits(int pkey, pkey_reg_t bits)
+{
+ u32 shift = pkey_to_shift(pkey);
+
+ return (bits << shift);
+}
+
+static inline pkey_reg_t right_shift_bits(int pkey, pkey_reg_t bits)
+{
+ u32 shift = pkey_to_shift(pkey);
+
+ return (bits >> shift);
+}
+
extern int dprint_in_signal;
extern char dprint_in_signal_buffer[DPRINT_IN_SIGNAL_BUF_SIZE];
static inline void sigsafe_printf(const char *format, ...)
diff --git a/tools/testing/selftests/vm/protection_keys.c b/tools/testing/selftests/vm/protection_keys.c
index bd46f87..e5f5535 100644
--- a/tools/testing/selftests/vm/protection_keys.c
+++ b/tools/testing/selftests/vm/protection_keys.c
@@ -374,7 +374,7 @@ u32 pkey_get(int pkey, unsigned long flags)
__func__, pkey, flags, 0, 0);
dprintf2("%s() raw pkey_reg: %x\n", __func__, pkey_reg);
- shifted_pkey_reg = (pkey_reg >> (pkey * PKEY_BITS_PER_PKEY));
+ shifted_pkey_reg = right_shift_bits(pkey, pkey_reg);
dprintf2("%s() shifted_pkey_reg: %x\n", __func__, shifted_pkey_reg);
masked_pkey_reg = shifted_pkey_reg & mask;
dprintf2("%s() masked pkey_reg: %x\n", __func__, masked_pkey_reg);
@@ -397,9 +397,9 @@ int pkey_set(int pkey, unsigned long rights, unsigned long flags)
/* copy old pkey_reg */
new_pkey_reg = old_pkey_reg;
/* mask out bits from pkey in old value: */
- new_pkey_reg &= ~(mask << (pkey * PKEY_BITS_PER_PKEY));
+ new_pkey_reg &= reset_bits(pkey, mask);
/* OR in new bits for pkey: */
- new_pkey_reg |= (rights << (pkey * PKEY_BITS_PER_PKEY));
+ new_pkey_reg |= left_shift_bits(pkey, rights);
__wrpkey_reg(new_pkey_reg);
@@ -430,7 +430,7 @@ void pkey_disable_set(int pkey, int flags)
ret = pkey_set(pkey, pkey_rights, syscall_flags);
assert(!ret);
/*pkey_reg and flags have the same format */
- shadow_pkey_reg |= flags << (pkey * 2);
+ shadow_pkey_reg |= left_shift_bits(pkey, flags);
dprintf1("%s(%d) shadow: 0x%016lx\n",
__func__, pkey, shadow_pkey_reg);
@@ -465,7 +465,7 @@ void pkey_disable_clear(int pkey, int flags)
ret = pkey_set(pkey, pkey_rights, 0);
/* pkey_reg and flags have the same format */
- shadow_pkey_reg &= ~(flags << (pkey * 2));
+ shadow_pkey_reg &= reset_bits(pkey, flags);
pkey_assert(ret >= 0);
pkey_rights = pkey_get(pkey, syscall_flags);
@@ -523,6 +523,21 @@ int sys_pkey_alloc(unsigned long flags, unsigned long init_val)
return ret;
}
+void pkey_setup_shadow(void)
+{
+ shadow_pkey_reg = __rdpkey_reg();
+}
+
+void pkey_reset_shadow(u32 key)
+{
+ shadow_pkey_reg &= reset_bits(key, 0x3);
+}
+
+void pkey_set_shadow(u32 key, u64 init_val)
+{
+ shadow_pkey_reg |= left_shift_bits(key, init_val);
+}
+
int alloc_pkey(void)
{
int ret;
@@ -540,7 +555,7 @@ int alloc_pkey(void)
shadow_pkey_reg);
if (ret) {
/* clear both the bits: */
- shadow_pkey_reg &= ~(0x3 << (ret * 2));
+ pkey_reset_shadow(ret);
dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016lx "
"shadow: 0x%016lx\n",
__func__,
@@ -550,7 +565,7 @@ int alloc_pkey(void)
* move the new state in from init_val
* (remember, we cheated and init_val == pkey_reg format)
*/
- shadow_pkey_reg |= (init_val << (ret * 2));
+ pkey_set_shadow(ret, init_val);
}
dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016lx shadow: 0x%016lx\n",
__func__, __LINE__, ret, __rdpkey_reg(),
@@ -1322,11 +1337,6 @@ void run_tests_once(void)
iteration_nr++;
}
-void pkey_setup_shadow(void)
-{
- shadow_pkey_reg = __rdpkey_reg();
-}
-
int main(void)
{
int nr_iterations = 22;
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:10 +0200 |
| Subject | [RFC v6 53/62] selftest/vm: powerpc implementation for generic abstraction |
| Message-ID | <u3J2x-2aY-7@gated-at.bofh.it> |
| In reply to | #1688056 |
Introduce powerpc implementation for the various
abstactions.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
tools/testing/selftests/vm/pkey-helpers.h | 97 +++++++++++++++++++++++--
tools/testing/selftests/vm/protection_keys.c | 33 +++++----
2 files changed, 107 insertions(+), 23 deletions(-)
diff --git a/tools/testing/selftests/vm/pkey-helpers.h b/tools/testing/selftests/vm/pkey-helpers.h
index 5211019..59172cc 100644
--- a/tools/testing/selftests/vm/pkey-helpers.h
+++ b/tools/testing/selftests/vm/pkey-helpers.h
@@ -17,27 +17,58 @@
#define u16 uint16_t
#define u32 uint32_t
#define u64 uint64_t
-#define pkey_reg_t u32
-#ifdef __i386__
+#ifdef __i386__ /* arch */
+
#define SYS_mprotect_key 380
#define SYS_pkey_alloc 381
#define SYS_pkey_free 382
#define REG_IP_IDX REG_EIP
#define si_pkey_offset 0x14
-#else
+
+#define NR_PKEYS 16
+#define NR_RESERVED_PKEYS 1
+#define PKEY_BITS_PER_PKEY 2
+#define PKEY_DISABLE_ACCESS 0x1
+#define PKEY_DISABLE_WRITE 0x2
+#define HPAGE_SIZE (1UL<<21)
+#define pkey_reg_t u32
+
+#elif __powerpc64__ /* arch */
+
+#define SYS_mprotect_key 386
+#define SYS_pkey_alloc 384
+#define SYS_pkey_free 385
+#define si_pkey_offset 0x20
+#define REG_IP_IDX PT_NIP
+#define REG_TRAPNO PT_TRAP
+#define REG_AMR 45
+#define gregs gp_regs
+#define fpregs fp_regs
+
+#define NR_PKEYS 32
+#define NR_RESERVED_PKEYS 3
+#define PKEY_BITS_PER_PKEY 2
+#define PKEY_DISABLE_ACCESS 0x3 /* disable read and write */
+#define PKEY_DISABLE_WRITE 0x2
+#define HPAGE_SIZE (1UL<<24)
+#define pkey_reg_t u64
+
+#else /* arch */
+
#define SYS_mprotect_key 329
#define SYS_pkey_alloc 330
#define SYS_pkey_free 331
#define REG_IP_IDX REG_RIP
#define si_pkey_offset 0x20
-#endif
-
#define NR_PKEYS 16
#define PKEY_BITS_PER_PKEY 2
#define PKEY_DISABLE_ACCESS 0x1
#define PKEY_DISABLE_WRITE 0x2
#define HPAGE_SIZE (1UL<<21)
+ NOT SUPPORTED
+
+#endif /* arch */
#ifndef DEBUG_LEVEL
#define DEBUG_LEVEL 0
@@ -46,7 +77,11 @@
static inline u32 pkey_to_shift(int pkey)
{
+#ifdef __i386__ /* arch */
return pkey * PKEY_BITS_PER_PKEY;
+#elif __powerpc64__ /* arch */
+ return (NR_PKEYS - pkey - 1) * PKEY_BITS_PER_PKEY;
+#endif /* arch */
}
static inline pkey_reg_t reset_bits(int pkey, pkey_reg_t bits)
@@ -107,6 +142,7 @@ static inline void sigsafe_printf(const char *format, ...)
extern pkey_reg_t shadow_pkey_reg;
static inline pkey_reg_t __rdpkey_reg(void)
{
+#ifdef __i386__ /* arch */
unsigned int eax, edx;
unsigned int ecx = 0;
pkey_reg_t pkey_reg;
@@ -114,7 +150,13 @@ static inline pkey_reg_t __rdpkey_reg(void)
asm volatile(".byte 0x0f,0x01,0xee\n\t"
: "=a" (eax), "=d" (edx)
: "c" (ecx));
- pkey_reg = eax;
+#elif __powerpc64__ /* arch */
+ pkey_reg_t eax;
+ pkey_reg_t pkey_reg;
+
+ asm volatile("mfspr %0, 0xd" : "=r" ((pkey_reg_t)(eax)));
+#endif /* arch */
+ pkey_reg = (pkey_reg_t)eax;
return pkey_reg;
}
@@ -134,6 +176,7 @@ static inline pkey_reg_t _rdpkey_reg(int line)
static inline void __wrpkey_reg(pkey_reg_t pkey_reg)
{
pkey_reg_t eax = pkey_reg;
+#ifdef __i386__ /* arch */
pkey_reg_t ecx = 0;
pkey_reg_t edx = 0;
@@ -142,6 +185,14 @@ static inline void __wrpkey_reg(pkey_reg_t pkey_reg)
asm volatile(".byte 0x0f,0x01,0xef\n\t"
: : "a" (eax), "c" (ecx), "d" (edx));
assert(pkey_reg == __rdpkey_reg());
+
+#else /* arch */
+ dprintf4("%s() changing %llx to %llx\n",
+ __func__, __rdpkey_reg(), pkey_reg);
+ asm volatile("mtspr 0xd, %0" : : "r" ((unsigned long)(eax)) : "memory");
+#endif /* arch */
+ dprintf4("%s() pkey register after changing %016lx to %016lx\n",
+ __func__, __rdpkey_reg(), pkey_reg);
}
static inline void wrpkey_reg(pkey_reg_t pkey_reg)
@@ -188,6 +239,8 @@ static inline void __pkey_write_allow(int pkey, int do_allow_write)
dprintf4("pkey_reg now: %08x\n", rdpkey_reg());
}
+#ifdef __i386__ /* arch */
+
#define PAGE_SIZE 4096
#define MB (1<<20)
@@ -270,8 +323,18 @@ static inline void __page_o_noops(void)
/* 8-bytes of instruction * 512 bytes = 1 page */
asm(".rept 512 ; nopl 0x7eeeeeee(%eax) ; .endr");
}
+#elif __powerpc64__ /* arch */
-#endif /* _PKEYS_HELPER_H */
+#define PAGE_SIZE (0x1UL << 16)
+static inline int cpu_has_pku(void)
+{
+ return 1;
+}
+
+/* 8-bytes of instruction * 16384bytes = 1 page */
+#define __page_o_noops() asm(".rept 16384 ; nop; .endr")
+
+#endif /* arch */
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
#define ALIGN_UP(x, align_to) (((x) + ((align_to)-1)) & ~((align_to)-1))
@@ -303,11 +366,29 @@ static inline void __page_o_noops(void)
static inline int open_hugepage_file(int flag)
{
- return open("/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages",
+ int fd;
+
+#ifdef __i386__ /* arch */
+ fd = open("/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages",
O_RDONLY);
+#elif __powerpc64__ /* arch */
+ fd = open("/sys/kernel/mm/hugepages/hugepages-16384kB/nr_hugepages",
+ O_RDONLY);
+#else /* arch */
+ NOT SUPPORTED
+#endif /* arch */
+ return fd;
}
static inline int get_start_key(void)
{
+#ifdef __i386__ /* arch */
return 1;
+#elif __powerpc64__ /* arch */
+ return 0;
+#else /* arch */
+ NOT SUPPORTED
+#endif /* arch */
}
+
+#endif /* _PKEYS_HELPER_H */
diff --git a/tools/testing/selftests/vm/protection_keys.c b/tools/testing/selftests/vm/protection_keys.c
index fd94449..1a28c88 100644
--- a/tools/testing/selftests/vm/protection_keys.c
+++ b/tools/testing/selftests/vm/protection_keys.c
@@ -186,6 +186,7 @@ void dump_mem(void *dumpme, int len_bytes)
int pkey_faults;
int last_si_pkey = -1;
+void pkey_access_allow(int pkey);
void signal_handler(int signum, siginfo_t *si, void *vucontext)
{
ucontext_t *uctxt = vucontext;
@@ -195,8 +196,6 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext)
pkey_reg_t *pkey_reg_ptr;
u32 si_pkey;
pkey_reg_t *si_pkey_ptr;
- int pkey_reg_offset;
- fpregset_t fpregset;
dprint_in_signal = 1;
dprintf1(">>>>===============SIGSEGV============================\n");
@@ -206,8 +205,7 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext)
trapno = uctxt->uc_mcontext.gregs[REG_TRAPNO];
ip = uctxt->uc_mcontext.gregs[REG_IP_IDX];
- fpregset = uctxt->uc_mcontext.fpregs;
- fpregs = (void *)fpregset;
+ fpregs = (char *) uctxt->uc_mcontext.fpregs;
dprintf2("%s() trapno: %d ip: 0x%016lx info->si_code: %s/%d\n",
__func__, trapno, ip, si_code_str(si->si_code),
@@ -219,19 +217,20 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext)
* state. We just assume that it is here.
*/
fpregs += 0x70;
-#endif
- pkey_reg_offset = pkey_reg_xstate_offset();
- pkey_reg_ptr = (void *)(&fpregs[pkey_reg_offset]);
-
- dprintf1("siginfo: %p\n", si);
- dprintf1(" fpregs: %p\n", fpregs);
+ pkey_reg_ptr = (void *)(&fpregs[pkru_xstate_offset()]);
/*
- * If we got a PKEY fault, we *HAVE* to have at least one bit set in
+ * If we got a key fault, we *HAVE* to have at least one bit set in
* here.
*/
- dprintf1("pkey_reg_xstate_offset: %d\n", pkey_reg_xstate_offset());
+ dprintf1("pkru_xstate_offset: %d\n", pkru_xstate_offset());
if (DEBUG_LEVEL > 4)
dump_mem(pkey_reg_ptr - 128, 256);
+#elif __powerpc64__
+ pkey_reg_ptr = &uctxt->uc_mcontext.gregs[REG_AMR];
+#endif
+
+ dprintf1("siginfo: %p\n", si);
+ dprintf1(" fpregs: %p\n", fpregs);
pkey_assert(*pkey_reg_ptr);
si_pkey_ptr = (pkey_reg_t *)(((u8 *)si) + si_pkey_offset);
@@ -254,13 +253,17 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext)
* checking
*/
dprintf1("signal pkey_reg from pkey_reg: %016lx\n", __rdpkey_reg());
- dprintf1("si_pkey from siginfo: %jx\n", si_pkey);
- *(u64 *)pkey_reg_ptr = 0x00000000;
+ dprintf1("si_pkey from siginfo: %lx\n", si_pkey);
+#ifdef __i386__
+ *(u64 *)pkey_reg_ptr &= reset_bits(si_pkey, PKEY_DISABLE_ACCESS);
+#elif __powerpc64__
+ pkey_access_allow(si_pkey);
+#endif
+ shadow_pkey_reg &= reset_bits(si_pkey, PKEY_DISABLE_ACCESS);
dprintf1("WARNING: set PKEY_REG=0 to allow faulting instruction "
"to continue\n");
pkey_faults++;
dprintf1("<<<<==================================================\n");
- return;
}
int wait_all_children(void)
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:10 +0200 |
| Subject | [RFC v6 51/62] selftest/vm: pkey register should match shadow pkey |
| Message-ID | <u3J2x-2aY-9@gated-at.bofh.it> |
| In reply to | #1688056 |
expected_pkey_fault() is comparing the contents of pkey register with 0. This may not be true all the time. There could be bits set by default by the architecture which can never be changed. Hence compare the value against shadow pkey register, which is supposed to track the bits accurately all throughout Signed-off-by: Ram Pai <linuxram@us.ibm.com> --- tools/testing/selftests/vm/protection_keys.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/vm/protection_keys.c b/tools/testing/selftests/vm/protection_keys.c index 20bab6d..f21e177 100644 --- a/tools/testing/selftests/vm/protection_keys.c +++ b/tools/testing/selftests/vm/protection_keys.c @@ -926,10 +926,10 @@ void expected_pkey_fault(int pkey) pkey_assert(last_pkey_faults + 1 == pkey_faults); pkey_assert(last_si_pkey == pkey); /* - * The signal handler shold have cleared out PKEY register to let the + * The signal handler shold have cleared out pkey-register to let the * test program continue. We now have to restore it. */ - if (__rdpkey_reg() != 0) + if (__rdpkey_reg() != shadow_pkey_reg) pkey_assert(0); __wrpkey_reg(shadow_pkey_reg); -- 1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:10 +0200 |
| Subject | [RFC v6 38/62] powerpc: implementation for arch_pkeys_enabled() |
| Message-ID | <u3J2x-2aY-11@gated-at.bofh.it> |
| In reply to | #1688056 |
arch_pkeys_enabled() returns true if the cpu
supports protection key, and the kernel has it
enabled.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
arch/powerpc/include/asm/pkeys.h | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h
index 7a9aade..ea43cb2 100644
--- a/arch/powerpc/include/asm/pkeys.h
+++ b/arch/powerpc/include/asm/pkeys.h
@@ -201,6 +201,11 @@ static inline int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
return __arch_set_user_pkey_access(tsk, pkey, init_val);
}
+static inline bool arch_pkeys_enabled(void)
+{
+ return pkey_inited;
+}
+
static inline void pkey_mm_init(struct mm_struct *mm)
{
if (!pkey_inited)
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:10 +0200 |
| Subject | [RFC v6 37/62] x86: implementation for arch_pkeys_enabled() |
| Message-ID | <u3J2x-2aY-13@gated-at.bofh.it> |
| In reply to | #1688056 |
arch_pkeys_enabled() returns true if the cpu
supports X86_FEATURE_OSPKE.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
arch/x86/include/asm/pkeys.h | 1 +
arch/x86/kernel/fpu/xstate.c | 5 +++++
2 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/arch/x86/include/asm/pkeys.h b/arch/x86/include/asm/pkeys.h
index b3b09b9..fa82799 100644
--- a/arch/x86/include/asm/pkeys.h
+++ b/arch/x86/include/asm/pkeys.h
@@ -5,6 +5,7 @@
extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
unsigned long init_val);
+extern bool arch_pkeys_enabled(void);
/*
* Try to dedicate one of the protection keys to be used as an
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
index c24ac1e..df594b8 100644
--- a/arch/x86/kernel/fpu/xstate.c
+++ b/arch/x86/kernel/fpu/xstate.c
@@ -918,6 +918,11 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
return 0;
}
+
+bool arch_pkeys_enabled(void)
+{
+ return boot_cpu_has(X86_FEATURE_OSPKE);
+}
#endif /* ! CONFIG_ARCH_HAS_PKEYS */
/*
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:10 +0200 |
| Subject | [RFC v6 46/62] selftest/vm: fix the wrong assert in pkey_disable_set() |
| Message-ID | <u3J2x-2aY-15@gated-at.bofh.it> |
| In reply to | #1688056 |
If the flag is 0, no bits will be set. Hence we cant expect
the resulting bitmap to have a higher value than what it
was earlier.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
tools/testing/selftests/vm/protection_keys.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/tools/testing/selftests/vm/protection_keys.c b/tools/testing/selftests/vm/protection_keys.c
index e5f5535..b2d7879 100644
--- a/tools/testing/selftests/vm/protection_keys.c
+++ b/tools/testing/selftests/vm/protection_keys.c
@@ -443,7 +443,7 @@ void pkey_disable_set(int pkey, int flags)
dprintf1("%s(%d) pkey_reg: 0x%lx\n",
__func__, pkey, rdpkey_reg());
if (flags)
- pkey_assert(rdpkey_reg() > orig_pkey_reg);
+ pkey_assert(rdpkey_reg() >= orig_pkey_reg);
dprintf1("END<---%s(%d, 0x%x)\n", __func__,
pkey, flags);
}
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:10 +0200 |
| Subject | [RFC v6 62/62] Documentation/vm: PowerPC specific updates to memory protection keys |
| Message-ID | <u3J2x-2aY-17@gated-at.bofh.it> |
| In reply to | #1688056 |
Add documentation updates that capture PowerPC specific changes. Signed-off-by: Ram Pai <linuxram@us.ibm.com> --- Documentation/vm/protection-keys.txt | 90 ++++++++++++++++++++++++--------- 1 files changed, 65 insertions(+), 25 deletions(-) diff --git a/Documentation/vm/protection-keys.txt b/Documentation/vm/protection-keys.txt index b643045..9330105 100644 --- a/Documentation/vm/protection-keys.txt +++ b/Documentation/vm/protection-keys.txt @@ -1,22 +1,45 @@ -Memory Protection Keys for Userspace (PKU aka PKEYs) is a CPU feature -which will be found on future Intel CPUs. - -Memory Protection Keys provides a mechanism for enforcing page-based -protections, but without requiring modification of the page tables -when an application changes protection domains. It works by -dedicating 4 previously ignored bits in each page table entry to a -"protection key", giving 16 possible keys. - -There is also a new user-accessible register (PKRU) with two separate -bits (Access Disable and Write Disable) for each key. Being a CPU -register, PKRU is inherently thread-local, potentially giving each -thread a different set of protections from every other thread. - -There are two new instructions (RDPKRU/WRPKRU) for reading and writing -to the new register. The feature is only available in 64-bit mode, -even though there is theoretically space in the PAE PTEs. These -permissions are enforced on data access only and have no effect on -instruction fetches. +Memory Protection Keys for Userspace (PKU aka PKEYs) is a CPU feature found on +future Intel CPUs and on PowerPC 7 and higher CPUs. + +Memory Protection Keys provide a mechanism for enforcing page-based +protections, but without requiring modification of the page tables when an +application changes protection domains. + +It works by dedicating bits in each page table entry to a "protection key". +There is also a user-accessible register with two separate bits for each +key. Being a CPU register, the user-accessible register is inherently +thread-local, potentially giving each thread a different set of protections +from every other thread. + +On Intel: + + Four previously bits are used the page table entry giving 16 possible keys. + + The user accessible register(PKRU) has a bit each per key to disable + access and to disable write. + + The feature is only available in 64-bit mode, even though there is + theoretically space in the PAE PTEs. These permissions are enforced on + data access only and have no effect on instruction fetches. + +On PowerPC: + + Five bits in the page table entry are used giving 32 possible keys. + This support is currently for Hash Page Table mode only. + + The user accessible register(AMR) has a bit each per key to disable + read and write. Access disable can be achieved by disabling + read and write. + + 'mtspr 0xd, mem' reads the AMR register + 'mfspr mem, 0xd' writes into the AMR register. + + Execution can be disabled by allocating a key with execute-disabled + permission. The execute-permissions on the key; however, cannot be + changed through a user accessible register. The CPU will not allow + execution of instruction in pages that are associated with + execute-disabled key. + =========================== Syscalls =========================== @@ -28,9 +51,9 @@ There are 3 system calls which directly interact with pkeys: unsigned long prot, int pkey); Before a pkey can be used, it must first be allocated with -pkey_alloc(). An application calls the WRPKRU instruction +pkey_alloc(). An application calls the WRPKRU/AMR instruction directly in order to change access permissions to memory covered -with a key. In this example WRPKRU is wrapped by a C function +with a key. In this example WRPKRU/AMR is wrapped by a C function called pkey_set(). int real_prot = PROT_READ|PROT_WRITE; @@ -52,11 +75,11 @@ is no longer in use: munmap(ptr, PAGE_SIZE); pkey_free(pkey); -(Note: pkey_set() is a wrapper for the RDPKRU and WRPKRU instructions. +(Note: pkey_set() is a wrapper for the RDPKRU,WRPKRU or AMR instructions. An example implementation can be found in - tools/testing/selftests/x86/protection_keys.c) + tools/testing/selftests/vm/protection_keys.c) -=========================== Behavior =========================== +=========================== Behavior ================================= The kernel attempts to make protection keys consistent with the behavior of a plain mprotect(). For instance if you do this: @@ -66,7 +89,7 @@ behavior of a plain mprotect(). For instance if you do this: you can expect the same effects with protection keys when doing this: - pkey = pkey_alloc(0, PKEY_DISABLE_WRITE | PKEY_DISABLE_READ); + pkey = pkey_alloc(0, PKEY_DISABLE_ACCESS); pkey_mprotect(ptr, size, PROT_READ|PROT_WRITE, pkey); something(ptr); @@ -83,3 +106,20 @@ with a read(): The kernel will send a SIGSEGV in both cases, but si_code will be set to SEGV_PKERR when violating protection keys versus SEGV_ACCERR when the plain mprotect() permissions are violated. + + +==================================================================== + Semantic differences + +The following semantic differences exist between x86 and power. + +a) powerpc *also* allows creation of a key with execute-disabled. + The following is allowed on powerpc. + pkey = pkey_alloc(0, PKEY_DISABLE_EXECUTE); + +b) changing the permission bits of a key from a signal handler does not + persist on x86. The PKRU specific fpregs entry needs to be modified + for it to persist. On powerpc the permission bits of the key can be + modified by programming the AMR register from the signal handler. + The changes persist across signal boundaries. +===================================================================== -- 1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:10 +0200 |
| Subject | [RFC v6 22/62] powerpc: ability to associate pkey to a vma |
| Message-ID | <u3J2y-2aY-21@gated-at.bofh.it> |
| In reply to | #1688056 |
arch-independent code expects the arch to map
a pkey into the vma's protection bit setting.
The patch provides that ability.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
arch/powerpc/include/asm/mman.h | 8 +++++++-
arch/powerpc/include/asm/pkeys.h | 18 +++++++++++++++---
2 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/include/asm/mman.h b/arch/powerpc/include/asm/mman.h
index 30922f6..067eec2 100644
--- a/arch/powerpc/include/asm/mman.h
+++ b/arch/powerpc/include/asm/mman.h
@@ -13,6 +13,7 @@
#include <asm/cputable.h>
#include <linux/mm.h>
+#include <linux/pkeys.h>
#include <asm/cpu_has_feature.h>
/*
@@ -22,7 +23,12 @@
static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot,
unsigned long pkey)
{
- return (prot & PROT_SAO) ? VM_SAO : 0;
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+ return (((prot & PROT_SAO) ? VM_SAO : 0) |
+ pkey_to_vmflag_bits(pkey));
+#else
+ return ((prot & PROT_SAO) ? VM_SAO : 0);
+#endif
}
#define arch_calc_vm_prot_bits(prot, pkey) arch_calc_vm_prot_bits(prot, pkey)
diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h
index 1864148..c92b049 100644
--- a/arch/powerpc/include/asm/pkeys.h
+++ b/arch/powerpc/include/asm/pkeys.h
@@ -14,14 +14,26 @@
PKEY_DISABLE_WRITE |\
PKEY_DISABLE_EXECUTE)
+#define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
+ VM_PKEY_BIT3 | VM_PKEY_BIT4)
+
+static inline u64 pkey_to_vmflag_bits(u16 pkey)
+{
+ if (!pkey_inited)
+ return 0x0UL;
+
+ return (((pkey & 0x1UL) ? VM_PKEY_BIT0 : 0x0UL) |
+ ((pkey & 0x2UL) ? VM_PKEY_BIT1 : 0x0UL) |
+ ((pkey & 0x4UL) ? VM_PKEY_BIT2 : 0x0UL) |
+ ((pkey & 0x8UL) ? VM_PKEY_BIT3 : 0x0UL) |
+ ((pkey & 0x10UL) ? VM_PKEY_BIT4 : 0x0UL));
+}
+
#define arch_max_pkey() 32
#define AMR_RD_BIT 0x1UL
#define AMR_WR_BIT 0x2UL
#define IAMR_EX_BIT 0x1UL
#define AMR_BITS_PER_PKEY 2
-#define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
- VM_PKEY_BIT3 | VM_PKEY_BIT4)
-#define AMR_BITS_PER_PKEY 2
/*
* Bits are in BE format.
* NOTE: key 31, 1, 0 are not used.
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:10 +0200 |
| Subject | [RFC v6 27/62] powerpc: helper to validate key-access permissions of a pte |
| Message-ID | <u3J2y-2aY-25@gated-at.bofh.it> |
| In reply to | #1688056 |
helper function that checks if the read/write/execute is allowed
on the pte.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
arch/powerpc/include/asm/book3s/64/pgtable.h | 4 +++
arch/powerpc/include/asm/pkeys.h | 12 +++++++++
arch/powerpc/mm/pkeys.c | 33 ++++++++++++++++++++++++++
3 files changed, 49 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index 30d7f55..0056e58 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -472,6 +472,10 @@ static inline void write_uamor(u64 value)
mtspr(SPRN_UAMOR, value);
}
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+extern bool arch_pte_access_permitted(u64 pte, bool write, bool execute);
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
unsigned long addr, pte_t *ptep)
diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h
index bbb5d85..7a9aade 100644
--- a/arch/powerpc/include/asm/pkeys.h
+++ b/arch/powerpc/include/asm/pkeys.h
@@ -53,6 +53,18 @@ static inline u64 pte_to_hpte_pkey_bits(u64 pteflags)
((pteflags & H_PAGE_PKEY_BIT4) ? HPTE_R_KEY_BIT4 : 0x0UL));
}
+static inline u16 pte_to_pkey_bits(u64 pteflags)
+{
+ if (!pkey_inited)
+ return 0x0UL;
+
+ return (((pteflags & H_PAGE_PKEY_BIT0) ? 0x10 : 0x0UL) |
+ ((pteflags & H_PAGE_PKEY_BIT1) ? 0x8 : 0x0UL) |
+ ((pteflags & H_PAGE_PKEY_BIT2) ? 0x4 : 0x0UL) |
+ ((pteflags & H_PAGE_PKEY_BIT3) ? 0x2 : 0x0UL) |
+ ((pteflags & H_PAGE_PKEY_BIT4) ? 0x1 : 0x0UL));
+}
+
static inline int vma_pkey(struct vm_area_struct *vma)
{
if (!pkey_inited)
diff --git a/arch/powerpc/mm/pkeys.c b/arch/powerpc/mm/pkeys.c
index 403f5ae..1794e17 100644
--- a/arch/powerpc/mm/pkeys.c
+++ b/arch/powerpc/mm/pkeys.c
@@ -201,3 +201,36 @@ int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot,
*/
return vma_pkey(vma);
}
+
+static bool pkey_access_permitted(int pkey, bool write, bool execute)
+{
+ int pkey_shift;
+ u64 amr;
+
+ if (!pkey)
+ return true;
+
+ pkey_shift = pkeyshift(pkey);
+ if (!(read_uamor() & (0x3UL << pkey_shift)))
+ return true;
+
+ if (execute && !(read_iamr() & (IAMR_EX_BIT << pkey_shift)))
+ return true;
+
+ if (!write) {
+ amr = read_amr();
+ if (!(amr & (AMR_RD_BIT << pkey_shift)))
+ return true;
+ }
+
+ amr = read_amr(); /* delay reading amr uptil absolutely needed */
+ return (write && !(amr & (AMR_WR_BIT << pkey_shift)));
+}
+
+bool arch_pte_access_permitted(u64 pte, bool write, bool execute)
+{
+ if (!pkey_inited)
+ return true;
+ return pkey_access_permitted(pte_to_pkey_bits(pte),
+ write, execute);
+}
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:10 +0200 |
| Subject | [RFC v6 30/62] powerpc: implementation for arch_vma_access_permitted() |
| Message-ID | <u3J2y-2aY-23@gated-at.bofh.it> |
| In reply to | #1688056 |
This patch provides the implementation for
arch_vma_access_permitted(). Returns true if the
requested access is allowed by pkey associated with the
vma.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
arch/powerpc/include/asm/mmu_context.h | 5 +++-
arch/powerpc/mm/pkeys.c | 43 ++++++++++++++++++++++++++++++++
2 files changed, 47 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h
index 7232484..635d4a6 100644
--- a/arch/powerpc/include/asm/mmu_context.h
+++ b/arch/powerpc/include/asm/mmu_context.h
@@ -175,6 +175,10 @@ static inline void arch_bprm_mm_init(struct mm_struct *mm,
{
}
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+bool arch_vma_access_permitted(struct vm_area_struct *vma,
+ bool write, bool execute, bool foreign);
+#else /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
bool write, bool execute, bool foreign)
{
@@ -182,7 +186,6 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
return true;
}
-#ifndef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
#define pkey_initialize()
#define pkey_mm_init(mm)
diff --git a/arch/powerpc/mm/pkeys.c b/arch/powerpc/mm/pkeys.c
index 1794e17..9999ce1 100644
--- a/arch/powerpc/mm/pkeys.c
+++ b/arch/powerpc/mm/pkeys.c
@@ -234,3 +234,46 @@ bool arch_pte_access_permitted(u64 pte, bool write, bool execute)
return pkey_access_permitted(pte_to_pkey_bits(pte),
write, execute);
}
+
+/*
+ * We only want to enforce protection keys on the current process
+ * because we effectively have no access to AMR/IAMR for other
+ * processes or any way to tell *which * AMR/IAMR in a threaded
+ * process we could use.
+ *
+ * So do not enforce things if the VMA is not from the current
+ * mm, or if we are in a kernel thread.
+ */
+static inline bool vma_is_foreign(struct vm_area_struct *vma)
+{
+ if (!current->mm)
+ return true;
+ /*
+ * if the VMA is from another process, then AMR/IAMR has no
+ * relevance and should not be enforced.
+ */
+ if (current->mm != vma->vm_mm)
+ return true;
+
+ return false;
+}
+
+bool arch_vma_access_permitted(struct vm_area_struct *vma,
+ bool write, bool execute, bool foreign)
+{
+ int pkey;
+
+ if (!pkey_inited)
+ return true;
+
+ /* allow access if the VMA is not one from this process */
+ if (foreign || vma_is_foreign(vma))
+ return true;
+
+ pkey = vma_pkey(vma);
+
+ if (!pkey)
+ return true;
+
+ return pkey_access_permitted(pkey, write, execute);
+}
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:10 +0200 |
| Subject | [RFC v6 44/62] selftest/vm: typecast the pkey register |
| Message-ID | <u3J2y-2aY-29@gated-at.bofh.it> |
| In reply to | #1688056 |
This is in preparation to accomadate a differing size register
across architectures.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
tools/testing/selftests/vm/pkey-helpers.h | 27 +++++-----
tools/testing/selftests/vm/protection_keys.c | 75 ++++++++++++++------------
2 files changed, 54 insertions(+), 48 deletions(-)
diff --git a/tools/testing/selftests/vm/pkey-helpers.h b/tools/testing/selftests/vm/pkey-helpers.h
index f378bc2..12260e8 100644
--- a/tools/testing/selftests/vm/pkey-helpers.h
+++ b/tools/testing/selftests/vm/pkey-helpers.h
@@ -17,6 +17,7 @@
#define u16 uint16_t
#define u32 uint32_t
#define u64 uint64_t
+#define pkey_reg_t u32
#ifdef __i386__
#define SYS_mprotect_key 380
@@ -76,12 +77,12 @@ static inline void sigsafe_printf(const char *format, ...)
#define dprintf3(args...) dprintf_level(3, args)
#define dprintf4(args...) dprintf_level(4, args)
-extern unsigned int shadow_pkey_reg;
-static inline unsigned int __rdpkey_reg(void)
+extern pkey_reg_t shadow_pkey_reg;
+static inline pkey_reg_t __rdpkey_reg(void)
{
unsigned int eax, edx;
unsigned int ecx = 0;
- unsigned int pkey_reg;
+ pkey_reg_t pkey_reg;
asm volatile(".byte 0x0f,0x01,0xee\n\t"
: "=a" (eax), "=d" (edx)
@@ -90,11 +91,11 @@ static inline unsigned int __rdpkey_reg(void)
return pkey_reg;
}
-static inline unsigned int _rdpkey_reg(int line)
+static inline pkey_reg_t _rdpkey_reg(int line)
{
- unsigned int pkey_reg = __rdpkey_reg();
+ pkey_reg_t pkey_reg = __rdpkey_reg();
- dprintf4("rdpkey_reg(line=%d) pkey_reg: %x shadow: %x\n",
+ dprintf4("rdpkey_reg(line=%d) pkey_reg: %016lx shadow: %016lx\n",
line, pkey_reg, shadow_pkey_reg);
assert(pkey_reg == shadow_pkey_reg);
@@ -103,11 +104,11 @@ static inline unsigned int _rdpkey_reg(int line)
#define rdpkey_reg() _rdpkey_reg(__LINE__)
-static inline void __wrpkey_reg(unsigned int pkey_reg)
+static inline void __wrpkey_reg(pkey_reg_t pkey_reg)
{
- unsigned int eax = pkey_reg;
- unsigned int ecx = 0;
- unsigned int edx = 0;
+ pkey_reg_t eax = pkey_reg;
+ pkey_reg_t ecx = 0;
+ pkey_reg_t edx = 0;
dprintf4("%s() changing %08x to %08x\n", __func__,
__rdpkey_reg(), pkey_reg);
@@ -116,7 +117,7 @@ static inline void __wrpkey_reg(unsigned int pkey_reg)
assert(pkey_reg == __rdpkey_reg());
}
-static inline void wrpkey_reg(unsigned int pkey_reg)
+static inline void wrpkey_reg(pkey_reg_t pkey_reg)
{
dprintf4("%s() changing %08x to %08x\n", __func__,
__rdpkey_reg(), pkey_reg);
@@ -134,7 +135,7 @@ static inline void wrpkey_reg(unsigned int pkey_reg)
*/
static inline void __pkey_access_allow(int pkey, int do_allow)
{
- unsigned int pkey_reg = rdpkey_reg();
+ pkey_reg_t pkey_reg = rdpkey_reg();
int bit = pkey * 2;
if (do_allow)
@@ -148,7 +149,7 @@ static inline void __pkey_access_allow(int pkey, int do_allow)
static inline void __pkey_write_allow(int pkey, int do_allow_write)
{
- long pkey_reg = rdpkey_reg();
+ pkey_reg_t pkey_reg = rdpkey_reg();
int bit = pkey * 2 + 1;
if (do_allow_write)
diff --git a/tools/testing/selftests/vm/protection_keys.c b/tools/testing/selftests/vm/protection_keys.c
index c345ff8..bd46f87 100644
--- a/tools/testing/selftests/vm/protection_keys.c
+++ b/tools/testing/selftests/vm/protection_keys.c
@@ -47,7 +47,7 @@
int iteration_nr = 1;
int test_nr;
-unsigned int shadow_pkey_reg;
+pkey_reg_t shadow_pkey_reg;
int dprint_in_signal;
char dprint_in_signal_buffer[DPRINT_IN_SIGNAL_BUF_SIZE];
@@ -157,7 +157,7 @@ void dump_mem(void *dumpme, int len_bytes)
for (i = 0; i < len_bytes; i += sizeof(u64)) {
u64 *ptr = (u64 *)(c + i);
- dprintf1("dump[%03d][@%p]: %016jx\n", i, ptr, *ptr);
+ dprintf1("dump[%03d][@%p]: %016lx\n", i, ptr, *ptr);
}
}
@@ -186,15 +186,16 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext)
int trapno;
unsigned long ip;
char *fpregs;
- u32 *pkey_reg_ptr;
- u64 si_pkey;
- u32 *si_pkey_ptr;
+ pkey_reg_t *pkey_reg_ptr;
+ u32 si_pkey;
+ pkey_reg_t *si_pkey_ptr;
int pkey_reg_offset;
fpregset_t fpregset;
dprint_in_signal = 1;
dprintf1(">>>>===============SIGSEGV============================\n");
- dprintf1("%s()::%d, pkey_reg: 0x%x shadow: %x\n", __func__, __LINE__,
+ dprintf1("%s()::%d, pkey_reg: 0x%016lx shadow: %016lx\n",
+ __func__, __LINE__,
__rdpkey_reg(), shadow_pkey_reg);
trapno = uctxt->uc_mcontext.gregs[REG_TRAPNO];
@@ -202,8 +203,9 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext)
fpregset = uctxt->uc_mcontext.fpregs;
fpregs = (void *)fpregset;
- dprintf2("%s() trapno: %d ip: 0x%lx info->si_code: %s/%d\n", __func__,
- trapno, ip, si_code_str(si->si_code), si->si_code);
+ dprintf2("%s() trapno: %d ip: 0x%016lx info->si_code: %s/%d\n",
+ __func__, trapno, ip, si_code_str(si->si_code),
+ si->si_code);
#ifdef __i386__
/*
* 32-bit has some extra padding so that userspace can tell whether
@@ -226,7 +228,7 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext)
dump_mem(pkey_reg_ptr - 128, 256);
pkey_assert(*pkey_reg_ptr);
- si_pkey_ptr = (u32 *)(((u8 *)si) + si_pkey_offset);
+ si_pkey_ptr = (pkey_reg_t *)(((u8 *)si) + si_pkey_offset);
dprintf1("si_pkey_ptr: %p\n", si_pkey_ptr);
dump_mem(si_pkey_ptr - 8, 24);
si_pkey = *si_pkey_ptr;
@@ -240,12 +242,12 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext)
exit(4);
}
- dprintf1("signal pkey_reg from xsave: %08x\n", *pkey_reg_ptr);
+ dprintf1("signal pkey_reg from xsave: %016lx\n", *pkey_reg_ptr);
/*
* need __rdpkey_reg() version so we do not do shadow_pkey_reg
* checking
*/
- dprintf1("signal pkey_reg from pkey_reg: %08x\n", __rdpkey_reg());
+ dprintf1("signal pkey_reg from pkey_reg: %016lx\n", __rdpkey_reg());
dprintf1("si_pkey from siginfo: %jx\n", si_pkey);
*(u64 *)pkey_reg_ptr = 0x00000000;
dprintf1("WARNING: set PRKU=0 to allow faulting instruction to continue\n");
@@ -364,8 +366,8 @@ void dumpit(char *f)
u32 pkey_get(int pkey, unsigned long flags)
{
u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE);
- u32 pkey_reg = __rdpkey_reg();
- u32 shifted_pkey_reg;
+ pkey_reg_t pkey_reg = __rdpkey_reg();
+ pkey_reg_t shifted_pkey_reg;
u32 masked_pkey_reg;
dprintf1("%s(pkey=%d, flags=%lx) = %x / %d\n",
@@ -386,8 +388,8 @@ u32 pkey_get(int pkey, unsigned long flags)
int pkey_set(int pkey, unsigned long rights, unsigned long flags)
{
u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE);
- u32 old_pkey_reg = __rdpkey_reg();
- u32 new_pkey_reg;
+ pkey_reg_t old_pkey_reg = __rdpkey_reg();
+ pkey_reg_t new_pkey_reg;
/* make sure that 'rights' only contains the bits we expect: */
assert(!(rights & ~mask));
@@ -401,10 +403,10 @@ int pkey_set(int pkey, unsigned long rights, unsigned long flags)
__wrpkey_reg(new_pkey_reg);
- dprintf3("%s(pkey=%d, rights=%lx, flags=%lx) = %x"
- " pkey_reg now: %x old_pkey_reg: %x\n",
- __func__, pkey, rights, flags, 0, __rdpkey_reg(),
- old_pkey_reg);
+ dprintf3("%s(pkey=%d, rights=%lx, flags=%lx) = %x "
+ "pkey_reg now: %016lx old_pkey_reg: %016lx\n",
+ __func__, pkey, rights, flags,
+ 0, __rdpkey_reg(), old_pkey_reg);
return 0;
}
@@ -413,7 +415,7 @@ void pkey_disable_set(int pkey, int flags)
unsigned long syscall_flags = 0;
int ret;
int pkey_rights;
- u32 orig_pkey_reg = rdpkey_reg();
+ pkey_reg_t orig_pkey_reg = rdpkey_reg();
dprintf1("START->%s(%d, 0x%x)\n", __func__,
pkey, flags);
@@ -421,8 +423,6 @@ void pkey_disable_set(int pkey, int flags)
pkey_rights = pkey_get(pkey, syscall_flags);
- dprintf1("%s(%d) pkey_get(%d): %x\n", __func__,
- pkey, pkey, pkey_rights);
pkey_assert(pkey_rights >= 0);
pkey_rights |= flags;
@@ -431,7 +431,8 @@ void pkey_disable_set(int pkey, int flags)
assert(!ret);
/*pkey_reg and flags have the same format */
shadow_pkey_reg |= flags << (pkey * 2);
- dprintf1("%s(%d) shadow: 0x%x\n", __func__, pkey, shadow_pkey_reg);
+ dprintf1("%s(%d) shadow: 0x%016lx\n",
+ __func__, pkey, shadow_pkey_reg);
pkey_assert(ret >= 0);
@@ -439,7 +440,8 @@ void pkey_disable_set(int pkey, int flags)
dprintf1("%s(%d) pkey_get(%d): %x\n", __func__,
pkey, pkey, pkey_rights);
- dprintf1("%s(%d) pkey_reg: 0x%x\n", __func__, pkey, rdpkey_reg());
+ dprintf1("%s(%d) pkey_reg: 0x%lx\n",
+ __func__, pkey, rdpkey_reg());
if (flags)
pkey_assert(rdpkey_reg() > orig_pkey_reg);
dprintf1("END<---%s(%d, 0x%x)\n", __func__,
@@ -451,7 +453,7 @@ void pkey_disable_clear(int pkey, int flags)
unsigned long syscall_flags = 0;
int ret;
int pkey_rights = pkey_get(pkey, syscall_flags);
- u32 orig_pkey_reg = rdpkey_reg();
+ pkey_reg_t orig_pkey_reg = rdpkey_reg();
pkey_assert(flags & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));
@@ -470,7 +472,8 @@ void pkey_disable_clear(int pkey, int flags)
dprintf1("%s(%d) pkey_get(%d): %x\n", __func__,
pkey, pkey, pkey_rights);
- dprintf1("%s(%d) pkey_reg: 0x%x\n", __func__, pkey, rdpkey_reg());
+ dprintf1("%s(%d) pkey_reg: 0x%016lx\n", __func__,
+ pkey, rdpkey_reg());
if (flags)
assert(rdpkey_reg() > orig_pkey_reg);
}
@@ -525,20 +528,21 @@ int alloc_pkey(void)
int ret;
unsigned long init_val = 0x0;
- dprintf1("%s()::%d, pkey_reg: 0x%x shadow: %x\n", __func__,
+ dprintf1("%s()::%d, pkey_reg: 0x%016lx shadow: %016lx\n", __func__,
__LINE__, __rdpkey_reg(), shadow_pkey_reg);
ret = sys_pkey_alloc(0, init_val);
/*
* pkey_alloc() sets PKEY register, so we need to reflect it in
* shadow_pkey_reg:
*/
- dprintf4("%s()::%d, ret: %d pkey_reg: 0x%x shadow: 0x%x\n",
+ dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016lx shadow: 0x%016lx\n",
__func__, __LINE__, ret, __rdpkey_reg(),
shadow_pkey_reg);
if (ret) {
/* clear both the bits: */
shadow_pkey_reg &= ~(0x3 << (ret * 2));
- dprintf4("%s()::%d, ret: %d pkey_reg: 0x%x shadow: 0x%x\n",
+ dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016lx "
+ "shadow: 0x%016lx\n",
__func__,
__LINE__, ret, __rdpkey_reg(),
shadow_pkey_reg);
@@ -548,13 +552,13 @@ int alloc_pkey(void)
*/
shadow_pkey_reg |= (init_val << (ret * 2));
}
- dprintf4("%s()::%d, ret: %d pkey_reg: 0x%x shadow: 0x%x\n",
+ dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016lx shadow: 0x%016lx\n",
__func__, __LINE__, ret, __rdpkey_reg(),
shadow_pkey_reg);
dprintf1("%s()::%d errno: %d\n", __func__, __LINE__, errno);
/* for shadow checking: */
rdpkey_reg();
- dprintf4("%s()::%d, ret: %d pkey_reg: 0x%x shadow: 0x%x\n",
+ dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016lx shadow: 0x%016lx\n",
__func__, __LINE__, ret, __rdpkey_reg(),
shadow_pkey_reg);
return ret;
@@ -1103,9 +1107,10 @@ void test_pkey_alloc_exhaust(int *ptr, u16 pkey)
int new_pkey;
dprintf1("%s() alloc loop: %d\n", __func__, i);
new_pkey = alloc_pkey();
- dprintf4("%s()::%d, err: %d pkey_reg: 0x%x shadow: 0x%x\n",
- __func__, __LINE__, err, __rdpkey_reg(),
- shadow_pkey_reg);
+ dprintf4("%s()::%d, err: %d pkey_reg: 0x%016lx "
+ "shadow: 0x%016lx\n",
+ __func__, __LINE__, err, __rdpkey_reg(),
+ shadow_pkey_reg);
rdpkey_reg(); /* for shadow checking */
dprintf2("%s() errno: %d ENOSPC: %d\n", __func__, errno, ENOSPC);
if ((new_pkey == -1) && (errno == ENOSPC)) {
@@ -1343,7 +1348,7 @@ int main(void)
}
pkey_setup_shadow();
- printf("startup pkey_reg: %x\n", rdpkey_reg());
+ printf("startup pkey_reg: 0x%016lx\n", rdpkey_reg());
setup_hugetlbfs();
while (nr_iterations-- > 0)
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Ram Pai <linuxram@us.ibm.com> |
|---|---|
| Date | 2017-07-16 06:10 +0200 |
| Subject | [RFC v6 24/62] powerpc: map vma key-protection bits to pte key bits. |
| Message-ID | <u3J2y-2aY-31@gated-at.bofh.it> |
| In reply to | #1688056 |
map the pkey bits in the pte from the key protection
bits of the vma.
The pte bits used for pkey are 3,4,5,6 and 57. The first
four bits are the same four bits that were freed up initially
in this patch series. remember? :-) Without those four bits
this patch would'nt be possible.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
---
arch/powerpc/include/asm/book3s/64/pgtable.h | 20 +++++++++++++++++++-
arch/powerpc/include/asm/mman.h | 8 ++++++++
arch/powerpc/include/asm/pkeys.h | 12 ++++++++++++
3 files changed, 39 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index d4da0e9..30d7f55 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -37,6 +37,7 @@
#define _RPAGE_RSV2 0x0800000000000000UL
#define _RPAGE_RSV3 0x0400000000000000UL
#define _RPAGE_RSV4 0x0200000000000000UL
+#define _RPAGE_RSV5 0x00040UL
#define _PAGE_PTE 0x4000000000000000UL /* distinguishes PTEs from pointers */
#define _PAGE_PRESENT 0x8000000000000000UL /* pte contains a translation */
@@ -56,6 +57,20 @@
/* Max physical address bit as per radix table */
#define _RPAGE_PA_MAX 57
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+#define H_PAGE_PKEY_BIT0 _RPAGE_RSV1
+#define H_PAGE_PKEY_BIT1 _RPAGE_RSV2
+#define H_PAGE_PKEY_BIT2 _RPAGE_RSV3
+#define H_PAGE_PKEY_BIT3 _RPAGE_RSV4
+#define H_PAGE_PKEY_BIT4 _RPAGE_RSV5
+#else /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+#define H_PAGE_PKEY_BIT0 0
+#define H_PAGE_PKEY_BIT1 0
+#define H_PAGE_PKEY_BIT2 0
+#define H_PAGE_PKEY_BIT3 0
+#define H_PAGE_PKEY_BIT4 0
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
/*
* Max physical address bit we will use for now.
*
@@ -116,13 +131,16 @@
#define _PAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HPTEFLAGS | _PAGE_DIRTY | \
_PAGE_ACCESSED | _PAGE_SPECIAL | _PAGE_PTE | \
_PAGE_SOFT_DIRTY)
+
+#define H_PAGE_PKEY (H_PAGE_PKEY_BIT0 | H_PAGE_PKEY_BIT1 | H_PAGE_PKEY_BIT2 | \
+ H_PAGE_PKEY_BIT3 | H_PAGE_PKEY_BIT4)
/*
* Mask of bits returned by pte_pgprot()
*/
#define PAGE_PROT_BITS (_PAGE_SAO | _PAGE_NON_IDEMPOTENT | _PAGE_TOLERANT | \
H_PAGE_4K_PFN | _PAGE_PRIVILEGED | _PAGE_ACCESSED | \
_PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_EXEC | \
- _PAGE_SOFT_DIRTY)
+ _PAGE_SOFT_DIRTY | H_PAGE_PKEY)
/*
* We define 2 sets of base prot bits, one for basic pages (ie,
* cacheable kernel and user pages) and one for non cacheable
diff --git a/arch/powerpc/include/asm/mman.h b/arch/powerpc/include/asm/mman.h
index 067eec2..3f7220f 100644
--- a/arch/powerpc/include/asm/mman.h
+++ b/arch/powerpc/include/asm/mman.h
@@ -32,12 +32,20 @@ static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot,
}
#define arch_calc_vm_prot_bits(prot, pkey) arch_calc_vm_prot_bits(prot, pkey)
+
static inline pgprot_t arch_vm_get_page_prot(unsigned long vm_flags)
{
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+ return (vm_flags & VM_SAO) ?
+ __pgprot(_PAGE_SAO | vmflag_to_page_pkey_bits(vm_flags)) :
+ __pgprot(0 | vmflag_to_page_pkey_bits(vm_flags));
+#else
return (vm_flags & VM_SAO) ? __pgprot(_PAGE_SAO) : __pgprot(0);
+#endif
}
#define arch_vm_get_page_prot(vm_flags) arch_vm_get_page_prot(vm_flags)
+
static inline bool arch_validate_prot(unsigned long prot)
{
if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM | PROT_SAO))
diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h
index 94013af..ad39db0 100644
--- a/arch/powerpc/include/asm/pkeys.h
+++ b/arch/powerpc/include/asm/pkeys.h
@@ -29,6 +29,18 @@ static inline u64 pkey_to_vmflag_bits(u16 pkey)
((pkey & 0x10UL) ? VM_PKEY_BIT4 : 0x0UL));
}
+static inline u64 vmflag_to_page_pkey_bits(u64 vm_flags)
+{
+ if (!pkey_inited)
+ return 0x0UL;
+
+ return (((vm_flags & VM_PKEY_BIT0) ? H_PAGE_PKEY_BIT4 : 0x0UL) |
+ ((vm_flags & VM_PKEY_BIT1) ? H_PAGE_PKEY_BIT3 : 0x0UL) |
+ ((vm_flags & VM_PKEY_BIT2) ? H_PAGE_PKEY_BIT2 : 0x0UL) |
+ ((vm_flags & VM_PKEY_BIT3) ? H_PAGE_PKEY_BIT1 : 0x0UL) |
+ ((vm_flags & VM_PKEY_BIT4) ? H_PAGE_PKEY_BIT0 : 0x0UL));
+}
+
static inline int vma_pkey(struct vm_area_struct *vma)
{
if (!pkey_inited)
--
1.7.1
[toc] | [prev] | [next] | [standalone]
Page 1 of 3 [1] 2 3 Next page →
Back to top | Article view | linux.kernel
csiph-web