The Solaris kernel runs in 64-bit mode on suitable hardware and supports both 32-bit and 64-bit applications. A 64-bit device driver is required to support I/O control commands from 32-bit and 64-bit user mode programs. The difference between a 32-bit program and a 64-bit program is its C language type model: a 32-bit program is ILP32 and a 64-bit program is LP64. See Appendix F, Making a Device Driver 64-Bit Ready , for information on C data type models.
Any data that flows between programs and the kernel and vice versa (for example using ddi_copyin(9F) or ddi_copyout(9F)) will either need to be identical in format regardless of the type model of the kernel and application, or the device driver should be able to handle a model mismatch between it and the application and adjust the data format accordingly.
To determine if there is a model mismatch, the ioctl(9E) mode parameter passes the data model bits to the driver. As Example 9-15 shows, the mode parameter is then passed to ddi_model_convert_from(9F) to determine if any model conversion is necessary.
In the following example, the driver copies a data structure which contains a user address. Because the data structure changes size from ILP32 to LP64, the 64-bit driver uses a 32-bit version of the structure when communicating with a 32-bit application.
struct args32 {
uint32_t addr; /* 32-bit address in LP64 */
int len;
}
struct args {
caddr_t addr; /* 64-bit address in LP64 */
int len;
}
static int
xxioctl(dev_t dev, int cmd, intptr_t arg, int mode,
cred_t *credp, int *rvalp)
{
struct xxstate *xsp;
struct args a;
xsp = ddi_get_soft_state(statep, getminor(dev));
if (xsp == NULL) {
return (ENXIO);
}
switch (cmd) {
case XX_COPYIN_DATA:
switch(ddi_model_convert_from(mode & FMODELS)) {
case DDI_MODEL_ILP32:
{
struct args32 a32;
/* copy 32-bit args data shape */
if (ddi_copyin((void *)arg, &a32,
sizeof (struct args32), mode) != 0) {
return (EFAULT);
}
/* convert 32-bit to 64-bit args data shape */
a.addr = a32.addr;
a.len = a32.len;
break;
}
case DDI_MODEL_NONE:
/* application and driver have same data model. */
if (ddi_copyin((void *)arg, &a, sizeof (struct args),
mode) != 0) {
return (EFAULT);
}
}
/* continue using data shape in native driver data model. */
break;
case XX_COPYOUT_DATA:
/* copyout handling */
break;
default:
/* generic "ioctl unknown" error */
return (ENOTTY);
}
return (0);
}