site_archiver@lists.apple.com Delivered-To: darwin-kernel@lists.apple.com o If you are using ioctl()'s, then you will have to do it manually. In termios.h, we have this structure: struct termios { tcflag_t c_iflag; /* input flags */ tcflag_t c_oflag; /* output flags */ tcflag_t c_cflag; /* control flags */ tcflag_t c_lflag; /* local flags */ cc_t c_cc[NCCS]; /* control chars */ speed_t c_ispeed; /* input speed */ speed_t c_ospeed; /* output speed */ }; This is a size variant structure for two reasons: 1) tcflag_t is defined as unsigned long 2) speed_t is defined as unsigned long You don't need to worry about cc_t, as it's defined as unsigned char. You define two more types and another structure: typedef unsigned long long user_tcflag_t; typedef unsigned long long user_speed_t; #if __DARWIN_ALIGN_NATURAL #pragma options align=natural #endif struct user_termios { user_tcflag_t c_iflag; /* input flags */ user_tcflag_t c_oflag; /* output flags */ user_tcflag_t c_cflag; /* control flags */ user_tcflag_t c_lflag; /* local flags */ cc_t c_cc[NCCS]; /* control chars */ user_speed_t c_ispeed; /* input speed */ user_speed_t c_ospeed; /* output speed */ }; #if __DARWIN_ALIGN_NATURAL #pragma options align=reset #endif ptr64 = CAST_USER_ADDR_T(ptr_32) ....and then use that as your argument to copyin/copyout. You can see the code that's described in this example at: -- Terry Thank you Andrew, Terry. Regards, Karunakar If you are using copyin()/copyout()/copyinstr() directly, rather than using uiomove()/uiomove64(), then you will need to make changes to your code. The reason for the change to the parameters was to support copying in/ out data with 64 bit user space addresses for 64 bit processes. Without the change, you would be limited to only passing data from the first 4G of process memory into the kernel when using a 64 bit process, and that wouldn't really be useful. -- Terry _______________________________________________ Do not post admin requests to the list. They will be ignored. Darwin-kernel mailing list (Darwin-kernel@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/darwin-kernel/site_archiver%40lists.a... In general, the approach you need to take to support 64 bit processes talking to your kexts depends on the method of passing information into the kernel: o If you are using Mach messages, "mig" knows how to generate the correct converter code. My general recommendation is to define a pseudo-device, and just let rad/write/mmap(0 take care of it for you; if you insist on moving the data yourself, your best bet is via ioctl()'s. To take an ioctl as an example, there are two methods available for passing data into an ioctl(); you either pass in your data by value, which only works portably with 32 bit or smaller data types (integer, short, char, but not long or pointer), or you pass it in by reference. If passing by reference, the passed in value might be a simple address, or it might be the address of a structure. For structure containing large objects, you need to define a structure that looks the same in 32 bits as in 64 bits, so that you can copy into/out of it. Here is an example from termios for the TCGETA ioctl: This is size variant because the 32 bit world is ILP32 - integer, long, and pointers are 32 bits - and the 64 bit world is LP64 - integeras are 32 bit, and longs and pointers are 64 bits. So this structure is at least size variant, and possibly also alignment variant. Why didn't we just change the definitions of tcflag_t and speed_t to be int's? The main reason is symbol decoration in C++; if either of these types were used in C+ + code as parameters or return values, then you would lose binary compatibility by having different symbol decoration if they were changed from long to int. This is a long standing problem in C++ compilation environaments, and pretty much everyone has he problem, because at the time that C++ was introduced, the symbol table format was not expanded to include type information separately from symbol name information. So we live with it. Sometimes it's handy: for time_t, for example, the 64 bit version doesn't have the Y2038 problem with the UNIX system clock rollover. So how do you write this ioctl() to work with both 64 bit and 32 bit versions of long? The pragma's ensure that the packing will be the same as in user space in a 64 bit process. Then you write your ioctl code that lives in the 32 bit kernel: case TIOCGETA: /* get termios struct */ case TIOCGETA_64: { /* get termios struct */ if (IS_64BIT_PROCESS(p)) { termios32to64(&tp->t_termios, (struct user_termios *)data); } else { bcopy(&tp->t_termios, data, sizeof(struct termios)); } break; -- one of the decisions you have to make in doing this is whether your kernel internal representation is going to be default for 32 bit processes, or default for 64 bit processes. Here, we picked 32 bit processes, so that people would not attempt to squirrel away information in the additional space, which would later not be visible to 32 bit programs. So tp->t_termios is of type struct termios, not type struct user_termios. We have also written a conversion function which converts between internal and external representation (in this case, we do a field-by- field assignment with proper type conversion to ensure we are not bitten by sign extension). The function for this ioctl(), which obtains data and copies it to user space, is to copy it out, so we need to convert from internal (32 bit) to external (64 bit) representation. The way this ends up working is that the structure size is encoded into the cmd parameter - this is also why, when using ioctl()'s, you rarely have to copy the data yourself, unless you are trying to move a large amount of it, at which point it's better to be a device or pesudodevice and jusst use read/write - and so we have separate TIOCGETA and TIOCGETA_64 entry points. #define TIOCGETA _IOR('t', 19, struct termios) /* get termios struct */ #ifdef KERNEL #define TIOCGETA_64 _IOR('t', 19, struct user_termios) #endif Note that the TIOCGETA_64 is only defined for kernel use: it's not implemented in 32 bit processes; instead, it's only implemented in the 32 bit kernel, which only uses it to communicate with 64 bit processes. When the TIOCGETA is defined in the 64 bit process, the value changes based on the size of the structure changing, and so it's seen by the user process as TIOCGETA, but by the kernel as TIOCGETA_64. If you were only doing a pointer, for a 64 bit process, you would take either a 64 bit value that you would bcopy into a user_addr_t, or for a 32 bit process, you would bcopy a 32 bit value into a void * (the ioctl takes care of making the data available, but not about changing the size of it one way or another). Then for the 32 bit process case, whether your pointer was in a structure or in a simple void *, you would convert it to a user_addr_t using: Obviously, if you are copying differently alighned/paced data items, then you could convert the 32 bit pointer in place in the first argument to the copyin() call itself, etc.. TIOCGETA/TIOCGETA64: http://darwinsource.opendarwin.org/10.4.2/xnu-792.2.4/bsd/sys/ ttycom.h struct termios/struct user_termios: http://darwinsource.opendarwin.org/10.4.2/xnu-792.2.4/bsd/sys/ termios.h ttioctl() code itself: http://darwinsource.opendarwin.org/10.4.2/xnu-792.2.4/bsd/kern/ tty.c On Aug 9, 2005, at 1:59 AM, Karunakar Reddy G wrote: Can you give some example how to use of them, as I am facing problem using structures, In my case structure pointer comes from the application to driver , previously I handled using void *. How to handle now since I cannot convet them as user_addr_t to use for copyin() and copyout() functions. _______________________________________________ Do not post admin requests to the list. They will be ignored. Darwin-kernel mailing list (Darwin-kernel@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/darwin-kernel/tlambert% 40apple.com This email sent to tlambert@apple.com This email sent to site_archiver@lists.apple.com