Message ID | 20190129133121.32564-1-jani.nikula@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | drm/i915/opregion: rvda is relative from opregion base, not absolute | expand |
On Tue, Jan 29, 2019 at 03:31:21PM +0200, Jani Nikula wrote: > We've supported the opregion RVDA/RVDS fields for VBT size >= 6 KB since > commit 04ebaadb9f2d ("drm/i915/opregion: handle VBT sizes bigger than 6 > KB"). That's three years, almost to the date. > > The implementation was based on spec only, in anticipation of systems > with big VBT. Now, the spec has been changed. The RVDA is supposed to be > relative from the beginning of opregion, not absolute address. > > This is obviously a backward/forward incompatible change. I've been told > there are no systems out there using the field. Fingers crossed. This > will still be problematic for older kernels, and we can only try to > backport the fix. > > Fix the error path while at it. > > Fixes: 04ebaadb9f2d ("drm/i915/opregion: handle VBT sizes bigger than 6 KB") > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> > Cc: Imre Deak <imre.deak@intel.com> > Signed-off-by: Jani Nikula <jani.nikula@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> > --- > drivers/gpu/drm/i915/intel_opregion.c | 12 ++++++++++-- > 1 file changed, 10 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c > index 30ae96c5c97c..30324b963e24 100644 > --- a/drivers/gpu/drm/i915/intel_opregion.c > +++ b/drivers/gpu/drm/i915/intel_opregion.c > @@ -118,7 +118,7 @@ struct opregion_asle { > u64 fdss; > u32 fdsp; > u32 stat; > - u64 rvda; /* Physical address of raw vbt data */ > + u64 rvda; /* Address of raw vbt data, relative from opregion */ > u32 rvds; /* Size of raw vbt data */ > u8 rsvd[58]; > } __packed; > @@ -954,7 +954,13 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv) > > if (opregion->header->opregion_ver >= 2 && opregion->asle && > opregion->asle->rvda && opregion->asle->rvds) { > - opregion->rvda = memremap(opregion->asle->rvda, > + /* > + * rvda is unsigned, relative from opregion base, and should > + * never point within opregion. > + */ > + WARN_ON(opregion->asle->rvda < OPREGION_SIZE); > + > + opregion->rvda = memremap(asls + opregion->asle->rvda, > opregion->asle->rvds, > MEMREMAP_WB); > vbt = opregion->rvda; > @@ -966,6 +972,8 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv) > goto out; > } else { > DRM_DEBUG_KMS("Invalid VBT in ACPI OpRegion (RVDA)\n"); > + memunmap(opregion->rvda); > + opregion->rvda = NULL; > } > } > > -- > 2.20.1
On Tue, 29 Jan 2019, Jani Nikula <jani.nikula@intel.com> wrote: > This is obviously a backward/forward incompatible change. I've been > told there are no systems out there using the field. There are systems like that, in our CI too. Back to the drawing board. BR, Jani.
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 30ae96c5c97c..30324b963e24 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -118,7 +118,7 @@ struct opregion_asle { u64 fdss; u32 fdsp; u32 stat; - u64 rvda; /* Physical address of raw vbt data */ + u64 rvda; /* Address of raw vbt data, relative from opregion */ u32 rvds; /* Size of raw vbt data */ u8 rsvd[58]; } __packed; @@ -954,7 +954,13 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv) if (opregion->header->opregion_ver >= 2 && opregion->asle && opregion->asle->rvda && opregion->asle->rvds) { - opregion->rvda = memremap(opregion->asle->rvda, + /* + * rvda is unsigned, relative from opregion base, and should + * never point within opregion. + */ + WARN_ON(opregion->asle->rvda < OPREGION_SIZE); + + opregion->rvda = memremap(asls + opregion->asle->rvda, opregion->asle->rvds, MEMREMAP_WB); vbt = opregion->rvda; @@ -966,6 +972,8 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv) goto out; } else { DRM_DEBUG_KMS("Invalid VBT in ACPI OpRegion (RVDA)\n"); + memunmap(opregion->rvda); + opregion->rvda = NULL; } }
We've supported the opregion RVDA/RVDS fields for VBT size >= 6 KB since commit 04ebaadb9f2d ("drm/i915/opregion: handle VBT sizes bigger than 6 KB"). That's three years, almost to the date. The implementation was based on spec only, in anticipation of systems with big VBT. Now, the spec has been changed. The RVDA is supposed to be relative from the beginning of opregion, not absolute address. This is obviously a backward/forward incompatible change. I've been told there are no systems out there using the field. Fingers crossed. This will still be problematic for older kernels, and we can only try to backport the fix. Fix the error path while at it. Fixes: 04ebaadb9f2d ("drm/i915/opregion: handle VBT sizes bigger than 6 KB") Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Imre Deak <imre.deak@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/intel_opregion.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)