linux/drivers/gpu/drm/i915/i915_cmd_parser.c

/*
 * Copyright © 2013 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 * Authors:
 *    Brad Volkin <[email protected]>
 *
 */

#include <linux/highmem.h>

#include <drm/drm_cache.h>

#include "gt/intel_engine.h"
#include "gt/intel_engine_regs.h"
#include "gt/intel_gpu_commands.h"
#include "gt/intel_gt_regs.h"

#include "i915_cmd_parser.h"
#include "i915_drv.h"
#include "i915_memcpy.h"
#include "i915_reg.h"

/**
 * DOC: batch buffer command parser
 *
 * Motivation:
 * Certain OpenGL features (e.g. transform feedback, performance monitoring)
 * require userspace code to submit batches containing commands such as
 * MI_LOAD_REGISTER_IMM to access various registers. Unfortunately, some
 * generations of the hardware will noop these commands in "unsecure" batches
 * (which includes all userspace batches submitted via i915) even though the
 * commands may be safe and represent the intended programming model of the
 * device.
 *
 * The software command parser is similar in operation to the command parsing
 * done in hardware for unsecure batches. However, the software parser allows
 * some operations that would be noop'd by hardware, if the parser determines
 * the operation is safe, and submits the batch as "secure" to prevent hardware
 * parsing.
 *
 * Threats:
 * At a high level, the hardware (and software) checks attempt to prevent
 * granting userspace undue privileges. There are three categories of privilege.
 *
 * First, commands which are explicitly defined as privileged or which should
 * only be used by the kernel driver. The parser rejects such commands
 *
 * Second, commands which access registers. To support correct/enhanced
 * userspace functionality, particularly certain OpenGL extensions, the parser
 * provides a whitelist of registers which userspace may safely access
 *
 * Third, commands which access privileged memory (i.e. GGTT, HWS page, etc).
 * The parser always rejects such commands.
 *
 * The majority of the problematic commands fall in the MI_* range, with only a
 * few specific commands on each engine (e.g. PIPE_CONTROL and MI_FLUSH_DW).
 *
 * Implementation:
 * Each engine maintains tables of commands and registers which the parser
 * uses in scanning batch buffers submitted to that engine.
 *
 * Since the set of commands that the parser must check for is significantly
 * smaller than the number of commands supported, the parser tables contain only
 * those commands required by the parser. This generally works because command
 * opcode ranges have standard command length encodings. So for commands that
 * the parser does not need to check, it can easily skip them. This is
 * implemented via a per-engine length decoding vfunc.
 *
 * Unfortunately, there are a number of commands that do not follow the standard
 * length encoding for their opcode range, primarily amongst the MI_* commands.
 * To handle this, the parser provides a way to define explicit "skip" entries
 * in the per-engine command tables.
 *
 * Other command table entries map fairly directly to high level categories
 * mentioned above: rejected, register whitelist. The parser implements a number
 * of checks, including the privileged memory checks, via a general bitmasking
 * mechanism.
 */

/*
 * A command that requires special handling by the command parser.
 */
struct drm_i915_cmd_descriptor {};

/*
 * A table of commands requiring special handling by the command parser.
 *
 * Each engine has an array of tables. Each table consists of an array of
 * command descriptors, which must be sorted with command opcodes in
 * ascending order.
 */
struct drm_i915_cmd_table {};

#define STD_MI_OPCODE_SHIFT
#define STD_3D_OPCODE_SHIFT
#define STD_2D_OPCODE_SHIFT
#define STD_MFX_OPCODE_SHIFT
#define MIN_OPCODE_SHIFT

#define CMD

/* Convenience macros to compress the tables */
#define SMI
#define S3D
#define S2D
#define SMFX
#define F
#define S
#define R
#define W
#define B

/*            Command                          Mask   Fixed Len   Action
	      ---------------------------------------------------------- */
static const struct drm_i915_cmd_descriptor gen7_common_cmds[] =;

static const struct drm_i915_cmd_descriptor gen7_render_cmds[] =;

static const struct drm_i915_cmd_descriptor hsw_render_cmds[] =;

static const struct drm_i915_cmd_descriptor gen7_video_cmds[] =;

static const struct drm_i915_cmd_descriptor gen7_vecs_cmds[] =;

static const struct drm_i915_cmd_descriptor gen7_blt_cmds[] =;

static const struct drm_i915_cmd_descriptor hsw_blt_cmds[] =;

/*
 * For Gen9 we can still rely on the h/w to enforce cmd security, and only
 * need to re-enforce the register access checks. We therefore only need to
 * teach the cmdparser how to find the end of each command, and identify
 * register accesses. The table doesn't need to reject any commands, and so
 * the only commands listed here are:
 *   1) Those that touch registers
 *   2) Those that do not have the default 8-bit length
 *
 * Note that the default MI length mask chosen for this table is 0xFF, not
 * the 0x3F used on older devices. This is because the vast majority of MI
 * cmds on Gen9 use a standard 8-bit Length field.
 * All the Gen9 blitter instructions are standard 0xFF length mask, and
 * none allow access to non-general registers, so in fact no BLT cmds are
 * included in the table at all.
 *
 */
static const struct drm_i915_cmd_descriptor gen9_blt_cmds[] =;

static const struct drm_i915_cmd_descriptor noop_desc =;

#undef CMD
#undef SMI
#undef S3D
#undef S2D
#undef SMFX
#undef F
#undef S
#undef R
#undef W
#undef B

static const struct drm_i915_cmd_table gen7_render_cmd_table[] =;

static const struct drm_i915_cmd_table hsw_render_ring_cmd_table[] =;

static const struct drm_i915_cmd_table gen7_video_cmd_table[] =;

static const struct drm_i915_cmd_table hsw_vebox_cmd_table[] =;

static const struct drm_i915_cmd_table gen7_blt_cmd_table[] =;

static const struct drm_i915_cmd_table hsw_blt_ring_cmd_table[] =;

static const struct drm_i915_cmd_table gen9_blt_cmd_table[] =;


/*
 * Register whitelists, sorted by increasing register offset.
 */

/*
 * An individual whitelist entry granting access to register addr.  If
 * mask is non-zero the argument of immediate register writes will be
 * AND-ed with mask, and the command will be rejected if the result
 * doesn't match value.
 *
 * Registers with non-zero mask are only allowed to be written using
 * LRI.
 */
struct drm_i915_reg_descriptor {};

/* Convenience macro for adding 32-bit registers. */
#define REG32

#define REG32_IDX(_reg, idx)

/*
 * Convenience macro for adding 64-bit registers.
 *
 * Some registers that userspace accesses are 64 bits. The register
 * access commands only allow 32-bit accesses. Hence, we have to include
 * entries for both halves of the 64-bit registers.
 */
#define REG64

#define REG64_IDX(_reg, idx)

#define REG64_BASE_IDX(_reg, base, idx)

static const struct drm_i915_reg_descriptor gen7_render_regs[] =;

static const struct drm_i915_reg_descriptor hsw_render_regs[] =;

static const struct drm_i915_reg_descriptor gen7_blt_regs[] =;

static const struct drm_i915_reg_descriptor gen9_blt_regs[] =;

#undef REG64
#undef REG32

struct drm_i915_reg_table {};

static const struct drm_i915_reg_table ivb_render_reg_tables[] =;

static const struct drm_i915_reg_table ivb_blt_reg_tables[] =;

static const struct drm_i915_reg_table hsw_render_reg_tables[] =;

static const struct drm_i915_reg_table hsw_blt_reg_tables[] =;

static const struct drm_i915_reg_table gen9_blt_reg_tables[] =;

static u32 gen7_render_get_cmd_length_mask(u32 cmd_header)
{}

static u32 gen7_bsd_get_cmd_length_mask(u32 cmd_header)
{}

static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header)
{}

static u32 gen9_blt_get_cmd_length_mask(u32 cmd_header)
{}

static bool validate_cmds_sorted(const struct intel_engine_cs *engine,
				 const struct drm_i915_cmd_table *cmd_tables,
				 int cmd_table_count)
{}

static bool check_sorted(const struct intel_engine_cs *engine,
			 const struct drm_i915_reg_descriptor *reg_table,
			 int reg_count)
{}

static bool validate_regs_sorted(struct intel_engine_cs *engine)
{}

struct cmd_node {};

/*
 * Different command ranges have different numbers of bits for the opcode. For
 * example, MI commands use bits 31:23 while 3D commands use bits 31:16. The
 * problem is that, for example, MI commands use bits 22:16 for other fields
 * such as GGTT vs PPGTT bits. If we include those bits in the mask then when
 * we mask a command from a batch it could hash to the wrong bucket due to
 * non-opcode bits being set. But if we don't include those bits, some 3D
 * commands may hash to the same bucket due to not including opcode bits that
 * make the command unique. For now, we will risk hashing to the same bucket.
 */
static inline u32 cmd_header_key(u32 x)
{}

static int init_hash_table(struct intel_engine_cs *engine,
			   const struct drm_i915_cmd_table *cmd_tables,
			   int cmd_table_count)
{}

static void fini_hash_table(struct intel_engine_cs *engine)
{}

/**
 * intel_engine_init_cmd_parser() - set cmd parser related fields for an engine
 * @engine: the engine to initialize
 *
 * Optionally initializes fields related to batch buffer command parsing in the
 * struct intel_engine_cs based on whether the platform requires software
 * command parsing.
 */
int intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
{}

/**
 * intel_engine_cleanup_cmd_parser() - clean up cmd parser related fields
 * @engine: the engine to clean up
 *
 * Releases any resources related to command parsing that may have been
 * initialized for the specified engine.
 */
void intel_engine_cleanup_cmd_parser(struct intel_engine_cs *engine)
{}

static const struct drm_i915_cmd_descriptor*
find_cmd_in_table(struct intel_engine_cs *engine,
		  u32 cmd_header)
{}

/*
 * Returns a pointer to a descriptor for the command specified by cmd_header.
 *
 * The caller must supply space for a default descriptor via the default_desc
 * parameter. If no descriptor for the specified command exists in the engine's
 * command parser tables, this function fills in default_desc based on the
 * engine's default length encoding and returns default_desc.
 */
static const struct drm_i915_cmd_descriptor*
find_cmd(struct intel_engine_cs *engine,
	 u32 cmd_header,
	 const struct drm_i915_cmd_descriptor *desc,
	 struct drm_i915_cmd_descriptor *default_desc)
{}

static const struct drm_i915_reg_descriptor *
__find_reg(const struct drm_i915_reg_descriptor *table, int count, u32 addr)
{}

static const struct drm_i915_reg_descriptor *
find_reg(const struct intel_engine_cs *engine, u32 addr)
{}

/* Returns a vmap'd pointer to dst_obj, which the caller must unmap */
static u32 *copy_batch(struct drm_i915_gem_object *dst_obj,
		       struct drm_i915_gem_object *src_obj,
		       unsigned long offset, unsigned long length,
		       bool *needs_clflush_after)
{}

static inline bool cmd_desc_is(const struct drm_i915_cmd_descriptor * const desc,
			       const u32 cmd)
{}

static bool check_cmd(const struct intel_engine_cs *engine,
		      const struct drm_i915_cmd_descriptor *desc,
		      const u32 *cmd, u32 length)
{}

static int check_bbstart(u32 *cmd, u32 offset, u32 length,
			 u32 batch_length,
			 u64 batch_addr,
			 u64 shadow_addr,
			 const unsigned long *jump_whitelist)
{}

static unsigned long *alloc_whitelist(u32 batch_length)
{}

#define LENGTH_BIAS

/**
 * intel_engine_cmd_parser() - parse a batch buffer for privilege violations
 * @engine: the engine on which the batch is to execute
 * @batch: the batch buffer in question
 * @batch_offset: byte offset in the batch at which execution starts
 * @batch_length: length of the commands in batch_obj
 * @shadow: validated copy of the batch buffer in question
 * @trampoline: true if we need to trampoline into privileged execution
 *
 * Parses the specified batch buffer looking for privilege violations as
 * described in the overview.
 *
 * Return: non-zero if the parser finds violations or otherwise fails; -EACCES
 * if the batch appears legal but should use hardware parsing
 */

int intel_engine_cmd_parser(struct intel_engine_cs *engine,
			    struct i915_vma *batch,
			    unsigned long batch_offset,
			    unsigned long batch_length,
			    struct i915_vma *shadow,
			    bool trampoline)
{}

/**
 * i915_cmd_parser_get_version() - get the cmd parser version number
 * @dev_priv: i915 device private
 *
 * The cmd parser maintains a simple increasing integer version number suitable
 * for passing to userspace clients to determine what operations are permitted.
 *
 * Return: the current version number of the cmd parser
 */
int i915_cmd_parser_get_version(struct drm_i915_private *dev_priv)
{}