Add 32-bit ioctl translations for 64-bit platforms
PATCH 1/1 Add 32-bit ioctl translations for 64-bit platforms
This contains the patch for supporting 32-bit compatible ioctls on x86_64 systems. The current x86_64 driver will not work with 32-bit applications.
drivers/char/ipmi/ipmi_devintf.c +175 -0
@@ -45,6 +45,7 @@#include <asm/semaphore.h> #include <linux/init.h> #include <linux/device.h> +#include <linux/compat.h> #define IPMI_DEVINTF_VERSION "v33"
@@ -500,10 +501,184 @@return rv; } +#ifdef CONFIG_COMPAT +/* +* The following code contains code for supporting 32-bit compatible +* ioctls on 64-bit kernels. This allows running 32-bit apps on the +* 64-bit kernel +*/ +#define IPMICTL_SEND_COMMAND32 _IOR(IPMI_IOC_MAGIC, 13, struct ipmi_req32) +#define IPMICTL_SEND_COMMAND_SETTIME32 _IOR(IPMI_IOC_MAGIC, 21, struct ipmi_req_settime32) +#define IPMICTL_RECEIVE_MSG32 _IOWR(IPMI_IOC_MAGIC, 12, struct ipmi_recv32) +#define IPMICTL_RECEIVE_MSG_TRUNC32 _IOWR(IPMI_IOC_MAGIC, 11, struct ipmi_recv32) + +struct ipmi_msg32 +{ +uint8_t netfn; +uint8_t cmd; +uint16_t data_len; +compat_uptr_t data; +}; + +struct ipmi_req32 +{ +compat_uptr_t addr; +uint32_t addr_len; +int32_t msgid; + +struct ipmi_msg32 msg; +}; + +struct ipmi_recv32 +{ +int32_t recv_type; +compat_uptr_t addr; +uint32_t addr_len; +uint32_t msgid; + +struct ipmi_msg32 msg; +}; + +struct ipmi_req_settime32 +{ +struct ipmi_req32 req; +int32_t retries; +uint32_t retry_time_ms; +}; + +/* +* Define some helper functions for copying IPMI data +*/ +static void ipmi_copymsg64 (struct ipmi_msg *p64,struct ipmi_msg32 *p32) +{ + p64->netfn = p32->netfn; + p64->cmd = p32->cmd; + p64->data_len = p32->data_len; + p64->data = (char __user *)(u64 )p32->data; +} +static void ipmi_copymsg32 (struct ipmi_msg32 *p32,struct ipmi_msg *p64) +{ + p32->netfn = p64->netfn; + p32->cmd = p64->cmd; + p32->data_len = p64->data_len; +} +static void ipmi_copyreq64 (struct ipmi_req *p64,struct ipmi_req32 *p32) +{ + p64->addr = (char __user *)(u64 )p32->addr; + p64->addr_len = p32->addr_len; + p64->msgid = p32->msgid; +ipmi_copymsg64 (&p64->msg, &p32->msg); +} +static void ipmi_copyrecv64 (struct ipmi_recv *p64,struct ipmi_recv32 *p32) +{ + p64->recv_type = p32->recv_type; + p64->addr = (char __user *)(u64 )p32->addr; + p64->addr_len = p32->addr_len; + p64->msgid = p32->msgid; +ipmi_copymsg64 (&p64->msg, &p32->msg); +} +static void ipmi_copyrecv32 (struct ipmi_recv32 *p32,struct ipmi_recv *p64) +{ + p32->recv_type = p64->recv_type; + p32->addr_len = p64->addr_len; + p32->msgid = p64->msgid; +ipmi_copymsg32 (&p32->msg, &p64->msg); +} + +/* +* Handle 32-bit ioctls on 64-bit kernel +*/ +static long ipmi_ioctl32 (struct file *filep,unsigned int cmd, +unsigned long arg) +{ +int rc; + +switch (cmd) { +case IPMICTL_SEND_COMMAND32 : + { +struct ipmi_req *preq64, req64; +struct ipmi_req32 req32; + +/* +* Copy in the 32-bit ioctl structure from userspace, +* move fields to 64-bit ioctl structure, copy back to +* userspace and issue 64-bit ioctl +*/ +if (copy_from_user (&req32,compat_ptr (arg),sizeof (req32))) +return -EFAULT ; + +ipmi_copyreq64 (&req64, &req32); + + preq64 =compat_alloc_user_space (sizeof (req64)); +if (copy_to_user (preq64, &req64,sizeof (req64))) +return -EFAULT ; + +return ipmi_ioctl (filep->f_dentry->d_inode, filep, +IPMICTL_SEND_COMMAND , (long ) preq64); + } +case IPMICTL_SEND_COMMAND_SETTIME32 : + { +struct ipmi_req_settime *preq64, req64; +struct ipmi_req_settime32 req32; + +if (copy_from_user (&req32,compat_ptr (arg),sizeof (req32))) +return -EFAULT ; + +ipmi_copyreq64 (&req64.req, &req32.req); + req64.retries = req32.retries; + req64.retry_time_ms = req32.retry_time_ms; + + preq64 =compat_alloc_user_space (sizeof (req64)); +if (copy_to_user (preq64, &req64,sizeof (req64))) +return -EFAULT ; + +return ipmi_ioctl (filep->f_dentry->d_inode, filep, +IPMICTL_SEND_COMMAND_SETTIME , (long ) preq64); + } +case IPMICTL_RECEIVE_MSG32 : +case IPMICTL_RECEIVE_MSG_TRUNC32 : + { +struct ipmi_recv *precv64, recv64; +struct ipmi_recv32 recv32; + +if (copy_from_user (&recv32,compat_ptr (arg),sizeof (recv32))) +return -EFAULT ; + +ipmi_copyrecv64 (&recv64, &recv32); + + precv64 =compat_alloc_user_space (sizeof (recv64)); +if (copy_to_user (precv64, &recv64,sizeof (recv64))) +return -EFAULT ; + + rc =ipmi_ioctl (filep->f_dentry->d_inode, filep, + ((cmd ==IPMICTL_RECEIVE_MSG32 ) + ?IPMICTL_RECEIVE_MSG + :IPMICTL_RECEIVE_MSG_TRUNC ), + (long ) precv64); +if (rc !=0 ) +return rc; + +if (copy_from_user (&recv64, precv64,sizeof (recv64))) +return -EFAULT ; + +ipmi_copyrecv32 (&recv32, &recv64); +if (copy_to_user (compat_ptr (arg), &recv32,sizeof (recv32))) +return -EFAULT ; + +return rc; + } +default : +return ipmi_ioctl (filep->f_dentry->d_inode, filep, cmd, arg); + } +} +#endif static struct file_operations ipmi_fops = { .owner =THIS_MODULE , .ioctl = ipmi_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ipmi_ioctl32, +#endif .open = ipmi_open, .release = ipmi_release, .fasync = ipmi_fasync,
Hi Cory,
drivers/char/ipmi/ipmi_devintf.c line 521
Quoted 8 lines · On Thu, 19 May 2005 18:33:21 -0500 Corey Minyard <[email protected]> wrote:
drivers/char/ipmi/ipmi_devintf.c +7
-0+struct ipmi_msg32 +{ +uint8_t netfn; +uint8_t cmd; +uint16_t data_len; +compat_uptr_t data; +};
Why are you using unint8_t etc when we have perfectly good kernel types u8 etc?
Signature · 3 lines
Cheers, Stephen Rothwell [email protected] http://www.canb.auug.org.au/~sfr/
Quoted 5 lines · Stephen Rothwell
Hi Cory,
On Thu, 19 May 2005 18:33:21 -0500 Corey Minyard <[email protected]> wrote:
Quoted 14 lines
Review
Quoted 9 lines
(quoted diff) +7
-0+struct ipmi_msg32 +{ + uint8_t netfn; + uint8_t cmd; + uint16_t data_len; + compat_uptr_t data; +};Why are you using
unint8_tetc when we have perfectly good kernel types u8 etc?
I would say "Why does the kernel have its own types when there are perfectly good types from the C standard?" However, it's no big deal to me, here's a version with the kernel types.
-Corey
This contains the patch for supporting 32-bit compatible ioctls on x86_64 systems. The current x86_64 driver will not work with 32-bit applications.
drivers/char/ipmi/ipmi_devintf.c +175 -0
@@ -45,6 +45,7 @@#include <asm/semaphore.h> #include <linux/init.h> #include <linux/device.h> +#include <linux/compat.h> #define IPMI_DEVINTF_VERSION "v33"
@@ -500,10 +501,184 @@return rv; } +#ifdef CONFIG_COMPAT +/* +* The following code contains code for supporting 32-bit compatible +* ioctls on 64-bit kernels. This allows running 32-bit apps on the +* 64-bit kernel +*/ +#define IPMICTL_SEND_COMMAND32 _IOR(IPMI_IOC_MAGIC, 13, struct ipmi_req32) +#define IPMICTL_SEND_COMMAND_SETTIME32 _IOR(IPMI_IOC_MAGIC, 21, struct ipmi_req_settime32) +#define IPMICTL_RECEIVE_MSG32 _IOWR(IPMI_IOC_MAGIC, 12, struct ipmi_recv32) +#define IPMICTL_RECEIVE_MSG_TRUNC32 _IOWR(IPMI_IOC_MAGIC, 11, struct ipmi_recv32) + +struct ipmi_msg32 +{ +u8 netfn; +u8 cmd; +u16 data_len; +compat_uptr_t data; +}; + +struct ipmi_req32 +{ +compat_uptr_t addr; +u32 addr_len; +s32 msgid; + +struct ipmi_msg32 msg; +}; + +struct ipmi_recv32 +{ +s32 recv_type; +compat_uptr_t addr; +u32 addr_len; +u32 msgid; + +struct ipmi_msg32 msg; +}; + +struct ipmi_req_settime32 +{ +struct ipmi_req32 req; +s32 retries; +u32 retry_time_ms; +}; + +/* +* Define some helper functions for copying IPMI data +*/ +static void ipmi_copymsg64 (struct ipmi_msg *p64,struct ipmi_msg32 *p32) +{ + p64->netfn = p32->netfn; + p64->cmd = p32->cmd; + p64->data_len = p32->data_len; + p64->data = (char __user *)(u64 )p32->data; +} +static void ipmi_copymsg32 (struct ipmi_msg32 *p32,struct ipmi_msg *p64) +{ + p32->netfn = p64->netfn; + p32->cmd = p64->cmd; + p32->data_len = p64->data_len; +} +static void ipmi_copyreq64 (struct ipmi_req *p64,struct ipmi_req32 *p32) +{ + p64->addr = (char __user *)(u64 )p32->addr; + p64->addr_len = p32->addr_len; + p64->msgid = p32->msgid; +ipmi_copymsg64 (&p64->msg, &p32->msg); +} +static void ipmi_copyrecv64 (struct ipmi_recv *p64,struct ipmi_recv32 *p32) +{ + p64->recv_type = p32->recv_type; + p64->addr = (char __user *)(u64 )p32->addr; + p64->addr_len = p32->addr_len; + p64->msgid = p32->msgid; +ipmi_copymsg64 (&p64->msg, &p32->msg); +} +static void ipmi_copyrecv32 (struct ipmi_recv32 *p32,struct ipmi_recv *p64) +{ + p32->recv_type = p64->recv_type; + p32->addr_len = p64->addr_len; + p32->msgid = p64->msgid; +ipmi_copymsg32 (&p32->msg, &p64->msg); +} + +/* +* Handle 32-bit ioctls on 64-bit kernel +*/ +static long ipmi_ioctl32 (struct file *filep,unsigned int cmd, +unsigned long arg) +{ +int rc; + +switch (cmd) { +case IPMICTL_SEND_COMMAND32 : + { +struct ipmi_req *preq64, req64; +struct ipmi_req32 req32; + +/* +* Copy in the 32-bit ioctl structure from userspace, +* move fields to 64-bit ioctl structure, copy back to +* userspace and issue 64-bit ioctl +*/ +if (copy_from_user (&req32,compat_ptr (arg),sizeof (req32))) +return -EFAULT ; + +ipmi_copyreq64 (&req64, &req32); + + preq64 =compat_alloc_user_space (sizeof (req64)); +if (copy_to_user (preq64, &req64,sizeof (req64))) +return -EFAULT ; + +return ipmi_ioctl (filep->f_dentry->d_inode, filep, +IPMICTL_SEND_COMMAND , (long ) preq64); + } +case IPMICTL_SEND_COMMAND_SETTIME32 : + { +struct ipmi_req_settime *preq64, req64; +struct ipmi_req_settime32 req32; + +if (copy_from_user (&req32,compat_ptr (arg),sizeof (req32))) +return -EFAULT ; + +ipmi_copyreq64 (&req64.req, &req32.req); + req64.retries = req32.retries; + req64.retry_time_ms = req32.retry_time_ms; + + preq64 =compat_alloc_user_space (sizeof (req64)); +if (copy_to_user (preq64, &req64,sizeof (req64))) +return -EFAULT ; + +return ipmi_ioctl (filep->f_dentry->d_inode, filep, +IPMICTL_SEND_COMMAND_SETTIME , (long ) preq64); + } +case IPMICTL_RECEIVE_MSG32 : +case IPMICTL_RECEIVE_MSG_TRUNC32 : + { +struct ipmi_recv *precv64, recv64; +struct ipmi_recv32 recv32; + +if (copy_from_user (&recv32,compat_ptr (arg),sizeof (recv32))) +return -EFAULT ; + +ipmi_copyrecv64 (&recv64, &recv32); + + precv64 =compat_alloc_user_space (sizeof (recv64)); +if (copy_to_user (precv64, &recv64,sizeof (recv64))) +return -EFAULT ; + + rc =ipmi_ioctl (filep->f_dentry->d_inode, filep, + ((cmd ==IPMICTL_RECEIVE_MSG32 ) + ?IPMICTL_RECEIVE_MSG + :IPMICTL_RECEIVE_MSG_TRUNC ), + (long ) precv64); +if (rc !=0 ) +return rc; + +if (copy_from_user (&recv64, precv64,sizeof (recv64))) +return -EFAULT ; + +ipmi_copyrecv32 (&recv32, &recv64); +if (copy_to_user (compat_ptr (arg), &recv32,sizeof (recv32))) +return -EFAULT ; + +return rc; + } +default : +return ipmi_ioctl (filep->f_dentry->d_inode, filep, cmd, arg); + } +} +#endif static struct file_operations ipmi_fops = { .owner =THIS_MODULE , .ioctl = ipmi_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ipmi_ioctl32, +#endif .open = ipmi_open, .release = ipmi_release, .fasync = ipmi_fasync,
Stephen suggested a lot of other changes, and I have tested the attached patch. It seems to work fine.
-Corey
Quoted 5 lines · Stephen Rothwell
Hi Cory,
On Thu, 19 May 2005 18:33:21 -0500 Corey Minyard <[email protected]> wrote:
Quoted 15 lines
Review
Quoted 9 lines
(quoted diff) +7
-0+struct ipmi_msg32 +{ + uint8_t netfn; + uint8_t cmd; + uint16_t data_len; + compat_uptr_t data; +};Why are you using
unint8_tetc when we have perfectly good kernel types u8 etc?
This contains the patch for supporting 32-bit compatible ioctls on x86_64 systems. The current x86_64 driver will not work with 32-bit applications.
drivers/char/ipmi/ipmi_devintf.c +196 -0
@@ -45,6 +45,7 @@#include <asm/semaphore.h> #include <linux/init.h> #include <linux/device.h> +#include <linux/compat.h> #define IPMI_DEVINTF_VERSION "v33"
@@ -500,10 +501,205 @@return rv; } +#ifdef CONFIG_COMPAT + +/* +* The following code contains code for supporting 32-bit compatible +* ioctls on 64-bit kernels. This allows running 32-bit apps on the +* 64-bit kernel +*/ +#define COMPAT_IPMICTL_SEND_COMMAND \ + _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req) +#define COMPAT_IPMICTL_SEND_COMMAND_SETTIME \ + _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime) +#define COMPAT_IPMICTL_RECEIVE_MSG \ + _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv) +#define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC \ + _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv) + +struct compat_ipmi_msg { +u8 netfn; +u8 cmd; +u16 data_len; +compat_uptr_t data; +}; + +struct compat_ipmi_req { +compat_uptr_t addr; +compat_uint_t addr_len; +compat_long_t msgid; +struct compat_ipmi_msg msg; +}; + +struct compat_ipmi_recv { +compat_int_t recv_type; +compat_uptr_t addr; +compat_uint_t addr_len; +compat_long_t msgid; +struct compat_ipmi_msg msg; +}; + +struct compat_ipmi_req_settime { +struct compat_ipmi_req req; +compat_int_t retries; +compat_uint_t retry_time_ms; +}; + +/* +* Define some helper functions for copying IPMI data +*/ +static long get_compat_ipmi_msg (struct ipmi_msg *p64, +struct compat_ipmi_msg __user *p32) +{ +compat_uptr_t tmp; + +if (!access_ok (VERIFY_READ , p32,sizeof (*p32)) || +__get_user (p64->netfn, &p32->netfn) || +__get_user (p64->cmd, &p32->cmd) || +__get_user (p64->data_len, &p32->data_len) || +__get_user (tmp, &p32->data)) +return -EFAULT ; + p64->data =compat_ptr (tmp); +return 0 ; +} + +static long put_compat_ipmi_msg (struct ipmi_msg *p64, +struct compat_ipmi_msg __user *p32) +{ +if (!access_ok (VERIFY_WRITE , p32,sizeof (*p32)) || +__put_user (p64->netfn, &p32->netfn) || +__put_user (p64->cmd, &p32->cmd) || +__put_user (p64->data_len, &p32->data_len)) +return -EFAULT ; +return 0 ; +} + +static long get_compat_ipmi_req (struct ipmi_req *p64, +struct compat_ipmi_req __user *p32) +{ + +compat_uptr_t tmp; + +if (!access_ok (VERIFY_READ , p32,sizeof (*p32)) || +__get_user (tmp, &p32->addr) || +__get_user (p64->addr_len, &p32->addr_len) || +__get_user (p64->msgid, &p32->msgid) || +get_compat_ipmi_msg (&p64->msg, &p32->msg)) +return -EFAULT ; + p64->addr =compat_ptr (tmp); +return 0 ; +} + +static long get_compat_ipmi_req_settime (struct ipmi_req_settime *p64, +struct compat_ipmi_req_settime __user *p32) +{ +if (!access_ok (VERIFY_READ , p32,sizeof (*p32)) || +get_compat_ipmi_req (&p64->req, &p32->req) || +__get_user (p64->retries, &p32->retries) || +__get_user (p64->retry_time_ms, &p32->retry_time_ms)) +return -EFAULT ; +return 0 ; +} + +static long get_compat_ipmi_recv (struct ipmi_recv *p64, +struct compat_ipmi_recv __user *p32) +{ +compat_uptr_t tmp; + +if (!access_ok (VERIFY_READ , p32,sizeof (*p32)) || +__get_user (p64->recv_type, &p32->recv_type) || +__get_user (tmp, &p32->addr) || +__get_user (p64->addr_len, &p32->addr_len) || +__get_user (p64->msgid, &p32->msgid) || +get_compat_ipmi_msg (&p64->msg, &p32->msg)) +return -EFAULT ; + p64->addr =compat_ptr (tmp); +return 0 ; +} + +static long put_compat_ipmi_recv (struct ipmi_recv *p64, +struct compat_ipmi_recv __user *p32) +{ +if (!access_ok (VERIFY_WRITE , p32,sizeof (*p32)) || +__put_user (p64->recv_type, &p32->recv_type) || +__put_user (p64->addr_len, &p32->addr_len) || +__put_user (p64->msgid, &p32->msgid) || +put_compat_ipmi_msg (&p64->msg, &p32->msg)) +return -EFAULT ; +return 0 ; +} + +/* +* Handle compatibility ioctls +*/ +static long compat_ipmi_ioctl (struct file *filep,unsigned int cmd, +unsigned long arg) +{ +int rc; +struct ipmi_file_private *priv = filep->private_data; + +switch (cmd) { +case COMPAT_IPMICTL_SEND_COMMAND : + { +struct ipmi_req rp; + +if (get_compat_ipmi_req (&rp,compat_ptr (arg))) +return -EFAULT ; + +return handle_send_req (priv->user, &rp, + priv->default_retries, + priv->default_retry_time_ms); + } +case COMPAT_IPMICTL_SEND_COMMAND_SETTIME : + { +struct ipmi_req_settime sp; + +if (get_compat_ipmi_req_settime (&sp,compat_ptr (arg))) +return -EFAULT ; + +return handle_send_req (priv->user, &sp.req, + sp.retries, sp.retry_time_ms); + } +case COMPAT_IPMICTL_RECEIVE_MSG : +case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC : + { +struct ipmi_recv *precv64, recv64; + +if (get_compat_ipmi_recv (&recv64,compat_ptr (arg))) +return -EFAULT ; + + precv64 =compat_alloc_user_space (sizeof (recv64)); +if (copy_to_user (precv64, &recv64,sizeof (recv64))) +return -EFAULT ; + + rc =ipmi_ioctl (filep->f_dentry->d_inode, filep, + ((cmd ==COMPAT_IPMICTL_RECEIVE_MSG ) + ?IPMICTL_RECEIVE_MSG + :IPMICTL_RECEIVE_MSG_TRUNC ), + (long ) precv64); +if (rc !=0 ) +return rc; + +if (copy_from_user (&recv64, precv64,sizeof (recv64))) +return -EFAULT ; + +if (put_compat_ipmi_recv (&recv64,compat_ptr (arg))) +return -EFAULT ; + +return rc; + } +default : +return ipmi_ioctl (filep->f_dentry->d_inode, filep, cmd, arg); + } +} +#endif static struct file_operations ipmi_fops = { .owner =THIS_MODULE , .ioctl = ipmi_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = compat_ipmi_ioctl, +#endif .open = ipmi_open, .release = ipmi_release, .fasync = ipmi_fasync,