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