Skip to contentSkip to conversation

powerpc: Free up RPAGE_RSV bits

PATCH Superseded Ram Pai 5 participants 134 messages Sep 8, 2017 – Oct 30, 2017

Subsystems (4)

v1 of 9 Superseded Latest is v9 →

lore
Share & tools
lore

Ram Pai

author
#0 lore raw

cover powerpc: Free up RPAGE_RSV bits

RPAGE_RSV0..4 pte bits are currently used for hpte slot

tracking. We  need  these bits   for  memory-protection
keys. Luckily these  four bits   are  relatively easier 

to move among all the other candidate bits.

For 64K linux-ptes backed by 4k hptes, these bits
are used for tracking the validity of the slot value
stored in the second-part-of-the-pte. We device a new
mechanism for tracking the validity without using
those bits. The mechanism is explained in the patch.

For 64K linux-pte backed by 64K hptes, we simply move
the slot tracking bits to the second-part-of-the-pte.

The above mechanism is also used to free the bits for hugetlb linux-ptes.

For 4k linux-pte, we have only 3 free bits available. We swizzle around the bits and release RPAGE_RSV{2,3,4} for memory protection keys.

Testing:
--------
has survived kernel compilation on multiple platforms p8 powernv hash-mode, p9 powernv hash-mode, p7 powervm, p8-powervm, p8-kvm-guest.

Has survived git-bisect on p8 power-nv with 64K page and 4K page.

History:
-------
This patchset is a spin-off from the memkey patchset.

version v9:
(1) rearranged the patch order. First the helper
routines are defined followed by the
patches that make use of the helpers.

version v8:

	(1) an  additional  patch   added  to  free  up
             RSV{2,3,4} on 4K linux-pte.

version v7:
(1) GIX bit reset change moved to the second patch -- noticed by Aneesh.
(2) Separated this patches from memkey patchset
(3) merged a bunch of patches, that used the helper function, into one.
version v6:
(1) No changes related to pte.

version v5:
(1) No changes related to pte.

version v4:
(1) No changes related to pte.

version v3:
(1) split the patches into smaller consumable patches.
(2) A bug fix while invalidating a hpte slot in __hash_page_4K()
-- noticed by Aneesh

version v2:
(1) 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.

version v1: Initial version

Ram Pai (7):
powerpc: introduce pte_set_hash_slot() helper
powerpc: introduce pte_get_hash_gslot() helper
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: Swizzle around 4K PTE bits to free up bit 5 and bit 6
powerpc: use helper functions to get and set hash slots
powerpc: capture the PTE format changes in the dump pte report

 arch/powerpc/include/asm/book3s/64/hash-4k.h  |   21 ++++
 arch/powerpc/include/asm/book3s/64/hash-64k.h |   61 ++++++++----
 arch/powerpc/include/asm/book3s/64/hash.h     |    8 +-
 arch/powerpc/mm/dump_linuxpagetables.c        |    3 +-
 arch/powerpc/mm/hash64_4k.c                   |   14 +--
 arch/powerpc/mm/hash64_64k.c                  |  131 +++++++++++++------------
 arch/powerpc/mm/hash_utils_64.c               |   35 +++++--
 arch/powerpc/mm/hugetlbpage-hash64.c          |   18 ++--
 8 files changed, 171 insertions(+), 120 deletions(-)
author
#1 lore raw

PATCH 1/7 powerpc: introduce pte_set_hash_slot() helper

Introduce pte_set_hash_slot().It sets the (H_PAGE_F_SECOND|H_PAGE_F_GIX)
bits at the appropriate location in the PTE of 4K PTE. For
64K PTE, it sets the bits in the second part of the PTE. Though the implementation for the former just needs the slot parameter, it does take some additional parameters to keep the prototype consistent.

This function will be handy as we work towards re-arranging the
bits in the later patches.

---
 arch/powerpc/include/asm/book3s/64/hash-4k.h  |   15 +++++++++++++++
 arch/powerpc/include/asm/book3s/64/hash-64k.h |   25 +++++++++++++++++++++++++
 2 files changed, 40 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/book3s/64/hash-4k.h +15 -0
index 0c4e470..8909039 100644
@@ -48,6 +48,21 @@ static inline int hash__hugepd_ok(hugepd_t hpd)
 }
 #endif
 
+/*
+ * 4k pte format is  different  from  64k  pte  format.  Saving  the
+ * hash_slot is just a matter of returning the pte bits that need to
+ * be modified. On 64k pte, things are a  little  more  involved and
+ * hence  needs   many   more  parameters  to  accomplish  the  same.
+ * However we  want  to abstract this out from the caller by keeping
+ * the prototype consistent across the two formats.
+ */
+static inline unsigned long pte_set_hash_slot(pte_t *ptep, real_pte_t rpte,
+			unsigned int subpg_index, unsigned long slot)
+{
+	return (slot << H_PAGE_F_GIX_SHIFT) &
+		(H_PAGE_F_SECOND | H_PAGE_F_GIX);
+}
+
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 
 static inline char *get_hpte_slot_array(pmd_t *pmdp)
arch/powerpc/include/asm/book3s/64/hash-64k.h +25 -0
index 9732837..6652669 100644
@@ -74,6 +74,31 @@ static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index)
 	return (pte_val(rpte.pte) >> H_PAGE_F_GIX_SHIFT) & 0xf;
 }
 
+/*
+ * Commit the hash slot and return pte bits that needs to be modified.
+ * The caller is expected to modify the pte bits accordingly and
+ * commit the pte to memory.
+ */
+static inline unsigned long pte_set_hash_slot(pte_t *ptep, real_pte_t rpte,
+		unsigned int subpg_index, unsigned long slot)
+{
+	unsigned long *hidxp = (unsigned long *)(ptep + PTRS_PER_PTE);
+
+	rpte.hidx &= ~(0xfUL << (subpg_index << 2));
+	*hidxp = rpte.hidx  | (slot << (subpg_index << 2));
+	/*
+	 * Commit the hidx bits to memory before returning.
+	 * Anyone reading  pte  must  ensure hidx bits are
+	 * read  only  after  reading the pte by using the
+	 * read-side  barrier  smp_rmb(). __real_pte() can
+	 * help ensure that.
+	 */
+	smp_wmb();
+
+	/* no pte bits to be modified, return 0x0UL */
+	return 0x0UL;
+}
+
 #define __rpte_to_pte(r)	((r).pte)
 extern bool __rpte_sub_valid(real_pte_t rpte, unsigned long index);
 /*
Signature · 1 line
1.7.1
Acked-by on v1 1/7
#2 lore raw

Re: [PATCH 1/7] powerpc: introduce pte_set_hash_slot() helper

Quoted 56 lines · Ram Pai

Introduce pte_set_hash_slot().It sets the (H_PAGE_F_SECOND|H_PAGE_F_GIX)
bits at the appropriate location in the PTE of 4K PTE. For
64K PTE, it sets the bits in the second part of the PTE. Though the implementation for the former just needs the slot parameter, it does take some additional parameters to keep the prototype consistent.

This function will be handy as we work towards re-arranging the
bits in the later patches.

---
 arch/powerpc/include/asm/book3s/64/hash-4k.h  |   15 +++++++++++++++
 arch/powerpc/include/asm/book3s/64/hash-64k.h |   25 +++++++++++++++++++++++++
 2 files changed, 40 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/book3s/64/hash-4k.h +15 -0
index 0c4e470..8909039 100644
@@ -48,6 +48,21 @@ static inline int hash__hugepd_ok(hugepd_t hpd)
 }
 #endif
 
+/*
+ * 4k pte format is  different  from  64k  pte  format.  Saving  the
+ * hash_slot is just a matter of returning the pte bits that need to
+ * be modified. On 64k pte, things are a  little  more  involved and
+ * hence  needs   many   more  parameters  to  accomplish  the  same.
+ * However we  want  to abstract this out from the caller by keeping
+ * the prototype consistent across the two formats.
+ */
+static inline unsigned long pte_set_hash_slot(pte_t *ptep, real_pte_t rpte,
+                       unsigned int subpg_index, unsigned long slot)
+{
+       return (slot << H_PAGE_F_GIX_SHIFT) &
+               (H_PAGE_F_SECOND | H_PAGE_F_GIX);
+}
+
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 
 static inline char *get_hpte_slot_array(pmd_t *pmdp)
arch/powerpc/include/asm/book3s/64/hash-64k.h +6 -0
index 9732837..6652669 100644
@@ -74,6 +74,31 @@ static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index)
        return (pte_val(rpte.pte) >> H_PAGE_F_GIX_SHIFT) & 0xf;
 }
 
+/*
+ * Commit the hash slot and return pte bits that needs to be modified.
+ * The caller is expected to modify the pte bits accordingly and
+ * commit the pte to memory.
+ */
+static inline unsigned long pte_set_hash_slot(pte_t *ptep, real_pte_t rpte,

arch/powerpc/include/asm/book3s/64/hash-64k.h static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index) · line 92

Quoted 10 lines
arch/powerpc/include/asm/book3s/64/hash-64k.h +10 -0
+               unsigned int subpg_index, unsigned long slot)
+{
+       unsigned long *hidxp = (unsigned long *)(ptep + PTRS_PER_PTE);
+
+       rpte.hidx &= ~(0xfUL << (subpg_index << 2));
+       *hidxp = rpte.hidx  | (slot << (subpg_index << 2));
+       /*
+        * Commit the hidx bits to memory before returning.
+        * Anyone reading  pte  must  ensure hidx bits are
+        * read  only  after  reading the pte by using the

Can you lose the only and make it "read after reading the pte" read only is easy to confuse as read-only

arch/powerpc/include/asm/book3s/64/hash-64k.h static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index) · line 99

Quoted 7 lines
arch/powerpc/include/asm/book3s/64/hash-64k.h +7 -0
+        * read-side  barrier  smp_rmb(). __real_pte() can
+        * help ensure that.
+        */
+       smp_wmb();
+
+       /* no pte bits to be modified, return 0x0UL */
+       return 0x0UL;

Balbir Singh.

#3 lore raw

Re: [PATCH 1/7] powerpc: introduce pte_set_hash_slot() helper

In reply to Ram Pai
Quoted 10 lines · Ram Pai
arch/powerpc/include/asm/book3s/64/hash-64k.h +2 -0
index 9732837..6652669 100644
@@ -74,6 +74,31 @@ static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index)
 	return (pte_val(rpte.pte) >> H_PAGE_F_GIX_SHIFT) & 0xf;
 }
 
+/*
+ * Commit the hash slot and return pte bits that needs to be modified.

arch/powerpc/include/asm/book3s/64/hash-64k.h static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index) · line 88

Quoted 10 lines
arch/powerpc/include/asm/book3s/64/hash-64k.h +10 -0
+ * The caller is expected to modify the pte bits accordingly and
+ * commit the pte to memory.
+ */
+static inline unsigned long pte_set_hash_slot(pte_t *ptep, real_pte_t rpte,
+		unsigned int subpg_index, unsigned long slot)
+{
+	unsigned long *hidxp = (unsigned long *)(ptep + PTRS_PER_PTE);
+
+	rpte.hidx &= ~(0xfUL << (subpg_index << 2));
+	*hidxp = rpte.hidx  | (slot << (subpg_index << 2));

^
stray space here

arch/powerpc/include/asm/book3s/64/hash-64k.h static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index) · line 90

Quoted 2 lines
arch/powerpc/include/asm/book3s/64/hash-64k.h +2 -0
+	/*
+	 * Commit the hidx bits to memory before returning.

I'd prefer we didn't use "commit", it implies the bits are actually written to memory by the barrier, which is not true. The barrier is just a barrier or fence which prevents some reorderings of the things before it and the things after it.

arch/powerpc/include/asm/book3s/64/hash-64k.h static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index)

Quoted 3 lines
arch/powerpc/include/asm/book3s/64/hash-64k.h +3 -0
+	 * Anyone reading  pte  must  ensure hidx bits are
+	 * read  only  after  reading the pte by using the
+	 * read-side  barrier  smp_rmb().

That seems OK. Though I'm reminded that I dislike your justified comments, the odd spacing is jarring to read.

arch/powerpc/include/asm/book3s/64/hash-64k.h static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index) · line 95

Quoted 2 lines
arch/powerpc/include/asm/book3s/64/hash-64k.h +1 -0
         __real_pte() can
+	 * help ensure that.

It doesn't help, it *does* do that.

cheers

author
#4 lore raw

PATCH 2/7 powerpc: introduce pte_get_hash_gslot() helper

In reply to Ram Pai

Introduce pte_get_hash_gslot()() which returns the slot number of the HPTE in the global hash table.

This function will come in handy as we work towards re-arranging the PTE bits in the later patches.

---
 arch/powerpc/include/asm/book3s/64/hash.h |    3 +++
 arch/powerpc/mm/hash_utils_64.c           |   18 ++++++++++++++++++
 2 files changed, 21 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/book3s/64/hash.h +3 -0
index f884520..060c059 100644
@@ -166,6 +166,9 @@ static inline int hash__pte_none(pte_t pte)
 	return (pte_val(pte) & ~H_PTE_NONE_MASK) == 0;
 }
 
+unsigned long pte_get_hash_gslot(unsigned long vpn, unsigned long shift,
+		int ssize, real_pte_t rpte, unsigned int subpg_index);
+
 /* This low level function performs the actual PTE insertion
  * Setting the PTE depends on the MMU type and other factors. It's
  * an horrible mess that I'm not going to try to clean up now but
arch/powerpc/mm/hash_utils_64.c +18 -0
index 67ec2e9..e68f053 100644
@@ -1591,6 +1591,24 @@ static inline void tm_flush_hash_page(int local)
 }
 #endif
 
+/*
+ * return the global hash slot, corresponding to the given
+ * pte, which contains the hpte.
+ */
+unsigned long pte_get_hash_gslot(unsigned long vpn, unsigned long shift,
+		int ssize, real_pte_t rpte, unsigned int subpg_index)
+{
+	unsigned long hash, slot, hidx;
+
+	hash = hpt_hash(vpn, shift, ssize);
+	hidx = __rpte_to_hidx(rpte, subpg_index);
+	if (hidx & _PTEIDX_SECONDARY)
+		hash = ~hash;
+	slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+	slot += hidx & _PTEIDX_GROUP_IX;
+	return slot;
+}
+
 /* WARNING: This is called from hash_low_64.S, if you change this prototype,
  *          do not forget to update the assembly call site !
  */
Signature · 1 line
1.7.1
#5 lore raw

Re: [PATCH 2/7] powerpc: introduce pte_get_hash_gslot() helper

Quoted 32 lines · Ram Pai

Introduce pte_get_hash_gslot()() which returns the slot number of the HPTE in the global hash table.

This function will come in handy as we work towards re-arranging the PTE bits in the later patches.

---
 arch/powerpc/include/asm/book3s/64/hash.h |    3 +++
 arch/powerpc/mm/hash_utils_64.c           |   18 ++++++++++++++++++
 2 files changed, 21 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/book3s/64/hash.h +3 -0
index f884520..060c059 100644
@@ -166,6 +166,9 @@ static inline int hash__pte_none(pte_t pte)
        return (pte_val(pte) & ~H_PTE_NONE_MASK) == 0;
 }
 
+unsigned long pte_get_hash_gslot(unsigned long vpn, unsigned long shift,
+               int ssize, real_pte_t rpte, unsigned int subpg_index);
+
 /* This low level function performs the actual PTE insertion
  * Setting the PTE depends on the MMU type and other factors. It's
  * an horrible mess that I'm not going to try to clean up now but
arch/powerpc/mm/hash_utils_64.c +0 -0
index 67ec2e9..e68f053 100644

arch/powerpc/mm/hash_utils_64.c static inline void tm_flush_hash_page(int local) · line 1596

Quoted 6 lines
arch/powerpc/mm/hash_utils_64.c +3 -0
@@ -1591,6 +1591,24 @@ static inline void tm_flush_hash_page(int local)
 }
 #endif
 
+/*
+ * return the global hash slot, corresponding to the given
+ * pte, which contains the hpte.

Does this work with native/guest page tables? I guess both. The comment sounds trivial, could you please elaborate more. Looking at the code, it seems like given a real pte, we use the hash value and hidx to figure out the slot value in the global slot information. This uses information in the software page tables. Is that correct? Do we have to consider validity and present state here or is that guaranteed?

Quoted 8 lines
arch/powerpc/mm/hash_utils_64.c +8 -0
+ */
+unsigned long pte_get_hash_gslot(unsigned long vpn, unsigned long shift,
+               int ssize, real_pte_t rpte, unsigned int subpg_index)
+{
+       unsigned long hash, slot, hidx;
+
+       hash = hpt_hash(vpn, shift, ssize);
+       hidx = __rpte_to_hidx(rpte, subpg_index);

arch/powerpc/mm/hash_utils_64.c static inline void tm_flush_hash_page(int local) · line 1614

Quoted 10 lines
arch/powerpc/mm/hash_utils_64.c +7 -0
+       if (hidx & _PTEIDX_SECONDARY)
+               hash = ~hash;
+       slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+       slot += hidx & _PTEIDX_GROUP_IX;
+       return slot;
+}
+
 /* WARNING: This is called from hash_low_64.S, if you change this prototype,
  *          do not forget to update the assembly call site !
  */

Balbir Singh.

author
#6 lore raw

Re: [PATCH 2/7] powerpc: introduce pte_get_hash_gslot() helper

Quoted 36 lines · Balbir Singh
Quoted 35 lines · Ram Pai

Introduce pte_get_hash_gslot()() which returns the slot number of the HPTE in the global hash table.

This function will come in handy as we work towards re-arranging the PTE bits in the later patches.

---
 arch/powerpc/include/asm/book3s/64/hash.h |    3 +++
 arch/powerpc/mm/hash_utils_64.c           |   18 ++++++++++++++++++
 2 files changed, 21 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/book3s/64/hash.h +3 -0
index f884520..060c059 100644
@@ -166,6 +166,9 @@ static inline int hash__pte_none(pte_t pte)
        return (pte_val(pte) & ~H_PTE_NONE_MASK) == 0;
 }
 
+unsigned long pte_get_hash_gslot(unsigned long vpn, unsigned long shift,
+               int ssize, real_pte_t rpte, unsigned int subpg_index);
+
 /* This low level function performs the actual PTE insertion
  * Setting the PTE depends on the MMU type and other factors. It's
  * an horrible mess that I'm not going to try to clean up now but
arch/powerpc/mm/hash_utils_64.c +0 -0
index 67ec2e9..e68f053 100644
@@ -1591,6 +1591,24 @@ static inline void tm_flush_hash_page(int local)
 }
 #endif
 
Quoted 5 lines

arch/powerpc/mm/hash_utils_64.c static inline void tm_flush_hash_page(int local) · line 1596

Quoted 3 lines
arch/powerpc/mm/hash_utils_64.c +3 -0
+/*
+ * return the global hash slot, corresponding to the given
+ * pte, which contains the hpte.

Does this work with native/guest page tables? I guess both.

Yes. it is supposed to work with native as well as guest page tables. The code has been this way for ages. This patch encapsulate the logic in a standalone function.

Quoted 5 lines

The comment sounds trivial, could you please elaborate more. Looking at the code, it seems like given a real pte, we use the hash value and hidx to figure out the slot value in the global slot information. This uses information in the software page tables. Is that correct?

Yes. This uses information passed to it by the caller, the information is expected to be derived from linux page table.

Quoted 2 lines

Do we have to consider validity and
present state here or is that guaranteed?

This function's job is to do the math and return the global slot based on the input. It will return the calculated value regardless of the validity of its inputs.

Its the the callers' job to validate the pte and ensure that it is hashed, before meaningfully using the return value of the this function.

Quoted 21 lines
Quoted 9 lines
arch/powerpc/mm/hash_utils_64.c +8 -0
+ */
+unsigned long pte_get_hash_gslot(unsigned long vpn, unsigned long shift,
+               int ssize, real_pte_t rpte, unsigned int subpg_index)
+{
+       unsigned long hash, slot, hidx;
+
+       hash = hpt_hash(vpn, shift, ssize);
+       hidx = __rpte_to_hidx(rpte, subpg_index);

arch/powerpc/mm/hash_utils_64.c static inline void tm_flush_hash_page(int local) · line 1614

Quoted 10 lines
arch/powerpc/mm/hash_utils_64.c +7 -0
+       if (hidx & _PTEIDX_SECONDARY)
+               hash = ~hash;
+       slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+       slot += hidx & _PTEIDX_GROUP_IX;
+       return slot;
+}
+
 /* WARNING: This is called from hash_low_64.S, if you change this prototype,
  *          do not forget to update the assembly call site !
  */

Balbir Singh.

Signature · 1 line
Ram Pai
author
#7 lore raw

PATCH 3/7 powerpc: Free up four 64K PTE bits in 4K backed HPTE pages

In reply to Ram Pai

Rearrange 64K PTE bits to free up bits 3, 4, 5 and 6, in the 4K backed HPTE pages.These bits continue to be used for 64K backed HPTE pages in this patch, but will be freed up in the next patch. The bit numbers are big-endian as defined in the ISA3.0

The patch does the following change to the 4k htpe backed 64K PTE's format.

H_PAGE_BUSY moves from bit 3 to bit 9 (B bit in the figure
below)
V0 which occupied bit 4 is not used anymore.
V1 which occupied bit 5 is not used anymore.
V2 which occupied bit 6 is not used anymore.
V3 which occupied bit 7 is not used anymore.

Before the patch, the 4k backed 64k PTE format was as follows

 0 1 2 3 4  5  6  7  8 9 10...........................63
 : : : : :  :  :  :  : : :                            :
 v v v v v  v  v  v  v v v                            v

,-,-,-,-,--,--,--,--,-,-,-,-,-,------------------,-,-,-, |x|x|x|B|V0|V1|V2|V3|x| | |x|x|................|x|x|x|x| <- primary pte '_'_'_'_'__'__'__'__'_'_'_'_'_'________________'_'_'_'_' |S|G|I|X|S |G |I |X |S|G|I|X|..................|S|G|I|X| <- secondary pte '_'_'_'_'__'__'__'__'_'_'_'_'__________________'_'_'_'_'

After the patch, the 4k backed 64k PTE format is as follows

 0 1 2 3 4  5  6  7  8 9 10...........................63
 : : : : :  :  :  :  : : :                            :
 v v v v v  v  v  v  v v v                            v

,-,-,-,-,--,--,--,--,-,-,-,-,-,------------------,-,-,-, |x|x|x| | | | | |x|B| |x|x|................|.|.|.|.| <- primary pte '_'_'_'_'__'__'__'__'_'_'_'_'_'________________'_'_'_'_' |S|G|I|X|S |G |I |X |S|G|I|X|..................|S|G|I|X| <- secondary pte '_'_'_'_'__'__'__'__'_'_'_'_'__________________'_'_'_'_'

the four bits S,G,I,X (one quadruplet per 4k HPTE) that cache the hash-bucket slot value, is initialized to
1,1,1,1 indicating -- an invalid slot. If a HPTE gets
cached in a 1111 slot(i.e 7th slot of secondary hash bucket), it is released immediately. In other words,
even though 1111 is a valid slot value in the hash
bucket, we consider it invalid and release the slot and the HPTE. This gives us the opportunity to determine the validity of S,G,I,X bits based on its contents and not on any of the bits V0,V1,V2 or V3 in the primary PTE

When   we  release  a    HPTE    cached in the 1111 slot
we also    release  a  legitimate   slot  in the primary

hash bucket and unmap its corresponding HPTE. This
is to ensure that we do get a HPTE cached in a slot
of the primary hash bucket, the next time we retry.

Though treating 1111 slot as invalid, reduces the number of available slots in the hash bucket and may
have an effect on the performance, the probabilty of
hitting a 1111 slot is extermely low.

Compared to the current scheme, the above scheme
reduces the number of false hash table updates
significantly and has the added advantage of releasing four valuable PTE bits for other purpose.

NOTE:even though bits 3, 4, 5, 6, 7 are not used when the 64K PTE is backed by 4k HPTE, they continue to be used if the PTE gets backed by 64k HPTE. The next patch will decouple that aswell, and truely release the bits.

This idea was jointly developed by Paul Mackerras, Aneesh, Michael Ellermen and myself.

4K PTE format remains unchanged currently.

The patch does the following code changes
a) PTE flags are split between 64k and 4k header files.
b) __hash_page_4K() is reimplemented to reflect the
above logic.

---
 arch/powerpc/include/asm/book3s/64/hash-4k.h  |    2 +
 arch/powerpc/include/asm/book3s/64/hash-64k.h |    8 +--
 arch/powerpc/include/asm/book3s/64/hash.h     |    1 -
 arch/powerpc/mm/hash64_64k.c                  |  106 +++++++++++++------------
 arch/powerpc/mm/hash_utils_64.c               |    4 +-
 5 files changed, 63 insertions(+), 58 deletions(-)
arch/powerpc/include/asm/book3s/64/hash-4k.h +2 -0
index 8909039..e66bfeb 100644
@@ -16,6 +16,8 @@
 #define H_PUD_TABLE_SIZE	(sizeof(pud_t) << H_PUD_INDEX_SIZE)
 #define H_PGD_TABLE_SIZE	(sizeof(pgd_t) << H_PGD_INDEX_SIZE)
 
+#define H_PAGE_BUSY	_RPAGE_RSV1     /* software: PTE & hash are busy */
+
 /* PTE flags to conserve for HPTE identification */
 #define _PAGE_HPTEFLAGS (H_PAGE_BUSY | H_PAGE_HASHPTE | \
 			 H_PAGE_F_SECOND | H_PAGE_F_GIX)
arch/powerpc/include/asm/book3s/64/hash-64k.h +2 -6
index 6652669..e038f1c 100644
@@ -12,18 +12,14 @@
  */
 #define H_PAGE_COMBO	_RPAGE_RPN0 /* this is a combo 4k page */
 #define H_PAGE_4K_PFN	_RPAGE_RPN1 /* PFN is for a single 4k page */
+#define H_PAGE_BUSY	_RPAGE_RPN42     /* software: PTE & hash are busy */
+
 /*
  * We need to differentiate between explicit huge page and THP huge
  * page, since THP huge page also need to track real subpage details
  */
 #define H_PAGE_THP_HUGE  H_PAGE_4K_PFN
 
-/*
- * Used to track subpage group valid if H_PAGE_COMBO is set
- * This overloads H_PAGE_F_GIX and H_PAGE_F_SECOND
- */
-#define H_PAGE_COMBO_VALID	(H_PAGE_F_GIX | H_PAGE_F_SECOND)
-
 /* PTE flags to conserve for HPTE identification */
 #define _PAGE_HPTEFLAGS (H_PAGE_BUSY | H_PAGE_F_SECOND | \
 			 H_PAGE_F_GIX | H_PAGE_HASHPTE | H_PAGE_COMBO)
arch/powerpc/include/asm/book3s/64/hash.h +0 -1
index 060c059..8ce4112 100644
@@ -9,7 +9,6 @@
  */
 #define H_PTE_NONE_MASK		_PAGE_HPTEFLAGS
 #define H_PAGE_F_GIX_SHIFT	56
-#define H_PAGE_BUSY		_RPAGE_RSV1 /* software: PTE & hash are busy */
 #define H_PAGE_F_SECOND		_RPAGE_RSV2	/* HPTE is in 2ndary HPTEG */
 #define H_PAGE_F_GIX		(_RPAGE_RSV3 | _RPAGE_RSV4 | _RPAGE_RPN44)
 #define H_PAGE_HASHPTE		_RPAGE_RPN43	/* PTE has associated HPTE */
arch/powerpc/mm/hash64_64k.c +56 -50

162 lines not on this page · raw message

arch/powerpc/mm/hash_utils_64.c +3 -1
index e68f053..a40c7bc 100644
@@ -978,8 +978,9 @@ void __init hash__early_init_devtree(void)
 
 void __init hash__early_init_mmu(void)
 {
+#ifndef CONFIG_PPC_64K_PAGES
 	/*
-	 * We have code in __hash_page_64K() and elsewhere, which assumes it can
+	 * We have code in __hash_page_4K() and elsewhere, which assumes it can
 	 * do the following:
 	 *   new_pte |= (slot << H_PAGE_F_GIX_SHIFT) & (H_PAGE_F_SECOND | H_PAGE_F_GIX);
 	 *
@@ -990,6 +991,7 @@ void __init hash__early_init_mmu(void)
 	 * with a BUILD_BUG_ON().
 	 */
 	BUILD_BUG_ON(H_PAGE_F_SECOND != (1ul  << (H_PAGE_F_GIX_SHIFT + 3)));
+#endif /* CONFIG_PPC_64K_PAGES */
 
 	htab_init_page_sizes();
 
Signature · 1 line
1.7.1
Acked-by on v1 3/7
#8 lore raw

Re: [PATCH 3/7] powerpc: Free up four 64K PTE bits in 4K backed HPTE pages

Quoted 67 lines · On Fri, 8 Sep 2017 15:44:43 -0700 Ram Pai <[email protected]> wrote:

Rearrange 64K PTE bits to free up bits 3, 4, 5 and 6, in the 4K backed HPTE pages.These bits continue to be used for 64K backed HPTE pages in this patch, but will be freed up in the next patch. The bit numbers are big-endian as defined in the ISA3.0

The patch does the following change to the 4k htpe backed 64K PTE's format.

H_PAGE_BUSY moves from bit 3 to bit 9 (B bit in the figure
below)
V0 which occupied bit 4 is not used anymore.
V1 which occupied bit 5 is not used anymore.
V2 which occupied bit 6 is not used anymore.
V3 which occupied bit 7 is not used anymore.

Before the patch, the 4k backed 64k PTE format was as follows

 0 1 2 3 4  5  6  7  8 9 10...........................63
 : : : : :  :  :  :  : : :                            :
 v v v v v  v  v  v  v v v                            v

,-,-,-,-,--,--,--,--,-,-,-,-,-,------------------,-,-,-, |x|x|x|B|V0|V1|V2|V3|x| | |x|x|................|x|x|x|x| <- primary pte '_'_'_'_'__'__'__'__'_'_'_'_'_'________________'_'_'_'_' |S|G|I|X|S |G |I |X |S|G|I|X|..................|S|G|I|X| <- secondary pte '_'_'_'_'__'__'__'__'_'_'_'_'__________________'_'_'_'_'

After the patch, the 4k backed 64k PTE format is as follows

 0 1 2 3 4  5  6  7  8 9 10...........................63
 : : : : :  :  :  :  : : :                            :
 v v v v v  v  v  v  v v v                            v

,-,-,-,-,--,--,--,--,-,-,-,-,-,------------------,-,-,-, |x|x|x| | | | | |x|B| |x|x|................|.|.|.|.| <- primary pte '_'_'_'_'__'__'__'__'_'_'_'_'_'________________'_'_'_'_' |S|G|I|X|S |G |I |X |S|G|I|X|..................|S|G|I|X| <- secondary pte '_'_'_'_'__'__'__'__'_'_'_'_'__________________'_'_'_'_'

the four bits S,G,I,X (one quadruplet per 4k HPTE) that cache the hash-bucket slot value, is initialized to
1,1,1,1 indicating -- an invalid slot. If a HPTE gets
cached in a 1111 slot(i.e 7th slot of secondary hash bucket), it is released immediately. In other words,
even though 1111 is a valid slot value in the hash
bucket, we consider it invalid and release the slot and the HPTE. This gives us the opportunity to determine the validity of S,G,I,X bits based on its contents and not on any of the bits V0,V1,V2 or V3 in the primary PTE

When   we  release  a    HPTE    cached in the 1111 slot
we also    release  a  legitimate   slot  in the primary

hash bucket and unmap its corresponding HPTE. This
is to ensure that we do get a HPTE cached in a slot
of the primary hash bucket, the next time we retry.

Though treating 1111 slot as invalid, reduces the number of available slots in the hash bucket and may
have an effect on the performance, the probabilty of
hitting a 1111 slot is extermely low.

Compared to the current scheme, the above scheme
reduces the number of false hash table updates
significantly and has the added advantage of releasing four valuable PTE bits for other purpose.

Quoted 9 lines

NOTE:even though bits 3, 4, 5, 6, 7 are not used when the 64K PTE is backed by 4k HPTE, they continue to be used if the PTE gets backed by 64k HPTE. The next patch will decouple that aswell, and truely release the bits.

This idea was jointly developed by Paul Mackerras, Aneesh, Michael Ellermen and myself.

#9 lore raw

Re: [PATCH 3/7] powerpc: Free up four 64K PTE bits in 4K backed HPTE pages

In reply to Ram Pai
Quoted 8 lines · Ram Pai
arch/powerpc/mm/hash64_64k.c +0 -0
index 1a68cb1..c6c5559 100644
@@ -126,18 +113,13 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 	if (__rpte_sub_valid(rpte, subpg_index)) {
 		int ret;
 

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 119

Quoted 10 lines
arch/powerpc/mm/hash64_64k.c +4 -6
-		hash = hpt_hash(vpn, shift, ssize);
-		hidx = __rpte_to_hidx(rpte, subpg_index);
-		if (hidx & _PTEIDX_SECONDARY)
-			hash = ~hash;
-		slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
-		slot += hidx & _PTEIDX_GROUP_IX;
+		gslot = pte_get_hash_gslot(vpn, shift, ssize, rpte,
+					subpg_index);
+		ret = mmu_hash_ops.hpte_updatepp(gslot, rflags, vpn,
+			MMU_PAGE_4K, MMU_PAGE_4K, ssize, flags);

This was formatted correctly before:

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 122

Quoted 6 lines
arch/powerpc/mm/hash64_64k.c +1 -4
-		ret = mmu_hash_ops.hpte_updatepp(slot, rflags, vpn,
-						 MMU_PAGE_4K, MMU_PAGE_4K,
-						 ssize, flags);
 		/*
-		 *if we failed because typically the HPTE wasn't really here
+		 * if we failed because typically the HPTE wasn't really here

If you're fixing it up please make it "If ...".

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 138

Quoted 13 lines
arch/powerpc/mm/hash64_64k.c +6 -0
 		 * we try an insertion.
 		 */
 		if (ret == -1)
@@ -148,6 +130,15 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 	}
 
 htab_insert_hpte:
+
+	/*
+	 * initialize all hidx entries to invalid value,
+	 * the first time the PTE is about to allocate
+	 * a 4K hpte
+	 */

Should be:

	/*
	 * Initialize all hidx entries to invalid value, the first time
         * the PTE is about to allocate a 4K HPTE.
	 */

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 141

Quoted 3 lines
arch/powerpc/mm/hash64_64k.c +3 -0
+	if (!(old_pte & H_PAGE_COMBO))
+		rpte.hidx = ~0x0UL;
+

Paul had the idea that if we biased the slot number by 1, we could make the "invalid" value be == 0.

That would avoid needing to that above, and also mean the value is correctly invalid from the get-go, which would be good IMO.

I think now that you've added the slot accessors it would be pretty easy to do.

Quoted 22 lines
arch/powerpc/mm/hash64_64k.c +6 -2
 	/*
 	 * handle H_PAGE_4K_PFN case
 	 */
@@ -172,15 +163,41 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 	 * Primary is full, try the secondary
 	 */
 	if (unlikely(slot == -1)) {
+		bool soft_invalid;
+
 		hpte_group = ((~hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL;
 		slot = mmu_hash_ops.hpte_insert(hpte_group, vpn, pa,
 						rflags, HPTE_V_SECONDARY,
 						MMU_PAGE_4K, MMU_PAGE_4K,
 						ssize);
-		if (slot == -1) {
-			if (mftb() & 0x1)
+
+		soft_invalid = hpte_soft_invalid(slot);
+		if (unlikely(soft_invalid)) {
 
 
+			/*

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 188

Quoted 10 lines
arch/powerpc/mm/hash64_64k.c +10 -0
+			 * we got a valid slot from a hardware point of view.
+			 * but we cannot use it, because we use this special
+			 * value; as     defined   by    hpte_soft_invalid(),
+			 * to  track    invalid  slots.  We  cannot  use  it.
+			 * So invalidate it.
+			 */
+			gslot = slot & _PTEIDX_GROUP_IX;
+			mmu_hash_ops.hpte_invalidate(hpte_group+gslot, vpn,
+				MMU_PAGE_4K, MMU_PAGE_4K,
+				ssize, 0);

Please:

			mmu_hash_ops.hpte_invalidate(hpte_group+gslot, vpn,
                        			     MMU_PAGE_4K, MMU_PAGE_4K,
						     ssize, 0);

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 191

Quoted 5 lines
arch/powerpc/mm/hash64_64k.c +5 -0
+		}
+
+		if (unlikely(slot == -1 || soft_invalid)) {
+			/*
+			 * for soft invalid slot, lets   ensure that we

For .. let's

cheers

author
#10 lore raw

Re: [PATCH 3/7] powerpc: Free up four 64K PTE bits in 4K backed HPTE pages

Quoted 59 lines · Michael Ellerman
Quoted 8 lines · Ram Pai
arch/powerpc/mm/hash64_64k.c +0 -0
index 1a68cb1..c6c5559 100644
@@ -126,18 +113,13 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 	if (__rpte_sub_valid(rpte, subpg_index)) {
 		int ret;
 

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 119

Quoted 10 lines
arch/powerpc/mm/hash64_64k.c +4 -6
-		hash = hpt_hash(vpn, shift, ssize);
-		hidx = __rpte_to_hidx(rpte, subpg_index);
-		if (hidx & _PTEIDX_SECONDARY)
-			hash = ~hash;
-		slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
-		slot += hidx & _PTEIDX_GROUP_IX;
+		gslot = pte_get_hash_gslot(vpn, shift, ssize, rpte,
+					subpg_index);
+		ret = mmu_hash_ops.hpte_updatepp(gslot, rflags, vpn,
+			MMU_PAGE_4K, MMU_PAGE_4K, ssize, flags);

This was formatted correctly before:

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 122

Quoted 6 lines
arch/powerpc/mm/hash64_64k.c +1 -4
-		ret = mmu_hash_ops.hpte_updatepp(slot, rflags, vpn,
-						 MMU_PAGE_4K, MMU_PAGE_4K,
-						 ssize, flags);
 		/*
-		 *if we failed because typically the HPTE wasn't really here
+		 * if we failed because typically the HPTE wasn't really here

If you're fixing it up please make it "If ...".

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 138

Quoted 13 lines
arch/powerpc/mm/hash64_64k.c +6 -0
 		 * we try an insertion.
 		 */
 		if (ret == -1)
@@ -148,6 +130,15 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 	}
 
 htab_insert_hpte:
+
+	/*
+	 * initialize all hidx entries to invalid value,
+	 * the first time the PTE is about to allocate
+	 * a 4K hpte
+	 */

Should be:

	/*
	 * Initialize all hidx entries to invalid value, the first time
         * the PTE is about to allocate a 4K HPTE.
	 */

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 141

Quoted 3 lines
arch/powerpc/mm/hash64_64k.c +3 -0
+	if (!(old_pte & H_PAGE_COMBO))
+		rpte.hidx = ~0x0UL;
+

Paul had the idea that if we biased the slot number by 1, we could make the "invalid" value be == 0.

Quoted 5 lines

That would avoid needing to that above, and also mean the value is correctly invalid from the get-go, which would be good IMO.

I think now that you've added the slot accessors it would be pretty easy to do.

I did attempt to do so, and was not getting it right. The machine went unstable. So left it with an accessor, to be revisited at a later point in time. That time has come... I suppose. Shall I make it a separate patch instead of baking it into this patch?

RP

#11 lore raw

Re: [PATCH 3/7] powerpc: Free up four 64K PTE bits in 4K backed HPTE pages

In reply to Michael Ellerman
Quoted 59 lines · Michael Ellerman
Quoted 8 lines · Ram Pai
arch/powerpc/mm/hash64_64k.c +0 -0
index 1a68cb1..c6c5559 100644
@@ -126,18 +113,13 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 	if (__rpte_sub_valid(rpte, subpg_index)) {
 		int ret;
 

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 119

Quoted 10 lines
arch/powerpc/mm/hash64_64k.c +4 -6
-		hash = hpt_hash(vpn, shift, ssize);
-		hidx = __rpte_to_hidx(rpte, subpg_index);
-		if (hidx & _PTEIDX_SECONDARY)
-			hash = ~hash;
-		slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
-		slot += hidx & _PTEIDX_GROUP_IX;
+		gslot = pte_get_hash_gslot(vpn, shift, ssize, rpte,
+					subpg_index);
+		ret = mmu_hash_ops.hpte_updatepp(gslot, rflags, vpn,
+			MMU_PAGE_4K, MMU_PAGE_4K, ssize, flags);

This was formatted correctly before:

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 122

Quoted 6 lines
arch/powerpc/mm/hash64_64k.c +1 -4
-		ret = mmu_hash_ops.hpte_updatepp(slot, rflags, vpn,
-						 MMU_PAGE_4K, MMU_PAGE_4K,
-						 ssize, flags);
 		/*
-		 *if we failed because typically the HPTE wasn't really here
+		 * if we failed because typically the HPTE wasn't really here

If you're fixing it up please make it "If ...".

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 138

Quoted 13 lines
arch/powerpc/mm/hash64_64k.c +6 -0
 		 * we try an insertion.
 		 */
 		if (ret == -1)
@@ -148,6 +130,15 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 	}
 
 htab_insert_hpte:
+
+	/*
+	 * initialize all hidx entries to invalid value,
+	 * the first time the PTE is about to allocate
+	 * a 4K hpte
+	 */

Should be:

	/*
	 * Initialize all hidx entries to invalid value, the first time
         * the PTE is about to allocate a 4K HPTE.
	 */

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 141

Quoted 3 lines
arch/powerpc/mm/hash64_64k.c +3 -0
+	if (!(old_pte & H_PAGE_COMBO))
+		rpte.hidx = ~0x0UL;
+

Paul had the idea that if we biased the slot number by 1, we could make the "invalid" value be == 0.

Quoted 5 lines

That would avoid needing to that above, and also mean the value is correctly invalid from the get-go, which would be good IMO.

I think now that you've added the slot accessors it would be pretty easy to do.

That would be imply, we loose one slot in primary group, which means we will do extra work in some case because our primary now has only 7 slots. And in case of pseries, the hypervisor will always return the least available slot, which implie we will do extra hcalls in case of an hpte insert to an empty group?

-aneesh

author
#12 lore raw

Re: [PATCH 3/7] powerpc: Free up four 64K PTE bits in 4K backed HPTE pages

Quoted 64 lines · Aneesh Kumar K.V
Quoted 62 lines · Michael Ellerman
Quoted 8 lines · Ram Pai
arch/powerpc/mm/hash64_64k.c +0 -0
index 1a68cb1..c6c5559 100644
@@ -126,18 +113,13 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 	if (__rpte_sub_valid(rpte, subpg_index)) {
 		int ret;
 

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 119

Quoted 10 lines
arch/powerpc/mm/hash64_64k.c +4 -6
-		hash = hpt_hash(vpn, shift, ssize);
-		hidx = __rpte_to_hidx(rpte, subpg_index);
-		if (hidx & _PTEIDX_SECONDARY)
-			hash = ~hash;
-		slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
-		slot += hidx & _PTEIDX_GROUP_IX;
+		gslot = pte_get_hash_gslot(vpn, shift, ssize, rpte,
+					subpg_index);
+		ret = mmu_hash_ops.hpte_updatepp(gslot, rflags, vpn,
+			MMU_PAGE_4K, MMU_PAGE_4K, ssize, flags);

This was formatted correctly before:

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 122

Quoted 6 lines
arch/powerpc/mm/hash64_64k.c +1 -4
-		ret = mmu_hash_ops.hpte_updatepp(slot, rflags, vpn,
-						 MMU_PAGE_4K, MMU_PAGE_4K,
-						 ssize, flags);
 		/*
-		 *if we failed because typically the HPTE wasn't really here
+		 * if we failed because typically the HPTE wasn't really here

If you're fixing it up please make it "If ...".

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 138

Quoted 13 lines
arch/powerpc/mm/hash64_64k.c +6 -0
 		 * we try an insertion.
 		 */
 		if (ret == -1)
@@ -148,6 +130,15 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 	}
 
 htab_insert_hpte:
+
+	/*
+	 * initialize all hidx entries to invalid value,
+	 * the first time the PTE is about to allocate
+	 * a 4K hpte
+	 */

Should be:

	/*
	 * Initialize all hidx entries to invalid value, the first time
         * the PTE is about to allocate a 4K HPTE.
	 */

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 141

Quoted 3 lines
arch/powerpc/mm/hash64_64k.c +3 -0
+	if (!(old_pte & H_PAGE_COMBO))
+		rpte.hidx = ~0x0UL;
+

Paul had the idea that if we biased the slot number by 1, we could make the "invalid" value be == 0.

That would avoid needing to that above, and also mean the value is correctly invalid from the get-go, which would be good IMO.

Quoted 8 lines
Quoted 2 lines

I think now that you've added the slot accessors it would be pretty easy to do.

That would be imply, we loose one slot in primary group, which means we will do extra work in some case because our primary now has only 7 slots. And in case of pseries, the hypervisor will always return the least available slot, which implie we will do extra hcalls in case of an hpte insert to an empty group?

No. that is not the idea. The idea is that slot 'F' in the seconday will continue to be a invalid slot, but will be represented as offset-by-one in the PTE. In other words, 0 will be repesented as 1,
1 as 2.... and n as (n+1)%32

The idea seems feasible. It has the advantage -- where 0 in the PTE means invalid slot. But it can be confusing to the casual code- reader. Will need to put in a big-huge comment to explain that.

RP

#13 lore raw

Re: [PATCH 3/7] powerpc: Free up four 64K PTE bits in 4K backed HPTE pages

Quoted 3 lines · Ram Pai
Quoted 2 lines · Aneesh Kumar K.V
Quoted 1 line · Michael Ellerman

Ram Pai <[email protected]> writes:

...

Quoted 25 lines
Quoted 16 lines
Quoted 16 lines

Should be:

	/*
	 * Initialize all hidx entries to invalid value, the first time
         * the PTE is about to allocate a 4K HPTE.
	 */

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 141

Quoted 3 lines
arch/powerpc/mm/hash64_64k.c +3 -0
+	if (!(old_pte & H_PAGE_COMBO))
+		rpte.hidx = ~0x0UL;
+

Paul had the idea that if we biased the slot number by 1, we could make the "invalid" value be == 0.

That would avoid needing to that above, and also mean the value is correctly invalid from the get-go, which would be good IMO.

Quoted 8 lines
Quoted 2 lines

I think now that you've added the slot accessors it would be pretty easy to do.

That would be imply, we loose one slot in primary group, which means we will do extra work in some case because our primary now has only 7 slots. And in case of pseries, the hypervisor will always return the least available slot, which implie we will do extra hcalls in case of an hpte insert to an empty group?

Quoted 4 lines

No. that is not the idea. The idea is that slot 'F' in the seconday will continue to be a invalid slot, but will be represented as offset-by-one in the PTE. In other words, 0 will be repesented as 1,
1 as 2.... and n as (n+1)%32

Right.

Quoted 3 lines

The idea seems feasible. It has the advantage -- where 0 in the PTE means invalid slot. But it can be confusing to the casual code- reader. Will need to put in a big-huge comment to explain that.

This code is already confusing to *any* reader, so I don't think it's a worry. :)

cheers

author
#14 lore raw

Re: [PATCH 3/7] powerpc: Free up four 64K PTE bits in 4K backed HPTE pages

Quoted 35 lines · Michael Ellerman
Quoted 3 lines · Ram Pai
Quoted 2 lines · Aneesh Kumar K.V
Quoted 1 line · Michael Ellerman

Ram Pai <[email protected]> writes:

...

Quoted 25 lines
Quoted 16 lines
Quoted 16 lines

Should be:

	/*
	 * Initialize all hidx entries to invalid value, the first time
         * the PTE is about to allocate a 4K HPTE.
	 */

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 141

Quoted 3 lines
arch/powerpc/mm/hash64_64k.c +3 -0
+	if (!(old_pte & H_PAGE_COMBO))
+		rpte.hidx = ~0x0UL;
+

Paul had the idea that if we biased the slot number by 1, we could make the "invalid" value be == 0.

That would avoid needing to that above, and also mean the value is correctly invalid from the get-go, which would be good IMO.

Quoted 8 lines
Quoted 2 lines

I think now that you've added the slot accessors it would be pretty easy to do.

That would be imply, we loose one slot in primary group, which means we will do extra work in some case because our primary now has only 7 slots. And in case of pseries, the hypervisor will always return the least available slot, which implie we will do extra hcalls in case of an hpte insert to an empty group?

Quoted 4 lines

No. that is not the idea. The idea is that slot 'F' in the seconday will continue to be a invalid slot, but will be represented as offset-by-one in the PTE. In other words, 0 will be repesented as 1,
1 as 2.... and n as (n+1)%32

Quoted 8 lines

Right.

Quoted 3 lines

The idea seems feasible. It has the advantage -- where 0 in the PTE means invalid slot. But it can be confusing to the casual code- reader. Will need to put in a big-huge comment to explain that.

This code is already confusing to *any* reader, so I don't think it's a worry. :)

I just got it coded and working. But I see no advantage implementing the shifted-value. The hidx in the secondary-part of the pte, still needs to be initialzed to all-zeros. Because it could contain the value of the hidx corresponding the 64k-backed hpte, which needs to be cleared.

I will send the patch anyway. But we should not apply it for I see no apparent gain.

RP

Quoted 2 lines

cheers

Signature · 1 line
Ram Pai
author
#15 lore raw

PATCH 4/7 powerpc: Free up four 64K PTE bits in 64K backed HPTE pages

In reply to Ram Pai

Rearrange 64K PTE bits to free up bits 3, 4, 5 and 6 in the 64K backed HPTE pages. This along with the earlier patch will entirely free up the four bits from 64K PTE. The bit numbers are big-endian as defined in the ISA3.0

This patch does the following change to 64K PTE backed by 64K HPTE.

H_PAGE_F_SECOND (S) which occupied bit 4 moves to the
second part of the pte to bit 60.
H_PAGE_F_GIX (G,I,X) which occupied bit 5, 6 and 7 also

	moves  to  the   second part of the pte to bit 61,
       	62, 63, 64 respectively

since bit 7 is now freed up, we move H_PAGE_BUSY (B) from bit 9 to bit 7.

The second part of the PTE will hold (H_PAGE_F_SECOND|H_PAGE_F_GIX) at bit 60,61,62,63.
NOTE: None of the bits in the secondary PTE were not used by 64k-HPTE backed PTE.

Before the patch, the 64K HPTE backed 64k PTE format was as follows

 0 1 2 3 4  5  6  7  8 9 10...........................63
 : : : : :  :  :  :  : : :                            :
 v v v v v  v  v  v  v v v                            v

,-,-,-,-,--,--,--,--,-,-,-,-,-,------------------,-,-,-, |x|x|x| |S |G |I |X |x|B| |x|x|................|x|x|x|x| <- primary pte '_'_'_'_'__'__'__'__'_'_'_'_'_'________________'_'_'_'_'
| | | | | | | | | | | | |..................| | | | | <- secondary pte '_'_'_'_'__'__'__'__'_'_'_'_'__________________'_'_'_'_'

After the patch, the 64k HPTE backed 64k PTE format is as follows

 0 1 2 3 4  5  6  7  8 9 10...........................63
 : : : : :  :  :  :  : : :                            :
 v v v v v  v  v  v  v v v                            v

,-,-,-,-,--,--,--,--,-,-,-,-,-,------------------,-,-,-, |x|x|x| | | | |B |x| | |x|x|................|.|.|.|.| <- primary pte '_'_'_'_'__'__'__'__'_'_'_'_'_'________________'_'_'_'_'
| | | | | | | | | | | | |..................|S|G|I|X| <- secondary pte '_'_'_'_'__'__'__'__'_'_'_'_'__________________'_'_'_'_'

The above PTE changes is applicable to hugetlbpages aswell.

The patch does the following code changes:

a) moves the H_PAGE_F_SECOND and H_PAGE_F_GIX to 4k PTE
header since it is no more needed b the 64k PTEs.
b) abstracts out __real_pte() and __rpte_to_hidx() so the caller need not know the bit location of the slot.
c) moves the slot bits to the secondary pte.

---
 arch/powerpc/include/asm/book3s/64/hash-4k.h  |    3 ++
 arch/powerpc/include/asm/book3s/64/hash-64k.h |   29 +++++++++++-------------
 arch/powerpc/include/asm/book3s/64/hash.h     |    3 --
 arch/powerpc/mm/hash64_64k.c                  |   23 ++++++++-----------
 arch/powerpc/mm/hugetlbpage-hash64.c          |   18 ++++++---------
 5 files changed, 33 insertions(+), 43 deletions(-)
arch/powerpc/include/asm/book3s/64/hash-4k.h +3 -0
index e66bfeb..dc153c6 100644
@@ -16,6 +16,9 @@
 #define H_PUD_TABLE_SIZE	(sizeof(pud_t) << H_PUD_INDEX_SIZE)
 #define H_PGD_TABLE_SIZE	(sizeof(pgd_t) << H_PGD_INDEX_SIZE)
 
+#define H_PAGE_F_GIX_SHIFT	56
+#define H_PAGE_F_SECOND	_RPAGE_RSV2	/* HPTE is in 2ndary HPTEG */
+#define H_PAGE_F_GIX	(_RPAGE_RSV3 | _RPAGE_RSV4 | _RPAGE_RPN44)
 #define H_PAGE_BUSY	_RPAGE_RSV1     /* software: PTE & hash are busy */
 
 /* PTE flags to conserve for HPTE identification */
arch/powerpc/include/asm/book3s/64/hash-64k.h +13 -16
index e038f1c..89ef5a9 100644
@@ -12,7 +12,7 @@
  */
 #define H_PAGE_COMBO	_RPAGE_RPN0 /* this is a combo 4k page */
 #define H_PAGE_4K_PFN	_RPAGE_RPN1 /* PFN is for a single 4k page */
-#define H_PAGE_BUSY	_RPAGE_RPN42     /* software: PTE & hash are busy */
+#define H_PAGE_BUSY	_RPAGE_RPN44     /* software: PTE & hash are busy */
 
 /*
  * We need to differentiate between explicit huge page and THP huge
@@ -21,8 +21,7 @@
 #define H_PAGE_THP_HUGE  H_PAGE_4K_PFN
 
 /* PTE flags to conserve for HPTE identification */
-#define _PAGE_HPTEFLAGS (H_PAGE_BUSY | H_PAGE_F_SECOND | \
-			 H_PAGE_F_GIX | H_PAGE_HASHPTE | H_PAGE_COMBO)
+#define _PAGE_HPTEFLAGS (H_PAGE_BUSY | H_PAGE_HASHPTE | H_PAGE_COMBO)
 /*
  * we support 16 fragments per PTE page of 64K size.
  */
@@ -50,24 +49,22 @@ static inline real_pte_t __real_pte(pte_t pte, pte_t *ptep)
 	unsigned long *hidxp;
 
 	rpte.pte = pte;
-	rpte.hidx = 0;
-	if (pte_val(pte) & H_PAGE_COMBO) {
-		/*
-		 * Make sure we order the hidx load against the H_PAGE_COMBO
-		 * check. The store side ordering is done in __hash_page_4K
-		 */
-		smp_rmb();
-		hidxp = (unsigned long *)(ptep + PTRS_PER_PTE);
-		rpte.hidx = *hidxp;
-	}
+	/*
+	 * Ensure that we do not read the hidx before we read
+	 * the pte. Because the writer side is  expected
+	 * to finish writing the hidx first followed by the pte,
+	 * by using smp_wmb().
+	 * pte_set_hash_slot() ensures that.
+	 */
+	smp_rmb();
+	hidxp = (unsigned long *)(ptep + PTRS_PER_PTE);
+	rpte.hidx = *hidxp;
 	return rpte;
 }
 
 static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index)
 {
-	if ((pte_val(rpte.pte) & H_PAGE_COMBO))
-		return (rpte.hidx >> (index<<2)) & 0xf;
-	return (pte_val(rpte.pte) >> H_PAGE_F_GIX_SHIFT) & 0xf;
+	return ((rpte.hidx >> (index<<2)) & 0xfUL);
 }
 
 /*
arch/powerpc/include/asm/book3s/64/hash.h +0 -3
index 8ce4112..46f3a23 100644
@@ -8,9 +8,6 @@
  *
  */
 #define H_PTE_NONE_MASK		_PAGE_HPTEFLAGS
-#define H_PAGE_F_GIX_SHIFT	56
-#define H_PAGE_F_SECOND		_RPAGE_RSV2	/* HPTE is in 2ndary HPTEG */
-#define H_PAGE_F_GIX		(_RPAGE_RSV3 | _RPAGE_RSV4 | _RPAGE_RPN44)
 #define H_PAGE_HASHPTE		_RPAGE_RPN43	/* PTE has associated HPTE */
 
 #ifdef CONFIG_PPC_64K_PAGES
arch/powerpc/mm/hash64_64k.c +10 -13
index c6c5559..9c63844 100644
@@ -103,8 +103,8 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 		 * On hash insert failure we use old pte value and we don't
 		 * want slot information there if we have a insert failure.
 		 */
-		old_pte &= ~(H_PAGE_HASHPTE | H_PAGE_F_GIX | H_PAGE_F_SECOND);
-		new_pte &= ~(H_PAGE_HASHPTE | H_PAGE_F_GIX | H_PAGE_F_SECOND);
+		old_pte &= ~H_PAGE_HASHPTE;
+		new_pte &= ~H_PAGE_HASHPTE;
 		goto htab_insert_hpte;
 	}
 	/*
@@ -227,6 +227,7 @@ int __hash_page_64K(unsigned long ea, unsigned long access,
 		    unsigned long vsid, pte_t *ptep, unsigned long trap,
 		    unsigned long flags, int ssize)
 {
+	real_pte_t rpte;
 	unsigned long hpte_group;
 	unsigned long rflags, pa;
 	unsigned long old_pte, new_pte;
@@ -263,6 +264,7 @@ int __hash_page_64K(unsigned long ea, unsigned long access,
 	} while (!pte_xchg(ptep, __pte(old_pte), __pte(new_pte)));
 
 	rflags = htab_convert_pte_flags(new_pte);
+	rpte = __real_pte(__pte(old_pte), ptep);
 
 	if (cpu_has_feature(CPU_FTR_NOEXECUTE) &&
 	    !cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
@@ -270,18 +272,13 @@ 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 gslot;
 		/*
 		 * There MIGHT be an HPTE for this pte
 		 */
-		hash = hpt_hash(vpn, shift, ssize);
-		if (old_pte & H_PAGE_F_SECOND)
-			hash = ~hash;
-		slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
-		slot += (old_pte & H_PAGE_F_GIX) >> H_PAGE_F_GIX_SHIFT;
-
-		if (mmu_hash_ops.hpte_updatepp(slot, rflags, vpn, MMU_PAGE_64K,
-					       MMU_PAGE_64K, ssize,
-					       flags) == -1)
+		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;
 	}
 
@@ -328,9 +325,9 @@ int __hash_page_64K(unsigned long ea, unsigned long access,
 					   MMU_PAGE_64K, MMU_PAGE_64K, old_pte);
 			return -1;
 		}
+
 		new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | H_PAGE_HASHPTE;
-		new_pte |= (slot << H_PAGE_F_GIX_SHIFT) &
-			(H_PAGE_F_SECOND | H_PAGE_F_GIX);
+		new_pte |= pte_set_hash_slot(ptep, rpte, 0, slot);
 	}
 	*ptep = __pte(new_pte & ~H_PAGE_BUSY);
 	return 0;
arch/powerpc/mm/hugetlbpage-hash64.c +7 -11
index a84bb44..d52d667 100644
@@ -22,6 +22,7 @@ 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)
 {
+	real_pte_t rpte;
 	unsigned long vpn;
 	unsigned long old_pte, new_pte;
 	unsigned long rflags, pa, sz;
@@ -61,6 +62,7 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
 	} while(!pte_xchg(ptep, __pte(old_pte), __pte(new_pte)));
 
 	rflags = htab_convert_pte_flags(new_pte);
+	rpte = __real_pte(__pte(old_pte), ptep);
 
 	sz = ((1UL) << shift);
 	if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
@@ -71,16 +73,11 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
 	/* Check if pte already has an hpte (case 2) */
 	if (unlikely(old_pte & H_PAGE_HASHPTE)) {
 		/* There MIGHT be an HPTE for this pte */
-		unsigned long hash, slot;
+		unsigned long gslot;
 
-		hash = hpt_hash(vpn, shift, ssize);
-		if (old_pte & H_PAGE_F_SECOND)
-			hash = ~hash;
-		slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
-		slot += (old_pte & H_PAGE_F_GIX) >> H_PAGE_F_GIX_SHIFT;
-
-		if (mmu_hash_ops.hpte_updatepp(slot, rflags, vpn, mmu_psize,
-					       mmu_psize, ssize, flags) == -1)
+		gslot = pte_get_hash_gslot(vpn, shift, ssize, rpte, 0);
+		if (mmu_hash_ops.hpte_updatepp(gslot, rflags, vpn, mmu_psize,
+				mmu_psize, ssize, flags) == -1)
 			old_pte &= ~_PAGE_HPTEFLAGS;
 	}
 
@@ -106,8 +103,7 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
 			return -1;
 		}
 
-		new_pte |= (slot << H_PAGE_F_GIX_SHIFT) &
-			(H_PAGE_F_SECOND | H_PAGE_F_GIX);
+		new_pte |= pte_set_hash_slot(ptep, rpte, 0, slot);
 	}
 
 	/*
Signature · 1 line
1.7.1
#16 lore raw

Re: [PATCH 4/7] powerpc: Free up four 64K PTE bits in 64K backed HPTE pages

Quoted 160 lines · On Fri, 8 Sep 2017 15:44:44 -0700 Ram Pai <[email protected]> wrote:

Rearrange 64K PTE bits to free up bits 3, 4, 5 and 6 in the 64K backed HPTE pages. This along with the earlier patch will entirely free up the four bits from 64K PTE. The bit numbers are big-endian as defined in the ISA3.0

This patch does the following change to 64K PTE backed by 64K HPTE.

H_PAGE_F_SECOND (S) which occupied bit 4 moves to the
second part of the pte to bit 60.
H_PAGE_F_GIX (G,I,X) which occupied bit 5, 6 and 7 also

	moves  to  the   second part of the pte to bit 61,
       	62, 63, 64 respectively

since bit 7 is now freed up, we move H_PAGE_BUSY (B) from bit 9 to bit 7.

The second part of the PTE will hold (H_PAGE_F_SECOND|H_PAGE_F_GIX) at bit 60,61,62,63.
NOTE: None of the bits in the secondary PTE were not used by 64k-HPTE backed PTE.

Before the patch, the 64K HPTE backed 64k PTE format was as follows

 0 1 2 3 4  5  6  7  8 9 10...........................63
 : : : : :  :  :  :  : : :                            :
 v v v v v  v  v  v  v v v                            v

,-,-,-,-,--,--,--,--,-,-,-,-,-,------------------,-,-,-, |x|x|x| |S |G |I |X |x|B| |x|x|................|x|x|x|x| <- primary pte '_'_'_'_'__'__'__'__'_'_'_'_'_'________________'_'_'_'_'
| | | | | | | | | | | | |..................| | | | | <- secondary pte '_'_'_'_'__'__'__'__'_'_'_'_'__________________'_'_'_'_'

After the patch, the 64k HPTE backed 64k PTE format is as follows

 0 1 2 3 4  5  6  7  8 9 10...........................63
 : : : : :  :  :  :  : : :                            :
 v v v v v  v  v  v  v v v                            v

,-,-,-,-,--,--,--,--,-,-,-,-,-,------------------,-,-,-, |x|x|x| | | | |B |x| | |x|x|................|.|.|.|.| <- primary pte '_'_'_'_'__'__'__'__'_'_'_'_'_'________________'_'_'_'_'
| | | | | | | | | | | | |..................|S|G|I|X| <- secondary pte '_'_'_'_'__'__'__'__'_'_'_'_'__________________'_'_'_'_'

The above PTE changes is applicable to hugetlbpages aswell.

The patch does the following code changes:

a) moves the H_PAGE_F_SECOND and H_PAGE_F_GIX to 4k PTE
header since it is no more needed b the 64k PTEs.
b) abstracts out __real_pte() and __rpte_to_hidx() so the caller need not know the bit location of the slot.
c) moves the slot bits to the secondary pte.

---
 arch/powerpc/include/asm/book3s/64/hash-4k.h  |    3 ++
 arch/powerpc/include/asm/book3s/64/hash-64k.h |   29 +++++++++++-------------
 arch/powerpc/include/asm/book3s/64/hash.h     |    3 --
 arch/powerpc/mm/hash64_64k.c                  |   23 ++++++++-----------
 arch/powerpc/mm/hugetlbpage-hash64.c          |   18 ++++++---------
 5 files changed, 33 insertions(+), 43 deletions(-)
arch/powerpc/include/asm/book3s/64/hash-4k.h +3 -0
index e66bfeb..dc153c6 100644
@@ -16,6 +16,9 @@
 #define H_PUD_TABLE_SIZE	(sizeof(pud_t) << H_PUD_INDEX_SIZE)
 #define H_PGD_TABLE_SIZE	(sizeof(pgd_t) << H_PGD_INDEX_SIZE)
 
+#define H_PAGE_F_GIX_SHIFT	56
+#define H_PAGE_F_SECOND	_RPAGE_RSV2	/* HPTE is in 2ndary HPTEG */
+#define H_PAGE_F_GIX	(_RPAGE_RSV3 | _RPAGE_RSV4 | _RPAGE_RPN44)
 #define H_PAGE_BUSY	_RPAGE_RSV1     /* software: PTE & hash are busy */
 
 /* PTE flags to conserve for HPTE identification */
arch/powerpc/include/asm/book3s/64/hash-64k.h +13 -16
index e038f1c..89ef5a9 100644
@@ -12,7 +12,7 @@
  */
 #define H_PAGE_COMBO	_RPAGE_RPN0 /* this is a combo 4k page */
 #define H_PAGE_4K_PFN	_RPAGE_RPN1 /* PFN is for a single 4k page */
-#define H_PAGE_BUSY	_RPAGE_RPN42     /* software: PTE & hash are busy */
+#define H_PAGE_BUSY	_RPAGE_RPN44     /* software: PTE & hash are busy */
 
 /*
  * We need to differentiate between explicit huge page and THP huge
@@ -21,8 +21,7 @@
 #define H_PAGE_THP_HUGE  H_PAGE_4K_PFN
 
 /* PTE flags to conserve for HPTE identification */
-#define _PAGE_HPTEFLAGS (H_PAGE_BUSY | H_PAGE_F_SECOND | \
-			 H_PAGE_F_GIX | H_PAGE_HASHPTE | H_PAGE_COMBO)
+#define _PAGE_HPTEFLAGS (H_PAGE_BUSY | H_PAGE_HASHPTE | H_PAGE_COMBO)
 /*
  * we support 16 fragments per PTE page of 64K size.
  */
@@ -50,24 +49,22 @@ static inline real_pte_t __real_pte(pte_t pte, pte_t *ptep)
 	unsigned long *hidxp;
 
 	rpte.pte = pte;
-	rpte.hidx = 0;
-	if (pte_val(pte) & H_PAGE_COMBO) {
-		/*
-		 * Make sure we order the hidx load against the H_PAGE_COMBO
-		 * check. The store side ordering is done in __hash_page_4K
-		 */
-		smp_rmb();
-		hidxp = (unsigned long *)(ptep + PTRS_PER_PTE);
-		rpte.hidx = *hidxp;
-	}
+	/*
+	 * Ensure that we do not read the hidx before we read
+	 * the pte. Because the writer side is  expected
+	 * to finish writing the hidx first followed by the pte,
+	 * by using smp_wmb().
+	 * pte_set_hash_slot() ensures that.
+	 */
+	smp_rmb();
+	hidxp = (unsigned long *)(ptep + PTRS_PER_PTE);
+	rpte.hidx = *hidxp;
 	return rpte;
 }
 
 static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index)
 {
-	if ((pte_val(rpte.pte) & H_PAGE_COMBO))
-		return (rpte.hidx >> (index<<2)) & 0xf;
-	return (pte_val(rpte.pte) >> H_PAGE_F_GIX_SHIFT) & 0xf;
+	return ((rpte.hidx >> (index<<2)) & 0xfUL);
 }
 
 /*
arch/powerpc/include/asm/book3s/64/hash.h +0 -3
index 8ce4112..46f3a23 100644
@@ -8,9 +8,6 @@
  *
  */
 #define H_PTE_NONE_MASK		_PAGE_HPTEFLAGS
-#define H_PAGE_F_GIX_SHIFT	56
-#define H_PAGE_F_SECOND		_RPAGE_RSV2	/* HPTE is in 2ndary HPTEG */
-#define H_PAGE_F_GIX		(_RPAGE_RSV3 | _RPAGE_RSV4 | _RPAGE_RPN44)
 #define H_PAGE_HASHPTE		_RPAGE_RPN43	/* PTE has associated HPTE */
 
 #ifdef CONFIG_PPC_64K_PAGES
arch/powerpc/mm/hash64_64k.c +0 -0
index c6c5559..9c63844 100644

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 107

Quoted 7 lines
arch/powerpc/mm/hash64_64k.c +2 -2
@@ -103,8 +103,8 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 		 * On hash insert failure we use old pte value and we don't
 		 * want slot information there if we have a insert failure.
 		 */
-		old_pte &= ~(H_PAGE_HASHPTE | H_PAGE_F_GIX | H_PAGE_F_SECOND);
-		new_pte &= ~(H_PAGE_HASHPTE | H_PAGE_F_GIX | H_PAGE_F_SECOND);
+		old_pte &= ~H_PAGE_HASHPTE;
+		new_pte &= ~H_PAGE_HASHPTE;

Shouldn't we set old/new_pte.slot = invalid? via rpte.hidx

Quoted 96 lines
arch/powerpc/mm/hash64_64k.c +8 -11
 		goto htab_insert_hpte;
 	}
 	/*
@@ -227,6 +227,7 @@ int __hash_page_64K(unsigned long ea, unsigned long access,
 		    unsigned long vsid, pte_t *ptep, unsigned long trap,
 		    unsigned long flags, int ssize)
 {
+	real_pte_t rpte;
 	unsigned long hpte_group;
 	unsigned long rflags, pa;
 	unsigned long old_pte, new_pte;
@@ -263,6 +264,7 @@ int __hash_page_64K(unsigned long ea, unsigned long access,
 	} while (!pte_xchg(ptep, __pte(old_pte), __pte(new_pte)));
 
 	rflags = htab_convert_pte_flags(new_pte);
+	rpte = __real_pte(__pte(old_pte), ptep);
 
 	if (cpu_has_feature(CPU_FTR_NOEXECUTE) &&
 	    !cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
@@ -270,18 +272,13 @@ 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 gslot;
 		/*
 		 * There MIGHT be an HPTE for this pte
 		 */
-		hash = hpt_hash(vpn, shift, ssize);
-		if (old_pte & H_PAGE_F_SECOND)
-			hash = ~hash;
-		slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
-		slot += (old_pte & H_PAGE_F_GIX) >> H_PAGE_F_GIX_SHIFT;
-
-		if (mmu_hash_ops.hpte_updatepp(slot, rflags, vpn, MMU_PAGE_64K,
-					       MMU_PAGE_64K, ssize,
-					       flags) == -1)
+		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;
 	}
 
@@ -328,9 +325,9 @@ int __hash_page_64K(unsigned long ea, unsigned long access,
 					   MMU_PAGE_64K, MMU_PAGE_64K, old_pte);
 			return -1;
 		}
+
 		new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | H_PAGE_HASHPTE;
-		new_pte |= (slot << H_PAGE_F_GIX_SHIFT) &
-			(H_PAGE_F_SECOND | H_PAGE_F_GIX);
+		new_pte |= pte_set_hash_slot(ptep, rpte, 0, slot);
 	}
 	*ptep = __pte(new_pte & ~H_PAGE_BUSY);
 	return 0;
arch/powerpc/mm/hugetlbpage-hash64.c +6 -9
index a84bb44..d52d667 100644
@@ -22,6 +22,7 @@ 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)
 {
+	real_pte_t rpte;
 	unsigned long vpn;
 	unsigned long old_pte, new_pte;
 	unsigned long rflags, pa, sz;
@@ -61,6 +62,7 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
 	} while(!pte_xchg(ptep, __pte(old_pte), __pte(new_pte)));
 
 	rflags = htab_convert_pte_flags(new_pte);
+	rpte = __real_pte(__pte(old_pte), ptep);
 
 	sz = ((1UL) << shift);
 	if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
@@ -71,16 +73,11 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
 	/* Check if pte already has an hpte (case 2) */
 	if (unlikely(old_pte & H_PAGE_HASHPTE)) {
 		/* There MIGHT be an HPTE for this pte */
-		unsigned long hash, slot;
+		unsigned long gslot;
 
-		hash = hpt_hash(vpn, shift, ssize);
-		if (old_pte & H_PAGE_F_SECOND)
-			hash = ~hash;
-		slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
-		slot += (old_pte & H_PAGE_F_GIX) >> H_PAGE_F_GIX_SHIFT;
-
-		if (mmu_hash_ops.hpte_updatepp(slot, rflags, vpn, mmu_psize,
-					       mmu_psize, ssize, flags) == -1)
+		gslot = pte_get_hash_gslot(vpn, shift, ssize, rpte, 0);
+		if (mmu_hash_ops.hpte_updatepp(gslot, rflags, vpn, mmu_psize,
+				mmu_psize, ssize, flags) == -1)
 			old_pte &= ~_PAGE_HPTEFLAGS;
 	}
 

arch/powerpc/mm/hugetlbpage-hash64.c int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, · line 109

Quoted 9 lines
arch/powerpc/mm/hugetlbpage-hash64.c +1 -2
@@ -106,8 +103,7 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
 			return -1;
 		}
 
-		new_pte |= (slot << H_PAGE_F_GIX_SHIFT) &
-			(H_PAGE_F_SECOND | H_PAGE_F_GIX);
+		new_pte |= pte_set_hash_slot(ptep, rpte, 0, slot);
 	}
 
 	/*

Balbir

author
#17 lore raw

Re: [PATCH 4/7] powerpc: Free up four 64K PTE bits in 64K backed HPTE pages

Quoted 157 lines · Balbir Singh
Quoted 154 lines · On Fri, 8 Sep 2017 15:44:44 -0700 Ram Pai <[email protected]> wrote:

Rearrange 64K PTE bits to free up bits 3, 4, 5 and 6 in the 64K backed HPTE pages. This along with the earlier patch will entirely free up the four bits from 64K PTE. The bit numbers are big-endian as defined in the ISA3.0

This patch does the following change to 64K PTE backed by 64K HPTE.

H_PAGE_F_SECOND (S) which occupied bit 4 moves to the
second part of the pte to bit 60.
H_PAGE_F_GIX (G,I,X) which occupied bit 5, 6 and 7 also

	moves  to  the   second part of the pte to bit 61,
       	62, 63, 64 respectively

since bit 7 is now freed up, we move H_PAGE_BUSY (B) from bit 9 to bit 7.

The second part of the PTE will hold (H_PAGE_F_SECOND|H_PAGE_F_GIX) at bit 60,61,62,63.
NOTE: None of the bits in the secondary PTE were not used by 64k-HPTE backed PTE.

Before the patch, the 64K HPTE backed 64k PTE format was as follows

 0 1 2 3 4  5  6  7  8 9 10...........................63
 : : : : :  :  :  :  : : :                            :
 v v v v v  v  v  v  v v v                            v

,-,-,-,-,--,--,--,--,-,-,-,-,-,------------------,-,-,-, |x|x|x| |S |G |I |X |x|B| |x|x|................|x|x|x|x| <- primary pte '_'_'_'_'__'__'__'__'_'_'_'_'_'________________'_'_'_'_'
| | | | | | | | | | | | |..................| | | | | <- secondary pte '_'_'_'_'__'__'__'__'_'_'_'_'__________________'_'_'_'_'

After the patch, the 64k HPTE backed 64k PTE format is as follows

 0 1 2 3 4  5  6  7  8 9 10...........................63
 : : : : :  :  :  :  : : :                            :
 v v v v v  v  v  v  v v v                            v

,-,-,-,-,--,--,--,--,-,-,-,-,-,------------------,-,-,-, |x|x|x| | | | |B |x| | |x|x|................|.|.|.|.| <- primary pte '_'_'_'_'__'__'__'__'_'_'_'_'_'________________'_'_'_'_'
| | | | | | | | | | | | |..................|S|G|I|X| <- secondary pte '_'_'_'_'__'__'__'__'_'_'_'_'__________________'_'_'_'_'

The above PTE changes is applicable to hugetlbpages aswell.

The patch does the following code changes:

a) moves the H_PAGE_F_SECOND and H_PAGE_F_GIX to 4k PTE
header since it is no more needed b the 64k PTEs.
b) abstracts out __real_pte() and __rpte_to_hidx() so the caller need not know the bit location of the slot.
c) moves the slot bits to the secondary pte.

---
 arch/powerpc/include/asm/book3s/64/hash-4k.h  |    3 ++
 arch/powerpc/include/asm/book3s/64/hash-64k.h |   29 +++++++++++-------------
 arch/powerpc/include/asm/book3s/64/hash.h     |    3 --
 arch/powerpc/mm/hash64_64k.c                  |   23 ++++++++-----------
 arch/powerpc/mm/hugetlbpage-hash64.c          |   18 ++++++---------
 5 files changed, 33 insertions(+), 43 deletions(-)
arch/powerpc/include/asm/book3s/64/hash-4k.h +3 -0
index e66bfeb..dc153c6 100644
@@ -16,6 +16,9 @@
 #define H_PUD_TABLE_SIZE	(sizeof(pud_t) << H_PUD_INDEX_SIZE)
 #define H_PGD_TABLE_SIZE	(sizeof(pgd_t) << H_PGD_INDEX_SIZE)
 
+#define H_PAGE_F_GIX_SHIFT	56
+#define H_PAGE_F_SECOND	_RPAGE_RSV2	/* HPTE is in 2ndary HPTEG */
+#define H_PAGE_F_GIX	(_RPAGE_RSV3 | _RPAGE_RSV4 | _RPAGE_RPN44)
 #define H_PAGE_BUSY	_RPAGE_RSV1     /* software: PTE & hash are busy */
 
 /* PTE flags to conserve for HPTE identification */
arch/powerpc/include/asm/book3s/64/hash-64k.h +13 -16
index e038f1c..89ef5a9 100644
@@ -12,7 +12,7 @@
  */
 #define H_PAGE_COMBO	_RPAGE_RPN0 /* this is a combo 4k page */
 #define H_PAGE_4K_PFN	_RPAGE_RPN1 /* PFN is for a single 4k page */
-#define H_PAGE_BUSY	_RPAGE_RPN42     /* software: PTE & hash are busy */
+#define H_PAGE_BUSY	_RPAGE_RPN44     /* software: PTE & hash are busy */
 
 /*
  * We need to differentiate between explicit huge page and THP huge
@@ -21,8 +21,7 @@
 #define H_PAGE_THP_HUGE  H_PAGE_4K_PFN
 
 /* PTE flags to conserve for HPTE identification */
-#define _PAGE_HPTEFLAGS (H_PAGE_BUSY | H_PAGE_F_SECOND | \
-			 H_PAGE_F_GIX | H_PAGE_HASHPTE | H_PAGE_COMBO)
+#define _PAGE_HPTEFLAGS (H_PAGE_BUSY | H_PAGE_HASHPTE | H_PAGE_COMBO)
 /*
  * we support 16 fragments per PTE page of 64K size.
  */
@@ -50,24 +49,22 @@ static inline real_pte_t __real_pte(pte_t pte, pte_t *ptep)
 	unsigned long *hidxp;
 
 	rpte.pte = pte;
-	rpte.hidx = 0;
-	if (pte_val(pte) & H_PAGE_COMBO) {
-		/*
-		 * Make sure we order the hidx load against the H_PAGE_COMBO
-		 * check. The store side ordering is done in __hash_page_4K
-		 */
-		smp_rmb();
-		hidxp = (unsigned long *)(ptep + PTRS_PER_PTE);
-		rpte.hidx = *hidxp;
-	}
+	/*
+	 * Ensure that we do not read the hidx before we read
+	 * the pte. Because the writer side is  expected
+	 * to finish writing the hidx first followed by the pte,
+	 * by using smp_wmb().
+	 * pte_set_hash_slot() ensures that.
+	 */
+	smp_rmb();
+	hidxp = (unsigned long *)(ptep + PTRS_PER_PTE);
+	rpte.hidx = *hidxp;
 	return rpte;
 }
 
 static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index)
 {
-	if ((pte_val(rpte.pte) & H_PAGE_COMBO))
-		return (rpte.hidx >> (index<<2)) & 0xf;
-	return (pte_val(rpte.pte) >> H_PAGE_F_GIX_SHIFT) & 0xf;
+	return ((rpte.hidx >> (index<<2)) & 0xfUL);
 }
 
 /*
arch/powerpc/include/asm/book3s/64/hash.h +0 -3
index 8ce4112..46f3a23 100644
@@ -8,9 +8,6 @@
  *
  */
 #define H_PTE_NONE_MASK		_PAGE_HPTEFLAGS
-#define H_PAGE_F_GIX_SHIFT	56
-#define H_PAGE_F_SECOND		_RPAGE_RSV2	/* HPTE is in 2ndary HPTEG */
-#define H_PAGE_F_GIX		(_RPAGE_RSV3 | _RPAGE_RSV4 | _RPAGE_RPN44)
 #define H_PAGE_HASHPTE		_RPAGE_RPN43	/* PTE has associated HPTE */
 
Quoted 15 lines

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 107

Quoted 13 lines
arch/powerpc/include/asm/book3s/64/hash.h +0 -0
 #ifdef CONFIG_PPC_64K_PAGES
arch/powerpc/mm/hash64_64k.c +2 -2
index c6c5559..9c63844 100644
@@ -103,8 +103,8 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 		 * On hash insert failure we use old pte value and we don't
 		 * want slot information there if we have a insert failure.
 		 */
-		old_pte &= ~(H_PAGE_HASHPTE | H_PAGE_F_GIX | H_PAGE_F_SECOND);
-		new_pte &= ~(H_PAGE_HASHPTE | H_PAGE_F_GIX | H_PAGE_F_SECOND);
+		old_pte &= ~H_PAGE_HASHPTE;
+		new_pte &= ~H_PAGE_HASHPTE;

Shouldn't we set old/new_pte.slot = invalid? via rpte.hidx

by resetting the H_PAGE_HASHPTE flag, we are invalidating slot information. Would that not be sufficient?

RP

Quoted 108 lines
Quoted 97 lines
arch/powerpc/mm/hash64_64k.c +8 -11
 		goto htab_insert_hpte;
 	}
 	/*
@@ -227,6 +227,7 @@ int __hash_page_64K(unsigned long ea, unsigned long access,
 		    unsigned long vsid, pte_t *ptep, unsigned long trap,
 		    unsigned long flags, int ssize)
 {
+	real_pte_t rpte;
 	unsigned long hpte_group;
 	unsigned long rflags, pa;
 	unsigned long old_pte, new_pte;
@@ -263,6 +264,7 @@ int __hash_page_64K(unsigned long ea, unsigned long access,
 	} while (!pte_xchg(ptep, __pte(old_pte), __pte(new_pte)));
 
 	rflags = htab_convert_pte_flags(new_pte);
+	rpte = __real_pte(__pte(old_pte), ptep);
 
 	if (cpu_has_feature(CPU_FTR_NOEXECUTE) &&
 	    !cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
@@ -270,18 +272,13 @@ 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 gslot;
 		/*
 		 * There MIGHT be an HPTE for this pte
 		 */
-		hash = hpt_hash(vpn, shift, ssize);
-		if (old_pte & H_PAGE_F_SECOND)
-			hash = ~hash;
-		slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
-		slot += (old_pte & H_PAGE_F_GIX) >> H_PAGE_F_GIX_SHIFT;
-
-		if (mmu_hash_ops.hpte_updatepp(slot, rflags, vpn, MMU_PAGE_64K,
-					       MMU_PAGE_64K, ssize,
-					       flags) == -1)
+		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;
 	}
 
@@ -328,9 +325,9 @@ int __hash_page_64K(unsigned long ea, unsigned long access,
 					   MMU_PAGE_64K, MMU_PAGE_64K, old_pte);
 			return -1;
 		}
+
 		new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | H_PAGE_HASHPTE;
-		new_pte |= (slot << H_PAGE_F_GIX_SHIFT) &
-			(H_PAGE_F_SECOND | H_PAGE_F_GIX);
+		new_pte |= pte_set_hash_slot(ptep, rpte, 0, slot);
 	}
 	*ptep = __pte(new_pte & ~H_PAGE_BUSY);
 	return 0;
arch/powerpc/mm/hugetlbpage-hash64.c +6 -9
index a84bb44..d52d667 100644
@@ -22,6 +22,7 @@ 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)
 {
+	real_pte_t rpte;
 	unsigned long vpn;
 	unsigned long old_pte, new_pte;
 	unsigned long rflags, pa, sz;
@@ -61,6 +62,7 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
 	} while(!pte_xchg(ptep, __pte(old_pte), __pte(new_pte)));
 
 	rflags = htab_convert_pte_flags(new_pte);
+	rpte = __real_pte(__pte(old_pte), ptep);
 
 	sz = ((1UL) << shift);
 	if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
@@ -71,16 +73,11 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
 	/* Check if pte already has an hpte (case 2) */
 	if (unlikely(old_pte & H_PAGE_HASHPTE)) {
 		/* There MIGHT be an HPTE for this pte */
-		unsigned long hash, slot;
+		unsigned long gslot;
 
-		hash = hpt_hash(vpn, shift, ssize);
-		if (old_pte & H_PAGE_F_SECOND)
-			hash = ~hash;
-		slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
-		slot += (old_pte & H_PAGE_F_GIX) >> H_PAGE_F_GIX_SHIFT;
-
-		if (mmu_hash_ops.hpte_updatepp(slot, rflags, vpn, mmu_psize,
-					       mmu_psize, ssize, flags) == -1)
+		gslot = pte_get_hash_gslot(vpn, shift, ssize, rpte, 0);
+		if (mmu_hash_ops.hpte_updatepp(gslot, rflags, vpn, mmu_psize,
+				mmu_psize, ssize, flags) == -1)
 			old_pte &= ~_PAGE_HPTEFLAGS;
 	}
 

arch/powerpc/mm/hugetlbpage-hash64.c int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, · line 109

Quoted 9 lines
arch/powerpc/mm/hugetlbpage-hash64.c +1 -2
@@ -106,8 +103,7 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
 			return -1;
 		}
 
-		new_pte |= (slot << H_PAGE_F_GIX_SHIFT) &
-			(H_PAGE_F_SECOND | H_PAGE_F_GIX);
+		new_pte |= pte_set_hash_slot(ptep, rpte, 0, slot);
 	}
 
 	/*

Balbir

Signature · 1 line
Ram Pai
author
#18 lore raw

Re: [PATCH 4/7] powerpc: Free up four 64K PTE bits in 64K backed HPTE pages

Quoted 174 lines · Ram Pai
Quoted 157 lines · Balbir Singh
Quoted 154 lines · On Fri, 8 Sep 2017 15:44:44 -0700 Ram Pai <[email protected]> wrote:

Rearrange 64K PTE bits to free up bits 3, 4, 5 and 6 in the 64K backed HPTE pages. This along with the earlier patch will entirely free up the four bits from 64K PTE. The bit numbers are big-endian as defined in the ISA3.0

This patch does the following change to 64K PTE backed by 64K HPTE.

H_PAGE_F_SECOND (S) which occupied bit 4 moves to the
second part of the pte to bit 60.
H_PAGE_F_GIX (G,I,X) which occupied bit 5, 6 and 7 also

	moves  to  the   second part of the pte to bit 61,
       	62, 63, 64 respectively

since bit 7 is now freed up, we move H_PAGE_BUSY (B) from bit 9 to bit 7.

The second part of the PTE will hold (H_PAGE_F_SECOND|H_PAGE_F_GIX) at bit 60,61,62,63.
NOTE: None of the bits in the secondary PTE were not used by 64k-HPTE backed PTE.

Before the patch, the 64K HPTE backed 64k PTE format was as follows

 0 1 2 3 4  5  6  7  8 9 10...........................63
 : : : : :  :  :  :  : : :                            :
 v v v v v  v  v  v  v v v                            v

,-,-,-,-,--,--,--,--,-,-,-,-,-,------------------,-,-,-, |x|x|x| |S |G |I |X |x|B| |x|x|................|x|x|x|x| <- primary pte '_'_'_'_'__'__'__'__'_'_'_'_'_'________________'_'_'_'_'
| | | | | | | | | | | | |..................| | | | | <- secondary pte '_'_'_'_'__'__'__'__'_'_'_'_'__________________'_'_'_'_'

After the patch, the 64k HPTE backed 64k PTE format is as follows

 0 1 2 3 4  5  6  7  8 9 10...........................63
 : : : : :  :  :  :  : : :                            :
 v v v v v  v  v  v  v v v                            v

,-,-,-,-,--,--,--,--,-,-,-,-,-,------------------,-,-,-, |x|x|x| | | | |B |x| | |x|x|................|.|.|.|.| <- primary pte '_'_'_'_'__'__'__'__'_'_'_'_'_'________________'_'_'_'_'
| | | | | | | | | | | | |..................|S|G|I|X| <- secondary pte '_'_'_'_'__'__'__'__'_'_'_'_'__________________'_'_'_'_'

The above PTE changes is applicable to hugetlbpages aswell.

The patch does the following code changes:

a) moves the H_PAGE_F_SECOND and H_PAGE_F_GIX to 4k PTE
header since it is no more needed b the 64k PTEs.
b) abstracts out __real_pte() and __rpte_to_hidx() so the caller need not know the bit location of the slot.
c) moves the slot bits to the secondary pte.

---
 arch/powerpc/include/asm/book3s/64/hash-4k.h  |    3 ++
 arch/powerpc/include/asm/book3s/64/hash-64k.h |   29 +++++++++++-------------
 arch/powerpc/include/asm/book3s/64/hash.h     |    3 --
 arch/powerpc/mm/hash64_64k.c                  |   23 ++++++++-----------
 arch/powerpc/mm/hugetlbpage-hash64.c          |   18 ++++++---------
 5 files changed, 33 insertions(+), 43 deletions(-)
arch/powerpc/include/asm/book3s/64/hash-4k.h +3 -0
index e66bfeb..dc153c6 100644
@@ -16,6 +16,9 @@
 #define H_PUD_TABLE_SIZE	(sizeof(pud_t) << H_PUD_INDEX_SIZE)
 #define H_PGD_TABLE_SIZE	(sizeof(pgd_t) << H_PGD_INDEX_SIZE)
 
+#define H_PAGE_F_GIX_SHIFT	56
+#define H_PAGE_F_SECOND	_RPAGE_RSV2	/* HPTE is in 2ndary HPTEG */
+#define H_PAGE_F_GIX	(_RPAGE_RSV3 | _RPAGE_RSV4 | _RPAGE_RPN44)
 #define H_PAGE_BUSY	_RPAGE_RSV1     /* software: PTE & hash are busy */
 
 /* PTE flags to conserve for HPTE identification */
arch/powerpc/include/asm/book3s/64/hash-64k.h +13 -16
index e038f1c..89ef5a9 100644
@@ -12,7 +12,7 @@
  */
 #define H_PAGE_COMBO	_RPAGE_RPN0 /* this is a combo 4k page */
 #define H_PAGE_4K_PFN	_RPAGE_RPN1 /* PFN is for a single 4k page */
-#define H_PAGE_BUSY	_RPAGE_RPN42     /* software: PTE & hash are busy */
+#define H_PAGE_BUSY	_RPAGE_RPN44     /* software: PTE & hash are busy */
 
 /*
  * We need to differentiate between explicit huge page and THP huge
@@ -21,8 +21,7 @@
 #define H_PAGE_THP_HUGE  H_PAGE_4K_PFN
 
 /* PTE flags to conserve for HPTE identification */
-#define _PAGE_HPTEFLAGS (H_PAGE_BUSY | H_PAGE_F_SECOND | \
-			 H_PAGE_F_GIX | H_PAGE_HASHPTE | H_PAGE_COMBO)
+#define _PAGE_HPTEFLAGS (H_PAGE_BUSY | H_PAGE_HASHPTE | H_PAGE_COMBO)
 /*
  * we support 16 fragments per PTE page of 64K size.
  */
@@ -50,24 +49,22 @@ static inline real_pte_t __real_pte(pte_t pte, pte_t *ptep)
 	unsigned long *hidxp;
 
 	rpte.pte = pte;
-	rpte.hidx = 0;
-	if (pte_val(pte) & H_PAGE_COMBO) {
-		/*
-		 * Make sure we order the hidx load against the H_PAGE_COMBO
-		 * check. The store side ordering is done in __hash_page_4K
-		 */
-		smp_rmb();
-		hidxp = (unsigned long *)(ptep + PTRS_PER_PTE);
-		rpte.hidx = *hidxp;
-	}
+	/*
+	 * Ensure that we do not read the hidx before we read
+	 * the pte. Because the writer side is  expected
+	 * to finish writing the hidx first followed by the pte,
+	 * by using smp_wmb().
+	 * pte_set_hash_slot() ensures that.
+	 */
+	smp_rmb();
+	hidxp = (unsigned long *)(ptep + PTRS_PER_PTE);
+	rpte.hidx = *hidxp;
 	return rpte;
 }
 
 static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index)
 {
-	if ((pte_val(rpte.pte) & H_PAGE_COMBO))
-		return (rpte.hidx >> (index<<2)) & 0xf;
-	return (pte_val(rpte.pte) >> H_PAGE_F_GIX_SHIFT) & 0xf;
+	return ((rpte.hidx >> (index<<2)) & 0xfUL);
 }
 
 /*
arch/powerpc/include/asm/book3s/64/hash.h +0 -3
index 8ce4112..46f3a23 100644
@@ -8,9 +8,6 @@
  *
  */
 #define H_PTE_NONE_MASK		_PAGE_HPTEFLAGS
-#define H_PAGE_F_GIX_SHIFT	56
-#define H_PAGE_F_SECOND		_RPAGE_RSV2	/* HPTE is in 2ndary HPTEG */
-#define H_PAGE_F_GIX		(_RPAGE_RSV3 | _RPAGE_RSV4 | _RPAGE_RPN44)
 #define H_PAGE_HASHPTE		_RPAGE_RPN43	/* PTE has associated HPTE */
 
Quoted 15 lines

arch/powerpc/mm/hash64_64k.c int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, · line 107

Quoted 13 lines
arch/powerpc/include/asm/book3s/64/hash.h +0 -0
 #ifdef CONFIG_PPC_64K_PAGES
arch/powerpc/mm/hash64_64k.c +2 -2
index c6c5559..9c63844 100644
@@ -103,8 +103,8 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 		 * On hash insert failure we use old pte value and we don't
 		 * want slot information there if we have a insert failure.
 		 */
-		old_pte &= ~(H_PAGE_HASHPTE | H_PAGE_F_GIX | H_PAGE_F_SECOND);
-		new_pte &= ~(H_PAGE_HASHPTE | H_PAGE_F_GIX | H_PAGE_F_SECOND);
+		old_pte &= ~H_PAGE_HASHPTE;
+		new_pte &= ~H_PAGE_HASHPTE;

Shouldn't we set old/new_pte.slot = invalid? via rpte.hidx

Quoted 2 lines

by resetting the H_PAGE_HASHPTE flag, we are invalidating slot information. Would that not be sufficient?

I think i misunderstood you question. Yes rpte.hidx will have to be reset to invalid. The code does that further down in that function.

	if (!(old_pte & H_PAGE_COMBO))
		rpte.hidx = ~0x0UL;

RP

#19 lore raw

Re: [PATCH 4/7] powerpc: Free up four 64K PTE bits in 64K backed HPTE pages

In reply to Ram Pai
Quoted 4 lines · Ram Pai

The second part of the PTE will hold (H_PAGE_F_SECOND|H_PAGE_F_GIX) at bit 60,61,62,63.
NOTE: None of the bits in the secondary PTE were not used by 64k-HPTE backed PTE.

Have you measured the performance impact of this ? The second part of the PTE being in a different cache line there could be one...

Cheers,
Ben.

#20 lore raw

Re: [PATCH 4/7] powerpc: Free up four 64K PTE bits in 64K backed HPTE pages

Quoted 9 lines · Benjamin Herrenschmidt
Quoted 4 lines · Ram Pai

The second part of the PTE will hold (H_PAGE_F_SECOND|H_PAGE_F_GIX) at bit 60,61,62,63.
NOTE: None of the bits in the secondary PTE were not used by 64k-HPTE backed PTE.

Have you measured the performance impact of this ? The second part of the PTE being in a different cache line there could be one...

I am also looking at a patch series removing the slot tracking completely. With randomize address turned off and no swap in guest/host and making sure we touched most of guest ram, I don't find much impact in performance when we don't track the slot at all. I will post the patch series with numbers in a day or two. But my test was

while (5000) {
mmap(128M)
touch every page of 2048 pages
munmap()
}

I could also be the best case in my run because i might have always found the hash pte slot in the primary. In one measurement with swap on and address randmization enabled, i did find a 50% impact. But then i was not able to recreate that again. So could be something i did wrong in the test setup.

Ram,

Will you be able to get a test run with the above loop?

-aneesh

author
#21 lore raw

Re: [PATCH 4/7] powerpc: Free up four 64K PTE bits in 64K backed HPTE pages

Quoted 30 lines · Aneesh Kumar K.V
Quoted 9 lines · Benjamin Herrenschmidt
Quoted 4 lines · Ram Pai

The second part of the PTE will hold (H_PAGE_F_SECOND|H_PAGE_F_GIX) at bit 60,61,62,63.
NOTE: None of the bits in the secondary PTE were not used by 64k-HPTE backed PTE.

Have you measured the performance impact of this ? The second part of the PTE being in a different cache line there could be one...

I am also looking at a patch series removing the slot tracking completely. With randomize address turned off and no swap in guest/host and making sure we touched most of guest ram, I don't find much impact in performance when we don't track the slot at all. I will post the patch series with numbers in a day or two. But my test was

while (5000) {
mmap(128M)
touch every page of 2048 pages
munmap()
}

I could also be the best case in my run because i might have always found the hash pte slot in the primary. In one measurement with swap on and address randmization enabled, i did find a 50% impact. But then i was not able to recreate that again. So could be something i did wrong in the test setup.

Quoted 3 lines

Ram,

Will you be able to get a test run with the above loop?

Yes. results with patch look good; better than w/o patch.

/-----------------------------------------------\
|Itteratn| secs w/ patch |secs w/o patch |
-------------------------------------------------

|1	 | 45.572621     	| 49.046994	|
|2	 | 46.049545     	| 49.378756	|
|3	 | 46.103657     	| 49.223591	|
|4	 | 46.298903     	| 48.991245	|
|5	 | 46.353202     	| 48.988033	|
|6	 | 45.440878     	| 49.175846	|
|7	 | 46.860373     	| 49.008395	|
|8	 | 46.221390     	| 49.236964	|
|9	 | 45.794993     	| 49.171927	|
|10	 | 46.569491     	| 48.995628	|
|-----------------------------------------------|
|average  | 46.1265053		| 49.1217379    |

\-----------------------------------------------/

The code is as follows:

tools/testing/selftests/powerpc/benchmarks/mmap_bench.c +6 -2
index 8d084a2..ef2ad87 100644
@@ -10,14 +10,14 @@
 
 #include "utils.h"
 
-#define ITERATIONS 5000000
+#define ITERATIONS 5000
 
 #define MEMSIZE (128 * 1024 * 1024)
 
 int test_mmap(void)
 {
 	struct timespec ts_start, ts_end;
-	unsigned long i = ITERATIONS;
+	unsigned long i = ITERATIONS, j;
 
 	clock_gettime(CLOCK_MONOTONIC, &ts_start);
 
@@ -25,6 +25,10 @@ int test_mmap(void)
 		char *c = mmap(NULL, MEMSIZE, PROT_READ|PROT_WRITE,
 			       MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
 		FAIL_IF(c == MAP_FAILED);
+
+		for (j=0; j < (MEMSIZE >> 16); j++)
+			c[j<<16] = 0xf;
+
 		munmap(c, MEMSIZE);
 	}
 
author
#22 lore raw

Re: [PATCH 4/7] powerpc: Free up four 64K PTE bits in 64K backed HPTE pages

In reply to Benjamin Herrenschmidt
Quoted 8 lines · Benjamin Herrenschmidt
Quoted 4 lines · Ram Pai

The second part of the PTE will hold (H_PAGE_F_SECOND|H_PAGE_F_GIX) at bit 60,61,62,63.
NOTE: None of the bits in the secondary PTE were not used by 64k-HPTE backed PTE.

Have you measured the performance impact of this ? The second part of the PTE being in a different cache line there could be one...

hmm..missed responding to this comment.

I did a preliminay measurement running mmap bench in the selftest. Ran it multiple times. almost always the numbers were either equal-to or better-than without the patch-series.

RP

#23 lore raw

Re: [PATCH 4/7] powerpc: Free up four 64K PTE bits in 64K backed HPTE pages

Quoted 7 lines · Ram Pai
Quoted 6 lines · Benjamin Herrenschmidt
Quoted 4 lines · Ram Pai

The second part of the PTE will hold (H_PAGE_F_SECOND|H_PAGE_F_GIX) at bit 60,61,62,63.
NOTE: None of the bits in the secondary PTE were not used by 64k-HPTE backed PTE.

Quoted 8 lines
Quoted 2 lines

Have you measured the performance impact of this ? The second part of the PTE being in a different cache line there could be one...

hmm..missed responding to this comment.

I did a preliminay measurement running mmap bench in the selftest. Ran it multiple times. almost always the numbers were either equal-to or better-than without the patch-series.

mmap bench doesn't do any fault. It is just mmap/munmap in loop.

-aneesh

author
#24 lore raw

PATCH 5/7 powerpc: Swizzle around 4K PTE bits to free up bit 5 and bit 6

In reply to Ram Pai

We need PTE bits 3 ,4, 5, 6 and 57 to support protection-keys, because these are the bits we want to consolidate on across all configuration to support protection keys.

Bit 3,4,5 and 6 are currently used on 4K-pte kernels. But bit 9 and 10 are available. Hence we use the two available bits and free up bit 5 and 6. We will still not be able to free up bit 3 and 4. In the absence of any other free bits, we will have to
stay satisfied with what we have :-(. This means we will not
be able to support 32 protection keys, but only 8. The bit numbers are big-endian as defined in the ISA3.0

This patch does the following change to 4K PTE.

H_PAGE_F_SECOND (S) which occupied bit 4 moves to bit 7.
H_PAGE_F_GIX (G,I,X) which occupied bit 5, 6 and 7 also moves to bit 8,9, 10 respectively.
H_PAGE_HASHPTE (H) which occupied bit 8 moves to bit 4.

Before the patch, the 4k PTE format was as follows

 0 1 2 3 4  5  6  7  8 9 10....................57.....63
 : : : : :  :  :  :  : : :                      :     :
 v v v v v  v  v  v  v v v                      v     v

,-,-,-,-,--,--,--,--,-,-,-,-,-,------------------,-,-,-, |x|x|x|B|S |G |I |X |H| | |x|x|................| |x|x|x| '_'_'_'_'__'__'__'__'_'_'_'_'_'________________'_'_'_'_'

After the patch, the 4k PTE format is as follows

 0 1 2 3 4  5  6  7  8 9 10....................57.....63
 : : : : :  :  :  :  : : :                      :     :
 v v v v v  v  v  v  v v v                      v     v

,-,-,-,-,--,--,--,--,-,-,-,-,-,------------------,-,-,-, |x|x|x|B|H | | |S |G|I|X|x|x|................| |.|.|.| '_'_'_'_'__'__'__'__'_'_'_'_'_'________________'_'_'_'_'

The patch has no code changes; just swizzles around bits.

---
 arch/powerpc/include/asm/book3s/64/hash-4k.h  |    7 ++++---
 arch/powerpc/include/asm/book3s/64/hash-64k.h |    1 +
 arch/powerpc/include/asm/book3s/64/hash.h     |    1 -
 3 files changed, 5 insertions(+), 4 deletions(-)
arch/powerpc/include/asm/book3s/64/hash-4k.h +4 -3
index dc153c6..5187249 100644
@@ -16,10 +16,11 @@
 #define H_PUD_TABLE_SIZE	(sizeof(pud_t) << H_PUD_INDEX_SIZE)
 #define H_PGD_TABLE_SIZE	(sizeof(pgd_t) << H_PGD_INDEX_SIZE)
 
-#define H_PAGE_F_GIX_SHIFT	56
-#define H_PAGE_F_SECOND	_RPAGE_RSV2	/* HPTE is in 2ndary HPTEG */
-#define H_PAGE_F_GIX	(_RPAGE_RSV3 | _RPAGE_RSV4 | _RPAGE_RPN44)
+#define H_PAGE_F_GIX_SHIFT	53
+#define H_PAGE_F_SECOND	_RPAGE_RPN44	/* HPTE is in 2ndary HPTEG */
+#define H_PAGE_F_GIX	(_RPAGE_RPN43 | _RPAGE_RPN42 | _RPAGE_RPN41)
 #define H_PAGE_BUSY	_RPAGE_RSV1     /* software: PTE & hash are busy */
+#define H_PAGE_HASHPTE	_RPAGE_RSV2     /* software: PTE & hash are busy */
 
 /* PTE flags to conserve for HPTE identification */
 #define _PAGE_HPTEFLAGS (H_PAGE_BUSY | H_PAGE_HASHPTE | \
arch/powerpc/include/asm/book3s/64/hash-64k.h +1 -0
index 89ef5a9..8576060 100644
@@ -13,6 +13,7 @@
 #define H_PAGE_COMBO	_RPAGE_RPN0 /* this is a combo 4k page */
 #define H_PAGE_4K_PFN	_RPAGE_RPN1 /* PFN is for a single 4k page */
 #define H_PAGE_BUSY	_RPAGE_RPN44     /* software: PTE & hash are busy */
+#define H_PAGE_HASHPTE	_RPAGE_RPN43	/* PTE has associated HPTE */
 
 /*
  * We need to differentiate between explicit huge page and THP huge
arch/powerpc/include/asm/book3s/64/hash.h +0 -1
index 46f3a23..953795e 100644
@@ -8,7 +8,6 @@
  *
  */
 #define H_PTE_NONE_MASK		_PAGE_HPTEFLAGS
-#define H_PAGE_HASHPTE		_RPAGE_RPN43	/* PTE has associated HPTE */
 
 #ifdef CONFIG_PPC_64K_PAGES
 #include <asm/book3s/64/hash-64k.h>
Signature · 1 line
1.7.1
#25 lore raw

Re: [PATCH 5/7] powerpc: Swizzle around 4K PTE bits to free up bit 5 and bit 6

Quoted 4 lines · On Fri, 8 Sep 2017 15:44:45 -0700 Ram Pai <[email protected]> wrote:

We need PTE bits 3 ,4, 5, 6 and 57 to support protection-keys, because these are the bits we want to consolidate on across all configuration to support protection keys.

Quoted 8 lines

Bit 3,4,5 and 6 are currently used on 4K-pte kernels. But bit 9 and 10 are available. Hence we use the two available bits and free up bit 5 and 6. We will still not be able to free up bit 3 and 4. In the absence of any other free bits, we will have to
stay satisfied with what we have :-(. This means we will not
be able to support 32 protection keys, but only 8. The bit numbers are big-endian as defined in the ISA3.0

Any chance for 4k PTE's we can do slot searching for the PTE? I guess thats add additional complexity

Balbir Singh.

author
#26 lore raw

Re: [PATCH 5/7] powerpc: Swizzle around 4K PTE bits to free up bit 5 and bit 6

Quoted 16 lines · Balbir Singh
Quoted 4 lines · On Fri, 8 Sep 2017 15:44:45 -0700 Ram Pai <[email protected]> wrote:

We need PTE bits 3 ,4, 5, 6 and 57 to support protection-keys, because these are the bits we want to consolidate on across all configuration to support protection keys.

Quoted 8 lines

Bit 3,4,5 and 6 are currently used on 4K-pte kernels. But bit 9 and 10 are available. Hence we use the two available bits and free up bit 5 and 6. We will still not be able to free up bit 3 and 4. In the absence of any other free bits, we will have to
stay satisfied with what we have :-(. This means we will not
be able to support 32 protection keys, but only 8. The bit numbers are big-endian as defined in the ISA3.0

Quoted 2 lines

Any chance for 4k PTE's we can do slot searching for the PTE? I guess thats add additional complexity

Aneesh, i think, is working on moving slot information out of the PTE. If that happens, we will have leg-space to support more keys.

RP

author
#27 lore raw

PATCH 6/7 powerpc: use helper functions to get and set hash slots

In reply to Ram Pai

replace redundant code in __hash_page_4K() and flush_hash_page()
with helper functions pte_get_hash_gslot() and pte_set_hash_slot()

---
 arch/powerpc/mm/hash64_4k.c     |   14 ++++++--------
 arch/powerpc/mm/hash_utils_64.c |   13 ++++---------
 2 files changed, 10 insertions(+), 17 deletions(-)
arch/powerpc/mm/hash64_4k.c +6 -8
index 6fa450c..a1eebc1 100644
@@ -20,6 +20,7 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 		   pte_t *ptep, unsigned long trap, unsigned long flags,
 		   int ssize, int subpg_prot)
 {
+	real_pte_t rpte;
 	unsigned long hpte_group;
 	unsigned long rflags, pa;
 	unsigned long old_pte, new_pte;
@@ -54,6 +55,7 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 	 * need to add in 0x1 if it's a read-only user page
 	 */
 	rflags = htab_convert_pte_flags(new_pte);
+	rpte = __real_pte(__pte(old_pte), ptep);
 
 	if (cpu_has_feature(CPU_FTR_NOEXECUTE) &&
 	    !cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
@@ -64,13 +66,10 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 		/*
 		 * There MIGHT be an HPTE for this pte
 		 */
-		hash = hpt_hash(vpn, shift, ssize);
-		if (old_pte & H_PAGE_F_SECOND)
-			hash = ~hash;
-		slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
-		slot += (old_pte & H_PAGE_F_GIX) >> H_PAGE_F_GIX_SHIFT;
+		unsigned long gslot = pte_get_hash_gslot(vpn, shift,
+						ssize, rpte, 0);
 
-		if (mmu_hash_ops.hpte_updatepp(slot, rflags, vpn, MMU_PAGE_4K,
+		if (mmu_hash_ops.hpte_updatepp(gslot, rflags, vpn, MMU_PAGE_4K,
 					       MMU_PAGE_4K, ssize, flags) == -1)
 			old_pte &= ~_PAGE_HPTEFLAGS;
 	}
@@ -118,8 +117,7 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
 			return -1;
 		}
 		new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | H_PAGE_HASHPTE;
-		new_pte |= (slot << H_PAGE_F_GIX_SHIFT) &
-			(H_PAGE_F_SECOND | H_PAGE_F_GIX);
+		new_pte |= pte_set_hash_slot(ptep, rpte, 0, slot);
 	}
 	*ptep = __pte(new_pte & ~H_PAGE_BUSY);
 	return 0;
arch/powerpc/mm/hash_utils_64.c +4 -9
index a40c7bc..0dff57b 100644
@@ -1617,23 +1617,18 @@ unsigned long pte_get_hash_gslot(unsigned long vpn, unsigned long shift,
 void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, int ssize,
 		     unsigned long flags)
 {
-	unsigned long hash, index, shift, hidx, slot;
+	unsigned long index, shift, gslot;
 	int local = flags & HPTE_LOCAL_UPDATE;
 
 	DBG_LOW("flush_hash_page(vpn=%016lx)\n", vpn);
 	pte_iterate_hashed_subpages(pte, psize, vpn, index, shift) {
-		hash = hpt_hash(vpn, shift, ssize);
-		hidx = __rpte_to_hidx(pte, index);
-		if (hidx & _PTEIDX_SECONDARY)
-			hash = ~hash;
-		slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
-		slot += hidx & _PTEIDX_GROUP_IX;
-		DBG_LOW(" sub %ld: hash=%lx, hidx=%lx\n", index, slot, hidx);
+		gslot = pte_get_hash_gslot(vpn, shift, ssize, pte, index);
+		DBG_LOW(" sub %ld: gslot=%lx\n", index, gslot);
 		/*
 		 * We use same base page size and actual psize, because we don't
 		 * use these functions for hugepage
 		 */
-		mmu_hash_ops.hpte_invalidate(slot, vpn, psize, psize,
+		mmu_hash_ops.hpte_invalidate(gslot, vpn, psize, psize,
 					     ssize, local);
 	} pte_iterate_hashed_end();
 
Signature · 1 line
1.7.1
author
#28 lore raw

PATCH 7/7 powerpc: capture the PTE format changes in the dump pte report

In reply to Ram Pai

The H_PAGE_F_SECOND,H_PAGE_F_GIX are not in the 64K main-PTE. capture these changes in the dump pte report.

---
 arch/powerpc/mm/dump_linuxpagetables.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
arch/powerpc/mm/dump_linuxpagetables.c +2 -1
index c9282d2..0323dc4 100644
@@ -213,7 +213,7 @@ struct flag_info {
 		.val	= H_PAGE_4K_PFN,
 		.set	= "4K_pfn",
 	}, {
-#endif
+#else /* CONFIG_PPC_64K_PAGES */
 		.mask	= H_PAGE_F_GIX,
 		.val	= H_PAGE_F_GIX,
 		.set	= "f_gix",
@@ -224,6 +224,7 @@ struct flag_info {
 		.val	= H_PAGE_F_SECOND,
 		.set	= "f_second",
 	}, {
+#endif /* CONFIG_PPC_64K_PAGES */
 #endif
 		.mask	= _PAGE_SPECIAL,
 		.val	= _PAGE_SPECIAL,
Signature · 1 line
1.7.1
author
#30 lore raw

Re: [PATCH 7/7] powerpc: capture the PTE format changes in the dump pte report

Quoted 6 lines · Balbir Singh
Quoted 3 lines · On Fri, 8 Sep 2017 15:44:47 -0700 Ram Pai <[email protected]> wrote:

The H_PAGE_F_SECOND,H_PAGE_F_GIX are not in the 64K main-PTE. capture these changes in the dump pte report.

Quoted 6 lines
Quoted 3 lines

---

So we lose slot and secondary information for 64K PTE's with this change?

yes. It was anyway not there for 4k-backed-64k ptes. Now it wont be there for any 64k ptes.

RP

author
#31 lore raw

cover powerpc: Memory Protection Keys

In reply to Ram Pai

Memory protection keys enable applications to protect its address space from inadvertent access from or corruption by itself.

These patches along with the pte-bit freeing patch series enables the protection key feature on powerpc; 4k and 64k hashpage kernels. A subsequent patch series that changes the generic and x86 code will expose memkey features through sysfs and provide testcases and Documentation updates.

Patches are based on powerpc -next branch. All patches
can be found at --
https://github.com/rampai/memorykeys.git memkey.v8

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.

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.
NOTE: All the selftest related patches will be part
of a separate patch series.

History:
-------
version v8:
(1) Contents of the AMR register withdrawn from the siginfo structure. Applications can always read the AMR register.
(2) AMR/IAMR/UAMOR are now available through ptrace system call. -- thanks to Thiago
(3) code changes to handle legacy power cpus that do not support execute-disable.
(4) incorporates many code improvement suggestions.

version v7:
(1) refers to device tree property to enable protection keys.
(2) adds 4K PTE support.
(3) fixes a couple of bugs noticed by Thiago
(4) decouples this patch series from arch-
independent code. This patch series can now stand by itself, with one kludge patch(2).
version v7:
(1) refers to device tree property to enable protection keys.
(2) adds 4K PTE support.
(3) fixes a couple of bugs noticed by Thiago
(4) decouples this patch series from arch-
independent code. This patch series can now stand by itself, with one kludge patch(2).

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 (24):
powerpc: initial pkey plumbing
powerpc: define an additional vma bit for protection keys.
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 UAMOR 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: implementation for arch_vma_access_permitted()
powerpc: Handle exceptions caused by pkey violation
powerpc: introduce get_pte_pkey() helper
powerpc: capture the violated protection key on fault
powerpc: Deliver SEGV signal on pkey violation
powerpc: Enable pkey subsystem

Thiago Jung Bauermann (1):
powerpc/ptrace: Add memory protection key regset

 arch/powerpc/Kconfig                          |   16 +
 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  |   74 +++++-
 arch/powerpc/include/asm/cputable.h           |   15 +-
 arch/powerpc/include/asm/mman.h               |   16 +-
 arch/powerpc/include/asm/mmu_context.h        |   21 ++
 arch/powerpc/include/asm/paca.h               |    3 +
 arch/powerpc/include/asm/pkeys.h              |  252 +++++++++++++++++
 arch/powerpc/include/asm/processor.h          |    5 +
 arch/powerpc/include/asm/systbl.h             |    3 +
 arch/powerpc/include/asm/unistd.h             |    6 +-
 arch/powerpc/include/uapi/asm/elf.h           |    1 +
 arch/powerpc/include/uapi/asm/mman.h          |    6 +
 arch/powerpc/include/uapi/asm/unistd.h        |    3 +
 arch/powerpc/kernel/asm-offsets.c             |    5 +
 arch/powerpc/kernel/process.c                 |   10 +
 arch/powerpc/kernel/prom.c                    |   19 ++
 arch/powerpc/kernel/ptrace.c                  |   66 +++++
 arch/powerpc/kernel/setup_64.c                |    4 +
 arch/powerpc/kernel/traps.c                   |   22 ++
 arch/powerpc/mm/Makefile                      |    1 +
 arch/powerpc/mm/fault.c                       |   46 +++-
 arch/powerpc/mm/hash_utils_64.c               |   26 ++
 arch/powerpc/mm/mmu_context_book3s64.c        |    2 +
 arch/powerpc/mm/pkeys.c                       |  374 +++++++++++++++++++++++++
 include/uapi/linux/elf.h                      |    1 +
 27 files changed, 1000 insertions(+), 17 deletions(-)
 create mode 100644 arch/powerpc/include/asm/pkeys.h
 create mode 100644 arch/powerpc/mm/pkeys.c
author
#32 lore raw

PATCH 1/25 powerpc: initial pkey plumbing

In reply to Ram Pai

Basic plumbing to initialize the pkey system.
Nothing is enabled yet. A later patch will enable it ones all the infrastructure is in place.

---
 arch/powerpc/Kconfig                   |   16 +++++++++++
 arch/powerpc/include/asm/mmu_context.h |    5 +++
 arch/powerpc/include/asm/pkeys.h       |   45 ++++++++++++++++++++++++++++++++
 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                |   33 +++++++++++++++++++++++
 7 files changed, 105 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/include/asm/pkeys.h
 create mode 100644 arch/powerpc/mm/pkeys.c
arch/powerpc/Kconfig +16 -0
index 9fc3c0b..a4cd210 100644
@@ -864,6 +864,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
+	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
arch/powerpc/include/asm/mmu_context.h +5 -0
index 3095925..7badf29 100644
@@ -141,5 +141,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 */
arch/powerpc/include/asm/pkeys.h new file +45 -0

45 lines not on this page · raw message

arch/powerpc/kernel/setup_64.c +4 -0
index b89c6aa..3b67014 100644
@@ -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
arch/powerpc/mm/Makefile +1 -0
index fb844d2..927620a 100644
@@ -43,3 +43,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
arch/powerpc/mm/hash_utils_64.c +1 -0
index 0dff57b..67f62b5 100644
@@ -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>
arch/powerpc/mm/pkeys.c new file +33 -0
new file mode 100644
index 0000000..418a05b
@@ -0,0 +1,33 @@
+/*
+ * 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 <linux/pkeys.h>                /* PKEY_*                       */
+
+bool pkey_inited;
+bool pkey_execute_disable_support;
+
+void __init pkey_initialize(void)
+{
+	/* disable the pkey system till everything
+	 * is in place. A patch further down the
+	 * line will enable it.
+	 */
+	pkey_inited = false;
+
+	/*
+	 * disable execute_disable support for now.
+	 * A patch further down will enable it.
+	 */
+	pkey_execute_disable_support = false;
+}
Signature · 1 line
1.7.1
#33 lore raw

Re: [PATCH 01/25] powerpc: initial pkey plumbing

Quoted 22 lines · On Fri, 8 Sep 2017 15:44:49 -0700 Ram Pai <[email protected]> wrote:

Basic plumbing to initialize the pkey system.
Nothing is enabled yet. A later patch will enable it ones all the infrastructure is in place.

---
 arch/powerpc/Kconfig                   |   16 +++++++++++
 arch/powerpc/include/asm/mmu_context.h |    5 +++
 arch/powerpc/include/asm/pkeys.h       |   45 ++++++++++++++++++++++++++++++++
 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                |   33 +++++++++++++++++++++++
 7 files changed, 105 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/include/asm/pkeys.h
 create mode 100644 arch/powerpc/mm/pkeys.c
arch/powerpc/Kconfig +0 -0
index 9fc3c0b..a4cd210 100644

arch/powerpc/Kconfig config SECCOMP · line 871

Quoted 8 lines
arch/powerpc/Kconfig +5 -0
@@ -864,6 +864,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

This is not sufficient right, you need PPC_BOOK3S_64 for compile time at-least?

Quoted 144 lines
arch/powerpc/Kconfig +11 -0
+	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
arch/powerpc/include/asm/mmu_context.h +5 -0
index 3095925..7badf29 100644
@@ -141,5 +141,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 */
arch/powerpc/include/asm/pkeys.h new file +45 -0
new file mode 100644
index 0000000..c02305a
@@ -0,0 +1,45 @@
+#ifndef _ASM_PPC64_PKEYS_H
+#define _ASM_PPC64_PKEYS_H
+
+extern bool pkey_inited;
+extern bool pkey_execute_disable_support;
+#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;
+}
+
+extern void pkey_initialize(void);
+#endif /*_ASM_PPC64_PKEYS_H */
arch/powerpc/kernel/setup_64.c +4 -0
index b89c6aa..3b67014 100644
@@ -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
arch/powerpc/mm/Makefile +1 -0
index fb844d2..927620a 100644
@@ -43,3 +43,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
arch/powerpc/mm/hash_utils_64.c +1 -0
index 0dff57b..67f62b5 100644
@@ -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>
arch/powerpc/mm/pkeys.c new file +15 -0
new file mode 100644
index 0000000..418a05b
@@ -0,0 +1,33 @@
+/*
+ * 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 <linux/pkeys.h>                /* PKEY_*                       */

arch/powerpc/mm/pkeys.c line 25

Quoted 10 lines
arch/powerpc/mm/pkeys.c new file +10 -0
+
+bool pkey_inited;
+bool pkey_execute_disable_support;
+
+void __init pkey_initialize(void)
+{
+	/* disable the pkey system till everything
+	 * is in place. A patch further down the
+	 * line will enable it.
+	 */

Comment style is broken

arch/powerpc/mm/pkeys.c line 33

Quoted 8 lines
arch/powerpc/mm/pkeys.c new file +8 -0
+	pkey_inited = false;
+
+	/*
+	 * disable execute_disable support for now.
+	 * A patch further down will enable it.
+	 */
+	pkey_execute_disable_support = false;
+}

Balbir Singh.

author
#34 lore raw

Re: [PATCH 01/25] powerpc: initial pkey plumbing

Quoted 28 lines · Balbir Singh
Quoted 25 lines · On Fri, 8 Sep 2017 15:44:49 -0700 Ram Pai <[email protected]> wrote:

Basic plumbing to initialize the pkey system.
Nothing is enabled yet. A later patch will enable it ones all the infrastructure is in place.

---
 arch/powerpc/Kconfig                   |   16 +++++++++++
 arch/powerpc/include/asm/mmu_context.h |    5 +++
 arch/powerpc/include/asm/pkeys.h       |   45 ++++++++++++++++++++++++++++++++
 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                |   33 +++++++++++++++++++++++
 7 files changed, 105 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/include/asm/pkeys.h
 create mode 100644 arch/powerpc/mm/pkeys.c
arch/powerpc/Kconfig +0 -0
index 9fc3c0b..a4cd210 100644
@@ -864,6 +864,22 @@ config SECCOMP
 
 	  If unsure, say Y. Only embedded should say N here.
 
Quoted 8 lines

arch/powerpc/Kconfig config SECCOMP · line 871

Quoted 5 lines
arch/powerpc/Kconfig +5 -0
+config PPC64_MEMORY_PROTECTION_KEYS
+	prompt "PowerPC Memory Protection Keys"
+	def_bool y
+	# Note: only available in 64-bit mode
+	depends on PPC64

This is not sufficient right, you need PPC_BOOK3S_64 for compile time at-least?

Ok. Not thought too deep about this. Thanks for the input.

Quoted 3 lines
Quoted 3 lines
arch/powerpc/Kconfig +2 -0
+	select ARCH_USES_HIGH_VMA_FLAGS
+

.....

Quoted 9 lines

arch/powerpc/Kconfig

Quoted 6 lines
arch/powerpc/Kconfig +6 -0
+void __init pkey_initialize(void)
+{
+	/* disable the pkey system till everything
+	 * is in place. A patch further down the
+	 * line will enable it.
+	 */

Comment style is broken

checkpatch.pl does not complain. So is it really a broken comment style, or is it checkpatch.pl needs to be fixed?

RP

#35 lore raw

Re: [PATCH 01/25] powerpc: initial pkey plumbing

In reply to Ram Pai

arch/powerpc/Kconfig config SECCOMP · line 867

Quoted 9 lines · Ram Pai
arch/powerpc/Kconfig +1 -0
index 9fc3c0b..a4cd210 100644
@@ -864,6 +864,22 @@ config SECCOMP
 
 	  If unsure, say Y. Only embedded should say N here.
 
+config PPC64_MEMORY_PROTECTION_KEYS

That's pretty wordy, can we make it CONFIG_PPC_MEM_KEYS ?

I think you're a sufficient vim wizard to search and replace all usages at once, if not I can do it before I apply the series.

arch/powerpc/Kconfig config SECCOMP · line 870

Quoted 3 lines
arch/powerpc/Kconfig +3 -0
+	prompt "PowerPC Memory Protection Keys"
+	def_bool y
+	# Note: only available in 64-bit mode

We don't need the note, that's exactly what the next line says:

arch/powerpc/Kconfig config SECCOMP · line 871

Quoted 1 line
arch/powerpc/Kconfig +1 -0
+	depends on PPC64

But shouldn't it be BOOK3S_64 ?

I don't think it works on BookE does it?

arch/powerpc/Kconfig config SECCOMP · line 874

Quoted 3 lines
arch/powerpc/Kconfig +3 -0
+	select ARCH_USES_HIGH_VMA_FLAGS
+	select ARCH_HAS_PKEYS
+	---help---

I prefer just "help".

arch/powerpc/include/asm/mmu_context.h static inline bool arch_vma_access_permitted(struct vm_area_struct *vma, · line 147

Quoted 12 lines
arch/powerpc/include/asm/mmu_context.h +4 -0
index 3095925..7badf29 100644
@@ -141,5 +141,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 */

You don't need ifdefs around that. But you also don't need it (see below).

arch/powerpc/include/asm/pkeys.h line 2

Quoted 8 lines
arch/powerpc/include/asm/pkeys.h new file +2 -0
new file mode 100644
index 0000000..c02305a
@@ -0,0 +1,45 @@
+#ifndef _ASM_PPC64_PKEYS_H
+#define _ASM_PPC64_PKEYS_H

_ASM_POWERPC_KEYS_H

Missing copyright header here.

arch/powerpc/include/asm/pkeys.h line 10

Quoted 8 lines
arch/powerpc/include/asm/pkeys.h new file +8 -0
+
+extern bool pkey_inited;
+extern bool pkey_execute_disable_support;
+#define ARCH_VM_PKEY_FLAGS 0
+
+static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
+{
+	return (pkey == 0);

That means pkey 1 is not allocated and pkey 0 is?

Surely this should just return false for now?

Quoted 13 lines
arch/powerpc/include/asm/pkeys.h new file +13 -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;
+}
+
+/*

arch/powerpc/include/asm/pkeys.h line 33

Quoted 10 lines
arch/powerpc/include/asm/pkeys.h new file +10 -0
+ * 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)

static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
int prot, int pkey)

arch/powerpc/kernel/setup_64.c void __init early_setup(unsigned long dt_ptr) · line 322

Quoted 11 lines
arch/powerpc/kernel/setup_64.c +3 -0
index b89c6aa..3b67014 100644
@@ -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();
+

I'm not sure we need to initialise this that early, but if we do, it should be done in early_init_mmu(), not here.

arch/powerpc/mm/hash_utils_64.c line 38

Quoted 9 lines
arch/powerpc/mm/hash_utils_64.c +1 -0
index 0dff57b..67f62b5 100644
@@ -35,6 +35,7 @@
 #include <linux/memblock.h>
 #include <linux/context_tracking.h>
 #include <linux/libfdt.h>
+#include <linux/pkeys.h>

This should go in a later patch when it's needed.

arch/powerpc/mm/pkeys.c line 3

Quoted 9 lines
arch/powerpc/mm/pkeys.c new file +3 -0
new file mode 100644
index 0000000..418a05b
@@ -0,0 +1,33 @@
+/*
+ * PowerPC Memory Protection Keys management
+ * Copyright (c) 2015, Intel Corporation.

Is any of it really copyright Intel?

arch/powerpc/mm/pkeys.c line 8

Quoted 5 lines
arch/powerpc/mm/pkeys.c new file +5 -0
+ * 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.

We're meant to use "or later" on new code.

arch/powerpc/mm/pkeys.c line 13

Quoted 5 lines
arch/powerpc/mm/pkeys.c new file +5 -0
+ *
+ * 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.

But not this part.

arch/powerpc/mm/pkeys.c line 14

Quoted 1 line
arch/powerpc/mm/pkeys.c new file +1 -0
+ */

Blank line.

arch/powerpc/mm/pkeys.c line 15

Quoted 1 line
arch/powerpc/mm/pkeys.c new file +1 -0
+#include <linux/pkeys.h>                /* PKEY_*                       */

Comment is wrong and unnecessary.

arch/powerpc/mm/pkeys.c line 25

Quoted 9 lines
arch/powerpc/mm/pkeys.c new file +9 -0
+bool pkey_inited;
+bool pkey_execute_disable_support;
+
+void __init pkey_initialize(void)
+{
+	/* disable the pkey system till everything
+	 * is in place. A patch further down the
+	 * line will enable it.
+	 */
	/*
         * Disable the pkey system till everything is in place. A patch
         * further down the line will enable it.
	 */

I'm going to stop commenting on every badly formatted comment :)

arch/powerpc/mm/pkeys.c line 32

Quoted 7 lines
arch/powerpc/mm/pkeys.c new file +7 -0
+	pkey_inited = false;
+
+	/*
+	 * disable execute_disable support for now.
+	 * A patch further down will enable it.
+	 */
+	pkey_execute_disable_support = false;

Those are both false anyway, so I'm not sure we really needed to initialise them to false again, but I don't feel that strongly about it.

cheers

author
#36 lore raw

Re: [PATCH 01/25] powerpc: initial pkey plumbing

Quoted 8 lines · Michael Ellerman
Quoted 6 lines · Ram Pai
arch/powerpc/Kconfig +0 -0
index 9fc3c0b..a4cd210 100644
@@ -864,6 +864,22 @@ config SECCOMP
 
Quoted 8 lines

arch/powerpc/Kconfig config SECCOMP · line 867

Quoted 3 lines
arch/powerpc/Kconfig +1 -0
 	  If unsure, say Y. Only embedded should say N here.
 
+config PPC64_MEMORY_PROTECTION_KEYS

That's pretty wordy, can we make it CONFIG_PPC_MEM_KEYS ?

I think you're a sufficient vim wizard to search and replace all usages at once,

I take that as a compliment for now ;)

Quoted 1 line

if not I can do it before I apply the series.

Will change it...just that I was trying to keep it similar to what intel has X86_INTEL_MEMORY_PROTECTION_KEYS

Quoted 10 lines

arch/powerpc/Kconfig config SECCOMP · line 870

Quoted 4 lines
arch/powerpc/Kconfig +3 -0
+	prompt "PowerPC Memory Protection Keys"
+	def_bool y
+	# Note: only available in 64-bit mode

We don't need the note, that's exactly what the next line says:

arch/powerpc/Kconfig config SECCOMP · line 871

Quoted 1 line
arch/powerpc/Kconfig +1 -0
+	depends on PPC64

But shouldn't it be BOOK3S_64 ?

Quoted 7 lines

I don't think it works on BookE does it?

arch/powerpc/Kconfig config SECCOMP · line 874

Quoted 3 lines
arch/powerpc/Kconfig +3 -0
+	select ARCH_USES_HIGH_VMA_FLAGS
+	select ARCH_HAS_PKEYS
+	---help---

I prefer just "help".

ok.

Quoted 7 lines

arch/powerpc/include/asm/mmu_context.h static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,

Quoted 6 lines
arch/powerpc/include/asm/mmu_context.h +0 -0
index 3095925..7badf29 100644
@@ -141,5 +141,10 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
	/*

....snip...

Quoted 5 lines

* Disable the pkey system till everything is in place. A patch
* further down the line will enable it.
*/

I'm going to stop commenting on every badly formatted comment :)

did not realize I had acquired a habit for badly formatted comments. :-( Sorry for causing the pain. Will fix it.

RP

#37 lore raw

Re: [PATCH 01/25] powerpc: initial pkey plumbing

Quoted 18 lines · Ram Pai
Quoted 8 lines · Michael Ellerman
Quoted 6 lines · Ram Pai
arch/powerpc/Kconfig +0 -0
index 9fc3c0b..a4cd210 100644
@@ -864,6 +864,22 @@ config SECCOMP
 
Quoted 8 lines

arch/powerpc/Kconfig config SECCOMP · line 867

Quoted 3 lines
arch/powerpc/Kconfig +1 -0
 	  If unsure, say Y. Only embedded should say N here.
 
+config PPC64_MEMORY_PROTECTION_KEYS

That's pretty wordy, can we make it CONFIG_PPC_MEM_KEYS ?

I think you're a sufficient vim wizard to search and replace all usages at once,

Quoted 6 lines

I take that as a compliment for now ;)

Quoted 1 line

if not I can do it before I apply the series.

Will change it...just that I was trying to keep it similar to what intel has X86_INTEL_MEMORY_PROTECTION_KEYS

Yeah I realise that's why you chose that name, but I'd still prefer something shorter. I don't think it matters that the CONFIG names are slightly different between the arches, it's still pretty clear what it's for I think.

cheers

author
#38 lore raw

PATCH 2/25 powerpc: define an additional vma bit for protection keys.

In reply to Ram Pai

powerpc needs an additional vma bit to support 32 keys. Till the additional vma bit lands in include/linux/mm.h we have to define it in powerpc specific header file. This is needed to get pkeys working on power.

---
 arch/powerpc/include/asm/pkeys.h |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +18 -0
index c02305a..44e01a2 100644
@@ -3,6 +3,24 @@
 
 extern bool pkey_inited;
 extern bool pkey_execute_disable_support;
+
+/*
+ * powerpc needs an additional vma bit to support 32 keys.
+ * Till the additional vma bit lands in include/linux/mm.h
+ * we have to carry the hunk below. This is  needed to get
+ * pkeys working on power. -- Ram
+ */
+#ifndef VM_HIGH_ARCH_BIT_4
+#define VM_HIGH_ARCH_BIT_4	36
+#define VM_HIGH_ARCH_4	BIT(VM_HIGH_ARCH_BIT_4)
+#define VM_PKEY_SHIFT VM_HIGH_ARCH_BIT_0
+#define VM_PKEY_BIT0	VM_HIGH_ARCH_0
+#define VM_PKEY_BIT1	VM_HIGH_ARCH_1
+#define VM_PKEY_BIT2	VM_HIGH_ARCH_2
+#define VM_PKEY_BIT3	VM_HIGH_ARCH_3
+#define VM_PKEY_BIT4	VM_HIGH_ARCH_4
+#endif
+
 #define ARCH_VM_PKEY_FLAGS 0
 
 static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
Signature · 1 line
1.7.1
#39 lore raw

Re: [PATCH 02/25] powerpc: define an additional vma bit for protection keys.

Quoted 7 lines · On Fri, 8 Sep 2017 15:44:50 -0700 Ram Pai <[email protected]> wrote:

powerpc needs an additional vma bit to support 32 keys. Till the additional vma bit lands in include/linux/mm.h we have to define it in powerpc specific header file. This is needed to get pkeys working on power.

---

"This" being an arch specific hack for the additional bit?

Balbir

#40 lore raw

Re: [PATCH 02/25] powerpc: define an additional vma bit for protection keys.

Quoted 8 lines · Balbir Singh
Quoted 5 lines · On Fri, 8 Sep 2017 15:44:50 -0700 Ram Pai <[email protected]> wrote:

powerpc needs an additional vma bit to support 32 keys. Till the additional vma bit lands in include/linux/mm.h we have to define it in powerpc specific header file. This is needed to get pkeys working on power.

Quoted 4 lines
Quoted 2 lines

---

"This" being an arch specific hack for the additional bit?

Arch VMA bits ? really ? I'd rather we limit ourselves to 16 keys first then push for adding the extra bit to the generic code.

Ben.

author
#41 lore raw

Re: [PATCH 02/25] powerpc: define an additional vma bit for protection keys.

Quoted 9 lines · Benjamin Herrenschmidt
Quoted 8 lines · Balbir Singh
Quoted 5 lines · On Fri, 8 Sep 2017 15:44:50 -0700 Ram Pai <[email protected]> wrote:

powerpc needs an additional vma bit to support 32 keys. Till the additional vma bit lands in include/linux/mm.h we have to define it in powerpc specific header file. This is needed to get pkeys working on power.

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

---

"This" being an arch specific hack for the additional bit?

Arch VMA bits ? really ? I'd rather we limit ourselves to 16 keys first then push for adding the extra bit to the generic code.

(hmm.. this mail did not land in my mailbox :( Sorry for the delay. Just saw it in the mailing list.)

I think this is good idea. I can code it such a way that we support 16 or 32 keys depending on the availability of the vma bit.

No more hunks in the code.

RP

author
#42 lore raw

Re: [PATCH 02/25] powerpc: define an additional vma bit for protection keys.

In reply to Balbir Singh
Quoted 8 lines · Balbir Singh
Quoted 5 lines · On Fri, 8 Sep 2017 15:44:50 -0700 Ram Pai <[email protected]> wrote:

powerpc needs an additional vma bit to support 32 keys. Till the additional vma bit lands in include/linux/mm.h we have to define it in powerpc specific header file. This is needed to get pkeys working on power.

Quoted 4 lines
Quoted 2 lines

---

"This" being an arch specific hack for the additional bit?

Yes. arch-specific hack. I am trying to get the arch specific changes merged parallelly, along with these patches. Don't know which one will merge first. Regardless of which patch-set lands-in first; I have organized the code such that nothing breaks.

RP

#43 lore raw

Re: [PATCH 02/25] powerpc: define an additional vma bit for protection keys.

In reply to Ram Pai
Quoted 27 lines · Ram Pai

powerpc needs an additional vma bit to support 32 keys. Till the additional vma bit lands in include/linux/mm.h we have to define it in powerpc specific header file. This is needed to get pkeys working on power.

---
 arch/powerpc/include/asm/pkeys.h |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +9 -0
index c02305a..44e01a2 100644
@@ -3,6 +3,24 @@
 
 extern bool pkey_inited;
 extern bool pkey_execute_disable_support;
+
+/*
+ * powerpc needs an additional vma bit to support 32 keys.
+ * Till the additional vma bit lands in include/linux/mm.h
+ * we have to carry the hunk below. This is  needed to get
+ * pkeys working on power. -- Ram
+ */
+#ifndef VM_HIGH_ARCH_BIT_4
+#define VM_HIGH_ARCH_BIT_4	36

arch/powerpc/include/asm/pkeys.h line 24

Quoted 10 lines
arch/powerpc/include/asm/pkeys.h +9 -0
+#define VM_HIGH_ARCH_4	BIT(VM_HIGH_ARCH_BIT_4)
+#define VM_PKEY_SHIFT VM_HIGH_ARCH_BIT_0
+#define VM_PKEY_BIT0	VM_HIGH_ARCH_0
+#define VM_PKEY_BIT1	VM_HIGH_ARCH_1
+#define VM_PKEY_BIT2	VM_HIGH_ARCH_2
+#define VM_PKEY_BIT3	VM_HIGH_ARCH_3
+#define VM_PKEY_BIT4	VM_HIGH_ARCH_4
+#endif
+
 #define ARCH_VM_PKEY_FLAGS 0

Do we want them in pkeys.h ? Even if they are arch specific for the existing ones we have them in include/linux/mm.h. IIUC, vmflags details are always in mm.h? This will be the first exception to that?

Quoted 4 lines
arch/powerpc/include/asm/pkeys.h +0 -0
 static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
Signature · 1 line
1.7.1
#44 lore raw

Re: [PATCH 02/25] powerpc: define an additional vma bit for protection keys.

Quoted 35 lines · Aneesh Kumar K.V
Quoted 33 lines · Ram Pai

powerpc needs an additional vma bit to support 32 keys. Till the additional vma bit lands in include/linux/mm.h we have to define it in powerpc specific header file. This is needed to get pkeys working on power.

---
 arch/powerpc/include/asm/pkeys.h |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +15 -0
index c02305a..44e01a2 100644
@@ -3,6 +3,24 @@
 
 extern bool pkey_inited;
 extern bool pkey_execute_disable_support;
+
+/*
+ * powerpc needs an additional vma bit to support 32 keys.
+ * Till the additional vma bit lands in include/linux/mm.h
+ * we have to carry the hunk below. This is  needed to get
+ * pkeys working on power. -- Ram
+ */
+#ifndef VM_HIGH_ARCH_BIT_4
+#define VM_HIGH_ARCH_BIT_4	36
+#define VM_HIGH_ARCH_4	BIT(VM_HIGH_ARCH_BIT_4)
+#define VM_PKEY_SHIFT VM_HIGH_ARCH_BIT_0
+#define VM_PKEY_BIT0	VM_HIGH_ARCH_0
+#define VM_PKEY_BIT1	VM_HIGH_ARCH_1
+#define VM_PKEY_BIT2	VM_HIGH_ARCH_2
+#define VM_PKEY_BIT3	VM_HIGH_ARCH_3
Quoted 8 lines

arch/powerpc/include/asm/pkeys.h line 24

Quoted 4 lines
arch/powerpc/include/asm/pkeys.h +3 -0
+#define VM_PKEY_BIT4	VM_HIGH_ARCH_4
+#endif
+
 #define ARCH_VM_PKEY_FLAGS 0

Do we want them in pkeys.h ? Even if they are arch specific for the existing ones we have them in include/linux/mm.h. IIUC, vmflags details are always in mm.h? This will be the first exception to that?

Also can we move that

#if defined (CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS)

# define VM_PKEY_SHIFT	VM_HIGH_ARCH_BIT_0
# define VM_PKEY_BIT0	VM_HIGH_ARCH_0	/* A protection key is a 4-bit value */
# define VM_PKEY_BIT1	VM_HIGH_ARCH_1
# define VM_PKEY_BIT2	VM_HIGH_ARCH_2
# define VM_PKEY_BIT3	VM_HIGH_ARCH_3
#endif

to

#if defined (CONFIG_ARCH_HAS_PKEYS)

# define VM_PKEY_SHIFT	VM_HIGH_ARCH_BIT_0
# define VM_PKEY_BIT0	VM_HIGH_ARCH_0	/* A protection key is a 4-bit value */
# define VM_PKEY_BIT1	VM_HIGH_ARCH_1
# define VM_PKEY_BIT2	VM_HIGH_ARCH_2
# define VM_PKEY_BIT3	VM_HIGH_ARCH_3
#endif

And then later update the generic to handle PKEY_BIT4?

-aneesh

author
#45 lore raw

Re: [PATCH 02/25] powerpc: define an additional vma bit for protection keys.

Quoted 68 lines · Aneesh Kumar K.V
Quoted 35 lines · Aneesh Kumar K.V
Quoted 33 lines · Ram Pai

powerpc needs an additional vma bit to support 32 keys. Till the additional vma bit lands in include/linux/mm.h we have to define it in powerpc specific header file. This is needed to get pkeys working on power.

---
 arch/powerpc/include/asm/pkeys.h |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +15 -0
index c02305a..44e01a2 100644
@@ -3,6 +3,24 @@
 
 extern bool pkey_inited;
 extern bool pkey_execute_disable_support;
+
+/*
+ * powerpc needs an additional vma bit to support 32 keys.
+ * Till the additional vma bit lands in include/linux/mm.h
+ * we have to carry the hunk below. This is  needed to get
+ * pkeys working on power. -- Ram
+ */
+#ifndef VM_HIGH_ARCH_BIT_4
+#define VM_HIGH_ARCH_BIT_4	36
+#define VM_HIGH_ARCH_4	BIT(VM_HIGH_ARCH_BIT_4)
+#define VM_PKEY_SHIFT VM_HIGH_ARCH_BIT_0
+#define VM_PKEY_BIT0	VM_HIGH_ARCH_0
+#define VM_PKEY_BIT1	VM_HIGH_ARCH_1
+#define VM_PKEY_BIT2	VM_HIGH_ARCH_2
+#define VM_PKEY_BIT3	VM_HIGH_ARCH_3
Quoted 8 lines

arch/powerpc/include/asm/pkeys.h line 24

Quoted 4 lines
arch/powerpc/include/asm/pkeys.h +3 -0
+#define VM_PKEY_BIT4	VM_HIGH_ARCH_4
+#endif
+
 #define ARCH_VM_PKEY_FLAGS 0

Do we want them in pkeys.h ? Even if they are arch specific for the existing ones we have them in include/linux/mm.h. IIUC, vmflags details are always in mm.h? This will be the first exception to that?

Also can we move that

#if defined (CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS)

# define VM_PKEY_SHIFT	VM_HIGH_ARCH_BIT_0
# define VM_PKEY_BIT0	VM_HIGH_ARCH_0	/* A protection key is a 4-bit value */
# define VM_PKEY_BIT1	VM_HIGH_ARCH_1
# define VM_PKEY_BIT2	VM_HIGH_ARCH_2
# define VM_PKEY_BIT3	VM_HIGH_ARCH_3
#endif

to

#if defined (CONFIG_ARCH_HAS_PKEYS)

# define VM_PKEY_SHIFT	VM_HIGH_ARCH_BIT_0
# define VM_PKEY_BIT0	VM_HIGH_ARCH_0	/* A protection key is a 4-bit value */
# define VM_PKEY_BIT1	VM_HIGH_ARCH_1
# define VM_PKEY_BIT2	VM_HIGH_ARCH_2
# define VM_PKEY_BIT3	VM_HIGH_ARCH_3
#endif
Quoted 1 line

And then later update the generic to handle PKEY_BIT4?

Yes. The above changes have been implemented in a patch sent to the mm mailing list as well as to lkml.

https://lkml.org/lkml/2017/9/15/504

RP

author
#46 lore raw

Re: [PATCH 02/25] powerpc: define an additional vma bit for protection keys.

In reply to Aneesh Kumar K.V
Quoted 35 lines · Aneesh Kumar K.V
Quoted 33 lines · Ram Pai

powerpc needs an additional vma bit to support 32 keys. Till the additional vma bit lands in include/linux/mm.h we have to define it in powerpc specific header file. This is needed to get pkeys working on power.

---
 arch/powerpc/include/asm/pkeys.h |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +15 -0
index c02305a..44e01a2 100644
@@ -3,6 +3,24 @@
 
 extern bool pkey_inited;
 extern bool pkey_execute_disable_support;
+
+/*
+ * powerpc needs an additional vma bit to support 32 keys.
+ * Till the additional vma bit lands in include/linux/mm.h
+ * we have to carry the hunk below. This is  needed to get
+ * pkeys working on power. -- Ram
+ */
+#ifndef VM_HIGH_ARCH_BIT_4
+#define VM_HIGH_ARCH_BIT_4	36
+#define VM_HIGH_ARCH_4	BIT(VM_HIGH_ARCH_BIT_4)
+#define VM_PKEY_SHIFT VM_HIGH_ARCH_BIT_0
+#define VM_PKEY_BIT0	VM_HIGH_ARCH_0
+#define VM_PKEY_BIT1	VM_HIGH_ARCH_1
+#define VM_PKEY_BIT2	VM_HIGH_ARCH_2
+#define VM_PKEY_BIT3	VM_HIGH_ARCH_3
Quoted 8 lines

arch/powerpc/include/asm/pkeys.h line 24

Quoted 4 lines
arch/powerpc/include/asm/pkeys.h +3 -0
+#define VM_PKEY_BIT4	VM_HIGH_ARCH_4
+#endif
+
 #define ARCH_VM_PKEY_FLAGS 0

Do we want them in pkeys.h ? Even if they are arch specific for the existing ones we have them in include/linux/mm.h. IIUC, vmflags details are always in mm.h? This will be the first exception to that?

I am trying to get the real fix in include/linux/mm.h If that happens sooner than this hunk is not needed. Till then this is an exception, but it is the **ONLY** exception.

I think your point is to have this hunk in include/linux/mm.h ?

If yes, than it would be easier to push the real fix in include/linux/mm.h instead of pushing this hunk in the there.

RP

author
#47 lore raw

PATCH 3/25 powerpc: track allocation status of all pkeys

In reply to Ram Pai

Total 32 keys are available on power7 and above. However pkey 0,1 are reserved. So effectively we have 30 pkeys.

On 4K kernels, we do not have 5 bits in the PTE to represent all the keys; we only have 3bits.Two of those keys are reserved; pkey 0 and pkey 1. So effectively we have 6 pkeys.

This patch keeps track of reserved keys, allocated keys and keys that are currently free.

Also it adds skeletal functions and macros, that the architecture-independent code expects to be available.

---
 arch/powerpc/include/asm/book3s/64/mmu.h |    9 ++++
 arch/powerpc/include/asm/mmu_context.h   |    1 +
 arch/powerpc/include/asm/pkeys.h         |   72 ++++++++++++++++++++++++++++--
 arch/powerpc/mm/mmu_context_book3s64.c   |    2 +
 arch/powerpc/mm/pkeys.c                  |   28 ++++++++++++
 5 files changed, 108 insertions(+), 4 deletions(-)
arch/powerpc/include/asm/book3s/64/mmu.h +9 -0
index c3b00e8..55950f4 100644
@@ -107,6 +107,15 @@ struct patb_entry {
 #ifdef CONFIG_SPAPR_TCE_IOMMU
 	struct list_head iommu_group_mem_list;
 #endif
+
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	/*
+	 * Each bit represents one protection key.
+	 * bit set   -> key allocated
+	 * bit unset -> key available for allocation
+	 */
+	u32 pkey_allocation_map;
+#endif
 } mm_context_t;
 
 /*
arch/powerpc/include/asm/mmu_context.h +1 -0
index 7badf29..c705a5d 100644
@@ -144,6 +144,7 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
 
 #ifndef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
 #define pkey_initialize()
+#define pkey_mm_init(mm)
 #endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 
 #endif /* __KERNEL__ */
arch/powerpc/include/asm/pkeys.h +68 -4

100 lines not on this page · raw message

arch/powerpc/mm/mmu_context_book3s64.c +2 -0
index 05e1538..5df223a 100644
@@ -16,6 +16,7 @@
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/mm.h>
+#include <linux/pkeys.h>
 #include <linux/spinlock.h>
 #include <linux/idr.h>
 #include <linux/export.h>
@@ -118,6 +119,7 @@ static int hash__init_new_context(struct mm_struct *mm)
 
 	subpage_prot_init_new_context(mm);
 
+	pkey_mm_init(mm);
 	return index;
 }
 
arch/powerpc/mm/pkeys.c +28 -0
index 418a05b..ebc9e84 100644
@@ -16,9 +16,13 @@
 
 bool pkey_inited;
 bool pkey_execute_disable_support;
+int  pkeys_total;		/* total pkeys as per device tree */
+u32  initial_allocation_mask;	/* bits set for reserved keys */
 
 void __init pkey_initialize(void)
 {
+	int os_reserved, i;
+
 	/* disable the pkey system till everything
 	 * is in place. A patch further down the
 	 * line will enable it.
@@ -30,4 +34,28 @@ void __init pkey_initialize(void)
 	 * A patch further down will enable it.
 	 */
 	pkey_execute_disable_support = false;
+
+	/* Lets assume 32 keys */
+	pkeys_total = 32;
+
+#ifdef CONFIG_PPC_4K_PAGES
+	/*
+	 * the OS can manage only 8 pkeys
+	 * due to its inability to represent
+	 * them in the linux 4K-PTE.
+	 */
+	os_reserved = pkeys_total-8;
+#else
+	os_reserved = 0;
+#endif
+	/*
+	 * Bits are in LE format.
+	 * NOTE: 1, 0 are reserved.
+	 * key 0 is the default key, which allows read/write/execute.
+	 * key 1 is recommended not to be used.
+	 * PowerISA(3.0) page 1015, programming note.
+	 */
+	initial_allocation_mask = ~0x0;
+	for (i = 2; i < (pkeys_total - os_reserved); i++)
+		initial_allocation_mask &= ~(0x1<<i);
 }
Signature · 1 line
1.7.1
#48 lore raw

Re: [PATCH 03/25] powerpc: track allocation status of all pkeys

Quoted 11 lines · Ram Pai

Total 32 keys are available on power7 and above. However pkey 0,1 are reserved. So effectively we have 30 pkeys.

On 4K kernels, we do not have 5 bits in the PTE to represent all the keys; we only have 3bits.Two of those keys are reserved; pkey 0 and pkey 1. So effectively we have 6 pkeys.

This patch keeps track of reserved keys, allocated keys and keys that are currently free.

Quoted 8 lines

Also it adds skeletal functions and macros, that the architecture-independent code expects to be available.

---
 arch/powerpc/include/asm/book3s/64/mmu.h |    9 ++++
 arch/powerpc/include/asm/mmu_context.h   |    1 +

arch/powerpc/include/asm/pkeys.h | 72 ++++++++++++++++++++++++=

++++--

Quoted 3 lines
 arch/powerpc/mm/mmu_context_book3s64.c   |    2 +
 arch/powerpc/mm/pkeys.c                  |   28 ++++++++++++
 5 files changed, 108 insertions(+), 4 deletions(-)

This doesn't build for me, with pseries_le_defconfig. I assume it built for you. So something has changed upstream maybe?

In file included from ../include/linux/pkeys.h:8:0,

                 from ../mm/mprotect.c:26:
../mm/mprotect.c: In function =E2=80=98do_mprotect_pkey=E2=80=99:
../arch/powerpc/include/asm/pkeys.h:27:29: error: =E2=80=98VM_PKEY_BIT0=E2=
=80=99 undeclared (first use in this function)
 #define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
                             ^
../mm/mprotect.c:470:6: note: in expansion of macro =E2=80=98ARCH_VM_PKEY_F=
LAGS=E2=80=99
      ARCH_VM_PKEY_FLAGS;
      ^~~~~~~~~~~~~~~~~~
../arch/powerpc/include/asm/pkeys.h:27:29: note: each undeclared identifier=
 is reported only once for each function it appears in
 #define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
                             ^
../mm/mprotect.c:470:6: note: in expansion of macro =E2=80=98ARCH_VM_PKEY_F=
LAGS=E2=80=99
      ARCH_VM_PKEY_FLAGS;
      ^~~~~~~~~~~~~~~~~~
../arch/powerpc/include/asm/pkeys.h:27:44: error: =E2=80=98VM_PKEY_BIT1=E2=
=80=99 undeclared (first use in this function)
 #define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
                                            ^
../mm/mprotect.c:470:6: note: in expansion of macro =E2=80=98ARCH_VM_PKEY_F=
LAGS=E2=80=99
      ARCH_VM_PKEY_FLAGS;
      ^~~~~~~~~~~~~~~~~~
../arch/powerpc/include/asm/pkeys.h:27:59: error: =E2=80=98VM_PKEY_BIT2=E2=
=80=99 undeclared (first use in this function)
 #define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
                                                           ^
../mm/mprotect.c:470:6: note: in expansion of macro =E2=80=98ARCH_VM_PKEY_F=
LAGS=E2=80=99
      ARCH_VM_PKEY_FLAGS;
      ^~~~~~~~~~~~~~~~~~
../arch/powerpc/include/asm/pkeys.h:28:5: error: =E2=80=98VM_PKEY_BIT3=E2=
=80=99 undeclared (first use in this function)
     VM_PKEY_BIT3 | VM_PKEY_BIT4)
     ^
../mm/mprotect.c:470:6: note: in expansion of macro =E2=80=98ARCH_VM_PKEY_F=
LAGS=E2=80=99
      ARCH_VM_PKEY_FLAGS;
      ^~~~~~~~~~~~~~~~~~
../arch/powerpc/include/asm/pkeys.h:28:20: error: =E2=80=98VM_PKEY_BIT4=E2=
=80=99 undeclared (first use in this function)
     VM_PKEY_BIT3 | VM_PKEY_BIT4)
                    ^
../mm/mprotect.c:470:6: note: in expansion of macro =E2=80=98ARCH_VM_PKEY_F=
LAGS=E2=80=99
      ARCH_VM_PKEY_FLAGS;
      ^~~~~~~~~~~~~~~~~~

../scripts/Makefile.build:311: recipe for target 'mm/mprotect.o' failed

cheers

author
#49 lore raw

Re: [PATCH 03/25] powerpc: track allocation status of all pkeys

Quoted 25 lines · Michael Ellerman
Quoted 14 lines · Ram Pai

Total 32 keys are available on power7 and above. However pkey 0,1 are reserved. So effectively we have 30 pkeys.

On 4K kernels, we do not have 5 bits in the PTE to represent all the keys; we only have 3bits.Two of those keys are reserved; pkey 0 and pkey 1. So effectively we have 6 pkeys.

This patch keeps track of reserved keys, allocated keys and keys that are currently free.

Also it adds skeletal functions and macros, that the architecture-independent code expects to be available.

Quoted 8 lines
---
 arch/powerpc/include/asm/book3s/64/mmu.h |    9 ++++
 arch/powerpc/include/asm/mmu_context.h   |    1 +
 arch/powerpc/include/asm/pkeys.h         |   72 ++++++++++++++++++++++++++++--
 arch/powerpc/mm/mmu_context_book3s64.c   |    2 +
 arch/powerpc/mm/pkeys.c                  |   28 ++++++++++++
 5 files changed, 108 insertions(+), 4 deletions(-)
Quoted 3 lines

This doesn't build for me, with pseries_le_defconfig. I assume it built for you. So something has changed upstream maybe?

Yes. :(
The following commit upstream broke my patches.
df3735c5b40fad8d0d28eb8ab065fe955b3347ee

Will fix and send you a patch.

RP

Quoted 7 lines

In file included from ../include/linux/pkeys.h:8:0,

                 from ../mm/mprotect.c:26:
../mm/mprotect.c: In function ‘do_mprotect_pkey’:
../arch/powerpc/include/asm/pkeys.h:27:29: error: ‘VM_PKEY_BIT0’ undeclared (first use in this function)
 #define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
                             ^

..snip...

#50 lore raw

Re: [PATCH 03/25] powerpc: track allocation status of all pkeys

In reply to Ram Pai
Quoted 8 lines · On Fri, 8 Sep 2017 15:44:51 -0700 Ram Pai <[email protected]> wrote:

Total 32 keys are available on power7 and above. However pkey 0,1 are reserved. So effectively we have 30 pkeys.

On 4K kernels, we do not have 5 bits in the PTE to represent all the keys; we only have 3bits.Two of those keys are reserved; pkey 0 and pkey 1. So effectively we have 6 pkeys.

Quoted 7 lines

This patch keeps track of reserved keys, allocated keys and keys that are currently free.

Also it adds skeletal functions and macros, that the architecture-independent code expects to be available.

I ended up reviewing v7 of the patch. Is this v8?
I think the comments still apply to this revision

Balbir Singh.

#51 lore raw

Re: [PATCH 03/25] powerpc: track allocation status of all pkeys

In reply to Ram Pai
Quoted 2 lines · Ram Pai

Total 32 keys are available on power7 and above. However pkey 0,1 are reserved. So effectively we have 30 pkeys.

When you say reserved, reserved by whom? Is that part of ISA or PAPR ? Also do you expect that to change. If not why all these indirection? Can we have the mask as a #define for 4K and 64K page size config?

Quoted 11 lines

On 4K kernels, we do not have 5 bits in the PTE to represent all the keys; we only have 3bits.Two of those keys are reserved; pkey 0 and pkey 1. So effectively we have 6 pkeys.

This patch keeps track of reserved keys, allocated keys and keys that are currently free.

Also it adds skeletal functions and macros, that the architecture-independent code expects to be available.

-aneesh

author
#52 lore raw

Re: [PATCH 03/25] powerpc: track allocation status of all pkeys

Quoted 9 lines · Aneesh Kumar K.V
Quoted 2 lines · Ram Pai

Total 32 keys are available on power7 and above. However pkey 0,1 are reserved. So effectively we have 30 pkeys.

When you say reserved, reserved by whom? Is that part of ISA or PAPR ? Also do you expect that to change. If not why all these indirection? Can we have the mask as a #define for 4K and 64K page size config?

The reserved keys cannot be determined
statically. It depends on the platform and the key info exported to us by the device-tree. Hence it cannot be macro'd.

One of the subsequent patch, reads the device tree and sets pkeys_total appropriately. FYI.

BTW: key 0 is reserved by the ISA. key 1 is reserved, but its nebulous. There is a programming note in the ISA to avoid key 1. Also testing and experimentation with key 1 lead to unpredicatable behavior on powervm. Key 31 may or may not be used by the hypervisor. The device tree has to be referred to determine that.

Bottomline, the mask can be determined only during runtime.

RP

#53 lore raw

Re: [PATCH 03/25] powerpc: track allocation status of all pkeys

In reply to Ram Pai

Ram Pai <[email protected]> writes:
+

arch/powerpc/include/asm/pkeys.h line 54

Quoted 13 lines
arch/powerpc/include/asm/pkeys.h +7 -1
+#define mm_set_pkey_is_allocated(mm, pkey)	\
+	(mm_pkey_allocation_map(mm) & pkey_alloc_mask(pkey))
+
 
 static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
 {
-	return (pkey == 0);
+	/* a reserved key is never considered as 'explicitly allocated' */
+	return ((pkey < arch_max_pkey()) &&
+		!mm_set_pkey_is_reserved(mm, pkey) &&
+		mm_set_pkey_is_allocated(mm, pkey));
 }

that is confusing naming. what is mm_set_pkey_is_allocated()? . 'set' in that name is confusing.

-aneesh

author
#54 lore raw

Re: [PATCH 03/25] powerpc: track allocation status of all pkeys

Quoted 6 lines · Aneesh Kumar K.V

Ram Pai <[email protected]> writes:
+

Quoted 3 lines
arch/powerpc/include/asm/pkeys.h +3 -0
+#define mm_set_pkey_is_allocated(mm, pkey)	\
+	(mm_pkey_allocation_map(mm) & pkey_alloc_mask(pkey))
+
Quoted 12 lines

arch/powerpc/include/asm/pkeys.h line 54

Quoted 9 lines

static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey) {

arch/powerpc/include/asm/pkeys.h +4 -1
-	return (pkey == 0);
+	/* a reserved key is never considered as 'explicitly allocated' */
+	return ((pkey < arch_max_pkey()) &&
+		!mm_set_pkey_is_reserved(mm, pkey) &&
+		mm_set_pkey_is_allocated(mm, pkey));
 }

that is confusing naming. what is mm_set_pkey_is_allocated()? . 'set' in that name is confusing.

will change it by removing the 'set' in the names.

thanks,
RP

author
#55 lore raw

PATCH 4/25 powerpc: helper function to read, write AMR, IAMR, UAMOR registers

In reply to Ram Pai

Implements helper functions to read and write the key related registers; AMR, IAMR, UAMOR.

AMR register tracks the read,write permission of a key IAMR register tracks the execute permission of a key UAMOR register enables and disables a key

---
 arch/powerpc/include/asm/book3s/64/pgtable.h |   31 ++++++++++++++++++++++++++
 1 files changed, 31 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/book3s/64/pgtable.h +31 -0
index b9aff51..73ed52c 100644
@@ -438,6 +438,37 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
 		pte_update(mm, addr, ptep, 0, _PAGE_PRIVILEGED, 1);
 }
 
+#include <asm/reg.h>
+static inline u64 read_amr(void)
+{
+	return mfspr(SPRN_AMR);
+}
+static inline void write_amr(u64 value)
+{
+	mtspr(SPRN_AMR, value);
+}
+extern bool pkey_execute_disable_support;
+static inline u64 read_iamr(void)
+{
+	if (pkey_execute_disable_support)
+		return mfspr(SPRN_IAMR);
+	else
+		return 0x0UL;
+}
+static inline void write_iamr(u64 value)
+{
+	if (pkey_execute_disable_support)
+		mtspr(SPRN_IAMR, value);
+}
+static inline u64 read_uamor(void)
+{
+	return mfspr(SPRN_UAMOR);
+}
+static inline void write_uamor(u64 value)
+{
+	mtspr(SPRN_UAMOR, value);
+}
+
 #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)
Signature · 1 line
1.7.1
Acked-by on v1 4/25
#56 lore raw

Re: [PATCH 04/25] powerpc: helper function to read,write AMR,IAMR,UAMOR registers

Quoted 19 lines · On Fri, 8 Sep 2017 15:44:52 -0700 Ram Pai <[email protected]> wrote:

Implements helper functions to read and write the key related registers; AMR, IAMR, UAMOR.

AMR register tracks the read,write permission of a key IAMR register tracks the execute permission of a key UAMOR register enables and disables a key

---
 arch/powerpc/include/asm/book3s/64/pgtable.h |   31 ++++++++++++++++++++++++++
 1 files changed, 31 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/book3s/64/pgtable.h +0 -0
index b9aff51..73ed52c 100644
@@ -438,6 +438,37 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
 		pte_update(mm, addr, ptep, 0, _PAGE_PRIVILEGED, 1);
 }

arch/powerpc/include/asm/book3s/64/pgtable.h static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, · line 449

Quoted 10 lines
arch/powerpc/include/asm/book3s/64/pgtable.h +9 -0
 
+#include <asm/reg.h>
+static inline u64 read_amr(void)
+{
+	return mfspr(SPRN_AMR);
+}
+static inline void write_amr(u64 value)
+{
+	mtspr(SPRN_AMR, value);
+}

Do we care to validate values or is that in
the caller

Quoted 15 lines
arch/powerpc/include/asm/book3s/64/pgtable.h +15 -0
+extern bool pkey_execute_disable_support;
+static inline u64 read_iamr(void)
+{
+	if (pkey_execute_disable_support)
+		return mfspr(SPRN_IAMR);
+	else
+		return 0x0UL;
+}
+static inline void write_iamr(u64 value)
+{
+	if (pkey_execute_disable_support)
+		mtspr(SPRN_IAMR, value);
+}
+static inline u64 read_uamor(void)
+{

arch/powerpc/include/asm/book3s/64/pgtable.h static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, · line 474

Quoted 10 lines
arch/powerpc/include/asm/book3s/64/pgtable.h +7 -0
+	return mfspr(SPRN_UAMOR);
+}
+static inline void write_uamor(u64 value)
+{
+	mtspr(SPRN_UAMOR, value);
+}
+
 #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)

Looks reasonable otherwise

author
#57 lore raw

Re: [PATCH 04/25] powerpc: helper function to read,write AMR,IAMR,UAMOR registers

Quoted 23 lines · Balbir Singh
Quoted 20 lines · On Fri, 8 Sep 2017 15:44:52 -0700 Ram Pai <[email protected]> wrote:

Implements helper functions to read and write the key related registers; AMR, IAMR, UAMOR.

AMR register tracks the read,write permission of a key IAMR register tracks the execute permission of a key UAMOR register enables and disables a key

---
 arch/powerpc/include/asm/book3s/64/pgtable.h |   31 ++++++++++++++++++++++++++
 1 files changed, 31 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/book3s/64/pgtable.h +0 -0
index b9aff51..73ed52c 100644
@@ -438,6 +438,37 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
 		pte_update(mm, addr, ptep, 0, _PAGE_PRIVILEGED, 1);
 }
 
Quoted 12 lines

arch/powerpc/include/asm/book3s/64/pgtable.h static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, · line 449

Quoted 9 lines
arch/powerpc/include/asm/book3s/64/pgtable.h +9 -0
+#include <asm/reg.h>
+static inline u64 read_amr(void)
+{
+	return mfspr(SPRN_AMR);
+}
+static inline void write_amr(u64 value)
+{
+	mtspr(SPRN_AMR, value);
+}

Do we care to validate values or is that in
the caller

No. Caller is expected to validate the values.

Quoted 20 lines
Quoted 20 lines
arch/powerpc/include/asm/book3s/64/pgtable.h +19 -0
+extern bool pkey_execute_disable_support;
+static inline u64 read_iamr(void)
+{
+	if (pkey_execute_disable_support)
+		return mfspr(SPRN_IAMR);
+	else
+		return 0x0UL;
+}
+static inline void write_iamr(u64 value)
+{
+	if (pkey_execute_disable_support)
+		mtspr(SPRN_IAMR, value);
+}
+static inline u64 read_uamor(void)
+{
+	return mfspr(SPRN_UAMOR);
+}
+static inline void write_uamor(u64 value)
+{
Quoted 8 lines

arch/powerpc/include/asm/book3s/64/pgtable.h static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, · line 474

Quoted 6 lines
arch/powerpc/include/asm/book3s/64/pgtable.h +3 -0
+	mtspr(SPRN_UAMOR, value);
+}
+
 #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)

Looks reasonable otherwise

Thanks!
RP

Quoted 1 line
Signature · 1 line
Ram Pai
author
#58 lore raw

PATCH 5/25 powerpc: helper functions to initialize AMR, IAMR and UAMOR registers

In reply to Ram Pai

Introduce helper functions that can initialize the bits in the AMR, IAMR and UAMOR register; the bits that correspond to the given pkey.

---
 arch/powerpc/include/asm/pkeys.h |    1 +
 arch/powerpc/mm/pkeys.c          |   46 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +1 -0
index 133f8c4..5a83ed7 100644
@@ -26,6 +26,7 @@
 #define arch_max_pkey()  pkeys_total
 #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
 
 #define pkey_alloc_mask(pkey) (0x1 << pkey)
 
arch/powerpc/mm/pkeys.c +46 -0

49 lines not on this page · raw message

Signature · 1 line
1.7.1
#59 lore raw

Re: [PATCH 05/25] powerpc: helper functions to initialize AMR, IAMR and UAMOR registers

Quoted 28 lines · On Fri, 8 Sep 2017 15:44:53 -0700 Ram Pai <[email protected]> wrote:

Introduce helper functions that can initialize the bits in the AMR, IAMR and UAMOR register; the bits that correspond to the given pkey.

---
 arch/powerpc/include/asm/pkeys.h |    1 +
 arch/powerpc/mm/pkeys.c          |   46 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +1 -0
index 133f8c4..5a83ed7 100644
@@ -26,6 +26,7 @@
 #define arch_max_pkey()  pkeys_total
 #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
 
 #define pkey_alloc_mask(pkey) (0x1 << pkey)
 
arch/powerpc/mm/pkeys.c +0 -0
index ebc9e84..178aa33 100644
@@ -59,3 +59,49 @@ void __init pkey_initialize(void)
 	for (i = 2; i < (pkeys_total - os_reserved); i++)
 		initial_allocation_mask &= ~(0x1<<i);

arch/powerpc/mm/pkeys.c void __init pkey_initialize(void) · line 70

Quoted 10 lines
arch/powerpc/mm/pkeys.c +9 -0
 }
+
+#define PKEY_REG_BITS (sizeof(u64)*8)
+#define pkeyshift(pkey) (PKEY_REG_BITS - ((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));
+

Do we need to check for reserved keys or that is at a layer above?

arch/powerpc/mm/pkeys.c void __init pkey_initialize(void) · line 79

Quoted 9 lines
arch/powerpc/mm/pkeys.c +9 -0
+	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_iamr(old_iamr | new_iamr_bits);

Do we need to check for reserved keys here?

Quoted 18 lines
arch/powerpc/mm/pkeys.c +18 -0
+}
+
+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);
+}

arch/powerpc/mm/pkeys.c void __init pkey_initialize(void) · line 107

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+
+void __arch_activate_pkey(int pkey)
+{
+	pkey_status_change(pkey, true);
+}
+
+void __arch_deactivate_pkey(int pkey)
+{
+	pkey_status_change(pkey, false);
+}

Balbir Singh.

author
#60 lore raw

Re: [PATCH 05/25] powerpc: helper functions to initialize AMR, IAMR and UAMOR registers

Quoted 35 lines · Balbir Singh
Quoted 32 lines · On Fri, 8 Sep 2017 15:44:53 -0700 Ram Pai <[email protected]> wrote:

Introduce helper functions that can initialize the bits in the AMR, IAMR and UAMOR register; the bits that correspond to the given pkey.

---
 arch/powerpc/include/asm/pkeys.h |    1 +
 arch/powerpc/mm/pkeys.c          |   46 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +1 -0
index 133f8c4..5a83ed7 100644
@@ -26,6 +26,7 @@
 #define arch_max_pkey()  pkeys_total
 #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
 
 #define pkey_alloc_mask(pkey) (0x1 << pkey)
 
arch/powerpc/mm/pkeys.c +3 -0
index ebc9e84..178aa33 100644
@@ -59,3 +59,49 @@ void __init pkey_initialize(void)
 	for (i = 2; i < (pkeys_total - os_reserved); i++)
 		initial_allocation_mask &= ~(0x1<<i);
 }
+
+#define PKEY_REG_BITS (sizeof(u64)*8)
+#define pkeyshift(pkey) (PKEY_REG_BITS - ((pkey+1) * AMR_BITS_PER_PKEY))
Quoted 8 lines

arch/powerpc/mm/pkeys.c void __init pkey_initialize(void) · line 70

Quoted 6 lines
arch/powerpc/mm/pkeys.c +6 -0
+
+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));
+

Do we need to check for reserved keys or that is at a layer above?

These routines blindly trust the caller. The assumption is the system calls which are the gate-keepers for the keys validate the keys before calling any lower level functions.

Quoted 13 lines

arch/powerpc/mm/pkeys.c void __init pkey_initialize(void) · line 79

Quoted 10 lines
arch/powerpc/mm/pkeys.c +9 -0
+	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_iamr(old_iamr | new_iamr_bits);

Do we need to check for reserved keys here?

ditto..

Quoted 31 lines
Quoted 18 lines
arch/powerpc/mm/pkeys.c +18 -0
+}
+
+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);
+}

arch/powerpc/mm/pkeys.c void __init pkey_initialize(void) · line 107

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+
+void __arch_activate_pkey(int pkey)
+{
+	pkey_status_change(pkey, true);
+}
+
+void __arch_deactivate_pkey(int pkey)
+{
+	pkey_status_change(pkey, false);
+}

Balbir Singh.

Signature · 1 line
Ram Pai
#61 lore raw

Re: [PATCH 05/25] powerpc: helper functions to initialize AMR, IAMR and UAMOR registers

In reply to Ram Pai
Quoted 55 lines · Ram Pai

Introduce helper functions that can initialize the bits in the AMR, IAMR and UAMOR register; the bits that correspond to the given pkey.

---
 arch/powerpc/include/asm/pkeys.h |    1 +
 arch/powerpc/mm/pkeys.c          |   46 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +1 -0
index 133f8c4..5a83ed7 100644
@@ -26,6 +26,7 @@
 #define arch_max_pkey()  pkeys_total
 #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
 
 #define pkey_alloc_mask(pkey) (0x1 << pkey)
 
arch/powerpc/mm/pkeys.c +26 -0
index ebc9e84..178aa33 100644
@@ -59,3 +59,49 @@ void __init pkey_initialize(void)
 	for (i = 2; i < (pkeys_total - os_reserved); i++)
 		initial_allocation_mask &= ~(0x1<<i);
 }
+
+#define PKEY_REG_BITS (sizeof(u64)*8)
+#define pkeyshift(pkey) (PKEY_REG_BITS - ((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_iamr(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);

arch/powerpc/mm/pkeys.c void __init pkey_initialize(void) · line 97

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+	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);
+}

That one is confusing, we discussed this outside the list, but want to bring the list to further discussion. So now the core kernel request for a key via mm_pkey_alloc(). Why not do the below there

static inline int mm_pkey_alloc(struct mm_struct *mm)

{
	/*
	 * Note: this is the one and only place we make sure
	 * that the pkey is valid as far as the hardware is
	 * concerned.  The rest of the kernel trusts that
	 * only good, valid pkeys come out of here.
	 */
	u32 all_pkeys_mask = (u32)(~(0x0));
	int ret;

	if (!pkey_inited)
		return -1;
	/*
	 * Are we out of pkeys?  We must handle this specially
	 * because ffz() behavior is undefined if there are no
	 * zeros.
	 */
	if (mm_pkey_allocation_map(mm) == all_pkeys_mask)
		return -1;

	ret = ffz((u32)mm_pkey_allocation_map(mm));
	mm_set_pkey_allocated(mm, ret);

	return ret;
}

your mm_pkey_allocation_map() should have the keys specified in AMOR and UAMOR marked as allocatied. It is in use by hypervisor and OS respectively.

There is no need of __arch_activate_key() etc. and by default if the OS has not requested for a key for its internal use UAMOR should be 0xFFFFFFFF and that AMOR value you derive from the device tree based of what keys hypervisor has reserved.

-aneesh

author
#62 lore raw

Re: [PATCH 05/25] powerpc: helper functions to initialize AMR, IAMR and UAMOR registers

Quoted 99 lines · Aneesh Kumar K.V
Quoted 55 lines · Ram Pai

Introduce helper functions that can initialize the bits in the AMR, IAMR and UAMOR register; the bits that correspond to the given pkey.

---
 arch/powerpc/include/asm/pkeys.h |    1 +
 arch/powerpc/mm/pkeys.c          |   46 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +1 -0
index 133f8c4..5a83ed7 100644
@@ -26,6 +26,7 @@
 #define arch_max_pkey()  pkeys_total
 #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
 
 #define pkey_alloc_mask(pkey) (0x1 << pkey)
 
arch/powerpc/mm/pkeys.c +26 -0
index ebc9e84..178aa33 100644
@@ -59,3 +59,49 @@ void __init pkey_initialize(void)
 	for (i = 2; i < (pkeys_total - os_reserved); i++)
 		initial_allocation_mask &= ~(0x1<<i);
 }
+
+#define PKEY_REG_BITS (sizeof(u64)*8)
+#define pkeyshift(pkey) (PKEY_REG_BITS - ((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_iamr(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);

arch/powerpc/mm/pkeys.c void __init pkey_initialize(void) · line 97

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+	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);
+}

That one is confusing, we discussed this outside the list, but want to bring the list to further discussion. So now the core kernel request for a key via mm_pkey_alloc(). Why not do the below there

static inline int mm_pkey_alloc(struct mm_struct *mm)

{
	/*
	 * Note: this is the one and only place we make sure
	 * that the pkey is valid as far as the hardware is
	 * concerned.  The rest of the kernel trusts that
	 * only good, valid pkeys come out of here.
	 */
	u32 all_pkeys_mask = (u32)(~(0x0));
	int ret;

	if (!pkey_inited)
		return -1;
	/*
	 * Are we out of pkeys?  We must handle this specially
	 * because ffz() behavior is undefined if there are no
	 * zeros.
	 */
	if (mm_pkey_allocation_map(mm) == all_pkeys_mask)
		return -1;

	ret = ffz((u32)mm_pkey_allocation_map(mm));
	mm_set_pkey_allocated(mm, ret);

	return ret;
}
Quoted 8 lines

your mm_pkey_allocation_map() should have the keys specified in AMOR and UAMOR marked as allocatied. It is in use by hypervisor and OS respectively.

There is no need of __arch_activate_key() etc. and by default if the OS has not requested for a key for its internal use UAMOR should be 0xFFFFFFFF and that AMOR value you derive from the device tree based of what keys hypervisor has reserved.

Ok. You are suggesting a programming model where
a) keys that are reserved by hypervisor are enabled by default.
b) keys that are reserved by the OS are enabled by default.
c) keys that are not yet allocated to userspace is enabled by default.

The problem with this model is that, the userspace can change the permissions of an unallocated key, and those permissions will go into effect immediately, because every key is enabled by default. If it happens to be a key that is reserved by the OS or the hypervisor, bad things can happen.

the programming model that I have implemented; **which is the programming model expected by linux**, is

a) keys that are reserved by hypervisor are left to the hypervisor to enable/disable whenever it needs to.
b) keys that are reserved by the OS are left to the OS to enable/disable whenever it needs to.
c) keys that are not yet allocated to userspace are not yet enabled. Will be enabled when the key is allocated to userspace through sys_pkey_alloc() syscall.

In this programming model, userspace is expected to use only keys that are allocated. And in case it inadvertetly uses a key that is not allocated, nothing bad happens because that key is not activated unless it is allocated. And in case it uses a key that is reserved by the hypervisor or OS, bad things will still not happen because those keys should not be kept enabled when the process is in userspace.

These are my thoughts, I will let the jury decide. :) RP

Quoted 2 lines

-aneesh

Signature · 1 line
Ram Pai
#63 lore raw

Re: [PATCH 05/25] powerpc: helper functions to initialize AMR, IAMR and UAMOR registers

Quoted 55 lines · Ram Pai
Quoted 54 lines · Aneesh Kumar K.V
Quoted 7 lines · Ram Pai
arch/powerpc/mm/pkeys.c +7 -0
+
+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);

arch/powerpc/mm/pkeys.c void __init pkey_initialize(void) · line 97

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+	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);
+}

That one is confusing, we discussed this outside the list, but want to bring the list to further discussion. So now the core kernel request for a key via mm_pkey_alloc(). Why not do the below there

static inline int mm_pkey_alloc(struct mm_struct *mm)

{
	/*
	 * Note: this is the one and only place we make sure
	 * that the pkey is valid as far as the hardware is
	 * concerned.  The rest of the kernel trusts that
	 * only good, valid pkeys come out of here.
	 */
	u32 all_pkeys_mask = (u32)(~(0x0));
	int ret;

	if (!pkey_inited)
		return -1;
	/*
	 * Are we out of pkeys?  We must handle this specially
	 * because ffz() behavior is undefined if there are no
	 * zeros.
	 */
	if (mm_pkey_allocation_map(mm) == all_pkeys_mask)
		return -1;

	ret = ffz((u32)mm_pkey_allocation_map(mm));
	mm_set_pkey_allocated(mm, ret);

	return ret;
}

your mm_pkey_allocation_map() should have the keys specified in AMOR and UAMOR marked as allocatied. It is in use by hypervisor and OS respectively.

Quoted 8 lines
Quoted 4 lines

There is no need of __arch_activate_key() etc. and by default if the OS has not requested for a key for its internal use UAMOR should be 0xFFFFFFFF and that AMOR value you derive from the device tree based of what keys hypervisor has reserved.

Ok. You are suggesting a programming model where
a) keys that are reserved by hypervisor are enabled by default.

No he's not saying that.

Quoted 1 line

b) keys that are reserved by the OS are enabled by default.

Or that.

Quoted 1 line

c) keys that are not yet allocated to userspace is enabled by default.

But he is saying this.

Quoted 3 lines

The problem with this model is that, the userspace can change the permissions of an unallocated key, and those permissions will go into effect immediately,

Correct, but an unallocated key should not be used anywhere, so it should have no effect, unless there's a bug.

Quoted 1 line

because every key is enabled by default. If it

Not every key, every key that is not reserved by the hypervisor or OS.

Quoted 2 lines

happens to be a key that is reserved by the OS or the hypervisor, bad things can happen.

So no nothing bad should be able to happen.

Quoted 6 lines

the programming model that I have implemented; **which is the programming model expected by linux**, is

a) keys that are reserved by hypervisor are left to the hypervisor to enable/disable whenever it needs to.

We agree on that.

Quoted 2 lines

b) keys that are reserved by the OS are left to the OS to enable/disable whenever it needs to.

And that.

Quoted 3 lines

c) keys that are not yet allocated to userspace are not yet enabled. Will be enabled when the key is allocated to userspace through sys_pkey_alloc() syscall.

This is the only part that is under discussion.

Quoted 4 lines

In this programming model, userspace is expected to use only keys that are allocated. And in case it inadvertetly uses a key that is not allocated, nothing bad happens because that key is not activated unless it is allocated.

This sames like a good design to me.

The only downside I see is we have to switch an extra SPR, but that's not much in the scheme of things.

cheers

author
#64 lore raw

PATCH 6/25 powerpc: cleaup AMR, iAMR when a key is allocated or freed

In reply to Ram Pai

cleanup the bits corresponding to a key in the AMR, and IAMR register, when the key is newly allocated/activated or is freed. We dont want some residual bits cause the hardware enforce unintended behavior when the key is activated or freed.

---
 arch/powerpc/include/asm/pkeys.h |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +12 -0
index 5a83ed7..53bf13b 100644
@@ -54,6 +54,8 @@ static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
 		mm_set_pkey_is_allocated(mm, pkey));
 }
 
+extern void __arch_activate_pkey(int pkey);
+extern void __arch_deactivate_pkey(int pkey);
 /*
  * Returns a positive, 5-bit key on success, or -1 on failure.
  */
@@ -80,6 +82,12 @@ static inline int mm_pkey_alloc(struct mm_struct *mm)
 
 	ret = ffz((u32)mm_pkey_allocation_map(mm));
 	mm_set_pkey_allocated(mm, ret);
+
+	/*
+	 * enable the key in the hardware
+	 */
+	if (ret > 0)
+		__arch_activate_pkey(ret);
 	return ret;
 }
 
@@ -91,6 +99,10 @@ static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
 	if (!mm_pkey_is_allocated(mm, pkey))
 		return -EINVAL;
 
+	/*
+	 * Disable the key in the hardware
+	 */
+	__arch_deactivate_pkey(pkey);
 	mm_set_pkey_free(mm, pkey);
 
 	return 0;
Signature · 1 line
1.7.1
#65 lore raw

Re: [PATCH 06/25] powerpc: cleaup AMR,iAMR when a key is allocated or freed

Quoted 37 lines · On Fri, 8 Sep 2017 15:44:54 -0700 Ram Pai <[email protected]> wrote:

cleanup the bits corresponding to a key in the AMR, and IAMR register, when the key is newly allocated/activated or is freed. We dont want some residual bits cause the hardware enforce unintended behavior when the key is activated or freed.

---
 arch/powerpc/include/asm/pkeys.h |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +8 -0
index 5a83ed7..53bf13b 100644
@@ -54,6 +54,8 @@ static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
 		mm_set_pkey_is_allocated(mm, pkey));
 }
 
+extern void __arch_activate_pkey(int pkey);
+extern void __arch_deactivate_pkey(int pkey);
 /*
  * Returns a positive, 5-bit key on success, or -1 on failure.
  */
@@ -80,6 +82,12 @@ static inline int mm_pkey_alloc(struct mm_struct *mm)
 
 	ret = ffz((u32)mm_pkey_allocation_map(mm));
 	mm_set_pkey_allocated(mm, ret);
+
+	/*
+	 * enable the key in the hardware
+	 */
+	if (ret > 0)
+		__arch_activate_pkey(ret);
 	return ret;
 }
 

arch/powerpc/include/asm/pkeys.h static inline int mm_pkey_free(struct mm_struct *mm, int pkey) · line 108

Quoted 10 lines
arch/powerpc/include/asm/pkeys.h +4 -0
@@ -91,6 +99,10 @@ static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
 	if (!mm_pkey_is_allocated(mm, pkey))
 		return -EINVAL;
 
+	/*
+	 * Disable the key in the hardware
+	 */
+	__arch_deactivate_pkey(pkey);
 	mm_set_pkey_free(mm, pkey);
 
 	return 0;

I think some of these patches can be merged, too much fine granularity is hurting my ability to see the larger function/implementation.

Balbir Singh.

#66 lore raw

Re: [PATCH 06/25] powerpc: cleaup AMR, iAMR when a key is allocated or freed

Quoted 49 lines · Balbir Singh
Quoted 46 lines · On Fri, 8 Sep 2017 15:44:54 -0700 Ram Pai <[email protected]> wrote:

cleanup the bits corresponding to a key in the AMR, and IAMR register, when the key is newly allocated/activated or is freed. We dont want some residual bits cause the hardware enforce unintended behavior when the key is activated or freed.

---
 arch/powerpc/include/asm/pkeys.h |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +12 -0
index 5a83ed7..53bf13b 100644
@@ -54,6 +54,8 @@ static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
 		mm_set_pkey_is_allocated(mm, pkey));
 }
 
+extern void __arch_activate_pkey(int pkey);
+extern void __arch_deactivate_pkey(int pkey);
 /*
  * Returns a positive, 5-bit key on success, or -1 on failure.
  */
@@ -80,6 +82,12 @@ static inline int mm_pkey_alloc(struct mm_struct *mm)
 
 	ret = ffz((u32)mm_pkey_allocation_map(mm));
 	mm_set_pkey_allocated(mm, ret);
+
+	/*
+	 * enable the key in the hardware
+	 */
+	if (ret > 0)
+		__arch_activate_pkey(ret);
 	return ret;
 }
 
@@ -91,6 +99,10 @@ static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
 	if (!mm_pkey_is_allocated(mm, pkey))
 		return -EINVAL;
 
+	/*
+	 * Disable the key in the hardware
+	 */
+	__arch_deactivate_pkey(pkey);
 	mm_set_pkey_free(mm, pkey);
 
Quoted 4 lines

arch/powerpc/include/asm/pkeys.h static inline int mm_pkey_free(struct mm_struct *mm, int pkey) · line 108

Quoted 1 line
arch/powerpc/include/asm/pkeys.h +0 -0
 	return 0;

I think some of these patches can be merged, too much fine granularity is hurting my ability to see the larger function/implementation.

Completely agree

-aneesh

author
#67 lore raw

Re: [PATCH 06/25] powerpc: cleaup AMR,iAMR when a key is allocated or freed

Quoted 51 lines · Aneesh Kumar K.V
Quoted 49 lines · Balbir Singh
Quoted 46 lines · On Fri, 8 Sep 2017 15:44:54 -0700 Ram Pai <[email protected]> wrote:

cleanup the bits corresponding to a key in the AMR, and IAMR register, when the key is newly allocated/activated or is freed. We dont want some residual bits cause the hardware enforce unintended behavior when the key is activated or freed.

---
 arch/powerpc/include/asm/pkeys.h |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +12 -0
index 5a83ed7..53bf13b 100644
@@ -54,6 +54,8 @@ static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
 		mm_set_pkey_is_allocated(mm, pkey));
 }
 
+extern void __arch_activate_pkey(int pkey);
+extern void __arch_deactivate_pkey(int pkey);
 /*
  * Returns a positive, 5-bit key on success, or -1 on failure.
  */
@@ -80,6 +82,12 @@ static inline int mm_pkey_alloc(struct mm_struct *mm)
 
 	ret = ffz((u32)mm_pkey_allocation_map(mm));
 	mm_set_pkey_allocated(mm, ret);
+
+	/*
+	 * enable the key in the hardware
+	 */
+	if (ret > 0)
+		__arch_activate_pkey(ret);
 	return ret;
 }
 
@@ -91,6 +99,10 @@ static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
 	if (!mm_pkey_is_allocated(mm, pkey))
 		return -EINVAL;
 
+	/*
+	 * Disable the key in the hardware
+	 */
+	__arch_deactivate_pkey(pkey);
 	mm_set_pkey_free(mm, pkey);
 
Quoted 7 lines
Quoted 4 lines

arch/powerpc/include/asm/pkeys.h static inline int mm_pkey_free(struct mm_struct *mm, int pkey) · line 108

Quoted 1 line
arch/powerpc/include/asm/pkeys.h +0 -0
 	return 0;

I think some of these patches can be merged, too much fine granularity is hurting my ability to see the larger function/implementation.

Completely agree

Me agree too :) Had to fine-grain it to satisfy comments received during the initial versions. I had about 10-12 patches in total.

Thanks, will merge a couple of these patches.

RP

#68 lore raw

Re: [PATCH 06/25] powerpc: cleaup AMR, iAMR when a key is allocated or freed

In reply to Ram Pai
Quoted 25 lines · Ram Pai

cleanup the bits corresponding to a key in the AMR, and IAMR register, when the key is newly allocated/activated or is freed. We dont want some residual bits cause the hardware enforce unintended behavior when the key is activated or freed.

---
 arch/powerpc/include/asm/pkeys.h |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +2 -0
index 5a83ed7..53bf13b 100644
@@ -54,6 +54,8 @@ static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
 		mm_set_pkey_is_allocated(mm, pkey));
 }
 
+extern void __arch_activate_pkey(int pkey);
+extern void __arch_deactivate_pkey(int pkey);
 /*
  * Returns a positive, 5-bit key on success, or -1 on failure.
  */
@@ -80,6 +82,12 @@ static inline int mm_pkey_alloc(struct mm_struct *mm)
 

arch/powerpc/include/asm/pkeys.h static inline int mm_pkey_alloc(struct mm_struct *mm) · line 92

Quoted 10 lines
arch/powerpc/include/asm/pkeys.h +6 -0
 	ret = ffz((u32)mm_pkey_allocation_map(mm));
 	mm_set_pkey_allocated(mm, ret);
+
+	/*
+	 * enable the key in the hardware
+	 */
+	if (ret > 0)
+		__arch_activate_pkey(ret);
 	return ret;
 }

We are already arch specific because we are defining them in arch/powerpc/include/asm/, then why __arch_activate_pkey() ?

Quoted 14 lines
arch/powerpc/include/asm/pkeys.h +4 -0
@@ -91,6 +99,10 @@ static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
 	if (!mm_pkey_is_allocated(mm, pkey))
 		return -EINVAL;
 
+	/*
+	 * Disable the key in the hardware
+	 */
+	__arch_deactivate_pkey(pkey);
 	mm_set_pkey_free(mm, pkey);
 
 	return 0;
Signature · 1 line
1.7.1
author
#69 lore raw

Re: [PATCH 06/25] powerpc: cleaup AMR,iAMR when a key is allocated or freed

Quoted 27 lines · Aneesh Kumar K.V
Quoted 25 lines · Ram Pai

cleanup the bits corresponding to a key in the AMR, and IAMR register, when the key is newly allocated/activated or is freed. We dont want some residual bits cause the hardware enforce unintended behavior when the key is activated or freed.

---
 arch/powerpc/include/asm/pkeys.h |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +2 -0
index 5a83ed7..53bf13b 100644
@@ -54,6 +54,8 @@ static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
 		mm_set_pkey_is_allocated(mm, pkey));
 }
 
+extern void __arch_activate_pkey(int pkey);
+extern void __arch_deactivate_pkey(int pkey);
 /*
  * Returns a positive, 5-bit key on success, or -1 on failure.
  */
@@ -80,6 +82,12 @@ static inline int mm_pkey_alloc(struct mm_struct *mm)
 
Quoted 13 lines

arch/powerpc/include/asm/pkeys.h static inline int mm_pkey_alloc(struct mm_struct *mm) · line 92

Quoted 10 lines
arch/powerpc/include/asm/pkeys.h +6 -0
 	ret = ffz((u32)mm_pkey_allocation_map(mm));
 	mm_set_pkey_allocated(mm, ret);
+
+	/*
+	 * enable the key in the hardware
+	 */
+	if (ret > 0)
+		__arch_activate_pkey(ret);
 	return ret;
 }

We are already arch specific because we are defining them in arch/powerpc/include/asm/, then why __arch_activate_pkey() ?

almost all the memory-key internal functions are named with a two leading underbars. So just *loosely* following a convention within that file. The corresponding functions without the two underbars are the one exposed to the arch-neutral code.

RP

author
#70 lore raw

PATCH 7/25 powerpc: implementation for arch_set_user_pkey_access()

In reply to Ram Pai

This patch provides the detailed implementation for a user to allocate a key and enable it in the hardware.

It provides the plumbing, but it cannot be used till the system call is implemented. The next patch will do so.

---
 arch/powerpc/include/asm/pkeys.h |    9 ++++++++-
 arch/powerpc/mm/pkeys.c          |   28 ++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletions(-)
arch/powerpc/include/asm/pkeys.h +8 -1
index 53bf13b..7fd48a4 100644
@@ -24,6 +24,9 @@
 #endif
 
 #define arch_max_pkey()  pkeys_total
+#define AMR_RD_BIT 0x1UL
+#define AMR_WR_BIT 0x2UL
+#define IAMR_EX_BIT 0x1UL
 #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
@@ -123,10 +126,14 @@ static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
 	return 0;
 }
 
+extern int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
+		unsigned long init_val);
 static inline int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
 		unsigned long init_val)
 {
-	return 0;
+	if (!pkey_inited)
+		return -EINVAL;
+	return __arch_set_user_pkey_access(tsk, pkey, init_val);
 }
 
 static inline void pkey_mm_init(struct mm_struct *mm)
arch/powerpc/mm/pkeys.c +28 -0
index 178aa33..cc5be6a 100644
@@ -12,6 +12,7 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  */
+#include <asm/mman.h>
 #include <linux/pkeys.h>                /* PKEY_*                       */
 
 bool pkey_inited;
@@ -63,6 +64,11 @@ void __init pkey_initialize(void)
 #define PKEY_REG_BITS (sizeof(u64)*8)
 #define pkeyshift(pkey) (PKEY_REG_BITS - ((pkey+1) * AMR_BITS_PER_PKEY))
 
+static bool is_pkey_enabled(int pkey)
+{
+	return !!(read_uamor() & (0x3ul << pkeyshift(pkey)));
+}
+
 static inline void init_amr(int pkey, u8 init_bits)
 {
 	u64 new_amr_bits = (((u64)init_bits & 0x3UL) << pkeyshift(pkey));
@@ -105,3 +111,25 @@ void __arch_deactivate_pkey(int pkey)
 {
 	pkey_status_change(pkey, false);
 }
+
+/*
+ * set the access right in AMR IAMR and UAMOR register
+ * for @pkey to that specified in @init_val.
+ */
+int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
+		unsigned long init_val)
+{
+	u64 new_amr_bits = 0x0ul;
+
+	if (!is_pkey_enabled(pkey))
+		return -EINVAL;
+
+	/* Set the bits we need in AMR:  */
+	if (init_val & PKEY_DISABLE_ACCESS)
+		new_amr_bits |= AMR_RD_BIT | AMR_WR_BIT;
+	else if (init_val & PKEY_DISABLE_WRITE)
+		new_amr_bits |= AMR_WR_BIT;
+
+	init_amr(pkey, new_amr_bits);
+	return 0;
+}
Signature · 1 line
1.7.1
author
#71 lore raw

PATCH 8/25 powerpc: sys_pkey_alloc() and sys_pkey_free() system calls

In reply to Ram Pai

Finally this patch provides the ability for a process to allocate and free a protection key.

---
 arch/powerpc/include/asm/systbl.h      |    2 ++
 arch/powerpc/include/asm/unistd.h      |    4 +---
 arch/powerpc/include/uapi/asm/unistd.h |    2 ++
 3 files changed, 5 insertions(+), 3 deletions(-)
arch/powerpc/include/asm/systbl.h +2 -0
index 1c94708..22dd776 100644
@@ -388,3 +388,5 @@
 COMPAT_SYS_SPU(pwritev2)
 SYSCALL(kexec_file_load)
 SYSCALL(statx)
+SYSCALL(pkey_alloc)
+SYSCALL(pkey_free)
arch/powerpc/include/asm/unistd.h +1 -3
index 9ba11db..e0273bc 100644
@@ -12,13 +12,11 @@
 #include <uapi/asm/unistd.h>
 
 
-#define NR_syscalls		384
+#define NR_syscalls		386
 
 #define __NR__exit __NR_exit
 
 #define __IGNORE_pkey_mprotect
-#define __IGNORE_pkey_alloc
-#define __IGNORE_pkey_free
 
 #ifndef __ASSEMBLY__
 
arch/powerpc/include/uapi/asm/unistd.h +2 -0
index b85f142..7993a07 100644
@@ -394,5 +394,7 @@
 #define __NR_pwritev2		381
 #define __NR_kexec_file_load	382
 #define __NR_statx		383
+#define __NR_pkey_alloc		384
+#define __NR_pkey_free		385
 
 #endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */
Signature · 1 line
1.7.1
#72 lore raw

Re: [PATCH 08/25] powerpc: sys_pkey_alloc() and sys_pkey_free() system calls

Quoted 2 lines · Ram Pai

Finally this patch provides the ability for a process to allocate and free a protection key.

This must be the last patch in the series.

We don't want to expose a half working interface to userspace.

cheers

author
#73 lore raw

Re: [PATCH 08/25] powerpc: sys_pkey_alloc() and sys_pkey_free() system calls

Quoted 8 lines · Michael Ellerman
Quoted 2 lines · Ram Pai

Finally this patch provides the ability for a process to allocate and free a protection key.

This must be the last patch in the series.

We don't want to expose a half working interface to userspace.

The way the patch series is organized -- this patch; even-though introduces the syscall, the syscall will fail because the pkey subsystem is enabled only by the last patch. Till than the code exists , but does a great job of failing with an appropriate return code.

Hope this helps,
RP

#74 lore raw

Re: [PATCH 08/25] powerpc: sys_pkey_alloc() and sys_pkey_free() system calls

Quoted 6 lines · Ram Pai
Quoted 5 lines · Michael Ellerman
Quoted 2 lines · Ram Pai

Finally this patch provides the ability for a process to allocate and free a protection key.

Quoted 8 lines
Quoted 3 lines

This must be the last patch in the series.

We don't want to expose a half working interface to userspace.

The way the patch series is organized -- this patch; even-though introduces the syscall, the syscall will fail because the pkey subsystem is enabled only by the last patch. Till than the code exists , but does a great job of failing with an appropriate return code.

See my previous mail :)

Please don't add the syscall until it can work.

cheers

author
#75 lore raw

PATCH 9/25 powerpc: ability to create execute-disabled pkeys

In reply to Ram Pai

powerpc has hardware support to disable execute on a pkey. This patch enables the ability to create execute-disabled keys.

---
 arch/powerpc/include/uapi/asm/mman.h |    6 ++++++
 arch/powerpc/mm/pkeys.c              |   16 ++++++++++++++++
 2 files changed, 22 insertions(+), 0 deletions(-)
arch/powerpc/include/uapi/asm/mman.h +6 -0
index ab45cc2..f272b09 100644
@@ -45,4 +45,10 @@
 #define MAP_HUGE_1GB	(30 << MAP_HUGE_SHIFT)	/* 1GB   HugeTLB Page */
 #define MAP_HUGE_16GB	(34 << MAP_HUGE_SHIFT)	/* 16GB  HugeTLB Page */
 
+/* override any generic PKEY Permission defines */
+#define PKEY_DISABLE_EXECUTE   0x4
+#undef PKEY_ACCESS_MASK
+#define PKEY_ACCESS_MASK       (PKEY_DISABLE_ACCESS |\
+				PKEY_DISABLE_WRITE  |\
+				PKEY_DISABLE_EXECUTE)
 #endif /* _UAPI_ASM_POWERPC_MMAN_H */
arch/powerpc/mm/pkeys.c +16 -0
index cc5be6a..2282864 100644
@@ -24,6 +24,14 @@ void __init pkey_initialize(void)
 {
 	int os_reserved, i;
 
+	/*
+	 * we define PKEY_DISABLE_EXECUTE in addition to the arch-neutral
+	 * generic defines for PKEY_DISABLE_ACCESS and PKEY_DISABLE_WRITE.
+	 * Ensure that the bits a distinct.
+	 */
+	BUILD_BUG_ON(PKEY_DISABLE_EXECUTE &
+		     (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));
+
 	/* disable the pkey system till everything
 	 * is in place. A patch further down the
 	 * line will enable it.
@@ -120,10 +128,18 @@ int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
 		unsigned long init_val)
 {
 	u64 new_amr_bits = 0x0ul;
+	u64 new_iamr_bits = 0x0ul;
 
 	if (!is_pkey_enabled(pkey))
 		return -EINVAL;
 
+	if ((init_val & PKEY_DISABLE_EXECUTE)) {
+		if (!pkey_execute_disable_support)
+			return -EINVAL;
+		new_iamr_bits |= IAMR_EX_BIT;
+	}
+	init_iamr(pkey, new_iamr_bits);
+
 	/* Set the bits we need in AMR:  */
 	if (init_val & PKEY_DISABLE_ACCESS)
 		new_amr_bits |= AMR_RD_BIT | AMR_WR_BIT;
Signature · 1 line
1.7.1
#76 lore raw

Re: [PATCH 09/25] powerpc: ability to create execute-disabled pkeys

Quoted 30 lines · On Fri, 8 Sep 2017 15:44:57 -0700 Ram Pai <[email protected]> wrote:

powerpc has hardware support to disable execute on a pkey. This patch enables the ability to create execute-disabled keys.

---
 arch/powerpc/include/uapi/asm/mman.h |    6 ++++++
 arch/powerpc/mm/pkeys.c              |   16 ++++++++++++++++
 2 files changed, 22 insertions(+), 0 deletions(-)
arch/powerpc/include/uapi/asm/mman.h +6 -0
index ab45cc2..f272b09 100644
@@ -45,4 +45,10 @@
 #define MAP_HUGE_1GB	(30 << MAP_HUGE_SHIFT)	/* 1GB   HugeTLB Page */
 #define MAP_HUGE_16GB	(34 << MAP_HUGE_SHIFT)	/* 16GB  HugeTLB Page */
 
+/* override any generic PKEY Permission defines */
+#define PKEY_DISABLE_EXECUTE   0x4
+#undef PKEY_ACCESS_MASK
+#define PKEY_ACCESS_MASK       (PKEY_DISABLE_ACCESS |\
+				PKEY_DISABLE_WRITE  |\
+				PKEY_DISABLE_EXECUTE)
 #endif /* _UAPI_ASM_POWERPC_MMAN_H */
arch/powerpc/mm/pkeys.c +0 -0
index cc5be6a..2282864 100644

arch/powerpc/mm/pkeys.c void __init pkey_initialize(void) · line 33

Quoted 10 lines
arch/powerpc/mm/pkeys.c +7 -0
@@ -24,6 +24,14 @@ void __init pkey_initialize(void)
 {
 	int os_reserved, i;
 
+	/*
+	 * we define PKEY_DISABLE_EXECUTE in addition to the arch-neutral
+	 * generic defines for PKEY_DISABLE_ACCESS and PKEY_DISABLE_WRITE.
+	 * Ensure that the bits a distinct.
+	 */
+	BUILD_BUG_ON(PKEY_DISABLE_EXECUTE &
+		     (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));

Will these values every change? It's good to have I guess.

Quoted 10 lines
arch/powerpc/mm/pkeys.c +2 -0
+
 	/* disable the pkey system till everything
 	 * is in place. A patch further down the
 	 * line will enable it.
@@ -120,10 +128,18 @@ int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
 		unsigned long init_val)
 {
 	u64 new_amr_bits = 0x0ul;
+	u64 new_iamr_bits = 0x0ul;
 

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 142

Quoted 10 lines
arch/powerpc/mm/pkeys.c +7 -0
 	if (!is_pkey_enabled(pkey))
 		return -EINVAL;
 
+	if ((init_val & PKEY_DISABLE_EXECUTE)) {
+		if (!pkey_execute_disable_support)
+			return -EINVAL;
+		new_iamr_bits |= IAMR_EX_BIT;
+	}
+	init_iamr(pkey, new_iamr_bits);
+

Where do we check the reserved keys?

Balbir Singh.

author
#77 lore raw

Re: [PATCH 09/25] powerpc: ability to create execute-disabled pkeys

Quoted 59 lines · Balbir Singh
Quoted 30 lines · On Fri, 8 Sep 2017 15:44:57 -0700 Ram Pai <[email protected]> wrote:

powerpc has hardware support to disable execute on a pkey. This patch enables the ability to create execute-disabled keys.

---
 arch/powerpc/include/uapi/asm/mman.h |    6 ++++++
 arch/powerpc/mm/pkeys.c              |   16 ++++++++++++++++
 2 files changed, 22 insertions(+), 0 deletions(-)
arch/powerpc/include/uapi/asm/mman.h +6 -0
index ab45cc2..f272b09 100644
@@ -45,4 +45,10 @@
 #define MAP_HUGE_1GB	(30 << MAP_HUGE_SHIFT)	/* 1GB   HugeTLB Page */
 #define MAP_HUGE_16GB	(34 << MAP_HUGE_SHIFT)	/* 16GB  HugeTLB Page */
 
+/* override any generic PKEY Permission defines */
+#define PKEY_DISABLE_EXECUTE   0x4
+#undef PKEY_ACCESS_MASK
+#define PKEY_ACCESS_MASK       (PKEY_DISABLE_ACCESS |\
+				PKEY_DISABLE_WRITE  |\
+				PKEY_DISABLE_EXECUTE)
 #endif /* _UAPI_ASM_POWERPC_MMAN_H */
arch/powerpc/mm/pkeys.c +0 -0
index cc5be6a..2282864 100644

arch/powerpc/mm/pkeys.c void __init pkey_initialize(void) · line 33

Quoted 10 lines
arch/powerpc/mm/pkeys.c +7 -0
@@ -24,6 +24,14 @@ void __init pkey_initialize(void)
 {
 	int os_reserved, i;
 
+	/*
+	 * we define PKEY_DISABLE_EXECUTE in addition to the arch-neutral
+	 * generic defines for PKEY_DISABLE_ACCESS and PKEY_DISABLE_WRITE.
+	 * Ensure that the bits a distinct.
+	 */
+	BUILD_BUG_ON(PKEY_DISABLE_EXECUTE &
+		     (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));

Will these values every change? It's good to have I guess.

Quoted 13 lines
arch/powerpc/mm/pkeys.c +2 -0
+
 	/* disable the pkey system till everything
 	 * is in place. A patch further down the
 	 * line will enable it.
@@ -120,10 +128,18 @@ int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
 		unsigned long init_val)
 {
 	u64 new_amr_bits = 0x0ul;
+	u64 new_iamr_bits = 0x0ul;
 
 	if (!is_pkey_enabled(pkey))
 		return -EINVAL;
 
Quoted 9 lines

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 142

Quoted 7 lines
arch/powerpc/mm/pkeys.c +7 -0
+	if ((init_val & PKEY_DISABLE_EXECUTE)) {
+		if (!pkey_execute_disable_support)
+			return -EINVAL;
+		new_iamr_bits |= IAMR_EX_BIT;
+	}
+	init_iamr(pkey, new_iamr_bits);
+

Where do we check the reserved keys?

The main gate keeper against spurious keys are the system calls. sys_pkey_mprotect(), sys_pkey_free() and sys_pkey_modify() are the one that will check against reserved and unallocated keys. Once it has passed the check, all other internal functions trust the key values provided to them. I can put in additional checks but that will unnecessarily chew a few cpu cycles.

Agree?

BTW: you raise a good point though, I may have missed guarding against unallocated or reserved keys in sys_pkey_modify(). That was a power specific system call that I have introduced to change the permissions on a key.

RP

#78 lore raw

Re: [PATCH 09/25] powerpc: ability to create execute-disabled pkeys

Quoted 77 lines · Ram Pai
Quoted 59 lines · Balbir Singh
Quoted 30 lines · On Fri, 8 Sep 2017 15:44:57 -0700 Ram Pai <[email protected]> wrote:

powerpc has hardware support to disable execute on a pkey. This patch enables the ability to create execute-disabled keys.

---
 arch/powerpc/include/uapi/asm/mman.h |    6 ++++++
 arch/powerpc/mm/pkeys.c              |   16 ++++++++++++++++
 2 files changed, 22 insertions(+), 0 deletions(-)
arch/powerpc/include/uapi/asm/mman.h +6 -0
index ab45cc2..f272b09 100644
@@ -45,4 +45,10 @@
 #define MAP_HUGE_1GB	(30 << MAP_HUGE_SHIFT)	/* 1GB   HugeTLB Page */
 #define MAP_HUGE_16GB	(34 << MAP_HUGE_SHIFT)	/* 16GB  HugeTLB Page */
 
+/* override any generic PKEY Permission defines */
+#define PKEY_DISABLE_EXECUTE   0x4
+#undef PKEY_ACCESS_MASK
+#define PKEY_ACCESS_MASK       (PKEY_DISABLE_ACCESS |\
+				PKEY_DISABLE_WRITE  |\
+				PKEY_DISABLE_EXECUTE)
 #endif /* _UAPI_ASM_POWERPC_MMAN_H */
arch/powerpc/mm/pkeys.c +0 -0
index cc5be6a..2282864 100644

arch/powerpc/mm/pkeys.c void __init pkey_initialize(void) · line 33

Quoted 10 lines
arch/powerpc/mm/pkeys.c +7 -0
@@ -24,6 +24,14 @@ void __init pkey_initialize(void)
 {
 	int os_reserved, i;
 
+	/*
+	 * we define PKEY_DISABLE_EXECUTE in addition to the arch-neutral
+	 * generic defines for PKEY_DISABLE_ACCESS and PKEY_DISABLE_WRITE.
+	 * Ensure that the bits a distinct.
+	 */
+	BUILD_BUG_ON(PKEY_DISABLE_EXECUTE &
+		     (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));

Will these values every change? It's good to have I guess.

Quoted 13 lines
arch/powerpc/mm/pkeys.c +2 -0
+
 	/* disable the pkey system till everything
 	 * is in place. A patch further down the
 	 * line will enable it.
@@ -120,10 +128,18 @@ int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
 		unsigned long init_val)
 {
 	u64 new_amr_bits = 0x0ul;
+	u64 new_iamr_bits = 0x0ul;
 
 	if (!is_pkey_enabled(pkey))
 		return -EINVAL;
 
Quoted 9 lines

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 142

Quoted 7 lines
arch/powerpc/mm/pkeys.c +7 -0
+	if ((init_val & PKEY_DISABLE_EXECUTE)) {
+		if (!pkey_execute_disable_support)
+			return -EINVAL;
+		new_iamr_bits |= IAMR_EX_BIT;
+	}
+	init_iamr(pkey, new_iamr_bits);
+

Where do we check the reserved keys?

The main gate keeper against spurious keys are the system calls. sys_pkey_mprotect(), sys_pkey_free() and sys_pkey_modify() are the one that will check against reserved and unallocated keys. Once it has passed the check, all other internal functions trust the key values provided to them. I can put in additional checks but that will unnecessarily chew a few cpu cycles.

Quoted 6 lines

Agree?

BTW: you raise a good point though, I may have missed guarding against unallocated or reserved keys in sys_pkey_modify(). That was a power specific system call that I have introduced to change the permissions on a key.

Why do you need a power specific syscall? We should ideally not require anything powerpc specific in the application to use memory keys. If it is for exectue only key, the programming model should remain same as the other keys.

NOTE: I am not able to find patch that add sys_pkey_modify()

-aneesh

author
#79 lore raw

Re: [PATCH 09/25] powerpc: ability to create execute-disabled pkeys

Quoted 86 lines · Aneesh Kumar K.V
Quoted 77 lines · Ram Pai
Quoted 59 lines · Balbir Singh
Quoted 30 lines · On Fri, 8 Sep 2017 15:44:57 -0700 Ram Pai <[email protected]> wrote:

powerpc has hardware support to disable execute on a pkey. This patch enables the ability to create execute-disabled keys.

---
 arch/powerpc/include/uapi/asm/mman.h |    6 ++++++
 arch/powerpc/mm/pkeys.c              |   16 ++++++++++++++++
 2 files changed, 22 insertions(+), 0 deletions(-)
arch/powerpc/include/uapi/asm/mman.h +6 -0
index ab45cc2..f272b09 100644
@@ -45,4 +45,10 @@
 #define MAP_HUGE_1GB	(30 << MAP_HUGE_SHIFT)	/* 1GB   HugeTLB Page */
 #define MAP_HUGE_16GB	(34 << MAP_HUGE_SHIFT)	/* 16GB  HugeTLB Page */
 
+/* override any generic PKEY Permission defines */
+#define PKEY_DISABLE_EXECUTE   0x4
+#undef PKEY_ACCESS_MASK
+#define PKEY_ACCESS_MASK       (PKEY_DISABLE_ACCESS |\
+				PKEY_DISABLE_WRITE  |\
+				PKEY_DISABLE_EXECUTE)
 #endif /* _UAPI_ASM_POWERPC_MMAN_H */
arch/powerpc/mm/pkeys.c +0 -0
index cc5be6a..2282864 100644

arch/powerpc/mm/pkeys.c void __init pkey_initialize(void) · line 33

Quoted 10 lines
arch/powerpc/mm/pkeys.c +7 -0
@@ -24,6 +24,14 @@ void __init pkey_initialize(void)
 {
 	int os_reserved, i;
 
+	/*
+	 * we define PKEY_DISABLE_EXECUTE in addition to the arch-neutral
+	 * generic defines for PKEY_DISABLE_ACCESS and PKEY_DISABLE_WRITE.
+	 * Ensure that the bits a distinct.
+	 */
+	BUILD_BUG_ON(PKEY_DISABLE_EXECUTE &
+		     (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));

Will these values every change? It's good to have I guess.

Quoted 13 lines
arch/powerpc/mm/pkeys.c +2 -0
+
 	/* disable the pkey system till everything
 	 * is in place. A patch further down the
 	 * line will enable it.
@@ -120,10 +128,18 @@ int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
 		unsigned long init_val)
 {
 	u64 new_amr_bits = 0x0ul;
+	u64 new_iamr_bits = 0x0ul;
 
 	if (!is_pkey_enabled(pkey))
 		return -EINVAL;
 
Quoted 9 lines

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 142

Quoted 7 lines
arch/powerpc/mm/pkeys.c +7 -0
+	if ((init_val & PKEY_DISABLE_EXECUTE)) {
+		if (!pkey_execute_disable_support)
+			return -EINVAL;
+		new_iamr_bits |= IAMR_EX_BIT;
+	}
+	init_iamr(pkey, new_iamr_bits);
+

Where do we check the reserved keys?

The main gate keeper against spurious keys are the system calls. sys_pkey_mprotect(), sys_pkey_free() and sys_pkey_modify() are the one that will check against reserved and unallocated keys. Once it has passed the check, all other internal functions trust the key values provided to them. I can put in additional checks but that will unnecessarily chew a few cpu cycles.

Quoted 6 lines

Agree?

BTW: you raise a good point though, I may have missed guarding against unallocated or reserved keys in sys_pkey_modify(). That was a power specific system call that I have introduced to change the permissions on a key.

Quoted 4 lines

Why do you need a power specific syscall? We should ideally not require anything powerpc specific in the application to use memory keys. If it is for exectue only key, the programming model should remain same as the other keys.

The programming model has not changed. It continues to be the same. i.e

a) allocate a key through sys_pkey_alloc()
b) associate the key to a addressspace through sys_pkey_mprotect()
c) change the permissions on the key by programming the AMR register as and when needed.
d) free the key through sys_pkey_free() when done.

the problem is with the programming of execute-permission on the key. x86 does not support the execute-permission and does not have the issue.

powerpc supports execute-permission but unfortunately has not exposed that capability to userspace, because IAMR cannot be programmed from userspace. I have filled in that gap, by providing a power-specific system call called sys_pkey_modify(). It is a way to enable the exact same programming model on keys for execute-permissions.

Quoted 2 lines

NOTE: I am not able to find patch that add sys_pkey_modify()

Yes that patch was added only recently to my tree after consulting Michael Ellermen. I am yet to send out that patch. Will be doing so in my next version.

RP

Quoted 2 lines

-aneesh

Signature · 1 line
Ram Pai
#80 lore raw

Re: [PATCH 09/25] powerpc: ability to create execute-disabled pkeys

In reply to Ram Pai
Quoted 3 lines · Ram Pai

powerpc has hardware support to disable execute on a pkey. This patch enables the ability to create execute-disabled keys.

Can you summarize here how this works? Access to IAMR is privileged so how will keys framework work with IAMR?

-aneesh

author
#81 lore raw

Re: [PATCH 09/25] powerpc: ability to create execute-disabled pkeys

Quoted 10 lines · Aneesh Kumar K.V
Quoted 3 lines · Ram Pai

powerpc has hardware support to disable execute on a pkey. This patch enables the ability to create execute-disabled keys.

Can you summarize here how this works? Access to IAMR is privileged so how will keys framework work with IAMR?

-aneesh

right. IAMR will have to programmed through a system call. I have introduced a sys_pkey_modify() which takes a key value and the permission that it wants to enable/disable on that key. This syscall is powerpc specific only for now, since no other arch's need it.

The patch is at http://patchwork.ozlabs.org/patch/817961/

Signature · 1 line
Ram Pai
author
#82 lore raw

PATCH 10/25 powerpc: store and restore the pkey state across context switches

In reply to Ram Pai

Store and restore the AMR, IAMR and UAMOR register state of the task before scheduling out and after scheduling in, respectively.

---
 arch/powerpc/include/asm/pkeys.h     |    4 +++
 arch/powerpc/include/asm/processor.h |    5 ++++
 arch/powerpc/kernel/process.c        |   10 ++++++++
 arch/powerpc/mm/pkeys.c              |   39 ++++++++++++++++++++++++++++++++++
 4 files changed, 58 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +4 -0
index 7fd48a4..78c5362 100644
@@ -143,5 +143,9 @@ static inline void pkey_mm_init(struct mm_struct *mm)
 	mm_pkey_allocation_map(mm) = initial_allocation_mask;
 }
 
+extern void thread_pkey_regs_save(struct thread_struct *thread);
+extern void thread_pkey_regs_restore(struct thread_struct *new_thread,
+			struct thread_struct *old_thread);
+extern void thread_pkey_regs_init(struct thread_struct *thread);
 extern void pkey_initialize(void);
 #endif /*_ASM_PPC64_PKEYS_H */
arch/powerpc/include/asm/processor.h +5 -0
index fab7ff8..de9d9ba 100644
@@ -309,6 +309,11 @@ struct thread_struct {
 	struct thread_vr_state ckvr_state; /* Checkpointed VR state */
 	unsigned long	ckvrsave; /* Checkpointed VRSAVE */
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	unsigned long	amr;
+	unsigned long	iamr;
+	unsigned long	uamor;
+#endif
 #ifdef CONFIG_KVM_BOOK3S_32_HANDLER
 	void*		kvm_shadow_vcpu; /* KVM internal data */
 #endif /* CONFIG_KVM_BOOK3S_32_HANDLER */
arch/powerpc/kernel/process.c +10 -0
index a0c74bb..ba80002 100644
@@ -42,6 +42,7 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/uaccess.h>
 #include <linux/elf-randomize.h>
+#include <linux/pkeys.h>
 
 #include <asm/pgtable.h>
 #include <asm/io.h>
@@ -1085,6 +1086,9 @@ static inline void save_sprs(struct thread_struct *t)
 		t->tar = mfspr(SPRN_TAR);
 	}
 #endif
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	thread_pkey_regs_save(t);
+#endif
 }
 
 static inline void restore_sprs(struct thread_struct *old_thread,
@@ -1120,6 +1124,9 @@ static inline void restore_sprs(struct thread_struct *old_thread,
 			mtspr(SPRN_TAR, new_thread->tar);
 	}
 #endif
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	thread_pkey_regs_restore(new_thread, old_thread);
+#endif
 }
 
 #ifdef CONFIG_PPC_BOOK3S_64
@@ -1705,6 +1712,9 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
 	current->thread.tm_tfiar = 0;
 	current->thread.load_tm = 0;
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	thread_pkey_regs_init(&current->thread);
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 }
 EXPORT_SYMBOL(start_thread);
 
arch/powerpc/mm/pkeys.c +39 -0
index 2282864..7cd1be4 100644
@@ -149,3 +149,42 @@ int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
 	init_amr(pkey, new_amr_bits);
 	return 0;
 }
+
+void thread_pkey_regs_save(struct thread_struct *thread)
+{
+	if (!pkey_inited)
+		return;
+
+	/* @TODO skip saving any registers if the thread
+	 * has not used any keys yet.
+	 */
+
+	thread->amr = read_amr();
+	thread->iamr = read_iamr();
+	thread->uamor = read_uamor();
+}
+
+void thread_pkey_regs_restore(struct thread_struct *new_thread,
+			struct thread_struct *old_thread)
+{
+	if (!pkey_inited)
+		return;
+
+	/* @TODO just reset uamor to zero if the new_thread
+	 * has not used any keys yet.
+	 */
+
+	if (old_thread->amr != new_thread->amr)
+		write_amr(new_thread->amr);
+	if (old_thread->iamr != new_thread->iamr)
+		write_iamr(new_thread->iamr);
+	if (old_thread->uamor != new_thread->uamor)
+		write_uamor(new_thread->uamor);
+}
+
+void thread_pkey_regs_init(struct thread_struct *thread)
+{
+	write_amr(0x0ul);
+	write_iamr(0x0ul);
+	write_uamor(0x0ul);
+}
Signature · 1 line
1.7.1
#83 lore raw

Re: [PATCH 10/25] powerpc: store and restore the pkey state across context switches

Quoted 54 lines · On Fri, 8 Sep 2017 15:44:58 -0700 Ram Pai <[email protected]> wrote:

Store and restore the AMR, IAMR and UAMOR register state of the task before scheduling out and after scheduling in, respectively.

---
 arch/powerpc/include/asm/pkeys.h     |    4 +++
 arch/powerpc/include/asm/processor.h |    5 ++++
 arch/powerpc/kernel/process.c        |   10 ++++++++
 arch/powerpc/mm/pkeys.c              |   39 ++++++++++++++++++++++++++++++++++
 4 files changed, 58 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +4 -0
index 7fd48a4..78c5362 100644
@@ -143,5 +143,9 @@ static inline void pkey_mm_init(struct mm_struct *mm)
 	mm_pkey_allocation_map(mm) = initial_allocation_mask;
 }
 
+extern void thread_pkey_regs_save(struct thread_struct *thread);
+extern void thread_pkey_regs_restore(struct thread_struct *new_thread,
+			struct thread_struct *old_thread);
+extern void thread_pkey_regs_init(struct thread_struct *thread);
 extern void pkey_initialize(void);
 #endif /*_ASM_PPC64_PKEYS_H */
arch/powerpc/include/asm/processor.h +5 -0
index fab7ff8..de9d9ba 100644
@@ -309,6 +309,11 @@ struct thread_struct {
 	struct thread_vr_state ckvr_state; /* Checkpointed VR state */
 	unsigned long	ckvrsave; /* Checkpointed VRSAVE */
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	unsigned long	amr;
+	unsigned long	iamr;
+	unsigned long	uamor;
+#endif
 #ifdef CONFIG_KVM_BOOK3S_32_HANDLER
 	void*		kvm_shadow_vcpu; /* KVM internal data */
 #endif /* CONFIG_KVM_BOOK3S_32_HANDLER */
arch/powerpc/kernel/process.c +1 -0
index a0c74bb..ba80002 100644
@@ -42,6 +42,7 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/uaccess.h>
 #include <linux/elf-randomize.h>
+#include <linux/pkeys.h>
 
 #include <asm/pgtable.h>
 #include <asm/io.h>

arch/powerpc/kernel/process.c static inline void save_sprs(struct thread_struct *t) · line 1091

Quoted 6 lines
arch/powerpc/kernel/process.c +3 -0
@@ -1085,6 +1086,9 @@ static inline void save_sprs(struct thread_struct *t)
 		t->tar = mfspr(SPRN_TAR);
 	}
 #endif
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	thread_pkey_regs_save(t);
+#endif

Just define two variants of thread_pkey_regs_save() based on CONFIG_PPC64_MEMORY_PROTECTION_KEYS and remove the #ifdefs from process.c Ditto for the lines below

Quoted 30 lines
arch/powerpc/kernel/process.c +6 -0
 }
 
 static inline void restore_sprs(struct thread_struct *old_thread,
@@ -1120,6 +1124,9 @@ static inline void restore_sprs(struct thread_struct *old_thread,
 			mtspr(SPRN_TAR, new_thread->tar);
 	}
 #endif
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	thread_pkey_regs_restore(new_thread, old_thread);
+#endif
 }
 
 #ifdef CONFIG_PPC_BOOK3S_64
@@ -1705,6 +1712,9 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
 	current->thread.tm_tfiar = 0;
 	current->thread.load_tm = 0;
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	thread_pkey_regs_init(&current->thread);
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 }
 EXPORT_SYMBOL(start_thread);
 
arch/powerpc/mm/pkeys.c +0 -0
index 2282864..7cd1be4 100644
@@ -149,3 +149,42 @@ int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
 	init_amr(pkey, new_amr_bits);
 	return 0;

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 160

Quoted 10 lines
arch/powerpc/mm/pkeys.c +9 -0
 }
+
+void thread_pkey_regs_save(struct thread_struct *thread)
+{
+	if (!pkey_inited)
+		return;
+
+	/* @TODO skip saving any registers if the thread
+	 * has not used any keys yet.
+	 */

Comment style is broken

Quoted 5 lines
arch/powerpc/mm/pkeys.c +5 -0
+
+	thread->amr = read_amr();
+	thread->iamr = read_iamr();
+	thread->uamor = read_uamor();
+}

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 175

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+
+void thread_pkey_regs_restore(struct thread_struct *new_thread,
+			struct thread_struct *old_thread)
+{
+	if (!pkey_inited)
+		return;
+
+	/* @TODO just reset uamor to zero if the new_thread
+	 * has not used any keys yet.
+	 */

Comment style is broken.

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 182

Quoted 7 lines
arch/powerpc/mm/pkeys.c +7 -0
+
+	if (old_thread->amr != new_thread->amr)
+		write_amr(new_thread->amr);
+	if (old_thread->iamr != new_thread->iamr)
+		write_iamr(new_thread->iamr);
+	if (old_thread->uamor != new_thread->uamor)
+		write_uamor(new_thread->uamor);

Is this order correct? Ideally, You want to write the uamor first but since we are in supervisor state, I think we can get away with this order. Do we want to expose the uamor to user space for it to modify the AMR directly?

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 189

Quoted 7 lines
arch/powerpc/mm/pkeys.c +7 -0
+}
+
+void thread_pkey_regs_init(struct thread_struct *thread)
+{
+	write_amr(0x0ul);
+	write_iamr(0x0ul);
+	write_uamor(0x0ul);

This is not correct, reserved keys should not be set to 0's

Balbir Singh.

author
#84 lore raw

Re: [PATCH 10/25] powerpc: store and restore the pkey state across context switches

Quoted 54 lines · Balbir Singh
Quoted 51 lines · On Fri, 8 Sep 2017 15:44:58 -0700 Ram Pai <[email protected]> wrote:

Store and restore the AMR, IAMR and UAMOR register state of the task before scheduling out and after scheduling in, respectively.

---
 arch/powerpc/include/asm/pkeys.h     |    4 +++
 arch/powerpc/include/asm/processor.h |    5 ++++
 arch/powerpc/kernel/process.c        |   10 ++++++++
 arch/powerpc/mm/pkeys.c              |   39 ++++++++++++++++++++++++++++++++++
 4 files changed, 58 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +4 -0
index 7fd48a4..78c5362 100644
@@ -143,5 +143,9 @@ static inline void pkey_mm_init(struct mm_struct *mm)
 	mm_pkey_allocation_map(mm) = initial_allocation_mask;
 }
 
+extern void thread_pkey_regs_save(struct thread_struct *thread);
+extern void thread_pkey_regs_restore(struct thread_struct *new_thread,
+			struct thread_struct *old_thread);
+extern void thread_pkey_regs_init(struct thread_struct *thread);
 extern void pkey_initialize(void);
 #endif /*_ASM_PPC64_PKEYS_H */
arch/powerpc/include/asm/processor.h +5 -0
index fab7ff8..de9d9ba 100644
@@ -309,6 +309,11 @@ struct thread_struct {
 	struct thread_vr_state ckvr_state; /* Checkpointed VR state */
 	unsigned long	ckvrsave; /* Checkpointed VRSAVE */
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	unsigned long	amr;
+	unsigned long	iamr;
+	unsigned long	uamor;
+#endif
 #ifdef CONFIG_KVM_BOOK3S_32_HANDLER
 	void*		kvm_shadow_vcpu; /* KVM internal data */
 #endif /* CONFIG_KVM_BOOK3S_32_HANDLER */
arch/powerpc/kernel/process.c +1 -0
index a0c74bb..ba80002 100644
@@ -42,6 +42,7 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/uaccess.h>
 #include <linux/elf-randomize.h>
+#include <linux/pkeys.h>
 
Quoted 13 lines

arch/powerpc/kernel/process.c static inline void save_sprs(struct thread_struct *t) · line 1091

Quoted 9 lines
arch/powerpc/kernel/process.c +3 -0
 #include <asm/pgtable.h>
 #include <asm/io.h>
@@ -1085,6 +1086,9 @@ static inline void save_sprs(struct thread_struct *t)
 		t->tar = mfspr(SPRN_TAR);
 	}
 #endif
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	thread_pkey_regs_save(t);
+#endif

Just define two variants of thread_pkey_regs_save() based on CONFIG_PPC64_MEMORY_PROTECTION_KEYS and remove the #ifdefs from process.c Ditto for the lines below

ok.

Quoted 11 lines

arch/powerpc/kernel/process.c static inline void restore_sprs(struct thread_struct *old_thread, · line 1129

Quoted 11 lines
arch/powerpc/kernel/process.c +3 -0
 }
 
 static inline void restore_sprs(struct thread_struct *old_thread,
@@ -1120,6 +1124,9 @@ static inline void restore_sprs(struct thread_struct *old_thread,
 			mtspr(SPRN_TAR, new_thread->tar);
 	}
 #endif
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	thread_pkey_regs_restore(new_thread, old_thread);
+#endif

ok.

Quoted 24 lines
Quoted 24 lines
arch/powerpc/kernel/process.c +3 -0
 }
 
 #ifdef CONFIG_PPC_BOOK3S_64
@@ -1705,6 +1712,9 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
 	current->thread.tm_tfiar = 0;
 	current->thread.load_tm = 0;
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	thread_pkey_regs_init(&current->thread);
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 }
 EXPORT_SYMBOL(start_thread);
 
arch/powerpc/mm/pkeys.c +3 -0
index 2282864..7cd1be4 100644
@@ -149,3 +149,42 @@ int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
 	init_amr(pkey, new_amr_bits);
 	return 0;
 }
+
+void thread_pkey_regs_save(struct thread_struct *thread)
+{
Quoted 8 lines

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 160

Quoted 6 lines
arch/powerpc/mm/pkeys.c +6 -0
+	if (!pkey_inited)
+		return;
+
+	/* @TODO skip saving any registers if the thread
+	 * has not used any keys yet.
+	 */

Comment style is broken

ok. this time i will fix them. It misses by radar screen because checkpatch.pl does not complain.

Quoted 19 lines
Quoted 6 lines
arch/powerpc/mm/pkeys.c +5 -0
+
+	thread->amr = read_amr();
+	thread->iamr = read_iamr();
+	thread->uamor = read_uamor();
+}

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 175

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+
+void thread_pkey_regs_restore(struct thread_struct *new_thread,
+			struct thread_struct *old_thread)
+{
+	if (!pkey_inited)
+		return;
+
+	/* @TODO just reset uamor to zero if the new_thread
+	 * has not used any keys yet.
+	 */

Comment style is broken.

Quoted 11 lines

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 182

Quoted 7 lines
arch/powerpc/mm/pkeys.c +7 -0
+
+	if (old_thread->amr != new_thread->amr)
+		write_amr(new_thread->amr);
+	if (old_thread->iamr != new_thread->iamr)
+		write_iamr(new_thread->iamr);
+	if (old_thread->uamor != new_thread->uamor)
+		write_uamor(new_thread->uamor);

Is this order correct? Ideally, You want to write the uamor first but since we are in supervisor state, I think we can get away with this order.

we could be in hypervisor state too, as is the case when we run a powernv kernel.

But..does it matter in which order they are written? if the thread is in the kernel, it cannot execute any instructions in userspace. So it wont see a intermediate state. right? or am i getting this wrong?

Quoted 2 lines

Do we want to expose the uamor to user space
for it to modify the AMR directly?

sorry I did not understand the comment. UAMOR cannot be accessed from usespace. and there are no system calls currently to help userspace to program the UAMOR on its behalf.

Quoted 10 lines

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 189

Quoted 8 lines
arch/powerpc/mm/pkeys.c +7 -0
+}
+
+void thread_pkey_regs_init(struct thread_struct *thread)
+{
+	write_amr(0x0ul);
+	write_iamr(0x0ul);
+	write_uamor(0x0ul);

This is not correct, reserved keys should not be set to 0's

ok. makes sense. best to not touch reserved key bits here.

Quoted 2 lines

Balbir Singh.

Signature · 1 line
Ram Pai
#85 lore raw

Re: [PATCH 10/25] powerpc: store and restore the pkey state across context switches

Quoted 118 lines · On Wed, 18 Oct 2017 13:47:05 -0700 Ram Pai <[email protected]> wrote:
Quoted 54 lines · Balbir Singh
Quoted 51 lines · On Fri, 8 Sep 2017 15:44:58 -0700 Ram Pai <[email protected]> wrote:

Store and restore the AMR, IAMR and UAMOR register state of the task before scheduling out and after scheduling in, respectively.

---
 arch/powerpc/include/asm/pkeys.h     |    4 +++
 arch/powerpc/include/asm/processor.h |    5 ++++
 arch/powerpc/kernel/process.c        |   10 ++++++++
 arch/powerpc/mm/pkeys.c              |   39 ++++++++++++++++++++++++++++++++++
 4 files changed, 58 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +4 -0
index 7fd48a4..78c5362 100644
@@ -143,5 +143,9 @@ static inline void pkey_mm_init(struct mm_struct *mm)
 	mm_pkey_allocation_map(mm) = initial_allocation_mask;
 }
 
+extern void thread_pkey_regs_save(struct thread_struct *thread);
+extern void thread_pkey_regs_restore(struct thread_struct *new_thread,
+			struct thread_struct *old_thread);
+extern void thread_pkey_regs_init(struct thread_struct *thread);
 extern void pkey_initialize(void);
 #endif /*_ASM_PPC64_PKEYS_H */
arch/powerpc/include/asm/processor.h +5 -0
index fab7ff8..de9d9ba 100644
@@ -309,6 +309,11 @@ struct thread_struct {
 	struct thread_vr_state ckvr_state; /* Checkpointed VR state */
 	unsigned long	ckvrsave; /* Checkpointed VRSAVE */
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	unsigned long	amr;
+	unsigned long	iamr;
+	unsigned long	uamor;
+#endif
 #ifdef CONFIG_KVM_BOOK3S_32_HANDLER
 	void*		kvm_shadow_vcpu; /* KVM internal data */
 #endif /* CONFIG_KVM_BOOK3S_32_HANDLER */
arch/powerpc/kernel/process.c +1 -0
index a0c74bb..ba80002 100644
@@ -42,6 +42,7 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/uaccess.h>
 #include <linux/elf-randomize.h>
+#include <linux/pkeys.h>
 
Quoted 13 lines

arch/powerpc/kernel/process.c static inline void save_sprs(struct thread_struct *t) · line 1091

Quoted 9 lines
arch/powerpc/kernel/process.c +3 -0
 #include <asm/pgtable.h>
 #include <asm/io.h>
@@ -1085,6 +1086,9 @@ static inline void save_sprs(struct thread_struct *t)
 		t->tar = mfspr(SPRN_TAR);
 	}
 #endif
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	thread_pkey_regs_save(t);
+#endif  

Just define two variants of thread_pkey_regs_save() based on CONFIG_PPC64_MEMORY_PROTECTION_KEYS and remove the #ifdefs from process.c Ditto for the lines below

ok.

Quoted 11 lines

arch/powerpc/kernel/process.c static inline void restore_sprs(struct thread_struct *old_thread, · line 1129

Quoted 11 lines
arch/powerpc/kernel/process.c +3 -0
 }
 
 static inline void restore_sprs(struct thread_struct *old_thread,
@@ -1120,6 +1124,9 @@ static inline void restore_sprs(struct thread_struct *old_thread,
 			mtspr(SPRN_TAR, new_thread->tar);
 	}
 #endif
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	thread_pkey_regs_restore(new_thread, old_thread);
+#endif  

ok.

Quoted 24 lines
Quoted 24 lines
arch/powerpc/kernel/process.c +3 -0
 }
 
 #ifdef CONFIG_PPC_BOOK3S_64
@@ -1705,6 +1712,9 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
 	current->thread.tm_tfiar = 0;
 	current->thread.load_tm = 0;
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	thread_pkey_regs_init(&current->thread);
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 }
 EXPORT_SYMBOL(start_thread);
 
arch/powerpc/mm/pkeys.c +3 -0
index 2282864..7cd1be4 100644
@@ -149,3 +149,42 @@ int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
 	init_amr(pkey, new_amr_bits);
 	return 0;
 }
+
+void thread_pkey_regs_save(struct thread_struct *thread)
+{
Quoted 8 lines

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 160

Quoted 6 lines
arch/powerpc/mm/pkeys.c +6 -0
+	if (!pkey_inited)
+		return;
+
+	/* @TODO skip saving any registers if the thread
+	 * has not used any keys yet.
+	 */  

Comment style is broken

Quoted 3 lines

ok. this time i will fix them. It misses by radar screen because checkpatch.pl does not complain.

Yep, there is an lkml thread on this style of coding. It's best avoided.

Quoted 31 lines
Quoted 19 lines
Quoted 6 lines
arch/powerpc/mm/pkeys.c +5 -0
+
+	thread->amr = read_amr();
+	thread->iamr = read_iamr();
+	thread->uamor = read_uamor();
+}

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 175

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+
+void thread_pkey_regs_restore(struct thread_struct *new_thread,
+			struct thread_struct *old_thread)
+{
+	if (!pkey_inited)
+		return;
+
+	/* @TODO just reset uamor to zero if the new_thread
+	 * has not used any keys yet.
+	 */  

Comment style is broken.

Quoted 11 lines

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 182

Quoted 7 lines
arch/powerpc/mm/pkeys.c +7 -0
+
+	if (old_thread->amr != new_thread->amr)
+		write_amr(new_thread->amr);
+	if (old_thread->iamr != new_thread->iamr)
+		write_iamr(new_thread->iamr);
+	if (old_thread->uamor != new_thread->uamor)
+		write_uamor(new_thread->uamor);  

Is this order correct? Ideally, You want to write the uamor first but since we are in supervisor state, I think we can get away with this order.

Quoted 7 lines

we could be in hypervisor state too, as is the case when we run a powernv kernel.

But..does it matter in which order they are written? if the thread is in the kernel, it cannot execute any instructions in userspace. So it wont see a intermediate state. right? or am i getting this wrong?

You are right, since uamor + amor control what can and cannot be set, there is a subtle dependency, but it does not apply to the kernel doing the context switch. AMR has two SPR values, 13 and 29. I presume we are using SPR #29 here?

Quoted 9 lines
Quoted 3 lines

Do we want to expose the uamor to user space
for it to modify the AMR directly?

sorry I did not understand the comment. UAMOR cannot be accessed from usespace. and there are no system calls currently to help userspace to program the UAMOR on its behalf.

I was just wondering how two threads can share a key if they decide to. They would need uamor to give them permissions to the same set of keys and then reuse the key via pkey_mprotect(.., pkey). I am missing the bit about how uamor's across these threads would be synchronized.

Quoted 11 lines
Quoted 10 lines

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 189

Quoted 8 lines
arch/powerpc/mm/pkeys.c +7 -0
+}
+
+void thread_pkey_regs_init(struct thread_struct *thread)
+{
+	write_amr(0x0ul);
+	write_iamr(0x0ul);
+	write_uamor(0x0ul);  

This is not correct, reserved keys should not be set to 0's

Quoted 1 line

ok. makes sense. best to not touch reserved key bits here.

Also this implies that at init time, the thread has access to all keys, but it can't modify any of the keys in the AMR/IAMR.

Quoted 4 lines
Quoted 3 lines

Balbir Singh.

author
#86 lore raw

Re: [PATCH 10/25] powerpc: store and restore the pkey state across context switches

Quoted 167 lines · Balbir Singh
Quoted 118 lines · On Wed, 18 Oct 2017 13:47:05 -0700 Ram Pai <[email protected]> wrote:
Quoted 54 lines · Balbir Singh
Quoted 51 lines · On Fri, 8 Sep 2017 15:44:58 -0700 Ram Pai <[email protected]> wrote:

Store and restore the AMR, IAMR and UAMOR register state of the task before scheduling out and after scheduling in, respectively.

---
 arch/powerpc/include/asm/pkeys.h     |    4 +++
 arch/powerpc/include/asm/processor.h |    5 ++++
 arch/powerpc/kernel/process.c        |   10 ++++++++
 arch/powerpc/mm/pkeys.c              |   39 ++++++++++++++++++++++++++++++++++
 4 files changed, 58 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +4 -0
index 7fd48a4..78c5362 100644
@@ -143,5 +143,9 @@ static inline void pkey_mm_init(struct mm_struct *mm)
 	mm_pkey_allocation_map(mm) = initial_allocation_mask;
 }
 
+extern void thread_pkey_regs_save(struct thread_struct *thread);
+extern void thread_pkey_regs_restore(struct thread_struct *new_thread,
+			struct thread_struct *old_thread);
+extern void thread_pkey_regs_init(struct thread_struct *thread);
 extern void pkey_initialize(void);
 #endif /*_ASM_PPC64_PKEYS_H */
arch/powerpc/include/asm/processor.h +5 -0
index fab7ff8..de9d9ba 100644
@@ -309,6 +309,11 @@ struct thread_struct {
 	struct thread_vr_state ckvr_state; /* Checkpointed VR state */
 	unsigned long	ckvrsave; /* Checkpointed VRSAVE */
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	unsigned long	amr;
+	unsigned long	iamr;
+	unsigned long	uamor;
+#endif
 #ifdef CONFIG_KVM_BOOK3S_32_HANDLER
 	void*		kvm_shadow_vcpu; /* KVM internal data */
 #endif /* CONFIG_KVM_BOOK3S_32_HANDLER */
arch/powerpc/kernel/process.c +1 -0
index a0c74bb..ba80002 100644
@@ -42,6 +42,7 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/uaccess.h>
 #include <linux/elf-randomize.h>
+#include <linux/pkeys.h>
 
Quoted 13 lines

arch/powerpc/kernel/process.c static inline void save_sprs(struct thread_struct *t) · line 1091

Quoted 9 lines
arch/powerpc/kernel/process.c +3 -0
 #include <asm/pgtable.h>
 #include <asm/io.h>
@@ -1085,6 +1086,9 @@ static inline void save_sprs(struct thread_struct *t)
 		t->tar = mfspr(SPRN_TAR);
 	}
 #endif
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	thread_pkey_regs_save(t);
+#endif  

Just define two variants of thread_pkey_regs_save() based on CONFIG_PPC64_MEMORY_PROTECTION_KEYS and remove the #ifdefs from process.c Ditto for the lines below

ok.

Quoted 11 lines

arch/powerpc/kernel/process.c static inline void restore_sprs(struct thread_struct *old_thread, · line 1129

Quoted 11 lines
arch/powerpc/kernel/process.c +3 -0
 }
 
 static inline void restore_sprs(struct thread_struct *old_thread,
@@ -1120,6 +1124,9 @@ static inline void restore_sprs(struct thread_struct *old_thread,
 			mtspr(SPRN_TAR, new_thread->tar);
 	}
 #endif
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	thread_pkey_regs_restore(new_thread, old_thread);
+#endif  

ok.

Quoted 24 lines
Quoted 24 lines
arch/powerpc/kernel/process.c +3 -0
 }
 
 #ifdef CONFIG_PPC_BOOK3S_64
@@ -1705,6 +1712,9 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
 	current->thread.tm_tfiar = 0;
 	current->thread.load_tm = 0;
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	thread_pkey_regs_init(&current->thread);
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 }
 EXPORT_SYMBOL(start_thread);
 
arch/powerpc/mm/pkeys.c +3 -0
index 2282864..7cd1be4 100644
@@ -149,3 +149,42 @@ int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
 	init_amr(pkey, new_amr_bits);
 	return 0;
 }
+
+void thread_pkey_regs_save(struct thread_struct *thread)
+{
Quoted 8 lines

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 160

Quoted 6 lines
arch/powerpc/mm/pkeys.c +6 -0
+	if (!pkey_inited)
+		return;
+
+	/* @TODO skip saving any registers if the thread
+	 * has not used any keys yet.
+	 */  

Comment style is broken

Quoted 3 lines

ok. this time i will fix them. It misses by radar screen because checkpatch.pl does not complain.

Yep, there is an lkml thread on this style of coding. It's best avoided.

Quoted 31 lines
Quoted 19 lines
Quoted 6 lines
arch/powerpc/mm/pkeys.c +5 -0
+
+	thread->amr = read_amr();
+	thread->iamr = read_iamr();
+	thread->uamor = read_uamor();
+}

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 175

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+
+void thread_pkey_regs_restore(struct thread_struct *new_thread,
+			struct thread_struct *old_thread)
+{
+	if (!pkey_inited)
+		return;
+
+	/* @TODO just reset uamor to zero if the new_thread
+	 * has not used any keys yet.
+	 */  

Comment style is broken.

Quoted 11 lines

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 182

Quoted 7 lines
arch/powerpc/mm/pkeys.c +7 -0
+
+	if (old_thread->amr != new_thread->amr)
+		write_amr(new_thread->amr);
+	if (old_thread->iamr != new_thread->iamr)
+		write_iamr(new_thread->iamr);
+	if (old_thread->uamor != new_thread->uamor)
+		write_uamor(new_thread->uamor);  

Is this order correct? Ideally, You want to write the uamor first but since we are in supervisor state, I think we can get away with this order.

Quoted 7 lines

we could be in hypervisor state too, as is the case when we run a powernv kernel.

But..does it matter in which order they are written? if the thread is in the kernel, it cannot execute any instructions in userspace. So it wont see a intermediate state. right? or am i getting this wrong?

Quoted 5 lines

You are right, since uamor + amor control what can and cannot be set, there is a subtle dependency, but it does not apply to the kernel doing the context switch. AMR has two SPR values, 13 and 29. I presume we are using SPR #29 here?

it is SPRN_AMR, which is 29 (0x1d)

Quoted 11 lines
Quoted 10 lines
Quoted 4 lines

Do we want to expose the uamor to user space
for it to modify the AMR directly?

sorry I did not understand the comment. UAMOR cannot be accessed from usespace. and there are no system calls currently to help userspace to program the UAMOR on its behalf.

Quoted 5 lines

I was just wondering how two threads can share a key if they decide to. They would need uamor to give them permissions to the same set of keys and then reuse the key via pkey_mprotect(.., pkey). I am missing the bit about how uamor's across these threads would be synchronized.

As it stands now, two threads are discouraged to share the same key, since we dont provide synchronization of keys across threads. A key allocated in one thread's context has no meaning in the context of another thread. I think, it is constraining to the application, but that is how the semantics were defined and i have implemented it that way for powerpc. Yes eventually; one day I am sure, as applications start exploiting this feature they will demand more flexibility. But for now that is what it is. So given the above semantics, there is no need currently to synchronize umor/amr/iamr across threads.

Quoted 13 lines
Quoted 13 lines
Quoted 12 lines

arch/powerpc/mm/pkeys.c int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 189

Quoted 10 lines
arch/powerpc/mm/pkeys.c +7 -0
+}
+
+void thread_pkey_regs_init(struct thread_struct *thread)
+{
+	write_amr(0x0ul);
+	write_iamr(0x0ul);
+	write_uamor(0x0ul);  

This is not correct, reserved keys should not be set to 0's

Quoted 4 lines
Quoted 1 line

ok. makes sense. best to not touch reserved key bits here.

Also this implies that at init time, the thread has access to all keys, but it can't modify any of the keys in the AMR/IAMR.

it shouldn't modify the bit corresponding to the reserved keys.

These patches dont touch AMOR. the hypervisor is entirely in control of the AMOR.

AMOR is the master controller for these keys. If a reserved key is disabled in AMOR, any changes to the bits corresponding to the reserved-key in AMR or IAMR or UAMOR will have any effect.

But if AMOR has enabled a reserved-key, than we will cause bad things by changing the bits in AMR/IAMR/UAMOR. So you are right. We better not touch the bits corresponding to the reserved-keys.

RP

author
#87 lore raw

PATCH 11/25 powerpc: introduce execute-only pkey

In reply to Ram Pai

This patch provides the implementation of execute-only pkey. The architecture-independent layer expects the arch-dependent layer, to support the ability to create and enable a special key which has execute-only permission.

---
 arch/powerpc/include/asm/book3s/64/mmu.h |    1 +
 arch/powerpc/include/asm/pkeys.h         |    9 ++++-
 arch/powerpc/mm/pkeys.c                  |   57 ++++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+), 1 deletions(-)
arch/powerpc/include/asm/book3s/64/mmu.h +1 -0
index 55950f4..ee18ba0 100644
@@ -115,6 +115,7 @@ struct patb_entry {
 	 * bit unset -> key available for allocation
 	 */
 	u32 pkey_allocation_map;
+	s16 execute_only_pkey; /* key holding execute-only protection */
 #endif
 } mm_context_t;
 
arch/powerpc/include/asm/pkeys.h +8 -1
index 78c5362..0cf115f 100644
@@ -115,11 +115,16 @@ static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
  * Try to dedicate one of the protection keys to be used as an
  * execute-only protection key.
  */
+extern int __execute_only_pkey(struct mm_struct *mm);
 static inline int execute_only_pkey(struct mm_struct *mm)
 {
-	return 0;
+	if (!pkey_inited || !pkey_execute_disable_support)
+		return -1;
+
+	return __execute_only_pkey(mm);
 }
 
+
 static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
 		int prot, int pkey)
 {
@@ -141,6 +146,8 @@ static inline void pkey_mm_init(struct mm_struct *mm)
 	if (!pkey_inited)
 		return;
 	mm_pkey_allocation_map(mm) = initial_allocation_mask;
+	/* -1 means unallocated or invalid */
+	mm->context.execute_only_pkey = -1;
 }
 
 extern void thread_pkey_regs_save(struct thread_struct *thread);
arch/powerpc/mm/pkeys.c +57 -0

60 lines not on this page · raw message

Signature · 1 line
1.7.1
Acked-by on v1 11/25
#88 lore raw

Re: [PATCH 11/25] powerpc: introduce execute-only pkey

Quoted 60 lines · On Fri, 8 Sep 2017 15:44:59 -0700 Ram Pai <[email protected]> wrote:

This patch provides the implementation of execute-only pkey. The architecture-independent layer expects the arch-dependent layer, to support the ability to create and enable a special key which has execute-only permission.

---
 arch/powerpc/include/asm/book3s/64/mmu.h |    1 +
 arch/powerpc/include/asm/pkeys.h         |    9 ++++-
 arch/powerpc/mm/pkeys.c                  |   57 ++++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+), 1 deletions(-)
arch/powerpc/include/asm/book3s/64/mmu.h +1 -0
index 55950f4..ee18ba0 100644
@@ -115,6 +115,7 @@ struct patb_entry {
 	 * bit unset -> key available for allocation
 	 */
 	u32 pkey_allocation_map;
+	s16 execute_only_pkey; /* key holding execute-only protection */
 #endif
 } mm_context_t;
 
arch/powerpc/include/asm/pkeys.h +8 -1
index 78c5362..0cf115f 100644
@@ -115,11 +115,16 @@ static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
  * Try to dedicate one of the protection keys to be used as an
  * execute-only protection key.
  */
+extern int __execute_only_pkey(struct mm_struct *mm);
 static inline int execute_only_pkey(struct mm_struct *mm)
 {
-	return 0;
+	if (!pkey_inited || !pkey_execute_disable_support)
+		return -1;
+
+	return __execute_only_pkey(mm);
 }
 
+
 static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
 		int prot, int pkey)
 {
@@ -141,6 +146,8 @@ static inline void pkey_mm_init(struct mm_struct *mm)
 	if (!pkey_inited)
 		return;
 	mm_pkey_allocation_map(mm) = initial_allocation_mask;
+	/* -1 means unallocated or invalid */
+	mm->context.execute_only_pkey = -1;
 }
 
 extern void thread_pkey_regs_save(struct thread_struct *thread);
arch/powerpc/mm/pkeys.c +0 -0
index 7cd1be4..8a24983 100644

arch/powerpc/mm/pkeys.c void thread_pkey_regs_init(struct thread_struct *thread) · line 197

Quoted 10 lines
arch/powerpc/mm/pkeys.c +7 -0
@@ -188,3 +188,60 @@ void thread_pkey_regs_init(struct thread_struct *thread)
 	write_iamr(0x0ul);
 	write_uamor(0x0ul);
 }
+
+static inline bool pkey_allows_readwrite(int pkey)
+{
+	int pkey_shift = pkeyshift(pkey);
+
+	if (!(read_uamor() & (0x3UL << pkey_shift)))
+		return true;

If uamor for key 0 is 0x10 for example or 0x01 it's a bug. The above check might miss it.

Quoted 40 lines
arch/powerpc/mm/pkeys.c +40 -0
+
+	return !(read_amr() & ((AMR_RD_BIT|AMR_WR_BIT) << pkey_shift));
+}
+
+int __execute_only_pkey(struct mm_struct *mm)
+{
+	bool need_to_set_mm_pkey = false;
+	int execute_only_pkey = mm->context.execute_only_pkey;
+	int ret;
+
+	/* Do we need to assign a pkey for mm's execute-only maps? */
+	if (execute_only_pkey == -1) {
+		/* Go allocate one to use, which might fail */
+		execute_only_pkey = mm_pkey_alloc(mm);
+		if (execute_only_pkey < 0)
+			return -1;
+		need_to_set_mm_pkey = true;
+	}
+
+	/*
+	 * We do not want to go through the relatively costly
+	 * dance to set AMR if we do not need to.  Check it
+	 * first and assume that if the execute-only pkey is
+	 * readwrite-disabled than we do not have to set it
+	 * ourselves.
+	 */
+	if (!need_to_set_mm_pkey &&
+	    !pkey_allows_readwrite(execute_only_pkey))
+		return execute_only_pkey;
+
+	/*
+	 * Set up AMR so that it denies access for everything
+	 * other than execution.
+	 */
+	ret = __arch_set_user_pkey_access(current, execute_only_pkey,
+			(PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));
+	/*
+	 * If the AMR-set operation failed somehow, just return
+	 * 0 and effectively disable execute-only support.
+	 */

arch/powerpc/mm/pkeys.c void thread_pkey_regs_init(struct thread_struct *thread) · line 247

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+	if (ret) {
+		mm_set_pkey_free(mm, execute_only_pkey);
+		return -1;
+	}
+
+	/* We got one, store it and use it from here on out */
+	if (need_to_set_mm_pkey)
+		mm->context.execute_only_pkey = execute_only_pkey;
+	return execute_only_pkey;
+}

Looks good otherwise

author
#89 lore raw

Re: [PATCH 11/25] powerpc: introduce execute-only pkey

Quoted 68 lines · Balbir Singh
Quoted 65 lines · On Fri, 8 Sep 2017 15:44:59 -0700 Ram Pai <[email protected]> wrote:

This patch provides the implementation of execute-only pkey. The architecture-independent layer expects the arch-dependent layer, to support the ability to create and enable a special key which has execute-only permission.

---
 arch/powerpc/include/asm/book3s/64/mmu.h |    1 +
 arch/powerpc/include/asm/pkeys.h         |    9 ++++-
 arch/powerpc/mm/pkeys.c                  |   57 ++++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+), 1 deletions(-)
arch/powerpc/include/asm/book3s/64/mmu.h +1 -0
index 55950f4..ee18ba0 100644
@@ -115,6 +115,7 @@ struct patb_entry {
 	 * bit unset -> key available for allocation
 	 */
 	u32 pkey_allocation_map;
+	s16 execute_only_pkey; /* key holding execute-only protection */
 #endif
 } mm_context_t;
 
arch/powerpc/include/asm/pkeys.h +8 -1
index 78c5362..0cf115f 100644
@@ -115,11 +115,16 @@ static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
  * Try to dedicate one of the protection keys to be used as an
  * execute-only protection key.
  */
+extern int __execute_only_pkey(struct mm_struct *mm);
 static inline int execute_only_pkey(struct mm_struct *mm)
 {
-	return 0;
+	if (!pkey_inited || !pkey_execute_disable_support)
+		return -1;
+
+	return __execute_only_pkey(mm);
 }
 
+
 static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
 		int prot, int pkey)
 {
@@ -141,6 +146,8 @@ static inline void pkey_mm_init(struct mm_struct *mm)
 	if (!pkey_inited)
 		return;
 	mm_pkey_allocation_map(mm) = initial_allocation_mask;
+	/* -1 means unallocated or invalid */
+	mm->context.execute_only_pkey = -1;
 }
 
 extern void thread_pkey_regs_save(struct thread_struct *thread);
arch/powerpc/mm/pkeys.c +2 -0
index 7cd1be4..8a24983 100644
@@ -188,3 +188,60 @@ void thread_pkey_regs_init(struct thread_struct *thread)
 	write_iamr(0x0ul);
 	write_uamor(0x0ul);
 }
+
+static inline bool pkey_allows_readwrite(int pkey)
Quoted 8 lines

arch/powerpc/mm/pkeys.c void thread_pkey_regs_init(struct thread_struct *thread) · line 197

Quoted 5 lines
arch/powerpc/mm/pkeys.c +5 -0
+{
+	int pkey_shift = pkeyshift(pkey);
+
+	if (!(read_uamor() & (0x3UL << pkey_shift)))
+		return true;

If uamor for key 0 is 0x10 for example or 0x01 it's a bug. The above check might miss it.

The specs says both the bits corresponding to a key are set or reset, cannot be anything else.

cut-n-paste from the ISA...
----------------------------------------------------
Software must ensure that both bits of each even/odd bit pair of the AMOR contain the same value. -- i.e., the contents of register RS for mtspr specifying the AMOR must be such that (RS)2n = (RS)2n+1 for every n in the range 0:31 - and like for the UAMOR.
---------------------------------------------------------

Quoted 54 lines
Quoted 41 lines
arch/powerpc/mm/pkeys.c +40 -0
+
+	return !(read_amr() & ((AMR_RD_BIT|AMR_WR_BIT) << pkey_shift));
+}
+
+int __execute_only_pkey(struct mm_struct *mm)
+{
+	bool need_to_set_mm_pkey = false;
+	int execute_only_pkey = mm->context.execute_only_pkey;
+	int ret;
+
+	/* Do we need to assign a pkey for mm's execute-only maps? */
+	if (execute_only_pkey == -1) {
+		/* Go allocate one to use, which might fail */
+		execute_only_pkey = mm_pkey_alloc(mm);
+		if (execute_only_pkey < 0)
+			return -1;
+		need_to_set_mm_pkey = true;
+	}
+
+	/*
+	 * We do not want to go through the relatively costly
+	 * dance to set AMR if we do not need to.  Check it
+	 * first and assume that if the execute-only pkey is
+	 * readwrite-disabled than we do not have to set it
+	 * ourselves.
+	 */
+	if (!need_to_set_mm_pkey &&
+	    !pkey_allows_readwrite(execute_only_pkey))
+		return execute_only_pkey;
+
+	/*
+	 * Set up AMR so that it denies access for everything
+	 * other than execution.
+	 */
+	ret = __arch_set_user_pkey_access(current, execute_only_pkey,
+			(PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));
+	/*
+	 * If the AMR-set operation failed somehow, just return
+	 * 0 and effectively disable execute-only support.
+	 */

arch/powerpc/mm/pkeys.c void thread_pkey_regs_init(struct thread_struct *thread) · line 247

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+	if (ret) {
+		mm_set_pkey_free(mm, execute_only_pkey);
+		return -1;
+	}
+
+	/* We got one, store it and use it from here on out */
+	if (need_to_set_mm_pkey)
+		mm->context.execute_only_pkey = execute_only_pkey;
+	return execute_only_pkey;
+}

Looks good otherwise

Quoted 1 line

thanks.

Signature · 1 line
Ram Pai
#90 lore raw

Re: [PATCH 11/25] powerpc: introduce execute-only pkey

Quoted 79 lines · On Wed, 18 Oct 2017 13:57:39 -0700 Ram Pai <[email protected]> wrote:
Quoted 68 lines · Balbir Singh
Quoted 65 lines · On Fri, 8 Sep 2017 15:44:59 -0700 Ram Pai <[email protected]> wrote:

This patch provides the implementation of execute-only pkey. The architecture-independent layer expects the arch-dependent layer, to support the ability to create and enable a special key which has execute-only permission.

---
 arch/powerpc/include/asm/book3s/64/mmu.h |    1 +
 arch/powerpc/include/asm/pkeys.h         |    9 ++++-
 arch/powerpc/mm/pkeys.c                  |   57 ++++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+), 1 deletions(-)
arch/powerpc/include/asm/book3s/64/mmu.h +1 -0
index 55950f4..ee18ba0 100644
@@ -115,6 +115,7 @@ struct patb_entry {
 	 * bit unset -> key available for allocation
 	 */
 	u32 pkey_allocation_map;
+	s16 execute_only_pkey; /* key holding execute-only protection */
 #endif
 } mm_context_t;
 
arch/powerpc/include/asm/pkeys.h +8 -1
index 78c5362..0cf115f 100644
@@ -115,11 +115,16 @@ static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
  * Try to dedicate one of the protection keys to be used as an
  * execute-only protection key.
  */
+extern int __execute_only_pkey(struct mm_struct *mm);
 static inline int execute_only_pkey(struct mm_struct *mm)
 {
-	return 0;
+	if (!pkey_inited || !pkey_execute_disable_support)
+		return -1;
+
+	return __execute_only_pkey(mm);
 }
 
+
 static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
 		int prot, int pkey)
 {
@@ -141,6 +146,8 @@ static inline void pkey_mm_init(struct mm_struct *mm)
 	if (!pkey_inited)
 		return;
 	mm_pkey_allocation_map(mm) = initial_allocation_mask;
+	/* -1 means unallocated or invalid */
+	mm->context.execute_only_pkey = -1;
 }
 
 extern void thread_pkey_regs_save(struct thread_struct *thread);
arch/powerpc/mm/pkeys.c +2 -0
index 7cd1be4..8a24983 100644
@@ -188,3 +188,60 @@ void thread_pkey_regs_init(struct thread_struct *thread)
 	write_iamr(0x0ul);
 	write_uamor(0x0ul);
 }
+
+static inline bool pkey_allows_readwrite(int pkey)
Quoted 8 lines

arch/powerpc/mm/pkeys.c void thread_pkey_regs_init(struct thread_struct *thread) · line 197

Quoted 5 lines
arch/powerpc/mm/pkeys.c +5 -0
+{
+	int pkey_shift = pkeyshift(pkey);
+
+	if (!(read_uamor() & (0x3UL << pkey_shift)))
+		return true;  

If uamor for key 0 is 0x10 for example or 0x01 it's a bug. The above check might miss it.

Quoted 3 lines

The specs says both the bits corresponding to a key are set or reset, cannot be anything else.

I agree, thats why I said it's a bug if the values are such. Do we care to validate that both bits are the same?

Balbir Singh.

author
#91 lore raw

Re: [PATCH 11/25] powerpc: introduce execute-only pkey

Quoted 82 lines · Balbir Singh
Quoted 79 lines · On Wed, 18 Oct 2017 13:57:39 -0700 Ram Pai <[email protected]> wrote:
Quoted 76 lines · Balbir Singh
Quoted 60 lines · On Fri, 8 Sep 2017 15:44:59 -0700 Ram Pai <[email protected]> wrote:

This patch provides the implementation of execute-only pkey. The architecture-independent layer expects the arch-dependent layer, to support the ability to create and enable a special key which has execute-only permission.

---
 arch/powerpc/include/asm/book3s/64/mmu.h |    1 +
 arch/powerpc/include/asm/pkeys.h         |    9 ++++-
 arch/powerpc/mm/pkeys.c                  |   57 ++++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+), 1 deletions(-)
arch/powerpc/include/asm/book3s/64/mmu.h +1 -0
index 55950f4..ee18ba0 100644
@@ -115,6 +115,7 @@ struct patb_entry {
 	 * bit unset -> key available for allocation
 	 */
 	u32 pkey_allocation_map;
+	s16 execute_only_pkey; /* key holding execute-only protection */
 #endif
 } mm_context_t;
 
arch/powerpc/include/asm/pkeys.h +8 -1
index 78c5362..0cf115f 100644
@@ -115,11 +115,16 @@ static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
  * Try to dedicate one of the protection keys to be used as an
  * execute-only protection key.
  */
+extern int __execute_only_pkey(struct mm_struct *mm);
 static inline int execute_only_pkey(struct mm_struct *mm)
 {
-	return 0;
+	if (!pkey_inited || !pkey_execute_disable_support)
+		return -1;
+
+	return __execute_only_pkey(mm);
 }
 
+
 static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
 		int prot, int pkey)
 {
@@ -141,6 +146,8 @@ static inline void pkey_mm_init(struct mm_struct *mm)
 	if (!pkey_inited)
 		return;
 	mm_pkey_allocation_map(mm) = initial_allocation_mask;
+	/* -1 means unallocated or invalid */
+	mm->context.execute_only_pkey = -1;
 }
 
 extern void thread_pkey_regs_save(struct thread_struct *thread);
arch/powerpc/mm/pkeys.c +0 -0
index 7cd1be4..8a24983 100644

arch/powerpc/mm/pkeys.c void thread_pkey_regs_init(struct thread_struct *thread) · line 197

Quoted 10 lines
arch/powerpc/mm/pkeys.c +7 -0
@@ -188,3 +188,60 @@ void thread_pkey_regs_init(struct thread_struct *thread)
 	write_iamr(0x0ul);
 	write_uamor(0x0ul);
 }
+
+static inline bool pkey_allows_readwrite(int pkey)
+{
+	int pkey_shift = pkeyshift(pkey);
+
+	if (!(read_uamor() & (0x3UL << pkey_shift)))
+		return true;  

If uamor for key 0 is 0x10 for example or 0x01 it's a bug. The above check might miss it.

Quoted 6 lines
Quoted 3 lines

The specs says both the bits corresponding to a key are set or reset, cannot be anything else.

I agree, thats why I said it's a bug if the values are such. Do we care to validate that both bits are the same?

I will put in a assert. Will that work?

RP

Quoted 2 lines

Balbir Singh.

Signature · 1 line
Ram Pai
author
#92 lore raw

PATCH 12/25 powerpc: ability to associate pkey to a vma

In reply to Ram Pai

arch-independent code expects the arch to map
a pkey into the vma's protection bit setting.
The patch provides that ability.

---
 arch/powerpc/include/asm/mman.h  |    8 +++++++-
 arch/powerpc/include/asm/pkeys.h |   18 ++++++++++++++++++
 2 files changed, 25 insertions(+), 1 deletions(-)
arch/powerpc/include/asm/mman.h +7 -1
index 30922f6..067eec2 100644
@@ -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)
 
arch/powerpc/include/asm/pkeys.h +18 -0
index 0cf115f..f13e913 100644
@@ -23,6 +23,24 @@
 #define VM_PKEY_BIT4	VM_HIGH_ARCH_4
 #endif
 
+/* override any generic PKEY Permission defines */
+#define PKEY_DISABLE_EXECUTE   0x4
+#define PKEY_ACCESS_MASK       (PKEY_DISABLE_ACCESS |\
+				PKEY_DISABLE_WRITE  |\
+				PKEY_DISABLE_EXECUTE)
+
+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()  pkeys_total
 #define AMR_RD_BIT 0x1UL
 #define AMR_WR_BIT 0x2UL
Signature · 1 line
1.7.1
#93 lore raw

Re: [PATCH 12/25] powerpc: ability to associate pkey to a vma

Quoted 51 lines · On Fri, 8 Sep 2017 15:45:00 -0700 Ram Pai <[email protected]> wrote:

arch-independent code expects the arch to map
a pkey into the vma's protection bit setting.
The patch provides that ability.

---
 arch/powerpc/include/asm/mman.h  |    8 +++++++-
 arch/powerpc/include/asm/pkeys.h |   18 ++++++++++++++++++
 2 files changed, 25 insertions(+), 1 deletions(-)
arch/powerpc/include/asm/mman.h +7 -1
index 30922f6..067eec2 100644
@@ -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)
 
arch/powerpc/include/asm/pkeys.h +7 -0
index 0cf115f..f13e913 100644
@@ -23,6 +23,24 @@
 #define VM_PKEY_BIT4	VM_HIGH_ARCH_4
 #endif
 
+/* override any generic PKEY Permission defines */
+#define PKEY_DISABLE_EXECUTE   0x4
+#define PKEY_ACCESS_MASK       (PKEY_DISABLE_ACCESS |\
+				PKEY_DISABLE_WRITE  |\
+				PKEY_DISABLE_EXECUTE)
+
+static inline u64 pkey_to_vmflag_bits(u16 pkey)

arch/powerpc/include/asm/pkeys.h line 42

Quoted 10 lines
arch/powerpc/include/asm/pkeys.h +10 -0
+{
+	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));
+}

Assuming that there is a linear order between VM_PKEY_BIT4 to VM_PKEY_BIT0, the conditional checks can be removed

(pkey & 0x1fUL) << VM_PKEY_BIT0?

Balbir Singh

author
#94 lore raw

Re: [PATCH 12/25] powerpc: ability to associate pkey to a vma

Quoted 68 lines · Balbir Singh
Quoted 51 lines · On Fri, 8 Sep 2017 15:45:00 -0700 Ram Pai <[email protected]> wrote:

arch-independent code expects the arch to map
a pkey into the vma's protection bit setting.
The patch provides that ability.

---
 arch/powerpc/include/asm/mman.h  |    8 +++++++-
 arch/powerpc/include/asm/pkeys.h |   18 ++++++++++++++++++
 2 files changed, 25 insertions(+), 1 deletions(-)
arch/powerpc/include/asm/mman.h +7 -1
index 30922f6..067eec2 100644
@@ -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)
 
arch/powerpc/include/asm/pkeys.h +7 -0
index 0cf115f..f13e913 100644
@@ -23,6 +23,24 @@
 #define VM_PKEY_BIT4	VM_HIGH_ARCH_4
 #endif
 
+/* override any generic PKEY Permission defines */
+#define PKEY_DISABLE_EXECUTE   0x4
+#define PKEY_ACCESS_MASK       (PKEY_DISABLE_ACCESS |\
+				PKEY_DISABLE_WRITE  |\
+				PKEY_DISABLE_EXECUTE)
+
+static inline u64 pkey_to_vmflag_bits(u16 pkey)

arch/powerpc/include/asm/pkeys.h line 42

Quoted 10 lines
arch/powerpc/include/asm/pkeys.h +10 -0
+{
+	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));
+}

Assuming that there is a linear order between VM_PKEY_BIT4 to VM_PKEY_BIT0, the conditional checks can be removed

Quoted 1 line

(pkey & 0x1fUL) << VM_PKEY_BIT0?

yes. currently the are linear. But I am afraid it will break without notice someday when someone decides to change the values of VM_PKEY_BITx to be non-contiguous. I can put a BUILD_ASSERTION I suppose. But thought this will be safe.

RP

Quoted 3 lines

Balbir Singh

Signature · 1 line
Ram Pai
author
#95 lore raw

PATCH 13/25 powerpc: implementation for arch_override_mprotect_pkey()

In reply to Ram Pai

arch independent code calls arch_override_mprotect_pkey() to return a pkey that best matches the requested protection.

This patch provides the implementation.

---
 arch/powerpc/include/asm/mmu_context.h |    5 +++
 arch/powerpc/include/asm/pkeys.h       |   17 ++++++++++-
 arch/powerpc/mm/pkeys.c                |   47 ++++++++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 2 deletions(-)
arch/powerpc/include/asm/mmu_context.h +5 -0
index c705a5d..8e5a87e 100644
@@ -145,6 +145,11 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
 #ifndef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
 #define pkey_initialize()
 #define pkey_mm_init(mm)
+
+static inline int vma_pkey(struct vm_area_struct *vma)
+{
+	return 0;
+}
 #endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 
 #endif /* __KERNEL__ */
arch/powerpc/include/asm/pkeys.h +15 -2
index f13e913..d2fffef 100644
@@ -41,6 +41,16 @@ static inline u64 pkey_to_vmflag_bits(u16 pkey)
 		((pkey & 0x10UL) ? VM_PKEY_BIT4 : 0x0UL));
 }
 
+#define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
+				VM_PKEY_BIT3 | VM_PKEY_BIT4)
+
+static inline int vma_pkey(struct vm_area_struct *vma)
+{
+	if (!pkey_inited)
+		return 0;
+	return (vma->vm_flags & ARCH_VM_PKEY_FLAGS) >> VM_PKEY_SHIFT;
+}
+
 #define arch_max_pkey()  pkeys_total
 #define AMR_RD_BIT 0x1UL
 #define AMR_WR_BIT 0x2UL
@@ -142,11 +152,14 @@ static inline int execute_only_pkey(struct mm_struct *mm)
 	return __execute_only_pkey(mm);
 }
 
-
+extern int __arch_override_mprotect_pkey(struct vm_area_struct *vma,
+		int prot, int pkey);
 static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
 		int prot, int pkey)
 {
-	return 0;
+	if (!pkey_inited)
+		return 0;
+	return __arch_override_mprotect_pkey(vma, prot, pkey);
 }
 
 extern int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
arch/powerpc/mm/pkeys.c +47 -0

50 lines not on this page · raw message

Signature · 1 line
1.7.1
#96 lore raw

Re: [PATCH 13/25] powerpc: implementation for arch_override_mprotect_pkey()

Quoted 33 lines · On Fri, 8 Sep 2017 15:45:01 -0700 Ram Pai <[email protected]> wrote:

arch independent code calls arch_override_mprotect_pkey() to return a pkey that best matches the requested protection.

This patch provides the implementation.

---
 arch/powerpc/include/asm/mmu_context.h |    5 +++
 arch/powerpc/include/asm/pkeys.h       |   17 ++++++++++-
 arch/powerpc/mm/pkeys.c                |   47 ++++++++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 2 deletions(-)
arch/powerpc/include/asm/mmu_context.h +5 -0
index c705a5d..8e5a87e 100644
@@ -145,6 +145,11 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
 #ifndef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
 #define pkey_initialize()
 #define pkey_mm_init(mm)
+
+static inline int vma_pkey(struct vm_area_struct *vma)
+{
+	return 0;
+}
 #endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 
 #endif /* __KERNEL__ */
arch/powerpc/include/asm/pkeys.h +0 -0
index f13e913..d2fffef 100644

arch/powerpc/include/asm/pkeys.h static inline u64 pkey_to_vmflag_bits(u16 pkey) · line 50

Quoted 10 lines
arch/powerpc/include/asm/pkeys.h +7 -0
@@ -41,6 +41,16 @@ static inline u64 pkey_to_vmflag_bits(u16 pkey)
 		((pkey & 0x10UL) ? VM_PKEY_BIT4 : 0x0UL));
 }
 
+#define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
+				VM_PKEY_BIT3 | VM_PKEY_BIT4)
+
+static inline int vma_pkey(struct vm_area_struct *vma)
+{
+	if (!pkey_inited)
+		return 0;

We don't want pkey_inited to be present in all functions, why do we need a conditional branch for all functions. Even if we do, it should be a jump label. I would rather we just removed !pkey_inited unless really really required.

Quoted 33 lines
arch/powerpc/include/asm/pkeys.h +8 -2
+	return (vma->vm_flags & ARCH_VM_PKEY_FLAGS) >> VM_PKEY_SHIFT;
+}
+
 #define arch_max_pkey()  pkeys_total
 #define AMR_RD_BIT 0x1UL
 #define AMR_WR_BIT 0x2UL
@@ -142,11 +152,14 @@ static inline int execute_only_pkey(struct mm_struct *mm)
 	return __execute_only_pkey(mm);
 }
 
-
+extern int __arch_override_mprotect_pkey(struct vm_area_struct *vma,
+		int prot, int pkey);
 static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
 		int prot, int pkey)
 {
-	return 0;
+	if (!pkey_inited)
+		return 0;
+	return __arch_override_mprotect_pkey(vma, prot, pkey);
 }
 
 extern int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
arch/powerpc/mm/pkeys.c +2 -0
index 8a24983..fb1a76a 100644
@@ -245,3 +245,50 @@ int __execute_only_pkey(struct mm_struct *mm)
 		mm->context.execute_only_pkey = execute_only_pkey;
 	return execute_only_pkey;
 }
+
+static inline bool vma_is_pkey_exec_only(struct vm_area_struct *vma)

arch/powerpc/mm/pkeys.c int __execute_only_pkey(struct mm_struct *mm) · line 259

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+{
+	/* Do this check first since the vm_flags should be hot */
+	if ((vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)) != VM_EXEC)
+		return false;
+
+	return (vma_pkey(vma) == vma->vm_mm->context.execute_only_pkey);
+}
+
+/*
+ * This should only be called for *plain* mprotect calls.

What's a plain mprotect call?

arch/powerpc/mm/pkeys.c int __execute_only_pkey(struct mm_struct *mm) · line 269

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+ */
+int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot,
+		int pkey)
+{
+	/*
+	 * Is this an mprotect_pkey() call?  If so, never
+	 * override the value that came from the user.
+	 */
+	if (pkey != -1)
+		return pkey;

If the user specified a key, we always use it? Presumably the user got it from pkey_alloc(), in other cases, the user was lazy and used -1 in the mprotect call?

Quoted 15 lines
arch/powerpc/mm/pkeys.c +15 -0
+
+	/*
+	 * If the currently associated pkey is execute-only,
+	 * but the requested protection requires read or write,
+	 * move it back to the default pkey.
+	 */
+	if (vma_is_pkey_exec_only(vma) &&
+	    (prot & (PROT_READ|PROT_WRITE)))
+		return 0;
+
+	/*
+	 * the requested protection is execute-only. Hence
+	 * lets use a execute-only pkey.
+	 */
+	if (prot == PROT_EXEC) {

arch/powerpc/mm/pkeys.c int __execute_only_pkey(struct mm_struct *mm) · line 294

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+		pkey = execute_only_pkey(vma->vm_mm);
+		if (pkey > 0)
+			return pkey;
+	}
+
+	/*
+	 * nothing to override.
+	 */
+	return vma_pkey(vma);
+}

Balbir Singh.

author
#97 lore raw

Re: [PATCH 13/25] powerpc: implementation for arch_override_mprotect_pkey()

Quoted 39 lines · Balbir Singh
Quoted 36 lines · On Fri, 8 Sep 2017 15:45:01 -0700 Ram Pai <[email protected]> wrote:

arch independent code calls arch_override_mprotect_pkey() to return a pkey that best matches the requested protection.

This patch provides the implementation.

---
 arch/powerpc/include/asm/mmu_context.h |    5 +++
 arch/powerpc/include/asm/pkeys.h       |   17 ++++++++++-
 arch/powerpc/mm/pkeys.c                |   47 ++++++++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 2 deletions(-)
arch/powerpc/include/asm/mmu_context.h +5 -0
index c705a5d..8e5a87e 100644
@@ -145,6 +145,11 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
 #ifndef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
 #define pkey_initialize()
 #define pkey_mm_init(mm)
+
+static inline int vma_pkey(struct vm_area_struct *vma)
+{
+	return 0;
+}
 #endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 
 #endif /* __KERNEL__ */
arch/powerpc/include/asm/pkeys.h +0 -0
index f13e913..d2fffef 100644
@@ -41,6 +41,16 @@ static inline u64 pkey_to_vmflag_bits(u16 pkey)
 		((pkey & 0x10UL) ? VM_PKEY_BIT4 : 0x0UL));
 }
 
Quoted 12 lines

arch/powerpc/include/asm/pkeys.h static inline u64 pkey_to_vmflag_bits(u16 pkey) · line 50

Quoted 7 lines
arch/powerpc/include/asm/pkeys.h +7 -0
+#define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
+				VM_PKEY_BIT3 | VM_PKEY_BIT4)
+
+static inline int vma_pkey(struct vm_area_struct *vma)
+{
+	if (!pkey_inited)
+		return 0;

We don't want pkey_inited to be present in all functions, why do we need a conditional branch for all functions. Even if we do, it should be a jump label. I would rather we just removed !pkey_inited unless really really required.

No. we really really need it. For example when we build a kernel with PROTECTION_KEYS config enabled and run that kernel on a older processor or on a system where the key feature is not enabled in the device tree, we have fail all the calls that get called-in by the arch-neutral code.

Hence we need this check.

BTW: jump labels are awkward IMHO, unless absolutely needed.

Quoted 38 lines
Quoted 38 lines
arch/powerpc/include/asm/pkeys.h +8 -2
+	return (vma->vm_flags & ARCH_VM_PKEY_FLAGS) >> VM_PKEY_SHIFT;
+}
+
 #define arch_max_pkey()  pkeys_total
 #define AMR_RD_BIT 0x1UL
 #define AMR_WR_BIT 0x2UL
@@ -142,11 +152,14 @@ static inline int execute_only_pkey(struct mm_struct *mm)
 	return __execute_only_pkey(mm);
 }
 
-
+extern int __arch_override_mprotect_pkey(struct vm_area_struct *vma,
+		int prot, int pkey);
 static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
 		int prot, int pkey)
 {
-	return 0;
+	if (!pkey_inited)
+		return 0;
+	return __arch_override_mprotect_pkey(vma, prot, pkey);
 }
 
 extern int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
arch/powerpc/mm/pkeys.c +6 -0
index 8a24983..fb1a76a 100644
@@ -245,3 +245,50 @@ int __execute_only_pkey(struct mm_struct *mm)
 		mm->context.execute_only_pkey = execute_only_pkey;
 	return execute_only_pkey;
 }
+
+static inline bool vma_is_pkey_exec_only(struct vm_area_struct *vma)
+{
+	/* Do this check first since the vm_flags should be hot */
+	if ((vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)) != VM_EXEC)
+		return false;
Quoted 8 lines

arch/powerpc/mm/pkeys.c int __execute_only_pkey(struct mm_struct *mm) · line 259

Quoted 6 lines
arch/powerpc/mm/pkeys.c +6 -0
+
+	return (vma_pkey(vma) == vma->vm_mm->context.execute_only_pkey);
+}
+
+/*
+ * This should only be called for *plain* mprotect calls.

What's a plain mprotect call?

there is sys_mprotect() and now there is a sys_pkey_mprotect() call. The 'plain' one is the former.

Quoted 15 lines

arch/powerpc/mm/pkeys.c int __execute_only_pkey(struct mm_struct *mm) · line 269

Quoted 11 lines
arch/powerpc/mm/pkeys.c +10 -0
+ */
+int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot,
+		int pkey)
+{
+	/*
+	 * Is this an mprotect_pkey() call?  If so, never
+	 * override the value that came from the user.
+	 */
+	if (pkey != -1)
+		return pkey;

If the user specified a key, we always use it? Presumably the user got it from pkey_alloc(), in other cases, the user was lazy and used -1 in the mprotect call?

in the plain sys_mprotect() key is not specified. In that case this function gets called with a -1.

Quoted 28 lines
Quoted 16 lines
arch/powerpc/mm/pkeys.c +15 -0
+
+	/*
+	 * If the currently associated pkey is execute-only,
+	 * but the requested protection requires read or write,
+	 * move it back to the default pkey.
+	 */
+	if (vma_is_pkey_exec_only(vma) &&
+	    (prot & (PROT_READ|PROT_WRITE)))
+		return 0;
+
+	/*
+	 * the requested protection is execute-only. Hence
+	 * lets use a execute-only pkey.
+	 */
+	if (prot == PROT_EXEC) {

arch/powerpc/mm/pkeys.c int __execute_only_pkey(struct mm_struct *mm) · line 294

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+		pkey = execute_only_pkey(vma->vm_mm);
+		if (pkey > 0)
+			return pkey;
+	}
+
+	/*
+	 * nothing to override.
+	 */
+	return vma_pkey(vma);
+}

Balbir Singh.

Signature · 1 line
Ram Pai
#98 lore raw

Re: [PATCH 13/25] powerpc: implementation for arch_override_mprotect_pkey()

Quoted 53 lines · On Wed, 18 Oct 2017 14:10:41 -0700 Ram Pai <[email protected]> wrote:
Quoted 39 lines · Balbir Singh
Quoted 36 lines · On Fri, 8 Sep 2017 15:45:01 -0700 Ram Pai <[email protected]> wrote:

arch independent code calls arch_override_mprotect_pkey() to return a pkey that best matches the requested protection.

This patch provides the implementation.

---
 arch/powerpc/include/asm/mmu_context.h |    5 +++
 arch/powerpc/include/asm/pkeys.h       |   17 ++++++++++-
 arch/powerpc/mm/pkeys.c                |   47 ++++++++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 2 deletions(-)
arch/powerpc/include/asm/mmu_context.h +5 -0
index c705a5d..8e5a87e 100644
@@ -145,6 +145,11 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
 #ifndef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
 #define pkey_initialize()
 #define pkey_mm_init(mm)
+
+static inline int vma_pkey(struct vm_area_struct *vma)
+{
+	return 0;
+}
 #endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 
 #endif /* __KERNEL__ */
arch/powerpc/include/asm/pkeys.h +0 -0
index f13e913..d2fffef 100644
@@ -41,6 +41,16 @@ static inline u64 pkey_to_vmflag_bits(u16 pkey)
 		((pkey & 0x10UL) ? VM_PKEY_BIT4 : 0x0UL));
 }
 
Quoted 12 lines

arch/powerpc/include/asm/pkeys.h static inline u64 pkey_to_vmflag_bits(u16 pkey) · line 50

Quoted 7 lines
arch/powerpc/include/asm/pkeys.h +7 -0
+#define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
+				VM_PKEY_BIT3 | VM_PKEY_BIT4)
+
+static inline int vma_pkey(struct vm_area_struct *vma)
+{
+	if (!pkey_inited)
+		return 0;  

We don't want pkey_inited to be present in all functions, why do we need a conditional branch for all functions. Even if we do, it should be a jump label. I would rather we just removed !pkey_inited unless really really required.

Quoted 7 lines

No. we really really need it. For example when we build a kernel with PROTECTION_KEYS config enabled and run that kernel on a older processor or on a system where the key feature is not enabled in the device tree, we have fail all the calls that get called-in by the arch-neutral code.

Hence we need this check.

Use a mmu_feature then, it's already designed and optimized for that purpose

Quoted 2 lines

BTW: jump labels are awkward IMHO, unless absolutely needed.

The if checks across the place will hurt performance and we want to have this enabled by default, we may need a mmu feature or jump labels

Balbir Singh.

author
#99 lore raw

Re: [PATCH 13/25] powerpc: implementation for arch_override_mprotect_pkey()

Quoted 61 lines · Balbir Singh
Quoted 58 lines · On Wed, 18 Oct 2017 14:10:41 -0700 Ram Pai <[email protected]> wrote:
Quoted 39 lines · Balbir Singh
Quoted 36 lines · On Fri, 8 Sep 2017 15:45:01 -0700 Ram Pai <[email protected]> wrote:

arch independent code calls arch_override_mprotect_pkey() to return a pkey that best matches the requested protection.

This patch provides the implementation.

---
 arch/powerpc/include/asm/mmu_context.h |    5 +++
 arch/powerpc/include/asm/pkeys.h       |   17 ++++++++++-
 arch/powerpc/mm/pkeys.c                |   47 ++++++++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 2 deletions(-)
arch/powerpc/include/asm/mmu_context.h +5 -0
index c705a5d..8e5a87e 100644
@@ -145,6 +145,11 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
 #ifndef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
 #define pkey_initialize()
 #define pkey_mm_init(mm)
+
+static inline int vma_pkey(struct vm_area_struct *vma)
+{
+	return 0;
+}
 #endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 
 #endif /* __KERNEL__ */
arch/powerpc/include/asm/pkeys.h +0 -0
index f13e913..d2fffef 100644
@@ -41,6 +41,16 @@ static inline u64 pkey_to_vmflag_bits(u16 pkey)
 		((pkey & 0x10UL) ? VM_PKEY_BIT4 : 0x0UL));
 }
 
Quoted 12 lines

arch/powerpc/include/asm/pkeys.h static inline u64 pkey_to_vmflag_bits(u16 pkey) · line 50

Quoted 7 lines
arch/powerpc/include/asm/pkeys.h +7 -0
+#define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
+				VM_PKEY_BIT3 | VM_PKEY_BIT4)
+
+static inline int vma_pkey(struct vm_area_struct *vma)
+{
+	if (!pkey_inited)
+		return 0;  

We don't want pkey_inited to be present in all functions, why do we need a conditional branch for all functions. Even if we do, it should be a jump label. I would rather we just removed !pkey_inited unless really really required.

No. we really really need it. For example when we build a kernel with PROTECTION_KEYS config enabled and run that kernel on a older processor or on a system where the key feature is not enabled in the device tree, we have fail all the calls that get called-in by the arch-neutral code.

Quoted 5 lines
Quoted 2 lines

Hence we need this check.

Use a mmu_feature then, it's already designed and optimized for that purpose

We rely on a combination of cpu_feature and firmware_feature. But that is still not sufficient. It is also gated on !radix_enabled().

In other words, the pkey system is enabled if
a) if we are in a lpar and device tree has the feature enabled, and there are more than zero keys enabled and radix is not enabled.

OR

b) if we in baremetal, and the CPU is power5 or later and radix is not enabled.

All these criteria determine the value of 'pkey_inited'.

Quoted 6 lines
Quoted 3 lines

BTW: jump labels are awkward IMHO, unless absolutely needed.

The if checks across the place will hurt performance and we want to have this enabled by default, we may need a mmu feature or jump labels

I like the idea of jump_label now that I googled for it.

Thanks,
RP

Quoted 2 lines

Balbir Singh.

Signature · 1 line
Ram Pai
author
#100 lore raw

PATCH 14/25 powerpc: map vma key-protection bits to pte key bits.

In reply to Ram Pai

map the key protection bits of the vma to the pkey bits in the PTE.

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.

BUT, On 4k kernel, bit 3, and 4 could not be freed up. remember? Hence we have to be satisfied with 5,6 and 7.

---
 arch/powerpc/include/asm/book3s/64/pgtable.h |   25 ++++++++++++++++++++++++-
 arch/powerpc/include/asm/mman.h              |    8 ++++++++
 arch/powerpc/include/asm/pkeys.h             |   12 ++++++++++++
 3 files changed, 44 insertions(+), 1 deletions(-)
arch/powerpc/include/asm/book3s/64/pgtable.h +24 -1
index 73ed52c..5935d4e 100644
@@ -38,6 +38,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 */
@@ -57,6 +58,25 @@
 /* Max physical address bit as per radix table */
 #define _RPAGE_PA_MAX		57
 
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+#ifdef CONFIG_PPC_64K_PAGES
+#define H_PAGE_PKEY_BIT0	_RPAGE_RSV1
+#define H_PAGE_PKEY_BIT1	_RPAGE_RSV2
+#else /* CONFIG_PPC_64K_PAGES */
+#define H_PAGE_PKEY_BIT0	0 /* _RPAGE_RSV1 is not available */
+#define H_PAGE_PKEY_BIT1	0 /* _RPAGE_RSV2 is not available */
+#endif /* CONFIG_PPC_64K_PAGES */
+#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.
  *
@@ -120,13 +140,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
arch/powerpc/include/asm/mman.h +8 -0
index 067eec2..3f7220f 100644
@@ -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))
arch/powerpc/include/asm/pkeys.h +12 -0
index d2fffef..0d2488a 100644
@@ -41,6 +41,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));
+}
+
 #define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
 				VM_PKEY_BIT3 | VM_PKEY_BIT4)
 
Signature · 1 line
1.7.1
#101 lore raw

Re: [PATCH 14/25] powerpc: map vma key-protection bits to pte key bits.

Quoted 42 lines · On Fri, 8 Sep 2017 15:45:02 -0700 Ram Pai <[email protected]> wrote:

map the key protection bits of the vma to the pkey bits in the PTE.

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.

BUT, On 4k kernel, bit 3, and 4 could not be freed up. remember? Hence we have to be satisfied with 5,6 and 7.

---
 arch/powerpc/include/asm/book3s/64/pgtable.h |   25 ++++++++++++++++++++++++-
 arch/powerpc/include/asm/mman.h              |    8 ++++++++
 arch/powerpc/include/asm/pkeys.h             |   12 ++++++++++++
 3 files changed, 44 insertions(+), 1 deletions(-)
arch/powerpc/include/asm/book3s/64/pgtable.h +9 -0
index 73ed52c..5935d4e 100644
@@ -38,6 +38,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 */
@@ -57,6 +58,25 @@
 /* Max physical address bit as per radix table */
 #define _RPAGE_PA_MAX		57
 
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+#ifdef CONFIG_PPC_64K_PAGES
+#define H_PAGE_PKEY_BIT0	_RPAGE_RSV1
+#define H_PAGE_PKEY_BIT1	_RPAGE_RSV2
+#else /* CONFIG_PPC_64K_PAGES */
+#define H_PAGE_PKEY_BIT0	0 /* _RPAGE_RSV1 is not available */
+#define H_PAGE_PKEY_BIT1	0 /* _RPAGE_RSV2 is not available */
+#endif /* CONFIG_PPC_64K_PAGES */

arch/powerpc/include/asm/book3s/64/pgtable.h line 78

Quoted 10 lines
arch/powerpc/include/asm/book3s/64/pgtable.h +10 -0
+#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 */

H_PTE_PKEY_BITX?

Quoted 52 lines
arch/powerpc/include/asm/book3s/64/pgtable.h +5 -1
+
 /*
  * Max physical address bit we will use for now.
  *
@@ -120,13 +140,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
arch/powerpc/include/asm/mman.h +8 -0
index 067eec2..3f7220f 100644
@@ -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))
arch/powerpc/include/asm/pkeys.h +0 -0
index d2fffef..0d2488a 100644

arch/powerpc/include/asm/pkeys.h static inline u64 pkey_to_vmflag_bits(u16 pkey) · line 44

Quoted 4 lines
arch/powerpc/include/asm/pkeys.h +1 -0
@@ -41,6 +41,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)

vmflag_to_pte_pkey_bits?

Quoted 4 lines
arch/powerpc/include/asm/pkeys.h +4 -0
+{
+	if (!pkey_inited)
+		return 0x0UL;
+

arch/powerpc/include/asm/pkeys.h static inline u64 pkey_to_vmflag_bits(u16 pkey) · line 58

Quoted 10 lines
arch/powerpc/include/asm/pkeys.h +7 -0
+	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));
+}
+
 #define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
 				VM_PKEY_BIT3 | VM_PKEY_BIT4)
 

Balbir Singh.

author
#102 lore raw

Re: [PATCH 14/25] powerpc: map vma key-protection bits to pte key bits.

Quoted 49 lines · Balbir Singh
Quoted 46 lines · On Fri, 8 Sep 2017 15:45:02 -0700 Ram Pai <[email protected]> wrote:

map the key protection bits of the vma to the pkey bits in the PTE.

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.

BUT, On 4k kernel, bit 3, and 4 could not be freed up. remember? Hence we have to be satisfied with 5,6 and 7.

---
 arch/powerpc/include/asm/book3s/64/pgtable.h |   25 ++++++++++++++++++++++++-
 arch/powerpc/include/asm/mman.h              |    8 ++++++++
 arch/powerpc/include/asm/pkeys.h             |   12 ++++++++++++
 3 files changed, 44 insertions(+), 1 deletions(-)
arch/powerpc/include/asm/book3s/64/pgtable.h +13 -0
index 73ed52c..5935d4e 100644
@@ -38,6 +38,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 */
@@ -57,6 +58,25 @@
 /* Max physical address bit as per radix table */
 #define _RPAGE_PA_MAX		57
 
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+#ifdef CONFIG_PPC_64K_PAGES
+#define H_PAGE_PKEY_BIT0	_RPAGE_RSV1
+#define H_PAGE_PKEY_BIT1	_RPAGE_RSV2
+#else /* CONFIG_PPC_64K_PAGES */
+#define H_PAGE_PKEY_BIT0	0 /* _RPAGE_RSV1 is not available */
+#define H_PAGE_PKEY_BIT1	0 /* _RPAGE_RSV2 is not available */
+#endif /* CONFIG_PPC_64K_PAGES */
+#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 */
Quoted 8 lines

arch/powerpc/include/asm/book3s/64/pgtable.h line 78

Quoted 6 lines
arch/powerpc/include/asm/book3s/64/pgtable.h +6 -0
+#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 */

H_PTE_PKEY_BITX?

ok. makes sense. will do.

Quoted 56 lines
Quoted 56 lines
arch/powerpc/include/asm/book3s/64/pgtable.h +5 -1
+
 /*
  * Max physical address bit we will use for now.
  *
@@ -120,13 +140,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
arch/powerpc/include/asm/mman.h +8 -0
index 067eec2..3f7220f 100644
@@ -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))
arch/powerpc/include/asm/pkeys.h +0 -0
index d2fffef..0d2488a 100644
@@ -41,6 +41,18 @@ static inline u64 pkey_to_vmflag_bits(u16 pkey)
 		((pkey & 0x10UL) ? VM_PKEY_BIT4 : 0x0UL));
 }
 
Quoted 3 lines

arch/powerpc/include/asm/pkeys.h static inline u64 pkey_to_vmflag_bits(u16 pkey) · line 44

Quoted 1 line
arch/powerpc/include/asm/pkeys.h +1 -0
+static inline u64 vmflag_to_page_pkey_bits(u64 vm_flags)

vmflag_to_pte_pkey_bits?

ok. if you insist :). will do.

Quoted 17 lines
Quoted 5 lines
arch/powerpc/include/asm/pkeys.h +4 -0
+{
+	if (!pkey_inited)
+		return 0x0UL;
+

arch/powerpc/include/asm/pkeys.h static inline u64 pkey_to_vmflag_bits(u16 pkey) · line 58

Quoted 10 lines
arch/powerpc/include/asm/pkeys.h +7 -0
+	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));
+}
+
 #define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
 				VM_PKEY_BIT3 | VM_PKEY_BIT4)
 

Balbir Singh.

Signature · 1 line
Ram Pai
author
#103 lore raw

PATCH 15/25 powerpc: sys_pkey_mprotect() system call

In reply to Ram Pai

Patch provides the ability for a process to
associate a pkey with a address range.

---
 arch/powerpc/include/asm/systbl.h      |    1 +
 arch/powerpc/include/asm/unistd.h      |    4 +---
 arch/powerpc/include/uapi/asm/unistd.h |    1 +
 3 files changed, 3 insertions(+), 3 deletions(-)
arch/powerpc/include/asm/systbl.h +1 -0
index 22dd776..b33b551 100644
@@ -390,3 +390,4 @@
 SYSCALL(statx)
 SYSCALL(pkey_alloc)
 SYSCALL(pkey_free)
+SYSCALL(pkey_mprotect)
arch/powerpc/include/asm/unistd.h +1 -3
index e0273bc..daf1ba9 100644
@@ -12,12 +12,10 @@
 #include <uapi/asm/unistd.h>
 
 
-#define NR_syscalls		386
+#define NR_syscalls		387
 
 #define __NR__exit __NR_exit
 
-#define __IGNORE_pkey_mprotect
-
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
arch/powerpc/include/uapi/asm/unistd.h +1 -0
index 7993a07..71ae45e 100644
@@ -396,5 +396,6 @@
 #define __NR_statx		383
 #define __NR_pkey_alloc		384
 #define __NR_pkey_free		385
+#define __NR_pkey_mprotect	386
 
 #endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */
Signature · 1 line
1.7.1
author
#104 lore raw

PATCH 16/25 powerpc: Program HPTE key protection bits

In reply to Ram Pai

Map the PTE protection key bits to the HPTE key protection bits, while creating HPTE entries.

---
 arch/powerpc/include/asm/book3s/64/mmu-hash.h |    5 +++++
 arch/powerpc/include/asm/mmu_context.h        |    6 ++++++
 arch/powerpc/include/asm/pkeys.h              |   13 +++++++++++++
 arch/powerpc/mm/hash_utils_64.c               |    1 +
 4 files changed, 25 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/book3s/64/mmu-hash.h +5 -0
index 508275b..2e22357 100644
@@ -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_R_KEY		(HPTE_R_KEY_LO | HPTE_R_KEY_HI)
 
 #define HPTE_V_1TB_SEG		ASM_CONST(0x4000000000000000)
arch/powerpc/include/asm/mmu_context.h +6 -0
index 8e5a87e..04e9221 100644
@@ -150,6 +150,12 @@ static inline int vma_pkey(struct vm_area_struct *vma)
 {
 	return 0;
 }
+
+static inline u64 pte_to_hpte_pkey_bits(u64 pteflags)
+{
+	return 0x0UL;
+}
+
 #endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 
 #endif /* __KERNEL__ */
arch/powerpc/include/asm/pkeys.h +13 -0
index 0d2488a..cd3924c 100644
@@ -67,6 +67,19 @@ static inline int vma_pkey(struct vm_area_struct *vma)
 #define AMR_RD_BIT 0x1UL
 #define AMR_WR_BIT 0x2UL
 #define IAMR_EX_BIT 0x1UL
+
+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));
+}
+
 #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
arch/powerpc/mm/hash_utils_64.c +1 -0
index 67f62b5..a739a2d 100644
@@ -232,6 +232,7 @@ unsigned long htab_convert_pte_flags(unsigned long pteflags)
 		 */
 		rflags |= HPTE_R_M;
 
+	rflags |= pte_to_hpte_pkey_bits(pteflags);
 	return rflags;
 }
 
Signature · 1 line
1.7.1
Acked-by on v1 16/25
#105 lore raw

Re: [PATCH 16/25] powerpc: Program HPTE key protection bits

Quoted 80 lines · On Fri, 8 Sep 2017 15:45:04 -0700 Ram Pai <[email protected]> wrote:

Map the PTE protection key bits to the HPTE key protection bits, while creating HPTE entries.

---
 arch/powerpc/include/asm/book3s/64/mmu-hash.h |    5 +++++
 arch/powerpc/include/asm/mmu_context.h        |    6 ++++++
 arch/powerpc/include/asm/pkeys.h              |   13 +++++++++++++
 arch/powerpc/mm/hash_utils_64.c               |    1 +
 4 files changed, 25 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/book3s/64/mmu-hash.h +5 -0
index 508275b..2e22357 100644
@@ -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_R_KEY		(HPTE_R_KEY_LO | HPTE_R_KEY_HI)
 
 #define HPTE_V_1TB_SEG		ASM_CONST(0x4000000000000000)
arch/powerpc/include/asm/mmu_context.h +6 -0
index 8e5a87e..04e9221 100644
@@ -150,6 +150,12 @@ static inline int vma_pkey(struct vm_area_struct *vma)
 {
 	return 0;
 }
+
+static inline u64 pte_to_hpte_pkey_bits(u64 pteflags)
+{
+	return 0x0UL;
+}
+
 #endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 
 #endif /* __KERNEL__ */
arch/powerpc/include/asm/pkeys.h +13 -0
index 0d2488a..cd3924c 100644
@@ -67,6 +67,19 @@ static inline int vma_pkey(struct vm_area_struct *vma)
 #define AMR_RD_BIT 0x1UL
 #define AMR_WR_BIT 0x2UL
 #define IAMR_EX_BIT 0x1UL
+
+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));
+}
+
 #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
arch/powerpc/mm/hash_utils_64.c +0 -0
index 67f62b5..a739a2d 100644

arch/powerpc/mm/hash_utils_64.c unsigned long htab_convert_pte_flags(unsigned long pteflags) · line 238

Quoted 7 lines
arch/powerpc/mm/hash_utils_64.c +1 -0
@@ -232,6 +232,7 @@ unsigned long htab_convert_pte_flags(unsigned long pteflags)
 		 */
 		rflags |= HPTE_R_M;
 
+	rflags |= pte_to_hpte_pkey_bits(pteflags);
 	return rflags;
 }
 

Looks good!

author
#106 lore raw

PATCH 17/25 powerpc: helper to validate key-access permissions of a pte

In reply to Ram Pai

helper function that checks if the read/write/execute is allowed on the pte.

---
 arch/powerpc/include/asm/book3s/64/pgtable.h |    4 +++
 arch/powerpc/include/asm/pkeys.h             |   12 +++++++++++
 arch/powerpc/mm/pkeys.c                      |   28 ++++++++++++++++++++++++++
 3 files changed, 44 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/book3s/64/pgtable.h +4 -0
index 5935d4e..bd244b3 100644
@@ -492,6 +492,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)
arch/powerpc/include/asm/pkeys.h +12 -0
index cd3924c..50522a0 100644
@@ -80,6 +80,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));
+}
+
 #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
arch/powerpc/mm/pkeys.c +28 -0
index fb1a76a..24589d9 100644
@@ -292,3 +292,31 @@ 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;
+
+	amr = read_amr(); /* delay reading amr uptil absolutely needed*/
+	return ((!write && !(amr & (AMR_RD_BIT << pkey_shift))) ||
+		(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);
+}
Signature · 1 line
1.7.1
#107 lore raw

Re: [PATCH 17/25] powerpc: helper to validate key-access permissions of a pte

Quoted 54 lines · On Fri, 8 Sep 2017 15:45:05 -0700 Ram Pai <[email protected]> wrote:

helper function that checks if the read/write/execute is allowed on the pte.

---
 arch/powerpc/include/asm/book3s/64/pgtable.h |    4 +++
 arch/powerpc/include/asm/pkeys.h             |   12 +++++++++++
 arch/powerpc/mm/pkeys.c                      |   28 ++++++++++++++++++++++++++
 3 files changed, 44 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/book3s/64/pgtable.h +4 -0
index 5935d4e..bd244b3 100644
@@ -492,6 +492,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)
arch/powerpc/include/asm/pkeys.h +12 -0
index cd3924c..50522a0 100644
@@ -80,6 +80,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));
+}
+
 #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
arch/powerpc/mm/pkeys.c +0 -0
index fb1a76a..24589d9 100644
@@ -292,3 +292,31 @@ int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot,
 	 */

arch/powerpc/mm/pkeys.c int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, · line 302

Quoted 10 lines
arch/powerpc/mm/pkeys.c +8 -0
 	return vma_pkey(vma);
 }
+
+static bool pkey_access_permitted(int pkey, bool write, bool execute)
+{
+	int pkey_shift;
+	u64 amr;
+
+	if (!pkey)
+		return true;

Why would we have pkey set to 0, it's reserved. Why do we return true?

Quoted 7 lines
arch/powerpc/mm/pkeys.c +7 -0
+
+	pkey_shift = pkeyshift(pkey);
+	if (!(read_uamor() & (0x3UL << pkey_shift)))
+		return true;
+
+	if (execute && !(read_iamr() & (IAMR_EX_BIT << pkey_shift)))
+		return true;

arch/powerpc/mm/pkeys.c int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, · line 319

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+
+	amr = read_amr(); /* delay reading amr uptil absolutely needed*/
+	return ((!write && !(amr & (AMR_RD_BIT << pkey_shift))) ||
+		(write &&  !(amr & (AMR_WR_BIT << pkey_shift))));
+}
+
+bool arch_pte_access_permitted(u64 pte, bool write, bool execute)
+{
+	if (!pkey_inited)
+		return true;

Again, don't like the pkey_inited bits :)

arch/powerpc/mm/pkeys.c int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, · line 322

Quoted 3 lines
arch/powerpc/mm/pkeys.c +3 -0
+	return pkey_access_permitted(pte_to_pkey_bits(pte),
+			write, execute);
+}

Balbir Singh

author
#108 lore raw

Re: [PATCH 17/25] powerpc: helper to validate key-access permissions of a pte

Quoted 61 lines · Balbir Singh
Quoted 58 lines · On Fri, 8 Sep 2017 15:45:05 -0700 Ram Pai <[email protected]> wrote:

helper function that checks if the read/write/execute is allowed on the pte.

---
 arch/powerpc/include/asm/book3s/64/pgtable.h |    4 +++
 arch/powerpc/include/asm/pkeys.h             |   12 +++++++++++
 arch/powerpc/mm/pkeys.c                      |   28 ++++++++++++++++++++++++++
 3 files changed, 44 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/book3s/64/pgtable.h +4 -0
index 5935d4e..bd244b3 100644
@@ -492,6 +492,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)
arch/powerpc/include/asm/pkeys.h +12 -0
index cd3924c..50522a0 100644
@@ -80,6 +80,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));
+}
+
 #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
arch/powerpc/mm/pkeys.c +2 -0
index fb1a76a..24589d9 100644
@@ -292,3 +292,31 @@ 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)
Quoted 8 lines

arch/powerpc/mm/pkeys.c int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, · line 302

Quoted 6 lines
arch/powerpc/mm/pkeys.c +6 -0
+{
+	int pkey_shift;
+	u64 amr;
+
+	if (!pkey)
+		return true;

Why would we have pkey set to 0, it's reserved. Why do we return true?

pkey 0 is reserved in some weird sense. it is the default key which is omnipresent, which cannot be allocated or freed, but can be used any time and allows read/write/execute at all times.

Quoted 12 lines
Quoted 12 lines
arch/powerpc/mm/pkeys.c +11 -0
+
+	pkey_shift = pkeyshift(pkey);
+	if (!(read_uamor() & (0x3UL << pkey_shift)))
+		return true;
+
+	if (execute && !(read_iamr() & (IAMR_EX_BIT << pkey_shift)))
+		return true;
+
+	amr = read_amr(); /* delay reading amr uptil absolutely needed*/
+	return ((!write && !(amr & (AMR_RD_BIT << pkey_shift))) ||
+		(write &&  !(amr & (AMR_WR_BIT << pkey_shift))));
Quoted 8 lines

arch/powerpc/mm/pkeys.c int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, · line 319

Quoted 6 lines
arch/powerpc/mm/pkeys.c +6 -0
+}
+
+bool arch_pte_access_permitted(u64 pte, bool write, bool execute)
+{
+	if (!pkey_inited)
+		return true;

Again, don't like the pkey_inited bits :)

suggest something. :) running out of ideas ;)

Quoted 6 lines

arch/powerpc/mm/pkeys.c int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, · line 322

Quoted 4 lines
arch/powerpc/mm/pkeys.c +3 -0
+	return pkey_access_permitted(pte_to_pkey_bits(pte),
+			write, execute);
+}

Balbir Singh

Signature · 1 line
Ram Pai
author
#109 lore raw

PATCH 18/25 powerpc: check key protection for user page access

In reply to Ram Pai

Make sure that the kernel does not access user pages without checking their key-protection.

---
 arch/powerpc/include/asm/book3s/64/pgtable.h |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/book3s/64/pgtable.h +14 -0
index bd244b3..d22bb4d 100644
@@ -494,6 +494,20 @@ static inline void write_uamor(u64 value)
 
 #ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
 extern bool arch_pte_access_permitted(u64 pte, bool write, bool execute);
+
+#define pte_access_permitted(pte, write) \
+	(pte_present(pte) && \
+	 ((!(write) || pte_write(pte)) && \
+	  arch_pte_access_permitted(pte_val(pte), !!write, 0)))
+
+/*
+ * We store key in pmd for huge tlb pages. So need
+ * to check for key protection.
+ */
+#define pmd_access_permitted(pmd, write) \
+	(pmd_present(pmd) && \
+	 ((!(write) || pmd_write(pmd)) && \
+	  arch_pte_access_permitted(pmd_val(pmd), !!write, 0)))
 #endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
Signature · 1 line
1.7.1
#110 lore raw

Re: [PATCH 18/25] powerpc: check key protection for user page access

Quoted 3 lines · On Fri, 8 Sep 2017 15:45:06 -0700 Ram Pai <[email protected]> wrote:

Make sure that the kernel does not access user pages without checking their key-protection.

Why? This makes the routines AMR/thread specific? Looks like x86 does this as well, but these routines are used by GUP from the kernel.

Balbir Singh.

author
#111 lore raw

Re: [PATCH 18/25] powerpc: check key protection for user page access

Quoted 9 lines · Balbir Singh
Quoted 3 lines · On Fri, 8 Sep 2017 15:45:06 -0700 Ram Pai <[email protected]> wrote:

Make sure that the kernel does not access user pages without checking their key-protection.

Why? This makes the routines AMR/thread specific? Looks like x86 does this as well

Yes. the memkey semantics implemented by x86, assumes that the keys and their access-permission are per thread. In other words, a key which is enabled in the context of one thread, will not be enabled in the context of another thread.

Quoted 2 lines

but these routines are used by GUP from
the kernel.

See a problem?

RP

#112 lore raw

Re: [PATCH 18/25] powerpc: check key protection for user page access

Quoted 16 lines · On Wed, 18 Oct 2017 14:29:24 -0700 Ram Pai <[email protected]> wrote:
Quoted 9 lines · Balbir Singh
Quoted 3 lines · On Fri, 8 Sep 2017 15:45:06 -0700 Ram Pai <[email protected]> wrote:

Make sure that the kernel does not access user pages without checking their key-protection.

Why? This makes the routines AMR/thread specific? Looks like x86 does this as well

Yes. the memkey semantics implemented by x86, assumes that the keys and their access-permission are per thread. In other words, a key which is enabled in the context of one thread, will not be enabled in the context of another thread.

Quoted 5 lines
Quoted 2 lines

but these routines are used by GUP from
the kernel.

See a problem?

No, I don't understand why gup (called from driver context, probably) should worry about permissions and keys?

Balbir Singh.

author
#113 lore raw

Re: [PATCH 18/25] powerpc: check key protection for user page access

Quoted 19 lines · Balbir Singh
Quoted 16 lines · On Wed, 18 Oct 2017 14:29:24 -0700 Ram Pai <[email protected]> wrote:
Quoted 9 lines · Balbir Singh
Quoted 3 lines · On Fri, 8 Sep 2017 15:45:06 -0700 Ram Pai <[email protected]> wrote:

Make sure that the kernel does not access user pages without checking their key-protection.

Why? This makes the routines AMR/thread specific? Looks like x86 does this as well

Yes. the memkey semantics implemented by x86, assumes that the keys and their access-permission are per thread. In other words, a key which is enabled in the context of one thread, will not be enabled in the context of another thread.

Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

but these routines are used by GUP from
the kernel.

See a problem?

No, I don't understand why gup (called from driver context, probably) should worry about permissions and keys?

There are some user level features; eg: pipe, where the userspace donates one of its pages to the kernel, to buffer the pipe stream.

But if the donated page has a non-permissive key associated, the kernel should reject and return failure. Access to a page associated with a non-permissive key should fail regardless of who accesses the page (userspace, or kernel on userspace's behalf).

That is the reason we tap into the GUP routines to validate such access.

RP

author
#114 lore raw

PATCH 19/25 powerpc: implementation for arch_vma_access_permitted()

In reply to Ram Pai

This patch provides the implementation for arch_vma_access_permitted(). Returns true if the requested access is allowed by pkey associated with the vma.

---
 arch/powerpc/include/asm/mmu_context.h |    5 +++-
 arch/powerpc/mm/pkeys.c                |   43 ++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 1 deletions(-)
arch/powerpc/include/asm/mmu_context.h +4 -1
index 04e9221..9a56355 100644
@@ -135,6 +135,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)
 {
@@ -142,7 +146,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)
 
arch/powerpc/mm/pkeys.c +43 -0

46 lines not on this page · raw message

Signature · 1 line
1.7.1
#115 lore raw

Re: [PATCH 19/25] powerpc: implementation for arch_vma_access_permitted()

Quoted 75 lines · On Fri, 8 Sep 2017 15:45:07 -0700 Ram Pai <[email protected]> wrote:

This patch provides the implementation for arch_vma_access_permitted(). Returns true if the requested access is allowed by pkey associated with the vma.

---
 arch/powerpc/include/asm/mmu_context.h |    5 +++-
 arch/powerpc/mm/pkeys.c                |   43 ++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 1 deletions(-)
arch/powerpc/include/asm/mmu_context.h +4 -1
index 04e9221..9a56355 100644
@@ -135,6 +135,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)
 {
@@ -142,7 +146,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)
 
arch/powerpc/mm/pkeys.c +33 -0
index 24589d9..21c3b42 100644
@@ -320,3 +320,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 */

arch/powerpc/mm/pkeys.c bool arch_pte_access_permitted(u64 pte, bool write, bool execute) · line 365

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+	if (foreign || vma_is_foreign(vma))
+		return true;
+
+	pkey = vma_pkey(vma);
+
+	if (!pkey)
+		return true;
+
+	return pkey_access_permitted(pkey, write, execute);
+}

Again, I think this is GUP, I don't really understand the top level use case of enforcing permissions for GUP in a thread context.

Balbir Singh.

#116 lore raw

Re: [PATCH 19/25] powerpc: implementation for arch_vma_access_permitted()

In reply to Ram Pai
Quoted 5 lines · Ram Pai
arch/powerpc/mm/pkeys.c +0 -0
index 24589d9..21c3b42 100644

arch/powerpc/mm/pkeys.c bool arch_pte_access_permitted(u64 pte, bool write, bool execute) · line 328

Quoted 9 lines
arch/powerpc/mm/pkeys.c +6 -0
@@ -320,3 +320,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.

This comment doesn't match the code, or at least is confusing to me.

A "threaded process" is two tasks that have the same mm. ie. where current->mm == vma->mm.

And in that case we *do* enforce protection, based on the AMR/IAMR of the current thread.

arch/powerpc/mm/pkeys.c bool arch_pte_access_permitted(u64 pte, bool write, bool execute) · line 342

Quoted 13 lines
arch/powerpc/mm/pkeys.c +13 -0
+ * 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;

ie. threaded processes end up here, because they *do* share an mm.

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+
+	return false;
+}
+
+bool arch_vma_access_permitted(struct vm_area_struct *vma,
+		bool write, bool execute, bool foreign)
+{
+	int pkey;
+
+	if (!pkey_inited)

arch/powerpc/mm/pkeys.c bool arch_pte_access_permitted(u64 pte, bool write, bool execute) · line 362

Quoted 10 lines
arch/powerpc/mm/pkeys.c +10 -0
+		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;

I think I'd prefer if we didn't special case key 0, instead just let it go through to pkey_access_permitted().

arch/powerpc/mm/pkeys.c bool arch_pte_access_permitted(u64 pte, bool write, bool execute) · line 365

Quoted 3 lines
arch/powerpc/mm/pkeys.c +3 -0
+
+	return pkey_access_permitted(pkey, write, execute);
+}

cheers

author
#117 lore raw

PATCH 20/25 powerpc: Handle exceptions caused by pkey violation

In reply to Ram Pai

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.

---
 arch/powerpc/mm/fault.c |   37 ++++++++++++++++++++++++++++++++-----
 1 files changed, 32 insertions(+), 5 deletions(-)
arch/powerpc/mm/fault.c +32 -5
index 4797d08..a16bc43 100644
@@ -145,6 +145,23 @@ static noinline int bad_area(struct pt_regs *regs, unsigned long address)
 	return __bad_area(regs, address, SEGV_MAPERR);
 }
 
+static int bad_page_fault_exception(struct pt_regs *regs, unsigned long address,
+					int si_code)
+{
+	int sig = SIGBUS;
+	int code = BUS_OBJERR;
+
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	if (si_code & DSISR_KEYFAULT) {
+		sig = SIGSEGV;
+		code = SEGV_PKUERR;
+	}
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
+	_exception(sig, regs, code, address);
+	return 0;
+}
+
 static int do_sigbus(struct pt_regs *regs, unsigned long address,
 		     unsigned int fault)
 {
@@ -391,11 +408,9 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
 		return 0;
 
 	if (unlikely(page_fault_is_bad(error_code))) {
-		if (is_user) {
-			_exception(SIGBUS, regs, BUS_OBJERR, address);
-			return 0;
-		}
-		return SIGBUS;
+		if (!is_user)
+			return SIGBUS;
+		return bad_page_fault_exception(regs, address, error_code);
 	}
 
 	/* Additional sanity check(s) */
@@ -492,6 +507,18 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
 	if (unlikely(access_error(is_write, is_exec, vma)))
 		return bad_area(regs, address);
 
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
+			is_exec, 0))
+		return __bad_area(regs, address, SEGV_PKUERR);
+#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
Signature · 1 line
1.7.1
#118 lore raw

Re: [PATCH 20/25] powerpc: Handle exceptions caused by pkey violation

Quoted 9 lines · On Fri, 8 Sep 2017 15:45:08 -0700 Ram Pai <[email protected]> wrote:

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.

This bit is not clear.

Quoted 50 lines
---
 arch/powerpc/mm/fault.c |   37 ++++++++++++++++++++++++++++++++-----
 1 files changed, 32 insertions(+), 5 deletions(-)
arch/powerpc/mm/fault.c +20 -5
index 4797d08..a16bc43 100644
@@ -145,6 +145,23 @@ static noinline int bad_area(struct pt_regs *regs, unsigned long address)
 	return __bad_area(regs, address, SEGV_MAPERR);
 }
 
+static int bad_page_fault_exception(struct pt_regs *regs, unsigned long address,
+					int si_code)
+{
+	int sig = SIGBUS;
+	int code = BUS_OBJERR;
+
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	if (si_code & DSISR_KEYFAULT) {
+		sig = SIGSEGV;
+		code = SEGV_PKUERR;
+	}
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
+	_exception(sig, regs, code, address);
+	return 0;
+}
+
 static int do_sigbus(struct pt_regs *regs, unsigned long address,
 		     unsigned int fault)
 {
@@ -391,11 +408,9 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
 		return 0;
 
 	if (unlikely(page_fault_is_bad(error_code))) {
-		if (is_user) {
-			_exception(SIGBUS, regs, BUS_OBJERR, address);
-			return 0;
-		}
-		return SIGBUS;
+		if (!is_user)
+			return SIGBUS;
+		return bad_page_fault_exception(regs, address, error_code);
 	}
 
 	/* Additional sanity check(s) */

arch/powerpc/mm/fault.c static int __do_page_fault(struct pt_regs *regs, unsigned long address, · line 513

Quoted 7 lines
arch/powerpc/mm/fault.c +4 -0
@@ -492,6 +507,18 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
 	if (unlikely(access_error(is_write, is_exec, vma)))
 		return bad_area(regs, address);
 
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
+			is_exec, 0))
+		return __bad_area(regs, address, SEGV_PKUERR);

Hmm.. this is for the missing entry in the HPT and software detecting the fault you mentioned above? Why do we need this case?

arch/powerpc/mm/fault.c static int __do_page_fault(struct pt_regs *regs, unsigned long address, · line 519

Quoted 6 lines
arch/powerpc/mm/fault.c +6 -0
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
+
+	/* handle_mm_fault() needs to know if its a instruction access
+	 * fault.
+	 */

comment style

arch/powerpc/mm/fault.c static int __do_page_fault(struct pt_regs *regs, unsigned long address, · line 524

Quoted 5 lines
arch/powerpc/mm/fault.c +2 -0
+	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

Balbir Singh.

author
#119 lore raw

Re: [PATCH 20/25] powerpc: Handle exceptions caused by pkey violation

Quoted 69 lines · Balbir Singh
Quoted 9 lines · On Fri, 8 Sep 2017 15:45:08 -0700 Ram Pai <[email protected]> wrote:

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.

This bit is not clear.

Quoted 53 lines
---
 arch/powerpc/mm/fault.c |   37 ++++++++++++++++++++++++++++++++-----
 1 files changed, 32 insertions(+), 5 deletions(-)
arch/powerpc/mm/fault.c +20 -5
index 4797d08..a16bc43 100644
@@ -145,6 +145,23 @@ static noinline int bad_area(struct pt_regs *regs, unsigned long address)
 	return __bad_area(regs, address, SEGV_MAPERR);
 }
 
+static int bad_page_fault_exception(struct pt_regs *regs, unsigned long address,
+					int si_code)
+{
+	int sig = SIGBUS;
+	int code = BUS_OBJERR;
+
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	if (si_code & DSISR_KEYFAULT) {
+		sig = SIGSEGV;
+		code = SEGV_PKUERR;
+	}
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
+	_exception(sig, regs, code, address);
+	return 0;
+}
+
 static int do_sigbus(struct pt_regs *regs, unsigned long address,
 		     unsigned int fault)
 {
@@ -391,11 +408,9 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
 		return 0;
 
 	if (unlikely(page_fault_is_bad(error_code))) {
-		if (is_user) {
-			_exception(SIGBUS, regs, BUS_OBJERR, address);
-			return 0;
-		}
-		return SIGBUS;
+		if (!is_user)
+			return SIGBUS;
+		return bad_page_fault_exception(regs, address, error_code);
 	}
 
 	/* Additional sanity check(s) */
@@ -492,6 +507,18 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
 	if (unlikely(access_error(is_write, is_exec, vma)))
 		return bad_area(regs, address);
 
Quoted 8 lines

arch/powerpc/mm/fault.c static int __do_page_fault(struct pt_regs *regs, unsigned long address, · line 513

Quoted 4 lines
arch/powerpc/mm/fault.c +4 -0
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
+			is_exec, 0))
+		return __bad_area(regs, address, SEGV_PKUERR);

Hmm.. this is for the missing entry in the HPT and software detecting the fault you mentioned above? Why do we need this case?

I thought I had put in a comment motivating the reason. Seems to have disappeared. Will add it back. But here is the reason....

hardware enforces key-exception only after the key is programmed into the HPTE. However there is a window where the key is programmed into the PTE and waiting for a page fault so that it can propagate key to the HPTE. It is that window, during which we have to guard for key violation. The above check closes that small window of vulnerability.

RP

#120 lore raw

Re: [PATCH 20/25] powerpc: Handle exceptions caused by pkey violation

In reply to Ram Pai
Quoted 9 lines · Ram Pai

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.

That seems like the wrong trade off to me.

It means every fault has to go through arch_vma_access_permitted(), which is at least a function call in the best case, even when pkeys are not in use, and/or the range in question is not protected by a key.

Why not instead just service the fault and let the hardware catch it?

If that access to a protected page is a bug then the process will probably just exit, in which case who cares about the overhead of the extra fault.

If the access is not currently allowed, but the process wants to take the signal and do something to allow it, then is the overhead of the extra fault going to matter vs the signal etc?

I think we should just let the hardware take a 2nd fault, unless someone can demonstrate a workload where the cost of that is prohibitive.

Or does that not work for some reason?

Quoted 6 lines
arch/powerpc/mm/fault.c +0 -0
index 4797d08..a16bc43 100644
@@ -391,11 +408,9 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
 		return 0;

arch/powerpc/mm/fault.c static int __do_page_fault(struct pt_regs *regs, unsigned long address, · line 413

Quoted 10 lines
arch/powerpc/mm/fault.c +3 -5
 
 	if (unlikely(page_fault_is_bad(error_code))) {
-		if (is_user) {
-			_exception(SIGBUS, regs, BUS_OBJERR, address);
-			return 0;
-		}
-		return SIGBUS;
+		if (!is_user)
+			return SIGBUS;
+		return bad_page_fault_exception(regs, address, error_code);

I don't see why we want to handle the key fault here.

I know it's caught here at the moment, because it's in DSISR_BAD_FAULT_64S, but I think now that we support keys we should remove DSISR_KEYFAULT from DSISR_BAD_FAULT_64S.

Then we should let it fall through to further down, and handle it in access_error().

That way eg. the page fault accounting will work as normal etc.

Quoted 6 lines
arch/powerpc/mm/fault.c +2 -0
@@ -492,6 +507,18 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
 	if (unlikely(access_error(is_write, is_exec, vma)))
 		return bad_area(regs, address);
 
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,

arch/powerpc/mm/fault.c static int __do_page_fault(struct pt_regs *regs, unsigned long address, · line 521

Quoted 10 lines
arch/powerpc/mm/fault.c +10 -0
+			is_exec, 0))
+		return __bad_area(regs, address, SEGV_PKUERR);
+#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;

What is this doing here? We already do that further up.

cheers

author
#121 lore raw

Re: [PATCH 20/25] powerpc: Handle exceptions caused by pkey violation

Quoted 24 lines · Michael Ellerman
Quoted 9 lines · Ram Pai

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.

That seems like the wrong trade off to me.

It means every fault has to go through arch_vma_access_permitted(), which is at least a function call in the best case, even when pkeys are not in use, and/or the range in question is not protected by a key.

Why not instead just service the fault and let the hardware catch it?

If that access to a protected page is a bug then the process will probably just exit, in which case who cares about the overhead of the extra fault.

Quoted 8 lines

If the access is not currently allowed, but the process wants to take the signal and do something to allow it, then is the overhead of the extra fault going to matter vs the signal etc?

I think we should just let the hardware take a 2nd fault, unless someone can demonstrate a workload where the cost of that is prohibitive.

Or does that not work for some reason?

It does not work, because the arch-neutral code error-outs the fault without letting the power-specific code to page-in the faulting page.

So neither does the page gets faulted, nor does the key-fault gets signalled.

Quoted 20 lines
Quoted 7 lines
arch/powerpc/mm/fault.c +0 -0
index 4797d08..a16bc43 100644
@@ -391,11 +408,9 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
 		return 0;

arch/powerpc/mm/fault.c static int __do_page_fault(struct pt_regs *regs, unsigned long address, · line 413

Quoted 10 lines
arch/powerpc/mm/fault.c +3 -5
 
 	if (unlikely(page_fault_is_bad(error_code))) {
-		if (is_user) {
-			_exception(SIGBUS, regs, BUS_OBJERR, address);
-			return 0;
-		}
-		return SIGBUS;
+		if (!is_user)
+			return SIGBUS;
+		return bad_page_fault_exception(regs, address, error_code);

I don't see why we want to handle the key fault here.

Quoted 8 lines

I know it's caught here at the moment, because it's in DSISR_BAD_FAULT_64S, but I think now that we support keys we should remove DSISR_KEYFAULT from DSISR_BAD_FAULT_64S.

Then we should let it fall through to further down, and handle it in access_error().

That way eg. the page fault accounting will work as normal etc.

Bit tricky to do that. Will try. For one if I take out DSISR_KEYFAULT from DSISR_BAD_FAULT_64S, than the assembly code in do_hash_page() will not call __do_page_fault(). We want it called, but somehow special-handle DSISR_KEYFAULT to call access_error().

Quoted 5 lines
Quoted 5 lines
arch/powerpc/mm/fault.c +0 -0
@@ -492,6 +507,18 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
 	if (unlikely(access_error(is_write, is_exec, vma)))
 		return bad_area(regs, address);
 
Quoted 14 lines

arch/powerpc/mm/fault.c static int __do_page_fault(struct pt_regs *regs, unsigned long address, · line 521

Quoted 12 lines
arch/powerpc/mm/fault.c +12 -0
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
+			is_exec, 0))
+		return __bad_area(regs, address, SEGV_PKUERR);
+#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;

What is this doing here? We already do that further up.

The more I think of this, I find that the code can be optimized and remove redundancy. I am unnecessarily called arch_vma_access_permitted() above, when all the hardwork anyway gets done by handle_mm_fault(). handle_mm_fault() anyway calls arch_vma_access_permitted().

I could rather use the return value of handle_mm_fault() to signal a key-error to the userspace.

RP

#122 lore raw

Re: [PATCH 20/25] powerpc: Handle exceptions caused by pkey violation

In reply to Michael Ellerman
Quoted 12 lines · Michael Ellerman
Quoted 9 lines · Ram Pai

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.

Quoted 5 lines

That seems like the wrong trade off to me.

It means every fault has to go through arch_vma_access_permitted(), which is at least a function call in the best case, even when pkeys are not in use, and/or the range in question is not protected by a key.

We don't really need to call arch_vma_access_permitted() in arch/powerpc/ do_page_fault(). Core kernel does that in handle_mm_fault(). So if the first fault is a bad access handle_mm_fault handle this. If it is a valid access we insert the right hash page table entry and then we do a wrong access, we detect that a key fault in the low level hash fault handler. IIUC, the call the arch_vma_access_permitted() from arch/powerpc/ can go away?

-aneesh

author
#123 lore raw

Re: [PATCH 20/25] powerpc: Handle exceptions caused by pkey violation

Quoted 20 lines · Aneesh Kumar K.V
Quoted 12 lines · Michael Ellerman
Quoted 9 lines · Ram Pai

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.

Quoted 5 lines

That seems like the wrong trade off to me.

It means every fault has to go through arch_vma_access_permitted(), which is at least a function call in the best case, even when pkeys are not in use, and/or the range in question is not protected by a key.

Quoted 7 lines

We don't really need to call arch_vma_access_permitted() in arch/powerpc/ do_page_fault(). Core kernel does that in handle_mm_fault(). So if the first fault is a bad access handle_mm_fault handle this. If it is a valid access we insert the right hash page table entry and then we do a wrong access, we detect that a key fault in the low level hash fault handler. IIUC, the call the arch_vma_access_permitted() from arch/powerpc/ can go away?

Yes. since handle_mm_fault() checks for key-violation, we can leverage that in __do_page_fault(), instead of calling arch_vma_access_permitted().

Have fixed it in the next version of patches, about to to hit the mailing list this week.

RP

author
#124 lore raw

PATCH 21/25 powerpc: introduce get_pte_pkey() helper

In reply to Ram Pai

get_pte_pkey() helper returns the pkey associated with a address corresponding to a given mm_struct.

---
 arch/powerpc/include/asm/book3s/64/mmu-hash.h |    5 +++++
 arch/powerpc/mm/hash_utils_64.c               |   24 ++++++++++++++++++++++++
 2 files changed, 29 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/book3s/64/mmu-hash.h +5 -0
index 2e22357..8716031 100644
@@ -451,6 +451,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,
arch/powerpc/mm/hash_utils_64.c +24 -0
index a739a2d..5917d45 100644
@@ -1572,6 +1572,30 @@ 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(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)
 {
Signature · 1 line
1.7.1
#125 lore raw

Re: [PATCH 21/25] powerpc: introduce get_pte_pkey() helper

Quoted 3 lines · On Fri, 8 Sep 2017 15:45:09 -0700 Ram Pai <[email protected]> wrote:

get_pte_pkey() helper returns the pkey associated with a address corresponding to a given mm_struct.

This is really get_mm_addr_key() -- no?

Balbir Singh.

author
#126 lore raw

Re: [PATCH 21/25] powerpc: introduce get_pte_pkey() helper

Quoted 8 lines · Balbir Singh
Quoted 3 lines · On Fri, 8 Sep 2017 15:45:09 -0700 Ram Pai <[email protected]> wrote:

get_pte_pkey() helper returns the pkey associated with a address corresponding to a given mm_struct.

This is really get_mm_addr_key() -- no?

ok. will be so.

RP

author
#127 lore raw

PATCH 22/25 powerpc: capture the violated protection key on fault

In reply to Ram Pai

Capture the protection key that got violated in paca. This value will be later used to inform the signal handler.

---
 arch/powerpc/include/asm/paca.h   |    3 +++
 arch/powerpc/kernel/asm-offsets.c |    5 +++++
 arch/powerpc/mm/fault.c           |   11 ++++++++++-
 3 files changed, 18 insertions(+), 1 deletions(-)
arch/powerpc/include/asm/paca.h +3 -0
index 04b60af..51c89c1 100644
@@ -97,6 +97,9 @@ struct paca_struct {
 	struct dtl_entry *dispatch_log_end;
 #endif /* CONFIG_PPC_STD_MMU_64 */
 	u64 dscr_default;		/* per-CPU default DSCR */
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	u16 paca_pkey;                  /* exception causing pkey */
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 
 #ifdef CONFIG_PPC_STD_MMU_64
 	/*
arch/powerpc/kernel/asm-offsets.c +5 -0
index 8cfb20e..361f0d4 100644
@@ -241,6 +241,11 @@ int main(void)
 	OFFSET(PACAHWCPUID, paca_struct, hw_cpu_id);
 	OFFSET(PACAKEXECSTATE, paca_struct, kexec_state);
 	OFFSET(PACA_DSCR_DEFAULT, paca_struct, dscr_default);
+
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	OFFSET(PACA_PKEY, paca_struct, paca_pkey);
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
 	OFFSET(ACCOUNT_STARTTIME, paca_struct, accounting.starttime);
 	OFFSET(ACCOUNT_STARTTIME_USER, paca_struct, accounting.starttime_user);
 	OFFSET(ACCOUNT_USER_TIME, paca_struct, accounting.utime);
arch/powerpc/mm/fault.c +10 -1
index a16bc43..ad31f6e 100644
@@ -153,6 +153,7 @@ static int bad_page_fault_exception(struct pt_regs *regs, unsigned long address,
 
 #ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
 	if (si_code & DSISR_KEYFAULT) {
+		get_paca()->paca_pkey = get_pte_pkey(current->mm, address);
 		sig = SIGSEGV;
 		code = SEGV_PKUERR;
 	}
@@ -509,8 +510,16 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
 
 #ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
 	if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
-			is_exec, 0))
+			is_exec, 0)) {
+		/*
+		 * The pgd-pdt...pmd-pte tree may not  have  been fully setup.
+		 * Hence we cannot walk the tree to locate the pte, to locate
+		 * the key. Hence lets use vma_pkey() to get the key; instead
+		 * of get_pte_pkey().
+		 */
+		get_paca()->paca_pkey = vma_pkey(vma);
 		return __bad_area(regs, address, SEGV_PKUERR);
+	}
 #endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 
 
Signature · 1 line
1.7.1
#128 lore raw

Re: [PATCH 22/25] powerpc: capture the violated protection key on fault

arch/powerpc/include/asm/paca.h struct paca_struct { · line 102

Quoted 11 lines · Ram Pai
arch/powerpc/include/asm/paca.h +3 -0
index 04b60af..51c89c1 100644
@@ -97,6 +97,9 @@ struct paca_struct {
 	struct dtl_entry *dispatch_log_end;
 #endif /* CONFIG_PPC_STD_MMU_64 */
 	u64 dscr_default;		/* per-CPU default DSCR */
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	u16 paca_pkey;                  /* exception causing pkey */
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */

I can't see any reason why this should be in the paca.

arch/powerpc/mm/fault.c static int bad_page_fault_exception(struct pt_regs *regs, unsigned long address, · line 156

Quoted 9 lines
arch/powerpc/mm/fault.c +1 -0
index a16bc43..ad31f6e 100644
@@ -153,6 +153,7 @@ static int bad_page_fault_exception(struct pt_regs *regs, unsigned long address,
 
 #ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
 	if (si_code & DSISR_KEYFAULT) {
+		get_paca()->paca_pkey = get_pte_pkey(current->mm, address);

You seem to be using the paca as a temporary stash so that you don't have to pass it to _exception().

But that's not what the paca is for, the paca is for per-cpu data not per-thread data, and (preferably) only for things that need to be accessed in low-level code where proper per_cpu() variables don't work.

Updating _exception() to take the key would be a mess, because there are so many callers who don't care about the key. For now we can probably just do something ~=:

void _exception_pkey(int signr, struct pt_regs *regs, int code, unsigned long addr, int key) {
< current body of _exception >

+ pkey bits
}

void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)

{
	_exception_pkey(..., 0);
}

cheers

author
#129 lore raw

PATCH 23/25 powerpc: Deliver SEGV signal on pkey violation

In reply to Ram Pai

The value of the pkey, whose protection got violated, is made available in si_pkey field of the siginfo structure.

Also keep the thread's pkey-register fields up2date.

---
 arch/powerpc/kernel/traps.c |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)
arch/powerpc/kernel/traps.c +22 -0
index ec74e20..f2a310d 100644
@@ -20,6 +20,7 @@
 #include <linux/sched/debug.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/pkeys.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
@@ -265,6 +266,15 @@ void user_single_step_siginfo(struct task_struct *tsk,
 	info->si_addr = (void __user *)regs->nip;
 }
 
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+static void fill_sig_info_pkey(int si_code, siginfo_t *info, unsigned long addr)
+{
+	if (info->si_signo != SIGSEGV || si_code != SEGV_PKUERR)
+		return;
+	info->si_pkey = get_paca()->paca_pkey;
+}
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
 void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
 {
 	siginfo_t info;
@@ -292,6 +302,18 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
 	info.si_signo = signr;
 	info.si_code = code;
 	info.si_addr = (void __user *) addr;
+
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	/*
+	 * update the thread's pkey related fields.
+	 * core-dump handlers and other sub-systems
+	 * depend on those values.
+	 */
+	thread_pkey_regs_save(&current->thread);
+	/* update the violated-key value */
+	fill_sig_info_pkey(code, &info, addr);
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
+
 	force_sig_info(signr, &info, current);
 }
 
Signature · 1 line
1.7.1
#130 lore raw

Re: [PATCH 23/25] powerpc: Deliver SEGV signal on pkey violation

arch/powerpc/kernel/traps.c void user_single_step_siginfo(struct task_struct *tsk, · line 272

Quoted 12 lines · Ram Pai
arch/powerpc/kernel/traps.c +4 -0
index ec74e20..f2a310d 100644
@@ -265,6 +266,15 @@ void user_single_step_siginfo(struct task_struct *tsk,
 	info->si_addr = (void __user *)regs->nip;
 }
 
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+static void fill_sig_info_pkey(int si_code, siginfo_t *info, unsigned long addr)
+{
+	if (info->si_signo != SIGSEGV || si_code != SEGV_PKUERR)

Just checking si_code is sufficient there I think.

arch/powerpc/kernel/traps.c void user_single_step_siginfo(struct task_struct *tsk, · line 276

Quoted 4 lines
arch/powerpc/kernel/traps.c +4 -0
+		return;
+	info->si_pkey = get_paca()->paca_pkey;
+}
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */

This should define an empty version in the #else case, so we don't need the ifdef below.

arch/powerpc/kernel/traps.c void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) · line 312

Quoted 12 lines
arch/powerpc/kernel/traps.c +8 -0
@@ -292,6 +302,18 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
 	info.si_signo = signr;
 	info.si_code = code;
 	info.si_addr = (void __user *) addr;
+
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	/*
+	 * update the thread's pkey related fields.
+	 * core-dump handlers and other sub-systems
+	 * depend on those values.
+	 */
+	thread_pkey_regs_save(&current->thread);

You shouldn't need to do this.

We're not putting any of the pkey regs in the signal frame, so you don't need to save before we do that. [And if you did the right place to do it would be in setup_sigcontext() (or the TM version).]

For ptrace and coredumps it should happen in pkey_get(), see eg. fpr_get() which does flush_fp_to_thread() as an example.

arch/powerpc/kernel/traps.c void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) · line 318

Quoted 7 lines
arch/powerpc/kernel/traps.c +4 -0
+	/* update the violated-key value */
+	fill_sig_info_pkey(code, &info, addr);
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 
+
 	force_sig_info(signr, &info, current);
 }

cheers

author
#131 lore raw

Re: [PATCH 23/25] powerpc: Deliver SEGV signal on pkey violation

Quoted 40 lines · Michael Ellerman

arch/powerpc/kernel/traps.c void user_single_step_siginfo(struct task_struct *tsk, · line 272

Quoted 12 lines · Ram Pai
arch/powerpc/kernel/traps.c +4 -0
index ec74e20..f2a310d 100644
@@ -265,6 +266,15 @@ void user_single_step_siginfo(struct task_struct *tsk,
 	info->si_addr = (void __user *)regs->nip;
 }
 
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+static void fill_sig_info_pkey(int si_code, siginfo_t *info, unsigned long addr)
+{
+	if (info->si_signo != SIGSEGV || si_code != SEGV_PKUERR)

Just checking si_code is sufficient there I think.

arch/powerpc/kernel/traps.c void user_single_step_siginfo(struct task_struct *tsk, · line 276

Quoted 4 lines
arch/powerpc/kernel/traps.c +4 -0
+		return;
+	info->si_pkey = get_paca()->paca_pkey;
+}
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */

This should define an empty version in the #else case, so we don't need the ifdef below.

arch/powerpc/kernel/traps.c void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) · line 312

Quoted 12 lines
arch/powerpc/kernel/traps.c +8 -0
@@ -292,6 +302,18 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
 	info.si_signo = signr;
 	info.si_code = code;
 	info.si_addr = (void __user *) addr;
+
+#ifdef CONFIG_PPC64_MEMORY_PROTECTION_KEYS
+	/*
+	 * update the thread's pkey related fields.
+	 * core-dump handlers and other sub-systems
+	 * depend on those values.
+	 */
+	thread_pkey_regs_save(&current->thread);

You shouldn't need to do this.

Quoted 3 lines

We're not putting any of the pkey regs in the signal frame, so you don't need to save before we do that. [And if you did the right place to do it would be in setup_sigcontext() (or the TM version).]

One of the comments in the past was the ability to capture AMR register status in core-dumps and also the ability to modify the AMR through ptrace. Thiago wrote a patch towards that. That patch is one of the subsequent patches sent in this series.

I will move the code to pkey_get().

Quoted 3 lines

For ptrace and coredumps it should happen in pkey_get(), see eg. fpr_get() which does flush_fp_to_thread() as an example.

Ok.

Quoted 10 lines

arch/powerpc/kernel/traps.c void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) · line 318

Quoted 8 lines
arch/powerpc/kernel/traps.c +4 -0
+	/* update the violated-key value */
+	fill_sig_info_pkey(code, &info, addr);
+#endif /* CONFIG_PPC64_MEMORY_PROTECTION_KEYS */
 
+
 	force_sig_info(signr, &info, current);
 }

cheers

Signature · 1 line
Ram Pai
author
#132 lore raw

PATCH 24/25 powerpc/ptrace: Add memory protection key regset

In reply to Ram Pai

From: Thiago Jung Bauermann <[email protected]>

The AMR/IAMR/UAMOR are part of the program context. Allow it to be accessed via ptrace and through core files.

---
 arch/powerpc/include/asm/pkeys.h    |    5 +++
 arch/powerpc/include/uapi/asm/elf.h |    1 +
 arch/powerpc/kernel/ptrace.c        |   66 +++++++++++++++++++++++++++++++++++
 include/uapi/linux/elf.h            |    1 +
 4 files changed, 73 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/pkeys.h +5 -0
index 50522a0..a0111de 100644
@@ -209,6 +209,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)
arch/powerpc/include/uapi/asm/elf.h +1 -0
index b2c6fdd..923e6d5 100644
@@ -96,6 +96,7 @@
 #define ELF_NTMSPRREG	3	/* include tfhar, tfiar, texasr */
 #define ELF_NEBB	3	/* includes ebbrr, ebbhr, bescr */
 #define ELF_NPMU	5	/* includes siar, sdar, sier, mmcr2, mmcr0 */
+#define ELF_NPKEY	3	/* includes amr, iamr, uamor */
 
 typedef unsigned long elf_greg_t64;
 typedef elf_greg_t64 elf_gregset_t64[ELF_NGREG];
arch/powerpc/kernel/ptrace.c +66 -0

90 lines not on this page · raw message

include/uapi/linux/elf.h +1 -0
index b5280db..0708516 100644
@@ -395,6 +395,7 @@
 #define NT_PPC_TM_CTAR	0x10d		/* TM checkpointed Target Address Register */
 #define NT_PPC_TM_CPPR	0x10e		/* TM checkpointed Program Priority Register */
 #define NT_PPC_TM_CDSCR	0x10f		/* TM checkpointed Data Stream Control Register */
+#define NT_PPC_PKEY	0x110		/* Memory Protection Keys registers */
 #define NT_386_TLS	0x200		/* i386 TLS slots (struct user_desc) */
 #define NT_386_IOPERM	0x201		/* x86 io permission bitmap (1=deny) */
 #define NT_X86_XSTATE	0x202		/* x86 extended state using xsave */
Signature · 1 line
1.7.1
author
#133 lore raw

PATCH 25/25 powerpc: Enable pkey subsystem

In reply to Ram Pai

PAPR defines 'ibm,processor-storage-keys' property. It exports two values.The first value indicates the number of data-access keys and the second indicates the number of instruction-access keys. Though this hints that keys can be either data access or instruction access only,that is not the case in reality.Any key can be of any kind. This patch adds all the keys and uses that as the total number of keys available to us.

Non PAPR platforms do not define this property in the device
tree yet. Here, we hardcode CPUs that support pkey by
consulting PowerISA3.0

---
 arch/powerpc/include/asm/cputable.h    |   15 ++++++++++-----
 arch/powerpc/include/asm/mmu_context.h |    1 +
 arch/powerpc/include/asm/pkeys.h       |   21 +++++++++++++++++++++
 arch/powerpc/kernel/prom.c             |   19 +++++++++++++++++++
 arch/powerpc/mm/pkeys.c                |   19 ++++++++++++++-----
 5 files changed, 65 insertions(+), 10 deletions(-)
arch/powerpc/include/asm/cputable.h +10 -5
index a9bf921..31ed1d2 100644
@@ -214,7 +214,9 @@ enum {
 #define CPU_FTR_DAWR			LONG_ASM_CONST(0x0400000000000000)
 #define CPU_FTR_DABRX			LONG_ASM_CONST(0x0800000000000000)
 #define CPU_FTR_PMAO_BUG		LONG_ASM_CONST(0x1000000000000000)
+#define CPU_FTR_PKEY			LONG_ASM_CONST(0x2000000000000000)
 #define CPU_FTR_POWER9_DD1		LONG_ASM_CONST(0x4000000000000000)
+#define CPU_FTR_PKEY_EXECUTE		LONG_ASM_CONST(0x8000000000000000)
 
 #ifndef __ASSEMBLY__
 
@@ -435,7 +437,8 @@ enum {
 	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_MMCRA | CPU_FTR_SMT | \
 	    CPU_FTR_COHERENT_ICACHE | CPU_FTR_PURR | \
-	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_DABRX)
+	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_DABRX | \
+	    CPU_FTR_PKEY)
 #define CPU_FTRS_POWER6 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
 	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -443,7 +446,7 @@ enum {
 	    CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
 	    CPU_FTR_DSCR | CPU_FTR_UNALIGNED_LD_STD | \
 	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_CFAR | \
-	    CPU_FTR_DABRX)
+	    CPU_FTR_DABRX | CPU_FTR_PKEY)
 #define CPU_FTRS_POWER7 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
 	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | CPU_FTR_ARCH_206 |\
 	    CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -452,7 +455,7 @@ enum {
 	    CPU_FTR_DSCR | CPU_FTR_SAO  | CPU_FTR_ASYM_SMT | \
 	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
 	    CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | \
-	    CPU_FTR_VMX_COPY | CPU_FTR_HAS_PPR | CPU_FTR_DABRX)
+	    CPU_FTR_VMX_COPY | CPU_FTR_HAS_PPR | CPU_FTR_DABRX | CPU_FTR_PKEY)
 #define CPU_FTRS_POWER8 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
 	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | CPU_FTR_ARCH_206 |\
 	    CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -462,7 +465,8 @@ enum {
 	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
 	    CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \
 	    CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_DAWR | \
-	    CPU_FTR_ARCH_207S | CPU_FTR_TM_COMP)
+	    CPU_FTR_ARCH_207S | CPU_FTR_TM_COMP | CPU_FTR_PKEY |\
+	    CPU_FTR_PKEY_EXECUTE)
 #define CPU_FTRS_POWER8E (CPU_FTRS_POWER8 | CPU_FTR_PMAO_BUG)
 #define CPU_FTRS_POWER8_DD1 (CPU_FTRS_POWER8 & ~CPU_FTR_DBELL)
 #define CPU_FTRS_POWER9 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
@@ -474,7 +478,8 @@ enum {
 	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
 	    CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \
 	    CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_DAWR | \
-	    CPU_FTR_ARCH_207S | CPU_FTR_TM_COMP | CPU_FTR_ARCH_300)
+	    CPU_FTR_ARCH_207S | CPU_FTR_TM_COMP | CPU_FTR_ARCH_300 | \
+	    CPU_FTR_PKEY | CPU_FTR_PKEY_EXECUTE)
 #define CPU_FTRS_POWER9_DD1 ((CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD1) & \
 			     (~CPU_FTR_SAO))
 #define CPU_FTRS_CELL	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
arch/powerpc/include/asm/mmu_context.h +1 -0
index 9a56355..98ac713 100644
@@ -148,6 +148,7 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
 
 #define pkey_initialize()
 #define pkey_mm_init(mm)
+#define pkey_mmu_values(total_data, total_execute)
 
 static inline int vma_pkey(struct vm_area_struct *vma)
 {
arch/powerpc/include/asm/pkeys.h +21 -0
index a0111de..baac435 100644
@@ -1,9 +1,12 @@
 #ifndef _ASM_PPC64_PKEYS_H
 #define _ASM_PPC64_PKEYS_H
 
+#include <asm/firmware.h>
+
 extern bool pkey_inited;
 extern bool pkey_execute_disable_support;
 extern int pkeys_total; /* total pkeys as per device tree */
+extern int pkey_total_execute; /* total execute pkeys as per device tree */
 extern u32 initial_allocation_mask;/* bits set for reserved keys */
 
 /*
@@ -223,6 +226,24 @@ static inline void pkey_mm_init(struct mm_struct *mm)
 	mm->context.execute_only_pkey = -1;
 }
 
+static inline void pkey_mmu_values(int total_data, int total_execute)
+{
+	/*
+	 * since any pkey can be used for data or execute, we
+	 * will  just  treat all keys as equal and track them
+	 * as one entity.
+	 */
+	pkeys_total = total_data;
+}
+
+static inline bool pkey_mmu_enabled(void)
+{
+	if (firmware_has_feature(FW_FEATURE_LPAR))
+		return pkeys_total;
+	else
+		return cpu_has_feature(CPU_FTR_PKEY);
+}
+
 extern void thread_pkey_regs_save(struct thread_struct *thread);
 extern void thread_pkey_regs_restore(struct thread_struct *new_thread,
 			struct thread_struct *old_thread);
arch/powerpc/kernel/prom.c +19 -0
index f830562..f61da26 100644
@@ -35,6 +35,7 @@
 #include <linux/of_fdt.h>
 #include <linux/libfdt.h>
 #include <linux/cpu.h>
+#include <linux/pkeys.h>
 
 #include <asm/prom.h>
 #include <asm/rtas.h>
@@ -228,6 +229,23 @@ static void __init check_cpu_pa_features(unsigned long node)
 		      ibm_pa_features, ARRAY_SIZE(ibm_pa_features));
 }
 
+static void __init check_cpu_pkey_feature(unsigned long node)
+{
+	const __be32 *ftrs;
+	int len, total_data, total_execute;
+
+	ftrs = of_get_flat_dt_prop(node,
+		"ibm,processor-storage-keys", &len);
+	if (ftrs == NULL)
+		return;
+
+	len /= sizeof(int);
+	total_execute = (len >= 2) ? be32_to_cpu(ftrs[1]) : 0;
+	total_data = (len >= 1) ? be32_to_cpu(ftrs[0]) : 0;
+	pkey_mmu_values(total_data, total_execute);
+}
+
+
 #ifdef CONFIG_PPC_STD_MMU_64
 static void __init init_mmu_slb_size(unsigned long node)
 {
@@ -391,6 +409,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
 
 		check_cpu_feature_properties(node);
 		check_cpu_pa_features(node);
+		check_cpu_pkey_feature(node);
 	}
 
 	identical_pvr_fixup(node);
arch/powerpc/mm/pkeys.c +14 -5
index 21c3b42..c3ed473 100644
@@ -37,15 +37,24 @@ void __init pkey_initialize(void)
 	 * line will enable it.
 	 */
 	pkey_inited = false;
+	if (pkey_mmu_enabled())
+		pkey_inited = !radix_enabled();
+	if (!pkey_inited)
+		return;
 
 	/*
-	 * disable execute_disable support for now.
-	 * A patch further down will enable it.
+	 * the device tree cannot be relied on for 
+	 * execute_disable support. Hence we depend
+	 * on CPU FTR.
 	 */
-	pkey_execute_disable_support = false;
+	pkey_execute_disable_support = cpu_has_feature(CPU_FTR_PKEY_EXECUTE);
 
-	/* Lets assume 32 keys */
-	pkeys_total = 32;
+	/*
+	 * Lets assume 32 keys if we are not told
+	 * the number of pkeys.
+	 */
+	if (!pkeys_total)
+		pkeys_total = 32;
 
 #ifdef CONFIG_PPC_4K_PAGES
 	/*
Signature · 1 line
1.7.1