git: 376330aca184 - main - smbus: add compat32 support for SMB ioctls
Date: Wed, 29 Nov 2023 23:16:10 UTC
The branch main has been updated by stevek: URL: https://cgit.FreeBSD.org/src/commit/?id=376330aca1846d0f7771c16604b41bd7f6f1f14c commit 376330aca1846d0f7771c16604b41bd7f6f1f14c Author: Stephen J. Kiernan <stevek@FreeBSD.org> AuthorDate: 2023-11-29 19:33:59 +0000 Commit: Stephen J. Kiernan <stevek@FreeBSD.org> CommitDate: 2023-11-29 23:15:09 +0000 smbus: add compat32 support for SMB ioctls Some of the SMB ioctl request structures contain pointers and need to handle requests from 32-bit applications on 64-bit kernels. Obtained from: Juniper Networks, Inc. Reviewed by: kib Differential Revision: https://reviews.freebsd.org/D42837 --- sys/dev/smbus/smb.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/sys/dev/smbus/smb.c b/sys/dev/smbus/smb.c index f47fc753bbdc..ee323c835f10 100644 --- a/sys/dev/smbus/smb.c +++ b/sys/dev/smbus/smb.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 @@ -29,6 +30,7 @@ #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> +#include <sys/abi_compat.h> #include <sys/module.h> #include <sys/bus.h> #include <sys/conf.h> @@ -41,6 +43,44 @@ #include "smbus_if.h" +#ifdef COMPAT_FREEBSD32 +struct smbcmd32 { + u_char cmd; + u_char reserved; + u_short op; + union { + char byte; + char buf[2]; + short word; + } wdata; + union { + char byte; + char buf[2]; + short word; + } rdata; + int slave; + uint32_t wbuf; + int wcount; + uint32_t rbuf; + int rcount; +}; + +#define SMB_QUICK_WRITE32 _IOW('i', 1, struct smbcmd32) +#define SMB_QUICK_READ32 _IOW('i', 2, struct smbcmd32) +#define SMB_SENDB32 _IOW('i', 3, struct smbcmd32) +#define SMB_RECVB32 _IOWR('i', 4, struct smbcmd32) +#define SMB_WRITEB32 _IOW('i', 5, struct smbcmd32) +#define SMB_WRITEW32 _IOW('i', 6, struct smbcmd32) +#define SMB_READB32 _IOWR('i', 7, struct smbcmd32) +#define SMB_READW32 _IOWR('i', 8, struct smbcmd32) +#define SMB_PCALL32 _IOWR('i', 9, struct smbcmd32) +#define SMB_BWRITE32 _IOW('i', 10, struct smbcmd32) +#define SMB_BREAD32 _IOWR('i', 11, struct smbcmd32) +#define SMB_OLD_READB32 _IOW('i', 7, struct smbcmd32) +#define SMB_OLD_READW32 _IOW('i', 8, struct smbcmd32) +#define SMB_OLD_PCALL32 _IOW('i', 9, struct smbcmd32) +#endif + #define SMB_OLD_READB _IOW('i', 7, struct smbcmd) #define SMB_OLD_READW _IOW('i', 8, struct smbcmd) #define SMB_OLD_PCALL _IOW('i', 9, struct smbcmd) @@ -131,11 +171,30 @@ smb_detach(device_t dev) return (0); } +#ifdef COMPAT_FREEBSD32 +static void +smbcopyincmd32(struct smbcmd32 *uaddr, struct smbcmd *kaddr) +{ + CP(*uaddr, *kaddr, cmd); + CP(*uaddr, *kaddr, op); + CP(*uaddr, *kaddr, wdata.word); + CP(*uaddr, *kaddr, slave); + PTRIN_CP(*uaddr, *kaddr, wbuf); + CP(*uaddr, *kaddr, wcount); + PTRIN_CP(*uaddr, *kaddr, rbuf); + CP(*uaddr, *kaddr, rcount); +} +#endif + static int smbioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) { char buf[SMB_MAXBLOCKSIZE]; device_t parent; +#ifdef COMPAT_FREEBSD32 + struct smbcmd sswab; + struct smbcmd32 *s32 = (struct smbcmd32 *)data; +#endif struct smbcmd *s = (struct smbcmd *)data; struct smb_softc *sc = dev->si_drv1; device_t smbdev = sc->sc_dev; @@ -162,35 +221,81 @@ smbioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t (flags & O_NONBLOCK) ? SMB_DONTWAIT : (SMB_WAIT | SMB_INTR)))) return (error); +#ifdef COMPAT_FREEBSD32 + switch (cmd) { + case SMB_QUICK_WRITE32: + case SMB_QUICK_READ32: + case SMB_SENDB32: + case SMB_RECVB32: + case SMB_WRITEB32: + case SMB_WRITEW32: + case SMB_OLD_READB32: + case SMB_READB32: + case SMB_OLD_READW32: + case SMB_READW32: + case SMB_OLD_PCALL32: + case SMB_PCALL32: + case SMB_BWRITE32: + case SMB_BREAD32: + smbcopyincmd32(s32, &sswab); + s = &sswab; + break; + default: + break; + } +#endif + switch (cmd) { case SMB_QUICK_WRITE: +#ifdef COMPAT_FREEBSD32 + case SMB_QUICK_WRITE32: +#endif error = smbus_error(smbus_quick(parent, s->slave, SMB_QWRITE)); break; case SMB_QUICK_READ: +#ifdef COMPAT_FREEBSD32 + case SMB_QUICK_READ32: +#endif error = smbus_error(smbus_quick(parent, s->slave, SMB_QREAD)); break; case SMB_SENDB: +#ifdef COMPAT_FREEBSD32 + case SMB_SENDB32: +#endif error = smbus_error(smbus_sendb(parent, s->slave, s->cmd)); break; case SMB_RECVB: +#ifdef COMPAT_FREEBSD32 + case SMB_RECVB32: +#endif error = smbus_error(smbus_recvb(parent, s->slave, &s->cmd)); break; case SMB_WRITEB: +#ifdef COMPAT_FREEBSD32 + case SMB_WRITEB32: +#endif error = smbus_error(smbus_writeb(parent, s->slave, s->cmd, s->wdata.byte)); break; case SMB_WRITEW: +#ifdef COMPAT_FREEBSD32 + case SMB_WRITEW32: +#endif error = smbus_error(smbus_writew(parent, s->slave, s->cmd, s->wdata.word)); break; case SMB_OLD_READB: case SMB_READB: +#ifdef COMPAT_FREEBSD32 + case SMB_OLD_READB32: + case SMB_READB32: +#endif /* NB: for SMB_OLD_READB the read data goes to rbuf only. */ error = smbus_error(smbus_readb(parent, s->slave, s->cmd, &s->rdata.byte)); @@ -204,6 +309,10 @@ smbioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t case SMB_OLD_READW: case SMB_READW: +#ifdef COMPAT_FREEBSD32 + case SMB_OLD_READW32: + case SMB_READW32: +#endif /* NB: for SMB_OLD_READW the read data goes to rbuf only. */ error = smbus_error(smbus_readw(parent, s->slave, s->cmd, &s->rdata.word)); @@ -219,6 +328,10 @@ smbioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t case SMB_OLD_PCALL: case SMB_PCALL: +#ifdef COMPAT_FREEBSD32 + case SMB_OLD_PCALL32: + case SMB_PCALL32: +#endif /* NB: for SMB_OLD_PCALL the read data goes to rbuf only. */ error = smbus_error(smbus_pcall(parent, s->slave, s->cmd, s->wdata.word, &s->rdata.word)); @@ -234,6 +347,9 @@ smbioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t break; case SMB_BWRITE: +#ifdef COMPAT_FREEBSD32 + case SMB_BWRITE32: +#endif if (s->wcount < 0) { error = EINVAL; break; @@ -249,6 +365,9 @@ smbioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t break; case SMB_BREAD: +#ifdef COMPAT_FREEBSD32 + case SMB_BREAD32: +#endif if (s->rcount < 0) { error = EINVAL; break; @@ -268,6 +387,29 @@ smbioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t error = ENOTTY; } +#ifdef COMPAT_FREEBSD32 + switch (cmd) { + case SMB_RECVB32: + CP(*s, *s32, cmd); + break; + case SMB_OLD_READB32: + case SMB_READB32: + case SMB_OLD_READW32: + case SMB_READW32: + case SMB_OLD_PCALL32: + case SMB_PCALL32: + CP(*s, *s32, rdata.word); + break; + case SMB_BREAD32: + if (s->rbuf == NULL) + CP(*s, *s32, rdata.word); + CP(*s, *s32, rcount); + break; + default: + break; + } +#endif + smbus_release_bus(parent, smbdev); return (error);