[Qemu-devel] [PATCH v3 3/3] linux-user: Implement special usbfs ioctls.

2018-10-08 Thread Cortland Tölva
Userspace submits a USB Request Buffer to the kernel, optionally
discards it, and finally reaps the URB.  Thunk buffers from target
to host and back.

Tested by running an i386 scanner driver on ARMv7 and by running
the PowerPC lsusb utility on x86_64.  The discardurb ioctl is
not exercised in these tests.

Signed-off-by: Cortland Tölva 
---
There are two alternatives for the strategy of holding lock_user on
memory from submit until reap.  v3 of this series tries to determine
the access permissions for user memory from endpoint direction, but
the logic for this is complex.  The first alternative is to request
write access.  If that fails, request read access.  If that fails, try
to submit the ioctl with no buffer - perhaps the user code filled in
fields the kernel will ignore.  The second alternative is to read user
memory into an allocated buffer, pass it to the kernel, and write back
to target memory only if the kernel indicates that writes occurred.

Changes from v1:
  improve pointer cast to int compatibility
  remove unimplemented types for usb streams
  struct definitions moved to this patch where possible

Changes from v2:
 organize urb thunk metadata in a struct
 hold lock_user from submit until discard
 fixes for 64-bit hosts

 linux-user/ioctls.h|   8 ++
 linux-user/syscall.c   | 177 +
 linux-user/syscall_defs.h  |   4 +
 linux-user/syscall_types.h |  20 +
 4 files changed, 209 insertions(+)

diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 92f6177f1d..ae8951625f 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -143,6 +143,14 @@
   IOCTL(USBDEVFS_SETCONFIGURATION, IOC_W, MK_PTR(TYPE_INT))
   IOCTL(USBDEVFS_GETDRIVER, IOC_R,
 MK_PTR(MK_STRUCT(STRUCT_usbdevfs_getdriver)))
+  IOCTL_SPECIAL(USBDEVFS_SUBMITURB, IOC_W, do_ioctl_usbdevfs_submiturb,
+  MK_PTR(MK_STRUCT(STRUCT_usbdevfs_urb)))
+  IOCTL_SPECIAL(USBDEVFS_DISCARDURB, IOC_RW, do_ioctl_usbdevfs_discardurb,
+  MK_PTR(MK_STRUCT(STRUCT_usbdevfs_urb)))
+  IOCTL_SPECIAL(USBDEVFS_REAPURB, IOC_R, do_ioctl_usbdevfs_reapurb,
+  MK_PTR(TYPE_PTRVOID))
+  IOCTL_SPECIAL(USBDEVFS_REAPURBNDELAY, IOC_R, do_ioctl_usbdevfs_reapurb,
+  MK_PTR(TYPE_PTRVOID))
   IOCTL(USBDEVFS_DISCSIGNAL, IOC_W,
 MK_PTR(MK_STRUCT(STRUCT_usbdevfs_disconnectsignal)))
   IOCTL(USBDEVFS_CLAIMINTERFACE, IOC_W, MK_PTR(TYPE_INT))
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 2641260186..9b7ea96cfb 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -96,6 +96,7 @@
 #include 
 #if defined(CONFIG_USBFS)
 #include 
+#include 
 #endif
 #include 
 #include 
@@ -4199,6 +4200,182 @@ static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, 
uint8_t *buf_temp,
 return ret;
 }
 
+#if defined(CONFIG_USBFS)
+#if HOST_LONG_BITS > 64
+#error USBDEVFS thunks do not support >64 bit hosts yet.
+#endif
+struct live_urb {
+uint64_t target_urb_adr;
+uint64_t target_buf_adr;
+char *target_buf_ptr;
+struct usbdevfs_urb host_urb;
+};
+
+static GHashTable *usbdevfs_urb_hashtable(void)
+{
+static GHashTable *urb_hashtable;
+
+if (!urb_hashtable) {
+urb_hashtable = g_hash_table_new(g_int64_hash, g_int64_equal);
+}
+return urb_hashtable;
+}
+
+static void urb_hashtable_insert(struct live_urb *urb)
+{
+GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
+g_hash_table_insert(urb_hashtable, urb, urb);
+}
+
+static struct live_urb *urb_hashtable_lookup(uint64_t target_urb_adr)
+{
+GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
+return g_hash_table_lookup(urb_hashtable, _urb_adr);
+}
+
+static void urb_hashtable_remove(struct live_urb *urb)
+{
+GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
+g_hash_table_remove(urb_hashtable, urb);
+}
+
+static abi_long
+do_ioctl_usbdevfs_reapurb(const IOCTLEntry *ie, uint8_t *buf_temp,
+  int fd, int cmd, abi_long arg)
+{
+const argtype usbfsurb_arg_type[] = { MK_STRUCT(STRUCT_usbdevfs_urb) };
+const argtype ptrvoid_arg_type[] = { TYPE_PTRVOID, 0, 0 };
+struct live_urb *lurb;
+void *argptr;
+uint64_t hurb;
+int target_size;
+uintptr_t target_urb_adr;
+abi_long ret;
+
+target_size = thunk_type_size(usbfsurb_arg_type, THUNK_TARGET);
+
+memset(buf_temp, 0, sizeof(uint64_t));
+ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
+if (is_error(ret)) {
+return ret;
+}
+
+memcpy(, buf_temp, sizeof(uint64_t));
+lurb = (void *)((uintptr_t)hurb - offsetof(struct live_urb, host_urb));
+if (!lurb->target_urb_adr) {
+return -TARGET_EFAULT;
+}
+urb_hashtable_remove(lurb);
+unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr,
+lurb->host_urb.buffer_length);
+lurb->target_buf_ptr = NULL;
+
+/* restore the guest buffer pointer */
+lurb->host_urb.buffer = (void *)(uintptr_t)lurb->target_buf_adr;
+
+

[Qemu-devel] [PATCH v3 1/3] linux-user: Check for Linux USBFS in configure

2018-10-08 Thread Cortland Tölva
In preparation for adding user mode emulation support for the
Linux usbfs interface, check for its kernel header.

Signed-off-by: Cortland Tölva 
Reviewed-by: Laurent Vivier 
Message-Id: <20180925071228.32040-2-...@tolva.net>
Signed-off-by: Laurent Vivier 
---
 configure | 12 +++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/configure b/configure
index f89d293585..19d66bbdeb 100755
--- a/configure
+++ b/configure
@@ -4236,7 +4236,14 @@ if compile_prog "" "" ; then
   memfd=yes
 fi
 
-
+# check for usbfs
+have_usbfs=no
+if test "$linux_user" = "yes"; then
+  if check_include linux/usbdevice_fs.h; then
+have_usbfs=yes
+  fi
+  have_usbfs=yes
+fi
 
 # check for fallocate
 fallocate=no
@@ -6350,6 +6357,9 @@ fi
 if test "$memfd" = "yes" ; then
   echo "CONFIG_MEMFD=y" >> $config_host_mak
 fi
+if test "$have_usbfs" = "yes" ; then
+  echo "CONFIG_USBFS=y" >> $config_host_mak
+fi
 if test "$fallocate" = "yes" ; then
   echo "CONFIG_FALLOCATE=y" >> $config_host_mak
 fi
-- 
2.11.0



[Qemu-devel] [PATCH v3 2/3] linux-user: Define ordinary usbfs ioctls.

2018-10-08 Thread Cortland Tölva
Provide ioctl definitions for the generic thunk mechanism to
convert most usbfs calls.  Calculate arg size at runtime.

Signed-off-by: Cortland Tölva 
---
Changes from v1:
  move some type definitions to patch 3/3
Changes from v2:
  calculate ioctl arg size at runtime

 linux-user/ioctls.h| 38 
 linux-user/syscall.c   |  3 +++
 linux-user/syscall_defs.h  | 24 +++
 linux-user/syscall_types.h | 48 ++
 4 files changed, 113 insertions(+)

diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 586c794639..92f6177f1d 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -131,6 +131,44 @@
  IOCTL(FS_IOC_GETFLAGS, IOC_R, MK_PTR(TYPE_INT))
  IOCTL(FS_IOC_SETFLAGS, IOC_W, MK_PTR(TYPE_INT))
 
+#ifdef CONFIG_USBFS
+  /* USB ioctls */
+  IOCTL(USBDEVFS_CONTROL, IOC_RW,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_ctrltransfer)))
+  IOCTL(USBDEVFS_BULK, IOC_RW,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_bulktransfer)))
+  IOCTL(USBDEVFS_RESETEP, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_SETINTERFACE, IOC_W,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_setinterface)))
+  IOCTL(USBDEVFS_SETCONFIGURATION, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_GETDRIVER, IOC_R,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_getdriver)))
+  IOCTL(USBDEVFS_DISCSIGNAL, IOC_W,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_disconnectsignal)))
+  IOCTL(USBDEVFS_CLAIMINTERFACE, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_RELEASEINTERFACE, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_CONNECTINFO, IOC_R,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_connectinfo)))
+  IOCTL(USBDEVFS_IOCTL, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_usbdevfs_ioctl)))
+  IOCTL(USBDEVFS_HUB_PORTINFO, IOC_R,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_hub_portinfo)))
+  IOCTL(USBDEVFS_RESET, 0, TYPE_NULL)
+  IOCTL(USBDEVFS_CLEAR_HALT, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_DISCONNECT, 0, TYPE_NULL)
+  IOCTL(USBDEVFS_CONNECT, 0, TYPE_NULL)
+  IOCTL(USBDEVFS_CLAIM_PORT, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_RELEASE_PORT, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_GET_CAPABILITIES, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_DISCONNECT_CLAIM, IOC_W,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_disconnect_claim)))
+#ifdef USBDEVFS_DROP_PRIVILEGES
+  IOCTL(USBDEVFS_DROP_PRIVILEGES, IOC_W, MK_PTR(TYPE_INT))
+#endif
+#ifdef USBDEVFS_GET_SPEED
+  IOCTL(USBDEVFS_GET_SPEED, 0, TYPE_NULL)
+#endif
+#endif /* CONFIG_USBFS */
+
   IOCTL(SIOCATMARK, IOC_R, MK_PTR(TYPE_INT))
   IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT))
   IOCTL(SIOCGIFFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq)))
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index ae3c0dfef7..2641260186 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -94,6 +94,9 @@
 #include 
 #endif
 #include 
+#if defined(CONFIG_USBFS)
+#include 
+#endif
 #include 
 #include 
 #include 
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 18d434d6dc..2daa5ebdcc 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -863,6 +863,30 @@ struct target_pollfd {
 
 #define TARGET_FS_IOC_FIEMAP TARGET_IOWR('f',11,struct fiemap)
 
+/* usb ioctls */
+#define TARGET_USBDEVFS_CONTROL TARGET_IOWRU('U', 0)
+#define TARGET_USBDEVFS_BULK TARGET_IOWRU('U', 2)
+#define TARGET_USBDEVFS_RESETEP TARGET_IORU('U', 3)
+#define TARGET_USBDEVFS_SETINTERFACE TARGET_IORU('U', 4)
+#define TARGET_USBDEVFS_SETCONFIGURATION TARGET_IORU('U',  5)
+#define TARGET_USBDEVFS_GETDRIVER TARGET_IOWU('U', 8)
+#define TARGET_USBDEVFS_DISCSIGNAL TARGET_IORU('U', 14)
+#define TARGET_USBDEVFS_CLAIMINTERFACE TARGET_IORU('U', 15)
+#define TARGET_USBDEVFS_RELEASEINTERFACE TARGET_IORU('U', 16)
+#define TARGET_USBDEVFS_CONNECTINFO TARGET_IOWU('U', 17)
+#define TARGET_USBDEVFS_IOCTL TARGET_IOWRU('U', 18)
+#define TARGET_USBDEVFS_HUB_PORTINFO TARGET_IORU('U', 19)
+#define TARGET_USBDEVFS_RESET TARGET_IO('U', 20)
+#define TARGET_USBDEVFS_CLEAR_HALT TARGET_IORU('U', 21)
+#define TARGET_USBDEVFS_DISCONNECT TARGET_IO('U', 22)
+#define TARGET_USBDEVFS_CONNECT TARGET_IO('U', 23)
+#define TARGET_USBDEVFS_CLAIM_PORT TARGET_IORU('U', 24)
+#define TARGET_USBDEVFS_RELEASE_PORT TARGET_IORU('U', 25)
+#define TARGET_USBDEVFS_GET_CAPABILITIES TARGET_IORU('U', 26)
+#define TARGET_USBDEVFS_DISCONNECT_CLAIM TARGET_IORU('U', 27)
+#define TARGET_USBDEVFS_DROP_PRIVILEGES TARGET_IOWU('U', 30)
+#define TARGET_USBDEVFS_GET_SPEED TARGET_IO('U', 31)
+
 /* cdrom commands */
 #define TARGET_CDROMPAUSE  0x5301 /* Pause Audio Operation */
 #define TARGET_CDROMRESUME 0x5302 /* Resume paused Audio Operation 
*/
diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
index 24631b09be..6f64a8bdf7 100644
--- a/linux-user/syscall_types.h
+++ b/linux-user/syscall_types.h
@@ -266,3 +266,51 @@ STRUCT(blkpg_ioctl_arg,
TYPE_INT, /* flags */
TYPE_INT, /* datalen */
TYPE_PTRVOID) /* data

[Qemu-devel] [PATCH v3 0/3] Linux usermode emulation user mode USB driver support.

2018-10-08 Thread Cortland Tölva
This patch series enables programs running under QEMU Linux user mode
emulation to implement user-space USB drivers via the USBFS ioctl()s.
Support is limited to control, bulk, and possibly interrupt transfers.

The series compiles for i386, ppc64, ppc64le, mips, mipsel, xtensa, and
xtensaeb with an armv7l host and an x86_64 host.  The i386-linux-user target is
tested working with a USB scanner driver on an armv7l host.  Additionally, a
patched copy of strace was used to verify the conversion for reaping.
Additionally, a MIPS binary of lsusb was run on armv7l host to check reaping
and other functionality across endianness.

Changes from v1:
  use check_include in configure
  move struct definitions to later patch where possible
  improve pointer cast to int compatibility
  remove unimplemented types for usb streams

Changes from v2:
  calculate ioctl arg size at runtime
  organize urb metadata with struct
  hold lock_user memory from submit until reap
  supersedes patch series 'linux-user: usbfs improvements'

Cortland Tölva (3):
  linux-user: Check for Linux USBFS in configure
  linux-user: Define ordinary usbfs ioctls.
  linux-user: Implement special usbfs ioctls.

 configure  |  12 ++-
 linux-user/ioctls.h|  46 
 linux-user/syscall.c   | 180 +
 linux-user/syscall_defs.h  |  28 +++
 linux-user/syscall_types.h |  68 +
 5 files changed, 333 insertions(+), 1 deletion(-)

-- 
2.11.0



[Qemu-devel] [PATCH 1/2] linux-user: Use calculated sizes for usbfs ioctls.

2018-10-07 Thread Cortland Tölva
Size calculation should have used the target struct.  Fix the error by
marking these ioctls as needing runtime size calcuation.

Signed-off-by: Cortland Tölva 
---
 linux-user/syscall_defs.h | 38 ++
 1 file changed, 18 insertions(+), 20 deletions(-)

diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index af91f9582d..2daa5ebdcc 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -863,31 +863,29 @@ struct target_pollfd {
 
 #define TARGET_FS_IOC_FIEMAP TARGET_IOWR('f',11,struct fiemap)
 
-#if defined(CONFIG_USBFS)
 /* usb ioctls */
-#define TARGET_USBDEVFS_CONTROL TARGET_IOWR('U', 0, struct 
usbdevfs_ctrltransfer)
-#define TARGET_USBDEVFS_BULK TARGET_IOWR('U', 2, struct usbdevfs_bulktransfer)
-#define TARGET_USBDEVFS_RESETEP TARGET_IOR('U', 3, int)
-#define TARGET_USBDEVFS_SETINTERFACE TARGET_IOR('U', 4, struct 
usbdevfs_setinterface)
-#define TARGET_USBDEVFS_SETCONFIGURATION TARGET_IOR('U',  5, int)
-#define TARGET_USBDEVFS_GETDRIVER TARGET_IOW('U', 8, struct usbdevfs_getdriver)
-#define TARGET_USBDEVFS_DISCSIGNAL TARGET_IOR('U', 14, struct 
usbdevfs_disconnectsignal)
-#define TARGET_USBDEVFS_CLAIMINTERFACE TARGET_IOR('U', 15, int)
-#define TARGET_USBDEVFS_RELEASEINTERFACE TARGET_IOR('U', 16, int)
-#define TARGET_USBDEVFS_CONNECTINFO TARGET_IOW('U', 17, struct 
usbdevfs_connectinfo)
-#define TARGET_USBDEVFS_IOCTL TARGET_IOWR('U', 18, struct usbdevfs_ioctl)
-#define TARGET_USBDEVFS_HUB_PORTINFO TARGET_IOR('U', 19, struct 
usbdevfs_hub_portinfo)
+#define TARGET_USBDEVFS_CONTROL TARGET_IOWRU('U', 0)
+#define TARGET_USBDEVFS_BULK TARGET_IOWRU('U', 2)
+#define TARGET_USBDEVFS_RESETEP TARGET_IORU('U', 3)
+#define TARGET_USBDEVFS_SETINTERFACE TARGET_IORU('U', 4)
+#define TARGET_USBDEVFS_SETCONFIGURATION TARGET_IORU('U',  5)
+#define TARGET_USBDEVFS_GETDRIVER TARGET_IOWU('U', 8)
+#define TARGET_USBDEVFS_DISCSIGNAL TARGET_IORU('U', 14)
+#define TARGET_USBDEVFS_CLAIMINTERFACE TARGET_IORU('U', 15)
+#define TARGET_USBDEVFS_RELEASEINTERFACE TARGET_IORU('U', 16)
+#define TARGET_USBDEVFS_CONNECTINFO TARGET_IOWU('U', 17)
+#define TARGET_USBDEVFS_IOCTL TARGET_IOWRU('U', 18)
+#define TARGET_USBDEVFS_HUB_PORTINFO TARGET_IORU('U', 19)
 #define TARGET_USBDEVFS_RESET TARGET_IO('U', 20)
-#define TARGET_USBDEVFS_CLEAR_HALT TARGET_IOR('U', 21, int)
+#define TARGET_USBDEVFS_CLEAR_HALT TARGET_IORU('U', 21)
 #define TARGET_USBDEVFS_DISCONNECT TARGET_IO('U', 22)
 #define TARGET_USBDEVFS_CONNECT TARGET_IO('U', 23)
-#define TARGET_USBDEVFS_CLAIM_PORT TARGET_IOR('U', 24, int)
-#define TARGET_USBDEVFS_RELEASE_PORT TARGET_IOR('U', 25, int)
-#define TARGET_USBDEVFS_GET_CAPABILITIES TARGET_IOR('U', 26, int)
-#define TARGET_USBDEVFS_DISCONNECT_CLAIM TARGET_IOR('U', 27, struct 
usbdevfs_disconnect_claim)
-#define TARGET_USBDEVFS_DROP_PRIVILEGES TARGET_IOW('U', 30, int)
+#define TARGET_USBDEVFS_CLAIM_PORT TARGET_IORU('U', 24)
+#define TARGET_USBDEVFS_RELEASE_PORT TARGET_IORU('U', 25)
+#define TARGET_USBDEVFS_GET_CAPABILITIES TARGET_IORU('U', 26)
+#define TARGET_USBDEVFS_DISCONNECT_CLAIM TARGET_IORU('U', 27)
+#define TARGET_USBDEVFS_DROP_PRIVILEGES TARGET_IOWU('U', 30)
 #define TARGET_USBDEVFS_GET_SPEED TARGET_IO('U', 31)
-#endif /* CONFIG_USBFS */
 
 /* cdrom commands */
 #define TARGET_CDROMPAUSE  0x5301 /* Pause Audio Operation */
-- 
2.17.1



[Qemu-devel] [PATCH 2/2] linux-user: Implement usbfs submit and reap ioctls.

2018-10-07 Thread Cortland Tölva
Userspace submits a USB Request Buffer to the kernel, optionally
discards it, and finally reaps the URB.  Thunk buffers from target
to host and back.

Tested by running an i386 scanner driver on ARMv7, by running
the PowerPC lsusb utility on x86_64, and MIPS lsusb on ARMv7.  
The discard urb ioctl is implemented but has not been tested.

Signed-off-by: Cortland Tölva 
---
lsusb was run with -vv so as to exercise the submit and reap ioctls.

 linux-user/ioctls.h|   8 ++
 linux-user/syscall.c   | 177 +
 linux-user/syscall_defs.h  |   4 +
 linux-user/syscall_types.h |  20 +
 4 files changed, 209 insertions(+)

diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 92f6177f1d..ae8951625f 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -143,6 +143,14 @@
   IOCTL(USBDEVFS_SETCONFIGURATION, IOC_W, MK_PTR(TYPE_INT))
   IOCTL(USBDEVFS_GETDRIVER, IOC_R,
 MK_PTR(MK_STRUCT(STRUCT_usbdevfs_getdriver)))
+  IOCTL_SPECIAL(USBDEVFS_SUBMITURB, IOC_W, do_ioctl_usbdevfs_submiturb,
+  MK_PTR(MK_STRUCT(STRUCT_usbdevfs_urb)))
+  IOCTL_SPECIAL(USBDEVFS_DISCARDURB, IOC_RW, do_ioctl_usbdevfs_discardurb,
+  MK_PTR(MK_STRUCT(STRUCT_usbdevfs_urb)))
+  IOCTL_SPECIAL(USBDEVFS_REAPURB, IOC_R, do_ioctl_usbdevfs_reapurb,
+  MK_PTR(TYPE_PTRVOID))
+  IOCTL_SPECIAL(USBDEVFS_REAPURBNDELAY, IOC_R, do_ioctl_usbdevfs_reapurb,
+  MK_PTR(TYPE_PTRVOID))
   IOCTL(USBDEVFS_DISCSIGNAL, IOC_W,
 MK_PTR(MK_STRUCT(STRUCT_usbdevfs_disconnectsignal)))
   IOCTL(USBDEVFS_CLAIMINTERFACE, IOC_W, MK_PTR(TYPE_INT))
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 2641260186..9b7ea96cfb 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -96,6 +96,7 @@
 #include 
 #if defined(CONFIG_USBFS)
 #include 
+#include 
 #endif
 #include 
 #include 
@@ -4199,6 +4200,182 @@ static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, 
uint8_t *buf_temp,
 return ret;
 }
 
+#if defined(CONFIG_USBFS)
+#if HOST_LONG_BITS > 64
+#error USBDEVFS thunks do not support >64 bit hosts yet.
+#endif
+struct live_urb {
+uint64_t target_urb_adr;
+uint64_t target_buf_adr;
+char *target_buf_ptr;
+struct usbdevfs_urb host_urb;
+};
+
+static GHashTable *usbdevfs_urb_hashtable(void)
+{
+static GHashTable *urb_hashtable;
+
+if (!urb_hashtable) {
+urb_hashtable = g_hash_table_new(g_int64_hash, g_int64_equal);
+}
+return urb_hashtable;
+}
+
+static void urb_hashtable_insert(struct live_urb *urb)
+{
+GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
+g_hash_table_insert(urb_hashtable, urb, urb);
+}
+
+static struct live_urb *urb_hashtable_lookup(uint64_t target_urb_adr)
+{
+GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
+return g_hash_table_lookup(urb_hashtable, _urb_adr);
+}
+
+static void urb_hashtable_remove(struct live_urb *urb)
+{
+GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
+g_hash_table_remove(urb_hashtable, urb);
+}
+
+static abi_long
+do_ioctl_usbdevfs_reapurb(const IOCTLEntry *ie, uint8_t *buf_temp,
+  int fd, int cmd, abi_long arg)
+{
+const argtype usbfsurb_arg_type[] = { MK_STRUCT(STRUCT_usbdevfs_urb) };
+const argtype ptrvoid_arg_type[] = { TYPE_PTRVOID, 0, 0 };
+struct live_urb *lurb;
+void *argptr;
+uint64_t hurb;
+int target_size;
+uintptr_t target_urb_adr;
+abi_long ret;
+
+target_size = thunk_type_size(usbfsurb_arg_type, THUNK_TARGET);
+
+memset(buf_temp, 0, sizeof(uint64_t));
+ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
+if (is_error(ret)) {
+return ret;
+}
+
+memcpy(, buf_temp, sizeof(uint64_t));
+lurb = (void *)((uintptr_t)hurb - offsetof(struct live_urb, host_urb));
+if (!lurb->target_urb_adr) {
+return -TARGET_EFAULT;
+}
+urb_hashtable_remove(lurb);
+unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr,
+lurb->host_urb.buffer_length);
+lurb->target_buf_ptr = NULL;
+
+/* restore the guest buffer pointer */
+lurb->host_urb.buffer = (void *)(uintptr_t)lurb->target_buf_adr;
+
+/* update the guest urb struct */
+argptr = lock_user(VERIFY_WRITE, lurb->target_urb_adr, target_size, 0);
+if (!argptr) {
+g_free(lurb);
+return -TARGET_EFAULT;
+}
+thunk_convert(argptr, >host_urb, usbfsurb_arg_type, THUNK_TARGET);
+unlock_user(argptr, lurb->target_urb_adr, target_size);
+
+target_size = thunk_type_size(ptrvoid_arg_type, THUNK_TARGET);
+/* write back the urb handle */
+argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
+if (!argptr) {
+g_free(lurb);
+return -TARGET_EFAULT;
+}
+
+/* GHashTable uses 64-bit keys but thunk_convert expects uintptr_t */
+target_urb_adr = lurb->target_urb_adr;
+thunk_convert(argptr, _urb_adr, ptrvoid_arg_type, THUNK_TARGET);
+unlock_user(argptr, arg, target_s

[Qemu-devel] [PATCH 0/2] linux-user: usbfs improvements

2018-10-07 Thread Cortland Tölva
From: Cortland Setlow Tölva 

This patch series enables programs running under QEMU Linux user mode
emulation to implement user-space USB drivers via the USBFS ioctl()s.
Support is limited to control, bulk, and possibly interrupt transfers.

Usbfs ioctl codes were incorrect whenever host and target disagreed on
struct size.  The submit, discard, and reap usbfs ioctls require special
memory buffer handling and the second commit implements this but not for
USB3 streams or isochronous transfers.

Cortland Tölva (2):
  linux-user: Use calculated sizes for usbfs ioctls.
  linux-user: Implement special usbfs ioctls.

 linux-user/ioctls.h|   8 ++
 linux-user/syscall.c   | 177 +
 linux-user/syscall_defs.h  |  42 -
 linux-user/syscall_types.h |  20 +
 4 files changed, 227 insertions(+), 20 deletions(-)

-- 
2.17.1



[Qemu-devel] [PATCH v2 2/3] linux-user: Define ordinary usbfs ioctls.

2018-09-25 Thread Cortland Tölva
Provide ioctl definitions for the generic thunk mechanism to
convert most usbfs calls.

Signed-off-by: Cortland Tölva 
---

v2 patch lacks some types that are not used until patch 3/3

 linux-user/ioctls.h| 38 
 linux-user/syscall.c   |  3 +++
 linux-user/syscall_defs.h  | 26 +
 linux-user/syscall_types.h | 48 ++
 4 files changed, 115 insertions(+)

diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 586c794639..92f6177f1d 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -131,6 +131,44 @@
  IOCTL(FS_IOC_GETFLAGS, IOC_R, MK_PTR(TYPE_INT))
  IOCTL(FS_IOC_SETFLAGS, IOC_W, MK_PTR(TYPE_INT))
 
+#ifdef CONFIG_USBFS
+  /* USB ioctls */
+  IOCTL(USBDEVFS_CONTROL, IOC_RW,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_ctrltransfer)))
+  IOCTL(USBDEVFS_BULK, IOC_RW,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_bulktransfer)))
+  IOCTL(USBDEVFS_RESETEP, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_SETINTERFACE, IOC_W,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_setinterface)))
+  IOCTL(USBDEVFS_SETCONFIGURATION, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_GETDRIVER, IOC_R,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_getdriver)))
+  IOCTL(USBDEVFS_DISCSIGNAL, IOC_W,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_disconnectsignal)))
+  IOCTL(USBDEVFS_CLAIMINTERFACE, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_RELEASEINTERFACE, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_CONNECTINFO, IOC_R,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_connectinfo)))
+  IOCTL(USBDEVFS_IOCTL, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_usbdevfs_ioctl)))
+  IOCTL(USBDEVFS_HUB_PORTINFO, IOC_R,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_hub_portinfo)))
+  IOCTL(USBDEVFS_RESET, 0, TYPE_NULL)
+  IOCTL(USBDEVFS_CLEAR_HALT, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_DISCONNECT, 0, TYPE_NULL)
+  IOCTL(USBDEVFS_CONNECT, 0, TYPE_NULL)
+  IOCTL(USBDEVFS_CLAIM_PORT, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_RELEASE_PORT, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_GET_CAPABILITIES, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_DISCONNECT_CLAIM, IOC_W,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_disconnect_claim)))
+#ifdef USBDEVFS_DROP_PRIVILEGES
+  IOCTL(USBDEVFS_DROP_PRIVILEGES, IOC_W, MK_PTR(TYPE_INT))
+#endif
+#ifdef USBDEVFS_GET_SPEED
+  IOCTL(USBDEVFS_GET_SPEED, 0, TYPE_NULL)
+#endif
+#endif /* CONFIG_USBFS */
+
   IOCTL(SIOCATMARK, IOC_R, MK_PTR(TYPE_INT))
   IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT))
   IOCTL(SIOCGIFFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq)))
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 850b72a0c7..39f21b78c8 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -94,6 +94,9 @@
 #include 
 #endif
 #include 
+#if defined(CONFIG_USBFS)
+#include 
+#endif
 #include 
 #include 
 #include 
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 40bb60ef4c..357ee6a8c2 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -858,6 +858,32 @@ struct target_pollfd {
 
 #define TARGET_FS_IOC_FIEMAP TARGET_IOWR('f',11,struct fiemap)
 
+#if defined(CONFIG_USBFS)
+/* usb ioctls */
+#define TARGET_USBDEVFS_CONTROL TARGET_IOWR('U', 0, struct 
usbdevfs_ctrltransfer)
+#define TARGET_USBDEVFS_BULK TARGET_IOWR('U', 2, struct usbdevfs_bulktransfer)
+#define TARGET_USBDEVFS_RESETEP TARGET_IOR('U', 3, int)
+#define TARGET_USBDEVFS_SETINTERFACE TARGET_IOR('U', 4, struct 
usbdevfs_setinterface)
+#define TARGET_USBDEVFS_SETCONFIGURATION TARGET_IOR('U',  5, int)
+#define TARGET_USBDEVFS_GETDRIVER TARGET_IOW('U', 8, struct usbdevfs_getdriver)
+#define TARGET_USBDEVFS_DISCSIGNAL TARGET_IOR('U', 14, struct 
usbdevfs_disconnectsignal)
+#define TARGET_USBDEVFS_CLAIMINTERFACE TARGET_IOR('U', 15, int)
+#define TARGET_USBDEVFS_RELEASEINTERFACE TARGET_IOR('U', 16, int)
+#define TARGET_USBDEVFS_CONNECTINFO TARGET_IOW('U', 17, struct 
usbdevfs_connectinfo)
+#define TARGET_USBDEVFS_IOCTL TARGET_IOWR('U', 18, struct usbdevfs_ioctl)
+#define TARGET_USBDEVFS_HUB_PORTINFO TARGET_IOR('U', 19, struct 
usbdevfs_hub_portinfo)
+#define TARGET_USBDEVFS_RESET TARGET_IO('U', 20)
+#define TARGET_USBDEVFS_CLEAR_HALT TARGET_IOR('U', 21, int)
+#define TARGET_USBDEVFS_DISCONNECT TARGET_IO('U', 22)
+#define TARGET_USBDEVFS_CONNECT TARGET_IO('U', 23)
+#define TARGET_USBDEVFS_CLAIM_PORT TARGET_IOR('U', 24, int)
+#define TARGET_USBDEVFS_RELEASE_PORT TARGET_IOR('U', 25, int)
+#define TARGET_USBDEVFS_GET_CAPABILITIES TARGET_IOR('U', 26, int)
+#define TARGET_USBDEVFS_DISCONNECT_CLAIM TARGET_IOR('U', 27, struct 
usbdevfs_disconnect_claim)
+#define TARGET_USBDEVFS_DROP_PRIVILEGES TARGET_IOW('U', 30, int)
+#define TARGET_USBDEVFS_GET_SPEED TARGET_IO('U', 31)
+#endif /* CONFIG_USBFS */
+
 /* cdrom commands */
 #define TARGET_CDROMPAUSE  0x5301 /* Pause Audio Operation */
 #define TARGET_CDROMRESUME 0x5302 /* Resume paused Audio Operation 
*/
diff --git a/linux-user/syscall_types.h b

[Qemu-devel] [PATCH v2 3/3] linux-user: implement special usbfs ioctls.

2018-09-25 Thread Cortland Tölva
Userspace submits a USB Request Buffer to the kernel, optionally
discards it, and finally reaps the URB.  Thunk buffers from target
to host and back.

Tested by running an i386 scanner driver on ARMv7.  Neither the
discardurb ioctl nor the kernel's updating the argument to the
reap ioctl with a pointer to a reaped URB are exercised by this.

Signed-off-by: Cortland Tölva 
---
Changes from v1:
  improve pointer cast to int compatibility
  remove unimplemented types for usb streams
  struct definitions moved to this patch where possible

 linux-user/ioctls.h|   8 +++
 linux-user/syscall.c   | 168 +
 linux-user/syscall_defs.h  |   4 ++
 linux-user/syscall_types.h |  20 ++
 4 files changed, 200 insertions(+)

diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 92f6177f1d..f04461fff7 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -143,6 +143,14 @@
   IOCTL(USBDEVFS_SETCONFIGURATION, IOC_W, MK_PTR(TYPE_INT))
   IOCTL(USBDEVFS_GETDRIVER, IOC_R,
 MK_PTR(MK_STRUCT(STRUCT_usbdevfs_getdriver)))
+  IOCTL_SPECIAL(USBDEVFS_SUBMITURB, IOC_W, do_ioctl_usbdevfs_submiturb,
+  MK_PTR(MK_STRUCT(STRUCT_usbdevfs_urb)))
+  IOCTL_SPECIAL(USBDEVFS_DISCARDURB, IOC_RW, do_ioctl_usbdevfs_discardurb,
+  MK_PTR(MK_STRUCT(STRUCT_usbdevfs_urb)))
+  IOCTL_SPECIAL(USBDEVFS_REAPURB, IOC_R, do_ioctl_usbdevfs_reapurb,
+  MK_PTR(MK_STRUCT(STRUCT_usbdevfs_urb)))
+  IOCTL_SPECIAL(USBDEVFS_REAPURBNDELAY, IOC_R, do_ioctl_usbdevfs_reapurb,
+  MK_PTR(MK_STRUCT(STRUCT_usbdevfs_urb)))
   IOCTL(USBDEVFS_DISCSIGNAL, IOC_W,
 MK_PTR(MK_STRUCT(STRUCT_usbdevfs_disconnectsignal)))
   IOCTL(USBDEVFS_CLAIMINTERFACE, IOC_W, MK_PTR(TYPE_INT))
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 39f21b78c8..bb0bf7e03d 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5491,6 +5491,174 @@ static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, 
uint8_t *buf_temp,
 return ret;
 }
 
+#if defined(CONFIG_USBFS)
+#if HOST_LONG_BITS > 64
+#error USBDEVFS thunks do not support >64 bit hosts yet.
+#endif
+static GHashTable *usbdevfs_urb_hashtable(void)
+{
+static GHashTable *urb_hashtable;
+
+if (!urb_hashtable) {
+urb_hashtable = g_hash_table_new(g_int64_hash, g_int64_equal);
+}
+return urb_hashtable;
+}
+
+static abi_long
+do_ioctl_usbdevfs_reapurb(const IOCTLEntry *ie, uint8_t *buf_temp,
+  int fd, int cmd, abi_long arg)
+{
+const argtype *arg_type = ie->arg_type;
+GHashTable * const urb_hash = usbdevfs_urb_hashtable();
+const argtype ptrvoid_arg_type[] = { TYPE_PTRVOID, 0, 0 };
+int target_size;
+int64_t reaped_userurb;
+int64_t target_urbptr;
+uintptr_t target_urbptr_ptr;
+char *tagged_urb;
+void *argptr;
+abi_long ret;
+
+target_size = thunk_type_size(++arg_type, THUNK_TARGET);
+
+ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
+if (is_error(ret)) {
+return ret;
+}
+
+memcpy(_userurb, buf_temp, sizeof(int64_t));
+tagged_urb = ((char *)(uintptr_t)reaped_userurb) - sizeof(int64_t);
+memcpy(_urbptr, tagged_urb, sizeof(int64_t));
+if (!target_urbptr) {
+return -TARGET_EFAULT;
+}
+g_hash_table_remove(urb_hash, tagged_urb);
+
+argptr = lock_user(VERIFY_WRITE, (abi_long) target_urbptr, target_size, 0);
+if (!argptr) {
+g_free(tagged_urb);
+return -TARGET_EFAULT;
+}
+thunk_convert(argptr, (char *)(uintptr_t)reaped_userurb, arg_type,
+  THUNK_TARGET);
+unlock_user(argptr, target_urbptr, target_size);
+
+target_size = thunk_type_size(ptrvoid_arg_type, THUNK_TARGET);
+argptr = lock_user(VERIFY_WRITE, (abi_long)arg, target_size, 0);
+if (!argptr) {
+g_free(tagged_urb);
+return -TARGET_EFAULT;
+}
+target_urbptr_ptr = (uintptr_t)target_urbptr;
+thunk_convert(argptr, _urbptr_ptr, ptrvoid_arg_type, THUNK_TARGET);
+unlock_user(argptr, (abi_long) arg, target_size);
+g_free(tagged_urb);
+return ret;
+}
+
+static abi_long
+do_ioctl_usbdevfs_discardurb(const IOCTLEntry *ie,
+ uint8_t *buf_temp __attribute__((unused)),
+ int fd, int cmd, abi_long arg)
+{
+GHashTable * const urb_hash = usbdevfs_urb_hashtable();
+abi_long host_urb;
+int64_t tag_urb_key;
+char *tagged_urb;
+
+/* map target pointer back to host tagged URB. */
+tag_urb_key = (int64_t)arg;
+tagged_urb = g_hash_table_lookup(urb_hash, _urb_key);
+if (!tagged_urb) {
+return -TARGET_EFAULT;
+}
+/* offset from tag to urb */
+host_urb = (abi_long)(uintptr_t)(tagged_urb + sizeof(int64_t));
+return get_errno(safe_ioctl(fd, ie->host_cmd, host_urb));
+}
+
+static int convert_iso_packets(uint8_t *dst, int totlen, abi_long src)
+{
+void *srcptr;
+int host_size, target_size;
+int i, iso_packets;
+const a

[Qemu-devel] [PATCH v2 0/3] Linux usermode emulation user mode USB driver support.

2018-09-25 Thread Cortland Tölva
This patch series aims to let programs running under QEMU Linux user mode
emulation implement user-space USB drivers via the USBFS ioctl()s.  First
I check for the necessary header files, then I define some types, and
last I implement the submit, discard, and reap functions, which involve
USB request buffers which live beyond a single ioctl() call.

Each patch in this series compiles for i386, ppc64, ppc64le, mips, mipsel,
xtensa, and xtensaeb with an armv7l host and an x86_64 host.  The
i386-linux-user target is tested working with a USB scanner driver on an
armv7l host.  Additionally, a patched copy of strace was used to verify
the conversion for reaping.  Additionally, a MIPS binary of lsusb was run
on armv7l host to check reaping and other functionality across endianness.

Not tested on 64-bit hosts.

Changes from v1:
  use check_include in configure
  move struct definitions to later patch where possible
  improve pointer cast to int compatibility
  remove unimplemented types for usb streams

Cortland Tölva (3):
  linux-user: Check for Linux USBFS in configure
  linux-user: Define ordinary usbfs ioctls.
  linux-user: implement special usbfs ioctls.

 configure  |  12 +++-
 linux-user/ioctls.h|  46 
 linux-user/syscall.c   | 171 +
 linux-user/syscall_defs.h  |  30 
 linux-user/syscall_types.h |  68 ++
 5 files changed, 326 insertions(+), 1 deletion(-)

-- 
2.11.0



[Qemu-devel] [PATCH v2 1/3] linux-user: Check for Linux USBFS in configure

2018-09-25 Thread Cortland Tölva
In preparation for adding user mode emulation support for the
Linux usbfs interface, check for its kernel header.

Signed-off-by: Cortland Tölva 
---

v2 patch uses check_include instead of doing things by hand.

 configure | 12 +++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/configure b/configure
index 7fd989aee1..5ebdb8901f 100755
--- a/configure
+++ b/configure
@@ -4234,7 +4234,14 @@ if compile_prog "" "" ; then
   memfd=yes
 fi
 
-
+# check for usbfs
+have_usbfs=no
+if test "$linux_user" = "yes"; then
+  if check_include linux/usbdevice_fs.h; then
+have_usbfs=yes
+  fi
+  have_usbfs=yes
+fi
 
 # check for fallocate
 fallocate=no
@@ -6345,6 +6352,9 @@ fi
 if test "$memfd" = "yes" ; then
   echo "CONFIG_MEMFD=y" >> $config_host_mak
 fi
+if test "$have_usbfs" = "yes" ; then
+  echo "CONFIG_USBFS=y" >> $config_host_mak
+fi
 if test "$fallocate" = "yes" ; then
   echo "CONFIG_FALLOCATE=y" >> $config_host_mak
 fi
-- 
2.11.0



[Qemu-devel] [PATCH 2/3] Linux user mode usbfs types and defs.

2018-09-19 Thread Cortland Tölva
Provide ioctl definitions for the generic thunk mechanism to
convert most usbfs calls.

Signed-off-by: Cortland Tölva 
---
 linux-user/ioctls.h| 38 ++
 linux-user/syscall.c   |  3 ++
 linux-user/syscall_defs.h  | 32 ++
 linux-user/syscall_types.h | 68 ++
 4 files changed, 141 insertions(+)

diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 586c794639..92f6177f1d 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -131,6 +131,44 @@
  IOCTL(FS_IOC_GETFLAGS, IOC_R, MK_PTR(TYPE_INT))
  IOCTL(FS_IOC_SETFLAGS, IOC_W, MK_PTR(TYPE_INT))
 
+#ifdef CONFIG_USBFS
+  /* USB ioctls */
+  IOCTL(USBDEVFS_CONTROL, IOC_RW,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_ctrltransfer)))
+  IOCTL(USBDEVFS_BULK, IOC_RW,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_bulktransfer)))
+  IOCTL(USBDEVFS_RESETEP, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_SETINTERFACE, IOC_W,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_setinterface)))
+  IOCTL(USBDEVFS_SETCONFIGURATION, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_GETDRIVER, IOC_R,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_getdriver)))
+  IOCTL(USBDEVFS_DISCSIGNAL, IOC_W,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_disconnectsignal)))
+  IOCTL(USBDEVFS_CLAIMINTERFACE, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_RELEASEINTERFACE, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_CONNECTINFO, IOC_R,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_connectinfo)))
+  IOCTL(USBDEVFS_IOCTL, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_usbdevfs_ioctl)))
+  IOCTL(USBDEVFS_HUB_PORTINFO, IOC_R,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_hub_portinfo)))
+  IOCTL(USBDEVFS_RESET, 0, TYPE_NULL)
+  IOCTL(USBDEVFS_CLEAR_HALT, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_DISCONNECT, 0, TYPE_NULL)
+  IOCTL(USBDEVFS_CONNECT, 0, TYPE_NULL)
+  IOCTL(USBDEVFS_CLAIM_PORT, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_RELEASE_PORT, IOC_W, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_GET_CAPABILITIES, IOC_R, MK_PTR(TYPE_INT))
+  IOCTL(USBDEVFS_DISCONNECT_CLAIM, IOC_W,
+MK_PTR(MK_STRUCT(STRUCT_usbdevfs_disconnect_claim)))
+#ifdef USBDEVFS_DROP_PRIVILEGES
+  IOCTL(USBDEVFS_DROP_PRIVILEGES, IOC_W, MK_PTR(TYPE_INT))
+#endif
+#ifdef USBDEVFS_GET_SPEED
+  IOCTL(USBDEVFS_GET_SPEED, 0, TYPE_NULL)
+#endif
+#endif /* CONFIG_USBFS */
+
   IOCTL(SIOCATMARK, IOC_R, MK_PTR(TYPE_INT))
   IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT))
   IOCTL(SIOCGIFFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq)))
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 850b72a0c7..39f21b78c8 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -94,6 +94,9 @@
 #include 
 #endif
 #include 
+#if defined(CONFIG_USBFS)
+#include 
+#endif
 #include 
 #include 
 #include 
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 40bb60ef4c..29aad4757d 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -858,6 +858,38 @@ struct target_pollfd {
 
 #define TARGET_FS_IOC_FIEMAP TARGET_IOWR('f',11,struct fiemap)
 
+#if defined(CONFIG_USBFS)
+/* usb ioctls */
+#define TARGET_USBDEVFS_CONTROL TARGET_IOWR('U', 0, struct 
usbdevfs_ctrltransfer)
+#define TARGET_USBDEVFS_BULK TARGET_IOWR('U', 2, struct usbdevfs_bulktransfer)
+#define TARGET_USBDEVFS_RESETEP TARGET_IOR('U', 3, int)
+#define TARGET_USBDEVFS_SETINTERFACE TARGET_IOR('U', 4, struct 
usbdevfs_setinterface)
+#define TARGET_USBDEVFS_SETCONFIGURATION TARGET_IOR('U',  5, int)
+#define TARGET_USBDEVFS_GETDRIVER TARGET_IOW('U', 8, struct usbdevfs_getdriver)
+#define TARGET_USBDEVFS_SUBMITURB TARGET_IOR('U', 10, struct usbdevfs_urb)
+#define TARGET_USBDEVFS_DISCARDURB TARGET_IO('U', 11)
+#define TARGET_USBDEVFS_REAPURB TARGET_IOW('U', 12, int)
+#define TARGET_USBDEVFS_REAPURBNDELAY TARGET_IOW('U', 13, int)
+#define TARGET_USBDEVFS_DISCSIGNAL TARGET_IOR('U', 14, struct 
usbdevfs_disconnectsignal)
+#define TARGET_USBDEVFS_CLAIMINTERFACE TARGET_IOR('U', 15, int)
+#define TARGET_USBDEVFS_RELEASEINTERFACE TARGET_IOR('U', 16, int)
+#define TARGET_USBDEVFS_CONNECTINFO TARGET_IOW('U', 17, struct 
usbdevfs_connectinfo)
+#define TARGET_USBDEVFS_IOCTL TARGET_IOWR('U', 18, struct usbdevfs_ioctl)
+#define TARGET_USBDEVFS_HUB_PORTINFO TARGET_IOR('U', 19, struct 
usbdevfs_hub_portinfo)
+#define TARGET_USBDEVFS_RESET TARGET_IO('U', 20)
+#define TARGET_USBDEVFS_CLEAR_HALT TARGET_IOR('U', 21, int)
+#define TARGET_USBDEVFS_DISCONNECT TARGET_IO('U', 22)
+#define TARGET_USBDEVFS_CONNECT TARGET_IO('U', 23)
+#define TARGET_USBDEVFS_CLAIM_PORT TARGET_IOR('U', 24, int)
+#define TARGET_USBDEVFS_RELEASE_PORT TARGET_IOR('U', 25, int)
+#define TARGET_USBDEVFS_GET_CAPABILITIES TARGET_IOR('U', 26, int)
+#define TARGET_USBDEVFS_DISCONNECT_CLAIM TARGET_IOR('U', 27, struct 
usbdevfs_disconnect_claim)
+#define TARGET_USBDEVFS_ALLOC_STREAMS TARGET_IOR('U', 28, struct 
usbdevfs_streams)
+#define TARGET_USBDEVFS_FREE_STREAMS TARGET_IOR('U', 29, struct 
usbdevfs_streams)
+#define

[Qemu-devel] [PATCH 3/3] linux-user: implement special usbfs ioctls.

2018-09-19 Thread Cortland Tölva
Userspace submits a USB Request Buffer to the kernel, optionally
discards it, and finally reaps the URB.  Thunk buffers from target
to host and back.

Tested by running an i386 scanner driver on ARMv7.  Neither the
discardurb ioctl nor the kernel's updating the argument to the
reap ioctl with a pointer to a reaped URB are exercised by this.

Signed-off-by: Cortland Tölva 
---
 linux-user/ioctls.h  |   9 +++
 linux-user/syscall.c | 168 +++
 2 files changed, 177 insertions(+)

diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 92f6177f1d..0118fa7e64 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -143,6 +143,14 @@
   IOCTL(USBDEVFS_SETCONFIGURATION, IOC_W, MK_PTR(TYPE_INT))
   IOCTL(USBDEVFS_GETDRIVER, IOC_R,
 MK_PTR(MK_STRUCT(STRUCT_usbdevfs_getdriver)))
+  IOCTL_SPECIAL(USBDEVFS_SUBMITURB, IOC_W, do_ioctl_usbdevfs_submiturb,
+  MK_PTR(MK_STRUCT(STRUCT_usbdevfs_urb)))
+  IOCTL_SPECIAL(USBDEVFS_DISCARDURB, IOC_RW, do_ioctl_usbdevfs_discardurb,
+  MK_PTR(MK_STRUCT(STRUCT_usbdevfs_urb)))
+  IOCTL_SPECIAL(USBDEVFS_REAPURB, IOC_R, do_ioctl_usbdevfs_reapurb,
+  MK_PTR(MK_STRUCT(STRUCT_usbdevfs_urb)))
+  IOCTL_SPECIAL(USBDEVFS_REAPURBNDELAY, IOC_R, do_ioctl_usbdevfs_reapurb,
+  MK_PTR(MK_STRUCT(STRUCT_usbdevfs_urb)))
   IOCTL(USBDEVFS_DISCSIGNAL, IOC_W,
 MK_PTR(MK_STRUCT(STRUCT_usbdevfs_disconnectsignal)))
   IOCTL(USBDEVFS_CLAIMINTERFACE, IOC_W, MK_PTR(TYPE_INT))
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 39f21b78c8..b66688277b 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5491,6 +5491,174 @@ static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, 
uint8_t *buf_temp,
 return ret;
 }
 
+#if defined(CONFIG_USBFS)
+#if HOST_LONG_BITS > 64
+#error USBDEVFS thunks do not support >64 bit hosts yet.
+#endif
+static GHashTable *usbdevfs_urb_hashtable(void)
+{
+static GHashTable *urb_hashtable;
+
+if (!urb_hashtable) {
+urb_hashtable = g_hash_table_new(g_int64_hash, g_int64_equal);
+}
+return urb_hashtable;
+}
+
+static abi_long
+do_ioctl_usbdevfs_reapurb(const IOCTLEntry *ie, uint8_t *buf_temp,
+  int fd, int cmd, abi_long arg)
+{
+const argtype *arg_type = ie->arg_type;
+GHashTable * const urb_hash = usbdevfs_urb_hashtable();
+const argtype ptrvoid_arg_type[] = { TYPE_PTRVOID, 0, 0 };
+int target_size;
+int64_t reaped_userurb;
+int64_t target_urbptr;
+uintptr_t target_urbptr_ptr;
+char *tagged_urb;
+void *argptr;
+abi_long ret;
+
+target_size = thunk_type_size(++arg_type, THUNK_TARGET);
+
+ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
+if (is_error(ret)) {
+return ret;
+}
+
+memcpy(_userurb, buf_temp, sizeof(int64_t));
+tagged_urb = ((char *)(uintptr_t)reaped_userurb) - sizeof(int64_t);
+memcpy(_urbptr, tagged_urb, sizeof(int64_t));
+if (!target_urbptr) {
+return -TARGET_EFAULT;
+}
+g_hash_table_remove(urb_hash, tagged_urb);
+
+argptr = lock_user(VERIFY_WRITE, (abi_long) target_urbptr, target_size, 0);
+if (!argptr) {
+g_free(tagged_urb);
+return -TARGET_EFAULT;
+}
+thunk_convert(argptr, (char *)(uintptr_t)reaped_userurb, arg_type,
+  THUNK_TARGET);
+unlock_user(argptr, target_urbptr, target_size);
+
+target_size = thunk_type_size(ptrvoid_arg_type, THUNK_TARGET);
+argptr = lock_user(VERIFY_WRITE, (abi_long)arg, target_size, 0);
+if (!argptr) {
+g_free(tagged_urb);
+return -TARGET_EFAULT;
+}
+target_urbptr_ptr = (uintptr_t) target_urbptr;
+thunk_convert(argptr, _urbptr_ptr, ptrvoid_arg_type, THUNK_TARGET);
+unlock_user(argptr, (abi_long) arg, target_size);
+g_free(tagged_urb);
+return ret;
+}
+
+static abi_long
+do_ioctl_usbdevfs_discardurb(const IOCTLEntry *ie,
+ uint8_t *buf_temp __attribute__((unused)),
+ int fd, int cmd, abi_long arg)
+{
+GHashTable * const urb_hash = usbdevfs_urb_hashtable();
+abi_long host_urb;
+int64_t tag_urb_key;
+char *tagged_urb;
+
+/* map target pointer back to host tagged URB. */
+tag_urb_key = (int64_t) arg;
+tagged_urb = g_hash_table_lookup(urb_hash, _urb_key);
+if (!tagged_urb) {
+return -TARGET_EFAULT;
+}
+/* offset from tag to urb */
+host_urb = (abi_long) (tagged_urb + sizeof(int64_t));
+return get_errno(safe_ioctl(fd, ie->host_cmd, host_urb));
+}
+
+static int convert_iso_packets(uint8_t *dst, int totlen, abi_long src)
+{
+void *srcptr;
+int host_size, target_size;
+int i, iso_packets;
+const argtype arg_type[] = { MK_STRUCT(STRUCT_usbdevfs_iso_packet_desc) };
+
+if (((struct usbdevfs_urb *)dst)->type == USBDEVFS_URB_TYPE_ISO) {
+iso_packets = ((struct usbdevfs_urb *)dst)->number_of_packets;
+} else {
+  

[Qemu-devel] [PATCH 1/3] Check for Linux USBFS in configure

2018-09-19 Thread Cortland Tölva
In preparation for adding user mode emulation support for the
Linux usbfs interface, check for its kernel header.

Signed-off-by: Cortland Tölva 
---
 configure | 21 -
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/configure b/configure
index 58862d2ae8..5d36f45442 100755
--- a/configure
+++ b/configure
@@ -4235,7 +4235,23 @@ if compile_prog "" "" ; then
   memfd=yes
 fi
 
-
+# check for usbfs
+have_usbfs=no
+if test "$linux_user" = "yes"; then
+  cat > $TMPC << EOF
+#include 
+int main(void) {
+#if !defined(USBDEVFS_URB_TYPE_CONTROL)
+#error Missing usbdevfs defintions.
+#else
+   return 0;
+#endif
+}
+EOF
+  if compile_prog "" "" ; then
+have_usbfs=yes
+  fi
+fi
 
 # check for fallocate
 fallocate=no
@@ -6346,6 +6362,9 @@ fi
 if test "$memfd" = "yes" ; then
   echo "CONFIG_MEMFD=y" >> $config_host_mak
 fi
+if test "$have_usbfs" = "yes" ; then
+  echo "CONFIG_USBFS=y" >> $config_host_mak
+fi
 if test "$fallocate" = "yes" ; then
   echo "CONFIG_FALLOCATE=y" >> $config_host_mak
 fi
-- 
2.11.0



[Qemu-devel] [PATCH 0/3] Linux usermode emulation user mode USB driver support.

2018-09-19 Thread Cortland Tölva
This patch series aims to let programs running under QEMU Linux user mode
emulation implement user-space USB drivers via the USBFS ioctl()s.  First
I check for the necessary header files, then I define some types, and
last I implement the submit, discard, and reap functions, which involve
USB request buffers which live beyond a single ioctl() call.

Cortland Tölva (3):
  Check for Linux USBFS in configure
  Linux user mode usbfs types and defs.
  linux-user: implement special usbfs ioctls.

 configure  |  21 +-
 linux-user/ioctls.h|  47 +
 linux-user/syscall.c   | 171 +
 linux-user/syscall_defs.h  |  32 +
 linux-user/syscall_types.h |  68 ++
 5 files changed, 338 insertions(+), 1 deletion(-)

-- 
2.11.0