mirror of
https://github.com/torvalds/linux.git
synced 2024-11-12 07:01:57 +00:00
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:
parent
3188a24c25
commit
1d6bb8e51d
@ -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
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
@ -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
|
||||
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user