aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2010-02-24 02:17:13 -0500
committerDave Airlie <airlied@redhat.com>2010-03-01 01:08:22 -0500
commit566d84d172161cb6c0c4dd834c34abbac6bf7b38 (patch)
tree613023d32e2c2a359e5a8d3d838e35fa65d94e91 /drivers/gpu
parenta55e8d452ed2f6bbecda1a3039e82cd05244be3d (diff)
drm/radeon: r100/r200 ums: block ability for userspace app to trash 0 page and beyond
radeon's have a special ability to passthrough writes in their internal memory space directly to PCI, this ability means that if some of the internal surfaces like the depth buffer point at 0x0, any writes to these will go directly to RAM at 0x0 via PCI busmastering. Now mesa used to always emit clears after emitting state, since the radeon mesa driver was refactored a year or more ago, it was found it could generate a clear request without ever sending any setup state to the card. So the clear would attempt to clear the depth buffer at 0x0, which would overwrite main memory at this point. fs corruption ensues. Also once one app did this correctly, it would never get set back to 0 making this messy to reproduce. The kernel should block this from happening as mesa runs without privs, though it does require the user be connected to the current running X session. This patch implements a check to make sure the depth offset has been set before a depth clear occurs and if it finds one it prints a warning and ignores the depth clear request. There is also a mesa fix to avoid sending the badness going into mesa. This only affects r100/r200 GPUs in user modesetting mode. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/radeon/radeon_cp.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_state.c6
3 files changed, 9 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
index 06123ba31d31..dc6eba6b96dd 100644
--- a/drivers/gpu/drm/radeon/radeon_cp.c
+++ b/drivers/gpu/drm/radeon/radeon_cp.c
@@ -1644,6 +1644,7 @@ static int radeon_do_resume_cp(struct drm_device *dev, struct drm_file *file_pri
1644 radeon_cp_load_microcode(dev_priv); 1644 radeon_cp_load_microcode(dev_priv);
1645 radeon_cp_init_ring_buffer(dev, dev_priv, file_priv); 1645 radeon_cp_init_ring_buffer(dev, dev_priv, file_priv);
1646 1646
1647 dev_priv->have_z_offset = 0;
1647 radeon_do_engine_reset(dev); 1648 radeon_do_engine_reset(dev);
1648 radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1); 1649 radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
1649 1650
diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h
index f6d20cee5705..ee484b61bc5c 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.h
+++ b/drivers/gpu/drm/radeon/radeon_drv.h
@@ -267,6 +267,8 @@ typedef struct drm_radeon_private {
267 267
268 u32 scratch_ages[5]; 268 u32 scratch_ages[5];
269 269
270 int have_z_offset;
271
270 /* starting from here on, data is preserved accross an open */ 272 /* starting from here on, data is preserved accross an open */
271 uint32_t flags; /* see radeon_chip_flags */ 273 uint32_t flags; /* see radeon_chip_flags */
272 resource_size_t fb_aper_offset; 274 resource_size_t fb_aper_offset;
diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c
index 44b6d66b0ab3..8e69dc485dcb 100644
--- a/drivers/gpu/drm/radeon/radeon_state.c
+++ b/drivers/gpu/drm/radeon/radeon_state.c
@@ -105,6 +105,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
105 DRM_ERROR("Invalid depth buffer offset\n"); 105 DRM_ERROR("Invalid depth buffer offset\n");
106 return -EINVAL; 106 return -EINVAL;
107 } 107 }
108 dev_priv->have_z_offset = 1;
108 break; 109 break;
109 110
110 case RADEON_EMIT_PP_CNTL: 111 case RADEON_EMIT_PP_CNTL:
@@ -898,6 +899,11 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev,
898 if (tmp & RADEON_BACK) 899 if (tmp & RADEON_BACK)
899 flags |= RADEON_FRONT; 900 flags |= RADEON_FRONT;
900 } 901 }
902 if (flags & (RADEON_DEPTH|RADEON_STENCIL)) {
903 if (!dev_priv->have_z_offset)
904 printk_once(KERN_ERR "radeon: illegal depth clear request. Buggy mesa detected - please update.\n");
905 flags &= ~(RADEON_DEPTH | RADEON_STENCIL);
906 }
901 907
902 if (flags & (RADEON_FRONT | RADEON_BACK)) { 908 if (flags & (RADEON_FRONT | RADEON_BACK)) {
903 909