[FreeBSD 8/9] [64-bit IOCTL] Using the USB stack from a 32-bit application under a 64-bit kernel.

Andrew Thompson thompsa at FreeBSD.org
Sun May 30 22:59:13 UTC 2010


On 31 May 2010 10:19, Kostik Belousov <kostikbel at gmail.com> wrote:
> On Sun, May 30, 2010 at 09:50:15PM +0200, Hans Petter Selasky wrote:
>> Hi,
>>
>> The USB team in FreeBSD has discussed this issue internally and would like
>> some advice how to best resolve the 32 bit to 64 bit IOCTL conversion issue.
>>
>> Sometimes IOCTL requests contain userland pointers of type "void *". When
>> compiled on a 64-bit OS, sizeof(void *) is 8 bytes and when compiled on a 32-
>> bit OS sizeof(void *) is 4 bytes. This size difference makes it impossible to
>> forward IOCTLs 1:1 from a 32-bit application running under a 64-bit kernel.
>>
>> This issue does not only apply to the USB subsystem, but also other kernel
>> IOCTL interfaces. I suggest a more general solution:
>>
>> typedef uint64_t pvoid64;
>>
>> When an IOCTL needs to reference pointers in userspace, then they should
>> always pad the pointer to 64-bit and use the pvoid64, which could have been a
>> compiler type, so that we can easily convert to "void *" without using casts.
>>
>>
>> When converting 32-bit userland pointers into 64-bit ones, there is no pointer
>> conversion except for the unsigned expansion and resulting zero-padding. I
>> assume this assumption will always be valid.
>>
>>
>> Please find attached an example patch to make the USB stack in 8 and 9 fully
>> 64-bit compatible.
>>
>>
>> Any comments are welcome!
>>
>>
>> --HPS
>> --- src/sys/dev/usb/usb_ioctl.h       2010-02-14 12:03:51.000000000 0000
>> +++ src/sys/dev/usb/usb_ioctl.h       2010-02-14 12:03:51.000000000 0000
>> @@ -131,9 +131,10 @@
>>        * NOTE: isochronous USB transfer only use one buffer, but can have
>>        * multiple frame lengths !
>>        */
>> -     void  **ppBuffer;               /* pointer to userland buffers */
>> -     uint32_t *pLength;              /* pointer to frame lengths, updated
>> -                                      * to actual length */
>> +     uint64_t ppBuffer;              /* pointer to 64-bit userland buffer pointers */
>> +     uint64_t pLength;               /* pointer to 32-bit frame lengths, which
>> +                                      * get updated to the actual length after
>> +                                      * the transfer is complete. */
>>       uint32_t nFrames;               /* number of frames */
>>       uint32_t aFrames;               /* actual number of frames */
>>       uint16_t flags;
>
> Doesn't this change the existing ABI for 32bit platforms ?
>
> You may take a look at the sys/net/bpf.c, where the similar
> issue is handled for bpf ioctls. To keep the ABI intact, you
> would need to define the 32bit ABI structures and define
> compat ioctls, then handle the ioctls by converting the structures
> and calling the native handler. BIOCSRTIMEOUT32 is a good example.

This has been done for other usb ioctls but the above struct has a
pointer to an array of pointers in userland which makes it difficult.
It isnt copied in with the ioctl so doesnt get the chance to be fixed
up.

so far, http://people.freebsd.org/~thompsa/linux_usb_amd64_2.diff


Andrew


More information about the freebsd-hackers mailing list