cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

intel_pxp.c (8068B)


      1// SPDX-License-Identifier: MIT
      2/*
      3 * Copyright(c) 2020 Intel Corporation.
      4 */
      5#include <linux/workqueue.h>
      6#include "intel_pxp.h"
      7#include "intel_pxp_irq.h"
      8#include "intel_pxp_session.h"
      9#include "intel_pxp_tee.h"
     10#include "gem/i915_gem_context.h"
     11#include "gt/intel_context.h"
     12#include "i915_drv.h"
     13
     14/**
     15 * DOC: PXP
     16 *
     17 * PXP (Protected Xe Path) is a feature available in Gen12 and newer platforms.
     18 * It allows execution and flip to display of protected (i.e. encrypted)
     19 * objects. The SW support is enabled via the CONFIG_DRM_I915_PXP kconfig.
     20 *
     21 * Objects can opt-in to PXP encryption at creation time via the
     22 * I915_GEM_CREATE_EXT_PROTECTED_CONTENT create_ext flag. For objects to be
     23 * correctly protected they must be used in conjunction with a context created
     24 * with the I915_CONTEXT_PARAM_PROTECTED_CONTENT flag. See the documentation
     25 * of those two uapi flags for details and restrictions.
     26 *
     27 * Protected objects are tied to a pxp session; currently we only support one
     28 * session, which i915 manages and whose index is available in the uapi
     29 * (I915_PROTECTED_CONTENT_DEFAULT_SESSION) for use in instructions targeting
     30 * protected objects.
     31 * The session is invalidated by the HW when certain events occur (e.g.
     32 * suspend/resume). When this happens, all the objects that were used with the
     33 * session are marked as invalid and all contexts marked as using protected
     34 * content are banned. Any further attempt at using them in an execbuf call is
     35 * rejected, while flips are converted to black frames.
     36 *
     37 * Some of the PXP setup operations are performed by the Management Engine,
     38 * which is handled by the mei driver; communication between i915 and mei is
     39 * performed via the mei_pxp component module.
     40 */
     41
     42struct intel_gt *pxp_to_gt(const struct intel_pxp *pxp)
     43{
     44	return container_of(pxp, struct intel_gt, pxp);
     45}
     46
     47bool intel_pxp_is_enabled(const struct intel_pxp *pxp)
     48{
     49	return pxp->ce;
     50}
     51
     52bool intel_pxp_is_active(const struct intel_pxp *pxp)
     53{
     54	return pxp->arb_is_valid;
     55}
     56
     57/* KCR register definitions */
     58#define KCR_INIT _MMIO(0x320f0)
     59/* Setting KCR Init bit is required after system boot */
     60#define KCR_INIT_ALLOW_DISPLAY_ME_WRITES REG_BIT(14)
     61
     62static void kcr_pxp_enable(struct intel_gt *gt)
     63{
     64	intel_uncore_write(gt->uncore, KCR_INIT,
     65			   _MASKED_BIT_ENABLE(KCR_INIT_ALLOW_DISPLAY_ME_WRITES));
     66}
     67
     68static void kcr_pxp_disable(struct intel_gt *gt)
     69{
     70	intel_uncore_write(gt->uncore, KCR_INIT,
     71			   _MASKED_BIT_DISABLE(KCR_INIT_ALLOW_DISPLAY_ME_WRITES));
     72}
     73
     74static int create_vcs_context(struct intel_pxp *pxp)
     75{
     76	static struct lock_class_key pxp_lock;
     77	struct intel_gt *gt = pxp_to_gt(pxp);
     78	struct intel_engine_cs *engine;
     79	struct intel_context *ce;
     80	int i;
     81
     82	/*
     83	 * Find the first VCS engine present. We're guaranteed there is one
     84	 * if we're in this function due to the check in has_pxp
     85	 */
     86	for (i = 0, engine = NULL; !engine; i++)
     87		engine = gt->engine_class[VIDEO_DECODE_CLASS][i];
     88
     89	GEM_BUG_ON(!engine || engine->class != VIDEO_DECODE_CLASS);
     90
     91	ce = intel_engine_create_pinned_context(engine, engine->gt->vm, SZ_4K,
     92						I915_GEM_HWS_PXP_ADDR,
     93						&pxp_lock, "pxp_context");
     94	if (IS_ERR(ce)) {
     95		drm_err(&gt->i915->drm, "failed to create VCS ctx for PXP\n");
     96		return PTR_ERR(ce);
     97	}
     98
     99	pxp->ce = ce;
    100
    101	return 0;
    102}
    103
    104static void destroy_vcs_context(struct intel_pxp *pxp)
    105{
    106	intel_engine_destroy_pinned_context(fetch_and_zero(&pxp->ce));
    107}
    108
    109void intel_pxp_init(struct intel_pxp *pxp)
    110{
    111	struct intel_gt *gt = pxp_to_gt(pxp);
    112	int ret;
    113
    114	if (!HAS_PXP(gt->i915))
    115		return;
    116
    117	mutex_init(&pxp->tee_mutex);
    118
    119	/*
    120	 * we'll use the completion to check if there is a termination pending,
    121	 * so we start it as completed and we reinit it when a termination
    122	 * is triggered.
    123	 */
    124	init_completion(&pxp->termination);
    125	complete_all(&pxp->termination);
    126
    127	mutex_init(&pxp->arb_mutex);
    128	INIT_WORK(&pxp->session_work, intel_pxp_session_work);
    129
    130	ret = create_vcs_context(pxp);
    131	if (ret)
    132		return;
    133
    134	ret = intel_pxp_tee_component_init(pxp);
    135	if (ret)
    136		goto out_context;
    137
    138	drm_info(&gt->i915->drm, "Protected Xe Path (PXP) protected content support initialized\n");
    139
    140	return;
    141
    142out_context:
    143	destroy_vcs_context(pxp);
    144}
    145
    146void intel_pxp_fini(struct intel_pxp *pxp)
    147{
    148	if (!intel_pxp_is_enabled(pxp))
    149		return;
    150
    151	pxp->arb_is_valid = false;
    152
    153	intel_pxp_tee_component_fini(pxp);
    154
    155	destroy_vcs_context(pxp);
    156}
    157
    158void intel_pxp_mark_termination_in_progress(struct intel_pxp *pxp)
    159{
    160	pxp->arb_is_valid = false;
    161	reinit_completion(&pxp->termination);
    162}
    163
    164static void pxp_queue_termination(struct intel_pxp *pxp)
    165{
    166	struct intel_gt *gt = pxp_to_gt(pxp);
    167
    168	/*
    169	 * We want to get the same effect as if we received a termination
    170	 * interrupt, so just pretend that we did.
    171	 */
    172	spin_lock_irq(&gt->irq_lock);
    173	intel_pxp_mark_termination_in_progress(pxp);
    174	pxp->session_events |= PXP_TERMINATION_REQUEST;
    175	queue_work(system_unbound_wq, &pxp->session_work);
    176	spin_unlock_irq(&gt->irq_lock);
    177}
    178
    179/*
    180 * the arb session is restarted from the irq work when we receive the
    181 * termination completion interrupt
    182 */
    183int intel_pxp_start(struct intel_pxp *pxp)
    184{
    185	int ret = 0;
    186
    187	if (!intel_pxp_is_enabled(pxp))
    188		return -ENODEV;
    189
    190	mutex_lock(&pxp->arb_mutex);
    191
    192	if (pxp->arb_is_valid)
    193		goto unlock;
    194
    195	pxp_queue_termination(pxp);
    196
    197	if (!wait_for_completion_timeout(&pxp->termination,
    198					msecs_to_jiffies(250))) {
    199		ret = -ETIMEDOUT;
    200		goto unlock;
    201	}
    202
    203	/* make sure the compiler doesn't optimize the double access */
    204	barrier();
    205
    206	if (!pxp->arb_is_valid)
    207		ret = -EIO;
    208
    209unlock:
    210	mutex_unlock(&pxp->arb_mutex);
    211	return ret;
    212}
    213
    214void intel_pxp_init_hw(struct intel_pxp *pxp)
    215{
    216	kcr_pxp_enable(pxp_to_gt(pxp));
    217	intel_pxp_irq_enable(pxp);
    218}
    219
    220void intel_pxp_fini_hw(struct intel_pxp *pxp)
    221{
    222	kcr_pxp_disable(pxp_to_gt(pxp));
    223
    224	intel_pxp_irq_disable(pxp);
    225}
    226
    227int intel_pxp_key_check(struct intel_pxp *pxp,
    228			struct drm_i915_gem_object *obj,
    229			bool assign)
    230{
    231	if (!intel_pxp_is_active(pxp))
    232		return -ENODEV;
    233
    234	if (!i915_gem_object_is_protected(obj))
    235		return -EINVAL;
    236
    237	GEM_BUG_ON(!pxp->key_instance);
    238
    239	/*
    240	 * If this is the first time we're using this object, it's not
    241	 * encrypted yet; it will be encrypted with the current key, so mark it
    242	 * as such. If the object is already encrypted, check instead if the
    243	 * used key is still valid.
    244	 */
    245	if (!obj->pxp_key_instance && assign)
    246		obj->pxp_key_instance = pxp->key_instance;
    247
    248	if (obj->pxp_key_instance != pxp->key_instance)
    249		return -ENOEXEC;
    250
    251	return 0;
    252}
    253
    254void intel_pxp_invalidate(struct intel_pxp *pxp)
    255{
    256	struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915;
    257	struct i915_gem_context *ctx, *cn;
    258
    259	/* ban all contexts marked as protected */
    260	spin_lock_irq(&i915->gem.contexts.lock);
    261	list_for_each_entry_safe(ctx, cn, &i915->gem.contexts.list, link) {
    262		struct i915_gem_engines_iter it;
    263		struct intel_context *ce;
    264
    265		if (!kref_get_unless_zero(&ctx->ref))
    266			continue;
    267
    268		if (likely(!i915_gem_context_uses_protected_content(ctx))) {
    269			i915_gem_context_put(ctx);
    270			continue;
    271		}
    272
    273		spin_unlock_irq(&i915->gem.contexts.lock);
    274
    275		/*
    276		 * By the time we get here we are either going to suspend with
    277		 * quiesced execution or the HW keys are already long gone and
    278		 * in this case it is worthless to attempt to close the context
    279		 * and wait for its execution. It will hang the GPU if it has
    280		 * not already. So, as a fast mitigation, we can ban the
    281		 * context as quick as we can. That might race with the
    282		 * execbuffer, but currently this is the best that can be done.
    283		 */
    284		for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it)
    285			intel_context_ban(ce, NULL);
    286		i915_gem_context_unlock_engines(ctx);
    287
    288		/*
    289		 * The context has been banned, no need to keep the wakeref.
    290		 * This is safe from races because the only other place this
    291		 * is touched is context_release and we're holding a ctx ref
    292		 */
    293		if (ctx->pxp_wakeref) {
    294			intel_runtime_pm_put(&i915->runtime_pm,
    295					     ctx->pxp_wakeref);
    296			ctx->pxp_wakeref = 0;
    297		}
    298
    299		spin_lock_irq(&i915->gem.contexts.lock);
    300		list_safe_reset_next(ctx, cn, link);
    301		i915_gem_context_put(ctx);
    302	}
    303	spin_unlock_irq(&i915->gem.contexts.lock);
    304}