diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c index 40c6568bfc3107427c4de679bedcfc53d73dd359..9e64b7c8b0b24baab2ce3d9fc5ebaa42b651c089 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c @@ -876,6 +876,37 @@ acr_r352_shutdown(struct acr_r352 *acr, struct nvkm_secboot *sb) return 0; } +/** + * Check if the WPR region has been indeed set by the ACR firmware, and + * matches where it should be. + */ +static bool +acr_r352_wpr_is_set(const struct acr_r352 *acr, const struct nvkm_secboot *sb) +{ + const struct nvkm_subdev *subdev = &sb->subdev; + const struct nvkm_device *device = subdev->device; + u64 wpr_lo, wpr_hi; + u64 wpr_range_lo, wpr_range_hi; + + nvkm_wr32(device, 0x100cd4, 0x2); + wpr_lo = (nvkm_rd32(device, 0x100cd4) & ~0xff); + wpr_lo <<= 8; + nvkm_wr32(device, 0x100cd4, 0x3); + wpr_hi = (nvkm_rd32(device, 0x100cd4) & ~0xff); + wpr_hi <<= 8; + + if (sb->wpr_size != 0) { + wpr_range_lo = sb->wpr_addr; + wpr_range_hi = wpr_range_lo + sb->wpr_size; + } else { + wpr_range_lo = acr->ls_blob->addr; + wpr_range_hi = wpr_range_lo + acr->ls_blob->size; + } + + return (wpr_lo >= wpr_range_lo && wpr_lo < wpr_range_hi && + wpr_hi > wpr_range_lo && wpr_hi <= wpr_range_hi); +} + static int acr_r352_bootstrap(struct acr_r352 *acr, struct nvkm_secboot *sb) { @@ -896,11 +927,17 @@ acr_r352_bootstrap(struct acr_r352 *acr, struct nvkm_secboot *sb) ret = sb->func->run_blob(sb, acr->load_blob); /* clear halt interrupt */ nvkm_falcon_clear_interrupt(sb->boot_falcon, 0x10); + sb->wpr_set = acr_r352_wpr_is_set(acr, sb); if (ret) return ret; nvkm_debug(subdev, "HS load blob completed\n"); - - sb->wpr_set = true; + if (ret) + return ret; + /* WPR must be set at this point */ + if (!sb->wpr_set) { + nvkm_error(subdev, "ACR blob completed but WPR not set!\n"); + return -EINVAL; + } /* Run LS firmwares post_run hooks */ for_each_set_bit(falcon_id, &managed_falcons, NVKM_SECBOOT_FALCON_END) {