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 .
This commit is contained in:
committed by
Dave Airlie
parent
3188a24c25
commit
1d6bb8e51d
@@ -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 *
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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;
|
|||||||
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 *
|
|||||||
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 *
|
|||||||
/* 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 *
|
|||||||
|
|
||||||
/* 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;
|
||||||
|
Reference in New Issue
Block a user