summaryrefslogtreecommitdiff
path: root/shared
diff options
context:
space:
mode:
Diffstat (limited to 'shared')
-rw-r--r--shared/radeon.h21
-rw-r--r--shared/radeon_cp.c29
-rw-r--r--shared/radeon_drm.h16
-rw-r--r--shared/radeon_drv.h5
-rw-r--r--shared/radeon_state.c323
5 files changed, 339 insertions, 55 deletions
diff --git a/shared/radeon.h b/shared/radeon.h
index fadb248b..af1f6ca4 100644
--- a/shared/radeon.h
+++ b/shared/radeon.h
@@ -51,7 +51,7 @@
#define DRIVER_DATE "20020828"
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 9
+#define DRIVER_MINOR 10
#define DRIVER_PATCHLEVEL 0
/* Interface history:
@@ -81,6 +81,9 @@
* Add 'GET' queries for starting additional clients on different VT's.
* 1.9 - Add DRM_IOCTL_RADEON_CP_RESUME ioctl.
* Add texture rectangle support for r100.
+ * 1.10- Add SETPARAM ioctl; first parameter to set is FB_LOCATION, which
+ * clients use to tell the DRM where they think the framebuffer is
+ * located in the card's address space
*/
#define DRIVER_IOCTLS \
[DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \
@@ -106,8 +109,9 @@
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_ALLOC)] = { radeon_mem_alloc, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_FREE)] = { radeon_mem_free, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_INIT_HEAP)] = { radeon_mem_init_heap, 1, 1 }, \
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_EMIT)] = { radeon_irq_emit, 1, 0 }, \
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)] = { radeon_irq_wait, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_EMIT)] = { radeon_irq_emit, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)] = { radeon_irq_wait, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_SETPARAM)] = { radeon_cp_setparam, 1, 0 }, \
#define DRIVER_PCI_IDS \
{0x1002, 0x4242, 0, "ATI Radeon BB R200 AIW 8500DV"}, \
@@ -147,6 +151,17 @@
{0x1002, 0x5961, 0, "ATI Radeon RV280 9200"}, \
{0, 0, 0, NULL}
+#define DRIVER_FILE_FIELDS \
+ s64 radeon_fb_delta; \
+
+#define DRIVER_OPEN_HELPER( filp_priv, dev ) \
+do { \
+ drm_radeon_private_t *dev_priv = dev->dev_private; \
+ if ( dev_priv ) \
+ filp_priv->radeon_fb_delta = dev_priv->fb_location; \
+ else \
+ filp_priv->radeon_fb_delta = 0; \
+} while( 0 )
/* When a client dies:
* - Check for and clean up flipped page state
diff --git a/shared/radeon_cp.c b/shared/radeon_cp.c
index b24880a8..87aef010 100644
--- a/shared/radeon_cp.c
+++ b/shared/radeon_cp.c
@@ -855,7 +855,8 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev,
/* Initialize the memory controller */
RADEON_WRITE( RADEON_MC_FB_LOCATION,
- (dev_priv->gart_vm_start - 1) & 0xffff0000 );
+ ( ( dev_priv->gart_vm_start - 1 ) & 0xffff0000 )
+ | ( dev_priv->fb_location >> 16 ) );
#if __REALLY_HAVE_AGP
if ( !dev_priv->is_pci ) {
@@ -1071,13 +1072,6 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init )
dev_priv->depth_offset = init->depth_offset;
dev_priv->depth_pitch = init->depth_pitch;
- dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) |
- (dev_priv->front_offset >> 10));
- dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) |
- (dev_priv->back_offset >> 10));
- dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) |
- (dev_priv->depth_offset >> 10));
-
/* Hardware state for depth clears. Remove this if/when we no
* longer clear the depth buffer with a 3D rectangle. Hard-code
* all values to prevent unwanted 3D state from slipping through
@@ -1204,9 +1198,26 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init )
dev_priv->buffers->handle );
}
+ dev_priv->fb_location = ( RADEON_READ( RADEON_MC_FB_LOCATION )
+ & 0xffff ) << 16;
+
+ dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) |
+ ( ( dev_priv->front_offset
+ + dev_priv->fb_location ) >> 10 ) );
+
+ dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) |
+ ( ( dev_priv->back_offset
+ + dev_priv->fb_location ) >> 10 ) );
+
+ dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) |
+ ( ( dev_priv->depth_offset
+ + dev_priv->fb_location ) >> 10 ) );
+
dev_priv->gart_size = init->gart_size;
- dev_priv->gart_vm_start = RADEON_READ( RADEON_CONFIG_APER_SIZE );
+ dev_priv->gart_vm_start = dev_priv->fb_location
+ + RADEON_READ( RADEON_CONFIG_APER_SIZE );
+
#if __REALLY_HAVE_AGP
if ( !dev_priv->is_pci )
dev_priv->gart_buffers_offset = (dev_priv->buffers->offset
diff --git a/shared/radeon_drm.h b/shared/radeon_drm.h
index c4a74649..f56b188d 100644
--- a/shared/radeon_drm.h
+++ b/shared/radeon_drm.h
@@ -390,6 +390,7 @@ typedef struct {
#define DRM_IOCTL_RADEON_IRQ_WAIT DRM_IOW( 0x57, drm_radeon_irq_wait_t)
/* added by Charl P. Botha - see radeon_cp.c for details */
#define DRM_IOCTL_RADEON_CP_RESUME DRM_IO(0x58)
+#define DRM_IOCTL_RADEON_SETPARAM DRM_IOW(0x59, drm_radeon_setparam_t)
typedef struct drm_radeon_init {
enum {
@@ -502,7 +503,7 @@ typedef struct drm_radeon_tex_image {
} drm_radeon_tex_image_t;
typedef struct drm_radeon_texture {
- int offset;
+ unsigned int offset;
int pitch;
int format;
int width; /* Texture image coordinates */
@@ -537,6 +538,7 @@ typedef struct drm_radeon_indirect {
#define RADEON_PARAM_STATUS_HANDLE 8
#define RADEON_PARAM_SAREA_HANDLE 9
#define RADEON_PARAM_GART_TEX_HANDLE 10
+#define RADEON_PARAM_SCRATCH_OFFSET 11
typedef struct drm_radeon_getparam {
int param;
@@ -578,4 +580,16 @@ typedef struct drm_radeon_irq_wait {
} drm_radeon_irq_wait_t;
+/* 1.10: Clients tell the DRM where they think the framebuffer is located in
+ * the card's address space, via a new generic ioctl to set parameters
+ */
+
+typedef struct drm_radeon_setparam {
+ unsigned int param;
+ int64_t value;
+} drm_radeon_setparam_t;
+
+#define RADEON_SETPARAM_FB_LOCATION 1 /* determined framebuffer location */
+
+
#endif
diff --git a/shared/radeon_drv.h b/shared/radeon_drv.h
index fd23aa28..1569caa7 100644
--- a/shared/radeon_drv.h
+++ b/shared/radeon_drv.h
@@ -73,6 +73,8 @@ typedef struct drm_radeon_private {
drm_radeon_ring_buffer_t ring;
drm_radeon_sarea_t *sarea_priv;
+ u32 fb_location;
+
int gart_size;
u32 gart_vm_start;
unsigned long gart_buffers_offset;
@@ -184,6 +186,7 @@ extern int radeon_cp_indirect( DRM_IOCTL_ARGS );
extern int radeon_cp_vertex2( DRM_IOCTL_ARGS );
extern int radeon_cp_cmdbuf( DRM_IOCTL_ARGS );
extern int radeon_cp_getparam( DRM_IOCTL_ARGS );
+extern int radeon_cp_setparam( DRM_IOCTL_ARGS );
extern int radeon_cp_flip( DRM_IOCTL_ARGS );
extern int radeon_mem_alloc( DRM_IOCTL_ARGS );
@@ -239,6 +242,7 @@ extern void radeon_do_release(drm_device_t *dev);
#define RADEON_CRTC2_OFFSET 0x0324
#define RADEON_CRTC2_OFFSET_CNTL 0x0328
+#define RADEON_RB3D_COLOROFFSET 0x1c40
#define RADEON_RB3D_COLORPITCH 0x1c48
#define RADEON_DP_GUI_MASTER_CNTL 0x146c
@@ -332,6 +336,7 @@ extern void radeon_do_release(drm_device_t *dev);
#define RADEON_PP_MISC 0x1c14
#define RADEON_PP_ROT_MATRIX_0 0x1d58
#define RADEON_PP_TXFILTER_0 0x1c54
+#define RADEON_PP_TXOFFSET_0 0x1c5c
#define RADEON_PP_TXFILTER_1 0x1c6c
#define RADEON_PP_TXFILTER_2 0x1c84
diff --git a/shared/radeon_state.c b/shared/radeon_state.c
index 833f9698..e24bee8a 100644
--- a/shared/radeon_state.c
+++ b/shared/radeon_state.c
@@ -36,6 +36,151 @@
/* ================================================================
+ * Helper functions for client state checking and fixup
+ */
+
+static __inline__ int radeon_check_and_fixup_offset( drm_radeon_private_t *dev_priv,
+ drm_file_t *filp_priv,
+ u32 *offset ) {
+ u32 off = *offset;
+
+ if ( off >= dev_priv->fb_location &&
+ off < ( dev_priv->gart_vm_start + dev_priv->gart_size ) )
+ return 0;
+
+ off += filp_priv->radeon_fb_delta;
+
+ DRM_DEBUG( "offset fixed up to 0x%x\n", off );
+
+ if ( off < dev_priv->fb_location ||
+ off >= ( dev_priv->gart_vm_start + dev_priv->gart_size ) )
+ return DRM_ERR( EINVAL );
+
+ *offset = off;
+
+ return 0;
+}
+
+static __inline__ int radeon_check_and_fixup_offset_user( drm_radeon_private_t *dev_priv,
+ drm_file_t *filp_priv,
+ u32 *offset ) {
+ u32 off;
+
+ DRM_GET_USER_UNCHECKED( off, offset );
+
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &off ) )
+ return DRM_ERR( EINVAL );
+
+ DRM_PUT_USER_UNCHECKED( offset, off );
+
+ return 0;
+}
+
+static __inline__ int radeon_check_and_fixup_packets( drm_radeon_private_t *dev_priv,
+ drm_file_t *filp_priv,
+ int id,
+ u32 *data ) {
+ if ( id == RADEON_EMIT_PP_MISC &&
+ radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+ &data[( RADEON_RB3D_DEPTHOFFSET
+ - RADEON_PP_MISC ) / 4] ) ) {
+ DRM_ERROR( "Invalid depth buffer offset\n" );
+ return DRM_ERR( EINVAL );
+ } else if ( id == RADEON_EMIT_PP_CNTL &&
+ radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+ &data[( RADEON_RB3D_COLOROFFSET
+ - RADEON_PP_CNTL ) / 4] ) ) {
+ DRM_ERROR( "Invalid colour buffer offset\n" );
+ return DRM_ERR( EINVAL );
+ } else if ( id >= R200_EMIT_PP_TXOFFSET_0 &&
+ id <= R200_EMIT_PP_TXOFFSET_5 &&
+ radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+ &data[0] ) ) {
+ DRM_ERROR( "Invalid R200 texture offset\n" );
+ return DRM_ERR( EINVAL );
+ } else if ( ( id == RADEON_EMIT_PP_TXFILTER_0 || id == RADEON_EMIT_PP_TXFILTER_1 ||
+ id == RADEON_EMIT_PP_TXFILTER_2 /*|| id == RADEON_EMIT_PP_TXFILTER_3 ||
+ id == RADEON_EMIT_PP_TXFILTER_4 || id == RADEON_EMIT_PP_TXFILTER_5*/ ) &&
+ radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+ &data[( RADEON_PP_TXOFFSET_0
+ - RADEON_PP_TXFILTER_0 ) / 4] ) ) {
+ DRM_ERROR( "Invalid R100 texture offset\n" );
+ return DRM_ERR( EINVAL );
+ } else if ( id == R200_PP_CUBIC_OFFSET_F1_0 || id == R200_PP_CUBIC_OFFSET_F1_1 ||
+ id == R200_PP_CUBIC_OFFSET_F1_2 || id == R200_PP_CUBIC_OFFSET_F1_3 ||
+ id == R200_PP_CUBIC_OFFSET_F1_4 || id == R200_PP_CUBIC_OFFSET_F1_5 ) {
+ int i;
+ for ( i = 0; i < 6; i++ ) {
+ if ( radeon_check_and_fixup_offset_user( dev_priv,
+ filp_priv,
+ &data[i] ) ) {
+ DRM_ERROR( "Invalid R200 cubic texture offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+ }
+ }
+
+ return 0;
+}
+
+static __inline__ int radeon_check_and_fixup_packet3( drm_radeon_private_t *dev_priv,
+ drm_file_t *filp_priv,
+ drm_radeon_cmd_buffer_t *cmdbuf,
+ unsigned int *cmdsz ) {
+ u32 tmp[4], *cmd = ( u32* )cmdbuf->buf;
+
+ if ( DRM_COPY_FROM_USER_UNCHECKED( tmp, cmd, sizeof( tmp ) ) ) {
+ DRM_ERROR( "Failed to copy data from user space\n" );
+ return DRM_ERR( EFAULT );
+ }
+
+ *cmdsz = 2 + ( ( tmp[0] & RADEON_CP_PACKET_COUNT_MASK ) >> 16 );
+
+ if ( ( tmp[0] & 0xc0000000 ) != RADEON_CP_PACKET3 ) {
+ DRM_ERROR( "Not a type 3 packet\n" );
+ return DRM_ERR( EINVAL );
+ }
+
+ if ( 4 * *cmdsz > cmdbuf->bufsz ) {
+ DRM_ERROR( "Packet size larger than size of data provided\n" );
+ return DRM_ERR( EINVAL );
+ }
+
+ /* Check client state and fix it up if necessary */
+ if ( tmp[0] & 0x8000 ) { /* MSB of opcode: next DWORD GUI_CNTL */
+ u32 offset;
+
+ if ( tmp[1] & ( RADEON_GMC_SRC_PITCH_OFFSET_CNTL
+ | RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) {
+ offset = tmp[2] << 10;
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &offset ) ) {
+ DRM_ERROR( "Invalid first packet offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+ tmp[2] = ( tmp[2] & 0xffc00000 ) | offset >> 10;
+ }
+
+ if ( ( tmp[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL ) &&
+ ( tmp[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) {
+ offset = tmp[3] << 10;
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &offset ) ) {
+ DRM_ERROR( "Invalid second packet offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+ tmp[3] = ( tmp[3] & 0xffc00000 ) | offset >> 10;
+ }
+
+ if ( DRM_COPY_TO_USER_UNCHECKED( cmd, tmp, sizeof( tmp ) ) ) {
+ DRM_ERROR( "Failed to copy data to user space\n" );
+ return DRM_ERR( EFAULT );
+ }
+ }
+
+ return 0;
+}
+
+
+/* ================================================================
* CP hardware state programming functions
*/
@@ -57,15 +202,28 @@ static __inline__ void radeon_emit_clip_rect( drm_radeon_private_t *dev_priv,
/* Emit 1.1 state
*/
-static void radeon_emit_state( drm_radeon_private_t *dev_priv,
- drm_radeon_context_regs_t *ctx,
- drm_radeon_texture_regs_t *tex,
- unsigned int dirty )
+static int radeon_emit_state( drm_radeon_private_t *dev_priv,
+ drm_file_t *filp_priv,
+ drm_radeon_context_regs_t *ctx,
+ drm_radeon_texture_regs_t *tex,
+ unsigned int dirty )
{
RING_LOCALS;
DRM_DEBUG( "dirty=0x%08x\n", dirty );
if ( dirty & RADEON_UPLOAD_CONTEXT ) {
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+ &ctx->rb3d_depthoffset ) ) {
+ DRM_ERROR( "Invalid depth buffer offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+ &ctx->rb3d_coloroffset ) ) {
+ DRM_ERROR( "Invalid depth buffer offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+
BEGIN_RING( 14 );
OUT_RING( CP_PACKET0( RADEON_PP_MISC, 6 ) );
OUT_RING( ctx->pp_misc );
@@ -149,6 +307,12 @@ static void radeon_emit_state( drm_radeon_private_t *dev_priv,
}
if ( dirty & RADEON_UPLOAD_TEX0 ) {
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+ &tex[0].pp_txoffset ) ) {
+ DRM_ERROR( "Invalid texture offset for unit 0\n" );
+ return DRM_ERR( EINVAL );
+ }
+
BEGIN_RING( 9 );
OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_0, 5 ) );
OUT_RING( tex[0].pp_txfilter );
@@ -163,6 +327,12 @@ static void radeon_emit_state( drm_radeon_private_t *dev_priv,
}
if ( dirty & RADEON_UPLOAD_TEX1 ) {
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+ &tex[1].pp_txoffset ) ) {
+ DRM_ERROR( "Invalid texture offset for unit 1\n" );
+ return DRM_ERR( EINVAL );
+ }
+
BEGIN_RING( 9 );
OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_1, 5 ) );
OUT_RING( tex[1].pp_txfilter );
@@ -177,6 +347,12 @@ static void radeon_emit_state( drm_radeon_private_t *dev_priv,
}
if ( dirty & RADEON_UPLOAD_TEX2 ) {
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+ &tex[2].pp_txoffset ) ) {
+ DRM_ERROR( "Invalid texture offset for unit 2\n" );
+ return DRM_ERR( EINVAL );
+ }
+
BEGIN_RING( 9 );
OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_2, 5 ) );
OUT_RING( tex[2].pp_txfilter );
@@ -189,12 +365,15 @@ static void radeon_emit_state( drm_radeon_private_t *dev_priv,
OUT_RING( tex[2].pp_border_color );
ADVANCE_RING();
}
+
+ return 0;
}
/* Emit 1.2 state
*/
-static void radeon_emit_state2( drm_radeon_private_t *dev_priv,
- drm_radeon_state_t *state )
+static int radeon_emit_state2( drm_radeon_private_t *dev_priv,
+ drm_file_t *filp_priv,
+ drm_radeon_state_t *state )
{
RING_LOCALS;
@@ -206,7 +385,7 @@ static void radeon_emit_state2( drm_radeon_private_t *dev_priv,
ADVANCE_RING();
}
- radeon_emit_state( dev_priv, &state->context,
+ return radeon_emit_state( dev_priv, filp_priv, &state->context,
state->tex, state->dirty );
}
@@ -1065,6 +1244,7 @@ static int radeon_cp_dispatch_texture( DRMFILE filp,
drm_radeon_tex_image_t *image )
{
drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_file_t *filp_priv;
drm_buf_t *buf;
u32 format;
u32 *buffer;
@@ -1074,6 +1254,13 @@ static int radeon_cp_dispatch_texture( DRMFILE filp,
int i;
RING_LOCALS;
+ DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &tex->offset ) ) {
+ DRM_ERROR( "Invalid destination offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+
dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
/* Flush the pixel cache. This ensures no pixel data gets mixed
@@ -1377,6 +1564,7 @@ int radeon_cp_vertex( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_file_t *filp_priv;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_device_dma_t *dma = dev->dma;
drm_buf_t *buf;
@@ -1390,6 +1578,8 @@ int radeon_cp_vertex( DRM_IOCTL_ARGS )
return DRM_ERR(EINVAL);
}
+ DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
DRM_COPY_FROM_USER_IOCTL( vertex, (drm_radeon_vertex_t *)data,
sizeof(vertex) );
@@ -1429,11 +1619,14 @@ int radeon_cp_vertex( DRM_IOCTL_ARGS )
buf->used = vertex.count; /* not used? */
if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
- radeon_emit_state( dev_priv,
- &sarea_priv->context_state,
- sarea_priv->tex_state,
- sarea_priv->dirty );
-
+ if ( radeon_emit_state( dev_priv, filp_priv,
+ &sarea_priv->context_state,
+ sarea_priv->tex_state,
+ sarea_priv->dirty ) ) {
+ DRM_ERROR( "radeon_emit_state failed\n" );
+ return DRM_ERR( EINVAL );
+ }
+
sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
RADEON_UPLOAD_TEX1IMAGES |
RADEON_UPLOAD_TEX2IMAGES |
@@ -1461,6 +1654,7 @@ int radeon_cp_indices( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_file_t *filp_priv;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_device_dma_t *dma = dev->dma;
drm_buf_t *buf;
@@ -1475,6 +1669,8 @@ int radeon_cp_indices( DRM_IOCTL_ARGS )
return DRM_ERR(EINVAL);
}
+ DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
DRM_COPY_FROM_USER_IOCTL( elts, (drm_radeon_indices_t *)data,
sizeof(elts) );
@@ -1523,10 +1719,13 @@ int radeon_cp_indices( DRM_IOCTL_ARGS )
buf->used = elts.end;
if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
- radeon_emit_state( dev_priv,
- &sarea_priv->context_state,
- sarea_priv->tex_state,
- sarea_priv->dirty );
+ if ( radeon_emit_state( dev_priv, filp_priv,
+ &sarea_priv->context_state,
+ sarea_priv->tex_state,
+ sarea_priv->dirty ) ) {
+ DRM_ERROR( "radeon_emit_state failed\n" );
+ return DRM_ERR( EINVAL );
+ }
sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
RADEON_UPLOAD_TEX1IMAGES |
@@ -1686,6 +1885,7 @@ int radeon_cp_vertex2( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_file_t *filp_priv;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_device_dma_t *dma = dev->dma;
drm_buf_t *buf;
@@ -1700,6 +1900,8 @@ int radeon_cp_vertex2( DRM_IOCTL_ARGS )
return DRM_ERR(EINVAL);
}
+ DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
DRM_COPY_FROM_USER_IOCTL( vertex, (drm_radeon_vertex2_t *)data,
sizeof(vertex) );
@@ -1747,7 +1949,10 @@ int radeon_cp_vertex2( DRM_IOCTL_ARGS )
sizeof(state) ) )
return DRM_ERR(EFAULT);
- radeon_emit_state2( dev_priv, &state );
+ if ( radeon_emit_state2( dev_priv, filp_priv, &state ) ) {
+ DRM_ERROR( "radeon_emit_state2 failed\n" );
+ return DRM_ERR( EINVAL );
+ }
laststate = prim.stateidx;
}
@@ -1784,6 +1989,7 @@ int radeon_cp_vertex2( DRM_IOCTL_ARGS )
static int radeon_emit_packets(
drm_radeon_private_t *dev_priv,
+ drm_file_t *filp_priv,
drm_radeon_cmd_header_t header,
drm_radeon_cmd_buffer_t *cmdbuf )
{
@@ -1798,8 +2004,15 @@ static int radeon_emit_packets(
sz = packet[id].len;
reg = packet[id].start;
- if (sz * sizeof(int) > cmdbuf->bufsz)
+ if (sz * sizeof(int) > cmdbuf->bufsz) {
+ DRM_ERROR( "Packet size provided larger than data provided\n" );
return DRM_ERR(EINVAL);
+ }
+
+ if ( radeon_check_and_fixup_packets( dev_priv, filp_priv, id, data ) ) {
+ DRM_ERROR( "Packet verification failed\n" );
+ return DRM_ERR( EINVAL );
+ }
BEGIN_RING(sz+1);
OUT_RING( CP_PACKET0( reg, (sz-1) ) );
@@ -1882,24 +2095,21 @@ static __inline__ int radeon_emit_vectors(
static int radeon_emit_packet3( drm_device_t *dev,
+ drm_file_t *filp_priv,
drm_radeon_cmd_buffer_t *cmdbuf )
{
drm_radeon_private_t *dev_priv = dev->dev_private;
- int cmdsz, tmp;
- int *cmd = (int *)cmdbuf->buf;
+ unsigned int cmdsz;
+ int *cmd = (int *)cmdbuf->buf, ret;
RING_LOCALS;
-
DRM_DEBUG("\n");
- if (DRM_GET_USER_UNCHECKED( tmp, &cmd[0]))
- return DRM_ERR(EFAULT);
-
- cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16);
-
- if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 ||
- cmdsz * 4 > cmdbuf->bufsz)
- return DRM_ERR(EINVAL);
+ if ( ( ret = radeon_check_and_fixup_packet3( dev_priv, filp_priv,
+ cmdbuf, &cmdsz ) ) ) {
+ DRM_ERROR( "Packet verification failed\n" );
+ return ret;
+ }
BEGIN_RING( cmdsz );
OUT_RING_USER_TABLE( cmd, cmdsz );
@@ -1912,27 +2122,25 @@ static int radeon_emit_packet3( drm_device_t *dev,
static int radeon_emit_packet3_cliprect( drm_device_t *dev,
+ drm_file_t *filp_priv,
drm_radeon_cmd_buffer_t *cmdbuf,
int orig_nbox )
{
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_clip_rect_t box;
- int cmdsz, tmp;
- int *cmd = (int *)cmdbuf->buf;
+ unsigned int cmdsz;
+ int *cmd = (int *)cmdbuf->buf, ret;
drm_clip_rect_t *boxes = cmdbuf->boxes;
int i = 0;
RING_LOCALS;
DRM_DEBUG("\n");
- if (DRM_GET_USER_UNCHECKED( tmp, &cmd[0]))
- return DRM_ERR(EFAULT);
-
- cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16);
-
- if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 ||
- cmdsz * 4 > cmdbuf->bufsz)
- return DRM_ERR(EINVAL);
+ if ( ( ret = radeon_check_and_fixup_packet3( dev_priv, filp_priv,
+ cmdbuf, &cmdsz ) ) ) {
+ DRM_ERROR( "Packet verification failed\n" );
+ return ret;
+ }
if (!orig_nbox)
goto out;
@@ -2009,6 +2217,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_file_t *filp_priv;
drm_device_dma_t *dma = dev->dma;
drm_buf_t *buf = 0;
int idx;
@@ -2023,6 +2232,8 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
return DRM_ERR(EINVAL);
}
+ DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
DRM_COPY_FROM_USER_IOCTL( cmdbuf, (drm_radeon_cmd_buffer_t *)data,
sizeof(cmdbuf) );
@@ -2053,7 +2264,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
switch (header.header.cmd_type) {
case RADEON_CMD_PACKET:
DRM_DEBUG("RADEON_CMD_PACKET\n");
- if (radeon_emit_packets( dev_priv, header, &cmdbuf )) {
+ if (radeon_emit_packets( dev_priv, filp_priv, header, &cmdbuf )) {
DRM_ERROR("radeon_emit_packets failed\n");
return DRM_ERR(EINVAL);
}
@@ -2096,7 +2307,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
case RADEON_CMD_PACKET3:
DRM_DEBUG("RADEON_CMD_PACKET3\n");
- if (radeon_emit_packet3( dev, &cmdbuf )) {
+ if (radeon_emit_packet3( dev, filp_priv, &cmdbuf )) {
DRM_ERROR("radeon_emit_packet3 failed\n");
return DRM_ERR(EINVAL);
}
@@ -2104,7 +2315,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
case RADEON_CMD_PACKET3_CLIP:
DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
- if (radeon_emit_packet3_cliprect( dev, &cmdbuf, orig_nbox )) {
+ if (radeon_emit_packet3_cliprect( dev, filp_priv, &cmdbuf, orig_nbox )) {
DRM_ERROR("radeon_emit_packet3_clip failed\n");
return DRM_ERR(EINVAL);
}
@@ -2203,3 +2414,31 @@ int radeon_cp_getparam( DRM_IOCTL_ARGS )
return 0;
}
+
+int radeon_cp_setparam( DRM_IOCTL_ARGS ) {
+ DRM_DEVICE;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_file_t *filp_priv;
+ drm_radeon_setparam_t sp;
+
+ if ( !dev_priv ) {
+ DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+ return DRM_ERR( EINVAL );
+ }
+
+ DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
+ DRM_COPY_FROM_USER_IOCTL( sp, ( drm_radeon_setparam_t* )data,
+ sizeof( sp ) );
+
+ switch( sp.param ) {
+ case RADEON_SETPARAM_FB_LOCATION:
+ filp_priv->radeon_fb_delta = dev_priv->fb_location - sp.value;
+ break;
+ default:
+ DRM_DEBUG( "Invalid parameter %d\n", sp.param );
+ return DRM_ERR( EINVAL );
+ }
+
+ return 0;
+}