Chris Wilson | 984cade | 2021-01-11 22:52:20 +0000 | [diff] [blame] | 1 | // SPDX-License-Identifier: MIT |
| 2 | /* |
| 3 | * Copyright © 2021 Intel Corporation |
| 4 | */ |
| 5 | |
| 6 | #include <linux/kernel.h> |
| 7 | #include <linux/moduleparam.h> |
| 8 | #include <linux/slab.h> |
| 9 | #include <linux/string.h> |
| 10 | |
| 11 | #include "i915_drv.h" |
| 12 | #include "i915_mitigations.h" |
| 13 | |
| 14 | static unsigned long mitigations __read_mostly = ~0UL; |
| 15 | |
| 16 | enum { |
| 17 | CLEAR_RESIDUALS = 0, |
| 18 | }; |
| 19 | |
| 20 | static const char * const names[] = { |
| 21 | [CLEAR_RESIDUALS] = "residuals", |
| 22 | }; |
| 23 | |
| 24 | bool i915_mitigate_clear_residuals(void) |
| 25 | { |
| 26 | return READ_ONCE(mitigations) & BIT(CLEAR_RESIDUALS); |
| 27 | } |
| 28 | |
| 29 | static int mitigations_set(const char *val, const struct kernel_param *kp) |
| 30 | { |
| 31 | unsigned long new = ~0UL; |
| 32 | char *str, *sep, *tok; |
| 33 | bool first = true; |
| 34 | int err = 0; |
| 35 | |
| 36 | BUILD_BUG_ON(ARRAY_SIZE(names) >= BITS_PER_TYPE(mitigations)); |
| 37 | |
| 38 | str = kstrdup(val, GFP_KERNEL); |
| 39 | if (!str) |
| 40 | return -ENOMEM; |
| 41 | |
| 42 | for (sep = str; (tok = strsep(&sep, ","));) { |
| 43 | bool enable = true; |
| 44 | int i; |
| 45 | |
| 46 | /* Be tolerant of leading/trailing whitespace */ |
| 47 | tok = strim(tok); |
| 48 | |
| 49 | if (first) { |
| 50 | first = false; |
| 51 | |
| 52 | if (!strcmp(tok, "auto")) |
| 53 | continue; |
| 54 | |
| 55 | new = 0; |
| 56 | if (!strcmp(tok, "off")) |
| 57 | continue; |
| 58 | } |
| 59 | |
| 60 | if (*tok == '!') { |
| 61 | enable = !enable; |
| 62 | tok++; |
| 63 | } |
| 64 | |
| 65 | if (!strncmp(tok, "no", 2)) { |
| 66 | enable = !enable; |
| 67 | tok += 2; |
| 68 | } |
| 69 | |
| 70 | if (*tok == '\0') |
| 71 | continue; |
| 72 | |
| 73 | for (i = 0; i < ARRAY_SIZE(names); i++) { |
| 74 | if (!strcmp(tok, names[i])) { |
| 75 | if (enable) |
| 76 | new |= BIT(i); |
| 77 | else |
| 78 | new &= ~BIT(i); |
| 79 | break; |
| 80 | } |
| 81 | } |
| 82 | if (i == ARRAY_SIZE(names)) { |
| 83 | pr_err("Bad \"%s.mitigations=%s\", '%s' is unknown\n", |
| 84 | DRIVER_NAME, val, tok); |
| 85 | err = -EINVAL; |
| 86 | break; |
| 87 | } |
| 88 | } |
| 89 | kfree(str); |
| 90 | if (err) |
| 91 | return err; |
| 92 | |
| 93 | WRITE_ONCE(mitigations, new); |
| 94 | return 0; |
| 95 | } |
| 96 | |
| 97 | static int mitigations_get(char *buffer, const struct kernel_param *kp) |
| 98 | { |
| 99 | unsigned long local = READ_ONCE(mitigations); |
| 100 | int count, i; |
| 101 | bool enable; |
| 102 | |
| 103 | if (!local) |
| 104 | return scnprintf(buffer, PAGE_SIZE, "%s\n", "off"); |
| 105 | |
| 106 | if (local & BIT(BITS_PER_LONG - 1)) { |
| 107 | count = scnprintf(buffer, PAGE_SIZE, "%s,", "auto"); |
| 108 | enable = false; |
| 109 | } else { |
| 110 | enable = true; |
| 111 | count = 0; |
| 112 | } |
| 113 | |
| 114 | for (i = 0; i < ARRAY_SIZE(names); i++) { |
| 115 | if ((local & BIT(i)) != enable) |
| 116 | continue; |
| 117 | |
| 118 | count += scnprintf(buffer + count, PAGE_SIZE - count, |
| 119 | "%s%s,", enable ? "" : "!", names[i]); |
| 120 | } |
| 121 | |
| 122 | buffer[count - 1] = '\n'; |
| 123 | return count; |
| 124 | } |
| 125 | |
| 126 | static const struct kernel_param_ops ops = { |
| 127 | .set = mitigations_set, |
| 128 | .get = mitigations_get, |
| 129 | }; |
| 130 | |
| 131 | module_param_cb_unsafe(mitigations, &ops, NULL, 0600); |
| 132 | MODULE_PARM_DESC(mitigations, |
| 133 | "Selectively enable security mitigations for all Intel® GPUs in the system.\n" |
| 134 | "\n" |
| 135 | " auto -- enables all mitigations required for the platform [default]\n" |
| 136 | " off -- disables all mitigations\n" |
| 137 | "\n" |
| 138 | "Individual mitigations can be enabled by passing a comma-separated string,\n" |
| 139 | "e.g. mitigations=residuals to enable only clearing residuals or\n" |
| 140 | "mitigations=auto,noresiduals to disable only the clear residual mitigation.\n" |
| 141 | "Either '!' or 'no' may be used to switch from enabling the mitigation to\n" |
| 142 | "disabling it.\n" |
| 143 | "\n" |
| 144 | "Active mitigations for Ivybridge, Baytrail, Haswell:\n" |
| 145 | " residuals -- clear all thread-local registers between contexts" |
| 146 | ); |