Intention of this page
This page was created by Per Persson for describing the functions and macros copy_{to,from}_user() and __copy_{to,from}_user. Several people have asked about them at kernelnewbies@nl.linux.org.
Hopefully, I will not just start creating this page, but also complete it (if it can be completed ).
In the meantime, take a look at http://www.kernelnewbies.org/documents/copy_user/
- /Per
Introduction
During the time I've been on the KernelNewbies mailing list, I've seen questions about the "copy_user" functions several times, and also tried to explain some of them. Although I'm just a kernel newbie, the response to my explanations has been very positive. John Levon even has published my explanation of __copy_user at KernelNewbies: http://www.kernelnewbies.org/documents/copy_user/.
Even if you're not especially interested in the "copy_user" functions/macros themselves, their implementations contain some techniques that can be useful in other situations:
- macros and inline functions
- inline assembly (gcc style)
- sections
- removal of unneeded branches
Most of the code considered in this text can be found in the file include/asm-i386/uaccess.h.
There are four functions/macros that I will cover here:
copy_to_user
copy_from_user
__copy_to_user
__copy_from_user
|
Direction |
|
Accesschecking? |
Kernel-->User |
User-->Kernel |
Yes |
copy_to_user |
copy_from_user |
No |
__copy_to_user |
__copy_from_user |
Perhaps the __copy_{to,from}_user macros would better be called copy_{to,from}_user_nocheck because they don't do the access-checking that copy_{to,from}_user do.
Constant or Generic?
At the top level, the four "functions" are implemented as macros:
#define copy_to_user(to,from,n) \ (__builtin_constant_p(n) ? \ __constant_copy_to_user((to),(from),(n)) : \ __generic_copy_to_user((to),(from),(n)))
This code tells the compiler to check if n is a constant (known at compile time), and if so the optimised (inline) function __constant_copy_to_user should be used, in other cases the function __generic_copy_to_user should be used.