linux/arch/sparc64/solaris/misc.c
<<
>>
Prefs
   1/* $Id: misc.c,v 1.36 2002/02/09 19:49:31 davem Exp $
   2 * misc.c: Miscellaneous syscall emulation for Solaris
   3 *
   4 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
   5 */
   6
   7#include <linux/module.h> 
   8#include <linux/types.h>
   9#include <linux/utsname.h>
  10#include <linux/limits.h>
  11#include <linux/mm.h>
  12#include <linux/smp.h>
  13#include <linux/tty.h>
  14#include <linux/mman.h>
  15#include <linux/file.h>
  16#include <linux/timex.h>
  17#include <linux/major.h>
  18#include <linux/compat.h>
  19
  20#include <asm/uaccess.h>
  21#include <asm/string.h>
  22#include <asm/oplib.h>
  23#include <asm/idprom.h>
  24#include <asm/smp.h>
  25#include <asm/prom.h>
  26
  27#include "conv.h"
  28
  29/* Conversion from Linux to Solaris errnos. 0-34 are identity mapped.
  30   Some Linux errnos (EPROCLIM, EDOTDOT, ERREMOTE, EUCLEAN, ENOTNAM, 
  31   ENAVAIL, EISNAM, EREMOTEIO, ENOMEDIUM, EMEDIUMTYPE) have no Solaris
  32   equivalents. I return EINVAL in that case, which is very wrong. If
  33   someone suggest a better value for them, you're welcomed.
  34   On the other side, Solaris ECANCELED and ENOTSUP have no Linux equivalents,
  35   but that doesn't matter here. --jj */
  36int solaris_err_table[] = {
  37/* 0 */  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
  38/* 10 */  10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
  39/* 20 */  20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
  40/* 30 */  30, 31, 32, 33, 34, 22, 150, 149, 95, 96,
  41/* 40 */  97, 98, 99, 120, 121, 122, 123, 124, 125, 126, 
  42/* 50 */ 127, 128, 129, 130, 131, 132, 133, 134, 143, 144,
  43/* 60 */ 145, 146, 90, 78, 147, 148, 93, 22, 94, 49,
  44/* 70 */ 151, 66, 60, 62, 63, 35, 77, 36, 45, 46, 
  45/* 80 */ 64, 22, 67, 68, 69, 70, 71, 74, 22, 82, 
  46/* 90 */ 89, 92, 79, 81, 37, 38, 39, 40, 41, 42,
  47/* 100 */ 43, 44, 50, 51, 52, 53, 54, 55, 56, 57,
  48/* 110 */ 87, 61, 84, 65, 83, 80, 91, 22, 22, 22,
  49/* 120 */ 22, 22, 88, 86, 85, 22, 22,
  50};
  51
  52#define SOLARIS_NR_OPEN 256
  53
  54static u32 do_solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u64 off)
  55{
  56        struct file *file = NULL;
  57        unsigned long retval, ret_type;
  58
  59        /* Do we need it here? */
  60        set_personality(PER_SVR4);
  61        if (flags & MAP_NORESERVE) {
  62                static int cnt;
  63                
  64                if (cnt < 5) {
  65                        printk("%s:  unimplemented Solaris MAP_NORESERVE mmap() flag\n",
  66                               current->comm);
  67                        cnt++;
  68                }
  69                flags &= ~MAP_NORESERVE;
  70        }
  71        retval = -EBADF;
  72        if(!(flags & MAP_ANONYMOUS)) {
  73                if(fd >= SOLARIS_NR_OPEN)
  74                        goto out;
  75                file = fget(fd);
  76                if (!file)
  77                        goto out;
  78                else {
  79                        struct inode * inode = file->f_path.dentry->d_inode;
  80                        if(imajor(inode) == MEM_MAJOR &&
  81                           iminor(inode) == 5) {
  82                                flags |= MAP_ANONYMOUS;
  83                                fput(file);
  84                                file = NULL;
  85                        }
  86                }
  87        }
  88
  89        retval = -EINVAL;
  90        len = PAGE_ALIGN(len);
  91        if(!(flags & MAP_FIXED))
  92                addr = 0;
  93        else if (len > STACK_TOP32 || addr > STACK_TOP32 - len)
  94                goto out_putf;
  95        ret_type = flags & _MAP_NEW;
  96        flags &= ~_MAP_NEW;
  97
  98        down_write(&current->mm->mmap_sem);
  99        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 100        retval = do_mmap(file,
 101                         (unsigned long) addr, (unsigned long) len,
 102                         (unsigned long) prot, (unsigned long) flags, off);
 103        up_write(&current->mm->mmap_sem);
 104        if(!ret_type)
 105                retval = ((retval < STACK_TOP32) ? 0 : retval);
 106                                
 107out_putf:
 108        if (file)
 109                fput(file);
 110out:
 111        return (u32) retval;
 112}
 113
 114asmlinkage u32 solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off)
 115{
 116        return do_solaris_mmap(addr, len, prot, flags, fd, (u64) off);
 117}
 118
 119asmlinkage u32 solaris_mmap64(struct pt_regs *regs, u32 len, u32 prot, u32 flags, u32 fd, u32 offhi)
 120{
 121        u32 offlo;
 122        
 123        if (regs->u_regs[UREG_G1]) {
 124                if (get_user (offlo, (u32 __user *)(long)((u32)regs->u_regs[UREG_I6] + 0x5c)))
 125                        return -EFAULT;
 126        } else {
 127                if (get_user (offlo, (u32 __user *)(long)((u32)regs->u_regs[UREG_I6] + 0x60)))
 128                        return -EFAULT;
 129        }
 130        return do_solaris_mmap((u32)regs->u_regs[UREG_I0], len, prot, flags, fd, (((u64)offhi)<<32)|offlo);
 131}
 132
 133asmlinkage int solaris_brk(u32 brk)
 134{
 135        int (*sunos_brk)(u32) = (int (*)(u32))SUNOS(17);
 136        
 137        return sunos_brk(brk);
 138}
 139
 140static int __set_utsfield(char __user *to, int to_size,
 141                          const char *from, int from_size,
 142                          int dotchop, int countfrom)
 143{
 144        int len = countfrom ? (to_size > from_size ?
 145                               from_size : to_size) : to_size;
 146        int off;
 147
 148        if (copy_to_user(to, from, len))
 149                return -EFAULT;
 150
 151        off = len < to_size? len: len - 1;
 152        if (dotchop) {
 153                const char *p = strnchr(from, len, '.');
 154                if (p) off = p - from;
 155        }
 156
 157        if (__put_user('\0', to + off))
 158                return -EFAULT;
 159
 160        return 0;
 161}
 162
 163#define set_utsfield(to, from, dotchop, countfrom) \
 164        __set_utsfield((to), sizeof(to), \
 165                       (from), sizeof(from), \
 166                       (dotchop), (countfrom))
 167
 168struct sol_uname {
 169        char sysname[9];
 170        char nodename[9];
 171        char release[9];
 172        char version[9];
 173        char machine[9];
 174};
 175
 176struct sol_utsname {
 177        char sysname[257];
 178        char nodename[257];
 179        char release[257];
 180        char version[257];
 181        char machine[257];
 182};
 183
 184static char *machine(void)
 185{
 186        switch (sparc_cpu_model) {
 187        case sun4: return "sun4";
 188        case sun4c: return "sun4c";
 189        case sun4e: return "sun4e";
 190        case sun4m: return "sun4m";
 191        case sun4d: return "sun4d";
 192        case sun4u: return "sun4u";
 193        default: return "sparc";
 194        }
 195}
 196
 197static char *platform(char *buffer, int sz)
 198{
 199        struct device_node *dp = of_find_node_by_path("/");
 200        int len;
 201
 202        *buffer = 0;
 203        len = strlen(dp->name);
 204        if (len > sz)
 205                len = sz;
 206        memcpy(buffer, dp->name, len);
 207        buffer[len] = 0;
 208        if (*buffer) {
 209                char *p;
 210
 211                for (p = buffer; *p; p++)
 212                        if (*p == '/' || *p == ' ') *p = '_';
 213                return buffer;
 214        }
 215
 216        return "sun4u";
 217}
 218
 219static char *serial(char *buffer, int sz)
 220{
 221        struct device_node *dp = of_find_node_by_path("/options");
 222        int len;
 223
 224        *buffer = 0;
 225        if (dp) {
 226                const char *val =
 227                        of_get_property(dp, "system-board-serial#", &len);
 228
 229                if (val && len > 0) {
 230                        if (len > sz)
 231                                len = sz;
 232                        memcpy(buffer, val, len);
 233                        buffer[len] = 0;
 234                }
 235        }
 236        if (!*buffer)
 237                return "4512348717234";
 238        else
 239                return buffer;
 240}
 241
 242asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2)
 243{
 244        struct sol_uname __user *v = A(buf);
 245        int err;
 246
 247        switch (which) {
 248        case 0: /* old uname */
 249                /* Let's cheat */
 250                err  = set_utsfield(v->sysname, "SunOS", 1, 0);
 251                down_read(&uts_sem);
 252                err |= set_utsfield(v->nodename, utsname()->nodename,
 253                                    1, 1);
 254                up_read(&uts_sem);
 255                err |= set_utsfield(v->release, "2.6", 0, 0);
 256                err |= set_utsfield(v->version, "Generic", 0, 0);
 257                err |= set_utsfield(v->machine, machine(), 0, 0);
 258                return (err ? -EFAULT : 0);
 259        case 2: /* ustat */
 260                return -ENOSYS;
 261        case 3: /* fusers */
 262                return -ENOSYS;
 263        default:
 264                return -ENOSYS;
 265        }
 266}
 267
 268asmlinkage int solaris_utsname(u32 buf)
 269{
 270        struct sol_utsname __user *v = A(buf);
 271        int err;
 272
 273        /* Why should we not lie a bit? */
 274        down_read(&uts_sem);
 275        err  = set_utsfield(v->sysname, "SunOS", 0, 0);
 276        err |= set_utsfield(v->nodename, utsname()->nodename, 1, 1);
 277        err |= set_utsfield(v->release, "5.6", 0, 0);
 278        err |= set_utsfield(v->version, "Generic", 0, 0);
 279        err |= set_utsfield(v->machine, machine(), 0, 0);
 280        up_read(&uts_sem);
 281
 282        return (err ? -EFAULT : 0);
 283}
 284
 285#define SI_SYSNAME              1       /* return name of operating system */
 286#define SI_HOSTNAME             2       /* return name of node */
 287#define SI_RELEASE              3       /* return release of operating system */
 288#define SI_VERSION              4       /* return version field of utsname */
 289#define SI_MACHINE              5       /* return kind of machine */
 290#define SI_ARCHITECTURE         6       /* return instruction set arch */
 291#define SI_HW_SERIAL            7       /* return hardware serial number */
 292#define SI_HW_PROVIDER          8       /* return hardware manufacturer */
 293#define SI_SRPC_DOMAIN          9       /* return secure RPC domain */
 294#define SI_PLATFORM             513     /* return platform identifier */
 295
 296asmlinkage int solaris_sysinfo(int cmd, u32 buf, s32 count)
 297{
 298        char *p, *q, *r;
 299        char buffer[256];
 300        int len;
 301        
 302        /* Again, we cheat :)) */
 303        switch (cmd) {
 304        case SI_SYSNAME: r = "SunOS"; break;
 305        case SI_HOSTNAME:
 306                r = buffer + 256;
 307                down_read(&uts_sem);
 308                for (p = utsname()->nodename, q = buffer;
 309                     q < r && *p && *p != '.'; *q++ = *p++);
 310                up_read(&uts_sem);
 311                *q = 0;
 312                r = buffer;
 313                break;
 314        case SI_RELEASE: r = "5.6"; break;
 315        case SI_MACHINE: r = machine(); break;
 316        case SI_ARCHITECTURE: r = "sparc"; break;
 317        case SI_HW_PROVIDER: r = "Sun_Microsystems"; break;
 318        case SI_HW_SERIAL: r = serial(buffer, sizeof(buffer)); break;
 319        case SI_PLATFORM: r = platform(buffer, sizeof(buffer)); break;
 320        case SI_SRPC_DOMAIN: r = ""; break;
 321        case SI_VERSION: r = "Generic"; break;
 322        default: return -EINVAL;
 323        }
 324        len = strlen(r) + 1;
 325        if (count < len) {
 326                if (copy_to_user(A(buf), r, count - 1) ||
 327                    __put_user(0, (char __user *)A(buf) + count - 1))
 328                        return -EFAULT;
 329        } else {
 330                if (copy_to_user(A(buf), r, len))
 331                        return -EFAULT;
 332        }
 333        return len;
 334}
 335
 336#define SOLARIS_CONFIG_NGROUPS                  2
 337#define SOLARIS_CONFIG_CHILD_MAX                3
 338#define SOLARIS_CONFIG_OPEN_FILES               4
 339#define SOLARIS_CONFIG_POSIX_VER                5
 340#define SOLARIS_CONFIG_PAGESIZE                 6
 341#define SOLARIS_CONFIG_CLK_TCK                  7
 342#define SOLARIS_CONFIG_XOPEN_VER                8
 343#define SOLARIS_CONFIG_PROF_TCK                 10
 344#define SOLARIS_CONFIG_NPROC_CONF               11
 345#define SOLARIS_CONFIG_NPROC_ONLN               12
 346#define SOLARIS_CONFIG_AIO_LISTIO_MAX           13
 347#define SOLARIS_CONFIG_AIO_MAX                  14
 348#define SOLARIS_CONFIG_AIO_PRIO_DELTA_MAX       15
 349#define SOLARIS_CONFIG_DELAYTIMER_MAX           16
 350#define SOLARIS_CONFIG_MQ_OPEN_MAX              17
 351#define SOLARIS_CONFIG_MQ_PRIO_MAX              18
 352#define SOLARIS_CONFIG_RTSIG_MAX                19
 353#define SOLARIS_CONFIG_SEM_NSEMS_MAX            20
 354#define SOLARIS_CONFIG_SEM_VALUE_MAX            21
 355#define SOLARIS_CONFIG_SIGQUEUE_MAX             22
 356#define SOLARIS_CONFIG_SIGRT_MIN                23
 357#define SOLARIS_CONFIG_SIGRT_MAX                24
 358#define SOLARIS_CONFIG_TIMER_MAX                25
 359#define SOLARIS_CONFIG_PHYS_PAGES               26
 360#define SOLARIS_CONFIG_AVPHYS_PAGES             27
 361
 362asmlinkage int solaris_sysconf(int id)
 363{
 364        switch (id) {
 365        case SOLARIS_CONFIG_NGROUPS:    return NGROUPS_MAX;
 366        case SOLARIS_CONFIG_CHILD_MAX:
 367                return current->signal->rlim[RLIMIT_NPROC].rlim_cur;
 368        case SOLARIS_CONFIG_OPEN_FILES:
 369                return current->signal->rlim[RLIMIT_NOFILE].rlim_cur;
 370        case SOLARIS_CONFIG_POSIX_VER:  return 199309;
 371        case SOLARIS_CONFIG_PAGESIZE:   return PAGE_SIZE;
 372        case SOLARIS_CONFIG_XOPEN_VER:  return 3;
 373        case SOLARIS_CONFIG_CLK_TCK:
 374        case SOLARIS_CONFIG_PROF_TCK:
 375                return sparc64_get_clock_tick(smp_processor_id());
 376#ifdef CONFIG_SMP       
 377        case SOLARIS_CONFIG_NPROC_CONF: return NR_CPUS;
 378        case SOLARIS_CONFIG_NPROC_ONLN: return num_online_cpus();
 379#else
 380        case SOLARIS_CONFIG_NPROC_CONF: return 1;
 381        case SOLARIS_CONFIG_NPROC_ONLN: return 1;
 382#endif
 383        case SOLARIS_CONFIG_SIGRT_MIN:          return 37;
 384        case SOLARIS_CONFIG_SIGRT_MAX:          return 44;
 385        case SOLARIS_CONFIG_PHYS_PAGES:
 386        case SOLARIS_CONFIG_AVPHYS_PAGES:
 387                {
 388                        struct sysinfo s;
 389                        
 390                        si_meminfo(&s);
 391                        if (id == SOLARIS_CONFIG_PHYS_PAGES)
 392                                return s.totalram >>= PAGE_SHIFT;
 393                        else
 394                                return s.freeram >>= PAGE_SHIFT;
 395                }
 396        /* XXX support these as well -jj */
 397        case SOLARIS_CONFIG_AIO_LISTIO_MAX:     return -EINVAL;
 398        case SOLARIS_CONFIG_AIO_MAX:            return -EINVAL;
 399        case SOLARIS_CONFIG_AIO_PRIO_DELTA_MAX: return -EINVAL;
 400        case SOLARIS_CONFIG_DELAYTIMER_MAX:     return -EINVAL;
 401        case SOLARIS_CONFIG_MQ_OPEN_MAX:        return -EINVAL;
 402        case SOLARIS_CONFIG_MQ_PRIO_MAX:        return -EINVAL;
 403        case SOLARIS_CONFIG_RTSIG_MAX:          return -EINVAL;
 404        case SOLARIS_CONFIG_SEM_NSEMS_MAX:      return -EINVAL;
 405        case SOLARIS_CONFIG_SEM_VALUE_MAX:      return -EINVAL;
 406        case SOLARIS_CONFIG_SIGQUEUE_MAX:       return -EINVAL;
 407        case SOLARIS_CONFIG_TIMER_MAX:          return -EINVAL;
 408        default: return -EINVAL;
 409        }
 410}
 411
 412asmlinkage int solaris_procids(int cmd, s32 pid, s32 pgid)
 413{
 414        int ret;
 415        
 416        switch (cmd) {
 417        case 0: /* getpgrp */
 418                return task_pgrp_nr(current);
 419        case 1: /* setpgrp */
 420                {
 421                        int (*sys_setpgid)(pid_t,pid_t) =
 422                                (int (*)(pid_t,pid_t))SYS(setpgid);
 423                                
 424                        /* can anyone explain me the difference between
 425                           Solaris setpgrp and setsid? */
 426                        ret = sys_setpgid(0, 0);
 427                        if (ret) return ret;
 428                        proc_clear_tty(current);
 429                        return task_pgrp_nr(current);
 430                }
 431        case 2: /* getsid */
 432                {
 433                        int (*sys_getsid)(pid_t) = (int (*)(pid_t))SYS(getsid);
 434                        return sys_getsid(pid);
 435                }
 436        case 3: /* setsid */
 437                {
 438                        int (*sys_setsid)(void) = (int (*)(void))SYS(setsid);
 439                        return sys_setsid();
 440                }
 441        case 4: /* getpgid */
 442                {
 443                        int (*sys_getpgid)(pid_t) = (int (*)(pid_t))SYS(getpgid);
 444                        return sys_getpgid(pid);
 445                }
 446        case 5: /* setpgid */
 447                {
 448                        int (*sys_setpgid)(pid_t,pid_t) = 
 449                                (int (*)(pid_t,pid_t))SYS(setpgid);
 450                        return sys_setpgid(pid,pgid);
 451                }
 452        }
 453        return -EINVAL;
 454}
 455
 456asmlinkage int solaris_gettimeofday(u32 tim)
 457{
 458        int (*sys_gettimeofday)(struct timeval *, struct timezone *) =
 459                (int (*)(struct timeval *, struct timezone *))SYS(gettimeofday);
 460                
 461        return sys_gettimeofday((struct timeval *)(u64)tim, NULL);
 462}
 463
 464#define RLIM_SOL_INFINITY32     0x7fffffff
 465#define RLIM_SOL_SAVED_MAX32    0x7ffffffe
 466#define RLIM_SOL_SAVED_CUR32    0x7ffffffd
 467#define RLIM_SOL_INFINITY       ((u64)-3)
 468#define RLIM_SOL_SAVED_MAX      ((u64)-2)
 469#define RLIM_SOL_SAVED_CUR      ((u64)-1)
 470#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
 471#define RLIMIT_SOL_NOFILE       5
 472#define RLIMIT_SOL_VMEM         6
 473
 474struct rlimit32 {
 475        u32     rlim_cur;
 476        u32     rlim_max;
 477};
 478
 479asmlinkage int solaris_getrlimit(unsigned int resource, struct rlimit32 __user *rlim)
 480{
 481        struct rlimit r;
 482        int ret;
 483        mm_segment_t old_fs = get_fs ();
 484        int (*sys_getrlimit)(unsigned int, struct rlimit *) =
 485                (int (*)(unsigned int, struct rlimit *))SYS(getrlimit);
 486
 487        if (resource > RLIMIT_SOL_VMEM)
 488                return -EINVAL; 
 489        switch (resource) {
 490        case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break;
 491        case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break;
 492        default: break;
 493        }
 494        set_fs (KERNEL_DS);
 495        ret = sys_getrlimit(resource, &r);
 496        set_fs (old_fs);
 497        if (!ret) {
 498                if (r.rlim_cur == RLIM_INFINITY)
 499                        r.rlim_cur = RLIM_SOL_INFINITY32;
 500                else if ((u64)r.rlim_cur > RLIM_SOL_INFINITY32)
 501                        r.rlim_cur = RLIM_SOL_SAVED_CUR32;
 502                if (r.rlim_max == RLIM_INFINITY)
 503                        r.rlim_max = RLIM_SOL_INFINITY32;
 504                else if ((u64)r.rlim_max > RLIM_SOL_INFINITY32)
 505                        r.rlim_max = RLIM_SOL_SAVED_MAX32;
 506                ret = put_user (r.rlim_cur, &rlim->rlim_cur);
 507                ret |= __put_user (r.rlim_max, &rlim->rlim_max);
 508        }
 509        return ret;
 510}
 511
 512asmlinkage int solaris_setrlimit(unsigned int resource, struct rlimit32 __user *rlim)
 513{
 514        struct rlimit r, rold;
 515        int ret;
 516        mm_segment_t old_fs = get_fs ();
 517        int (*sys_getrlimit)(unsigned int, struct rlimit __user *) =
 518                (int (*)(unsigned int, struct rlimit __user *))SYS(getrlimit);
 519        int (*sys_setrlimit)(unsigned int, struct rlimit __user *) =
 520                (int (*)(unsigned int, struct rlimit __user *))SYS(setrlimit);
 521
 522        if (resource > RLIMIT_SOL_VMEM)
 523                return -EINVAL; 
 524        switch (resource) {
 525        case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break;
 526        case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break;
 527        default: break;
 528        }
 529        if (get_user (r.rlim_cur, &rlim->rlim_cur) ||
 530            __get_user (r.rlim_max, &rlim->rlim_max))
 531                return -EFAULT;
 532        set_fs (KERNEL_DS);
 533        ret = sys_getrlimit(resource, &rold);
 534        if (!ret) {
 535                if (r.rlim_cur == RLIM_SOL_INFINITY32)
 536                        r.rlim_cur = RLIM_INFINITY;
 537                else if (r.rlim_cur == RLIM_SOL_SAVED_CUR32)
 538                        r.rlim_cur = rold.rlim_cur;
 539                else if (r.rlim_cur == RLIM_SOL_SAVED_MAX32)
 540                        r.rlim_cur = rold.rlim_max;
 541                if (r.rlim_max == RLIM_SOL_INFINITY32)
 542                        r.rlim_max = RLIM_INFINITY;
 543                else if (r.rlim_max == RLIM_SOL_SAVED_CUR32)
 544                        r.rlim_max = rold.rlim_cur;
 545                else if (r.rlim_max == RLIM_SOL_SAVED_MAX32)
 546                        r.rlim_max = rold.rlim_max;
 547                ret = sys_setrlimit(resource, &r);
 548        }
 549        set_fs (old_fs);
 550        return ret;
 551}
 552
 553asmlinkage int solaris_getrlimit64(unsigned int resource, struct rlimit __user *rlim)
 554{
 555        struct rlimit r;
 556        int ret;
 557        mm_segment_t old_fs = get_fs ();
 558        int (*sys_getrlimit)(unsigned int, struct rlimit __user *) =
 559                (int (*)(unsigned int, struct rlimit __user *))SYS(getrlimit);
 560
 561        if (resource > RLIMIT_SOL_VMEM)
 562                return -EINVAL; 
 563        switch (resource) {
 564        case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break;
 565        case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break;
 566        default: break;
 567        }
 568        set_fs (KERNEL_DS);
 569        ret = sys_getrlimit(resource, &r);
 570        set_fs (old_fs);
 571        if (!ret) {
 572                if (r.rlim_cur == RLIM_INFINITY)
 573                        r.rlim_cur = RLIM_SOL_INFINITY;
 574                if (r.rlim_max == RLIM_INFINITY)
 575                        r.rlim_max = RLIM_SOL_INFINITY;
 576                ret = put_user (r.rlim_cur, &rlim->rlim_cur);
 577                ret |= __put_user (r.rlim_max, &rlim->rlim_max);
 578        }
 579        return ret;
 580}
 581
 582asmlinkage int solaris_setrlimit64(unsigned int resource, struct rlimit __user *rlim)
 583{
 584        struct rlimit r, rold;
 585        int ret;
 586        mm_segment_t old_fs = get_fs ();
 587        int (*sys_getrlimit)(unsigned int, struct rlimit __user *) =
 588                (int (*)(unsigned int, struct rlimit __user *))SYS(getrlimit);
 589        int (*sys_setrlimit)(unsigned int, struct rlimit __user *) =
 590                (int (*)(unsigned int, struct rlimit __user *))SYS(setrlimit);
 591
 592        if (resource > RLIMIT_SOL_VMEM)
 593                return -EINVAL; 
 594        switch (resource) {
 595        case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break;
 596        case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break;
 597        default: break;
 598        }
 599        if (get_user (r.rlim_cur, &rlim->rlim_cur) ||
 600            __get_user (r.rlim_max, &rlim->rlim_max))
 601                return -EFAULT;
 602        set_fs (KERNEL_DS);
 603        ret = sys_getrlimit(resource, &rold);
 604        if (!ret) {
 605                if (r.rlim_cur == RLIM_SOL_INFINITY)
 606                        r.rlim_cur = RLIM_INFINITY;
 607                else if (r.rlim_cur == RLIM_SOL_SAVED_CUR)
 608                        r.rlim_cur = rold.rlim_cur;
 609                else if (r.rlim_cur == RLIM_SOL_SAVED_MAX)
 610                        r.rlim_cur = rold.rlim_max;
 611                if (r.rlim_max == RLIM_SOL_INFINITY)
 612                        r.rlim_max = RLIM_INFINITY;
 613                else if (r.rlim_max == RLIM_SOL_SAVED_CUR)
 614                        r.rlim_max = rold.rlim_cur;
 615                else if (r.rlim_max == RLIM_SOL_SAVED_MAX)
 616                        r.rlim_max = rold.rlim_max;
 617                ret = sys_setrlimit(resource, &r);
 618        }
 619        set_fs (old_fs);
 620        return ret;
 621}
 622
 623struct sol_ntptimeval {
 624        struct compat_timeval time;
 625        s32 maxerror;
 626        s32 esterror;
 627};
 628
 629struct sol_timex {
 630        u32 modes;
 631        s32 offset;
 632        s32 freq;
 633        s32 maxerror;
 634        s32 esterror;
 635        s32 status;
 636        s32 constant;
 637        s32 precision;
 638        s32 tolerance;
 639        s32 ppsfreq;
 640        s32 jitter;
 641        s32 shift;
 642        s32 stabil;
 643        s32 jitcnt;
 644        s32 calcnt;
 645        s32 errcnt;
 646        s32 stbcnt;
 647};
 648
 649asmlinkage int solaris_ntp_gettime(struct sol_ntptimeval __user *ntp)
 650{
 651        int (*sys_adjtimex)(struct timex __user *) =
 652                (int (*)(struct timex __user *))SYS(adjtimex);
 653        struct timex t;
 654        int ret;
 655        mm_segment_t old_fs = get_fs();
 656        
 657        set_fs(KERNEL_DS);
 658        t.modes = 0;
 659        ret = sys_adjtimex(&t);
 660        set_fs(old_fs);
 661        if (ret < 0)
 662                return ret;
 663        ret = put_user (t.time.tv_sec, &ntp->time.tv_sec);
 664        ret |= __put_user (t.time.tv_usec, &ntp->time.tv_usec);
 665        ret |= __put_user (t.maxerror, &ntp->maxerror);
 666        ret |= __put_user (t.esterror, &ntp->esterror);
 667        return ret;                             
 668}
 669
 670asmlinkage int solaris_ntp_adjtime(struct sol_timex __user *txp)
 671{
 672        int (*sys_adjtimex)(struct timex __user *) =
 673                (int (*)(struct timex __user *))SYS(adjtimex);
 674        struct timex t;
 675        int ret, err;
 676        mm_segment_t old_fs = get_fs();
 677
 678        ret = get_user (t.modes, &txp->modes);
 679        ret |= __get_user (t.offset, &txp->offset);
 680        ret |= __get_user (t.freq, &txp->freq);
 681        ret |= __get_user (t.maxerror, &txp->maxerror);
 682        ret |= __get_user (t.esterror, &txp->esterror);
 683        ret |= __get_user (t.status, &txp->status);
 684        ret |= __get_user (t.constant, &txp->constant);
 685        set_fs(KERNEL_DS);
 686        ret = sys_adjtimex(&t);
 687        set_fs(old_fs);
 688        if (ret < 0)
 689                return ret;
 690        err = put_user (t.offset, &txp->offset);
 691        err |= __put_user (t.freq, &txp->freq);
 692        err |= __put_user (t.maxerror, &txp->maxerror);
 693        err |= __put_user (t.esterror, &txp->esterror);
 694        err |= __put_user (t.status, &txp->status);
 695        err |= __put_user (t.constant, &txp->constant);
 696        err |= __put_user (t.precision, &txp->precision);
 697        err |= __put_user (t.tolerance, &txp->tolerance);
 698        err |= __put_user (t.ppsfreq, &txp->ppsfreq);
 699        err |= __put_user (t.jitter, &txp->jitter);
 700        err |= __put_user (t.shift, &txp->shift);
 701        err |= __put_user (t.stabil, &txp->stabil);
 702        err |= __put_user (t.jitcnt, &txp->jitcnt);
 703        err |= __put_user (t.calcnt, &txp->calcnt);
 704        err |= __put_user (t.errcnt, &txp->errcnt);
 705        err |= __put_user (t.stbcnt, &txp->stbcnt);
 706        if (err)
 707                return -EFAULT;
 708        return ret;
 709}
 710
 711asmlinkage int do_sol_unimplemented(struct pt_regs *regs)
 712{
 713        printk ("Unimplemented Solaris syscall %d %08x %08x %08x %08x\n", 
 714                        (int)regs->u_regs[UREG_G1], 
 715                        (int)regs->u_regs[UREG_I0],
 716                        (int)regs->u_regs[UREG_I1],
 717                        (int)regs->u_regs[UREG_I2],
 718                        (int)regs->u_regs[UREG_I3]);
 719        return -ENOSYS;
 720}
 721
 722asmlinkage void solaris_register(void)
 723{
 724        set_personality(PER_SVR4);
 725}
 726
 727extern long solaris_to_linux_signals[], linux_to_solaris_signals[];
 728
 729struct exec_domain solaris_exec_domain = {
 730        .name =         "Solaris",
 731        .handler =      NULL,
 732        .pers_low =     1,              /* PER_SVR4 personality */
 733        .pers_high =    1,
 734        .signal_map =   solaris_to_linux_signals,
 735        .signal_invmap =linux_to_solaris_signals,
 736        .module =       THIS_MODULE,
 737        .next =         NULL
 738};
 739
 740extern int init_socksys(void);
 741
 742MODULE_AUTHOR("Jakub Jelinek (jj@ultra.linux.cz), Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)");
 743MODULE_DESCRIPTION("Solaris binary emulation module");
 744MODULE_LICENSE("GPL");
 745
 746extern u32 tl0_solaris[8];
 747#define update_ttable(x)                                                                                \
 748        tl0_solaris[3] = (((long)(x) - (long)tl0_solaris - 3) >> 2) | 0x40000000;                       \
 749        wmb();          \
 750        __asm__ __volatile__ ("flush %0" : : "r" (&tl0_solaris[3]))
 751
 752extern u32 solaris_sparc_syscall[];
 753extern u32 solaris_syscall[];
 754extern void cleanup_socksys(void);
 755
 756extern u32 entry64_personality_patch;
 757
 758static int __init solaris_init(void)
 759{
 760        int ret;
 761
 762        SOLDD(("Solaris module at %p\n", solaris_sparc_syscall));
 763        register_exec_domain(&solaris_exec_domain);
 764        if ((ret = init_socksys())) {
 765                unregister_exec_domain(&solaris_exec_domain);
 766                return ret;
 767        }
 768        update_ttable(solaris_sparc_syscall);
 769        entry64_personality_patch |=
 770                (offsetof(struct task_struct, personality) +
 771                 (sizeof(unsigned long) - 1));
 772        wmb();
 773        __asm__ __volatile__("flush %0"
 774                             : : "r" (&entry64_personality_patch));
 775        return 0;
 776}
 777
 778static void __exit solaris_exit(void)
 779{
 780        update_ttable(solaris_syscall);
 781        cleanup_socksys();
 782        unregister_exec_domain(&solaris_exec_domain);
 783}
 784
 785module_init(solaris_init);
 786module_exit(solaris_exit);
 787