Skip to content
Permalink
Browse files
x86/pks: Preserve the PKRS MSR on context switch
The PKRS MSR is defined as a per-logical-processor register.  This
isolates memory access by logical CPU.  Unfortunately, the MSR is not
managed by XSAVE.  Therefore, tasks must save/restore the MSR value on
context switch.

Define a saved PKRS value in the task struct, as well as a cached
per-logical-processor MSR value which mirrors the MSR value of the
current CPU.  Initialize all tasks with the default MSR value.  Then, on
schedule in, call write_pkrs() which automatically avoids the overhead
of the MSR write if possible.

Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Co-developed-by: Fenghua Yu <fenghua.yu@intel.com>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Signed-off-by: Ira Weiny <ira.weiny@intel.com>

---
Changes from V3
	From Dan Williams
		make pks_init_task() and pks_sched_in() macros
		To avoid Supervisor PKey '#ifdefery' in process.c and
		process_64.c
	Split write_pkrs() to an earlier patch to be used in setup_pks()
		Move Peter's authorship to that patch.
	From Dan Williams
		Use ARCH_ENABLE_SUPERVISOR_PKEYS
	Remove kernel doc comment from write_pkrs
	From Thomas Gleixner
		Fix where pks_sched_in() is called from.
			Should be called from __switch_to()
			NOTE: PKS requires x86_64 so there is no need to
			update process_32.c
		Make pkrs_cache static
		Remove unnecessary pkrs_cache declaration
		Clean up formatting

Changes from V2
	Adjust for PKS enable being final patch.

Changes from V1
	Rebase to latest tip/master
		Resolve conflicts with INIT_THREAD changes

Changes since RFC V3
	Per Dave Hansen
		Update commit message
		move saved_pkrs to be in a nicer place
	Per Peter Zijlstra
		Add Comment from Peter
		Clean up white space
		Update authorship
  • Loading branch information
weiny2 committed Mar 22, 2021
1 parent 919e5ec commit 585599523a4df2a1126e0348c1249262a8422efb
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 1 deletion.
@@ -765,6 +765,7 @@

#define MSR_IA32_TSC_DEADLINE 0x000006E0

#define MSR_IA32_PKRS 0x000006E1

#define MSR_TSX_FORCE_ABORT 0x0000010F

@@ -17,4 +17,18 @@
#define PKR_AD_KEY(pkey) (PKR_AD_BIT << PKR_PKEY_SHIFT(pkey))
#define PKR_WD_KEY(pkey) (PKR_WD_BIT << PKR_PKEY_SHIFT(pkey))

/*
* Define a default PKRS value for each task.
*
* Key 0 has no restriction. All other keys are set to the most restrictive
* value which is access disabled (AD=1).
*
* NOTE: This needs to be a macro to be used as part of the INIT_THREAD macro.
*/
#define INIT_PKRS_VALUE (PKR_AD_KEY(1) | PKR_AD_KEY(2) | PKR_AD_KEY(3) | \
PKR_AD_KEY(4) | PKR_AD_KEY(5) | PKR_AD_KEY(6) | \
PKR_AD_KEY(7) | PKR_AD_KEY(8) | PKR_AD_KEY(9) | \
PKR_AD_KEY(10) | PKR_AD_KEY(11) | PKR_AD_KEY(12) | \
PKR_AD_KEY(13) | PKR_AD_KEY(14) | PKR_AD_KEY(15))

#endif /*_ASM_X86_PKEYS_COMMON_H */
@@ -18,6 +18,7 @@ struct vm86;
#include <asm/cpufeatures.h>
#include <asm/page.h>
#include <asm/pgtable_types.h>
#include <asm/pkeys_common.h>
#include <asm/percpu.h>
#include <asm/msr.h>
#include <asm/desc_defs.h>
@@ -519,6 +520,12 @@ struct thread_struct {
unsigned long cr2;
unsigned long trap_nr;
unsigned long error_code;

#ifdef CONFIG_ARCH_ENABLE_SUPERVISOR_PKEYS
/* Saved Protection key register for supervisor mappings */
u32 saved_pkrs;
#endif

#ifdef CONFIG_VM86
/* Virtual 86 mode info */
struct vm86 *vm86;
@@ -784,7 +791,41 @@ static inline void spin_lock_prefetch(const void *x)
#define KSTK_ESP(task) (task_pt_regs(task)->sp)

#else
#define INIT_THREAD { }

#ifdef CONFIG_ARCH_ENABLE_SUPERVISOR_PKEYS
#define INIT_THREAD_PKRS .saved_pkrs = INIT_PKRS_VALUE

void write_pkrs(u32 new_pkrs);

/*
* Define pks_init_task and pks_sched_in as macros to avoid requiring the
* definition of struct task_struct in this header while keeping the supervisor
* pkey #ifdefery out of process.c and process_64.c
*/

/*
* New tasks get the most restrictive PKRS value.
*/
#define pks_init_task(tsk) \
tsk->thread.saved_pkrs = INIT_PKRS_VALUE;

/*
* PKRS is only temporarily changed during specific code paths. Only a
* preemption during these windows away from the default value would
* require updating the MSR. write_pkrs() handles this optimization.
*/
#define pks_sched_in() \
write_pkrs(current->thread.saved_pkrs);

#else
#define INIT_THREAD_PKRS 0
#define pks_init_task(tsk)
#define pks_sched_in()
#endif

#define INIT_THREAD { \
INIT_THREAD_PKRS, \
}

extern unsigned long KSTK_ESP(struct task_struct *task);

@@ -43,6 +43,7 @@
#include <asm/io_bitmap.h>
#include <asm/proto.h>
#include <asm/frame.h>
#include <asm/processor.h>

#include "process.h"

@@ -195,6 +196,8 @@ void flush_thread(void)
memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));

fpu__clear_all(&tsk->thread.fpu);

pks_init_task(tsk);
}

void disable_TSC(void)
@@ -632,6 +632,8 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
/* Load the Intel cache allocation PQR MSR. */
resctrl_sched_in();

pks_sched_in();

return prev_p;
}

0 comments on commit 5855995

Please sign in to comment.