Especially when writing ioctl, because of the 32bit userspace + 64bit kernel problem, and because of the different architecture, the length of different data types is also different, it is recommended to use u32 in ioctl, u64 and s32 ignore the data type with the architecture fix size.
Here is the size of data types from different architectures of LDD:
In addition, concerning the structure alignment in ioctl, note that adding padding makes the Data Length alignment. Currently, padding is usually added to 64bit alignment. Here is why we need to do this (for ARM, x86, not to mention, because x86-64 has long been there ):
Q: I'm new in kernel development. cocould you tell me or give me some
Materials to read that why we need to align the size of IOCTL Structures
To 64bit? I can understand if we're re working in a 64bit kernel but why we
Need to do this if we're in a 32bit ARM Kernel? Besides, why
Pointers in IOCTL structure shoshould be declared as u64?
A: Because in a few years/months you'll have arm64, but still the same
Driver with the same IOCTLs... and if the IOCTLs are not _ Exactly _
The same you get to write compat IOCTL code which copies the old 32bit
Struct into the 64bit struct the kernel understands. Hence your IOCTL
Must be laid out exactly the same for both 32bit and 64bit, which
Happens if you naturally align/PAD everything to 64 bits and only use
Fixed-sized integers and no pointers.
MARK: Ah, I see. Thanks. Yes, u64 still works as 32 bit pointer.
See the description of nature alignment in chapter 11 of LDD. Alignment mainly involves performance issues. Non-Alignment data may have exceptions during fetch, thus reducing performance.
Here are some suggestions found on the Internet:
There are some rules that shoshould be followed regardless:
* IOCTL commands shoshould never be written in an architecture specific
Way. In the example of the OMAP driver, you definitely want to be
Able ot use the same command when running Linux on the c6x DSP.
* If possible, use only scalar values as IOCTL arguments
* Avoid types that are register sized: 'long', 'size _ t', pointer.
Instead use only _ u8, _ 2010, _ u32 and _ u64 and their signed
Versions.
* If you use structures, try very hard to avoid pointers in them,
It messes up all sorts of tools.
* If you use structures, make all Members naturally aligned, and pad
The size of the structures to a multiple of the maximum member size.
* Never put Sub-command numbers into a structure.
Related to compat_ioctl: IOCTL required for 64-bit driver. When there is IOCTL for 32bit userspace application call 64bit kernel, this callback will be called.
Q: Suppose I have defined the following.
# Define my_ioctl_cmd1 _ ior (magic_number, 0x01, arg1)
# Define my_ioctl_cmd2 _ Iow (magic_number, 0x02, arg2)
# Ifdef config_compat
# Define my_compat_ioctl_cmd1 _ ior (magic_number, 0x01, compat_arg1)
# Define my_compat_ioctl_cmd2 _ Iow (magic_number, 0x02, compat_arg2)
# Endif
Now when we do IOCTL from user space, we usually do
IOCTL (FD, my_ioctl_cmd1, & arg1)
Q: Do we really need to have an IOCTL with my_compat_ioctl_cmd1 as request?
In the devide code I have handlers defined as follows. IOCTL: device_ioctl
# Ifdef config_compat
Compat_ioctl: device_compat_ioctl
# Endif
Can anybody please provide some explanations around this?
==============
A: This compat stuff is for running a 32-bit program in a 64-bit kernel. when you call the ioctl (FD, my_ioctl_cmd1, & arg1) from a 32-bit program on a 64-bit kernel, the kernel will divert the ioctl to. compat_ioctl function in the file_operations struct. this compat_ioctl function is responsible for copying the USER argument arg1 as if it were compat_arg1, which uses the 32-bit layout. the compat_arg1 typedef is defined in the kernel so that when compiled for 64-bit, the structure is exactly the same layout as the arg1 compiled for 32-bit.
The definition of my_ioctl_cmd1 will take the sizeof arg1 into account when creating the cmd id. when you compile a program for a 32-bit machine, the value for my_ioctl_cmd1 will be different than if you compiled it for a 64-bit machine. the 32-bit my_ioctl_cmd1 shoshould have the same value as the 64-bit my_compat_ioctl_cmd1 in the kernel, however.
There's never a need to use compat_arg1 or my_compat_ioctl_cmd1 in a user-space application. Those are only for code compiled in the kernel.