git: 682b069c5c56 - main - iicbus: add compat32 support for I2C ioctls
Date: Fri, 01 Dec 2023 01:33:55 UTC
The branch main has been updated by stevek:
URL: https://cgit.FreeBSD.org/src/commit/?id=682b069c5c5643d26199cc1b65717f99c98bce9d
commit 682b069c5c5643d26199cc1b65717f99c98bce9d
Author: Stephen J. Kiernan <stevek@FreeBSD.org>
AuthorDate: 2023-11-29 19:20:45 +0000
Commit: Stephen J. Kiernan <stevek@FreeBSD.org>
CommitDate: 2023-12-01 01:33:46 +0000
iicbus: add compat32 support for I2C ioctls
Some of the I2C ioctl request structures contain pointers and need to
handle requests from 32-bit applications on 64-bit kernels.
Obtained from: Juniper Networks, Inc.
Differential Revision: https://reviews.freebsd.org/D42836
---
sys/dev/iicbus/iic.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 108 insertions(+), 3 deletions(-)
diff --git a/sys/dev/iicbus/iic.c b/sys/dev/iicbus/iic.c
index baaa7a096a14..8c9dbb6bc145 100644
--- a/sys/dev/iicbus/iic.c
+++ b/sys/dev/iicbus/iic.c
@@ -2,6 +2,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1998, 2001 Nicolas Souchu
+ * Copyright (c) 2023 Juniper Networks, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,6 +28,7 @@
*
*/
#include <sys/param.h>
+#include <sys/abi_compat.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
@@ -57,6 +59,30 @@ struct iic_cdevpriv {
uint8_t addr;
};
+#ifdef COMPAT_FREEBSD32
+struct iic_msg32 {
+ uint16_t slave;
+ uint16_t flags;
+ uint16_t len;
+ uint32_t buf;
+};
+
+struct iiccmd32 {
+ u_char slave;
+ uint32_t count;
+ uint32_t last;
+ uint32_t buf;
+};
+
+struct iic_rdwr_data32 {
+ uint32_t msgs;
+ uint32_t nmsgs;
+};
+
+#define I2CWRITE32 _IOW('i', 4, struct iiccmd32)
+#define I2CREAD32 _IOW('i', 5, struct iiccmd32)
+#define I2CRDWR32 _IOW('i', 6, struct iic_rdwr_data32)
+#endif
#define IIC_LOCK(cdp) sx_xlock(&(cdp)->lock)
#define IIC_UNLOCK(cdp) sx_xunlock(&(cdp)->lock)
@@ -70,7 +96,7 @@ static void iic_identify(driver_t *driver, device_t parent);
static void iicdtor(void *data);
static int iicuio_move(struct iic_cdevpriv *priv, struct uio *uio, int last);
static int iicuio(struct cdev *dev, struct uio *uio, int ioflag);
-static int iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags);
+static int iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags, bool compat32);
static device_method_t iic_methods[] = {
/* device interface */
@@ -285,9 +311,36 @@ iicuio(struct cdev *dev, struct uio *uio, int ioflag)
return (error);
}
+#ifdef COMPAT_FREEBSD32
+static int
+iic_copyinmsgs32(struct iic_rdwr_data *d, struct iic_msg *buf)
+{
+ struct iic_msg32 msg32;
+ struct iic_msg32 *m32;
+ int error, i;
+
+ m32 = (struct iic_msg32 *)d->msgs;
+ for (i = 0; i < d->nmsgs; i++) {
+ error = copyin(&m32[i], &msg32, sizeof(msg32));
+ if (error != 0)
+ return (error);
+ CP(msg32, buf[i], slave);
+ CP(msg32, buf[i], flags);
+ CP(msg32, buf[i], len);
+ PTRIN_CP(msg32, buf[i], buf);
+ }
+ return (0);
+}
+#endif
+
static int
-iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags)
+iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags,
+ bool compat32 __unused)
{
+#ifdef COMPAT_FREEBSD32
+ struct iic_rdwr_data dswab;
+ struct iic_rdwr_data32 *d32;
+#endif
struct iic_msg *buf, *m;
void **usrbufs;
device_t iicdev, parent;
@@ -297,12 +350,25 @@ iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags)
iicdev = priv->sc->sc_dev;
parent = device_get_parent(iicdev);
error = 0;
+#ifdef COMPAT_FREEBSD32
+ if (compat32) {
+ d32 = (struct iic_rdwr_data32 *)d;
+ PTRIN_CP(*d32, dswab, msgs);
+ CP(*d32, dswab, nmsgs);
+ d = &dswab;
+ }
+#endif
if (d->nmsgs > IIC_RDRW_MAX_MSGS)
return (EINVAL);
buf = malloc(sizeof(*d->msgs) * d->nmsgs, M_IIC, M_WAITOK);
+#ifdef COMPAT_FREEBSD32
+ if (compat32)
+ error = iic_copyinmsgs32(d, buf);
+ else
+#endif
error = copyin(d->msgs, buf, sizeof(*d->msgs) * d->nmsgs);
if (error != 0) {
free(buf, M_IIC);
@@ -355,14 +421,24 @@ iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags)
static int
iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td)
{
+#ifdef COMPAT_FREEBSD32
+ struct iiccmd iicswab;
+#endif
device_t parent, iicdev;
struct iiccmd *s;
+#ifdef COMPAT_FREEBSD32
+ struct iiccmd32 *s32;
+#endif
struct uio ubuf;
struct iovec uvec;
struct iic_cdevpriv *priv;
int error;
+ bool compat32;
s = (struct iiccmd *)data;
+#ifdef COMPAT_FREEBSD32
+ s32 = (struct iiccmd32 *)data;
+#endif
error = devfs_get_cdevpriv((void**)&priv);
if (error != 0)
return (error);
@@ -373,6 +449,20 @@ iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t
parent = device_get_parent(iicdev);
IIC_LOCK(priv);
+#ifdef COMPAT_FREEBSD32
+ switch (cmd) {
+ case I2CWRITE32:
+ case I2CREAD32:
+ CP(*s32, iicswab, slave);
+ CP(*s32, iicswab, count);
+ CP(*s32, iicswab, last);
+ PTRIN_CP(*s32, iicswab, buf);
+ s = &iicswab;
+ break;
+ default:
+ break;
+ }
+#endif
switch (cmd) {
case I2CSTART:
@@ -428,6 +518,9 @@ iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t
break;
case I2CWRITE:
+#ifdef COMPAT_FREEBSD32
+ case I2CWRITE32:
+#endif
if (!priv->started) {
error = EINVAL;
break;
@@ -445,6 +538,9 @@ iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t
break;
case I2CREAD:
+#ifdef COMPAT_FREEBSD32
+ case I2CREAD32:
+#endif
if (!priv->started) {
error = EINVAL;
break;
@@ -461,6 +557,9 @@ iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t
error = iicuio_move(priv, &ubuf, s->last);
break;
+#ifdef COMPAT_FREEBSD32
+ case I2CRDWR32:
+#endif
case I2CRDWR:
/*
* The rdwr list should be a self-contained set of
@@ -471,7 +570,13 @@ iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t
break;
}
- error = iicrdwr(priv, (struct iic_rdwr_data *)data, flags);
+#ifdef COMPAT_FREEBSD32
+ compat32 = (cmd == I2CRDWR32);
+#else
+ compat32 = false;
+#endif
+ error = iicrdwr(priv, (struct iic_rdwr_data *)data, flags,
+ compat32);
break;