aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c')
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c254
1 files changed, 90 insertions, 164 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c
index 314be2192b7d..27c9dfffb9a6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c
@@ -19,184 +19,108 @@
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE. 20 * DEALINGS IN THE SOFTWARE.
21 */ 21 */
22
23/*
24 * Secure boot is the process by which NVIDIA-signed firmware is loaded into
25 * some of the falcons of a GPU. For production devices this is the only way
26 * for the firmware to access useful (but sensitive) registers.
27 *
28 * A Falcon microprocessor supporting advanced security modes can run in one of
29 * three modes:
30 *
31 * - Non-secure (NS). In this mode, functionality is similar to Falcon
32 * architectures before security modes were introduced (pre-Maxwell), but
33 * capability is restricted. In particular, certain registers may be
34 * inaccessible for reads and/or writes, and physical memory access may be
35 * disabled (on certain Falcon instances). This is the only possible mode that
36 * can be used if you don't have microcode cryptographically signed by NVIDIA.
37 *
38 * - Heavy Secure (HS). In this mode, the microprocessor is a black box - it's
39 * not possible to read or write any Falcon internal state or Falcon registers
40 * from outside the Falcon (for example, from the host system). The only way
41 * to enable this mode is by loading microcode that has been signed by NVIDIA.
42 * (The loading process involves tagging the IMEM block as secure, writing the
43 * signature into a Falcon register, and starting execution. The hardware will
44 * validate the signature, and if valid, grant HS privileges.)
45 *
46 * - Light Secure (LS). In this mode, the microprocessor has more privileges
47 * than NS but fewer than HS. Some of the microprocessor state is visible to
48 * host software to ease debugging. The only way to enable this mode is by HS
49 * microcode enabling LS mode. Some privileges available to HS mode are not
50 * available here. LS mode is introduced in GM20x.
51 *
52 * Secure boot consists in temporarily switching a HS-capable falcon (typically
53 * PMU) into HS mode in order to validate the LS firmwares of managed falcons,
54 * load them, and switch managed falcons into LS mode. Once secure boot
55 * completes, no falcon remains in HS mode.
56 *
57 * Secure boot requires a write-protected memory region (WPR) which can only be
58 * written by the secure falcon. On dGPU, the driver sets up the WPR region in
59 * video memory. On Tegra, it is set up by the bootloader and its location and
60 * size written into memory controller registers.
61 *
62 * The secure boot process takes place as follows:
63 *
64 * 1) A LS blob is constructed that contains all the LS firmwares we want to
65 * load, along with their signatures and bootloaders.
66 *
67 * 2) A HS blob (also called ACR) is created that contains the signed HS
68 * firmware in charge of loading the LS firmwares into their respective
69 * falcons.
70 *
71 * 3) The HS blob is loaded (via its own bootloader) and executed on the
72 * HS-capable falcon. It authenticates itself, switches the secure falcon to
73 * HS mode and setup the WPR region around the LS blob (dGPU) or copies the
74 * LS blob into the WPR region (Tegra).
75 *
76 * 4) The LS blob is now secure from all external tampering. The HS falcon
77 * checks the signatures of the LS firmwares and, if valid, switches the
78 * managed falcons to LS mode and makes them ready to run the LS firmware.
79 *
80 * 5) The managed falcons remain in LS mode and can be started.
81 *
82 */
83
22#include "priv.h" 84#include "priv.h"
85#include "acr.h"
23 86
24#include <subdev/mc.h> 87#include <subdev/mc.h>
25#include <subdev/timer.h> 88#include <subdev/timer.h>
89#include <subdev/pmu.h>
26 90
27static const char * 91const char *
28managed_falcons_names[] = { 92nvkm_secboot_falcon_name[] = {
29 [NVKM_SECBOOT_FALCON_PMU] = "PMU", 93 [NVKM_SECBOOT_FALCON_PMU] = "PMU",
30 [NVKM_SECBOOT_FALCON_RESERVED] = "<reserved>", 94 [NVKM_SECBOOT_FALCON_RESERVED] = "<reserved>",
31 [NVKM_SECBOOT_FALCON_FECS] = "FECS", 95 [NVKM_SECBOOT_FALCON_FECS] = "FECS",
32 [NVKM_SECBOOT_FALCON_GPCCS] = "GPCCS", 96 [NVKM_SECBOOT_FALCON_GPCCS] = "GPCCS",
33 [NVKM_SECBOOT_FALCON_END] = "<invalid>", 97 [NVKM_SECBOOT_FALCON_END] = "<invalid>",
34}; 98};
35
36/*
37 * Helper falcon functions
38 */
39
40static int
41falcon_clear_halt_interrupt(struct nvkm_device *device, u32 base)
42{
43 int ret;
44
45 /* clear halt interrupt */
46 nvkm_mask(device, base + 0x004, 0x10, 0x10);
47 /* wait until halt interrupt is cleared */
48 ret = nvkm_wait_msec(device, 10, base + 0x008, 0x10, 0x0);
49 if (ret < 0)
50 return ret;
51
52 return 0;
53}
54
55static int
56falcon_wait_idle(struct nvkm_device *device, u32 base)
57{
58 int ret;
59
60 ret = nvkm_wait_msec(device, 10, base + 0x04c, 0xffff, 0x0);
61 if (ret < 0)
62 return ret;
63
64 return 0;
65}
66
67static int
68nvkm_secboot_falcon_enable(struct nvkm_secboot *sb)
69{
70 struct nvkm_device *device = sb->subdev.device;
71 int ret;
72
73 /* enable engine */
74 nvkm_mc_enable(device, sb->devidx);
75 ret = nvkm_wait_msec(device, 10, sb->base + 0x10c, 0x6, 0x0);
76 if (ret < 0) {
77 nvkm_error(&sb->subdev, "Falcon mem scrubbing timeout\n");
78 nvkm_mc_disable(device, sb->devidx);
79 return ret;
80 }
81
82 ret = falcon_wait_idle(device, sb->base);
83 if (ret)
84 return ret;
85
86 /* enable IRQs */
87 nvkm_wr32(device, sb->base + 0x010, 0xff);
88 nvkm_mc_intr_mask(device, sb->devidx, true);
89
90 return 0;
91}
92
93static int
94nvkm_secboot_falcon_disable(struct nvkm_secboot *sb)
95{
96 struct nvkm_device *device = sb->subdev.device;
97
98 /* disable IRQs and wait for any previous code to complete */
99 nvkm_mc_intr_mask(device, sb->devidx, false);
100 nvkm_wr32(device, sb->base + 0x014, 0xff);
101
102 falcon_wait_idle(device, sb->base);
103
104 /* disable engine */
105 nvkm_mc_disable(device, sb->devidx);
106
107 return 0;
108}
109
110int
111nvkm_secboot_falcon_reset(struct nvkm_secboot *sb)
112{
113 int ret;
114
115 ret = nvkm_secboot_falcon_disable(sb);
116 if (ret)
117 return ret;
118
119 ret = nvkm_secboot_falcon_enable(sb);
120 if (ret)
121 return ret;
122
123 return 0;
124}
125
126/**
127 * nvkm_secboot_falcon_run - run the falcon that will perform secure boot
128 *
129 * This function is to be called after all chip-specific preparations have
130 * been completed. It will start the falcon to perform secure boot, wait for
131 * it to halt, and report if an error occurred.
132 */
133int
134nvkm_secboot_falcon_run(struct nvkm_secboot *sb)
135{
136 struct nvkm_device *device = sb->subdev.device;
137 int ret;
138
139 /* Start falcon */
140 nvkm_wr32(device, sb->base + 0x100, 0x2);
141
142 /* Wait for falcon halt */
143 ret = nvkm_wait_msec(device, 100, sb->base + 0x100, 0x10, 0x10);
144 if (ret < 0)
145 return ret;
146
147 /* If mailbox register contains an error code, then ACR has failed */
148 ret = nvkm_rd32(device, sb->base + 0x040);
149 if (ret) {
150 nvkm_error(&sb->subdev, "ACR boot failed, ret 0x%08x", ret);
151 falcon_clear_halt_interrupt(device, sb->base);
152 return -EINVAL;
153 }
154
155 return 0;
156}
157
158
159/** 99/**
160 * nvkm_secboot_reset() - reset specified falcon 100 * nvkm_secboot_reset() - reset specified falcon
161 */ 101 */
162int 102int
163nvkm_secboot_reset(struct nvkm_secboot *sb, u32 falcon) 103nvkm_secboot_reset(struct nvkm_secboot *sb, enum nvkm_secboot_falcon falcon)
164{ 104{
165 /* Unmanaged falcon? */ 105 /* Unmanaged falcon? */
166 if (!(BIT(falcon) & sb->func->managed_falcons)) { 106 if (!(BIT(falcon) & sb->acr->managed_falcons)) {
167 nvkm_error(&sb->subdev, "cannot reset unmanaged falcon!\n"); 107 nvkm_error(&sb->subdev, "cannot reset unmanaged falcon!\n");
168 return -EINVAL; 108 return -EINVAL;
169 } 109 }
170 110
171 return sb->func->reset(sb, falcon); 111 return sb->acr->func->reset(sb->acr, sb, falcon);
172}
173
174/**
175 * nvkm_secboot_start() - start specified falcon
176 */
177int
178nvkm_secboot_start(struct nvkm_secboot *sb, u32 falcon)
179{
180 /* Unmanaged falcon? */
181 if (!(BIT(falcon) & sb->func->managed_falcons)) {
182 nvkm_error(&sb->subdev, "cannot start unmanaged falcon!\n");
183 return -EINVAL;
184 }
185
186 return sb->func->start(sb, falcon);
187} 112}
188 113
189/** 114/**
190 * nvkm_secboot_is_managed() - check whether a given falcon is securely-managed 115 * nvkm_secboot_is_managed() - check whether a given falcon is securely-managed
191 */ 116 */
192bool 117bool
193nvkm_secboot_is_managed(struct nvkm_secboot *secboot, 118nvkm_secboot_is_managed(struct nvkm_secboot *sb, enum nvkm_secboot_falcon fid)
194 enum nvkm_secboot_falcon fid)
195{ 119{
196 if (!secboot) 120 if (!sb)
197 return false; 121 return false;
198 122
199 return secboot->func->managed_falcons & BIT(fid); 123 return sb->acr->managed_falcons & BIT(fid);
200} 124}
201 125
202static int 126static int
@@ -205,9 +129,19 @@ nvkm_secboot_oneinit(struct nvkm_subdev *subdev)
205 struct nvkm_secboot *sb = nvkm_secboot(subdev); 129 struct nvkm_secboot *sb = nvkm_secboot(subdev);
206 int ret = 0; 130 int ret = 0;
207 131
132 switch (sb->acr->boot_falcon) {
133 case NVKM_SECBOOT_FALCON_PMU:
134 sb->boot_falcon = subdev->device->pmu->falcon;
135 break;
136 default:
137 nvkm_error(subdev, "Unmanaged boot falcon %s!\n",
138 nvkm_secboot_falcon_name[sb->acr->boot_falcon]);
139 return -EINVAL;
140 }
141
208 /* Call chip-specific init function */ 142 /* Call chip-specific init function */
209 if (sb->func->init) 143 if (sb->func->oneinit)
210 ret = sb->func->init(sb); 144 ret = sb->func->oneinit(sb);
211 if (ret) { 145 if (ret) {
212 nvkm_error(subdev, "Secure Boot initialization failed: %d\n", 146 nvkm_error(subdev, "Secure Boot initialization failed: %d\n",
213 ret); 147 ret);
@@ -249,7 +183,7 @@ nvkm_secboot = {
249}; 183};
250 184
251int 185int
252nvkm_secboot_ctor(const struct nvkm_secboot_func *func, 186nvkm_secboot_ctor(const struct nvkm_secboot_func *func, struct nvkm_acr *acr,
253 struct nvkm_device *device, int index, 187 struct nvkm_device *device, int index,
254 struct nvkm_secboot *sb) 188 struct nvkm_secboot *sb)
255{ 189{
@@ -257,22 +191,14 @@ nvkm_secboot_ctor(const struct nvkm_secboot_func *func,
257 191
258 nvkm_subdev_ctor(&nvkm_secboot, device, index, &sb->subdev); 192 nvkm_subdev_ctor(&nvkm_secboot, device, index, &sb->subdev);
259 sb->func = func; 193 sb->func = func;
260 194 sb->acr = acr;
261 /* setup the performing falcon's base address and masks */ 195 acr->subdev = &sb->subdev;
262 switch (func->boot_falcon) {
263 case NVKM_SECBOOT_FALCON_PMU:
264 sb->devidx = NVKM_SUBDEV_PMU;
265 sb->base = 0x10a000;
266 break;
267 default:
268 nvkm_error(&sb->subdev, "invalid secure boot falcon\n");
269 return -EINVAL;
270 };
271 196
272 nvkm_debug(&sb->subdev, "securely managed falcons:\n"); 197 nvkm_debug(&sb->subdev, "securely managed falcons:\n");
273 for_each_set_bit(fid, &sb->func->managed_falcons, 198 for_each_set_bit(fid, &sb->acr->managed_falcons,
274 NVKM_SECBOOT_FALCON_END) 199 NVKM_SECBOOT_FALCON_END)
275 nvkm_debug(&sb->subdev, "- %s\n", managed_falcons_names[fid]); 200 nvkm_debug(&sb->subdev, "- %s\n",
201 nvkm_secboot_falcon_name[fid]);
276 202
277 return 0; 203 return 0;
278} 204}