Hi!

In order to be able for dri clients to write to certain registers when
direct write-access to the MMIO area of the unichrome is shut down, I've
added an IOCTL to Erdi's dma interface.

It has a very simple "parser" that denies access to register areas that
might be dangerous. The 2d blitter can supposedly access "system memory",
but this seems to be an MMIO mapped blitter aperture of the video chip
rather than AGP or "normal" system memory, like in the XAA howto.

The purpose is twofold:

1. If the X server fails to allocate AGP memory, dri can use PCI, at least
for 2d engine access and mpeg2.

2. The video accelerator (color transform and scaling) is not accessible
through AGP DMA, and can be written to using this IOCTL.

The command buffer syntax follows that for AGP DMA 2d engine writes, so
that it is possible to just use another IOCTL for PCI writes with the same
buffer contents.

Could this be acceptable security-wise?

/Thomas


? diffile
Index: via_dma.c
===================================================================
RCS file: /cvs/dri/drm/shared/via_dma.c,v
retrieving revision 1.4
diff -u -r1.4 via_dma.c
--- via_dma.c	30 Aug 2004 04:58:24 -0000	1.4
+++ via_dma.c	2 Sep 2004 13:48:45 -0000
@@ -223,6 +223,90 @@
 	return 0;
 }
 
+static int via_parse_pci_cmdbuffer( drm_device_t *dev, const char *buf, 
+				    unsigned int size )
+{
+	drm_via_private_t *dev_priv = dev->dev_private;
+	uint32_t offset, value;
+	const uint32_t *regbuf = (uint32_t *)buf;
+	unsigned int i;
+
+	size >>=3 ;
+	for (i=0; i<size; ++i) {
+		offset = (*regbuf++ & 0x0FFFFFFF) << 2;
+		value = *regbuf++;
+		if ((offset > 0x7FF) && ((offset < 0xC00))) {
+			DRM_DEBUG("Attempt to access Burst Command Area.\n");
+			return DRM_ERR( EINVAL );
+		} else if ((offset > 0xDFF)) {
+			DRM_DEBUG("Attempt to access DMA or VGA registers.\n");
+			return DRM_ERR( EINVAL );
+		}
+	}
+			
+	regbuf = (uint32_t *)buf;
+	via_quiescent(dev); 	
+	for ( i=0; i<size; ++i ) {
+		offset = (*regbuf++ & 0x0FFFFFFF) << 2;
+		value = *regbuf++;
+		VIA_WRITE( offset, value );
+	}
+	return 0;
+}
+		
+static int via_dispatch_pci_cmdbuffer(drm_device_t *dev, 
+				      drm_via_cmdbuffer_t *cmd )
+{
+	drm_via_private_t *dev_priv = dev->dev_private;
+	char *hugebuf;
+	int ret;
+
+	/*
+	 * We must be able to parse the buffer all at a time, so as
+	 * to return an error on an invalid operation without doing
+	 * anything.
+	 * Small buffers must, on the other hand be handled fast.
+	 */
+
+	if ( cmd->size > VIA_PREALLOCATED_PCI_SIZE ) {
+	  if (NULL == (hugebuf = (char *) kmalloc( cmd-> size, GFP_KERNEL )))
+			return DRM_ERR( ENOMEM );
+		DRM_COPY_FROM_USER( hugebuf, cmd->buf, cmd->size );
+		ret = via_parse_pci_cmdbuffer( dev, hugebuf, cmd->size );
+		kfree( hugebuf );
+	} else {
+		DRM_COPY_FROM_USER( dev_priv->pci_buf, cmd->buf, cmd->size );
+		ret = via_parse_pci_cmdbuffer( dev, dev_priv->pci_buf, cmd->size );
+	}
+	return ret;
+}
+
+
+
+int via_pci_cmdbuffer( DRM_IOCTL_ARGS )
+{
+	DRM_DEVICE;
+	drm_via_cmdbuffer_t cmdbuf;
+	int ret;
+
+	DRM_COPY_FROM_USER_IOCTL( cmdbuf, (drm_via_cmdbuffer_t *)data, 
+			sizeof(cmdbuf) );
+
+	DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf.buf, cmdbuf.size);
+
+	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("via_cmdbuffer called without lock held\n");
+		return DRM_ERR(EINVAL);
+	}
+
+	ret = via_dispatch_pci_cmdbuffer( dev, &cmdbuf );
+	if (ret) {
+		return ret;
+	}
+
+	return 0;
+}
+
 
 
 
Index: via_drm.h
===================================================================
RCS file: /cvs/dri/drm/shared/via_drm.h,v
retrieving revision 1.3
diff -u -r1.3 via_drm.h
--- via_drm.h	24 Aug 2004 01:44:37 -0000	1.3
+++ via_drm.h	2 Sep 2004 13:48:45 -0000
@@ -38,6 +38,7 @@
 #define VIA_NR_XVMC_PORTS               10
 #define VIA_NR_XVMC_LOCKS               5
 #define VIA_MAX_CACHELINE_SIZE          64
+#define VIA_PREALLOCATED_PCI_SIZE       32768
 #define XVMCLOCKPTR(saPriv,lockNo)					\
         ((volatile int *)(((((unsigned long) (saPriv)->XvMCLockArea) +	\
                             (VIA_MAX_CACHELINE_SIZE - 1)) &             \
@@ -67,8 +68,10 @@
 #define DRM_IOCTL_VIA_MAP_INIT	DRM_IOWR(0x44, drm_via_init_t)
 #define DRM_IOCTL_VIA_DEC_FUTEX DRM_IOW(0x45, drm_via_futex_t)
 #define DRM_IOCTL_VIA_DMA_INIT	DRM_IOWR(0x47, drm_via_dma_init_t)
-#define DRM_IOCTL_VIA_CMDBUFFER	DRM_IOWR(0x48, drm_via_dma_init_t)
+#define DRM_IOCTL_VIA_CMDBUFFER	DRM_IOW(0x48, drm_via_cmdbuffer_t)
 #define DRM_IOCTL_VIA_FLUSH	DRM_IO(0x49)
+#define DRM_IOCTL_VIA_PCICMD	DRM_IOW(0x4A, drm_via_cmdbuffer_t)
+
 
 /* Indices into buf.Setup where various bits of state are mirrored per
  * context and per buffer.  These can be fired at the card as a unit,
@@ -200,6 +203,7 @@
 int via_dma_init( DRM_IOCTL_ARGS );
 int via_cmdbuffer( DRM_IOCTL_ARGS );
 int via_flush_ioctl( DRM_IOCTL_ARGS );
+int via_pci_cmdbuffer( DRM_IOCTL_ARGS );
 
 #endif
 #endif /* _VIA_DRM_H_ */
Index: via_drv.c
===================================================================
RCS file: /cvs/dri/drm/shared/via_drv.c,v
retrieving revision 1.5
diff -u -r1.5 via_drv.c
--- via_drv.c	24 Aug 2004 11:15:53 -0000	1.5
+++ via_drv.c	2 Sep 2004 13:48:45 -0000
@@ -21,6 +21,7 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
+
 #include <linux/config.h>
 #include "via.h"
 #include "drmP.h"
@@ -47,7 +48,8 @@
         [DRM_IOCTL_NR(DRM_IOCTL_VIA_DEC_FUTEX)] = { via_decoder_futex, 1, 0}, \
         [DRM_IOCTL_NR(DRM_IOCTL_VIA_DMA_INIT)] = { via_dma_init, 1, 0}, \
         [DRM_IOCTL_NR(DRM_IOCTL_VIA_CMDBUFFER)] = { via_cmdbuffer, 1, 0}, \
-        [DRM_IOCTL_NR(DRM_IOCTL_VIA_FLUSH)] = { via_flush_ioctl, 1, 0}
+	[DRM_IOCTL_NR(DRM_IOCTL_VIA_FLUSH)] = { via_flush_ioctl, 1, 0}, \
+        [DRM_IOCTL_NR(DRM_IOCTL_VIA_PCICMD)] = { via_pci_cmdbuffer, 1, 0}
 
 
 #define __HAVE_COUNTERS		0
Index: via_drv.h
===================================================================
RCS file: /cvs/dri/drm/shared/via_drv.h,v
retrieving revision 1.5
diff -u -r1.5 via_drv.h
--- via_drv.h	24 Aug 2004 11:15:53 -0000	1.5
+++ via_drv.h	2 Sep 2004 13:48:45 -0000
@@ -46,6 +46,7 @@
         uint32_t * last_pause_ptr;
         volatile uint32_t * hw_addr_ptr;
         drm_via_ring_buffer_t ring;
+	char pci_buf[VIA_PREALLOCATED_PCI_SIZE];
 } drm_via_private_t;
 
  

Reply via email to