diff options
Diffstat (limited to 'bsd-core')
| -rw-r--r-- | bsd-core/drm_drv.c | 74 | ||||
| -rw-r--r-- | bsd-core/drm_os_freebsd.h | 21 | 
2 files changed, 77 insertions, 18 deletions
| diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c index 8d75e698..fb0454dd 100644 --- a/bsd-core/drm_drv.c +++ b/bsd-core/drm_drv.c @@ -1221,27 +1221,83 @@ int DRM(unlock)( DRM_IOCTL_ARGS )  }  #if DRM_LINUX +#define LINUX_IOCTL_DRM_MIN		0x6400 +#define LINUX_IOCTL_DRM_MAX		0x64ff +  static linux_ioctl_function_t DRM( linux_ioctl);  static struct linux_ioctl_handler DRM( handler) = {DRM( linux_ioctl), LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX};  SYSINIT  (DRM( register),   SI_SUB_KLD, SI_ORDER_MIDDLE, linux_ioctl_register_handler, &DRM( handler));  SYSUNINIT(DRM( unregister), SI_SUB_KLD, SI_ORDER_MIDDLE, linux_ioctl_unregister_handler, &DRM( handler)); +#define LINUX_IOC_VOID	IOC_VOID +#define LINUX_IOC_IN	IOC_OUT		/* Linux has the values the other way around */ +#define LINUX_IOC_OUT	IOC_IN +  /*   * Linux emulation IOCTL   */  static int  DRM(linux_ioctl)(DRM_STRUCTPROC *p, struct linux_ioctl_args* args)  { +	u_long		cmd = args->cmd; +#define STK_PARAMS	128 +	union { +	    char stkbuf[STK_PARAMS]; +	    long align; +	} ubuf; +	caddr_t		data=NULL, memp=NULL; +	u_int		size = IOCPARM_LEN(cmd); +	int		error;  #if (__FreeBSD_version >= 500000) -    struct file		*fp = p->td_proc->p_fd->fd_ofiles[args->fd]; +	struct file	*fp;  #else -    struct file		*fp = p->p_fd->fd_ofiles[args->fd]; -#endif -    u_long		cmd = args->cmd; -    caddr_t             data = (caddr_t) args->arg; -    /* -     * Pass the ioctl off to our standard handler. -     */ -    return(fo_ioctl(fp, cmd, data, p)); +	struct file	*fp = p->p_fd->fd_ofiles[args->fd]; +#endif +	if ( size > STK_PARAMS ) { +		if ( size > IOCPARM_MAX ) +			return EINVAL; +		memp = malloc( (u_long)size, DRM(M_DRM), M_WAITOK ); +		data = memp; +	} else { +		data = ubuf.stkbuf; +	} + +	if ( cmd & LINUX_IOC_IN ) { +		if ( size ) { +			error = copyin( (caddr_t)args->arg, data, (u_int)size ); +			if (error) { +				if ( memp ) +					free( data, DRM(M_DRM) ); +				return error; +			} +		} else { +			data = (caddr_t)args->arg; +		} +	} else if ( (cmd & LINUX_IOC_OUT) && size ) { +		/* +		 * Zero the buffer so the user always +		 * gets back something deterministic. +		 */ +		bzero( data, size ); +	} else if ( cmd & LINUX_IOC_VOID ) { +		*(caddr_t *)data = (caddr_t)args->arg; +	} + +#if (__FreeBSD_version >= 500000) +	if ( (error = fget( p, args->fd, &fp )) != 0 ) { +		if ( memp ) +			free( memp, DRM(M_DRM) ); +		return (error); +	} +	error = fo_ioctl( fp, cmd, data, p->td_ucred, p ); +	fdrop( fp, p ); +#else +	error = fo_ioctl( fp, cmd, data, p ); +#endif +	if ( error == 0 && (cmd & LINUX_IOC_OUT) && size ) +		error = copyout( data, (caddr_t)args->arg, (u_int)size ); +	if ( memp ) +		free( memp, DRM(M_DRM) ); +	return error;  }  #endif /* DRM_LINUX */ diff --git a/bsd-core/drm_os_freebsd.h b/bsd-core/drm_os_freebsd.h index 23838139..6f878d4f 100644 --- a/bsd-core/drm_os_freebsd.h +++ b/bsd-core/drm_os_freebsd.h @@ -65,7 +65,6 @@  #include <sys/proc.h>  #include <machine/../linux/linux.h>  #include <machine/../linux/linux_proto.h> -#include "drm_linux.h"  #endif  #define DRM_TIME_SLICE	      (hz/20)  /* Time slice for GLXContexts	  */ @@ -140,14 +139,18 @@ do {								\  	}							\  } while (0) -#define DRM_COPY_TO_USER_IOCTL(arg1, arg2, arg3) \ -	*arg1 = arg2 -#define DRM_COPY_FROM_USER_IOCTL(arg1, arg2, arg3) \ -	arg1 = *arg2 -#define DRM_COPY_TO_USER(arg1, arg2, arg3) \ -	copyout(arg2, arg1, arg3) -#define DRM_COPY_FROM_USER(arg1, arg2, arg3) \ -	copyin(arg2, arg1, arg3) +#define DRM_COPY_TO_USER_IOCTL(user, kern, size)	\ +	if ( IOCPARM_LEN(cmd) != size)			\ +		return EINVAL;				\ +	*user = kern; +#define DRM_COPY_FROM_USER_IOCTL(kern, user, size) \ +	if ( IOCPARM_LEN(cmd) != size)			\ +		return EINVAL;				\ +	kern = *user; +#define DRM_COPY_TO_USER(user, kern, size) \ +	copyout(kern, user, size) +#define DRM_COPY_FROM_USER(kern, user, size) \ +	copyin(user, kern, size)  /* Macros for userspace access with checking readability once */  /* FIXME: can't find equivalent functionality for nocheck yet.   * It's be slower than linux, but should be correct. | 
