Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/mm: Provide arch_prctl() interface for LAM

Add a few of arch_prctl() handles:

- ARCH_ENABLE_TAGGED_ADDR enabled LAM. The argument is required number
of tag bits. It is rounded up to the nearest LAM mode that can
provide it. For now only LAM_U57 is supported, with 6 tag bits.

- ARCH_GET_UNTAG_MASK returns untag mask. It can indicates where tag
bits located in the address.

- ARCH_GET_MAX_TAG_BITS returns the maximum tag bits user can request.
Zero if LAM is not supported.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: Alexander Potapenko <glider@google.com>
Link: https://lore.kernel.org/all/20230312112612.31869-9-kirill.shutemov%40linux.intel.com

authored by

Kirill A. Shutemov and committed by
Dave Hansen
2f8794bd e0bddc19

+63 -1
+2
arch/x86/include/asm/mmu.h
··· 12 12 #define MM_CONTEXT_UPROBE_IA32 0 13 13 /* vsyscall page is accessible on this MM */ 14 14 #define MM_CONTEXT_HAS_VSYSCALL 1 15 + /* Do not allow changing LAM mode */ 16 + #define MM_CONTEXT_LOCK_LAM 2 15 17 16 18 /* 17 19 * x86 has arch-specific MMU state beyond what lives in mm_struct.
+4
arch/x86/include/uapi/asm/prctl.h
··· 20 20 #define ARCH_MAP_VDSO_32 0x2002 21 21 #define ARCH_MAP_VDSO_64 0x2003 22 22 23 + #define ARCH_GET_UNTAG_MASK 0x4001 24 + #define ARCH_ENABLE_TAGGED_ADDR 0x4002 25 + #define ARCH_GET_MAX_TAG_BITS 0x4003 26 + 23 27 #endif /* _ASM_X86_PRCTL_H */
+3
arch/x86/kernel/process.c
··· 163 163 164 164 savesegment(es, p->thread.es); 165 165 savesegment(ds, p->thread.ds); 166 + 167 + if (p->mm && (clone_flags & (CLONE_VM | CLONE_VFORK)) == CLONE_VM) 168 + set_bit(MM_CONTEXT_LOCK_LAM, &p->mm->context.flags); 166 169 #else 167 170 p->thread.sp0 = (unsigned long) (childregs + 1); 168 171 savesegment(gs, p->thread.gs);
+54 -1
arch/x86/kernel/process_64.c
··· 743 743 } 744 744 #endif 745 745 746 + #ifdef CONFIG_ADDRESS_MASKING 747 + 748 + #define LAM_U57_BITS 6 749 + 750 + static int prctl_enable_tagged_addr(struct mm_struct *mm, unsigned long nr_bits) 751 + { 752 + if (!cpu_feature_enabled(X86_FEATURE_LAM)) 753 + return -ENODEV; 754 + 755 + /* PTRACE_ARCH_PRCTL */ 756 + if (current->mm != mm) 757 + return -EINVAL; 758 + 759 + if (mmap_write_lock_killable(mm)) 760 + return -EINTR; 761 + 762 + if (test_bit(MM_CONTEXT_LOCK_LAM, &mm->context.flags)) { 763 + mmap_write_unlock(mm); 764 + return -EBUSY; 765 + } 766 + 767 + if (!nr_bits) { 768 + mmap_write_unlock(mm); 769 + return -EINVAL; 770 + } else if (nr_bits <= LAM_U57_BITS) { 771 + mm->context.lam_cr3_mask = X86_CR3_LAM_U57; 772 + mm->context.untag_mask = ~GENMASK(62, 57); 773 + } else { 774 + mmap_write_unlock(mm); 775 + return -EINVAL; 776 + } 777 + 778 + write_cr3(__read_cr3() | mm->context.lam_cr3_mask); 779 + set_tlbstate_lam_mode(mm); 780 + set_bit(MM_CONTEXT_LOCK_LAM, &mm->context.flags); 781 + 782 + mmap_write_unlock(mm); 783 + 784 + return 0; 785 + } 786 + #endif 787 + 746 788 long do_arch_prctl_64(struct task_struct *task, int option, unsigned long arg2) 747 789 { 748 790 int ret = 0; ··· 872 830 case ARCH_MAP_VDSO_64: 873 831 return prctl_map_vdso(&vdso_image_64, arg2); 874 832 #endif 875 - 833 + #ifdef CONFIG_ADDRESS_MASKING 834 + case ARCH_GET_UNTAG_MASK: 835 + return put_user(task->mm->context.untag_mask, 836 + (unsigned long __user *)arg2); 837 + case ARCH_ENABLE_TAGGED_ADDR: 838 + return prctl_enable_tagged_addr(task->mm, arg2); 839 + case ARCH_GET_MAX_TAG_BITS: 840 + if (!cpu_feature_enabled(X86_FEATURE_LAM)) 841 + return put_user(0, (unsigned long __user *)arg2); 842 + else 843 + return put_user(LAM_U57_BITS, (unsigned long __user *)arg2); 844 + #endif 876 845 default: 877 846 ret = -EINVAL; 878 847 break;