summaryrefslogtreecommitdiff
path: root/arch/powerpc/include/asm/book3s/64/kup-radix.h
diff options
context:
space:
mode:
authorChristophe Leroy <christophe.leroy@c-s.fr>2020-01-24 14:54:45 +0300
committerMichael Ellerman <mpe@ellerman.id.au>2020-01-28 15:14:44 +0300
commit3d7dfd632f9b60cfce069b4da517e6b1a1c3f613 (patch)
tree02ec1e93d286d7c49dce90a4294f8ddc1edb3af4 /arch/powerpc/include/asm/book3s/64/kup-radix.h
parent5cd623333e7cf4e3a334c70529268b65f2a6c2c7 (diff)
downloadlinux-3d7dfd632f9b60cfce069b4da517e6b1a1c3f613.tar.xz
powerpc: Implement user_access_save() and user_access_restore()
Implement user_access_save() and user_access_restore() On 8xx and radix: - On save, get the value of the associated special register then prevent user access. - On restore, set back the saved value to the associated special register. On book3s/32: - On save, get the value stored in current->thread.kuap and prevent user access. - On restore, regenerate address range from the stored value and reopen read/write access for that range. Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/54f2f74938006b33c55a416674807b42ef222068.1579866752.git.christophe.leroy@c-s.fr
Diffstat (limited to 'arch/powerpc/include/asm/book3s/64/kup-radix.h')
-rw-r--r--arch/powerpc/include/asm/book3s/64/kup-radix.h22
1 files changed, 22 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/book3s/64/kup-radix.h b/arch/powerpc/include/asm/book3s/64/kup-radix.h
index a0263e94df33..90dd3a3fc8c7 100644
--- a/arch/powerpc/include/asm/book3s/64/kup-radix.h
+++ b/arch/powerpc/include/asm/book3s/64/kup-radix.h
@@ -63,6 +63,14 @@
* because that would require an expensive read/modify write of the AMR.
*/
+static inline unsigned long get_kuap(void)
+{
+ if (!early_mmu_has_feature(MMU_FTR_RADIX_KUAP))
+ return 0;
+
+ return mfspr(SPRN_AMR);
+}
+
static inline void set_kuap(unsigned long value)
{
if (!early_mmu_has_feature(MMU_FTR_RADIX_KUAP))
@@ -98,6 +106,20 @@ static inline void prevent_user_access(void __user *to, const void __user *from,
set_kuap(AMR_KUAP_BLOCKED);
}
+static inline unsigned long prevent_user_access_return(void)
+{
+ unsigned long flags = get_kuap();
+
+ set_kuap(AMR_KUAP_BLOCKED);
+
+ return flags;
+}
+
+static inline void restore_user_access(unsigned long flags)
+{
+ set_kuap(flags);
+}
+
static inline bool
bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
{