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
This commit is contained in:
Christophe Leroy 2023-07-11 17:59:14 +02:00 committed by Michael Ellerman
parent 880df2d46a
commit 1bec4adcd5
5 changed files with 29 additions and 39 deletions

View File

@ -77,10 +77,6 @@ static inline void kuap_unlock(unsigned long addr, bool ool)
kuap_unlock_all_ool(); kuap_unlock_all_ool();
} }
static inline void __kuap_lock(void)
{
}
static inline void __kuap_save_and_lock(struct pt_regs *regs) static inline void __kuap_save_and_lock(struct pt_regs *regs)
{ {
unsigned long kuap = current->thread.kuap; unsigned long kuap = current->thread.kuap;
@ -92,6 +88,7 @@ static inline void __kuap_save_and_lock(struct pt_regs *regs)
current->thread.kuap = KUAP_NONE; current->thread.kuap = KUAP_NONE;
kuap_lock_addr(kuap, false); kuap_lock_addr(kuap, false);
} }
#define __kuap_save_and_lock __kuap_save_and_lock
static inline void kuap_user_restore(struct pt_regs *regs) static inline void kuap_user_restore(struct pt_regs *regs)
{ {
@ -120,6 +117,7 @@ static inline unsigned long __kuap_get_and_assert_locked(void)
return kuap; return kuap;
} }
#define __kuap_get_and_assert_locked __kuap_get_and_assert_locked
static __always_inline void __allow_user_access(void __user *to, const void __user *from, static __always_inline void __allow_user_access(void __user *to, const void __user *from,
u32 size, unsigned long dir) u32 size, unsigned long dir)

View File

@ -298,15 +298,9 @@ static inline unsigned long __kuap_get_and_assert_locked(void)
WARN_ON_ONCE(amr != AMR_KUAP_BLOCKED); WARN_ON_ONCE(amr != AMR_KUAP_BLOCKED);
return amr; return amr;
} }
#define __kuap_get_and_assert_locked __kuap_get_and_assert_locked
/* Do nothing, book3s/64 does that in ASM */ /* __kuap_lock() not required, book3s/64 does that in ASM */
static inline void __kuap_lock(void)
{
}
static inline void __kuap_save_and_lock(struct pt_regs *regs)
{
}
/* /*
* We support individually allowing read or write, but we don't support nesting * We support individually allowing read or write, but we don't support nesting

View File

@ -52,16 +52,9 @@ __bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
return false; return false;
} }
static inline void __kuap_lock(void) { }
static inline void __kuap_save_and_lock(struct pt_regs *regs) { }
static inline void kuap_user_restore(struct pt_regs *regs) { } static inline void kuap_user_restore(struct pt_regs *regs) { }
static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long amr) { } static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long amr) { }
static inline unsigned long __kuap_get_and_assert_locked(void)
{
return 0;
}
/* /*
* book3s/64/kup-radix.h defines these functions for the !KUAP case to flush * book3s/64/kup-radix.h defines these functions for the !KUAP case to flush
* the L1D cache after user accesses. Only include the empty stubs for other * the L1D cache after user accesses. Only include the empty stubs for other
@ -85,29 +78,24 @@ bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
return __bad_kuap_fault(regs, address, is_write); return __bad_kuap_fault(regs, address, is_write);
} }
static __always_inline void kuap_assert_locked(void)
{
if (kuap_is_disabled())
return;
if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG))
__kuap_get_and_assert_locked();
}
static __always_inline void kuap_lock(void) static __always_inline void kuap_lock(void)
{ {
#ifdef __kuap_lock
if (kuap_is_disabled()) if (kuap_is_disabled())
return; return;
__kuap_lock(); __kuap_lock();
#endif
} }
static __always_inline void kuap_save_and_lock(struct pt_regs *regs) static __always_inline void kuap_save_and_lock(struct pt_regs *regs)
{ {
#ifdef __kuap_save_and_lock
if (kuap_is_disabled()) if (kuap_is_disabled())
return; return;
__kuap_save_and_lock(regs); __kuap_save_and_lock(regs);
#endif
} }
static __always_inline void kuap_kernel_restore(struct pt_regs *regs, unsigned long amr) static __always_inline void kuap_kernel_restore(struct pt_regs *regs, unsigned long amr)
@ -120,10 +108,17 @@ static __always_inline void kuap_kernel_restore(struct pt_regs *regs, unsigned l
static __always_inline unsigned long kuap_get_and_assert_locked(void) static __always_inline unsigned long kuap_get_and_assert_locked(void)
{ {
if (kuap_is_disabled()) #ifdef __kuap_get_and_assert_locked
return 0; if (!kuap_is_disabled())
return __kuap_get_and_assert_locked();
#endif
return 0;
}
return __kuap_get_and_assert_locked(); static __always_inline void kuap_assert_locked(void)
{
if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG))
kuap_get_and_assert_locked();
} }
#ifndef CONFIG_PPC_BOOK3S_64 #ifndef CONFIG_PPC_BOOK3S_64

View File

@ -20,15 +20,12 @@ static __always_inline bool kuap_is_disabled(void)
return static_branch_unlikely(&disable_kuap_key); return static_branch_unlikely(&disable_kuap_key);
} }
static inline void __kuap_lock(void)
{
}
static inline void __kuap_save_and_lock(struct pt_regs *regs) static inline void __kuap_save_and_lock(struct pt_regs *regs)
{ {
regs->kuap = mfspr(SPRN_MD_AP); regs->kuap = mfspr(SPRN_MD_AP);
mtspr(SPRN_MD_AP, MD_APG_KUAP); mtspr(SPRN_MD_AP, MD_APG_KUAP);
} }
#define __kuap_save_and_lock __kuap_save_and_lock
static inline void kuap_user_restore(struct pt_regs *regs) static inline void kuap_user_restore(struct pt_regs *regs)
{ {
@ -39,13 +36,15 @@ static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long kua
mtspr(SPRN_MD_AP, regs->kuap); mtspr(SPRN_MD_AP, regs->kuap);
} }
#ifdef CONFIG_PPC_KUAP_DEBUG
static inline unsigned long __kuap_get_and_assert_locked(void) static inline unsigned long __kuap_get_and_assert_locked(void)
{ {
if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG)) WARN_ON_ONCE(mfspr(SPRN_MD_AP) >> 16 != MD_APG_KUAP >> 16);
WARN_ON_ONCE(mfspr(SPRN_MD_AP) >> 16 != MD_APG_KUAP >> 16);
return 0; return 0;
} }
#define __kuap_get_and_assert_locked __kuap_get_and_assert_locked
#endif
static inline void __allow_user_access(void __user *to, const void __user *from, static inline void __allow_user_access(void __user *to, const void __user *from,
unsigned long size, unsigned long dir) unsigned long size, unsigned long dir)

View File

@ -30,6 +30,7 @@ static inline void __kuap_lock(void)
mtspr(SPRN_PID, 0); mtspr(SPRN_PID, 0);
isync(); isync();
} }
#define __kuap_lock __kuap_lock
static inline void __kuap_save_and_lock(struct pt_regs *regs) static inline void __kuap_save_and_lock(struct pt_regs *regs)
{ {
@ -37,6 +38,7 @@ static inline void __kuap_save_and_lock(struct pt_regs *regs)
mtspr(SPRN_PID, 0); mtspr(SPRN_PID, 0);
isync(); isync();
} }
#define __kuap_save_and_lock __kuap_save_and_lock
static inline void kuap_user_restore(struct pt_regs *regs) static inline void kuap_user_restore(struct pt_regs *regs)
{ {
@ -56,13 +58,15 @@ static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long kua
/* Context synchronisation is performed by rfi */ /* Context synchronisation is performed by rfi */
} }
#ifdef CONFIG_PPC_KUAP_DEBUG
static inline unsigned long __kuap_get_and_assert_locked(void) static inline unsigned long __kuap_get_and_assert_locked(void)
{ {
if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG)) WARN_ON_ONCE(mfspr(SPRN_PID));
WARN_ON_ONCE(mfspr(SPRN_PID));
return 0; return 0;
} }
#define __kuap_get_and_assert_locked __kuap_get_and_assert_locked
#endif
static inline void __allow_user_access(void __user *to, const void __user *from, static inline void __allow_user_access(void __user *to, const void __user *from,
unsigned long size, unsigned long dir) unsigned long size, unsigned long dir)