Path: blob/master/arch/powerpc/include/asm/book3s/32/kup.h
51689 views
/* SPDX-License-Identifier: GPL-2.0 */1#ifndef _ASM_POWERPC_BOOK3S_32_KUP_H2#define _ASM_POWERPC_BOOK3S_32_KUP_H34#include <asm/bug.h>5#include <asm/book3s/32/mmu-hash.h>6#include <asm/mmu.h>7#include <asm/synch.h>89#ifndef __ASSEMBLER__1011#ifdef CONFIG_PPC_KUAP1213#include <linux/sched.h>1415#define KUAP_NONE (~0UL)1617static __always_inline void kuap_lock_one(unsigned long addr)18{19mtsr(mfsr(addr) | SR_KS, addr);20isync(); /* Context sync required after mtsr() */21}2223static __always_inline void kuap_unlock_one(unsigned long addr)24{25mtsr(mfsr(addr) & ~SR_KS, addr);26isync(); /* Context sync required after mtsr() */27}2829static __always_inline void uaccess_begin_32s(unsigned long addr)30{31unsigned long tmp;3233asm volatile(ASM_MMU_FTR_IFSET(34"mfsrin %0, %1;"35"rlwinm %0, %0, 0, %2;"36"mtsrin %0, %1;"37"isync", "", %3)38: "=&r"(tmp)39: "r"(addr), "i"(~SR_KS), "i"(MMU_FTR_KUAP)40: "memory");41}4243static __always_inline void uaccess_end_32s(unsigned long addr)44{45unsigned long tmp;4647asm volatile(ASM_MMU_FTR_IFSET(48"mfsrin %0, %1;"49"oris %0, %0, %2;"50"mtsrin %0, %1;"51"isync", "", %3)52: "=&r"(tmp)53: "r"(addr), "i"(SR_KS >> 16), "i"(MMU_FTR_KUAP)54: "memory");55}5657static __always_inline void __kuap_save_and_lock(struct pt_regs *regs)58{59unsigned long kuap = current->thread.kuap;6061regs->kuap = kuap;62if (unlikely(kuap == KUAP_NONE))63return;6465current->thread.kuap = KUAP_NONE;66kuap_lock_one(kuap);67}68#define __kuap_save_and_lock __kuap_save_and_lock6970static __always_inline void kuap_user_restore(struct pt_regs *regs)71{72}7374static __always_inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)75{76if (unlikely(kuap != KUAP_NONE)) {77current->thread.kuap = KUAP_NONE;78kuap_lock_one(kuap);79}8081if (likely(regs->kuap == KUAP_NONE))82return;8384current->thread.kuap = regs->kuap;8586kuap_unlock_one(regs->kuap);87}8889static __always_inline unsigned long __kuap_get_and_assert_locked(void)90{91unsigned long kuap = current->thread.kuap;9293WARN_ON_ONCE(IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) && kuap != KUAP_NONE);9495return kuap;96}97#define __kuap_get_and_assert_locked __kuap_get_and_assert_locked9899static __always_inline void allow_user_access(void __user *to, unsigned long dir)100{101BUILD_BUG_ON(!__builtin_constant_p(dir));102103if (!(dir & KUAP_WRITE))104return;105106current->thread.kuap = (__force u32)to;107uaccess_begin_32s((__force u32)to);108}109110static __always_inline void prevent_user_access(unsigned long dir)111{112u32 kuap = current->thread.kuap;113114BUILD_BUG_ON(!__builtin_constant_p(dir));115116if (!(dir & KUAP_WRITE))117return;118119current->thread.kuap = KUAP_NONE;120uaccess_end_32s(kuap);121}122123static __always_inline unsigned long prevent_user_access_return(void)124{125unsigned long flags = current->thread.kuap;126127if (flags != KUAP_NONE) {128current->thread.kuap = KUAP_NONE;129uaccess_end_32s(flags);130}131132return flags;133}134135static __always_inline void restore_user_access(unsigned long flags)136{137if (flags != KUAP_NONE) {138current->thread.kuap = flags;139uaccess_begin_32s(flags);140}141}142143static __always_inline bool144__bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)145{146unsigned long kuap = regs->kuap;147148if (!is_write)149return false;150if (kuap == KUAP_NONE)151return true;152153/*154* If faulting address doesn't match unlocked segment, change segment.155* In case of unaligned store crossing two segments, emulate store.156*/157if ((kuap ^ address) & 0xf0000000) {158if (!(kuap & 0x0fffffff) && address > kuap - 4 && fix_alignment(regs)) {159regs_add_return_ip(regs, 4);160emulate_single_step(regs);161} else {162regs->kuap = address;163}164}165166return false;167}168169#endif /* CONFIG_PPC_KUAP */170171#endif /* __ASSEMBLER__ */172173#endif /* _ASM_POWERPC_BOOK3S_32_KUP_H */174175176