2021-10-19 09:29:28 +02:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
|
|
|
#ifndef _ASM_POWERPC_KUP_BOOKE_H_
|
|
|
|
#define _ASM_POWERPC_KUP_BOOKE_H_
|
|
|
|
|
|
|
|
#include <asm/bug.h>
|
2023-07-11 17:59:21 +02:00
|
|
|
#include <asm/mmu.h>
|
2021-10-19 09:29:28 +02:00
|
|
|
|
|
|
|
#ifdef CONFIG_PPC_KUAP
|
|
|
|
|
|
|
|
#ifdef __ASSEMBLY__
|
|
|
|
|
|
|
|
.macro kuap_check_amr gpr1, gpr2
|
|
|
|
.endm
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
#include <linux/sched.h>
|
|
|
|
|
|
|
|
#include <asm/reg.h>
|
|
|
|
|
2023-07-11 17:59:20 +02:00
|
|
|
static __always_inline void __kuap_lock(void)
|
2021-10-19 09:29:28 +02:00
|
|
|
{
|
|
|
|
mtspr(SPRN_PID, 0);
|
|
|
|
isync();
|
|
|
|
}
|
powerpc/kuap: Avoid useless jump_label on empty function
Disassembly of interrupt_enter_prepare() shows a pointless nop
before the mftb
c000abf0 <interrupt_enter_prepare>:
c000abf0: 81 23 00 84 lwz r9,132(r3)
c000abf4: 71 29 40 00 andi. r9,r9,16384
c000abf8: 41 82 00 28 beq- c000ac20 <interrupt_enter_prepare+0x30>
c000abfc: ===> 60 00 00 00 nop <====
c000ac00: 7d 0c 42 e6 mftb r8
c000ac04: 80 e2 00 08 lwz r7,8(r2)
c000ac08: 81 22 00 28 lwz r9,40(r2)
c000ac0c: 91 02 00 24 stw r8,36(r2)
c000ac10: 7d 29 38 50 subf r9,r9,r7
c000ac14: 7d 29 42 14 add r9,r9,r8
c000ac18: 91 22 00 08 stw r9,8(r2)
c000ac1c: 4e 80 00 20 blr
c000ac20: 60 00 00 00 nop
c000ac24: 7d 5a c2 a6 mfmd_ap r10
c000ac28: 3d 20 de 00 lis r9,-8704
c000ac2c: 91 43 00 b0 stw r10,176(r3)
c000ac30: 7d 3a c3 a6 mtspr 794,r9
c000ac34: 4e 80 00 20 blr
That comes from the call to kuap_loc(), allthough __kuap_lock() is an
empty function on the 8xx.
To avoid that, only perform kuap_is_disabled() check when there is
something to do with __kuap_lock().
Do the same with __kuap_save_and_lock() and
__kuap_get_and_assert_locked().
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/a854d25bea375d4ba6ca9c2617f9edbba397100a.1689091022.git.christophe.leroy@csgroup.eu
2023-07-11 17:59:14 +02:00
|
|
|
#define __kuap_lock __kuap_lock
|
2021-10-19 09:29:28 +02:00
|
|
|
|
2023-07-11 17:59:20 +02:00
|
|
|
static __always_inline void __kuap_save_and_lock(struct pt_regs *regs)
|
2021-10-19 09:29:28 +02:00
|
|
|
{
|
|
|
|
regs->kuap = mfspr(SPRN_PID);
|
|
|
|
mtspr(SPRN_PID, 0);
|
|
|
|
isync();
|
|
|
|
}
|
powerpc/kuap: Avoid useless jump_label on empty function
Disassembly of interrupt_enter_prepare() shows a pointless nop
before the mftb
c000abf0 <interrupt_enter_prepare>:
c000abf0: 81 23 00 84 lwz r9,132(r3)
c000abf4: 71 29 40 00 andi. r9,r9,16384
c000abf8: 41 82 00 28 beq- c000ac20 <interrupt_enter_prepare+0x30>
c000abfc: ===> 60 00 00 00 nop <====
c000ac00: 7d 0c 42 e6 mftb r8
c000ac04: 80 e2 00 08 lwz r7,8(r2)
c000ac08: 81 22 00 28 lwz r9,40(r2)
c000ac0c: 91 02 00 24 stw r8,36(r2)
c000ac10: 7d 29 38 50 subf r9,r9,r7
c000ac14: 7d 29 42 14 add r9,r9,r8
c000ac18: 91 22 00 08 stw r9,8(r2)
c000ac1c: 4e 80 00 20 blr
c000ac20: 60 00 00 00 nop
c000ac24: 7d 5a c2 a6 mfmd_ap r10
c000ac28: 3d 20 de 00 lis r9,-8704
c000ac2c: 91 43 00 b0 stw r10,176(r3)
c000ac30: 7d 3a c3 a6 mtspr 794,r9
c000ac34: 4e 80 00 20 blr
That comes from the call to kuap_loc(), allthough __kuap_lock() is an
empty function on the 8xx.
To avoid that, only perform kuap_is_disabled() check when there is
something to do with __kuap_lock().
Do the same with __kuap_save_and_lock() and
__kuap_get_and_assert_locked().
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/a854d25bea375d4ba6ca9c2617f9edbba397100a.1689091022.git.christophe.leroy@csgroup.eu
2023-07-11 17:59:14 +02:00
|
|
|
#define __kuap_save_and_lock __kuap_save_and_lock
|
2021-10-19 09:29:28 +02:00
|
|
|
|
2023-07-11 17:59:20 +02:00
|
|
|
static __always_inline void kuap_user_restore(struct pt_regs *regs)
|
2021-10-19 09:29:28 +02:00
|
|
|
{
|
|
|
|
if (kuap_is_disabled())
|
|
|
|
return;
|
|
|
|
|
|
|
|
mtspr(SPRN_PID, current->thread.pid);
|
|
|
|
|
|
|
|
/* Context synchronisation is performed by rfi */
|
|
|
|
}
|
|
|
|
|
2023-07-11 17:59:20 +02:00
|
|
|
static __always_inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
|
2021-10-19 09:29:28 +02:00
|
|
|
{
|
|
|
|
if (regs->kuap)
|
|
|
|
mtspr(SPRN_PID, current->thread.pid);
|
|
|
|
|
|
|
|
/* Context synchronisation is performed by rfi */
|
|
|
|
}
|
|
|
|
|
powerpc/kuap: Avoid useless jump_label on empty function
Disassembly of interrupt_enter_prepare() shows a pointless nop
before the mftb
c000abf0 <interrupt_enter_prepare>:
c000abf0: 81 23 00 84 lwz r9,132(r3)
c000abf4: 71 29 40 00 andi. r9,r9,16384
c000abf8: 41 82 00 28 beq- c000ac20 <interrupt_enter_prepare+0x30>
c000abfc: ===> 60 00 00 00 nop <====
c000ac00: 7d 0c 42 e6 mftb r8
c000ac04: 80 e2 00 08 lwz r7,8(r2)
c000ac08: 81 22 00 28 lwz r9,40(r2)
c000ac0c: 91 02 00 24 stw r8,36(r2)
c000ac10: 7d 29 38 50 subf r9,r9,r7
c000ac14: 7d 29 42 14 add r9,r9,r8
c000ac18: 91 22 00 08 stw r9,8(r2)
c000ac1c: 4e 80 00 20 blr
c000ac20: 60 00 00 00 nop
c000ac24: 7d 5a c2 a6 mfmd_ap r10
c000ac28: 3d 20 de 00 lis r9,-8704
c000ac2c: 91 43 00 b0 stw r10,176(r3)
c000ac30: 7d 3a c3 a6 mtspr 794,r9
c000ac34: 4e 80 00 20 blr
That comes from the call to kuap_loc(), allthough __kuap_lock() is an
empty function on the 8xx.
To avoid that, only perform kuap_is_disabled() check when there is
something to do with __kuap_lock().
Do the same with __kuap_save_and_lock() and
__kuap_get_and_assert_locked().
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/a854d25bea375d4ba6ca9c2617f9edbba397100a.1689091022.git.christophe.leroy@csgroup.eu
2023-07-11 17:59:14 +02:00
|
|
|
#ifdef CONFIG_PPC_KUAP_DEBUG
|
2023-07-11 17:59:20 +02:00
|
|
|
static __always_inline unsigned long __kuap_get_and_assert_locked(void)
|
2021-10-19 09:29:28 +02:00
|
|
|
{
|
powerpc/kuap: Avoid useless jump_label on empty function
Disassembly of interrupt_enter_prepare() shows a pointless nop
before the mftb
c000abf0 <interrupt_enter_prepare>:
c000abf0: 81 23 00 84 lwz r9,132(r3)
c000abf4: 71 29 40 00 andi. r9,r9,16384
c000abf8: 41 82 00 28 beq- c000ac20 <interrupt_enter_prepare+0x30>
c000abfc: ===> 60 00 00 00 nop <====
c000ac00: 7d 0c 42 e6 mftb r8
c000ac04: 80 e2 00 08 lwz r7,8(r2)
c000ac08: 81 22 00 28 lwz r9,40(r2)
c000ac0c: 91 02 00 24 stw r8,36(r2)
c000ac10: 7d 29 38 50 subf r9,r9,r7
c000ac14: 7d 29 42 14 add r9,r9,r8
c000ac18: 91 22 00 08 stw r9,8(r2)
c000ac1c: 4e 80 00 20 blr
c000ac20: 60 00 00 00 nop
c000ac24: 7d 5a c2 a6 mfmd_ap r10
c000ac28: 3d 20 de 00 lis r9,-8704
c000ac2c: 91 43 00 b0 stw r10,176(r3)
c000ac30: 7d 3a c3 a6 mtspr 794,r9
c000ac34: 4e 80 00 20 blr
That comes from the call to kuap_loc(), allthough __kuap_lock() is an
empty function on the 8xx.
To avoid that, only perform kuap_is_disabled() check when there is
something to do with __kuap_lock().
Do the same with __kuap_save_and_lock() and
__kuap_get_and_assert_locked().
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/a854d25bea375d4ba6ca9c2617f9edbba397100a.1689091022.git.christophe.leroy@csgroup.eu
2023-07-11 17:59:14 +02:00
|
|
|
WARN_ON_ONCE(mfspr(SPRN_PID));
|
2021-10-19 09:29:28 +02:00
|
|
|
|
2023-07-11 17:59:13 +02:00
|
|
|
return 0;
|
2021-10-19 09:29:28 +02:00
|
|
|
}
|
powerpc/kuap: Avoid useless jump_label on empty function
Disassembly of interrupt_enter_prepare() shows a pointless nop
before the mftb
c000abf0 <interrupt_enter_prepare>:
c000abf0: 81 23 00 84 lwz r9,132(r3)
c000abf4: 71 29 40 00 andi. r9,r9,16384
c000abf8: 41 82 00 28 beq- c000ac20 <interrupt_enter_prepare+0x30>
c000abfc: ===> 60 00 00 00 nop <====
c000ac00: 7d 0c 42 e6 mftb r8
c000ac04: 80 e2 00 08 lwz r7,8(r2)
c000ac08: 81 22 00 28 lwz r9,40(r2)
c000ac0c: 91 02 00 24 stw r8,36(r2)
c000ac10: 7d 29 38 50 subf r9,r9,r7
c000ac14: 7d 29 42 14 add r9,r9,r8
c000ac18: 91 22 00 08 stw r9,8(r2)
c000ac1c: 4e 80 00 20 blr
c000ac20: 60 00 00 00 nop
c000ac24: 7d 5a c2 a6 mfmd_ap r10
c000ac28: 3d 20 de 00 lis r9,-8704
c000ac2c: 91 43 00 b0 stw r10,176(r3)
c000ac30: 7d 3a c3 a6 mtspr 794,r9
c000ac34: 4e 80 00 20 blr
That comes from the call to kuap_loc(), allthough __kuap_lock() is an
empty function on the 8xx.
To avoid that, only perform kuap_is_disabled() check when there is
something to do with __kuap_lock().
Do the same with __kuap_save_and_lock() and
__kuap_get_and_assert_locked().
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/a854d25bea375d4ba6ca9c2617f9edbba397100a.1689091022.git.christophe.leroy@csgroup.eu
2023-07-11 17:59:14 +02:00
|
|
|
#define __kuap_get_and_assert_locked __kuap_get_and_assert_locked
|
|
|
|
#endif
|
2021-10-19 09:29:28 +02:00
|
|
|
|
2023-07-11 17:59:21 +02:00
|
|
|
static __always_inline void uaccess_begin_booke(unsigned long val)
|
2021-10-19 09:29:28 +02:00
|
|
|
{
|
2023-07-11 17:59:21 +02:00
|
|
|
asm(ASM_MMU_FTR_IFSET("mtspr %0, %1; isync", "", %2) : :
|
|
|
|
"i"(SPRN_PID), "r"(val), "i"(MMU_FTR_KUAP) : "memory");
|
2021-10-19 09:29:28 +02:00
|
|
|
}
|
|
|
|
|
2023-07-11 17:59:21 +02:00
|
|
|
static __always_inline void uaccess_end_booke(void)
|
2021-10-19 09:29:28 +02:00
|
|
|
{
|
2023-07-11 17:59:21 +02:00
|
|
|
asm(ASM_MMU_FTR_IFSET("mtspr %0, %1; isync", "", %2) : :
|
|
|
|
"i"(SPRN_PID), "r"(0), "i"(MMU_FTR_KUAP) : "memory");
|
|
|
|
}
|
|
|
|
|
|
|
|
static __always_inline void allow_user_access(void __user *to, const void __user *from,
|
|
|
|
unsigned long size, unsigned long dir)
|
|
|
|
{
|
|
|
|
uaccess_begin_booke(current->thread.pid);
|
2021-10-19 09:29:28 +02:00
|
|
|
}
|
|
|
|
|
2023-07-11 17:59:21 +02:00
|
|
|
static __always_inline void prevent_user_access(unsigned long dir)
|
|
|
|
{
|
|
|
|
uaccess_end_booke();
|
|
|
|
}
|
|
|
|
|
|
|
|
static __always_inline unsigned long prevent_user_access_return(void)
|
2021-10-19 09:29:28 +02:00
|
|
|
{
|
|
|
|
unsigned long flags = mfspr(SPRN_PID);
|
|
|
|
|
2023-07-11 17:59:21 +02:00
|
|
|
uaccess_end_booke();
|
2021-10-19 09:29:28 +02:00
|
|
|
|
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
2023-07-11 17:59:21 +02:00
|
|
|
static __always_inline void restore_user_access(unsigned long flags)
|
2021-10-19 09:29:28 +02:00
|
|
|
{
|
2023-07-11 17:59:21 +02:00
|
|
|
if (flags)
|
|
|
|
uaccess_begin_booke(current->thread.pid);
|
2021-10-19 09:29:28 +02:00
|
|
|
}
|
|
|
|
|
2023-07-11 17:59:20 +02:00
|
|
|
static __always_inline bool
|
2021-10-19 09:29:28 +02:00
|
|
|
__bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
|
|
|
|
{
|
|
|
|
return !regs->kuap;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* !__ASSEMBLY__ */
|
|
|
|
|
|
|
|
#endif /* CONFIG_PPC_KUAP */
|
|
|
|
|
|
|
|
#endif /* _ASM_POWERPC_KUP_BOOKE_H_ */
|