Skip to content

Commit

Permalink
drm: Unify radeon offset checking.
Browse files Browse the repository at this point in the history
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 .
  • Loading branch information
=?utf-8?q?Michel_D=C3=A4nzer?= authored and Dave Airlie committed Dec 15, 2006
1 parent 3188a24 commit 1d6bb8e
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 35 deletions.
32 changes: 6 additions & 26 deletions drivers/char/drm/r300_cmdbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,26 +242,6 @@ static __inline__ int r300_check_range(unsigned reg, int count)
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 *
dev_priv,
drm_radeon_kcmd_buffer_t
Expand Down Expand Up @@ -290,7 +270,7 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
case MARK_SAFE:
break;
case MARK_CHECK_OFFSET:
if (r300_check_offset(dev_priv, (u32) values[i])) {
if (!radeon_check_offset(dev_priv, (u32) values[i])) {
DRM_ERROR
("Offset failed range check (reg=%04x sz=%d)\n",
reg, sz);
Expand Down Expand Up @@ -452,7 +432,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
i = 1;
while ((k < narrays) && (i < (count + 1))) {
i++; /* skip attribute field */
if (r300_check_offset(dev_priv, payload[i])) {
if (!radeon_check_offset(dev_priv, payload[i])) {
DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i);
Expand All @@ -463,7 +443,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
if (k == narrays)
break;
/* 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
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i);
Expand Down Expand Up @@ -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
| RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[2] << 10;
ret = r300_check_offset(dev_priv, offset);
ret = !radeon_check_offset(dev_priv, offset);
if (ret) {
DRM_ERROR("Invalid bitblt first offset is %08X\n", offset);
return DRM_ERR(EINVAL);
Expand All @@ -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) &&
(cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[3] << 10;
ret = r300_check_offset(dev_priv, offset);
ret = !radeon_check_offset(dev_priv, offset);
if (ret) {
DRM_ERROR("Invalid bitblt second offset is %08X\n", offset);
return DRM_ERR(EINVAL);
Expand Down Expand Up @@ -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]);
return DRM_ERR(EINVAL);
}
ret = r300_check_offset(dev_priv, cmd[2]);
ret = !radeon_check_offset(dev_priv, cmd[2]);
if (ret) {
DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
return DRM_ERR(EINVAL);
Expand Down
15 changes: 15 additions & 0 deletions drivers/char/drm/radeon_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,21 @@ extern int radeon_no_wb;
extern drm_ioctl_desc_t radeon_ioctls[];
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 */
extern int radeon_cp_init(DRM_IOCTL_ARGS);
extern int radeon_cp_start(DRM_IOCTL_ARGS);
Expand Down
13 changes: 4 additions & 9 deletions drivers/char/drm/radeon_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,7 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
u32 *offset)
{
u64 off = *offset;
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;
u32 fb_end = dev_priv->fb_location + dev_priv->fb_size - 1;
struct drm_radeon_driver_file_fields *radeon_priv;

/* Hrm ... the story of the offset ... So this function converts
Expand All @@ -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
* framebuffer or the GART mapped space
*/
if ((off >= fb_start && off <= fb_end) ||
(off >= gart_start && off <= gart_end))
if (radeon_check_offset(dev_priv, off))
return 0;

/* Ok, that didn't happen... now check if we have a zero based
Expand All @@ -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 */
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 */
if ((off >= fb_start && off <= fb_end) ||
(off >= gart_start && off <= gart_end)) {
if (radeon_check_offset(dev_priv, off)) {
DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off);
*offset = off;
return 0;
Expand Down

0 comments on commit 1d6bb8e

Please sign in to comment.