/* * 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) { … }