lkml.org 
[lkml]   [2020]   [Nov]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC][PATCH 06/24] x86/pti: Provide C variants of PTI switch CR3 macros
    Date
    Page Table Isolation (PTI) use assembly macros to switch the CR3
    register between kernel and user page-tables. Add C functions which
    implement the same features. For now, these C functions are not
    used but they will eventually replace using the assembly macros.

    Signed-off-by: Alexandre Chartre <alexandre.chartre@oracle.com>
    ---
    arch/x86/entry/common.c | 44 +++++++++++++++
    arch/x86/include/asm/entry-common.h | 84 +++++++++++++++++++++++++++++
    2 files changed, 128 insertions(+)

    diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c
    index 7ee15a12c115..d09b1ded5287 100644
    --- a/arch/x86/entry/common.c
    +++ b/arch/x86/entry/common.c
    @@ -343,3 +343,47 @@ __visible noinstr void xen_pv_evtchn_do_upcall(struct pt_regs *regs)
    }
    }
    #endif /* CONFIG_XEN_PV */
    +
    +#ifdef CONFIG_PAGE_TABLE_ISOLATION
    +
    +static __always_inline unsigned long save_and_switch_to_kernel_cr3(void)
    +{
    + unsigned long cr3, saved_cr3;
    +
    + if (!static_cpu_has(X86_FEATURE_PTI))
    + return 0;
    +
    + saved_cr3 = cr3 = __read_cr3();
    + if (cr3 & PTI_USER_PGTABLE_MASK) {
    + adjust_kernel_cr3(&cr3);
    + native_write_cr3(cr3);
    + }
    +
    + return saved_cr3;
    +}
    +
    +static __always_inline void restore_cr3(unsigned long cr3)
    +{
    + if (!static_cpu_has(X86_FEATURE_PTI))
    + return;
    +
    + if (static_cpu_has(X86_FEATURE_PCID)) {
    + if (cr3 & PTI_USER_PGTABLE_MASK)
    + adjust_user_cr3(&cr3);
    + else
    + cr3 |= X86_CR3_PCID_NOFLUSH;
    + }
    +
    + native_write_cr3(cr3);
    +}
    +
    +#else /* CONFIG_PAGE_TABLE_ISOLATION */
    +
    +static __always_inline unsigned long save_and_switch_to_kernel_cr3(void)
    +{
    + return 0;
    +}
    +
    +static __always_inline void restore_cr3(unsigned long cr3) {}
    +
    +#endif /* CONFIG_PAGE_TABLE_ISOLATION */
    diff --git a/arch/x86/include/asm/entry-common.h b/arch/x86/include/asm/entry-common.h
    index 6fe54b2813c1..b05b212f5ebc 100644
    --- a/arch/x86/include/asm/entry-common.h
    +++ b/arch/x86/include/asm/entry-common.h
    @@ -7,6 +7,7 @@
    #include <asm/nospec-branch.h>
    #include <asm/io_bitmap.h>
    #include <asm/fpu/api.h>
    +#include <asm/tlbflush.h>

    /* Check that the stack and regs on entry from user mode are sane. */
    static __always_inline void arch_check_user_regs(struct pt_regs *regs)
    @@ -81,4 +82,87 @@ static __always_inline void arch_exit_to_user_mode(void)
    }
    #define arch_exit_to_user_mode arch_exit_to_user_mode

    +#ifndef MODULE
    +#ifdef CONFIG_PAGE_TABLE_ISOLATION
    +
    +/*
    + * PAGE_TABLE_ISOLATION PGDs are 8k. Flip bit 12 to switch between the two
    + * halves:
    + */
    +#define PTI_USER_PGTABLE_BIT PAGE_SHIFT
    +#define PTI_USER_PGTABLE_MASK (1 << PTI_USER_PGTABLE_BIT)
    +#define PTI_USER_PCID_BIT X86_CR3_PTI_PCID_USER_BIT
    +#define PTI_USER_PCID_MASK (1 << PTI_USER_PCID_BIT)
    +#define PTI_USER_PGTABLE_AND_PCID_MASK \
    + (PTI_USER_PCID_MASK | PTI_USER_PGTABLE_MASK)
    +
    +static __always_inline void adjust_kernel_cr3(unsigned long *cr3)
    +{
    + if (static_cpu_has(X86_FEATURE_PCID))
    + *cr3 |= X86_CR3_PCID_NOFLUSH;
    +
    + /*
    + * Clear PCID and "PAGE_TABLE_ISOLATION bit", point CR3
    + * at kernel pagetables.
    + */
    + *cr3 &= ~PTI_USER_PGTABLE_AND_PCID_MASK;
    +}
    +
    +static __always_inline void adjust_user_cr3(unsigned long *cr3)
    +{
    + unsigned short mask;
    + unsigned long asid;
    +
    + /*
    + * Test if the ASID needs a flush.
    + */
    + asid = *cr3 & 0x7ff;
    + mask = this_cpu_read(cpu_tlbstate.user_pcid_flush_mask);
    + if (mask & (1 << asid)) {
    + /* Flush needed, clear the bit */
    + this_cpu_and(cpu_tlbstate.user_pcid_flush_mask, ~(1 << asid));
    + } else {
    + *cr3 |= X86_CR3_PCID_NOFLUSH;
    + }
    +}
    +
    +static __always_inline void switch_to_kernel_cr3(void)
    +{
    + unsigned long cr3;
    +
    + if (!static_cpu_has(X86_FEATURE_PTI))
    + return;
    +
    + cr3 = __read_cr3();
    + adjust_kernel_cr3(&cr3);
    + native_write_cr3(cr3);
    +}
    +
    +static __always_inline void switch_to_user_cr3(void)
    +{
    + unsigned long cr3;
    +
    + if (!static_cpu_has(X86_FEATURE_PTI))
    + return;
    +
    + cr3 = __read_cr3();
    + if (static_cpu_has(X86_FEATURE_PCID)) {
    + adjust_user_cr3(&cr3);
    + /* Flip the ASID to the user version */
    + cr3 |= PTI_USER_PCID_MASK;
    + }
    +
    + /* Flip the PGD to the user version */
    + cr3 |= PTI_USER_PGTABLE_MASK;
    + native_write_cr3(cr3);
    +}
    +
    +#else /* CONFIG_PAGE_TABLE_ISOLATION */
    +
    +static inline void switch_to_kernel_cr3(void) {}
    +static inline void switch_to_user_cr3(void) {}
    +
    +#endif /* CONFIG_PAGE_TABLE_ISOLATION */
    +#endif /* MODULE */
    +
    #endif
    --
    2.18.4
    \
     
     \ /
      Last update: 2020-11-09 15:44    [W:4.327 / U:0.252 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site