Commit 1d6bb8e5 authored by =?utf-8?q?Michel_D=C3=A4nzer?='s avatar =?utf-8?q?Michel_D=C3=A4nzer?= Committed by Dave Airlie

drm: Unify radeon offset checking.

Replace r300_check_offset() with generic radeon_check_offset(), which doesn't
reject valid offsets when the framebuffer area is at the very end of the card's
32 bit address space. Make radeon_check_and_fixup_offset() use
radeon_check_offset() as well.

This fixes https://bugs.freedesktop.org/show_bug.cgi?id=7697 .
parent 3188a24c
...@@ -242,26 +242,6 @@ static __inline__ int r300_check_range(unsigned reg, int count) ...@@ -242,26 +242,6 @@ static __inline__ int r300_check_range(unsigned reg, int count)
return 0; return 0;
} }
/*
* we expect offsets passed to the framebuffer to be either within video
* memory or within AGP space
*/
static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv,
u32 offset)
{
/* we realy want to check against end of video aperture
but this value is not being kept.
This code is correct for now (does the same thing as the
code that sets MC_FB_LOCATION) in radeon_cp.c */
if (offset >= dev_priv->fb_location &&
offset < (dev_priv->fb_location + dev_priv->fb_size))
return 0;
if (offset >= dev_priv->gart_vm_start &&
offset < (dev_priv->gart_vm_start + dev_priv->gart_size))
return 0;
return 1;
}
static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t * static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
dev_priv, dev_priv,
drm_radeon_kcmd_buffer_t drm_radeon_kcmd_buffer_t
...@@ -290,7 +270,7 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t * ...@@ -290,7 +270,7 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
case MARK_SAFE: case MARK_SAFE:
break; break;
case MARK_CHECK_OFFSET: case MARK_CHECK_OFFSET:
if (r300_check_offset(dev_priv, (u32) values[i])) { if (!radeon_check_offset(dev_priv, (u32) values[i])) {
DRM_ERROR DRM_ERROR
("Offset failed range check (reg=%04x sz=%d)\n", ("Offset failed range check (reg=%04x sz=%d)\n",
reg, sz); reg, sz);
...@@ -452,7 +432,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv, ...@@ -452,7 +432,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
i = 1; i = 1;
while ((k < narrays) && (i < (count + 1))) { while ((k < narrays) && (i < (count + 1))) {
i++; /* skip attribute field */ i++; /* skip attribute field */
if (r300_check_offset(dev_priv, payload[i])) { if (!radeon_check_offset(dev_priv, payload[i])) {
DRM_ERROR DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n", ("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i); k, i);
...@@ -463,7 +443,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv, ...@@ -463,7 +443,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
if (k == narrays) if (k == narrays)
break; break;
/* have one more to process, they come in pairs */ /* have one more to process, they come in pairs */
if (r300_check_offset(dev_priv, payload[i])) { if (!radeon_check_offset(dev_priv, payload[i])) {
DRM_ERROR DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n", ("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i); k, i);
...@@ -508,7 +488,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, ...@@ -508,7 +488,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
| RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[2] << 10; offset = cmd[2] << 10;
ret = r300_check_offset(dev_priv, offset); ret = !radeon_check_offset(dev_priv, offset);
if (ret) { if (ret) {
DRM_ERROR("Invalid bitblt first offset is %08X\n", offset); DRM_ERROR("Invalid bitblt first offset is %08X\n", offset);
return DRM_ERR(EINVAL); return DRM_ERR(EINVAL);
...@@ -518,7 +498,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, ...@@ -518,7 +498,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) && if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
(cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[3] << 10; offset = cmd[3] << 10;
ret = r300_check_offset(dev_priv, offset); ret = !radeon_check_offset(dev_priv, offset);
if (ret) { if (ret) {
DRM_ERROR("Invalid bitblt second offset is %08X\n", offset); DRM_ERROR("Invalid bitblt second offset is %08X\n", offset);
return DRM_ERR(EINVAL); return DRM_ERR(EINVAL);
...@@ -551,7 +531,7 @@ static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv, ...@@ -551,7 +531,7 @@ static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv,
DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
return DRM_ERR(EINVAL); return DRM_ERR(EINVAL);
} }
ret = r300_check_offset(dev_priv, cmd[2]); ret = !radeon_check_offset(dev_priv, cmd[2]);
if (ret) { if (ret) {
DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
return DRM_ERR(EINVAL); return DRM_ERR(EINVAL);
......
...@@ -303,6 +303,21 @@ extern int radeon_no_wb; ...@@ -303,6 +303,21 @@ extern int radeon_no_wb;
extern drm_ioctl_desc_t radeon_ioctls[]; extern drm_ioctl_desc_t radeon_ioctls[];
extern int radeon_max_ioctl; extern int radeon_max_ioctl;
/* Check whether the given hardware address is inside the framebuffer or the
* GART area.
*/
static __inline__ int radeon_check_offset(drm_radeon_private_t *dev_priv,
u64 off)
{
u32 fb_start = dev_priv->fb_location;
u32 fb_end = fb_start + dev_priv->fb_size - 1;
u32 gart_start = dev_priv->gart_vm_start;
u32 gart_end = gart_start + dev_priv->gart_size - 1;
return ((off >= fb_start && off <= fb_end) ||
(off >= gart_start && off <= gart_end));
}
/* radeon_cp.c */ /* radeon_cp.c */
extern int radeon_cp_init(DRM_IOCTL_ARGS); extern int radeon_cp_init(DRM_IOCTL_ARGS);
extern int radeon_cp_start(DRM_IOCTL_ARGS); extern int radeon_cp_start(DRM_IOCTL_ARGS);
......
...@@ -43,10 +43,7 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * ...@@ -43,10 +43,7 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
u32 *offset) u32 *offset)
{ {
u64 off = *offset; u64 off = *offset;
u32 fb_start = dev_priv->fb_location; u32 fb_end = dev_priv->fb_location + dev_priv->fb_size - 1;
u32 fb_end = fb_start + dev_priv->fb_size - 1;
u32 gart_start = dev_priv->gart_vm_start;
u32 gart_end = gart_start + dev_priv->gart_size - 1;
struct drm_radeon_driver_file_fields *radeon_priv; struct drm_radeon_driver_file_fields *radeon_priv;
/* Hrm ... the story of the offset ... So this function converts /* Hrm ... the story of the offset ... So this function converts
...@@ -66,8 +63,7 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * ...@@ -66,8 +63,7 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
/* First, the best case, the offset already lands in either the /* First, the best case, the offset already lands in either the
* framebuffer or the GART mapped space * framebuffer or the GART mapped space
*/ */
if ((off >= fb_start && off <= fb_end) || if (radeon_check_offset(dev_priv, off))
(off >= gart_start && off <= gart_end))
return 0; return 0;
/* Ok, that didn't happen... now check if we have a zero based /* Ok, that didn't happen... now check if we have a zero based
...@@ -81,11 +77,10 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * ...@@ -81,11 +77,10 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
/* Finally, assume we aimed at a GART offset if beyond the fb */ /* Finally, assume we aimed at a GART offset if beyond the fb */
if (off > fb_end) if (off > fb_end)
off = off - fb_end - 1 + gart_start; off = off - fb_end - 1 + dev_priv->gart_vm_start;
/* Now recheck and fail if out of bounds */ /* Now recheck and fail if out of bounds */
if ((off >= fb_start && off <= fb_end) || if (radeon_check_offset(dev_priv, off)) {
(off >= gart_start && off <= gart_end)) {
DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off); DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off);
*offset = off; *offset = off;
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment