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